From 0889a9441d98af7951c5377647413d79c84c9efa Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 23 Sep 2006 22:11:07 +0000 Subject: [PATCH 01/27] CIFS: Use SEEK_END instead of hardcoded value Signed-off-by: Josef 'Jeff' Sipek Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index c3ef1c0d0e68..f5ba41132488 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -508,7 +508,7 @@ static ssize_t cifs_file_aio_write(struct kiocb *iocb, const char __user *buf, static loff_t cifs_llseek(struct file *file, loff_t offset, int origin) { /* origin == SEEK_END => we must revalidate the cached file length */ - if (origin == 2) { + if (origin == SEEK_END) { int retval = cifs_revalidate(file->f_dentry); if (retval < 0) return (loff_t)retval; From 1bd5bbcb6531776a8f73e2cc6287fc4dd542e1c7 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Sep 2006 03:35:57 +0000 Subject: [PATCH 02/27] [CIFS] Legacy time handling for Win9x and OS/2 part 1 Signed-off-by: Steve French --- fs/cifs/cifsproto.h | 3 +++ fs/cifs/cifssmb.c | 10 ++++++++- fs/cifs/inode.c | 7 +++++-- fs/cifs/link.c | 6 +++++- fs/cifs/netmisc.c | 51 +++++++++++++++++++++++++++++++++++++++++++++ fs/cifs/readdir.c | 7 +++++++ 6 files changed, 80 insertions(+), 4 deletions(-) diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index b35c55c3c8bb..2fbc982aa13d 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -80,6 +80,9 @@ extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, extern void DeleteOplockQEntry(struct oplock_q_entry *); extern struct timespec cifs_NTtimeToUnix(u64 /* utc nanoseconds since 1601 */ ); extern u64 cifs_UnixTimeToNT(struct timespec); +extern __le64 cnvrtDosCifsTm(__u16 date, __u16 time); +extern struct timespec cnvrtDosUnixTm(__u16 date, __u16 time); + extern int cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path, FILE_ALL_INFO * pfile_info, diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 075d8fb3d376..2851d6e0d823 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -2856,7 +2856,6 @@ qsec_out: return rc; } - /* Legacy Query Path Information call for lookup to old servers such as Win9x/WinME */ int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, @@ -2898,7 +2897,16 @@ QInfRetry: if (rc) { cFYI(1, ("Send error in QueryInfo = %d", rc)); } else if (pFinfo) { /* decode response */ + struct timespec ts; + __u32 time = le32_to_cpu(pSMBr->last_write_time); + /* BB FIXME - add time zone adjustment BB */ memset(pFinfo, 0, sizeof(FILE_ALL_INFO)); + ts.tv_nsec = 0; + ts.tv_sec = time; + /* decode time fields */ + pFinfo->ChangeTime = cifs_UnixTimeToNT(ts); + pFinfo->LastWriteTime = pFinfo->ChangeTime; + pFinfo->LastAccessTime = 0; pFinfo->AllocationSize = cpu_to_le64(le32_to_cpu(pSMBr->size)); pFinfo->EndOfFile = pFinfo->AllocationSize; diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index b88147c1dc27..06dbce3a1815 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -432,8 +432,11 @@ int cifs_get_inode_info(struct inode **pinode, (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/ /* Linux can not store file creation time so ignore it */ - inode->i_atime = - cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); + if(pfindData->LastAccessTime) + inode->i_atime = cifs_NTtimeToUnix + (le64_to_cpu(pfindData->LastAccessTime)); + else /* do not need to use current_fs_time - time not stored */ + inode->i_atime = CURRENT_TIME; inode->i_mtime = cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); inode->i_ctime = diff --git a/fs/cifs/link.c b/fs/cifs/link.c index a57f5d6e6213..0bee8b7e521a 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -254,7 +254,11 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) tmpbuffer, len - 1, cifs_sb->local_nls); - else { + else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { + cERROR(1,("SFU style symlinks not implemented yet")); + /* add open and read as in fs/cifs/inode.c */ + + } else { rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ, OPEN_REPARSE_POINT,&fid, &oplock, NULL, cifs_sb->local_nls, diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index ce87550e918f..fa5124d9af19 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -909,3 +909,54 @@ cifs_UnixTimeToNT(struct timespec t) /* Convert to 100ns intervals and then add the NTFS time offset. */ return (u64) t.tv_sec * 10000000 + t.tv_nsec/100 + NTFS_TIME_OFFSET; } + +static int total_days_of_prev_months[] = +{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334}; + + +__le64 cnvrtDosCifsTm(__u16 date, __u16 time) +{ + return cpu_to_le64(cifs_UnixTimeToNT(cnvrtDosUnixTm(date, time))); +} +struct timespec cnvrtDosUnixTm(__u16 date, __u16 time) +{ + __u8 dt[2]; + __u8 tm[2]; + struct timespec ts; + int sec,min, days, month, year; + struct timespec removeme; /* BB removeme BB */ +/* SMB_TIME * st = (SMB_TIME *)&time;*/ + + cFYI(1,("date %d time %d",date, time)); + + dt[0] = date & 0xFF; + dt[1] = (date & 0xFF00) >> 8; + tm[0] = time & 0xFF; + tm[1] = (time & 0xFF00) >> 8; + + sec = tm[0] & 0x1F; + sec = 2 * sec; + min = ((tm[0] >>5)&0xFF) + ((tm[1] & 0x7)<<3); + + sec += (min * 60); + sec += 60 * 60 * ((tm[1] >> 3) &0xFF) /* hours */; + days = (dt[0] & 0x1F) - 1; + month = ((dt[0] >> 5) & 0xFF) + ((dt[1] & 0x1) <<3); + if(month > 12) + cERROR(1,("illegal month %d in date", month)); + month -= 1; + days += total_days_of_prev_months[month]; + days += 3653; /* account for difference in days between 1980 and 1970 */ + year = (dt[1]>>1) & 0xFF; + days += year * 365; + days += (year/4); /* leap year */ + /* adjust for leap year where we are still before leap day */ + days -= ((year & 0x03) == 0) && (month < 2 ? 1 : 0); + sec += 24 * 60 * 60 * days; + + removeme = CURRENT_TIME; /* BB removeme BB */ + ts.tv_sec = sec; + + ts.tv_nsec = 0; + return ts; +} diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 9aeb58a7d369..71e86c38e632 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -135,12 +135,19 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, tmp_inode->i_ctime = cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); } else { /* legacy, OS2 and DOS style */ +/* struct timespec ts;*/ FIND_FILE_STANDARD_INFO * pfindData = (FIND_FILE_STANDARD_INFO *)buf; +/* ts = cnvrtDosUnixTm( + le16_to_cpu(pfindData->LastWriteDate), + le16_to_cpu(pfindData->LastWriteTime));*/ attr = le16_to_cpu(pfindData->Attributes); allocation_size = le32_to_cpu(pfindData->AllocationSize); end_of_file = le32_to_cpu(pfindData->DataSize); + /* do not need to use current_fs_time helper function since + time not stored for this case so atime can not "go backwards" + by pulling newer older from disk when inode refrenshed */ tmp_inode->i_atime = CURRENT_TIME; /* tmp_inode->i_mtime = BB FIXME - add dos time handling tmp_inode->i_ctime = 0; BB FIXME */ From 2cd646a2d1d5e0e46aa4bb55b1847b0cb35bd855 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Sep 2006 19:43:08 +0000 Subject: [PATCH 03/27] [CIFS] Remove static and unused symbols Most cases of the ones found by Shaggy by "make namespacecheck" could be removed or made static Ack: Dave Kleikamp Signed-off-by: Steve French --- fs/cifs/cifsacl.h | 4 ++-- fs/cifs/cifsencrypt.h | 2 -- fs/cifs/cifsfs.c | 5 +++-- fs/cifs/cifsfs.h | 2 +- fs/cifs/cifsglob.h | 4 ++-- fs/cifs/cifsproto.h | 6 ++---- fs/cifs/cifssmb.c | 6 ++++-- fs/cifs/connect.c | 20 ++++++++++++-------- fs/cifs/md5.c | 4 ++-- fs/cifs/md5.h | 8 ++++---- fs/cifs/misc.c | 2 +- fs/cifs/smbdes.c | 4 ++-- fs/cifs/smbencrypt.c | 4 ++-- 13 files changed, 37 insertions(+), 34 deletions(-) diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h index d0776ac2b804..5eff35d6e564 100644 --- a/fs/cifs/cifsacl.h +++ b/fs/cifs/cifsacl.h @@ -31,8 +31,8 @@ struct cifs_sid { } __attribute__((packed)); /* everyone */ -extern const struct cifs_sid sid_everyone; +/* extern const struct cifs_sid sid_everyone;*/ /* group users */ -extern const struct cifs_sid sid_user; +/* extern const struct cifs_sid sid_user;*/ #endif /* _CIFSACL_H */ diff --git a/fs/cifs/cifsencrypt.h b/fs/cifs/cifsencrypt.h index 03e359b32861..152fa2dcfc6c 100644 --- a/fs/cifs/cifsencrypt.h +++ b/fs/cifs/cifsencrypt.h @@ -27,8 +27,6 @@ extern void mdfour(unsigned char *out, unsigned char *in, int n); /* smbdes.c */ extern void E_P16(unsigned char *p14, unsigned char *p16); extern void E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24); -extern void D_P16(unsigned char *p14, unsigned char *in, unsigned char *out); -extern void E_old_pw_hash(unsigned char *, unsigned char *, unsigned char *); diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index f5ba41132488..cd17d4b78173 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -442,7 +442,7 @@ static int cifs_remount(struct super_block *sb, int *flags, char *data) return 0; } -struct super_operations cifs_super_ops = { +static struct super_operations cifs_super_ops = { .read_inode = cifs_read_inode, .put_super = cifs_put_super, .statfs = cifs_statfs, @@ -930,7 +930,7 @@ init_cifs(void) #ifdef CONFIG_PROC_FS cifs_proc_init(); #endif - INIT_LIST_HEAD(&GlobalServerList); /* BB not implemented yet */ +/* INIT_LIST_HEAD(&GlobalServerList);*/ /* BB not implemented yet */ INIT_LIST_HEAD(&GlobalSMBSessionList); INIT_LIST_HEAD(&GlobalTreeConnectionList); INIT_LIST_HEAD(&GlobalOplock_Q); @@ -958,6 +958,7 @@ init_cifs(void) GlobalCurrentXid = 0; GlobalTotalActiveXid = 0; GlobalMaxActiveXid = 0; + memset(Local_System_Name, 0, 15); rwlock_init(&GlobalSMBSeslock); spin_lock_init(&GlobalMid_Lock); diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index bea875d9a46a..a243f779b363 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -36,7 +36,7 @@ extern const struct address_space_operations cifs_addr_ops; extern const struct address_space_operations cifs_addr_ops_smallbuf; /* Functions related to super block operations */ -extern struct super_operations cifs_super_ops; +/* extern struct super_operations cifs_super_ops;*/ extern void cifs_read_inode(struct inode *); extern void cifs_delete_inode(struct inode *); /* extern void cifs_write_inode(struct inode *); *//* BB not needed yet */ diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index b24006c47df1..441f8d2514fa 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -512,7 +512,8 @@ require use of the stronger protocol */ * This list helps improve performance and eliminate the messages indicating * that we had a communications error talking to the server in this list. */ -GLOBAL_EXTERN struct servers_not_supported *NotSuppList; /*@z4a */ +/* Feature not supported */ +/* GLOBAL_EXTERN struct servers_not_supported *NotSuppList; */ /* * The following is a hash table of all the users we know about. @@ -568,7 +569,6 @@ GLOBAL_EXTERN unsigned int lookupCacheEnabled; GLOBAL_EXTERN unsigned int extended_security; /* if on, session setup sent with more secure ntlmssp2 challenge/resp */ GLOBAL_EXTERN unsigned int sign_CIFS_PDUs; /* enable smb packet signing */ -GLOBAL_EXTERN unsigned int secFlags; GLOBAL_EXTERN unsigned int linuxExtEnabled;/*enable Linux/Unix CIFS extensions*/ GLOBAL_EXTERN unsigned int CIFSMaxBufSize; /* max size not including hdr */ GLOBAL_EXTERN unsigned int cifs_min_rcv; /* min size of big ntwrk buf pool */ diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 2fbc982aa13d..7dd2f48a4073 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -50,11 +50,11 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, struct kvec *, int /* nvec to send */, int * /* type of buf returned */ , const int long_op); -extern int SendReceiveBlockingLock(const unsigned int /* xid */ , struct cifsTconInfo *, +extern int SendReceiveBlockingLock(const unsigned int /* xid */ , + struct cifsTconInfo *, struct smb_hdr * /* input */ , struct smb_hdr * /* out */ , int * /* bytes returned */); -extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *); extern int is_size_safe_to_change(struct cifsInodeInfo *); @@ -282,8 +282,6 @@ extern void sesInfoFree(struct cifsSesInfo *); extern struct cifsTconInfo *tconInfoAlloc(void); extern void tconInfoFree(struct cifsTconInfo *); -extern int cifs_reconnect(struct TCP_Server_Info *server); - extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *,__u32 *); extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *, __u32 *); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 2851d6e0d823..dcd7087a1ae8 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -2773,9 +2773,11 @@ GetExtAttrOut: /* security id for everyone */ -const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}}; +const static struct cifs_sid sid_everyone = + {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}}; /* group users */ -const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}}; +const static struct cifs_sid sid_user = + {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}}; /* Convert CIFS ACL to POSIX form */ static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 0e9ba0b9d71e..b3268e53ab95 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -109,7 +109,7 @@ static int ipv6_connect(struct sockaddr_in6 *psin_server, * wake up waiters on reconnection? - (not needed currently) */ -int +static int cifs_reconnect(struct TCP_Server_Info *server) { int rc = 0; @@ -771,13 +771,17 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) separator[0] = ','; separator[1] = 0; - memset(vol->source_rfc1001_name,0x20,15); - for(i=0;i < strnlen(system_utsname.nodename,15);i++) { - /* does not have to be a perfect mapping since the field is - informational, only used for servers that do not support - port 445 and it can be overridden at mount time */ - vol->source_rfc1001_name[i] = - toupper(system_utsname.nodename[i]); + if(Local_System_Name[0] != 0) + memcpy(vol->source_rfc1001_name, Local_System_Name,15); + else { + memset(vol->source_rfc1001_name,0x20,15); + for(i=0;i < strnlen(system_utsname.nodename,15);i++) { + /* does not have to be perfect mapping since field is + informational, only used for servers that do not support + port 445 and it can be overridden at mount time */ + vol->source_rfc1001_name[i] = + toupper(system_utsname.nodename[i]); + } } vol->source_rfc1001_name[15] = 0; /* null target name indicates to use *SMBSERVR default called name diff --git a/fs/cifs/md5.c b/fs/cifs/md5.c index 7aa23490541f..273aa0383f27 100644 --- a/fs/cifs/md5.c +++ b/fs/cifs/md5.c @@ -255,7 +255,7 @@ MD5Transform(__u32 buf[4], __u32 const in[16]) /*********************************************************************** the rfc 2104 version of hmac_md5 initialisation. ***********************************************************************/ -void +static void hmac_md5_init_rfc2104(unsigned char *key, int key_len, struct HMACMD5Context *ctx) { @@ -350,7 +350,7 @@ hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx) single function to calculate an HMAC MD5 digest from data. use the microsoft hmacmd5 init method because the key is 16 bytes. ************************************************************/ -void +static void hmac_md5(unsigned char key[16], unsigned char *data, int data_len, unsigned char *digest) { diff --git a/fs/cifs/md5.h b/fs/cifs/md5.h index 00e1c5394fe1..f7d4f4197bac 100644 --- a/fs/cifs/md5.h +++ b/fs/cifs/md5.h @@ -27,12 +27,12 @@ void MD5Final(unsigned char digest[16], struct MD5Context *context); /* The following definitions come from lib/hmacmd5.c */ -void hmac_md5_init_rfc2104(unsigned char *key, int key_len, - struct HMACMD5Context *ctx); +/* void hmac_md5_init_rfc2104(unsigned char *key, int key_len, + struct HMACMD5Context *ctx);*/ void hmac_md5_init_limK_to_64(const unsigned char *key, int key_len, struct HMACMD5Context *ctx); void hmac_md5_update(const unsigned char *text, int text_len, struct HMACMD5Context *ctx); void hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx); -void hmac_md5(unsigned char key[16], unsigned char *data, int data_len, - unsigned char *digest); +/* void hmac_md5(unsigned char key[16], unsigned char *data, int data_len, + unsigned char *digest);*/ diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 22c937e5884f..ca6e9b1413fa 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -389,7 +389,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , return; } -int +static int checkSMBhdr(struct smb_hdr *smb, __u16 mid) { /* Make sure that this really is an SMB, that it is a response, diff --git a/fs/cifs/smbdes.c b/fs/cifs/smbdes.c index efaa044523a7..2b193e422f83 100644 --- a/fs/cifs/smbdes.c +++ b/fs/cifs/smbdes.c @@ -364,14 +364,14 @@ E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24) smbhash(p24 + 16, c8, p21 + 14, 1); } -void +static void D_P16(unsigned char *p14, unsigned char *in, unsigned char *out) { smbhash(out, in, p14, 0); smbhash(out + 8, in + 8, p14 + 7, 0); } -void +static void E_old_pw_hash(unsigned char *p14, unsigned char *in, unsigned char *out) { smbhash(out, in, p14, 1); diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c index f518c5e45035..c7e55a940e2e 100644 --- a/fs/cifs/smbencrypt.c +++ b/fs/cifs/smbencrypt.c @@ -145,7 +145,7 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16) } /* Does both the NT and LM owfs of a user's password */ -void +static void nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]) { char passwd[514]; @@ -223,7 +223,7 @@ SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8, } /* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */ -void +static void NTLMSSPOWFencrypt(unsigned char passwd[8], unsigned char *ntlmchalresp, unsigned char p24[24]) { From e33c74d06e2b46a5f187ec7f60248da774c84e72 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Sep 2006 20:35:48 +0000 Subject: [PATCH 04/27] [CIFS] Fix build break Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index cd17d4b78173..51e888fcef2d 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -63,6 +63,7 @@ extern struct task_struct * oplockThread; /* remove sparse warning */ struct task_struct * oplockThread = NULL; extern struct task_struct * dnotifyThread; /* remove sparse warning */ struct task_struct * dnotifyThread = NULL; +static struct super_operations cifs_super_ops; unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE; module_param(CIFSMaxBufSize, int, 0); MODULE_PARM_DESC(CIFSMaxBufSize,"Network buffer size (not including header). Default: 16384 Range: 8192 to 130048"); From 2eaf55862e8eb03999169d84f21eadffc88a36ce Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Sep 2006 20:41:48 +0000 Subject: [PATCH 05/27] [CIFS] Remove unused prototypes Signed-off-by: Steve French --- fs/cifs/smbencrypt.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c index c7e55a940e2e..48314e5e785d 100644 --- a/fs/cifs/smbencrypt.c +++ b/fs/cifs/smbencrypt.c @@ -51,11 +51,8 @@ void SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); void E_md4hash(const unsigned char *passwd, unsigned char *p16); -void nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]); static void SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8, unsigned char p24[24]); -void NTLMSSPOWFencrypt(unsigned char passwd[8], - unsigned char *ntlmchalresp, unsigned char p24[24]); void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); /* From e10847ed499cb86bf8ce12f3a686be8a98f8e140 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Sep 2006 20:49:01 +0000 Subject: [PATCH 06/27] [CIFS] More removing of unused functions Signed-off-by: Steve French --- fs/cifs/md5.c | 4 ++++ fs/cifs/smbdes.c | 2 +- fs/cifs/smbencrypt.c | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/fs/cifs/md5.c b/fs/cifs/md5.c index 273aa0383f27..e6a2097d836b 100644 --- a/fs/cifs/md5.c +++ b/fs/cifs/md5.c @@ -252,6 +252,7 @@ MD5Transform(__u32 buf[4], __u32 const in[16]) buf[3] += d; } +#if 0 /* currently unused */ /*********************************************************************** the rfc 2104 version of hmac_md5 initialisation. ***********************************************************************/ @@ -289,6 +290,7 @@ hmac_md5_init_rfc2104(unsigned char *key, int key_len, MD5Init(&ctx->ctx); MD5Update(&ctx->ctx, ctx->k_ipad, 64); } +#endif /*********************************************************************** the microsoft version of hmac_md5 initialisation. @@ -333,6 +335,7 @@ hmac_md5_update(const unsigned char *text, int text_len, /*********************************************************************** finish off hmac_md5 "inner" buffer and generate outer one. ***********************************************************************/ +#if 0 /* currently unused */ void hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx) { @@ -361,3 +364,4 @@ hmac_md5(unsigned char key[16], unsigned char *data, int data_len, } hmac_md5_final(digest, &ctx); } +#endif diff --git a/fs/cifs/smbdes.c b/fs/cifs/smbdes.c index 2b193e422f83..7a1b2b961ec8 100644 --- a/fs/cifs/smbdes.c +++ b/fs/cifs/smbdes.c @@ -364,6 +364,7 @@ E_P24(unsigned char *p21, unsigned char *c8, unsigned char *p24) smbhash(p24 + 16, c8, p21 + 14, 1); } +#if 0 /* currently unsued */ static void D_P16(unsigned char *p14, unsigned char *in, unsigned char *out) { @@ -377,7 +378,6 @@ E_old_pw_hash(unsigned char *p14, unsigned char *in, unsigned char *out) smbhash(out, in, p14, 1); smbhash(out + 8, in + 8, p14 + 7, 1); } -#if 0 /* these routines are currently unneeded, but may be needed later */ void diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c index 48314e5e785d..4b25ba92180d 100644 --- a/fs/cifs/smbencrypt.c +++ b/fs/cifs/smbencrypt.c @@ -141,6 +141,7 @@ E_md4hash(const unsigned char *passwd, unsigned char *p16) memset(wpwd,0,129 * 2); } +#if 0 /* currently unused */ /* Does both the NT and LM owfs of a user's password */ static void nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]) @@ -168,6 +169,7 @@ nt_lm_owf_gen(char *pwd, unsigned char nt_p16[16], unsigned char p16[16]) /* clear out local copy of user's password (just being paranoid). */ memset(passwd, '\0', sizeof (passwd)); } +#endif /* Does the NTLMv2 owfs of a user's password */ #if 0 /* function not needed yet - but will be soon */ @@ -220,6 +222,7 @@ SMBOWFencrypt(unsigned char passwd[16], unsigned char *c8, } /* Does the des encryption from the FIRST 8 BYTES of the NT or LM MD4 hash. */ +#if 0 /* currently unused */ static void NTLMSSPOWFencrypt(unsigned char passwd[8], unsigned char *ntlmchalresp, unsigned char p24[24]) @@ -232,6 +235,7 @@ NTLMSSPOWFencrypt(unsigned char passwd[8], E_P24(p21, ntlmchalresp, p24); } +#endif /* Does the NT MD4 hash then des encryption. */ From a3ab41f10e2f5087e515da358680c88dd61d4832 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Sep 2006 20:52:08 +0000 Subject: [PATCH 07/27] [CIFS] Fix build break ifdef in wrong place Signed-off-by: Steve French --- fs/cifs/md5.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/md5.c b/fs/cifs/md5.c index e6a2097d836b..ccebf9b7eb86 100644 --- a/fs/cifs/md5.c +++ b/fs/cifs/md5.c @@ -335,7 +335,6 @@ hmac_md5_update(const unsigned char *text, int text_len, /*********************************************************************** finish off hmac_md5 "inner" buffer and generate outer one. ***********************************************************************/ -#if 0 /* currently unused */ void hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx) { @@ -353,6 +352,7 @@ hmac_md5_final(unsigned char *digest, struct HMACMD5Context *ctx) single function to calculate an HMAC MD5 digest from data. use the microsoft hmacmd5 init method because the key is 16 bytes. ************************************************************/ +#if 0 /* currently unused */ static void hmac_md5(unsigned char key[16], unsigned char *data, int data_len, unsigned char *digest) From bf97d28711e2dc4dc947faa6477cd1b36b91a2da Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 28 Sep 2006 21:34:06 +0000 Subject: [PATCH 08/27] [CIFS] CIFS support for /proc//mountstats part 1 Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 51e888fcef2d..7ecfcbf31e55 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -437,6 +437,14 @@ static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags) return; } +#ifdef CONFIG_CIFS_STATS2 +static int cifs_show_stats(struct seq_file *s, struct vfsmount *mnt) +{ + /* BB FIXME */ + return 0; +} +#endif + static int cifs_remount(struct super_block *sb, int *flags, char *data) { *flags |= MS_NODIRATIME; @@ -456,6 +464,9 @@ static struct super_operations cifs_super_ops = { .show_options = cifs_show_options, .umount_begin = cifs_umount_begin, .remount_fs = cifs_remount, +#ifdef CONFIG_CIFS_STATS2 + cifs_show_stats, +#endif }; static int From 25ee4a98c662317a7973f3053567d4ec51857511 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 30 Sep 2006 00:54:23 +0000 Subject: [PATCH 09/27] [CIFS] Handle legacy servers which return undefined time zone Signed-off-by: Guenter Kukkukk Signed-off-by: Steve French --- fs/cifs/cifssmb.c | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index dcd7087a1ae8..99718591ea29 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -447,6 +447,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) #ifdef CONFIG_CIFS_WEAK_PW_HASH } else if((pSMBr->hdr.WordCount == 13) && (pSMBr->DialectIndex == LANMAN_PROT)) { + int tmp, adjust; struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr; if((secFlags & CIFSSEC_MAY_LANMAN) || @@ -473,11 +474,36 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) server->capabilities = CAP_MPX_MODE; } server->timeZone = le16_to_cpu(rsp->ServerTimeZone); + tmp = le16_to_cpu(rsp->ServerTimeZone); + if (tmp == (int)0xffff) { + /* OS/2 often does not set timezone therefore + * we must use server time to calc time zone. + * Could deviate slightly from the right zone. Not easy + * to adjust, since timezones are not always a multiple + * of 60 (sometimes 30 minutes - are there smaller?) + */ + struct timespec ts, utc; + utc = CURRENT_TIME; + ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date), + le16_to_cpu(rsp->SrvTime.Time)); + cFYI(1,("SrvTime: %d sec since 1970 (utc: %d) diff: %d", + (int)ts.tv_sec, (int)utc.tv_sec, + (int)(utc.tv_sec - ts.tv_sec))); + tmp = (int)(utc.tv_sec - ts.tv_sec); + adjust = tmp < 0 ? -29 : 29; + tmp = ((tmp + adjust) / 60) * 60; + server->timeZone = tmp; + } else { + server->timeZone = tmp * 60; /* also in seconds */ + } + cFYI(1,("server->timeZone: %d seconds", server->timeZone)); + /* BB get server time for time conversions and add code to use it and timezone since this is not UTC */ - if (rsp->EncryptionKeyLength == cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) { + if (rsp->EncryptionKeyLength == + cpu_to_le16(CIFS_CRYPTO_KEY_SIZE)) { memcpy(server->cryptKey, rsp->EncryptionKey, CIFS_CRYPTO_KEY_SIZE); } else if (server->secMode & SECMODE_PW_ENCRYPT) { From 175ec9e11cf18f8373b32f7a33e75a4cf7ce25e3 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 30 Sep 2006 01:07:38 +0000 Subject: [PATCH 10/27] [CIFS] Rename server time zone field Server time zone is not really a time zone, rather a time adjustement in seconds. CC: Guenter Kukkukk Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 2 +- fs/cifs/cifsglob.h | 2 +- fs/cifs/cifspdu.h | 5 ++++- fs/cifs/cifssmb.c | 9 ++++----- fs/cifs/connect.c | 9 +++++---- 5 files changed, 15 insertions(+), 12 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 7ecfcbf31e55..e7641f9a13bb 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -465,7 +465,7 @@ static struct super_operations cifs_super_ops = { .umount_begin = cifs_umount_begin, .remount_fs = cifs_remount, #ifdef CONFIG_CIFS_STATS2 - cifs_show_stats, + .cifs_show_stats, #endif }; diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 441f8d2514fa..98eb5446e8c1 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -153,7 +153,7 @@ struct TCP_Server_Info { char sessid[4]; /* unique token id for this session */ /* (returned on Negotiate */ int capabilities; /* allow selective disabling of caps by smb sess */ - __u16 timeZone; + __u16 timeAdj; /* Adjust for difference in server time zone in sec */ __u16 CurrentMid; /* multiplex id - rotating counter */ char cryptKey[CIFS_CRYPTO_KEY_SIZE]; /* 16th byte of RFC1001 workstation name is always null */ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 81df2bf8e75a..e5dd8708d636 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -417,7 +417,10 @@ typedef struct lanman_neg_rsp { __le16 MaxNumberVcs; __le16 RawMode; __le32 SessionKey; - __le32 ServerTime; + struct { + __le16 Time; + __le16 Date; + } __attribute__((packed)) SrvTime; __le16 ServerTimeZone; __le16 EncryptionKeyLength; __le16 Reserved; diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 99718591ea29..6e004587fa48 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -473,7 +473,6 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) server->maxRw = 0;/* we do not need to use raw anyway */ server->capabilities = CAP_MPX_MODE; } - server->timeZone = le16_to_cpu(rsp->ServerTimeZone); tmp = le16_to_cpu(rsp->ServerTimeZone); if (tmp == (int)0xffff) { /* OS/2 often does not set timezone therefore @@ -492,11 +491,11 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) tmp = (int)(utc.tv_sec - ts.tv_sec); adjust = tmp < 0 ? -29 : 29; tmp = ((tmp + adjust) / 60) * 60; - server->timeZone = tmp; + server->timeAdj = tmp; } else { - server->timeZone = tmp * 60; /* also in seconds */ + server->timeAdj = tmp * 60; /* also in seconds */ } - cFYI(1,("server->timeZone: %d seconds", server->timeZone)); + cFYI(1,("server->timeAdj: %d seconds", server->timeAdj)); /* BB get server time for time conversions and add @@ -557,7 +556,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) cFYI(0, ("Max buf = %d", ses->server->maxBuf)); GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); server->capabilities = le32_to_cpu(pSMBr->Capabilities); - server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone); + server->timeAdj = le16_to_cpu(pSMBr->ServerTimeZone) * 60; if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { memcpy(server->cryptKey, pSMBr->u.EncryptionKey, CIFS_CRYPTO_KEY_SIZE); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index b3268e53ab95..083b2b2c1571 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3320,15 +3320,16 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, if(linuxExtEnabled == 0) pSesInfo->capabilities &= (~CAP_UNIX); /* pSesInfo->sequence_number = 0;*/ - cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d", + cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d", pSesInfo->server->secMode, pSesInfo->server->capabilities, - pSesInfo->server->timeZone)); + pSesInfo->server->timeAdj)); if(experimEnabled < 2) rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info); else if (extended_security - && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) + && (pSesInfo->capabilities + & CAP_EXTENDED_SECURITY) && (pSesInfo->server->secType == NTLMSSP)) { rc = -EOPNOTSUPP; } else if (extended_security @@ -3342,7 +3343,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, if (!rc) { if(ntlmv2_flag) { char * v2_response; - cFYI(1,("Can use more secure NTLM version 2 password hash")); + cFYI(1,("more secure NTLM ver2 hash")); if(CalcNTLMv2_partial_mac_key(pSesInfo, nls_info)) { rc = -ENOMEM; From f46d3e11903e452924ef2996aa9aca2aae4427e2 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 30 Sep 2006 01:08:55 +0000 Subject: [PATCH 11/27] [CIFS] Fix typo in name of new cifs_show_stats Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index e7641f9a13bb..ca53720fa5b1 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -465,7 +465,7 @@ static struct super_operations cifs_super_ops = { .umount_begin = cifs_umount_begin, .remount_fs = cifs_remount, #ifdef CONFIG_CIFS_STATS2 - .cifs_show_stats, + .show_stats = cifs_show_stats, #endif }; From 9ac00b7d96045fa3ce573e0ad5cdc0350ad8e1d2 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 30 Sep 2006 04:13:17 +0000 Subject: [PATCH 12/27] [CIFS] Do not send newer QFSInfo to legacy servers which can not support it Fix dialect negotiation to save off when we have negotiated lanman. This allows us to avoid sending some somewhat newer requests that the server can not handle and go directly to the older version (infolevel) of the same call. Make sure we try to negotiate a level which allows us to get the server OS (which we check so we can detect Win9x vs. other legacy servers and eventually work around the Win9x DOS time bug (they reverse date/time fields). Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 8 +++++--- fs/cifs/cifsglob.h | 9 +++++++-- fs/cifs/cifspdu.h | 3 ++- fs/cifs/cifssmb.c | 8 +++++--- fs/cifs/connect.c | 1 + fs/cifs/sess.c | 23 ++++++++++++----------- 6 files changed, 32 insertions(+), 20 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index ca53720fa5b1..d6d226addde2 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -199,10 +199,12 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf) /* Only need to call the old QFSInfo if failed on newer one */ if(rc) - rc = CIFSSMBQFSInfo(xid, pTcon, buf); + if((pTcon->ses->flags & CIFS_SES_LANMAN) == 0) + rc = CIFSSMBQFSInfo(xid, pTcon, buf); /* not supported by OS2 */ - /* Old Windows servers do not support level 103, retry with level - one if old server failed the previous call */ + /* Some old Windows servers also do not support level 103, retry with + older level one if old server failed the previous call or we + bypassed it because we detected that this was an older LANMAN sess */ if(rc) rc = SMBOldQFSInfo(xid, pTcon, buf); /* diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 98eb5446e8c1..597afdf4c69c 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -203,9 +203,14 @@ struct cifsSesInfo { char * domainName; char * password; }; -/* session flags */ +/* no more than one of the following three session flags may be set */ #define CIFS_SES_NT4 1 - +#define CIFS_SES_OS2 2 +#define CIFS_SES_W9X 4 +/* following flag is set for old servers such as OS2 (and Win95?) + which do not negotiate NTLM or POSIX dialects, but instead + negotiate one of the older LANMAN dialects */ +#define CIFS_SES_LANMAN 8 /* * there is one of these for each connection to a resource on a particular * session diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index e5dd8708d636..50505422dbb4 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -26,7 +26,8 @@ #ifdef CONFIG_CIFS_WEAK_PW_HASH #define LANMAN_PROT 0 -#define CIFS_PROT 1 +#define LANMAN2_PROT 1 +#define CIFS_PROT 2 #else #define CIFS_PROT 0 #endif diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 6e004587fa48..f2fa05bbcb47 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -46,6 +46,7 @@ static struct { } protocols[] = { #ifdef CONFIG_CIFS_WEAK_PW_HASH {LANMAN_PROT, "\2LM1.2X002"}, + {LANMAN2_PROT, "\2LANMAN2.1"}, #endif /* weak password hashing for legacy clients */ {CIFS_PROT, "\2NT LM 0.12"}, {POSIX_PROT, "\2POSIX 2"}, @@ -67,13 +68,13 @@ static struct { /* define the number of elements in the cifs dialect array */ #ifdef CONFIG_CIFS_POSIX #ifdef CONFIG_CIFS_WEAK_PW_HASH -#define CIFS_NUM_PROT 3 +#define CIFS_NUM_PROT 4 #else #define CIFS_NUM_PROT 2 #endif /* CIFS_WEAK_PW_HASH */ #else /* not posix */ #ifdef CONFIG_CIFS_WEAK_PW_HASH -#define CIFS_NUM_PROT 2 +#define CIFS_NUM_PROT 3 #else #define CIFS_NUM_PROT 1 #endif /* CONFIG_CIFS_WEAK_PW_HASH */ @@ -446,7 +447,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) goto neg_err_exit; #ifdef CONFIG_CIFS_WEAK_PW_HASH } else if((pSMBr->hdr.WordCount == 13) - && (pSMBr->DialectIndex == LANMAN_PROT)) { + && ((pSMBr->DialectIndex == LANMAN_PROT) + || (pSMBr->DialectIndex == LANMAN2_PROT))) { int tmp, adjust; struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 083b2b2c1571..c96f3edf1b9c 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3316,6 +3316,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, first_time = 1; } if (!rc) { + pSesInfo->flags = 0; pSesInfo->capabilities = pSesInfo->server->capabilities; if(linuxExtEnabled == 0) pSesInfo->capabilities &= (~CAP_UNIX); diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index d1705ab8136e..e4c4e466e320 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -268,6 +268,10 @@ static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo ses->serverOS = kzalloc(len + 1, GFP_KERNEL); if(ses->serverOS) strncpy(ses->serverOS, bcc_ptr, len); + if(strncmp(ses->serverOS, "OS/2",4) == 0) { + cFYI(1,("OS/2 server")); + ses->flags |= CIFS_SES_OS2; + } bcc_ptr += len + 1; bleft -= len + 1; @@ -290,16 +294,11 @@ static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo if(len > bleft) return rc; - if(ses->serverDomain) - kfree(ses->serverDomain); - - ses->serverDomain = kzalloc(len + 1, GFP_KERNEL); - if(ses->serverOS) - strncpy(ses->serverOS, bcc_ptr, len); - - bcc_ptr += len + 1; - bleft -= len + 1; - + /* No domain field in LANMAN case. Domain is + returned by old servers in the SMB negprot response */ + /* BB For newer servers which do not support Unicode, + but thus do return domain here we could add parsing + for it later, but it is not very important */ cFYI(1,("ascii: bytes left %d",bleft)); return rc; @@ -366,6 +365,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, str_area = kmalloc(2000, GFP_KERNEL); bcc_ptr = str_area; + ses->flags &= ~CIFS_SES_LANMAN; + if(type == LANMAN) { #ifdef CONFIG_CIFS_WEAK_PW_HASH char lnm_session_key[CIFS_SESS_KEY_SIZE]; @@ -377,7 +378,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, /* and copy into bcc */ calc_lanman_hash(ses, lnm_session_key); - + ses->flags |= CIFS_SES_LANMAN; /* #ifdef CONFIG_CIFS_DEBUG2 cifs_dump_mem("cryptkey: ",ses->server->cryptKey, CIFS_SESS_KEY_SIZE); From de7ed55dbb2f2c44be669d56c4adf28cbffb26ce Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 30 Sep 2006 13:25:52 +0000 Subject: [PATCH 13/27] [CIFS] Make use of newer QFSInfo dependent on capability bit instead of whether we negotiated legacy lanman dialect so we do not keep retrying for mount to WindowsME Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 2 +- fs/cifs/cifsglob.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index d6d226addde2..43364361276e 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -199,7 +199,7 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf) /* Only need to call the old QFSInfo if failed on newer one */ if(rc) - if((pTcon->ses->flags & CIFS_SES_LANMAN) == 0) + if(pTcon->ses->capabilities & CAP_NT_SMBS) rc = CIFSSMBQFSInfo(xid, pTcon, buf); /* not supported by OS2 */ /* Some old Windows servers also do not support level 103, retry with diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 597afdf4c69c..74d3ccbb103b 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -153,7 +153,7 @@ struct TCP_Server_Info { char sessid[4]; /* unique token id for this session */ /* (returned on Negotiate */ int capabilities; /* allow selective disabling of caps by smb sess */ - __u16 timeAdj; /* Adjust for difference in server time zone in sec */ + int timeAdj; /* Adjust for difference in server time zone in sec */ __u16 CurrentMid; /* multiplex id - rotating counter */ char cryptKey[CIFS_CRYPTO_KEY_SIZE]; /* 16th byte of RFC1001 workstation name is always null */ From 18f75ca0dc0d5b6a2ec15d89d517b3c67e0f1c87 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sun, 1 Oct 2006 03:13:01 +0000 Subject: [PATCH 14/27] [CIFS] Allow LANMAN21 support even in both POSIX non-POSIX path Signed-off-by: Guenter Kukkukk Signed-off-by: Steve French --- fs/cifs/cifssmb.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index f2fa05bbcb47..75f060328e29 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -59,6 +59,7 @@ static struct { } protocols[] = { #ifdef CONFIG_CIFS_WEAK_PW_HASH {LANMAN_PROT, "\2LM1.2X002"}, + {LANMAN2_PROT, "\2LANMAN2.1"}, #endif /* weak password hashing for legacy clients */ {CIFS_PROT, "\2NT LM 0.12"}, {BAD_PROT, "\2"} From 203cf2fc13a5db1fb202c294948fa9cb43bf69fa Mon Sep 17 00:00:00 2001 From: Steve French Date: Sun, 1 Oct 2006 19:59:41 +0000 Subject: [PATCH 15/27] [CIFS] Fix readdir of large directories for backlevel servers (were not setting all of resume key) Signed-off-by: Steve French --- fs/cifs/readdir.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 71e86c38e632..b0e5db10664c 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -946,6 +946,7 @@ static int cifs_save_resume_key(const char *current_entry, filename = &pFindData->FileName[0]; /* one byte length, no name conversion */ len = (unsigned int)pFindData->FileNameLength; + cifsFile->srch_inf.resume_key = pFindData->ResumeKey; } else { cFYI(1,("Unknown findfirst level %d",level)); return -EINVAL; From b815f1e559e7cbdf3e561cf0c7cffc4a4a57a013 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 2 Oct 2006 05:53:29 +0000 Subject: [PATCH 16/27] [CIFS] Allow for 15 minute TZs (e.g. Nepal) and be more explicit about not setting time on close Signed-off-by: Guenter Kukkukk Signed-off-by: Steve French --- fs/cifs/cifspdu.h | 4 +++- fs/cifs/cifssmb.c | 35 ++++++++++++++++++++++------------- 2 files changed, 25 insertions(+), 14 deletions(-) diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 50505422dbb4..6df9dadba647 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -409,6 +409,8 @@ typedef struct negotiate_req { /* Dialect index is 13 for LANMAN */ +#define MIN_TZ_ADJ (15 * 60) /* minimum grid for timezones in seconds */ + typedef struct lanman_neg_rsp { struct smb_hdr hdr; /* wct = 13 */ __le16 DialectIndex; @@ -678,7 +680,7 @@ typedef union smb_com_tree_disconnect { /* as an altetnative can use flag on typedef struct smb_com_close_req { struct smb_hdr hdr; /* wct = 3 */ __u16 FileID; - __u32 LastWriteTime; /* should be zero */ + __u32 LastWriteTime; /* should be zero or -1 */ __u16 ByteCount; /* 0 */ } __attribute__((packed)) CLOSE_REQ; diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 75f060328e29..8d30a5c4f244 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -450,7 +450,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) } else if((pSMBr->hdr.WordCount == 13) && ((pSMBr->DialectIndex == LANMAN_PROT) || (pSMBr->DialectIndex == LANMAN2_PROT))) { - int tmp, adjust; + __s16 tmp; struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr; if((secFlags & CIFSSEC_MAY_LANMAN) || @@ -476,14 +476,16 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) server->maxRw = 0;/* we do not need to use raw anyway */ server->capabilities = CAP_MPX_MODE; } - tmp = le16_to_cpu(rsp->ServerTimeZone); - if (tmp == (int)0xffff) { + tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone); + if (tmp == 0xffff) { /* OS/2 often does not set timezone therefore * we must use server time to calc time zone. - * Could deviate slightly from the right zone. Not easy - * to adjust, since timezones are not always a multiple - * of 60 (sometimes 30 minutes - are there smaller?) + * Could deviate slightly from the right zone. + * Smallest defined timezone difference is 15 minutes + * (i.e. Nepal). Rounding up/down is done to match + * this requirement. */ + int val, seconds, remain, result; struct timespec ts, utc; utc = CURRENT_TIME; ts = cnvrtDosUnixTm(le16_to_cpu(rsp->SrvTime.Date), @@ -491,12 +493,18 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) cFYI(1,("SrvTime: %d sec since 1970 (utc: %d) diff: %d", (int)ts.tv_sec, (int)utc.tv_sec, (int)(utc.tv_sec - ts.tv_sec))); - tmp = (int)(utc.tv_sec - ts.tv_sec); - adjust = tmp < 0 ? -29 : 29; - tmp = ((tmp + adjust) / 60) * 60; - server->timeAdj = tmp; + val = (int)(utc.tv_sec - ts.tv_sec); + seconds = val < 0 ? -val : val; + result = (seconds / IN_TZ_ADJ) * MIN_TZ_ADJ; + remain = seconds % MIN_TZ_ADJ; + if(remain >= (MIN_TZ_ADJ / 2)) + result += MIN_TZ_ADJ; + if(val < 0) + result = - result; + server->timeAdj = result; } else { - server->timeAdj = tmp * 60; /* also in seconds */ + server->timeAdj = (int)tmp; + server->timeAdj *= 60; /* also in seconds */ } cFYI(1,("server->timeAdj: %d seconds", server->timeAdj)); @@ -559,7 +567,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) cFYI(0, ("Max buf = %d", ses->server->maxBuf)); GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); server->capabilities = le32_to_cpu(pSMBr->Capabilities); - server->timeAdj = le16_to_cpu(pSMBr->ServerTimeZone) * 60; + server->timeAdj = (int)(__s16)le16_to_cpu(pSMBr->ServerTimeZone); + server->timeAdj *= 60; if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { memcpy(server->cryptKey, pSMBr->u.EncryptionKey, CIFS_CRYPTO_KEY_SIZE); @@ -1645,7 +1654,7 @@ CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, int smb_file_id) pSMBr = (CLOSE_RSP *)pSMB; /* BB removeme BB */ pSMB->FileID = (__u16) smb_file_id; - pSMB->LastWriteTime = 0; + pSMB->LastWriteTime = 0xFFFFFFFF; pSMB->ByteCount = 0; rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); From 947a50679570ef7a66e3e3107e95943a1cb14d08 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 2 Oct 2006 05:55:25 +0000 Subject: [PATCH 17/27] [CIFS] Fix typo Signed-off-by: Steve French --- fs/cifs/cifssmb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 8d30a5c4f244..005fb315477c 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -495,7 +495,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) (int)(utc.tv_sec - ts.tv_sec))); val = (int)(utc.tv_sec - ts.tv_sec); seconds = val < 0 ? -val : val; - result = (seconds / IN_TZ_ADJ) * MIN_TZ_ADJ; + result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ; remain = seconds % MIN_TZ_ADJ; if(remain >= (MIN_TZ_ADJ / 2)) result += MIN_TZ_ADJ; From 1a70d6529ad9f5978af846440f8a809784d6e813 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 2 Oct 2006 05:59:18 +0000 Subject: [PATCH 18/27] [CIFS] Fix compiler warning with previous patch Signed-off-by: Steve French --- fs/cifs/cifssmb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 005fb315477c..79a01d35a783 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -477,7 +477,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) server->capabilities = CAP_MPX_MODE; } tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone); - if (tmp == 0xffff) { + if (tmp == -1) { /* OS/2 often does not set timezone therefore * we must use server time to calc time zone. * Could deviate slightly from the right zone. From 268f3be177ce93791da38facc34126b5038cd851 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 6 Oct 2006 21:47:09 +0000 Subject: [PATCH 19/27] [CIFS] readdir (ffirst) enablement of accurate timestamps from legacy servers Signed-off-by: Steve French --- fs/cifs/netmisc.c | 39 ++++++++++++++++++--------------------- fs/cifs/readdir.c | 18 +++++++++--------- 2 files changed, 27 insertions(+), 30 deletions(-) diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index fa5124d9af19..3d86b31cf2e4 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -918,45 +918,42 @@ __le64 cnvrtDosCifsTm(__u16 date, __u16 time) { return cpu_to_le64(cifs_UnixTimeToNT(cnvrtDosUnixTm(date, time))); } + struct timespec cnvrtDosUnixTm(__u16 date, __u16 time) { - __u8 dt[2]; - __u8 tm[2]; struct timespec ts; - int sec,min, days, month, year; - struct timespec removeme; /* BB removeme BB */ -/* SMB_TIME * st = (SMB_TIME *)&time;*/ + int sec, min, days, month, year; + SMB_TIME * st = (SMB_TIME *)&time; + SMB_DATE * sd = (SMB_DATE *)&date; cFYI(1,("date %d time %d",date, time)); - dt[0] = date & 0xFF; - dt[1] = (date & 0xFF00) >> 8; - tm[0] = time & 0xFF; - tm[1] = (time & 0xFF00) >> 8; - - sec = tm[0] & 0x1F; - sec = 2 * sec; - min = ((tm[0] >>5)&0xFF) + ((tm[1] & 0x7)<<3); - + sec = 2 * st->TwoSeconds; + min = st->Minutes; + if((sec > 59) || (min > 59)) + cERROR(1,("illegal time min %d sec %d", min, sec)); sec += (min * 60); - sec += 60 * 60 * ((tm[1] >> 3) &0xFF) /* hours */; - days = (dt[0] & 0x1F) - 1; - month = ((dt[0] >> 5) & 0xFF) + ((dt[1] & 0x1) <<3); - if(month > 12) - cERROR(1,("illegal month %d in date", month)); + sec += 60 * 60 * st->Hours; + if(st->Hours > 24) + cERROR(1,("illegal hours %d",st->Hours)); + days = sd->Day; + month = sd->Month; + if((days > 31) || (month > 12)) + cERROR(1,("illegal date, month %d day: %d", month, days)); month -= 1; days += total_days_of_prev_months[month]; days += 3653; /* account for difference in days between 1980 and 1970 */ - year = (dt[1]>>1) & 0xFF; + year = sd->Year; days += year * 365; days += (year/4); /* leap year */ /* adjust for leap year where we are still before leap day */ days -= ((year & 0x03) == 0) && (month < 2 ? 1 : 0); sec += 24 * 60 * 60 * days; - removeme = CURRENT_TIME; /* BB removeme BB */ ts.tv_sec = sec; + /* cFYI(1,("sec after cnvrt dos to unix time %d",sec)); */ + ts.tv_nsec = 0; return ts; } diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index b0e5db10664c..81e7b2e5fb4d 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -139,19 +139,19 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, FIND_FILE_STANDARD_INFO * pfindData = (FIND_FILE_STANDARD_INFO *)buf; -/* ts = cnvrtDosUnixTm( + tmp_inode->i_mtime = cnvrtDosUnixTm( le16_to_cpu(pfindData->LastWriteDate), - le16_to_cpu(pfindData->LastWriteTime));*/ + le16_to_cpu(pfindData->LastWriteTime)); + tmp_inode->i_atime = cnvrtDosUnixTm( + le16_to_cpu(pfindData->LastAccessDate), + le16_to_cpu(pfindData->LastAccessTime)); + tmp_inode->i_ctime = cnvrtDosUnixTm( + le16_to_cpu(pfindData->LastWriteDate), + le16_to_cpu(pfindData->LastWriteTime)); + attr = le16_to_cpu(pfindData->Attributes); allocation_size = le32_to_cpu(pfindData->AllocationSize); end_of_file = le32_to_cpu(pfindData->DataSize); - /* do not need to use current_fs_time helper function since - time not stored for this case so atime can not "go backwards" - by pulling newer older from disk when inode refrenshed */ - tmp_inode->i_atime = CURRENT_TIME; - /* tmp_inode->i_mtime = BB FIXME - add dos time handling - tmp_inode->i_ctime = 0; BB FIXME */ - } /* Linux can not store file creation time unfortunately so ignore it */ From 438dd926260f11ff01fc3441ac6dd4c412d20ea4 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 11 Oct 2006 03:49:30 +0000 Subject: [PATCH 20/27] [CIFS] Fix leaps year calculation for years after 2100 Signed-off-by: Steve French --- fs/cifs/netmisc.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index 3d86b31cf2e4..32562d199552 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -946,6 +946,15 @@ struct timespec cnvrtDosUnixTm(__u16 date, __u16 time) year = sd->Year; days += year * 365; days += (year/4); /* leap year */ + /* generalized leap year calculation is more complex, ie no leap year + for years/100 except for years/400, but since the maximum number for DOS + year is 2**7, the last year is 1980+127, which means we need only + consider 2 special case years, ie the years 2000 and 2100, and only + adjust for the lack of leap year for the year 2100, as 2000 was a + leap year (divisable by 400) */ + if(year >= 120) /* the year 2100 */ + days = days - 1; /* do not count leap year for the year 2100 */ + /* adjust for leap year where we are still before leap day */ days -= ((year & 0x03) == 0) && (month < 2 ? 1 : 0); sec += 24 * 60 * 60 * days; From 70903ca004fef17b0f6483714baefdb2f6ecceb0 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 11 Oct 2006 18:49:24 +0000 Subject: [PATCH 21/27] [CIFS] Do not need to adjust for Jan/Feb for leap day calculation in 2100 (year divisible by 100) Signed-off-by: Yehuda Sadeh Weinraub Signed-off-by: Steve French --- fs/cifs/netmisc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index 32562d199552..3adbd128e08e 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -956,7 +956,8 @@ struct timespec cnvrtDosUnixTm(__u16 date, __u16 time) days = days - 1; /* do not count leap year for the year 2100 */ /* adjust for leap year where we are still before leap day */ - days -= ((year & 0x03) == 0) && (month < 2 ? 1 : 0); + if(year != 120) + days -= ((year & 0x03) == 0) && (month < 2 ? 1 : 0); sec += 24 * 60 * 60 * days; ts.tv_sec = sec; From 533f90af6d90b9e4859a158565385d1d84a79f75 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 12 Oct 2006 00:02:32 +0000 Subject: [PATCH 22/27] [CIFS] Fix old DOS time conversion to handle timezone Signed-off-by: Steve French --- fs/cifs/netmisc.c | 2 +- fs/cifs/readdir.c | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index 3adbd128e08e..992e80edc720 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -942,7 +942,7 @@ struct timespec cnvrtDosUnixTm(__u16 date, __u16 time) cERROR(1,("illegal date, month %d day: %d", month, days)); month -= 1; days += total_days_of_prev_months[month]; - days += 3653; /* account for difference in days between 1980 and 1970 */ + days += 3652; /* account for difference in days between 1980 and 1970 */ year = sd->Year; days += year * 365; days += (year/4); /* leap year */ diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 81e7b2e5fb4d..80e6ebd440a8 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -106,6 +106,17 @@ static int construct_dentry(struct qstr *qstring, struct file *file, return rc; } +static void AdjustForTZ(struct cifsTconInfo * tcon, struct inode * inode) +{ + if((tcon) && (tcon->ses) && (tcon->ses->server)) { + inode->i_ctime.tv_sec += tcon->ses->server.timeAdj; + inode->i_mtime.tv_sec += tcon->ses->server.timeAdj; + inode->i_atime.tv_sec += tcon->ses->server.timeAdj; + } + return; +} + + static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, char * buf, int *pobject_type, int isNewInode) { @@ -148,7 +159,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, tmp_inode->i_ctime = cnvrtDosUnixTm( le16_to_cpu(pfindData->LastWriteDate), le16_to_cpu(pfindData->LastWriteTime)); - + AdjustForTZ(cifs_sb->tcon, tmp_inode); attr = le16_to_cpu(pfindData->Attributes); allocation_size = le32_to_cpu(pfindData->AllocationSize); end_of_file = le32_to_cpu(pfindData->DataSize); From ddae957da48cc381c1472a8909905e1818e4afdd Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 12 Oct 2006 01:23:29 +0000 Subject: [PATCH 23/27] [CIFS] fix typo in previous patch Signed-off-by: Steve French --- fs/cifs/readdir.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 80e6ebd440a8..acbabc09543f 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -109,9 +109,9 @@ static int construct_dentry(struct qstr *qstring, struct file *file, static void AdjustForTZ(struct cifsTconInfo * tcon, struct inode * inode) { if((tcon) && (tcon->ses) && (tcon->ses->server)) { - inode->i_ctime.tv_sec += tcon->ses->server.timeAdj; - inode->i_mtime.tv_sec += tcon->ses->server.timeAdj; - inode->i_atime.tv_sec += tcon->ses->server.timeAdj; + inode->i_ctime.tv_sec += tcon->ses->server->timeAdj; + inode->i_mtime.tv_sec += tcon->ses->server->timeAdj; + inode->i_atime.tv_sec += tcon->ses->server->timeAdj; } return; } From acf1a1b1043327b2179ea529730358e58c7c277e Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 12 Oct 2006 03:28:28 +0000 Subject: [PATCH 24/27] [CIFS] Level 1 QPathInfo needed for proper OS2 support Signed-off-by: Steve French --- fs/cifs/cifsproto.h | 1 + fs/cifs/cifssmb.c | 21 ++++++++++++++++++--- fs/cifs/inode.c | 5 ++++- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 7dd2f48a4073..4a4fd2dbca63 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -119,6 +119,7 @@ extern int CIFSFindClose(const int, struct cifsTconInfo *tcon, extern int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, FILE_ALL_INFO * findData, + int legacy /* whether to use old info level */, const struct nls_table *nls_codepage, int remap); extern int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 79a01d35a783..6f50f2bc8870 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -2969,6 +2969,7 @@ int CIFSSMBQPathInfo(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, FILE_ALL_INFO * pFindData, + int legacy /* old style infolevel */, const struct nls_table *nls_codepage, int remap) { /* level 263 SMB_QUERY_FILE_ALL_INFO */ @@ -3017,7 +3018,10 @@ QPathInfoRetry: byte_count = params + 1 /* pad */ ; pSMB->TotalParameterCount = cpu_to_le16(params); pSMB->ParameterCount = pSMB->TotalParameterCount; - pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO); + if(legacy) + pSMB->InformationLevel = cpu_to_le16(SMB_INFO_STANDARD); + else + pSMB->InformationLevel = cpu_to_le16(SMB_QUERY_FILE_ALL_INFO); pSMB->Reserved4 = 0; pSMB->hdr.smb_buf_length += byte_count; pSMB->ByteCount = cpu_to_le16(byte_count); @@ -3029,13 +3033,24 @@ QPathInfoRetry: } else { /* decode response */ rc = validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || (pSMBr->ByteCount < 40)) + if (rc) /* BB add auto retry on EOPNOTSUPP? */ + rc = -EIO; + else if (!legacy && (pSMBr->ByteCount < 40)) rc = -EIO; /* bad smb */ + else if(legacy && (pSMBr->ByteCount < 24)) + rc = -EIO; /* 24 or 26 expected but we do not read last field */ else if (pFindData){ + int size; __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); + if(legacy) /* we do not read the last field, EAsize, fortunately + since it varies by subdialect and on Set vs. Get, is + two bytes or 4 bytes depending but we don't care here */ + size = sizeof(FILE_INFO_STANDARD); + else + size = sizeof(FILE_ALL_INFO); memcpy((char *) pFindData, (char *) &pSMBr->hdr.Protocol + - data_offset, sizeof (FILE_ALL_INFO)); + data_offset, size); } else rc = -ENOMEM; } diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 06dbce3a1815..fe6d21f99964 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -338,6 +338,7 @@ int cifs_get_inode_info(struct inode **pinode, pfindData = (FILE_ALL_INFO *)buf; /* could do find first instead but this returns more info */ rc = CIFSSMBQPathInfo(xid, pTcon, search_path, pfindData, + 0 /* not legacy */, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); /* BB optimize code so we do not make the above call @@ -385,8 +386,10 @@ int cifs_get_inode_info(struct inode **pinode, /* get new inode */ if (*pinode == NULL) { *pinode = new_inode(sb); - if (*pinode == NULL) + if (*pinode == NULL) { + kfree(buf); return -ENOMEM; + } /* Is an i_ino of zero legal? Can we use that to check if the server supports returning inode numbers? Are there other sanity checks we can use to ensure that From 230a03950ecd63bc613c6adeffbe9049189d9f05 Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Thu, 12 Oct 2006 15:07:55 +0000 Subject: [PATCH 25/27] [CIFS] cifs Kconfig: don't select CONNECTOR `select' is a bit obnoxious: the option keeps on coming back and it's hard to work out what to do to make it go away again. The use of `depends on' is preferred (although it has usability problems too..) Signed-off-by: Andrew Morton Signed-off-by: Steve French --- fs/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/Kconfig b/fs/Kconfig index 530581628311..6865a33544d5 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -1827,7 +1827,7 @@ config CIFS_EXPERIMENTAL config CIFS_UPCALL bool "Kerberos/SPNEGO advanced session setup (EXPERIMENTAL)" depends on CIFS_EXPERIMENTAL - select CONNECTOR + depends on CONNECTOR help Enables an upcall mechanism for CIFS which will be used to contact userspace helper utilities to provide SPNEGO packaged Kerberos From d103e164bee2f21d0efe7d713cbbb0a443ba480d Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 12 Oct 2006 17:49:24 +0000 Subject: [PATCH 26/27] [CIFS] Workaround incomplete byte length returned by some servers on small SMB responses Signed-off-by: Steve French --- fs/cifs/cifsproto.h | 2 +- fs/cifs/misc.c | 42 +++++++++++++++++++++++++++++------------- 2 files changed, 30 insertions(+), 14 deletions(-) diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 4a4fd2dbca63..f1f8225102f0 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -55,7 +55,7 @@ extern int SendReceiveBlockingLock(const unsigned int /* xid */ , struct smb_hdr * /* input */ , struct smb_hdr * /* out */ , int * /* bytes returned */); -extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); +extern int checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length); extern int is_valid_oplock_break(struct smb_hdr *smb, struct TCP_Server_Info *); extern int is_size_safe_to_change(struct cifsInodeInfo *); extern struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *); diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index ca6e9b1413fa..bbc9cd34b6ea 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -418,26 +418,42 @@ checkSMBhdr(struct smb_hdr *smb, __u16 mid) } int -checkSMB(struct smb_hdr *smb, __u16 mid, int length) +checkSMB(struct smb_hdr *smb, __u16 mid, unsigned int length) { __u32 len = smb->smb_buf_length; __u32 clc_len; /* calculated length */ cFYI(0, ("checkSMB Length: 0x%x, smb_buf_length: 0x%x", length, len)); - if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) || - (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)) { - if ((unsigned int)length < 2 + sizeof (struct smb_hdr)) { - if (((unsigned int)length >= - sizeof (struct smb_hdr) - 1) + + if (length < 2 + sizeof (struct smb_hdr)) { + if ((length >= sizeof (struct smb_hdr) - 1) && (smb->Status.CifsError != 0)) { - smb->WordCount = 0; - /* some error cases do not return wct and bcc */ + smb->WordCount = 0; + /* some error cases do not return wct and bcc */ + return 0; + } else if ((length == sizeof(struct smb_hdr) + 1) && + (smb->WordCount == 0)) { + char * tmp = (char *)smb; + /* Need to work around a bug in two servers here */ + /* First, check if the part of bcc they sent was zero */ + if (tmp[sizeof(struct smb_hdr)] == 0) { + /* some servers return only half of bcc + * on simple responses (wct, bcc both zero) + * in particular have seen this on + * ulogoffX and FindClose. This leaves + * one byte of bcc potentially unitialized + */ + /* zero rest of bcc */ + tmp[sizeof(struct smb_hdr)+1] = 0; return 0; - } else { - cERROR(1, ("Length less than smb header size")); } + cERROR(1,("rcvd invalid byte count (bcc)")); + } else { + cERROR(1, ("Length less than smb header size")); } - if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) - cERROR(1, ("smb length greater than MaxBufSize, mid=%d", + return 1; + } + if (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { + cERROR(1, ("smb length greater than MaxBufSize, mid=%d", smb->Mid)); return 1; } @@ -446,7 +462,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length) return 1; clc_len = smbCalcSize_LE(smb); - if(4 + len != (unsigned int)length) { + if(4 + len != length) { cERROR(1, ("Length read does not match RFC1001 length %d",len)); return 1; } From 1a4e15a04ec69cb3552f4120079f5472377df5f7 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 12 Oct 2006 21:33:51 +0000 Subject: [PATCH 27/27] [CIFS] Missing flags2 for DFS Partly suggested by Igor Mammedov Signed-off-by: Steve French --- fs/cifs/cifssmb.c | 8 ++++++++ fs/cifs/connect.c | 4 +++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 6f50f2bc8870..5dc5a966bd5f 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -3675,6 +3675,14 @@ getDFSRetry: strncpy(pSMB->RequestFileName, searchName, name_len); } + if(ses->server) { + if(ses->server->secMode & + (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + } + + pSMB->hdr.Uid = ses->Suid; + params = 2 /* level */ + name_len /*includes null */ ; pSMB->TotalDataCount = 0; pSMB->DataCount = 0; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index c96f3edf1b9c..1d17691086c2 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3219,7 +3219,9 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, } /* else do not bother copying these informational fields */ } - if(smb_buffer_response->WordCount == 3) + if((smb_buffer_response->WordCount == 3) || + (smb_buffer_response->WordCount == 7)) + /* field is in same location */ tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport); else tcon->Flags = 0;