From 26a21b980b1897b11fd7f9ba4bf6060c9e15df10 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 31 May 2006 18:05:34 +0000 Subject: [CIFS] Cleanup extra whitespace in dmesg logging. Update cifs change log --- fs/cifs/CHANGES | 5 ++++- fs/cifs/asn1.c | 10 +++++----- fs/cifs/cifssmb.c | 2 +- fs/cifs/dir.c | 2 +- fs/cifs/file.c | 18 +++++++++--------- fs/cifs/inode.c | 24 ++++++++++++------------ fs/cifs/link.c | 7 +++---- fs/cifs/readdir.c | 2 +- fs/cifs/transport.c | 3 +-- 9 files changed, 37 insertions(+), 36 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 7271bb0..953d2f7 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -3,7 +3,10 @@ Version 1.43 POSIX locking to servers which support CIFS POSIX Extensions (disabled by default controlled by proc/fs/cifs/Experimental). Handle conversion of long share names (especially Asian languages) -to Unicode during mount. +to Unicode during mount. Fix memory leak in sess struct on reconnect. +Fix rare oops after acpi suspend. Fix O_TRUNC opens to overwrite on +cifs open which helps rare case when setpathinfo fails or server does +not support it. Version 1.42 ------------ diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c index 086ae8f..031cdf2 100644 --- a/fs/cifs/asn1.c +++ b/fs/cifs/asn1.c @@ -467,7 +467,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, asn1_open(&ctx, security_blob, length); if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { - cFYI(1, ("Error decoding negTokenInit header ")); + cFYI(1, ("Error decoding negTokenInit header")); return 0; } else if ((cls != ASN1_APL) || (con != ASN1_CON) || (tag != ASN1_EOC)) { @@ -495,7 +495,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, } if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { - cFYI(1, ("Error decoding negTokenInit ")); + cFYI(1, ("Error decoding negTokenInit")); return 0; } else if ((cls != ASN1_CTX) || (con != ASN1_CON) || (tag != ASN1_EOC)) { @@ -505,7 +505,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, } if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { - cFYI(1, ("Error decoding negTokenInit ")); + cFYI(1, ("Error decoding negTokenInit")); return 0; } else if ((cls != ASN1_UNI) || (con != ASN1_CON) || (tag != ASN1_SEQ)) { @@ -515,7 +515,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, } if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { - cFYI(1, ("Error decoding 2nd part of negTokenInit ")); + cFYI(1, ("Error decoding 2nd part of negTokenInit")); return 0; } else if ((cls != ASN1_CTX) || (con != ASN1_CON) || (tag != ASN1_EOC)) { @@ -527,7 +527,7 @@ decode_negTokenInit(unsigned char *security_blob, int length, if (asn1_header_decode (&ctx, &sequence_end, &cls, &con, &tag) == 0) { - cFYI(1, ("Error decoding 2nd part of negTokenInit ")); + cFYI(1, ("Error decoding 2nd part of negTokenInit")); return 0; } else if ((cls != ASN1_UNI) || (con != ASN1_CON) || (tag != ASN1_SEQ)) { diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 925881e..f003692 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -2239,7 +2239,7 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, } symlinkinfo[buflen] = 0; /* just in case so the caller does not go off the end of the buffer */ - cFYI(1,("readlink result - %s ",symlinkinfo)); + cFYI(1,("readlink result - %s",symlinkinfo)); } } qreparse_out: diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 82315ed..57bdf7f 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -191,7 +191,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); } if (rc) { - cFYI(1, ("cifs_create returned 0x%x ", rc)); + cFYI(1, ("cifs_create returned 0x%x", rc)); } else { /* If Open reported that we actually created a file then we now have to set the mode if possible */ diff --git a/fs/cifs/file.c b/fs/cifs/file.c index e2b4ce1..379369e 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -201,7 +201,7 @@ int cifs_open(struct inode *inode, struct file *file) } else { if (file->f_flags & O_EXCL) cERROR(1, ("could not find file instance for " - "new file %p ", file)); + "new file %p", file)); } } @@ -272,7 +272,7 @@ int cifs_open(struct inode *inode, struct file *file) & CIFS_MOUNT_MAP_SPECIAL_CHR); } if (rc) { - cFYI(1, ("cifs_open returned 0x%x ", rc)); + cFYI(1, ("cifs_open returned 0x%x", rc)); goto out; } file->private_data = @@ -409,8 +409,8 @@ static int cifs_reopen_file(struct inode *inode, struct file *file, CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) { up(&pCifsFile->fh_sem); - cFYI(1, ("cifs_open returned 0x%x ", rc)); - cFYI(1, ("oplock: %d ", oplock)); + cFYI(1, ("cifs_open returned 0x%x", rc)); + cFYI(1, ("oplock: %d", oplock)); } else { pCifsFile->netfid = netfid; pCifsFile->invalidHandle = FALSE; @@ -531,7 +531,7 @@ int cifs_closedir(struct inode *inode, struct file *file) (struct cifsFileInfo *)file->private_data; char *ptmp; - cFYI(1, ("Closedir inode = 0x%p with ", inode)); + cFYI(1, ("Closedir inode = 0x%p", inode)); xid = GetXid(); @@ -605,7 +605,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) } if (pfLock->fl_flags & FL_ACCESS) cFYI(1, ("Process suspended by mandatory locking - " - "not implemented yet ")); + "not implemented yet")); if (pfLock->fl_flags & FL_LEASE) cFYI(1, ("Lease on file - not implemented yet")); if (pfLock->fl_flags & @@ -1377,7 +1377,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync) xid = GetXid(); - cFYI(1, ("Sync file - name: %s datasync: 0x%x ", + cFYI(1, ("Sync file - name: %s datasync: 0x%x", dentry->d_name.name, datasync)); rc = filemap_fdatawrite(inode->i_mapping); @@ -1406,7 +1406,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync) /* fill in rpages then result = cifs_pagein_inode(inode, index, rpages); */ /* BB finish */ -/* cFYI(1, ("rpages is %d for sync page of Index %ld ", rpages, index)); +/* cFYI(1, ("rpages is %d for sync page of Index %ld", rpages, index)); #if 0 if (rc < 0) @@ -1838,7 +1838,7 @@ static int cifs_readpage_worker(struct file *file, struct page *page, if (rc < 0) goto io_error; else - cFYI(1, ("Bytes read %d ",rc)); + cFYI(1, ("Bytes read %d",rc)); file->f_dentry->d_inode->i_atime = current_fs_time(file->f_dentry->d_inode->i_sb); diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 4093764..77a9e2f 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -41,7 +41,7 @@ int cifs_get_inode_info_unix(struct inode **pinode, char *tmp_path; pTcon = cifs_sb->tcon; - cFYI(1, ("Getting info on %s ", search_path)); + cFYI(1, ("Getting info on %s", search_path)); /* could have done a find first instead but this returns more info */ rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & @@ -97,9 +97,9 @@ int cifs_get_inode_info_unix(struct inode **pinode, inode = *pinode; cifsInfo = CIFS_I(inode); - cFYI(1, ("Old time %ld ", cifsInfo->time)); + cFYI(1, ("Old time %ld", cifsInfo->time)); cifsInfo->time = jiffies; - cFYI(1, ("New time %ld ", cifsInfo->time)); + cFYI(1, ("New time %ld", cifsInfo->time)); /* this is ok to set on every inode revalidate */ atomic_set(&cifsInfo->inUse,1); @@ -421,23 +421,23 @@ int cifs_get_inode_info(struct inode **pinode, inode = *pinode; cifsInfo = CIFS_I(inode); cifsInfo->cifsAttrs = attr; - cFYI(1, ("Old time %ld ", cifsInfo->time)); + cFYI(1, ("Old time %ld", cifsInfo->time)); cifsInfo->time = jiffies; - cFYI(1, ("New time %ld ", cifsInfo->time)); + cFYI(1, ("New time %ld", cifsInfo->time)); /* blksize needs to be multiple of two. So safer to default to blksize and blkbits set in superblock so 2**blkbits and blksize will match rather than setting to: (pTcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE) & 0xFFFFFE00;*/ - /* Linux can not store file creation time unfortunately so we ignore it */ + /* Linux can not store file creation time so ignore it */ inode->i_atime = cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); inode->i_mtime = cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); inode->i_ctime = cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); - cFYI(0, ("Attributes came in as 0x%x ", attr)); + cFYI(0, ("Attributes came in as 0x%x", attr)); /* set default mode. will override for dirs below */ if (atomic_read(&cifsInfo->inUse) == 0) @@ -731,7 +731,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc) { - cFYI(1, ("cifs_mkdir returned 0x%x ", rc)); + cFYI(1, ("cifs_mkdir returned 0x%x", rc)); d_drop(direntry); } else { inode->i_nlink++; @@ -798,7 +798,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) char *full_path = NULL; struct cifsInodeInfo *cifsInode; - cFYI(1, ("cifs_rmdir, inode = 0x%p with ", inode)); + cFYI(1, ("cifs_rmdir, inode = 0x%p", inode)); xid = GetXid(); @@ -1121,7 +1121,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) xid = GetXid(); - cFYI(1, ("In cifs_setattr, name = %s attrs->iavalid 0x%x ", + cFYI(1, ("In cifs_setattr, name = %s attrs->iavalid 0x%x", direntry->d_name.name, attrs->ia_valid)); cifs_sb = CIFS_SB(direntry->d_inode->i_sb); @@ -1289,7 +1289,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) it may be useful to Windows - but we do not want to set ctime unless some other timestamp is changing */ - cFYI(1, ("CIFS - CTIME changed ")); + cFYI(1, ("CIFS - CTIME changed")); time_buf.ChangeTime = cpu_to_le64(cifs_UnixTimeToNT(attrs->ia_ctime)); } else @@ -1356,7 +1356,7 @@ cifs_setattr_exit: void cifs_delete_inode(struct inode *inode) { - cFYI(1, ("In cifs_delete_inode, inode = 0x%p ", inode)); + cFYI(1, ("In cifs_delete_inode, inode = 0x%p", inode)); /* may have to add back in if and when safe distributed caching of directories added e.g. via FindNotify */ } diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 2ec99f8..a57f5d6 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -167,7 +167,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) return -ENOMEM; } - cFYI(1, ("Full path: %s ", full_path)); + cFYI(1, ("Full path: %s", full_path)); cFYI(1, ("symname is %s", symname)); /* BB what if DFS and this volume is on different share? BB */ @@ -186,8 +186,7 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) inode->i_sb,xid); if (rc != 0) { - cFYI(1, - ("Create symlink worked but get_inode_info failed with rc = %d ", + cFYI(1, ("Create symlink ok, getinodeinfo fail rc = %d", rc)); } else { if (pTcon->nocase) @@ -289,7 +288,7 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) else { cFYI(1,("num referral: %d",num_referrals)); if(referrals) { - cFYI(1,("referral string: %s ",referrals)); + cFYI(1,("referral string: %s",referrals)); strncpy(tmpbuffer, referrals, len-1); } } diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index b689c50..6b36c43 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -909,7 +909,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) case 1: if (filldir(direntry, "..", 2, file->f_pos, file->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) { - cERROR(1, ("Filldir for parent dir failed ")); + cERROR(1, ("Filldir for parent dir failed")); rc = -ENOMEM; break; } diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 3da8040..17ba329 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -654,8 +654,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, if (in_buf->smb_buf_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) { up(&ses->server->tcpSem); - cERROR(1, - ("Illegal length, greater than maximum frame, %d ", + cERROR(1, ("Illegal length, greater than maximum frame, %d", in_buf->smb_buf_length)); DeleteMidQEntry(midQ); /* If not lock req, update # of requests on wire to server */ -- cgit v1.1 From 3979877e5606ecc58c5a31bd0078c6d80ba9cbe7 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 31 May 2006 22:40:51 +0000 Subject: [CIFS] Support for setting up SMB sessions to legacy lanman servers --- fs/cifs/CHANGES | 5 + fs/cifs/Makefile | 2 +- fs/cifs/cifs_debug.c | 84 ++++++-- fs/cifs/cifs_debug.h | 4 + fs/cifs/cifs_unicode.c | 1 + fs/cifs/cifsencrypt.c | 2 + fs/cifs/cifsfs.c | 4 +- fs/cifs/cifsglob.h | 51 +++-- fs/cifs/cifspdu.h | 37 +++- fs/cifs/cifsproto.h | 2 +- fs/cifs/cifssmb.c | 95 ++++++++- fs/cifs/connect.c | 39 ++-- fs/cifs/dir.c | 2 +- fs/cifs/fcntl.c | 4 +- fs/cifs/inode.c | 3 +- fs/cifs/misc.c | 10 +- fs/cifs/readdir.c | 16 +- fs/cifs/sess.c | 511 +++++++++++++++++++++++++++++++++++++++++++++++++ fs/cifs/smbencrypt.c | 1 + 19 files changed, 799 insertions(+), 74 deletions(-) create mode 100644 fs/cifs/sess.c (limited to 'fs/cifs') diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 953d2f7..b878dfc 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -1,3 +1,8 @@ +Version 1.44 +------------ +Rewritten sessionsetup support, including support for legacy SMB +session setup needed for OS/2 and older servers such as Windows 95 and 98. + Version 1.43 ------------ POSIX locking to servers which support CIFS POSIX Extensions diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile index 58c7725..a26f26e 100644 --- a/fs/cifs/Makefile +++ b/fs/cifs/Makefile @@ -3,4 +3,4 @@ # obj-$(CONFIG_CIFS) += cifs.o -cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o ioctl.o ntlmssp.o +cifs-objs := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o link.o misc.o netmisc.o smbdes.o smbencrypt.o transport.o asn1.o md4.o md5.o cifs_unicode.o nterr.o xattr.o cifsencrypt.o fcntl.o readdir.o ioctl.o sess.o diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index f4124a3..7f4013a 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -39,7 +39,7 @@ cifs_dump_mem(char *label, void *data, int length) char *charptr = data; char buf[10], line[80]; - printk(KERN_DEBUG "%s: dump of %d bytes of data at 0x%p\n\n", + printk(KERN_DEBUG "%s: dump of %d bytes of data at 0x%p\n", label, length, data); for (i = 0; i < length; i += 16) { line[0] = 0; @@ -57,6 +57,57 @@ cifs_dump_mem(char *label, void *data, int length) } } +#ifdef CONFIG_CIFS_DEBUG2 +void cifs_dump_detail(struct smb_hdr * smb) +{ + cERROR(1,("Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d", + smb->Command, smb->Status.CifsError, + smb->Flags, smb->Flags2, smb->Mid, smb->Pid)); + cERROR(1,("smb buf %p len %d", smb, smbCalcSize_LE(smb))); +} + + +void cifs_dump_mids(struct TCP_Server_Info * server) +{ + struct list_head *tmp; + struct mid_q_entry * mid_entry; + + if(server == NULL) + return; + + cERROR(1,("Dump pending requests:")); + spin_lock(&GlobalMid_Lock); + list_for_each(tmp, &server->pending_mid_q) { + mid_entry = list_entry(tmp, struct mid_q_entry, qhead); + if(mid_entry) { + cERROR(1,("State: %d Cmd: %d Pid: %d Tsk: %p Mid %d", + mid_entry->midState, + (int)mid_entry->command, + mid_entry->pid, + mid_entry->tsk, + mid_entry->mid)); +#ifdef CONFIG_CIFS_STATS2 + cERROR(1,("IsLarge: %d buf: %p time rcv: %ld now: %ld", + mid_entry->largeBuf, + mid_entry->resp_buf, + mid_entry->when_received, + jiffies)); +#endif /* STATS2 */ + cERROR(1,("IsMult: %d IsEnd: %d", mid_entry->multiRsp, + mid_entry->multiEnd)); + if(mid_entry->resp_buf) { + cifs_dump_detail(mid_entry->resp_buf); + cifs_dump_mem("existing buf: ", + mid_entry->resp_buf, + 62 /* fixme */); + } + + } + } + spin_unlock(&GlobalMid_Lock); +} +#endif /* CONFIG_CIFS_DEBUG2 */ + #ifdef CONFIG_PROC_FS static int cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, @@ -73,7 +124,6 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, *beginBuffer = buf + offset; - length = sprintf(buf, "Display Internal CIFS Data Structures for Debugging\n" @@ -397,10 +447,10 @@ static read_proc_t multiuser_mount_read; static write_proc_t multiuser_mount_write; static read_proc_t extended_security_read; static write_proc_t extended_security_write; -static read_proc_t ntlmv2_enabled_read; +/* static read_proc_t ntlmv2_enabled_read; static write_proc_t ntlmv2_enabled_write; static read_proc_t packet_signing_enabled_read; -static write_proc_t packet_signing_enabled_write; +static write_proc_t packet_signing_enabled_write;*/ static read_proc_t experimEnabled_read; static write_proc_t experimEnabled_write; static read_proc_t linuxExtensionsEnabled_read; @@ -469,7 +519,7 @@ cifs_proc_init(void) if (pde) pde->write_proc = lookupFlag_write; - pde = +/* pde = create_proc_read_entry("NTLMV2Enabled", 0, proc_fs_cifs, ntlmv2_enabled_read, NULL); if (pde) @@ -479,7 +529,7 @@ cifs_proc_init(void) create_proc_read_entry("PacketSigningEnabled", 0, proc_fs_cifs, packet_signing_enabled_read, NULL); if (pde) - pde->write_proc = packet_signing_enabled_write; + pde->write_proc = packet_signing_enabled_write;*/ } void @@ -496,9 +546,9 @@ cifs_proc_clean(void) #endif remove_proc_entry("MultiuserMount", proc_fs_cifs); remove_proc_entry("OplockEnabled", proc_fs_cifs); - remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); +/* remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); */ remove_proc_entry("ExtendedSecurity",proc_fs_cifs); - remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); +/* remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); */ remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs); remove_proc_entry("Experimental",proc_fs_cifs); remove_proc_entry("LookupCacheEnabled",proc_fs_cifs); @@ -787,7 +837,7 @@ extended_security_read(char *page, char **start, off_t off, { int len; - len = sprintf(page, "%d\n", extended_security); + len = sprintf(page, "0x%x\n", extended_security); len -= off; *start = page + off; @@ -808,19 +858,25 @@ extended_security_write(struct file *file, const char __user *buffer, { char c; int rc; + cERROR(1,("size %ld",count)); /* BB removeme BB */ + if((count < 2) || (count > 8)) + return -EINVAL; rc = get_user(c, buffer); + +/* BB fixme need to parse more characters in order to handle CIFSSEC flags */ + if (rc) return rc; if (c == '0' || c == 'n' || c == 'N') - extended_security = 0; + extended_security = CIFSSEC_DEF; /* default */ else if (c == '1' || c == 'y' || c == 'Y') - extended_security = 1; + extended_security = CIFSSEC_MAX; return count; } -static int +/* static int ntlmv2_enabled_read(char *page, char **start, off_t off, int count, int *eof, void *data) { @@ -855,6 +911,8 @@ ntlmv2_enabled_write(struct file *file, const char __user *buffer, ntlmv2_support = 0; else if (c == '1' || c == 'y' || c == 'Y') ntlmv2_support = 1; + else if (c == '2') + ntlmv2_support = 2; return count; } @@ -898,7 +956,7 @@ packet_signing_enabled_write(struct file *file, const char __user *buffer, sign_CIFS_PDUs = 2; return count; -} +} */ #endif diff --git a/fs/cifs/cifs_debug.h b/fs/cifs/cifs_debug.h index 4304d9d..c26cd0d 100644 --- a/fs/cifs/cifs_debug.h +++ b/fs/cifs/cifs_debug.h @@ -24,6 +24,10 @@ #define _H_CIFS_DEBUG void cifs_dump_mem(char *label, void *data, int length); +#ifdef CONFIG_CIFS_DEBUG2 +void cifs_dump_detail(struct smb_hdr *); +void cifs_dump_mids(struct TCP_Server_Info *); +#endif extern int traceSMB; /* flag which enables the function below */ void dump_smb(struct smb_hdr *, int); #define CIFS_INFO 0x01 diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c index d2b1282..d2a8b29 100644 --- a/fs/cifs/cifs_unicode.c +++ b/fs/cifs/cifs_unicode.c @@ -22,6 +22,7 @@ #include "cifs_unicode.h" #include "cifs_uniupr.h" #include "cifspdu.h" +#include "cifsglob.h" #include "cifs_debug.h" /* diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index e7d6373..08781a4 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -225,6 +225,8 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_ user_name_len = strlen(ses->userName); if(user_name_len > MAX_USERNAME_SIZE) return -EINVAL; + if(ses->domainName == NULL) + return -EINVAL; /* BB should we use CIFS_LINUX_DOM */ dom_name_len = strlen(ses->domainName); if(dom_name_len > MAX_USERNAME_SIZE) return -EINVAL; diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index c262d88..7005705 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -56,8 +56,8 @@ unsigned int experimEnabled = 0; unsigned int linuxExtEnabled = 1; unsigned int lookupCacheEnabled = 1; unsigned int multiuser_mount = 0; -unsigned int extended_security = 0; -unsigned int ntlmv2_support = 0; +unsigned int extended_security = CIFSSEC_DEF; +/* unsigned int ntlmv2_support = 0; */ unsigned int sign_CIFS_PDUs = 1; extern struct task_struct * oplockThread; /* remove sparse warning */ struct task_struct * oplockThread = NULL; diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 006eb33..7a04204 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -88,7 +88,8 @@ enum statusEnum { }; enum securityEnum { - NTLM = 0, /* Legacy NTLM012 auth with NTLM hash */ + LANMAN = 0, /* Legacy LANMAN auth */ + NTLM, /* Legacy NTLM012 auth with NTLM hash */ NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */ RawNTLMSSP, /* NTLMSSP without SPNEGO */ NTLMSSP, /* NTLMSSP via SPNEGO */ @@ -179,7 +180,9 @@ struct cifsUidInfo { struct cifsSesInfo { struct list_head cifsSessionList; struct semaphore sesSem; +#if 0 struct cifsUidInfo *uidInfo; /* pointer to user info */ +#endif struct TCP_Server_Info *server; /* pointer to server info */ atomic_t inUse; /* # of mounts (tree connections) on this ses */ enum statusEnum status; @@ -194,7 +197,7 @@ struct cifsSesInfo { char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for TCP names - will ipv6 and sctp addresses fit? */ char userName[MAX_USERNAME_SIZE + 1]; - char domainName[MAX_USERNAME_SIZE + 1]; + char * domainName; char * password; }; /* session flags */ @@ -391,9 +394,9 @@ struct mid_q_entry { struct smb_hdr *resp_buf; /* response buffer */ int midState; /* wish this were enum but can not pass to wait_event */ __u8 command; /* smb command code */ - unsigned multiPart:1; /* multiple responses to one SMB request */ unsigned largeBuf:1; /* if valid response, is pointer to large buf */ - unsigned multiResp:1; /* multiple trans2 responses for one request */ + unsigned multiRsp:1; /* multiple trans2 responses for one request */ + unsigned multiEnd:1; /* both received */ }; struct oplock_q_entry { @@ -430,15 +433,35 @@ struct dir_notify_req { #define CIFS_LARGE_BUFFER 2 #define CIFS_IOVEC 4 /* array of response buffers */ -/* Type of session setup needed */ -#define CIFS_PLAINTEXT 0 -#define CIFS_LANMAN 1 -#define CIFS_NTLM 2 -#define CIFS_NTLMSSP_NEG 3 -#define CIFS_NTLMSSP_AUTH 4 -#define CIFS_SPNEGO_INIT 5 -#define CIFS_SPNEGO_TARG 6 - +/* Security Flags: indicate type of session setup needed */ +#define CIFSSEC_MAY_SIGN 0x00001 +#define CIFSSEC_MAY_NTLM 0x00002 +#define CIFSSEC_MAY_NTLMV2 0x00004 +#define CIFSSEC_MAY_KRB5 0x00008 +#ifdef CONFIG_CIFS_WEAK_PW_HASH +#define CIFSSEC_MAY_LANMAN 0x00010 +#define CIFSSEC_MAY_PLNTXT 0x00020 +#endif /* weak passwords */ +#define CIFSSEC_MAY_SEAL 0x00040 /* not supported yet */ + +#define CIFSSEC_MUST_SIGN 0x01001 +/* note that only one of the following can be set so the +result of setting MUST flags more than once will be to +require use of the stronger protocol */ +#define CIFSSEC_MUST_NTLM 0x02002 +#define CIFSSEC_MUST_NTLMV2 0x04004 +#define CIFSSEC_MUST_KRB5 0x08008 +#ifdef CONFIG_CIFS_WEAK_PW_HASH +#define CIFSSEC_MUST_LANMAN 0x10010 +#define CIFSSEC_MUST_PLNTXT 0x20020 +#define CIFSSEC_MASK 0x37037 /* current flags supported if weak */ +#else +#define CIFSSEC_MASK 0x07007 /* flags supported if no weak config */ +#endif /* WEAK_PW_HASH */ +#define CIFSSEC_MUST_SEAL 0x40040 /* not supported yet */ + +#define CIFSSEC_DEF CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 +#define CIFSSEC_MAX CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2 /* ***************************************************************** * All constants go here @@ -540,8 +563,8 @@ GLOBAL_EXTERN unsigned int experimEnabled; 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 ntlmv2_support; /* better optional password hash */ 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/cifspdu.h b/fs/cifs/cifspdu.h index b2233ac..e0ff9b5 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -16,7 +16,7 @@ * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifndef _CIFSPDU_H @@ -24,8 +24,14 @@ #include +#ifdef CONFIG_CIFS_WEAK_PW_HASH +#define LANMAN_PROT 0 +#define CIFS_PROT 1 +#else #define CIFS_PROT 0 -#define BAD_PROT CIFS_PROT+1 +#endif +#define POSIX_PROT CIFS_PROT+1 +#define BAD_PROT 0xFFFF /* SMB command codes */ /* Some commands have minimal (wct=0,bcc=0), or uninteresting, responses @@ -400,6 +406,25 @@ typedef struct negotiate_req { unsigned char DialectsArray[1]; } __attribute__((packed)) NEGOTIATE_REQ; +/* Dialect index is 13 for LANMAN */ + +typedef struct lanman_neg_rsp { + struct smb_hdr hdr; /* wct = 13 */ + __le16 DialectIndex; + __le16 SecurityMode; + __le16 MaxBufSize; + __le16 MaxMpxCount; + __le16 MaxNumberVcs; + __le16 RawMode; + __le32 SessionKey; + __le32 ServerTime; + __le16 ServerTimeZone; + __le16 EncryptionKeyLength; + __le16 Reserved; + __u16 ByteCount; + unsigned char EncryptionKey[1]; +} __attribute__((packed)) LANMAN_NEG_RSP; + typedef struct negotiate_rsp { struct smb_hdr hdr; /* wct = 17 */ __le16 DialectIndex; @@ -520,8 +545,8 @@ typedef union smb_com_session_setup_andx { __le16 MaxMpxCount; __le16 VcNumber; __u32 SessionKey; - __le16 PassswordLength; - __u32 Reserved; + __le16 PasswordLength; + __u32 Reserved; /* encrypt key len and offset */ __le16 ByteCount; unsigned char AccountPassword[1]; /* followed by */ /* STRING AccountName */ @@ -1844,13 +1869,13 @@ typedef struct { typedef struct { __le32 DeviceType; __le32 DeviceCharacteristics; -} __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO; /* device info, level 0x104 */ +} __attribute__((packed)) FILE_SYSTEM_DEVICE_INFO; /* device info level 0x104 */ typedef struct { __le32 Attributes; __le32 MaxPathNameComponentLength; __le32 FileSystemNameLen; - char FileSystemName[52]; /* do not really need to save this - so potentially get only subset of name */ + char FileSystemName[52]; /* do not have to save this - get subset? */ } __attribute__((packed)) FILE_SYSTEM_ATTRIBUTE_INFO; /******************************************************************************/ diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 310ea2f..ff78cf7 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -69,7 +69,7 @@ extern int small_smb_init_no_tc(const int smb_cmd, const int wct, struct cifsSesInfo *ses, void ** request_buf); extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, - const int stage, int * pNTLMv2_flg, + const int stage, const struct nls_table *nls_cp); #endif extern __u16 GetNextMid(struct TCP_Server_Info *server); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index f003692..da3154f 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -44,8 +44,11 @@ static struct { int index; char *name; } protocols[] = { +#ifdef CONFIG_CIFS_WEAK_PW_HASH + {LANMAN_PROT, "\2LM1.2X002"}, +#endif /* weak password hashing for legacy clients */ {CIFS_PROT, "\2NT LM 0.12"}, - {CIFS_PROT, "\2POSIX 2"}, + {POSIX_PROT, "\2POSIX 2"}, {BAD_PROT, "\2"} }; #else @@ -53,11 +56,29 @@ static struct { int index; char *name; } protocols[] = { +#ifdef CONFIG_CIFS_WEAK_PW_HASH + {LANMAN_PROT, "\2LM1.2X002"}, +#endif /* weak password hashing for legacy clients */ {CIFS_PROT, "\2NT LM 0.12"}, {BAD_PROT, "\2"} }; #endif +/* 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 +#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 +#else +#define CIFS_NUM_PROT 1 +#endif /* CONFIG_CIFS_WEAK_PW_HASH */ +#endif /* CIFS_POSIX */ + /* Mark as invalid, all open files on tree connections since they were closed when session to server was lost */ @@ -322,7 +343,8 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, /* potential retries of smb operations it turns out we can determine */ /* from the mid flags when the request buffer can be resent without */ /* having to use a second distinct buffer for the response */ - *response_buf = *request_buf; + if(response_buf) + *response_buf = *request_buf; header_assemble((struct smb_hdr *) *request_buf, smb_command, tcon, wct /*wct */ ); @@ -373,6 +395,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) NEGOTIATE_RSP *pSMBr; int rc = 0; int bytes_returned; + int i; struct TCP_Server_Info * server; u16 count; @@ -388,19 +411,71 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) return rc; pSMB->hdr.Mid = GetNextMid(server); pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; - if (extended_security) - pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; - - count = strlen(protocols[0].name) + 1; - strncpy(pSMB->DialectsArray, protocols[0].name, 30); - /* null guaranteed to be at end of source and target buffers anyway */ - +/* if (extended_security) + pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;*/ + + count = 0; + for(i=0;iDialectsArray+count, protocols[i].name, 16); + count += strlen(protocols[i].name) + 1; + /* null at end of source and target buffers anyway */ + } pSMB->hdr.smb_buf_length += count; pSMB->ByteCount = cpu_to_le16(count); rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc == 0) { + cFYI(1,("Dialect: %d", pSMBr->DialectIndex)); + /* Check wct = 1 error case */ + if((pSMBr->hdr.WordCount < 13) + || (pSMBr->DialectIndex == BAD_PROT)) { + /* core returns wct = 1, but we do not ask for + core - otherwise it just comes when dialect + index is -1 indicating we could not negotiate + a common dialect */ + rc = -EOPNOTSUPP; + goto neg_err_exit; + } else if((pSMBr->hdr.WordCount == 13) && + (pSMBr->DialectIndex == LANMAN_PROT)) { + struct lanman_neg_rsp * rsp = + (struct lanman_neg_rsp *)pSMBr; + + + /* BB Mark ses struct as negotiated lanman level BB */ + server->secType = LANMAN; + server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode); + server->maxReq = le16_to_cpu(rsp->MaxMpxCount); + server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize), + (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); + + /* BB what do we do with raw mode? BB */ + server->timeZone = le16_to_cpu(rsp->ServerTimeZone); + /* Do we have to set signing flags? no signing + was available LANMAN - default should be ok */ + + /* BB FIXME set default dummy capabilities since + they are not returned by the server in this dialect */ + + /* get server time for time conversions and add + code to use it and timezone since this is not UTC */ + + if (rsp->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { + memcpy(server->cryptKey, rsp->EncryptionKey, + CIFS_CRYPTO_KEY_SIZE); + } else { + rc = -EIO; + goto neg_err_exit; + } + + cFYI(1,("LANMAN negotiated")); /* BB removeme BB */ + goto neg_err_exit; + } else if(pSMBr->hdr.WordCount != 17) { + /* unknown wct */ + rc = -EOPNOTSUPP; + goto neg_err_exit; + } + server->secMode = pSMBr->SecurityMode; if((server->secMode & SECMODE_USER) == 0) cFYI(1,("share mode security")); @@ -479,7 +554,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) } } - +neg_err_exit: cifs_buf_release(pSMB); return rc; } diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index bae1479..7ffb8f2 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -49,8 +49,6 @@ static DECLARE_COMPLETION(cifsd_complete); -extern void SMBencrypt(unsigned char *passwd, unsigned char *c8, - unsigned char *p24); extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); @@ -585,9 +583,11 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) /* merge response - fix up 1st*/ if(coalesce_t2(smb_buffer, mid_entry->resp_buf)) { + mid_entry->multiRsp = 1; break; } else { /* all parts received */ + mid_entry->multiEnd = 1; goto multi_t2_fnd; } } else { @@ -632,9 +632,14 @@ multi_t2_fnd: wake_up_process(task_to_wake); } else if ((is_valid_oplock_break(smb_buffer, server) == FALSE) && (isMultiRsp == FALSE)) { - cERROR(1, ("No task to wake, unknown frame rcvd!")); + cERROR(1, ("No task to wake, unknown frame rcvd! NumMids %d", midCount.counter)); cifs_dump_mem("Received Data is: ",(char *)smb_buffer, sizeof(struct smb_hdr)); +#ifdef CONFIG_CIFS_DEBUG2 + cifs_dump_detail(smb_buffer); + cifs_dump_mids(server); +#endif /* CIFS_DEBUG2 */ + } } /* end while !EXITING */ @@ -976,7 +981,7 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) } /* BB are there cases in which a comma can be valid in a domain name and need special handling? */ - if (strnlen(value, 65) < 65) { + if (strnlen(value, 256) < 256) { vol->domainname = value; cFYI(1, ("Domain name set")); } else { @@ -1762,9 +1767,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, if (volume_info.username) strncpy(pSesInfo->userName, volume_info.username,MAX_USERNAME_SIZE); - if (volume_info.domainname) - strncpy(pSesInfo->domainName, - volume_info.domainname,MAX_USERNAME_SIZE); + if (volume_info.domainname) { + int len = strlen(volume_info.domainname); + pSesInfo->domainName = + kmalloc(len + 1, GFP_KERNEL); + if(pSesInfo->domainName) + strcpy(pSesInfo->domainName, + volume_info.domainname); + } pSesInfo->linux_uid = volume_info.linux_uid; down(&pSesInfo->sesSem); rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls); @@ -2054,7 +2064,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr++; } if(user == NULL) - bytes_returned = 0; /* skill null user */ + bytes_returned = 0; /* skip null user */ else bytes_returned = cifs_strtoUCS((__le16 *) bcc_ptr, user, 100, @@ -2635,8 +2645,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128; if(sign_CIFS_PDUs) negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN; - if(ntlmv2_support) - negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2; +/* if(ntlmv2_support) + negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/ /* setup pointers to domain name and workstation name */ bcc_ptr += SecurityBlobLength; @@ -3429,7 +3439,10 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, } /* else do not bother copying these informational fields */ } - tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport); + if(smb_buffer_response->WordCount == 3) + tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport); + else + tcon->Flags = 0; cFYI(1, ("Tcon flags: 0x%x ", tcon->Flags)); } else if ((rc == 0) && tcon == NULL) { /* all we need to save for IPC$ connection */ @@ -3528,8 +3541,8 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, pSesInfo->server->timeZone)); #ifdef CONFIG_CIFS_EXPERIMENTAL if(experimEnabled > 1) - rc = CIFS_SessSetup(xid, pSesInfo, CIFS_NTLM /* type */, - &ntlmv2_flag, nls_info); + rc = CIFS_SessSetup(xid, pSesInfo, + first_time, nls_info); else #endif if (extended_security diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 57bdf7f..e6ed64e 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -113,7 +113,7 @@ cifs_bp_rename_retry: full_path[namelen+2] = 0; BB remove above eight lines BB */ -/* Inode operations in similar order to how they appear in the Linux file fs.h */ +/* Inode operations in similar order to how they appear in Linux file fs.h */ int cifs_create(struct inode *inode, struct dentry *direntry, int mode, diff --git a/fs/cifs/fcntl.c b/fs/cifs/fcntl.c index 633a938..d91a3d4 100644 --- a/fs/cifs/fcntl.c +++ b/fs/cifs/fcntl.c @@ -91,14 +91,14 @@ int cifs_dir_notify(struct file * file, unsigned long arg) if(full_path == NULL) { rc = -ENOMEM; } else { - cERROR(1,("cifs dir notify on file %s with arg 0x%lx",full_path,arg)); /* BB removeme BB */ + cFYI(1,("dir notify on file %s Arg 0x%lx",full_path,arg)); rc = CIFSSMBOpen(xid, pTcon, full_path, FILE_OPEN, GENERIC_READ | SYNCHRONIZE, 0 /* create options */, &netfid, &oplock,NULL, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); /* BB fixme - add this handle to a notify handle list */ if(rc) { - cERROR(1,("Could not open directory for notify")); /* BB remove BB */ + cFYI(1,("Could not open directory for notify")); } else { filter = convert_to_cifs_notify_flags(arg); if(filter != 0) { diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 77a9e2f..a609d26 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1121,7 +1121,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) xid = GetXid(); - cFYI(1, ("In cifs_setattr, name = %s attrs->iavalid 0x%x", + cFYI(1, ("setattr on file %s attrs->iavalid 0x%x", direntry->d_name.name, attrs->ia_valid)); cifs_sb = CIFS_SB(direntry->d_inode->i_sb); @@ -1157,6 +1157,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) when the local oplock break takes longer to flush writebehind data than the SMB timeout for the SetPathInfo request would allow */ + open_file = find_writable_file(cifsInode); if (open_file) { __u16 nfid = open_file->netfid; diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index fafd056..22c937e 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -101,6 +101,7 @@ sesInfoFree(struct cifsSesInfo *buf_to_free) kfree(buf_to_free->serverDomain); kfree(buf_to_free->serverNOS); kfree(buf_to_free->password); + kfree(buf_to_free->domainName); kfree(buf_to_free); } @@ -499,11 +500,12 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) if(pSMBr->ByteCount > sizeof(struct file_notify_information)) { data_offset = le32_to_cpu(pSMBr->DataOffset); - pnotify = (struct file_notify_information *)((char *)&pSMBr->hdr.Protocol - + data_offset); - cFYI(1,("dnotify on %s with action: 0x%x",pnotify->FileName, + pnotify = (struct file_notify_information *) + ((char *)&pSMBr->hdr.Protocol + data_offset); + cFYI(1,("dnotify on %s Action: 0x%x",pnotify->FileName, pnotify->Action)); /* BB removeme BB */ - /* cifs_dump_mem("Received notify Data is: ",buf,sizeof(struct smb_hdr)+60); */ + /* cifs_dump_mem("Rcvd notify Data: ",buf, + sizeof(struct smb_hdr)+60); */ return TRUE; } if(pSMBr->hdr.Status.CifsError) { diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 6b36c43..53903a2 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -31,8 +31,8 @@ #include "cifs_fs_sb.h" #include "cifsfs.h" -/* BB fixme - add debug wrappers around this function to disable it fixme BB */ -/* static void dump_cifs_file_struct(struct file *file, char *label) +#ifdef CONFIG_CIFS_DEBUG2 +static void dump_cifs_file_struct(struct file *file, char *label) { struct cifsFileInfo * cf; @@ -53,7 +53,8 @@ } } -} */ +} +#endif /* DEBUG2 */ /* Returns one if new inode created (which therefore needs to be hashed) */ /* Might check in the future if inode number changed so we can rehash inode */ @@ -597,7 +598,9 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, . and .. for the root of a drive and for those we need to start two entries earlier */ -/* dump_cifs_file_struct(file, "In fce ");*/ +#ifdef CONFIG_CIFS_DEBUG2 + dump_cifs_file_struct(file, "In fce "); +#endif if(((index_to_find < cifsFile->srch_inf.index_of_last_entry) && is_dir_changed(file)) || (index_to_find < first_entry_in_buffer)) { @@ -980,9 +983,10 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) rc = cifs_filldir(current_entry, file, filldir, direntry,tmp_buf); file->f_pos++; - if(file->f_pos == cifsFile->srch_inf.index_of_last_entry) { + if(file->f_pos == + cifsFile->srch_inf.index_of_last_entry) { cFYI(1,("last entry in buf at pos %lld %s", - file->f_pos,tmp_buf)); /* BB removeme BB */ + file->f_pos,tmp_buf)); cifs_save_resume_key(current_entry,cifsFile); break; } else diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c new file mode 100644 index 0000000..3499841 --- /dev/null +++ b/fs/cifs/sess.c @@ -0,0 +1,511 @@ +/* + * fs/cifs/sess.c + * + * SMB/CIFS session setup handling routines + * + * Copyright (c) International Business Machines Corp., 2006 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifsproto.h" +#include "cifs_unicode.h" +#include "cifs_debug.h" +#include "ntlmssp.h" +#include "nterr.h" +#include + +extern void SMBencrypt(unsigned char *passwd, unsigned char *c8, + unsigned char *p24); + +extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, + unsigned char *p24); + +#ifdef CONFIG_CIFS_EXPERIMENTAL + +static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) +{ + __u32 capabilities = 0; + + /* init fields common to all four types of SessSetup */ + /* note that header is initialized to zero in header_assemble */ + pSMB->req.AndXCommand = 0xFF; + pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); + pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); + + /* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */ + + /* BB verify whether signing required on neg or just on auth frame + (and NTLM case) */ + + capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | + CAP_LARGE_WRITE_X | CAP_LARGE_READ_X; + + if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; + + if (ses->capabilities & CAP_UNICODE) { + pSMB->req.hdr.Flags2 |= SMBFLG2_UNICODE; + capabilities |= CAP_UNICODE; + } + if (ses->capabilities & CAP_STATUS32) { + pSMB->req.hdr.Flags2 |= SMBFLG2_ERR_STATUS; + capabilities |= CAP_STATUS32; + } + if (ses->capabilities & CAP_DFS) { + pSMB->req.hdr.Flags2 |= SMBFLG2_DFS; + capabilities |= CAP_DFS; + } + if (ses->capabilities & CAP_UNIX) { + capabilities |= CAP_UNIX; + } + + /* BB check whether to init vcnum BB */ + return capabilities; +} + +void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, + const struct nls_table * nls_cp) +{ + char * bcc_ptr = *pbcc_area; + int bytes_ret = 0; + + /* BB FIXME add check that strings total less + than 335 or will need to send them as arrays */ + + /* align unicode strings, must be word aligned */ + if ((long) bcc_ptr % 2) { + *bcc_ptr = 0; + bcc_ptr++; + } + /* copy user */ + if(ses->userName == NULL) { + /* BB what about null user mounts - check that we do this BB */ + } else { /* 300 should be long enough for any conceivable user name */ + bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->userName, + 300, nls_cp); + } + bcc_ptr += 2 * bytes_ret; + bcc_ptr += 2; /* account for null termination */ + /* copy domain */ + if(ses->domainName == NULL) + bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, + "CIFS_LINUX_DOM", 32, nls_cp); + else + bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->domainName, + 256, nls_cp); + bcc_ptr += 2 * bytes_ret; + bcc_ptr += 2; /* account for null terminator */ + + /* Copy OS version */ + bytes_ret = cifs_strtoUCS((__le16 *)bcc_ptr, "Linux version ", 32, + nls_cp); + bcc_ptr += 2 * bytes_ret; + bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, + 32, nls_cp); + bcc_ptr += 2 * bytes_ret; + bcc_ptr += 2; /* trailing null */ + + bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, + 32, nls_cp); + bcc_ptr += 2 * bytes_ret; + bcc_ptr += 2; /* trailing null */ + + *pbcc_area = bcc_ptr; +} + +void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, + const struct nls_table * nls_cp) +{ + char * bcc_ptr = *pbcc_area; + + /* copy user */ + /* BB what about null user mounts - check that we do this BB */ + /* copy user */ + if(ses->userName == NULL) { + /* BB what about null user mounts - check that we do this BB */ + } else { /* 300 should be long enough for any conceivable user name */ + strncpy(bcc_ptr, ses->userName, 300); + } + /* BB improve check for overflow */ + bcc_ptr += strnlen(ses->userName, 200); + *bcc_ptr = 0; + bcc_ptr++; /* account for null termination */ + + /* copy domain */ + + if(ses->domainName == NULL) { + strcpy(bcc_ptr, "CIFS_LINUX_DOM"); + bcc_ptr += 14; /* strlen(CIFS_LINUX_DOM) */ + } else { + strncpy(bcc_ptr, ses->domainName, 256); + bcc_ptr += strnlen(ses->domainName, 256); + } + *bcc_ptr = 0; + bcc_ptr++; + + /* BB check for overflow here */ + + strcpy(bcc_ptr, "Linux version "); + bcc_ptr += strlen("Linux version "); + strcpy(bcc_ptr, system_utsname.release); + bcc_ptr += strlen(system_utsname.release) + 1; + + strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); + bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; + + *pbcc_area = bcc_ptr; +} + +int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses, + const struct nls_table * nls_cp) +{ + int rc = 0; + int words_left, len; + char * data = *pbcc_area; + + + + cFYI(1,("bleft %d",bleft)); + + + /* word align, if bytes remaining is not even */ + if(bleft % 2) { + bleft--; + data++; + } + words_left = bleft / 2; + + /* save off server operating system */ + len = UniStrnlen((wchar_t *) data, words_left); + +/* We look for obvious messed up bcc or strings in response so we do not go off + the end since (at least) WIN2K and Windows XP have a major bug in not null + terminating last Unicode string in response */ + if(len >= words_left) + return rc; + + if(ses->serverOS) + kfree(ses->serverOS); + /* UTF-8 string will not grow more than four times as big as UCS-16 */ + ses->serverOS = kzalloc(4 * len, GFP_KERNEL); + if(ses->serverOS != NULL) { + cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len, + nls_cp); + } + data += 2 * (len + 1); + words_left -= len + 1; + + /* save off server network operating system */ + len = UniStrnlen((wchar_t *) data, words_left); + + if(len >= words_left) + return rc; + + if(ses->serverNOS) + kfree(ses->serverNOS); + ses->serverNOS = kzalloc(4 * len, GFP_KERNEL); /* BB this is wrong length FIXME BB */ + if(ses->serverNOS != NULL) { + cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len, + nls_cp); + if(strncmp(ses->serverNOS, "NT LAN Manager 4",16) == 0) { + cFYI(1,("NT4 server")); + ses->flags |= CIFS_SES_NT4; + } + } + data += 2 * (len + 1); + words_left -= len + 1; + + /* save off server domain */ + len = UniStrnlen((wchar_t *) data, words_left); + + if(len > words_left) + return rc; + + if(ses->serverDomain) + kfree(ses->serverDomain); + ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); /* BB FIXME wrong length */ + if(ses->serverDomain != NULL) { + cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len, + nls_cp); + ses->serverDomain[2*len] = 0; + ses->serverDomain[(2*len) + 1] = 0; + } + data += 2 * (len + 1); + words_left -= len + 1; + + cFYI(1,("words left: %d",words_left)); + + return rc; +} + +int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses, + const struct nls_table * nls_cp) +{ + int rc = 0; + int len; + char * bcc_ptr = *pbcc_area; + + cFYI(1,("decode sessetup ascii. bleft %d", bleft)); + + len = strnlen(bcc_ptr, bleft); + if(len >= bleft) + return rc; + + if(ses->serverOS) + kfree(ses->serverOS); + + ses->serverOS = kzalloc(len + 1, GFP_KERNEL); + if(ses->serverOS) + strncpy(ses->serverOS, bcc_ptr, len); + + bcc_ptr += len + 1; + bleft -= len + 1; + + len = strnlen(bcc_ptr, bleft); + if(len >= bleft) + return rc; + + if(ses->serverNOS) + kfree(ses->serverNOS); + + ses->serverNOS = kzalloc(len + 1, GFP_KERNEL); + if(ses->serverNOS) + strncpy(ses->serverNOS, bcc_ptr, len); + + bcc_ptr += len + 1; + bleft -= len + 1; + + len = strnlen(bcc_ptr, bleft); + 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; + + cFYI(1,("ascii: bytes left %d",bleft)); + + return rc; +} + +int +CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, + const struct nls_table *nls_cp) +{ + int rc = 0; + int wct; + int i; + struct smb_hdr *smb_buf; + char *bcc_ptr; + SESSION_SETUP_ANDX *pSMB; + __u32 capabilities; + int count; + int resp_buf_type = 0; + struct kvec iov[1]; + enum securityEnum type; + __u16 action; + int bytes_remaining; + + if(ses == NULL) + return -EINVAL; + + type = ses->server->secType; + if(type == LANMAN) { +#ifndef CONFIG_CIFS_WEAK_PW_HASH + /* LANMAN and plaintext are less secure and off by default. + So we make this explicitly be turned on in kconfig (in the + build) and turned on at runtime (changed from the default) + in proc/fs/cifs or via mount parm. Unfortunately this is + needed for old Win (e.g. Win95), some obscure NAS and OS/2 */ + return -EOPNOTSUPP; +#endif + wct = 10; /* lanman 2 style sessionsetup */ + } else if(type == NTLM) /* NTLMv2 may retry NTLM */ + wct = 13; /* old style NTLM sessionsetup */ + else /* same size for negotiate or auth, NTLMSSP or extended security */ + wct = 12; + + rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses, + (void **)&smb_buf); + if(rc) + return rc; + + pSMB = (SESSION_SETUP_ANDX *)smb_buf; + + capabilities = cifs_ssetup_hdr(ses, pSMB); + bcc_ptr = pByteArea(smb_buf); + + if(type == LANMAN) { +#ifdef CONFIG_CIFS_WEAK_PW_HASH + char lnm_session_key[CIFS_SESSION_KEY_SIZE]; + char password_with_pad[CIFS_ENCPWD_SIZE]; + + /* no capabilities flags in old lanman negotiation */ + + pSMB->old_req.PasswordLength = CIFS_SESSION_KEY_SIZE; + /* BB calculate hash with password */ + /* and copy into bcc */ + + memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); + strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE); + + /* calculate old style session key */ + /* toupper may be less broken then repeatedly calling + nls_toupper would be, but neither handles multibyte code pages + but the only alternative would be converting to UCS-16 (Unicode) + uppercasing and converting back which is only worth doing if + we knew it were utf8. utf8 code page needs its own + toupper and tolower and strnicmp functions */ + + for(i = 0; i< CIFS_ENCPWD_SIZE; i++) { + password_with_pad[i] = toupper(password_with_pad[i]); + } + + SMBencrypt(password_with_pad, ses->server->cryptKey, + lnm_session_key); + +#ifdef CONFIG_CIFS_DEBUG2 + cifs_dump_mem("cryptkey: ",ses->server->cryptKey, + CIFS_SESSION_KEY_SIZE); +#endif + /* clear password before we return/free memory */ + memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); + memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESSION_KEY_SIZE); + bcc_ptr += CIFS_SESSION_KEY_SIZE; + + /* can not sign if LANMAN negotiated so no need + to calculate signing key? but what if server + changed to do higher than lanman dialect and + we reconnected would we ever calc signing_key? */ + + cERROR(1,("Negotiating LANMAN setting up strings")); + /* Unicode not allowed for LANMAN dialects */ + ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); +#endif + } else if (type == NTLM) { + char ntlm_session_key[CIFS_SESSION_KEY_SIZE]; + + pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); + pSMB->req_no_secext.CaseInsensitivePasswordLength = + cpu_to_le16(CIFS_SESSION_KEY_SIZE); + pSMB->req_no_secext.CaseSensitivePasswordLength = + cpu_to_le16(CIFS_SESSION_KEY_SIZE); + + /* calculate session key */ + SMBNTencrypt(ses->password, ses->server->cryptKey, + ntlm_session_key); + + if(first_time) /* should this be moved into common code + with similar ntlmv2 path? */ + cifs_calculate_mac_key( + ses->server->mac_signing_key, + ntlm_session_key, ses->password); + /* copy session key */ + + memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESSION_KEY_SIZE); + bcc_ptr += CIFS_SESSION_KEY_SIZE; + memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESSION_KEY_SIZE); + bcc_ptr += CIFS_SESSION_KEY_SIZE; + if(ses->capabilities & CAP_UNICODE) + unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); + else + ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); + } else /* NTLMSSP or SPNEGO */ { + pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; + capabilities |= CAP_EXTENDED_SECURITY; + pSMB->req.Capabilities = cpu_to_le32(capabilities); + /* BB set password lengths */ + } + + count = (long) bcc_ptr - (long) pByteArea(smb_buf); + smb_buf->smb_buf_length += count; + + /* if we switch to small buffers, count will need to be fewer + than 383 (strings less than 335 bytes) */ + + BCC_LE(smb_buf) = cpu_to_le16(count); + + + /* BB FIXME check for other non ntlm code paths */ + + /* BB check is this too big for a small smb? */ + + iov[0].iov_base = (char *)pSMB; + iov[0].iov_len = smb_buf->smb_buf_length + 4; + + rc = SendReceive2(xid, ses, iov, 1 /* num_iovecs */, &resp_buf_type, 0); + /* SMB request buf freed in SendReceive2 */ + + cFYI(1,("ssetup rc from sendrecv2 is %d",rc)); + if(rc) + goto ssetup_exit; + + pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base; + smb_buf = (struct smb_hdr *)iov[0].iov_base; + + if((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) { + rc = -EIO; + cERROR(1,("bad word count %d", smb_buf->WordCount)); + goto ssetup_exit; + } + action = le16_to_cpu(pSMB->resp.Action); + if (action & GUEST_LOGIN) + cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */ + ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */ + cFYI(1, ("UID = %d ", ses->Suid)); + /* response can have either 3 or 4 word count - Samba sends 3 */ + /* and lanman response is 3 */ + bytes_remaining = BCC(smb_buf); + bcc_ptr = pByteArea(smb_buf); + + if(smb_buf->WordCount == 4) { + __u16 blob_len; + blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength); + bcc_ptr += blob_len; + if(blob_len > bytes_remaining) { + cERROR(1,("bad security blob length %d", blob_len)); + rc = -EINVAL; + goto ssetup_exit; + } + bytes_remaining -= blob_len; + } + + /* BB check if Unicode and decode strings */ + if(smb_buf->Flags2 & SMBFLG2_UNICODE) + rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining, + ses, nls_cp); + else + rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,nls_cp); + +ssetup_exit: + if(resp_buf_type == CIFS_SMALL_BUFFER) { + cFYI(1,("ssetup freeing small buf %p", iov[0].iov_base)); + cifs_small_buf_release(iov[0].iov_base); + } else if(resp_buf_type == CIFS_LARGE_BUFFER) + cifs_buf_release(iov[0].iov_base); + + return rc; +} +#endif /* CONFIG_CIFS_EXPERIMENTAL */ diff --git a/fs/cifs/smbencrypt.c b/fs/cifs/smbencrypt.c index 6103bcd..f518c5e 100644 --- a/fs/cifs/smbencrypt.c +++ b/fs/cifs/smbencrypt.c @@ -30,6 +30,7 @@ #include #include "cifs_unicode.h" #include "cifspdu.h" +#include "cifsglob.h" #include "md5.h" #include "cifs_debug.h" #include "cifsencrypt.h" -- cgit v1.1 From 9c53588ec96d85f82e9bf3fb1af7cca31056e940 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 1 Jun 2006 05:09:10 +0000 Subject: [CIFS] Missing include shows up on some architectures Signed-off-by: Steve French --- fs/cifs/cifsfs.h | 2 +- fs/cifs/ntlmssp.c | 143 ------------------------------------------------------ fs/cifs/sess.c | 1 + 3 files changed, 2 insertions(+), 144 deletions(-) delete mode 100644 fs/cifs/ntlmssp.c (limited to 'fs/cifs') diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index c98755d..2fc6d65 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -99,5 +99,5 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); extern int cifs_ioctl (struct inode * inode, struct file * filep, unsigned int command, unsigned long arg); -#define CIFS_VERSION "1.43" +#define CIFS_VERSION "1.44" #endif /* _CIFSFS_H */ diff --git a/fs/cifs/ntlmssp.c b/fs/cifs/ntlmssp.c deleted file mode 100644 index 115359c..0000000 --- a/fs/cifs/ntlmssp.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * fs/cifs/ntlmssp.h - * - * Copyright (c) International Business Machines Corp., 2006 - * Author(s): Steve French (sfrench@us.ibm.com) - * - * This library is free software; you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published - * by the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See - * the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "cifspdu.h" -#include "cifsglob.h" -#include "cifsproto.h" -#include "cifs_unicode.h" -#include "cifs_debug.h" -#include "ntlmssp.h" -#include "nterr.h" - -#ifdef CONFIG_CIFS_EXPERIMENTAL -static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) -{ - __u32 capabilities = 0; - - /* init fields common to all four types of SessSetup */ - /* note that header is initialized to zero in header_assemble */ - pSMB->req.AndXCommand = 0xFF; - pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); - pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); - - /* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */ - - /* BB verify whether signing required on neg or just on auth frame - (and NTLM case) */ - - capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | - CAP_LARGE_WRITE_X | CAP_LARGE_READ_X; - - if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) - pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; - - if (ses->capabilities & CAP_UNICODE) { - pSMB->req.hdr.Flags2 |= SMBFLG2_UNICODE; - capabilities |= CAP_UNICODE; - } - if (ses->capabilities & CAP_STATUS32) { - pSMB->req.hdr.Flags2 |= SMBFLG2_ERR_STATUS; - capabilities |= CAP_STATUS32; - } - if (ses->capabilities & CAP_DFS) { - pSMB->req.hdr.Flags2 |= SMBFLG2_DFS; - capabilities |= CAP_DFS; - } - - /* BB check whether to init vcnum BB */ - return capabilities; -} -int -CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, const int type, - int * pNTLMv2_flg, const struct nls_table *nls_cp) -{ - int rc = 0; - int wct; - struct smb_hdr *smb_buffer; - char *bcc_ptr; - SESSION_SETUP_ANDX *pSMB; - __u32 capabilities; - - if(ses == NULL) - return -EINVAL; - - cFYI(1,("SStp type: %d",type)); - if(type < CIFS_NTLM) { -#ifndef CONFIG_CIFS_WEAK_PW_HASH - /* LANMAN and plaintext are less secure and off by default. - So we make this explicitly be turned on in kconfig (in the - build) and turned on at runtime (changed from the default) - in proc/fs/cifs or via mount parm. Unfortunately this is - needed for old Win (e.g. Win95), some obscure NAS and OS/2 */ - return -EOPNOTSUPP; -#endif - wct = 10; /* lanman 2 style sessionsetup */ - } else if(type < CIFS_NTLMSSP_NEG) - wct = 13; /* old style NTLM sessionsetup */ - else /* same size for negotiate or auth, NTLMSSP or extended security */ - wct = 12; - - rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses, - (void **)&smb_buffer); - if(rc) - return rc; - - pSMB = (SESSION_SETUP_ANDX *)smb_buffer; - - capabilities = cifs_ssetup_hdr(ses, pSMB); - bcc_ptr = pByteArea(smb_buffer); - if(type > CIFS_NTLM) { - pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; - capabilities |= CAP_EXTENDED_SECURITY; - pSMB->req.Capabilities = cpu_to_le32(capabilities); - /* BB set password lengths */ - } else if(type < CIFS_NTLM) /* lanman */ { - /* no capabilities flags in old lanman negotiation */ - /* pSMB->old_req.PasswordLength = */ /* BB fixme BB */ - } else /* type CIFS_NTLM */ { - pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); - pSMB->req_no_secext.CaseInsensitivePasswordLength = - cpu_to_le16(CIFS_SESSION_KEY_SIZE); - pSMB->req_no_secext.CaseSensitivePasswordLength = - cpu_to_le16(CIFS_SESSION_KEY_SIZE); - } - - - /* copy session key */ - - /* if Unicode, align strings to two byte boundary */ - - /* copy user name */ /* BB Do we need to special case null user name? */ - - /* copy domain name */ - - /* copy Linux version */ - - /* copy network operating system name */ - - /* update bcc and smb buffer length */ - -/* rc = SendReceive2(xid, ses, iov, num_iovecs, &resp_buf_type, 0); */ - /* SMB request buf freed in SendReceive2 */ - - return rc; -} -#endif /* CONFIG_CIFS_EXPERIMENTAL */ diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 3499841..fdc248f 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -29,6 +29,7 @@ #include "ntlmssp.h" #include "nterr.h" #include +#include extern void SMBencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); -- cgit v1.1 From 7c7b25bc8e392aea781324efa771bc191377b876 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 1 Jun 2006 19:20:10 +0000 Subject: [CIFS] Support for setting up SMB sessions to legacy lanman servers part 2 --- fs/cifs/cifs_debug.c | 4 +-- fs/cifs/cifsencrypt.c | 40 +++++++++++++++++++-- fs/cifs/cifsglob.h | 2 +- fs/cifs/cifspdu.h | 3 +- fs/cifs/cifsproto.h | 3 ++ fs/cifs/cifssmb.c | 27 +++++++++++--- fs/cifs/connect.c | 47 +++++++++++++++---------- fs/cifs/netmisc.c | 2 +- fs/cifs/sess.c | 97 ++++++++++++++++++++++++++++----------------------- 9 files changed, 150 insertions(+), 75 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 7f4013a..4e10e21 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -508,7 +508,7 @@ cifs_proc_init(void) pde->write_proc = multiuser_mount_write; pde = - create_proc_read_entry("ExtendedSecurity", 0, proc_fs_cifs, + create_proc_read_entry("SecurityFlags", 0, proc_fs_cifs, extended_security_read, NULL); if (pde) pde->write_proc = extended_security_write; @@ -547,7 +547,7 @@ cifs_proc_clean(void) remove_proc_entry("MultiuserMount", proc_fs_cifs); remove_proc_entry("OplockEnabled", proc_fs_cifs); /* remove_proc_entry("NTLMV2Enabled",proc_fs_cifs); */ - remove_proc_entry("ExtendedSecurity",proc_fs_cifs); + remove_proc_entry("SecurityFlags",proc_fs_cifs); /* remove_proc_entry("PacketSigningEnabled",proc_fs_cifs); */ remove_proc_entry("LinuxExtensionsEnabled",proc_fs_cifs); remove_proc_entry("Experimental",proc_fs_cifs); diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 08781a4..e11d8c6 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -26,6 +26,7 @@ #include "md5.h" #include "cifs_unicode.h" #include "cifsproto.h" +#include /* Calculate and return the CIFS signature based on the mac key and the smb pdu */ /* the 16 byte signature must be allocated by the caller */ @@ -35,6 +36,8 @@ extern void mdfour(unsigned char *out, unsigned char *in, int n); extern void E_md4hash(const unsigned char *passwd, unsigned char *p16); +extern void SMBencrypt(unsigned char *passwd, unsigned char *c8, + unsigned char *p24); static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, const char * key, char * signature) @@ -45,7 +48,7 @@ static int cifs_calculate_signature(const struct smb_hdr * cifs_pdu, return -EINVAL; MD5Init(&context); - MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16); + MD5Update(&context,key,CIFS_SESS_KEY_SIZE+16); MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length); MD5Final(signature,&context); return 0; @@ -90,7 +93,7 @@ static int cifs_calc_signature2(const struct kvec * iov, int n_vec, return -EINVAL; MD5Init(&context); - MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16); + MD5Update(&context,key,CIFS_SESS_KEY_SIZE+16); for(i=0;ipassword, CIFS_ENCPWD_SIZE); + + /* calculate old style session key */ + /* calling toupper is less broken than repeatedly + calling nls_toupper would be since that will never + work for UTF8, but neither handles multibyte code pages + but the only alternative would be converting to UCS-16 (Unicode) + (using a routine something like UniStrupr) then + uppercasing and then converting back from Unicode - which + would only worth doing it if we knew it were utf8. Basically + utf8 and other multibyte codepages each need their own strupper + function since a byte at a time will ont work. */ + + for(i = 0; i < CIFS_ENCPWD_SIZE; i++) { + password_with_pad[i] = toupper(password_with_pad[i]); + } + + SMBencrypt(password_with_pad, ses->server->cryptKey, lnm_session_key); + /* clear password before we return/free memory */ + memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); +} +#endif /* CIFS_WEAK_PW_HASH */ + void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response) { struct HMACMD5Context context; diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 7a04204..975e69a 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -158,7 +158,7 @@ struct TCP_Server_Info { /* 16th byte of RFC1001 workstation name is always null */ char workstation_RFC1001_name[SERVER_NAME_LEN_WITH_NULL]; __u32 sequence_number; /* needed for CIFS PDU signature */ - char mac_signing_key[CIFS_SESSION_KEY_SIZE + 16]; + char mac_signing_key[CIFS_SESS_KEY_SIZE + 16]; }; /* diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index e0ff9b5..1359417 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -116,7 +116,8 @@ /* * Size of the session key (crypto key encrypted with the password */ -#define CIFS_SESSION_KEY_SIZE (24) +#define CIFS_SESS_KEY_SIZE (24) +#define V2_SESS_KEY_SIZE (86) /* * Maximum user name length diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index ff78cf7..59b037f 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -287,6 +287,9 @@ extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key, extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass); extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, struct nls_table *); extern void CalcNTLMv2_response(const struct cifsSesInfo *,char * ); +#ifdef CONFIG_CIFS_WEAK_PW_HASH +extern void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key); +#endif /* CIFS_WEAK_PW_HASH */ extern int CIFSSMBCopy(int xid, struct cifsTconInfo *source_tcon, const char *fromName, diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index da3154f..6b5be6d 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -438,12 +438,19 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) goto neg_err_exit; } else if((pSMBr->hdr.WordCount == 13) && (pSMBr->DialectIndex == LANMAN_PROT)) { +#ifdef CONFIG_CIFS_WEAK_PW_HASH struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr; - - /* BB Mark ses struct as negotiated lanman level BB */ - server->secType = LANMAN; + if((extended_security & CIFSSEC_MAY_LANMAN) || + (extended_security & CIFSSEC_MAY_PLNTXT)) + server->secType = LANMAN; + else { + cERROR(1, ("mount failed weak security disabled" + " in /proc/fs/cifs/SecurityFlags")); + rc = -EOPNOTSUPP; + goto neg_err_exit; + } server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode); server->maxReq = le16_to_cpu(rsp->MaxMpxCount); server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize), @@ -469,6 +476,11 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) } cFYI(1,("LANMAN negotiated")); /* BB removeme BB */ +#else /* weak security disabled */ + cERROR(1,("mount failed, cifs module not built with " + "CIFS_WEAK_PW_HASH support")); + rc = -EOPNOTSUPP; +#endif /* WEAK_PW_HASH */ goto neg_err_exit; } else if(pSMBr->hdr.WordCount != 17) { /* unknown wct */ @@ -479,8 +491,13 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) server->secMode = pSMBr->SecurityMode; if((server->secMode & SECMODE_USER) == 0) cFYI(1,("share mode security")); - server->secType = NTLM; /* BB override default for - NTLMv2 or kerberos v5 */ + + if(extended_security & CIFSSEC_MUST_NTLMV2) + server->secType = NTLMv2; + else + server->secType = NTLM; + /* else krb5 ... */ + /* one byte - no need to convert this or EncryptionKeyLen from little endian */ server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 7ffb8f2..e6f3d2f 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1990,7 +1990,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, static int CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, - char session_key[CIFS_SESSION_KEY_SIZE], + char session_key[CIFS_SESS_KEY_SIZE], const struct nls_table *nls_codepage) { struct smb_hdr *smb_buffer; @@ -2048,15 +2048,15 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); pSMB->req_no_secext.CaseInsensitivePasswordLength = - cpu_to_le16(CIFS_SESSION_KEY_SIZE); + cpu_to_le16(CIFS_SESS_KEY_SIZE); pSMB->req_no_secext.CaseSensitivePasswordLength = - cpu_to_le16(CIFS_SESSION_KEY_SIZE); + cpu_to_le16(CIFS_SESS_KEY_SIZE); bcc_ptr = pByteArea(smb_buffer); - memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE); - bcc_ptr += CIFS_SESSION_KEY_SIZE; - memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE); - bcc_ptr += CIFS_SESSION_KEY_SIZE; + memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE); + bcc_ptr += CIFS_SESS_KEY_SIZE; + memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE); + bcc_ptr += CIFS_SESS_KEY_SIZE; if (ses->capabilities & CAP_UNICODE) { if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */ @@ -3004,14 +3004,14 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, SecurityBlob->LmChallengeResponse.Buffer = 0; SecurityBlob->NtChallengeResponse.Length = - cpu_to_le16(CIFS_SESSION_KEY_SIZE); + cpu_to_le16(CIFS_SESS_KEY_SIZE); SecurityBlob->NtChallengeResponse.MaximumLength = - cpu_to_le16(CIFS_SESSION_KEY_SIZE); - memcpy(bcc_ptr, ntlm_session_key, CIFS_SESSION_KEY_SIZE); + cpu_to_le16(CIFS_SESS_KEY_SIZE); + memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE); SecurityBlob->NtChallengeResponse.Buffer = cpu_to_le32(SecurityBlobLength); - SecurityBlobLength += CIFS_SESSION_KEY_SIZE; - bcc_ptr += CIFS_SESSION_KEY_SIZE; + SecurityBlobLength += CIFS_SESS_KEY_SIZE; + bcc_ptr += CIFS_SESS_KEY_SIZE; if (ses->capabilities & CAP_UNICODE) { if (domain == NULL) { @@ -3350,22 +3350,33 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr = &pSMB->Password[0]; if((ses->server->secMode) & SECMODE_USER) { pSMB->PasswordLength = cpu_to_le16(1); /* minimum */ + *bcc_ptr = 0; /* password is null byte */ bcc_ptr++; /* skip password */ + /* already aligned so no need to do it below */ } else { - pSMB->PasswordLength = cpu_to_le16(CIFS_SESSION_KEY_SIZE); + pSMB->PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE); /* BB FIXME add code to fail this if NTLMv2 or Kerberos specified as required (when that support is added to the vfs in the future) as only NTLM or the much - weaker LANMAN (which we do not send) is accepted + weaker LANMAN (which we do not send by default) is accepted by Samba (not sure whether other servers allow NTLMv2 password here) */ +#ifdef CONFIG_CIFS_WEAK_PW_HASH + if((extended_security & CIFSSEC_MAY_LANMAN) && + (ses->server->secType == LANMAN)) + calc_lanman_hash(ses, bcc_ptr); + else +#endif /* CIFS_WEAK_PW_HASH */ SMBNTencrypt(ses->password, ses->server->cryptKey, bcc_ptr); - bcc_ptr += CIFS_SESSION_KEY_SIZE; - *bcc_ptr = 0; - bcc_ptr++; /* align */ + bcc_ptr += CIFS_SESS_KEY_SIZE; + if(ses->capabilities & CAP_UNICODE) { + /* must align unicode strings */ + *bcc_ptr = 0; /* null byte password */ + bcc_ptr++; + } } if(ses->server->secMode & @@ -3507,7 +3518,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, struct nls_table * nls_info) { int rc = 0; - char ntlm_session_key[CIFS_SESSION_KEY_SIZE]; + char ntlm_session_key[CIFS_SESS_KEY_SIZE]; int ntlmv2_flag = FALSE; int first_time = 0; diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index 5de74d2..a0bcdd6 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -84,7 +84,7 @@ static const struct smb_to_posix_error mapping_table_ERRDOS[] = { static const struct smb_to_posix_error mapping_table_ERRSRV[] = { {ERRerror, -EIO}, - {ERRbadpw, -EPERM}, + {ERRbadpw, -EACCES}, /* was EPERM */ {ERRbadtype, -EREMOTE}, {ERRaccess, -EACCES}, {ERRinvtid, -ENXIO}, diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index fdc248f..a52aacb 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -28,12 +28,8 @@ #include "cifs_debug.h" #include "ntlmssp.h" #include "nterr.h" -#include #include -extern void SMBencrypt(unsigned char *passwd, unsigned char *c8, - unsigned char *p24); - extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); @@ -80,7 +76,7 @@ static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) return capabilities; } -void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, +static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, const struct nls_table * nls_cp) { char * bcc_ptr = *pbcc_area; @@ -130,7 +126,7 @@ void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, *pbcc_area = bcc_ptr; } -void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, +static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, const struct nls_table * nls_cp) { char * bcc_ptr = *pbcc_area; @@ -173,7 +169,7 @@ void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, *pbcc_area = bcc_ptr; } -int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses, +static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses, const struct nls_table * nls_cp) { int rc = 0; @@ -255,7 +251,7 @@ int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses, return rc; } -int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses, +static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses, const struct nls_table * nls_cp) { int rc = 0; @@ -317,7 +313,6 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, { int rc = 0; int wct; - int i; struct smb_hdr *smb_buf; char *bcc_ptr; SESSION_SETUP_ANDX *pSMB; @@ -343,7 +338,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, return -EOPNOTSUPP; #endif wct = 10; /* lanman 2 style sessionsetup */ - } else if(type == NTLM) /* NTLMv2 may retry NTLM */ + } else if((type == NTLM) || (type == NTLMv2)) /* NTLMv2 may retry NTLM */ wct = 13; /* old style NTLM sessionsetup */ else /* same size for negotiate or auth, NTLMSSP or extended security */ wct = 12; @@ -360,41 +355,22 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, if(type == LANMAN) { #ifdef CONFIG_CIFS_WEAK_PW_HASH - char lnm_session_key[CIFS_SESSION_KEY_SIZE]; - char password_with_pad[CIFS_ENCPWD_SIZE]; + char lnm_session_key[CIFS_SESS_KEY_SIZE]; /* no capabilities flags in old lanman negotiation */ - pSMB->old_req.PasswordLength = CIFS_SESSION_KEY_SIZE; + pSMB->old_req.PasswordLength = CIFS_SESS_KEY_SIZE; /* BB calculate hash with password */ /* and copy into bcc */ - memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); - strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE); - - /* calculate old style session key */ - /* toupper may be less broken then repeatedly calling - nls_toupper would be, but neither handles multibyte code pages - but the only alternative would be converting to UCS-16 (Unicode) - uppercasing and converting back which is only worth doing if - we knew it were utf8. utf8 code page needs its own - toupper and tolower and strnicmp functions */ - - for(i = 0; i< CIFS_ENCPWD_SIZE; i++) { - password_with_pad[i] = toupper(password_with_pad[i]); - } - - SMBencrypt(password_with_pad, ses->server->cryptKey, - lnm_session_key); + calc_lanman_hash(ses, lnm_session_key); #ifdef CONFIG_CIFS_DEBUG2 cifs_dump_mem("cryptkey: ",ses->server->cryptKey, - CIFS_SESSION_KEY_SIZE); + CIFS_SESS_KEY_SIZE); #endif - /* clear password before we return/free memory */ - memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); - memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESSION_KEY_SIZE); - bcc_ptr += CIFS_SESSION_KEY_SIZE; + memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESS_KEY_SIZE); + bcc_ptr += CIFS_SESS_KEY_SIZE; /* can not sign if LANMAN negotiated so no need to calculate signing key? but what if server @@ -406,13 +382,13 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); #endif } else if (type == NTLM) { - char ntlm_session_key[CIFS_SESSION_KEY_SIZE]; + char ntlm_session_key[CIFS_SESS_KEY_SIZE]; pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); pSMB->req_no_secext.CaseInsensitivePasswordLength = - cpu_to_le16(CIFS_SESSION_KEY_SIZE); + cpu_to_le16(CIFS_SESS_KEY_SIZE); pSMB->req_no_secext.CaseSensitivePasswordLength = - cpu_to_le16(CIFS_SESSION_KEY_SIZE); + cpu_to_le16(CIFS_SESS_KEY_SIZE); /* calculate session key */ SMBNTencrypt(ses->password, ses->server->cryptKey, @@ -420,15 +396,48 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, if(first_time) /* should this be moved into common code with similar ntlmv2 path? */ - cifs_calculate_mac_key( - ses->server->mac_signing_key, + cifs_calculate_mac_key( ses->server->mac_signing_key, ntlm_session_key, ses->password); /* copy session key */ - memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESSION_KEY_SIZE); - bcc_ptr += CIFS_SESSION_KEY_SIZE; - memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESSION_KEY_SIZE); - bcc_ptr += CIFS_SESSION_KEY_SIZE; + memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESS_KEY_SIZE); + bcc_ptr += CIFS_SESS_KEY_SIZE; + memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESS_KEY_SIZE); + bcc_ptr += CIFS_SESS_KEY_SIZE; + if(ses->capabilities & CAP_UNICODE) + unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); + else + ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); + } else if (type == NTLMv2) { + char * v2_sess_key = kmalloc(V2_SESS_KEY_SIZE, GFP_KERNEL); + + if(v2_sess_key == NULL) { + cifs_small_buf_release(smb_buf); + return -ENOMEM; + } + + pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); + + /* LM2 password would be here if we supported it */ + pSMB->req_no_secext.CaseInsensitivePasswordLength = 0; + /* cpu_to_le16(LM2_SESS_KEY_SIZE); */ + + pSMB->req_no_secext.CaseSensitivePasswordLength = + cpu_to_le16(V2_SESS_KEY_SIZE); + + /* calculate session key */ + CalcNTLMv2_response(ses, v2_sess_key); + if(first_time) /* should this be moved into common code + with similar ntlmv2 path? */ + /* cifs_calculate_ntlmv2_mac_key(ses->server->mac_signing_key, + response BB FIXME, v2_sess_key); */ + + /* copy session key */ + + /* memcpy(bcc_ptr, (char *)ntlm_session_key,LM2_SESS_KEY_SIZE); + bcc_ptr += LM2_SESS_KEY_SIZE; */ + memcpy(bcc_ptr, (char *)v2_sess_key, V2_SESS_KEY_SIZE); + bcc_ptr += V2_SESS_KEY_SIZE; if(ses->capabilities & CAP_UNICODE) unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); else -- cgit v1.1 From 3856a9d443ee24248683c415e535f7a2b0fed0f3 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 1 Jun 2006 19:38:46 +0000 Subject: [CIFS] Fix minor build breaks due to cifs kconfig issues Signed-off-by: Steve French --- fs/cifs/cifssmb.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 6b5be6d..eea8967 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -436,9 +436,9 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) a common dialect */ rc = -EOPNOTSUPP; goto neg_err_exit; - } else if((pSMBr->hdr.WordCount == 13) && - (pSMBr->DialectIndex == LANMAN_PROT)) { -#ifdef CONFIG_CIFS_WEAK_PW_HASH +#ifdef CONFIG_CIFS_WEAK_PW_HASH + } else if((pSMBr->hdr.WordCount == 13) + && (pSMBr->DialectIndex == LANMAN_PROT)) { struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr; @@ -477,8 +477,9 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) cFYI(1,("LANMAN negotiated")); /* BB removeme BB */ #else /* weak security disabled */ - cERROR(1,("mount failed, cifs module not built with " - "CIFS_WEAK_PW_HASH support")); + } else if(pSMBr->hdr.WordCount == 13) + cERROR(1,("mount failed, cifs module not built " + "with CIFS_WEAK_PW_HASH support")); rc = -EOPNOTSUPP; #endif /* WEAK_PW_HASH */ goto neg_err_exit; -- cgit v1.1 From 273d81d6ada951ba99f10b755d6f849dbb352730 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Thu, 1 Jun 2006 19:41:23 +0000 Subject: [CIFS] Do not overwrite aops cifs should not be overwriting an element of the aops structure, since the structure is shared by all cifs inodes. Instead define a separate aops structure to suit each purpose. I also took the liberty of replacing a hard-coded 4096 with PAGE_CACHE_SIZE Signed-off-by: Dave Kleikamp Signed-off-by: Steven French Signed-off-by: Andrew Morton --- fs/cifs/cifsfs.h | 1 + fs/cifs/file.c | 16 ++++++++++++++++ fs/cifs/inode.c | 14 ++++++++------ fs/cifs/readdir.c | 16 ++++++++++------ 4 files changed, 35 insertions(+), 12 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 2fc6d65..3011df9 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -33,6 +33,7 @@ #endif extern struct address_space_operations cifs_addr_ops; +extern struct address_space_operations cifs_addr_ops_smallbuf; /* Functions related to super block operations */ extern struct super_operations cifs_super_ops; diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 379369e..d62e29f 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1959,3 +1959,19 @@ struct address_space_operations cifs_addr_ops = { /* .sync_page = cifs_sync_page, */ /* .direct_IO = */ }; + +/* + * cifs_readpages requires the server to support a buffer large enough to + * contain the header plus one complete page of data. Otherwise, we need + * to leave cifs_readpages out of the address space operations. + */ +struct address_space_operations cifs_addr_ops_smallbuf = { + .readpage = cifs_readpage, + .writepage = cifs_writepage, + .writepages = cifs_writepages, + .prepare_write = cifs_prepare_write, + .commit_write = cifs_commit_write, + .set_page_dirty = __set_page_dirty_nobuffers, + /* .sync_page = cifs_sync_page, */ + /* .direct_IO = */ +}; diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index a609d26..b88147c 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -180,11 +180,12 @@ int cifs_get_inode_info_unix(struct inode **pinode, else /* not direct, send byte range locks */ inode->i_fop = &cifs_file_ops; - inode->i_data.a_ops = &cifs_addr_ops; /* check if server can support readpages */ if(pTcon->ses->server->maxBuf < - 4096 + MAX_CIFS_HDR_SIZE) - inode->i_data.a_ops->readpages = NULL; + PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE) + inode->i_data.a_ops = &cifs_addr_ops_smallbuf; + else + inode->i_data.a_ops = &cifs_addr_ops; } else if (S_ISDIR(inode->i_mode)) { cFYI(1, ("Directory inode")); inode->i_op = &cifs_dir_inode_ops; @@ -519,10 +520,11 @@ int cifs_get_inode_info(struct inode **pinode, else /* not direct, send byte range locks */ inode->i_fop = &cifs_file_ops; - inode->i_data.a_ops = &cifs_addr_ops; if(pTcon->ses->server->maxBuf < - 4096 + MAX_CIFS_HDR_SIZE) - inode->i_data.a_ops->readpages = NULL; + PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE) + inode->i_data.a_ops = &cifs_addr_ops_smallbuf; + else + inode->i_data.a_ops = &cifs_addr_ops; } else if (S_ISDIR(inode->i_mode)) { cFYI(1, ("Directory inode")); inode->i_op = &cifs_dir_inode_ops; diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 53903a2..e3e762d 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -21,6 +21,7 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include +#include #include #include #include "cifspdu.h" @@ -216,11 +217,13 @@ static void fill_in_inode(struct inode *tmp_inode, else tmp_inode->i_fop = &cifs_file_ops; - tmp_inode->i_data.a_ops = &cifs_addr_ops; if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server->maxBuf < - 4096 + MAX_CIFS_HDR_SIZE)) - tmp_inode->i_data.a_ops->readpages = NULL; + PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)) + tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf; + else + tmp_inode->i_data.a_ops = &cifs_addr_ops; + if(isNewInode) return; /* No sense invalidating pages for new inode since have not started caching readahead file @@ -339,11 +342,12 @@ static void unix_fill_in_inode(struct inode *tmp_inode, else tmp_inode->i_fop = &cifs_file_ops; - tmp_inode->i_data.a_ops = &cifs_addr_ops; if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server->maxBuf < - 4096 + MAX_CIFS_HDR_SIZE)) - tmp_inode->i_data.a_ops->readpages = NULL; + PAGE_CACHE_SIZE + MAX_CIFS_HDR_SIZE)) + tmp_inode->i_data.a_ops = &cifs_addr_ops_smallbuf; + else + tmp_inode->i_data.a_ops = &cifs_addr_ops; if(isNewInode) return; /* No sense invalidating pages for new inode since we -- cgit v1.1 From 7a0d22317614ee8e2598feafd4812e33be17f421 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 1 Jun 2006 19:44:37 +0000 Subject: [CIFS] Missing brace --- fs/cifs/cifssmb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index eea8967..b8c236b 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -477,7 +477,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) cFYI(1,("LANMAN negotiated")); /* BB removeme BB */ #else /* weak security disabled */ - } else if(pSMBr->hdr.WordCount == 13) + } else if(pSMBr->hdr.WordCount == 13) { cERROR(1,("mount failed, cifs module not built " "with CIFS_WEAK_PW_HASH support")); rc = -EOPNOTSUPP; -- cgit v1.1 From 43411d699e8cf3293674da558d31a02e0012aa9d Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 2 Jun 2006 18:17:11 +0000 Subject: [CIFS] Fix mapping of old SMB return code Invalid Net Name so it is recognized on mount the old mapping of this was to ENODEV (instead of ENXIO) - but ENODEV is what mount returns when the cifs driver will not load so change this to map to ENXIO (which was what the equivalent condition returned for mapping errors from more modern servers) Signed-off-by: Steve French --- fs/cifs/netmisc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/cifs') diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index a0bcdd6..b66eff5 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -88,7 +88,7 @@ static const struct smb_to_posix_error mapping_table_ERRSRV[] = { {ERRbadtype, -EREMOTE}, {ERRaccess, -EACCES}, {ERRinvtid, -ENXIO}, - {ERRinvnetname, -ENODEV}, + {ERRinvnetname, -ENXIO}, {ERRinvdevice, -ENXIO}, {ERRqfull, -ENOSPC}, {ERRqtoobig, -ENOSPC}, -- cgit v1.1 From bdc4bf6e8ac8cc29c61c2f0dc61d9776ef9a8ed4 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 2 Jun 2006 22:57:13 +0000 Subject: [CIFS] Support for older servers which require plaintext passwords disabled by default, but can be enabled via proc for servers which require such support. Also includes support for setting security flags for cifs. See fs/cifs/README Signed-off-by: Steve French --- fs/cifs/cifs_debug.c | 56 ++++++++++++++++++++++++++++++++++++--------------- fs/cifs/cifsencrypt.c | 9 +++++++++ fs/cifs/cifssmb.c | 7 +++++++ 3 files changed, 56 insertions(+), 16 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 4e10e21..7c0015a 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -445,8 +445,8 @@ static read_proc_t traceSMB_read; static write_proc_t traceSMB_write; static read_proc_t multiuser_mount_read; static write_proc_t multiuser_mount_write; -static read_proc_t extended_security_read; -static write_proc_t extended_security_write; +static read_proc_t security_flags_read; +static write_proc_t security_flags_write; /* static read_proc_t ntlmv2_enabled_read; static write_proc_t ntlmv2_enabled_write; static read_proc_t packet_signing_enabled_read; @@ -509,9 +509,9 @@ cifs_proc_init(void) pde = create_proc_read_entry("SecurityFlags", 0, proc_fs_cifs, - extended_security_read, NULL); + security_flags_read, NULL); if (pde) - pde->write_proc = extended_security_write; + pde->write_proc = security_flags_write; pde = create_proc_read_entry("LookupCacheEnabled", 0, proc_fs_cifs, @@ -832,7 +832,7 @@ multiuser_mount_write(struct file *file, const char __user *buffer, } static int -extended_security_read(char *page, char **start, off_t off, +security_flags_read(char *page, char **start, off_t off, int count, int *eof, void *data) { int len; @@ -853,26 +853,50 @@ extended_security_read(char *page, char **start, off_t off, return len; } static int -extended_security_write(struct file *file, const char __user *buffer, +security_flags_write(struct file *file, const char __user *buffer, unsigned long count, void *data) { + unsigned int flags; + char flags_string[12]; char c; - int rc; + cERROR(1,("size %ld",count)); /* BB removeme BB */ - if((count < 2) || (count > 8)) + + if((count < 1) || (count > 11)) return -EINVAL; - rc = get_user(c, buffer); + memset(flags_string, 0, 12); -/* BB fixme need to parse more characters in order to handle CIFSSEC flags */ + if(copy_from_user(flags_string, buffer, count)) + return -EFAULT; - if (rc) - return rc; - if (c == '0' || c == 'n' || c == 'N') - extended_security = CIFSSEC_DEF; /* default */ - else if (c == '1' || c == 'y' || c == 'Y') - extended_security = CIFSSEC_MAX; + if(count < 3) { + /* single char or single char followed by null */ + c = flags_string[0]; + if (c == '0' || c == 'n' || c == 'N') + extended_security = CIFSSEC_DEF; /* default */ + else if (c == '1' || c == 'y' || c == 'Y') + extended_security = CIFSSEC_MAX; + return count; + } + /* else we have a number */ + + flags = simple_strtoul(flags_string, NULL, 0); + + cERROR(1,("sec flags 0x%x", flags)); /* BB FIXME make cFYI */ + + if(flags <= 0) { + cERROR(1,("invalid security flags %s",flags_string)); + return -EINVAL; + } + if((flags & CIFSSEC_MASK) != CIFSSEC_MASK) { + cERROR(1,("attempt to set unsupported security flags 0x%d", + flags & ~CIFSSEC_MASK)); + return -EINVAL; + } + /* flags look ok - update the global security flags for cifs module */ + extended_security = flags; return count; } diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index e11d8c6..3ae964b 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -271,9 +271,18 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key) int i; char password_with_pad[CIFS_ENCPWD_SIZE]; + if(ses->server == NULL) + return; + memset(password_with_pad, 0, CIFS_ENCPWD_SIZE); strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE); + if((ses->server->secMode & SECMODE_PW_ENCRYPT) == 0) + if(extended_security & CIFSSEC_MAY_PLNTXT) { + memcpy(lnm_session_key, password_with_pad, CIFS_ENCPWD_SIZE); + return; + } + /* calculate old style session key */ /* calling toupper is less broken than repeatedly calling nls_toupper would be since that will never diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index b8c236b..77cca380 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -492,6 +492,13 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) server->secMode = pSMBr->SecurityMode; if((server->secMode & SECMODE_USER) == 0) cFYI(1,("share mode security")); + + if((server->secMode & SECMODE_PW_ENCRYPT) == 0) +#ifdef CONFIG_CIFS_WEAK_PW_HASH + if ((extended_security & CIFSSEC_MAY_PLNTXT) == 0) +#endif /* CIFS_WEAK_PW_HASH */ + cERROR(1,("Server requests plain text password" + " but client support disabled")); if(extended_security & CIFSSEC_MUST_NTLMV2) server->secType = NTLMv2; -- cgit v1.1 From 254e55ed03e2e8d23089b4a468eec2fd2e1ead9b Mon Sep 17 00:00:00 2001 From: Steve French Date: Sun, 4 Jun 2006 05:53:15 +0000 Subject: CIFS] Support for older servers which require plaintext passwords - part 2 Signed-off-by: Steve French --- fs/cifs/README | 32 ++++-- fs/cifs/cifsglob.h | 17 ++-- fs/cifs/cifspdu.h | 4 + fs/cifs/cifssmb.c | 279 +++++++++++++++++++++++++++-------------------------- fs/cifs/sess.c | 3 +- 5 files changed, 184 insertions(+), 151 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/README b/fs/cifs/README index 0355003..a68f8e3 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -485,14 +485,34 @@ PacketSigningEnabled If set to one, cifs packet signing is enabled it. If set to two, cifs packet signing is required even if the server considers packet signing optional. (default 1) +SecurityFlags Flags which control security negotiation and + also packet signing. Authentication (may/must) + flags (e.g. for NTLM and/or NTLMv2) may be combined with + the signing flags. Specifying two different password + hashing mechanisms (as "must use") on the other hand + does not make much sense. Default flags are + 0x07007 + (NTLM, NTLMv2 and packet signing allowed). Maximum + allowable flags if you want to allow mounts to servers + using weaker password hashes is 0x37037 (lanman, + plaintext, ntlm, ntlmv2, signing allowed): + + may use packet signing 0x00001 + must use packet signing 0x01001 + may use NTLM (most common password hash) 0x00002 + must use NTLM 0x02002 + may use NTLMv2 0x00004 + must use NTLMv2 0x04004 + may use Kerberos security (not implemented yet) 0x00008 + must use Kerberos (not implemented yet) 0x08008 + may use lanman (weak) password hash 0x00010 + must use lanman password hash 0x10010 + may use plaintext passwords 0x00020 + must use plaintext passwords 0x20020 + (reserved for future packet encryption) 0x00040 + cifsFYI If set to one, additional debug information is logged to the system error log. (default 0) -ExtendedSecurity If set to one, SPNEGO session establishment - is allowed which enables more advanced - secure CIFS session establishment (default 0) -NTLMV2Enabled If set to one, more secure password hashes - are used when the server supports them and - when kerberos is not negotiated (default 0) traceSMB If set to one, debug information is logged to the system error log with the start of smb requests and responses (default 0) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 975e69a..87453a6b 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -212,12 +212,12 @@ struct cifsTconInfo { struct list_head openFileList; struct semaphore tconSem; struct cifsSesInfo *ses; /* pointer to session associated with */ - char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource (in ASCII not UTF) */ + char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */ char *nativeFileSystem; __u16 tid; /* The 2 byte tree id */ __u16 Flags; /* optional support bits */ enum statusEnum tidStatus; - atomic_t useCount; /* how many mounts (explicit or implicit) to this share */ + atomic_t useCount; /* how many explicit/implicit mounts to share */ #ifdef CONFIG_CIFS_STATS atomic_t num_smbs_sent; atomic_t num_writes; @@ -257,7 +257,7 @@ struct cifsTconInfo { spinlock_t stat_lock; #endif /* CONFIG_CIFS_STATS */ FILE_SYSTEM_DEVICE_INFO fsDevInfo; - FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if file system name truncated */ + FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if fs name truncated */ FILE_SYSTEM_UNIX_INFO fsUnixInfo; unsigned retry:1; unsigned nocase:1; @@ -308,7 +308,6 @@ struct cifsFileInfo { atomic_t wrtPending; /* handle in use - defer close */ struct semaphore fh_sem; /* prevents reopen race after dead ses*/ char * search_resume_name; /* BB removeme BB */ - unsigned int resume_name_length; /* BB removeme - field renamed and moved BB */ struct cifs_search_info srch_inf; }; @@ -523,16 +522,16 @@ GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */ GLOBAL_EXTERN struct list_head GlobalOplock_Q; GLOBAL_EXTERN struct list_head GlobalDnotifyReqList; /* Outstanding dir notify requests */ -GLOBAL_EXTERN struct list_head GlobalDnotifyRsp_Q; /* Dir notify response queue */ +GLOBAL_EXTERN struct list_head GlobalDnotifyRsp_Q;/* DirNotify response queue */ /* * Global transaction id (XID) information */ GLOBAL_EXTERN unsigned int GlobalCurrentXid; /* protected by GlobalMid_Sem */ -GLOBAL_EXTERN unsigned int GlobalTotalActiveXid; /* prot by GlobalMid_Sem */ +GLOBAL_EXTERN unsigned int GlobalTotalActiveXid; /* prot by GlobalMid_Sem */ GLOBAL_EXTERN unsigned int GlobalMaxActiveXid; /* prot by GlobalMid_Sem */ -GLOBAL_EXTERN spinlock_t GlobalMid_Lock; /* protects above and list operations */ - /* on midQ entries */ +GLOBAL_EXTERN spinlock_t GlobalMid_Lock; /* protects above & list operations */ + /* on midQ entries */ GLOBAL_EXTERN char Local_System_Name[15]; /* @@ -554,7 +553,7 @@ GLOBAL_EXTERN atomic_t smBufAllocCount; GLOBAL_EXTERN atomic_t midCount; /* Misc globals */ -GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions +GLOBAL_EXTERN unsigned int multiuser_mount; /* if enabled allows new sessions to be established on existing mount if we have the uid/password or Kerberos credential or equivalent for current user */ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 1359417..e714803 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -426,6 +426,10 @@ typedef struct lanman_neg_rsp { unsigned char EncryptionKey[1]; } __attribute__((packed)) LANMAN_NEG_RSP; +#define READ_RAW_ENABLE 1 +#define WRITE_RAW_ENABLE 2 +#define RAW_ENABLE (READ_RAW_ENABLE | WRITE_RAW_ENABLE) + typedef struct negotiate_rsp { struct smb_hdr hdr; /* wct = 17 */ __le16 DialectIndex; diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 77cca380..0442c3b 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -411,8 +411,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) return rc; pSMB->hdr.Mid = GetNextMid(server); pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; -/* if (extended_security) - pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC;*/ + if((extended_security & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5) + pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; count = 0; for(i=0;iDialectIndex)); - /* Check wct = 1 error case */ - if((pSMBr->hdr.WordCount < 13) - || (pSMBr->DialectIndex == BAD_PROT)) { - /* core returns wct = 1, but we do not ask for - core - otherwise it just comes when dialect - index is -1 indicating we could not negotiate - a common dialect */ + if (rc != 0) + goto neg_err_exit; + + cFYI(1,("Dialect: %d", pSMBr->DialectIndex)); + /* Check wct = 1 error case */ + if((pSMBr->hdr.WordCount < 13) || (pSMBr->DialectIndex == BAD_PROT)) { + /* core returns wct = 1, but we do not ask for core - otherwise + small wct just comes when dialect index is -1 indicating we + could not negotiate a common dialect */ + rc = -EOPNOTSUPP; + goto neg_err_exit; +#ifdef CONFIG_CIFS_WEAK_PW_HASH + } else if((pSMBr->hdr.WordCount == 13) + && (pSMBr->DialectIndex == LANMAN_PROT)) { + struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr; + + if((extended_security & CIFSSEC_MAY_LANMAN) || + (extended_security & CIFSSEC_MAY_PLNTXT)) + server->secType = LANMAN; + else { + cERROR(1, ("mount failed weak security disabled" + " in /proc/fs/cifs/SecurityFlags")); rc = -EOPNOTSUPP; goto neg_err_exit; -#ifdef CONFIG_CIFS_WEAK_PW_HASH - } else if((pSMBr->hdr.WordCount == 13) - && (pSMBr->DialectIndex == LANMAN_PROT)) { - struct lanman_neg_rsp * rsp = - (struct lanman_neg_rsp *)pSMBr; - - if((extended_security & CIFSSEC_MAY_LANMAN) || - (extended_security & CIFSSEC_MAY_PLNTXT)) - server->secType = LANMAN; - else { - cERROR(1, ("mount failed weak security disabled" - " in /proc/fs/cifs/SecurityFlags")); - rc = -EOPNOTSUPP; - goto neg_err_exit; - } - server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode); - server->maxReq = le16_to_cpu(rsp->MaxMpxCount); - server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize), + } + server->secMode = (__u8)le16_to_cpu(rsp->SecurityMode); + server->maxReq = le16_to_cpu(rsp->MaxMpxCount); + server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize), (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); + GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey); + /* even though we do not use raw we might as well set this + accurately, in case we ever find a need for it */ + if((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) { + server->maxRw = 0xFF00; + server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE; + } else { + server->maxRw = 0;/* we do not need to use raw anyway */ + server->capabilities = CAP_MPX_MODE; + } + server->timeZone = le16_to_cpu(rsp->ServerTimeZone); - /* BB what do we do with raw mode? BB */ - server->timeZone = le16_to_cpu(rsp->ServerTimeZone); - /* Do we have to set signing flags? no signing - was available LANMAN - default should be ok */ - - /* BB FIXME set default dummy capabilities since - they are not returned by the server in this dialect */ - - /* get server time for time conversions and add - code to use it and timezone since this is not UTC */ + /* BB get server time for time conversions and add + code to use it and timezone since this is not UTC */ - if (rsp->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { - memcpy(server->cryptKey, rsp->EncryptionKey, - CIFS_CRYPTO_KEY_SIZE); - } else { - rc = -EIO; - goto neg_err_exit; - } + if (rsp->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { + memcpy(server->cryptKey, rsp->EncryptionKey, + CIFS_CRYPTO_KEY_SIZE); + } else if (server->secMode & SECMODE_PW_ENCRYPT) { + rc = -EIO; /* need cryptkey unless plain text */ + goto neg_err_exit; + } - cFYI(1,("LANMAN negotiated")); /* BB removeme BB */ + cFYI(1,("LANMAN negotiated")); + /* we will not end up setting signing flags - as no signing + was in LANMAN and server did not return the flags on */ + goto signing_check; #else /* weak security disabled */ - } else if(pSMBr->hdr.WordCount == 13) { - cERROR(1,("mount failed, cifs module not built " - "with CIFS_WEAK_PW_HASH support")); + } else if(pSMBr->hdr.WordCount == 13) { + cERROR(1,("mount failed, cifs module not built " + "with CIFS_WEAK_PW_HASH support")); rc = -EOPNOTSUPP; #endif /* WEAK_PW_HASH */ - goto neg_err_exit; - } else if(pSMBr->hdr.WordCount != 17) { - /* unknown wct */ - rc = -EOPNOTSUPP; - goto neg_err_exit; - } - - server->secMode = pSMBr->SecurityMode; - if((server->secMode & SECMODE_USER) == 0) - cFYI(1,("share mode security")); + goto neg_err_exit; + } else if(pSMBr->hdr.WordCount != 17) { + /* unknown wct */ + rc = -EOPNOTSUPP; + goto neg_err_exit; + } + /* else wct == 17 NTLM */ + server->secMode = pSMBr->SecurityMode; + if((server->secMode & SECMODE_USER) == 0) + cFYI(1,("share mode security")); - if((server->secMode & SECMODE_PW_ENCRYPT) == 0) + if((server->secMode & SECMODE_PW_ENCRYPT) == 0) #ifdef CONFIG_CIFS_WEAK_PW_HASH - if ((extended_security & CIFSSEC_MAY_PLNTXT) == 0) + if ((extended_security & CIFSSEC_MAY_PLNTXT) == 0) #endif /* CIFS_WEAK_PW_HASH */ - cERROR(1,("Server requests plain text password" - " but client support disabled")); + cERROR(1,("Server requests plain text password" + " but client support disabled")); - if(extended_security & CIFSSEC_MUST_NTLMV2) - server->secType = NTLMv2; - else - server->secType = NTLM; - /* else krb5 ... */ - - /* one byte - no need to convert this or EncryptionKeyLen - from little endian */ - server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount); - /* probably no need to store and check maxvcs */ - server->maxBuf = - min(le32_to_cpu(pSMBr->MaxBufferSize), + if(extended_security & CIFSSEC_MUST_NTLMV2) + server->secType = NTLMv2; + else + server->secType = NTLM; + /* else krb5 ... */ + + /* one byte, so no need to convert this or EncryptionKeyLen from + little endian */ + server->maxReq = le16_to_cpu(pSMBr->MaxMpxCount); + /* probably no need to store and check maxvcs */ + server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize), (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); - server->maxRw = le32_to_cpu(pSMBr->MaxRawSize); - 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); - /* BB with UTC do we ever need to be using srvr timezone? */ - if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { - memcpy(server->cryptKey, pSMBr->u.EncryptionKey, - CIFS_CRYPTO_KEY_SIZE); - } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) - && (pSMBr->EncryptionKeyLength == 0)) { - /* decode security blob */ - } else - rc = -EIO; + server->maxRw = le32_to_cpu(pSMBr->MaxRawSize); + 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); + if (pSMBr->EncryptionKeyLength == CIFS_CRYPTO_KEY_SIZE) { + memcpy(server->cryptKey, pSMBr->u.EncryptionKey, + CIFS_CRYPTO_KEY_SIZE); + } else if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) + && (pSMBr->EncryptionKeyLength == 0)) { + /* decode security blob */ + } else if (server->secMode & SECMODE_PW_ENCRYPT) { + rc = -EIO; /* no crypt key only if plain text pwd */ + goto neg_err_exit; + } - /* BB might be helpful to save off the domain of server here */ + /* BB might be helpful to save off the domain of server here */ - if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && - (server->capabilities & CAP_EXTENDED_SECURITY)) { - count = pSMBr->ByteCount; - if (count < 16) - rc = -EIO; - else if (count == 16) { - server->secType = RawNTLMSSP; - if (server->socketUseCount.counter > 1) { - if (memcmp - (server->server_GUID, - pSMBr->u.extended_response. - GUID, 16) != 0) { - cFYI(1, ("server UID changed")); - memcpy(server-> - server_GUID, - pSMBr->u. - extended_response. - GUID, 16); - } - } else + if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && + (server->capabilities & CAP_EXTENDED_SECURITY)) { + count = pSMBr->ByteCount; + if (count < 16) + rc = -EIO; + else if (count == 16) { + server->secType = RawNTLMSSP; + if (server->socketUseCount.counter > 1) { + if (memcmp(server->server_GUID, + pSMBr->u.extended_response. + GUID, 16) != 0) { + cFYI(1, ("server UID changed")); memcpy(server->server_GUID, - pSMBr->u.extended_response. - GUID, 16); - } else { - rc = decode_negTokenInit(pSMBr->u. - extended_response. - SecurityBlob, - count - 16, - &server->secType); - if(rc == 1) { - /* BB Need to fill struct for sessetup here */ - rc = -EOPNOTSUPP; - } else { - rc = -EINVAL; + pSMBr->u.extended_response.GUID, + 16); } + } else + memcpy(server->server_GUID, + pSMBr->u.extended_response.GUID, 16); + } else { + rc = decode_negTokenInit(pSMBr->u.extended_response. + SecurityBlob, + count - 16, + &server->secType); + if(rc == 1) { + /* BB Need to fill struct for sessetup here */ + rc = -EOPNOTSUPP; + } else { + rc = -EINVAL; } - } else - server->capabilities &= ~CAP_EXTENDED_SECURITY; - if(sign_CIFS_PDUs == FALSE) { - if(server->secMode & SECMODE_SIGN_REQUIRED) - cERROR(1, - ("Server requires /proc/fs/cifs/PacketSigningEnabled")); - server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); - } else if(sign_CIFS_PDUs == 1) { - if((server->secMode & SECMODE_SIGN_REQUIRED) == 0) - server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); } - + } else + server->capabilities &= ~CAP_EXTENDED_SECURITY; + +signing_check: + if(sign_CIFS_PDUs == FALSE) { + if(server->secMode & SECMODE_SIGN_REQUIRED) + cERROR(1,("Server requires " + "/proc/fs/cifs/PacketSigningEnabled to be on")); + server->secMode &= + ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); + } else if(sign_CIFS_PDUs == 1) { + if((server->secMode & SECMODE_SIGN_REQUIRED) == 0) + server->secMode &= + ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); + } else if(sign_CIFS_PDUs == 2) { + if((server->secMode & + (SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED)) == 0) { + cERROR(1,("signing required but server lacks support")); + } } neg_err_exit: cifs_buf_release(pSMB); + + cFYI(1,("negprot rc %d",rc)); return rc; } diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index a52aacb..76a09f5 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -323,7 +323,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, enum securityEnum type; __u16 action; int bytes_remaining; - + + cFYI(1,("new sess setup")); if(ses == NULL) return -EINVAL; -- cgit v1.1 From 9312f6754d4b2d3ce27c21b16fb92923ce92a411 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sun, 4 Jun 2006 22:21:07 +0000 Subject: [CIFS] Fix mask so can set new cifs security flags properly Signed-off-by: Steve French --- fs/cifs/cifs_debug.c | 6 ++---- fs/cifs/cifssmb.c | 2 +- fs/cifs/sess.c | 5 +++-- 3 files changed, 6 insertions(+), 7 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 7c0015a..2f55edf 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -860,8 +860,6 @@ security_flags_write(struct file *file, const char __user *buffer, char flags_string[12]; char c; - cERROR(1,("size %ld",count)); /* BB removeme BB */ - if((count < 1) || (count > 11)) return -EINVAL; @@ -883,14 +881,14 @@ security_flags_write(struct file *file, const char __user *buffer, flags = simple_strtoul(flags_string, NULL, 0); - cERROR(1,("sec flags 0x%x", flags)); /* BB FIXME make cFYI */ + cFYI(1,("sec flags 0x%x", flags)); if(flags <= 0) { cERROR(1,("invalid security flags %s",flags_string)); return -EINVAL; } - if((flags & CIFSSEC_MASK) != CIFSSEC_MASK) { + if(flags & ~CIFSSEC_MASK) { cERROR(1,("attempt to set unsupported security flags 0x%d", flags & ~CIFSSEC_MASK)); return -EINVAL; diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 0442c3b..acae583 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -504,7 +504,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) #endif /* CIFS_WEAK_PW_HASH */ cERROR(1,("Server requests plain text password" " but client support disabled")); - + if(extended_security & CIFSSEC_MUST_NTLMV2) server->secType = NTLMv2; else diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 76a09f5..1fe9461 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -339,9 +339,10 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, return -EOPNOTSUPP; #endif wct = 10; /* lanman 2 style sessionsetup */ - } else if((type == NTLM) || (type == NTLMv2)) /* NTLMv2 may retry NTLM */ + } else if((type == NTLM) || (type == NTLMv2)) { + /* For NTLMv2 failures eventually may need to retry NTLM */ wct = 13; /* old style NTLM sessionsetup */ - else /* same size for negotiate or auth, NTLMSSP or extended security */ + } else /* same size for negotiate or auth, NTLMSSP or extended security */ wct = 12; rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses, -- cgit v1.1 From f64b23ae4aef9f69d71ea41529a188acd5ab4930 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 5 Jun 2006 05:27:37 +0000 Subject: [CIFS] NTLMv2 support part 2 Still need to fill in response structure and check that hash works Signed-off-by: Steve French --- fs/cifs/cifsencrypt.c | 2 ++ fs/cifs/cifspdu.h | 27 ++++++++++++++++++++++++--- fs/cifs/sess.c | 13 +++++++++---- 3 files changed, 35 insertions(+), 7 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 3ae964b..24ab770 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -306,6 +306,8 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key) void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response) { + /* BB FIXME - update struct ntlmv2_response and change calling convention + of this function */ struct HMACMD5Context context; memcpy(v2_session_response + 8, ses->server->cryptKey,8); /* gen_blob(v2_session_response + 16); */ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index e714803..503b7e3 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -117,7 +117,6 @@ * Size of the session key (crypto key encrypted with the password */ #define CIFS_SESS_KEY_SIZE (24) -#define V2_SESS_KEY_SIZE (86) /* * Maximum user name length @@ -539,7 +538,7 @@ typedef union smb_com_session_setup_andx { /* unsigned char * NativeOS; */ /* unsigned char * NativeLanMan; */ /* unsigned char * PrimaryDomain; */ - } __attribute__((packed)) resp; /* NTLM response format (with or without extended security */ + } __attribute__((packed)) resp; /* NTLM response with or without extended sec*/ struct { /* request format */ struct smb_hdr hdr; /* wct = 10 */ @@ -573,6 +572,26 @@ typedef union smb_com_session_setup_andx { } __attribute__((packed)) old_resp; /* pre-NTLM (LANMAN2.1) response */ } __attribute__((packed)) SESSION_SETUP_ANDX; +/* format of NLTMv2 Response ie "case sensitive password" hash when NTLMv2 */ + +struct ntlmssp2_name { + __le16 type; + __le16 length; +/* char name[length]; */ +} __attribute__((packed)); + +struct ntlmv2_resp { + char ntlmv2_hash[CIFS_ENCPWD_SIZE]; + __le32 blob_sign; + __u32 reserved; + __le64 time; + __u64 client_chal; /* random */ + __u32 reserved2; + struct ntlmssp2_name names[1]; + /* array of name entries could follow ending in minimum 4 byte struct */ +} __attribute__((packed)); + + #define CIFS_NETWORK_OPSYS "CIFS VFS Client for Linux" /* Capabilities bits (for NTLM SessSetup request) */ @@ -603,7 +622,9 @@ typedef struct smb_com_tconx_req { } __attribute__((packed)) TCONX_REQ; typedef struct smb_com_tconx_rsp { - struct smb_hdr hdr; /* wct = 3 *//* note that Win2000 has sent wct=7 in some cases on responses. Four unspecified words followed OptionalSupport */ + struct smb_hdr hdr; /* wct = 3 note that Win2000 has sent wct = 7 + in some cases on responses. Four unspecified + words followed OptionalSupport */ __u8 AndXCommand; __u8 AndXReserved; __le16 AndXOffset; diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 1fe9461..9ce628d 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -411,7 +411,11 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, else ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); } else if (type == NTLMv2) { - char * v2_sess_key = kmalloc(V2_SESS_KEY_SIZE, GFP_KERNEL); + char * v2_sess_key = kmalloc(sizeof(struct ntlmv2_resp), + GFP_KERNEL); + + /* BB FIXME change all users of v2_sess_key to + struct ntlmv2_resp */ if(v2_sess_key == NULL) { cifs_small_buf_release(smb_buf); @@ -425,7 +429,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, /* cpu_to_le16(LM2_SESS_KEY_SIZE); */ pSMB->req_no_secext.CaseSensitivePasswordLength = - cpu_to_le16(V2_SESS_KEY_SIZE); + cpu_to_le16(sizeof(struct ntlmv2_resp)); /* calculate session key */ CalcNTLMv2_response(ses, v2_sess_key); @@ -438,8 +442,9 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, /* memcpy(bcc_ptr, (char *)ntlm_session_key,LM2_SESS_KEY_SIZE); bcc_ptr += LM2_SESS_KEY_SIZE; */ - memcpy(bcc_ptr, (char *)v2_sess_key, V2_SESS_KEY_SIZE); - bcc_ptr += V2_SESS_KEY_SIZE; + memcpy(bcc_ptr, (char *)v2_sess_key, sizeof(struct ntlmv2_resp)); + bcc_ptr += sizeof(struct ntlmv2_resp); + kfree(v2_sess_key); if(ses->capabilities & CAP_UNICODE) unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); else -- cgit v1.1 From 6d027cfdb19c26df3151a519ed55acfe2c4cb7c3 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 5 Jun 2006 16:26:05 +0000 Subject: [CIFS] NTLMv2 support part 3 Response struct filled in exacty for 16 byte hash which we need to check more to make sure it works. Signed-off-by: Steve French --- fs/cifs/cifsencrypt.c | 17 +++++++++++++++-- fs/cifs/cifspdu.h | 2 +- fs/cifs/cifsproto.h | 1 + fs/cifs/sess.c | 6 +++--- 4 files changed, 20 insertions(+), 6 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 24ab770..09f9461 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -27,6 +27,7 @@ #include "cifs_unicode.h" #include "cifsproto.h" #include +#include /* Calculate and return the CIFS signature based on the mac key and the smb pdu */ /* the 16 byte signature must be allocated by the caller */ @@ -304,10 +305,22 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key) } #endif /* CIFS_WEAK_PW_HASH */ +void setup_ntlmv2_rsp(const struct cifsSesInfo * ses, char * resp_buf) +{ + struct ntlmv2_resp * buf = (struct ntlmv2_resp *)resp_buf; + + buf->blob_signature = cpu_to_le32(0x00000101); + buf->reserved = 0; + buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); + get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); + buf->reserved2 = 0; + buf->names[0].type = 0; + buf->names[0].length = 0; + /* calculate buf->ntlmv2_hash */ +} + void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response) { - /* BB FIXME - update struct ntlmv2_response and change calling convention - of this function */ struct HMACMD5Context context; memcpy(v2_session_response + 8, ses->server->cryptKey,8); /* gen_blob(v2_session_response + 16); */ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 503b7e3..5250b93 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -582,7 +582,7 @@ struct ntlmssp2_name { struct ntlmv2_resp { char ntlmv2_hash[CIFS_ENCPWD_SIZE]; - __le32 blob_sign; + __le32 blob_signature; __u32 reserved; __le64 time; __u64 client_chal; /* random */ diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 59b037f..824afb9 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -287,6 +287,7 @@ extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key, extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass); extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, struct nls_table *); extern void CalcNTLMv2_response(const struct cifsSesInfo *,char * ); +extern void setup_ntlmv2_rsp(const struct cifsSesInfo *, char *); #ifdef CONFIG_CIFS_WEAK_PW_HASH extern void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key); #endif /* CIFS_WEAK_PW_HASH */ diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 9ce628d..c6fd01f 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -411,8 +411,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, else ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); } else if (type == NTLMv2) { - char * v2_sess_key = kmalloc(sizeof(struct ntlmv2_resp), - GFP_KERNEL); + char * v2_sess_key = + kmalloc(sizeof(struct ntlmv2_resp), GFP_KERNEL); /* BB FIXME change all users of v2_sess_key to struct ntlmv2_resp */ @@ -432,7 +432,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, cpu_to_le16(sizeof(struct ntlmv2_resp)); /* calculate session key */ - CalcNTLMv2_response(ses, v2_sess_key); + setup_ntlmv2_rsp(ses, v2_sess_key); if(first_time) /* should this be moved into common code with similar ntlmv2 path? */ /* cifs_calculate_ntlmv2_mac_key(ses->server->mac_signing_key, -- cgit v1.1 From a8ee03441f66e0674e641c0cbe1a9534cdee968f Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 5 Jun 2006 23:34:19 +0000 Subject: [CIFS] NTLMv2 support part 4 Signed-off-by: Steve French --- fs/cifs/cifs_debug.c | 2 +- fs/cifs/cifsencrypt.c | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 2f55edf..96abeb7 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -889,7 +889,7 @@ security_flags_write(struct file *file, const char __user *buffer, } if(flags & ~CIFSSEC_MASK) { - cERROR(1,("attempt to set unsupported security flags 0x%d", + cERROR(1,("attempt to set unsupported security flags 0x%x", flags & ~CIFSSEC_MASK)); return -EINVAL; } diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 09f9461..8bcb1da 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -305,8 +305,44 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key) } #endif /* CIFS_WEAK_PW_HASH */ +static int calc_ntlmv2_hash(const struct cifsSesInfo *ses, + char * ntv2_hash) +{ + int rc = 0; + int len; + char nt_hash[16]; + struct HMACMD5Context * pctxt; + + pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL); + + if(pctxt == NULL) + return -ENOMEM; + + /* calculate md4 hash of password */ + E_md4hash(ses->password, nt_hash); + + /* convERT Domainname to unicode and uppercase */ + hmac_md5_init_limK_to_64(nt_hash, 16, pctxt); + + /* convert ses->userName to unicode and uppercase */ + + /* len = ... */ /* BB FIXME BB */ + + /* hmac_md5_update(user, len, pctxt); */ + + /* convert ses->domainName to unicode and uppercase */ + + /* len = ... */ /* BB FIXME BB */ + /* hmac_md5_update(domain, len, pctxt); */ + + hmac_md5_final(ntv2_hash, pctxt); + + return rc; +} + void setup_ntlmv2_rsp(const struct cifsSesInfo * ses, char * resp_buf) { + int rc; struct ntlmv2_resp * buf = (struct ntlmv2_resp *)resp_buf; buf->blob_signature = cpu_to_le32(0x00000101); @@ -316,7 +352,11 @@ void setup_ntlmv2_rsp(const struct cifsSesInfo * ses, char * resp_buf) buf->reserved2 = 0; buf->names[0].type = 0; buf->names[0].length = 0; + /* calculate buf->ntlmv2_hash */ + rc = calc_ntlmv2_hash(ses,buf->ntlmv2_hash); + if(rc) + cERROR(1,("could not get v2 hash rc %d",rc)); } void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response) -- cgit v1.1 From 5bafd76593f060540acbea3b61e3087e009aa269 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 7 Jun 2006 00:18:43 +0000 Subject: [CIFS] Add support for readdir to legacy servers Fixes oops to OS/2 on ls and removes redundant NTCreateX calls to servers which do not support NT SMBs. Key operations to OS/2 work. Signed-off-by: Steve French --- fs/cifs/CHANGES | 4 ++ fs/cifs/cifspdu.h | 29 +++++++++-- fs/cifs/dir.c | 11 +++- fs/cifs/file.c | 9 +++- fs/cifs/readdir.c | 150 +++++++++++++++++++++++++++++++++++++++--------------- 5 files changed, 153 insertions(+), 50 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index b878dfc..7e0058b 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -2,6 +2,10 @@ Version 1.44 ------------ Rewritten sessionsetup support, including support for legacy SMB session setup needed for OS/2 and older servers such as Windows 95 and 98. +Fix oops on ls to OS/2 servers. Add support for level 1 FindFirst +so we can do search (ls etc.) to OS/2. Do not send NTCreateX +or recent levels of FindFirst unless server says it supports NT SMBs +(instead use legacy equivalents from LANMAN dialect). Version 1.43 ------------ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 5250b93..8623902 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -1374,6 +1374,9 @@ struct smb_t2_rsp { #define SMB_FILE_MAXIMUM_INFO 0x40d /* Find File infolevels */ +#define SMB_FIND_FILE_INFO_STANDARD 0x001 +#define SMB_FIND_FILE_QUERY_EA_SIZE 0x002 +#define SMB_FIND_FILE_QUERY_EAS_FROM_LIST 0x003 #define SMB_FIND_FILE_DIRECTORY_INFO 0x101 #define SMB_FIND_FILE_FULL_DIRECTORY_INFO 0x102 #define SMB_FIND_FILE_NAMES_INFO 0x103 @@ -1998,7 +2001,8 @@ typedef struct { struct file_allocation_info { __le64 AllocationSize; /* Note old Samba srvr rounds this up too much */ -} __attribute__((packed)); /* size used on disk, level 0x103 for set, 0x105 for query */ +} __attribute__((packed)); /* size used on disk, for level 0x103 for set, + 0x105 for query */ struct file_end_of_file_info { __le64 FileSize; /* offset to end of file */ @@ -2105,7 +2109,7 @@ typedef struct { __le32 ExtFileAttributes; __le32 FileNameLength; char FileName[1]; -} __attribute__((packed)) FILE_DIRECTORY_INFO; /* level 0x101 FF response data area */ +} __attribute__((packed)) FILE_DIRECTORY_INFO; /* level 0x101 FF resp data */ typedef struct { __le32 NextEntryOffset; @@ -2120,7 +2124,7 @@ typedef struct { __le32 FileNameLength; __le32 EaSize; /* length of the xattrs */ char FileName[1]; -} __attribute__((packed)) FILE_FULL_DIRECTORY_INFO; /* level 0x102 FF response data area */ +} __attribute__((packed)) FILE_FULL_DIRECTORY_INFO; /* level 0x102 rsp data */ typedef struct { __le32 NextEntryOffset; @@ -2137,7 +2141,7 @@ typedef struct { __le32 Reserved; __u64 UniqueId; /* inode num - le since Samba puts ino in low 32 bit*/ char FileName[1]; -} __attribute__((packed)) SEARCH_ID_FULL_DIR_INFO; /* level 0x105 FF response data area */ +} __attribute__((packed)) SEARCH_ID_FULL_DIR_INFO; /* level 0x105 FF rsp data */ typedef struct { __le32 NextEntryOffset; @@ -2155,7 +2159,22 @@ typedef struct { __u8 Reserved; __u8 ShortName[12]; char FileName[1]; -} __attribute__((packed)) FILE_BOTH_DIRECTORY_INFO; /* level 0x104 FF response data area */ +} __attribute__((packed)) FILE_BOTH_DIRECTORY_INFO; /* level 0x104 FFrsp data */ + +typedef struct { + __u32 ResumeKey; + __le16 CreationDate; /* SMB Date */ + __le16 CreationTime; /* SMB Time */ + __le16 LastAccessDate; + __le16 LastAccessTime; + __le16 LastWriteDate; + __le16 LastWriteTime; + __le32 DataSize; /* File Size (EOF) */ + __le32 AllocationSize; + __le16 Attributes; /* verify not u32 */ + __u8 FileNameLength; + char FileName[1]; +} __attribute__((packed)) FIND_FILE_STANDARD_INFO; /* level 0x1 FF resp data */ struct win_dev { diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index e6ed64e..ba4cbe9 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -178,11 +178,14 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, FreeXid(xid); return -ENOMEM; } - - rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, + if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS) + rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, CREATE_NOT_DIR, &fileHandle, &oplock, buf, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + else + rc = -EIO; /* no NT SMB support fall into legacy open below */ + if(rc == -EIO) { /* old server, retry the open legacy style */ rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, @@ -369,6 +372,10 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + /* BB FIXME - add handling for backlevel servers + which need legacy open and check for all + calls to SMBOpen for fallback to + SMBLeagcyOpen */ if(!rc) { /* BB Do not bother to decode buf since no local inode yet to put timestamps in, diff --git a/fs/cifs/file.c b/fs/cifs/file.c index d62e29f..fafdcdf 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -260,10 +260,15 @@ int cifs_open(struct inode *inode, struct file *file) rc = -ENOMEM; goto out; } - rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, desiredAccess, - CREATE_NOT_DIR, &netfid, &oplock, buf, + + if (cifs_sb->tcon->ses->capabilities & CAP_NT_SMBS) + rc = CIFSSMBOpen(xid, pTcon, full_path, disposition, + desiredAccess, CREATE_NOT_DIR, &netfid, &oplock, buf, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + else + rc = -EIO; /* no NT SMB support fall into legacy open below */ + if (rc == -EIO) { /* Old server, try legacy style OpenX */ rc = SMBLegacyOpen(xid, pTcon, full_path, disposition, diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index e3e762d..03bbcb3 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -109,32 +109,52 @@ static int construct_dentry(struct qstr *qstring, struct file *file, return rc; } -static void fill_in_inode(struct inode *tmp_inode, - FILE_DIRECTORY_INFO *pfindData, int *pobject_type, int isNewInode) +static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, + char * buf, int *pobject_type, int isNewInode) { loff_t local_size; struct timespec local_mtime; struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode); struct cifs_sb_info *cifs_sb = CIFS_SB(tmp_inode->i_sb); - __u32 attr = le32_to_cpu(pfindData->ExtFileAttributes); - __u64 allocation_size = le64_to_cpu(pfindData->AllocationSize); - __u64 end_of_file = le64_to_cpu(pfindData->EndOfFile); - - cifsInfo->cifsAttrs = attr; - cifsInfo->time = jiffies; + __u32 attr; + __u64 allocation_size; + __u64 end_of_file; /* save mtime and size */ local_mtime = tmp_inode->i_mtime; local_size = tmp_inode->i_size; + if(new_buf_type) { + FILE_DIRECTORY_INFO *pfindData = (FILE_DIRECTORY_INFO *)buf; + + attr = le32_to_cpu(pfindData->ExtFileAttributes); + allocation_size = le64_to_cpu(pfindData->AllocationSize); + end_of_file = le64_to_cpu(pfindData->EndOfFile); + tmp_inode->i_atime = + cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); + tmp_inode->i_mtime = + cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); + tmp_inode->i_ctime = + cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); + } else { /* legacy, OS2 and DOS style */ + FIND_FILE_STANDARD_INFO * pfindData = + (FIND_FILE_STANDARD_INFO *)buf; + + attr = le16_to_cpu(pfindData->Attributes); + allocation_size = le32_to_cpu(pfindData->AllocationSize); + end_of_file = le32_to_cpu(pfindData->DataSize); + 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 */ - tmp_inode->i_atime = - cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastAccessTime)); - tmp_inode->i_mtime = - cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); - tmp_inode->i_ctime = - cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); + + cifsInfo->cifsAttrs = attr; + cifsInfo->time = jiffies; + /* treat dos attribute of read-only as read-only mode bit e.g. 555? */ /* 2767 perms - indicate mandatory locking */ /* BB fill in uid and gid here? with help from winbind? @@ -420,7 +440,10 @@ static int initiate_cifs_search(const int xid, struct file *file) ffirst_retry: /* test for Unix extensions */ if (pTcon->ses->capabilities & CAP_UNIX) { - cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX; + cifsFile->srch_inf.info_level = SMB_FIND_FILE_UNIX; + } else if ((pTcon->ses->capabilities & + (CAP_NT_SMBS | CAP_NT_FIND)) == 0) { + cifsFile->srch_inf.info_level = SMB_FIND_FILE_INFO_STANDARD; } else if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { cifsFile->srch_inf.info_level = SMB_FIND_FILE_ID_FULL_DIR_INFO; } else /* not srvinos - BB fixme add check for backlevel? */ { @@ -456,12 +479,19 @@ static int cifs_unicode_bytelen(char *str) return len << 1; } -static char *nxt_dir_entry(char *old_entry, char *end_of_smb) +static char *nxt_dir_entry(char *old_entry, char *end_of_smb, int level) { char * new_entry; FILE_DIRECTORY_INFO * pDirInfo = (FILE_DIRECTORY_INFO *)old_entry; - new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset); + if(level == SMB_FIND_FILE_INFO_STANDARD) { + FIND_FILE_STANDARD_INFO * pfData; + pfData = (FIND_FILE_STANDARD_INFO *)pDirInfo; + + new_entry = old_entry + sizeof(FIND_FILE_STANDARD_INFO) + + pfData->FileNameLength; + } else + new_entry = old_entry + le32_to_cpu(pDirInfo->NextEntryOffset); cFYI(1,("new entry %p old entry %p",new_entry,old_entry)); /* validate that new_entry is not past end of SMB */ if(new_entry >= end_of_smb) { @@ -469,7 +499,10 @@ static char *nxt_dir_entry(char *old_entry, char *end_of_smb) ("search entry %p began after end of SMB %p old entry %p", new_entry, end_of_smb, old_entry)); return NULL; - } else if (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb) { + } else if(((level == SMB_FIND_FILE_INFO_STANDARD) && + (new_entry + sizeof(FIND_FILE_STANDARD_INFO) > end_of_smb)) || + ((level != SMB_FIND_FILE_INFO_STANDARD) && + (new_entry + sizeof(FILE_DIRECTORY_INFO) > end_of_smb))) { cERROR(1,("search entry %p extends after end of SMB %p", new_entry, end_of_smb)); return NULL; @@ -487,7 +520,7 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile) char * filename = NULL; int len = 0; - if(cfile->srch_inf.info_level == 0x202) { + if(cfile->srch_inf.info_level == SMB_FIND_FILE_UNIX) { FILE_UNIX_INFO * pFindData = (FILE_UNIX_INFO *)current_entry; filename = &pFindData->FileName[0]; if(cfile->srch_inf.unicode) { @@ -496,26 +529,34 @@ static int cifs_entry_is_dot(char *current_entry, struct cifsFileInfo *cfile) /* BB should we make this strnlen of PATH_MAX? */ len = strnlen(filename, 5); } - } else if(cfile->srch_inf.info_level == 0x101) { + } else if(cfile->srch_inf.info_level == SMB_FIND_FILE_DIRECTORY_INFO) { FILE_DIRECTORY_INFO * pFindData = (FILE_DIRECTORY_INFO *)current_entry; filename = &pFindData->FileName[0]; len = le32_to_cpu(pFindData->FileNameLength); - } else if(cfile->srch_inf.info_level == 0x102) { + } else if(cfile->srch_inf.info_level == + SMB_FIND_FILE_FULL_DIRECTORY_INFO) { FILE_FULL_DIRECTORY_INFO * pFindData = (FILE_FULL_DIRECTORY_INFO *)current_entry; filename = &pFindData->FileName[0]; len = le32_to_cpu(pFindData->FileNameLength); - } else if(cfile->srch_inf.info_level == 0x105) { + } else if(cfile->srch_inf.info_level == + SMB_FIND_FILE_ID_FULL_DIR_INFO) { SEARCH_ID_FULL_DIR_INFO * pFindData = (SEARCH_ID_FULL_DIR_INFO *)current_entry; filename = &pFindData->FileName[0]; len = le32_to_cpu(pFindData->FileNameLength); - } else if(cfile->srch_inf.info_level == 0x104) { + } else if(cfile->srch_inf.info_level == + SMB_FIND_FILE_BOTH_DIRECTORY_INFO) { FILE_BOTH_DIRECTORY_INFO * pFindData = (FILE_BOTH_DIRECTORY_INFO *)current_entry; filename = &pFindData->FileName[0]; len = le32_to_cpu(pFindData->FileNameLength); + } else if(cfile->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) { + FIND_FILE_STANDARD_INFO * pFindData = + (FIND_FILE_STANDARD_INFO *)current_entry; + filename = &pFindData->FileName[0]; + len = le32_to_cpu(pFindData->FileNameLength); } else { cFYI(1,("Unknown findfirst level %d",cfile->srch_inf.info_level)); } @@ -651,10 +692,12 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, first_entry_in_buffer = cifsFile->srch_inf.index_of_last_entry - cifsFile->srch_inf.entries_in_buffer; pos_in_buf = index_to_find - first_entry_in_buffer; - cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); + cFYI(1,("found entry - pos_in_buf %d",pos_in_buf)); + for(i=0;(i<(pos_in_buf)) && (current_entry != NULL);i++) { /* go entry by entry figuring out which is first */ - current_entry = nxt_dir_entry(current_entry,end_of_smb); + current_entry = nxt_dir_entry(current_entry,end_of_smb, + cifsFile->srch_inf.info_level); } if((current_entry == NULL) && (i < pos_in_buf)) { /* BB fixme - check if we should flag this error */ @@ -681,7 +724,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon, /* inode num, inode type and filename returned */ static int cifs_get_name_from_search_buf(struct qstr *pqst, char *current_entry, __u16 level, unsigned int unicode, - struct cifs_sb_info * cifs_sb, ino_t *pinum) + struct cifs_sb_info * cifs_sb, int max_len, ino_t *pinum) { int rc = 0; unsigned int len = 0; @@ -725,10 +768,22 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst, (FILE_BOTH_DIRECTORY_INFO *)current_entry; filename = &pFindData->FileName[0]; len = le32_to_cpu(pFindData->FileNameLength); + } else if(level == SMB_FIND_FILE_INFO_STANDARD) { + FIND_FILE_STANDARD_INFO * pFindData = + (FIND_FILE_STANDARD_INFO *)current_entry; + filename = &pFindData->FileName[0]; + /* one byte length, no name conversion */ + len = (unsigned int)pFindData->FileNameLength; } else { cFYI(1,("Unknown findfirst level %d",level)); return -EINVAL; } + + if(len > max_len) { + cERROR(1,("bad search response length %d past smb end", len)); + return -EINVAL; + } + if(unicode) { /* BB fixme - test with long names */ /* Note converted filename can be longer than in unicode */ @@ -748,7 +803,7 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst, } static int cifs_filldir(char *pfindEntry, struct file *file, - filldir_t filldir, void *direntry, char *scratch_buf) + filldir_t filldir, void *direntry, char *scratch_buf, int max_len) { int rc = 0; struct qstr qstring; @@ -784,6 +839,7 @@ static int cifs_filldir(char *pfindEntry, struct file *file, rc = cifs_get_name_from_search_buf(&qstring,pfindEntry, pCifsF->srch_inf.info_level, pCifsF->srch_inf.unicode,cifs_sb, + max_len, &inum /* returned */); if(rc) @@ -805,13 +861,16 @@ static int cifs_filldir(char *pfindEntry, struct file *file, /* we pass in rc below, indicating whether it is a new inode, so we can figure out whether to invalidate the inode cached data if the file has changed */ - if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) { + if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX) unix_fill_in_inode(tmp_inode, - (FILE_UNIX_INFO *)pfindEntry,&obj_type, rc); - } else { - fill_in_inode(tmp_inode, - (FILE_DIRECTORY_INFO *)pfindEntry,&obj_type, rc); - } + (FILE_UNIX_INFO *)pfindEntry, + &obj_type, rc); + else if(pCifsF->srch_inf.info_level == SMB_FIND_FILE_INFO_STANDARD) + fill_in_inode(tmp_inode, 0 /* old level 1 buffer type */, + pfindEntry, &obj_type, rc); + else + fill_in_inode(tmp_inode, 1 /* NT */, pfindEntry, &obj_type, rc); + rc = filldir(direntry,qstring.name,qstring.len,file->f_pos, tmp_inode->i_ino,obj_type); @@ -871,6 +930,12 @@ static int cifs_save_resume_key(const char *current_entry, filename = &pFindData->FileName[0]; len = le32_to_cpu(pFindData->FileNameLength); cifsFile->srch_inf.resume_key = pFindData->FileIndex; + } else if(level == SMB_FIND_FILE_INFO_STANDARD) { + FIND_FILE_STANDARD_INFO * pFindData = + (FIND_FILE_STANDARD_INFO *)current_entry; + filename = &pFindData->FileName[0]; + /* one byte length, no name conversion */ + len = (unsigned int)pFindData->FileNameLength; } else { cFYI(1,("Unknown findfirst level %d",level)); return -EINVAL; @@ -891,6 +956,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) int num_to_fill = 0; char * tmp_buf = NULL; char * end_of_smb; + int max_len; xid = GetXid(); @@ -966,10 +1032,11 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) goto rddir2_exit; } cFYI(1,("loop through %d times filling dir for net buf %p", - num_to_fill,cifsFile->srch_inf.ntwrk_buf_start)); - end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + - smbCalcSize((struct smb_hdr *) - cifsFile->srch_inf.ntwrk_buf_start); + num_to_fill,cifsFile->srch_inf.ntwrk_buf_start)); + max_len = smbCalcSize((struct smb_hdr *) + cifsFile->srch_inf.ntwrk_buf_start); + end_of_smb = cifsFile->srch_inf.ntwrk_buf_start + max_len; + /* To be safe - for UCS to UTF-8 with strings loaded with the rare long characters alloc more to account for such multibyte target UTF-8 characters. cifs_unicode.c, @@ -984,8 +1051,8 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) } /* if buggy server returns . and .. late do we want to check for that here? */ - rc = cifs_filldir(current_entry, file, - filldir, direntry,tmp_buf); + rc = cifs_filldir(current_entry, file, + filldir, direntry, tmp_buf, max_len); file->f_pos++; if(file->f_pos == cifsFile->srch_inf.index_of_last_entry) { @@ -994,8 +1061,9 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) cifs_save_resume_key(current_entry,cifsFile); break; } else - current_entry = nxt_dir_entry(current_entry, - end_of_smb); + current_entry = + nxt_dir_entry(current_entry, end_of_smb, + cifsFile->srch_inf.info_level); } kfree(tmp_buf); break; -- cgit v1.1 From 1717ffc58850dfa9e08b4977f8d0323cb3336863 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 8 Jun 2006 05:41:32 +0000 Subject: [CIFS] NTLMv2 support part 5 NTLMv2 authentication (stronger authentication than default NTLM) which many servers support now works. There was a problem with the construction of the security blob in the older code. Currently requires /proc/fs/cifs/Experimental to be set to 2 and /proc/fs/cifs/SecurityFlags to be set to 0x4004 (to require using NTLMv2 instead of default of NTLM) Next we will check signing to make sure optional NTLMv2 packet signing also works. Signed-off-by: Steve French --- fs/cifs/CHANGES | 4 +++- fs/cifs/cifsencrypt.c | 60 +++++++++++++++++++++++++++++++++++---------------- fs/cifs/cifsproto.h | 8 ++++--- fs/cifs/sess.c | 2 +- 4 files changed, 50 insertions(+), 24 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 7e0058b..79a202b 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -5,7 +5,9 @@ session setup needed for OS/2 and older servers such as Windows 95 and 98. Fix oops on ls to OS/2 servers. Add support for level 1 FindFirst so we can do search (ls etc.) to OS/2. Do not send NTCreateX or recent levels of FindFirst unless server says it supports NT SMBs -(instead use legacy equivalents from LANMAN dialect). +(instead use legacy equivalents from LANMAN dialect). Fix to allow +NTLMv2 authentication support (now can use stronger password hashing +on mount if corresponding /proc/fs/cifs/SecurityFlags is set (0x4004) Version 1.43 ------------ diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 8bcb1da..a89efaf 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -212,7 +212,8 @@ int cifs_calculate_mac_key(char * key, const char * rn, const char * password) return 0; } -int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_info) +int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, + const struct nls_table * nls_info) { char temp_hash[16]; struct HMACMD5Context ctx; @@ -305,13 +306,15 @@ void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key) } #endif /* CIFS_WEAK_PW_HASH */ -static int calc_ntlmv2_hash(const struct cifsSesInfo *ses, - char * ntv2_hash) +static int calc_ntlmv2_hash(struct cifsSesInfo *ses, + const struct nls_table * nls_cp) { int rc = 0; int len; char nt_hash[16]; struct HMACMD5Context * pctxt; + wchar_t * user; + wchar_t * domain; pctxt = kmalloc(sizeof(struct HMACMD5Context), GFP_KERNEL); @@ -321,26 +324,44 @@ static int calc_ntlmv2_hash(const struct cifsSesInfo *ses, /* calculate md4 hash of password */ E_md4hash(ses->password, nt_hash); - /* convERT Domainname to unicode and uppercase */ + /* convert Domainname to unicode and uppercase */ hmac_md5_init_limK_to_64(nt_hash, 16, pctxt); /* convert ses->userName to unicode and uppercase */ - - /* len = ... */ /* BB FIXME BB */ - - /* hmac_md5_update(user, len, pctxt); */ + len = strlen(ses->userName); + user = kmalloc(2 + (len * 2), GFP_KERNEL); + if(user == NULL) + goto calc_exit_2; + len = cifs_strtoUCS(user, ses->userName, len, nls_cp); + UniStrupr(user); + hmac_md5_update((char *)user, 2*len, pctxt); /* convert ses->domainName to unicode and uppercase */ + if(ses->domainName) { + len = strlen(ses->domainName); - /* len = ... */ /* BB FIXME BB */ - /* hmac_md5_update(domain, len, pctxt); */ + domain = kmalloc(2 + (len * 2), GFP_KERNEL); + if(domain == NULL) + goto calc_exit_1; + len = cifs_strtoUCS(domain, ses->domainName, len, nls_cp); + UniStrupr(domain); - hmac_md5_final(ntv2_hash, pctxt); + hmac_md5_update((char *)domain, 2*len, pctxt); + + kfree(domain); + } +calc_exit_1: + kfree(user); +calc_exit_2: + /* BB FIXME what about bytes 24 through 40 of the signing key? + compare with the NTLM example */ + hmac_md5_final(ses->server->mac_signing_key, pctxt); return rc; } -void setup_ntlmv2_rsp(const struct cifsSesInfo * ses, char * resp_buf) +void setup_ntlmv2_rsp(struct cifsSesInfo * ses, char * resp_buf, + const struct nls_table * nls_cp) { int rc; struct ntlmv2_resp * buf = (struct ntlmv2_resp *)resp_buf; @@ -348,27 +369,28 @@ void setup_ntlmv2_rsp(const struct cifsSesInfo * ses, char * resp_buf) buf->blob_signature = cpu_to_le32(0x00000101); buf->reserved = 0; buf->time = cpu_to_le64(cifs_UnixTimeToNT(CURRENT_TIME)); - get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); + get_random_bytes(&buf->client_chal, sizeof(buf->client_chal)); buf->reserved2 = 0; buf->names[0].type = 0; buf->names[0].length = 0; /* calculate buf->ntlmv2_hash */ - rc = calc_ntlmv2_hash(ses,buf->ntlmv2_hash); + rc = calc_ntlmv2_hash(ses, nls_cp); if(rc) cERROR(1,("could not get v2 hash rc %d",rc)); + CalcNTLMv2_response(ses, resp_buf); } -void CalcNTLMv2_response(const struct cifsSesInfo * ses,char * v2_session_response) +void CalcNTLMv2_response(const struct cifsSesInfo * ses, char * v2_session_response) { struct HMACMD5Context context; + /* rest of v2 struct already generated */ memcpy(v2_session_response + 8, ses->server->cryptKey,8); - /* gen_blob(v2_session_response + 16); */ hmac_md5_init_limK_to_64(ses->server->mac_signing_key, 16, &context); - hmac_md5_update(ses->server->cryptKey,8,&context); -/* hmac_md5_update(v2_session_response+16)client thing,8,&context); */ /* BB fix */ + hmac_md5_update(v2_session_response+8, + sizeof(struct ntlmv2_resp) - 8, &context); hmac_md5_final(v2_session_response,&context); - cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); /* BB removeme BB */ +/* cifs_dump_mem("v2_sess_rsp: ", v2_session_response, 32); */ } diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 824afb9..7ffd5b0 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -285,9 +285,11 @@ extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *, extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key, __u32 expected_sequence_number); extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass); -extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, struct nls_table *); -extern void CalcNTLMv2_response(const struct cifsSesInfo *,char * ); -extern void setup_ntlmv2_rsp(const struct cifsSesInfo *, char *); +extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, + const struct nls_table *); +extern void CalcNTLMv2_response(const struct cifsSesInfo *, char * ); +extern void setup_ntlmv2_rsp(struct cifsSesInfo *, char *, + const struct nls_table *); #ifdef CONFIG_CIFS_WEAK_PW_HASH extern void calc_lanman_hash(struct cifsSesInfo * ses, char * lnm_session_key); #endif /* CIFS_WEAK_PW_HASH */ diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index c6fd01f..c039b54 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -432,7 +432,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, cpu_to_le16(sizeof(struct ntlmv2_resp)); /* calculate session key */ - setup_ntlmv2_rsp(ses, v2_sess_key); + setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp); if(first_time) /* should this be moved into common code with similar ntlmv2 path? */ /* cifs_calculate_ntlmv2_mac_key(ses->server->mac_signing_key, -- cgit v1.1 From 8b512d9a88875affe584bb3d2a7a235f84343b9e Mon Sep 17 00:00:00 2001 From: Trond Myklebust Date: Fri, 9 Jun 2006 09:34:18 -0400 Subject: VFS: Remove dependency of ->umount_begin() call on MNT_FORCE Allow filesystems to decide to perform pre-umount processing whether or not MNT_FORCE is set. Signed-off-by: Trond Myklebust --- fs/cifs/cifsfs.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index c262d88..3fdc225 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -402,12 +402,14 @@ static struct quotactl_ops cifs_quotactl_ops = { #endif #ifdef CONFIG_CIFS_EXPERIMENTAL -static void cifs_umount_begin(struct super_block * sblock) +static void cifs_umount_begin(struct vfsmount * vfsmnt, int flags) { struct cifs_sb_info *cifs_sb; struct cifsTconInfo * tcon; - cifs_sb = CIFS_SB(sblock); + if (!(flags & MNT_FORCE)) + return; + cifs_sb = CIFS_SB(vfsmnt->mnt_sb); if(cifs_sb == NULL) return; -- cgit v1.1 From 6344a423e5806d138923caa1d7699f3b7809fe43 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 12 Jun 2006 04:18:35 +0000 Subject: [CIFS] fix minor compile warning when config_cifs_weak_security is off Signed-off-by: Steve French --- fs/cifs/cifssmb.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'fs/cifs') diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index acae583..271a037 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -569,7 +569,9 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) } else server->capabilities &= ~CAP_EXTENDED_SECURITY; +#ifdef CONFIG_CIFS_WEAK_PW_HASH signing_check: +#endif if(sign_CIFS_PDUs == FALSE) { if(server->secMode & SECMODE_SIGN_REQUIRED) cERROR(1,("Server requires " -- cgit v1.1 From 0fd1ffe0633b4b039b343b753598e6df435e034d Mon Sep 17 00:00:00 2001 From: Pavel Machek Date: Tue, 13 Jun 2006 21:31:39 +0000 Subject: [CIFS] Fix suspend/resume problem which causes EIO on subsequent access to the mount. Signed-off-by: Pavel Machek Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 2 +- fs/cifs/connect.c | 24 ++++++++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 7005705..fb7c11c 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -905,7 +905,7 @@ static int cifs_dnotify_thread(void * dummyarg) struct cifsSesInfo *ses; do { - if(try_to_freeze()) + if (try_to_freeze()) continue; set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(15*HZ); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index e6f3d2f..faaf9eb 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -367,21 +367,21 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) continue; if (bigbuf == NULL) { bigbuf = cifs_buf_get(); - if(bigbuf == NULL) { - cERROR(1,("No memory for large SMB response")); + if (!bigbuf) { + cERROR(1, ("No memory for large SMB response")); msleep(3000); /* retry will check if exiting */ continue; } - } else if(isLargeBuf) { - /* we are reusing a dirtry large buf, clear its start */ + } else if (isLargeBuf) { + /* we are reusing a dirty large buf, clear its start */ memset(bigbuf, 0, sizeof (struct smb_hdr)); } if (smallbuf == NULL) { smallbuf = cifs_small_buf_get(); - if(smallbuf == NULL) { - cERROR(1,("No memory for SMB response")); + if (!smallbuf) { + cERROR(1, ("No memory for SMB response")); msleep(1000); /* retry will check if exiting */ continue; @@ -401,12 +401,12 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) kernel_recvmsg(csocket, &smb_msg, &iov, 1, 4, 0 /* BB see socket.h flags */); - if(server->tcpStatus == CifsExiting) { + if (server->tcpStatus == CifsExiting) { break; } else if (server->tcpStatus == CifsNeedReconnect) { - cFYI(1,("Reconnect after server stopped responding")); + cFYI(1, ("Reconnect after server stopped responding")); cifs_reconnect(server); - cFYI(1,("call to reconnect done")); + cFYI(1, ("call to reconnect done")); csocket = server->ssocket; continue; } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) { @@ -415,15 +415,15 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) tcpStatus CifsNeedReconnect if server hung */ continue; } else if (length <= 0) { - if(server->tcpStatus == CifsNew) { - cFYI(1,("tcp session abend after SMBnegprot")); + if (server->tcpStatus == CifsNew) { + cFYI(1, ("tcp session abend after SMBnegprot")); /* some servers kill the TCP session rather than returning an SMB negprot error, in which case reconnecting here is not going to help, and so simply return error to mount */ break; } - if(length == -EINTR) { + if (!try_to_freeze() && (length == -EINTR)) { cFYI(1,("cifsd thread killed")); break; } -- cgit v1.1 From 189acaaef81b1d71aedd0d28810de24160c2e781 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 23 Jun 2006 02:33:48 +0000 Subject: [CIFS] Enable sec flags on mount for cifs (part one) Signed-off-by: Steve French --- fs/cifs/README | 2 + fs/cifs/cifsproto.h | 2 +- fs/cifs/connect.c | 338 ++++------------------------------------------------ fs/cifs/sess.c | 7 +- 4 files changed, 28 insertions(+), 321 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/README b/fs/cifs/README index a68f8e3..46c2cfa 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -453,6 +453,8 @@ sec Security mode. Allowed values are: server requires signing also can be the default) ntlmv2 Use NTLMv2 password hashing ntlmv2i Use NTLMv2 password hashing with packet signing + lanman (if configured in kernel config) use older + lanman hash The mount.cifs mount helper also accepts a few mount options before -o including: diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 7ffd5b0..7ed06bf 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -68,10 +68,10 @@ extern void header_assemble(struct smb_hdr *, char /* command */ , extern int small_smb_init_no_tc(const int smb_cmd, const int wct, struct cifsSesInfo *ses, void ** request_buf); +#endif extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, const int stage, const struct nls_table *nls_cp); -#endif extern __u16 GetNextMid(struct TCP_Server_Info *server); extern struct oplock_q_entry * AllocOplockQEntry(struct inode *, u16, struct cifsTconInfo *); diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index faaf9eb..01608bb 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -68,6 +68,7 @@ struct smb_vol { gid_t linux_gid; mode_t file_mode; mode_t dir_mode; + unsigned secFlg; unsigned rw:1; unsigned retry:1; unsigned intr:1; @@ -81,12 +82,7 @@ struct smb_vol { unsigned remap:1; /* set to remap seven reserved chars in filenames */ unsigned posix_paths:1; /* unset to not ask for posix pathnames. */ unsigned sfu_emul:1; - unsigned krb5:1; - unsigned ntlm:1; - unsigned ntlmv2:1; unsigned nullauth:1; /* attempt to authenticate with null user */ - unsigned sign:1; - unsigned seal:1; /* encrypt */ unsigned nocase; /* request case insensitive filenames */ unsigned nobrl; /* disable sending byte range locks to srv */ unsigned int rsize; @@ -789,7 +785,6 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ vol->rw = TRUE; - vol->ntlm = TRUE; /* default is always to request posix paths. */ vol->posix_paths = 1; @@ -920,30 +915,35 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) cERROR(1,("no security value specified")); continue; } else if (strnicmp(value, "krb5i", 5) == 0) { - vol->sign = 1; - vol->krb5 = 1; + vol->secFlg = CIFSSEC_MAY_KRB5 | + CIFSSEC_MUST_SIGN; } else if (strnicmp(value, "krb5p", 5) == 0) { - /* vol->seal = 1; - vol->krb5 = 1; */ + /* vol->secFlg = CIFSSEC_MUST_SEAL | + CIFSSEC_MAY_KRB5; */ cERROR(1,("Krb5 cifs privacy not supported")); return 1; } else if (strnicmp(value, "krb5", 4) == 0) { - vol->krb5 = 1; + vol->secFlg = CIFSSEC_MAY_KRB5; } else if (strnicmp(value, "ntlmv2i", 7) == 0) { - vol->ntlmv2 = 1; - vol->sign = 1; + vol->secFlg = CIFSSEC_MAY_NTLMV2 | + CIFSSEC_MUST_SIGN; } else if (strnicmp(value, "ntlmv2", 6) == 0) { - vol->ntlmv2 = 1; + vol->secFlg = CIFSSEC_MAY_NTLMV2; } else if (strnicmp(value, "ntlmi", 5) == 0) { - vol->ntlm = 1; - vol->sign = 1; + vol->secFlg = CIFSSEC_MAY_NTLM | + CIFSSEC_MUST_SIGN; } else if (strnicmp(value, "ntlm", 4) == 0) { /* ntlm is default so can be turned off too */ - vol->ntlm = 1; + vol->secFlg = CIFSSEC_MAY_NTLM; } else if (strnicmp(value, "nontlm", 6) == 0) { - vol->ntlm = 0; + /* BB is there a better way to do this? */ + vol->secFlg = CIFSSEC_MAY_NTLMV2; +#ifdef CONFIG_CIFS_WEAK_PW_HASH + } else if (strnicmp(value, "lanman", 6) == 0) { + vol->secFlg = CIFSSEC_MAY_LANMAN; +#endif } else if (strnicmp(value, "none", 4) == 0) { - vol->nullauth = 1; + vol->nullauth = 1; } else { cERROR(1,("bad security option: %s", value)); return 1; @@ -1777,6 +1777,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, } pSesInfo->linux_uid = volume_info.linux_uid; down(&pSesInfo->sesSem); + /* BB FIXME need to pass vol->secFlgs BB */ rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls); up(&pSesInfo->sesSem); if(!rc) @@ -2284,292 +2285,6 @@ sesssetup_nomem: /* do not return an error on nomem for the info strings, } static int -CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, - char *SecurityBlob,int SecurityBlobLength, - const struct nls_table *nls_codepage) -{ - struct smb_hdr *smb_buffer; - struct smb_hdr *smb_buffer_response; - SESSION_SETUP_ANDX *pSMB; - SESSION_SETUP_ANDX *pSMBr; - char *bcc_ptr; - char *user; - char *domain; - int rc = 0; - int remaining_words = 0; - int bytes_returned = 0; - int len; - __u32 capabilities; - __u16 count; - - cFYI(1, ("In spnego sesssetup ")); - if(ses == NULL) - return -EINVAL; - user = ses->userName; - domain = ses->domainName; - - smb_buffer = cifs_buf_get(); - if (smb_buffer == NULL) { - return -ENOMEM; - } - smb_buffer_response = smb_buffer; - pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer; - - /* send SMBsessionSetup here */ - header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, - NULL /* no tCon exists yet */ , 12 /* wct */ ); - - smb_buffer->Mid = GetNextMid(ses->server); - pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; - pSMB->req.AndXCommand = 0xFF; - if(ses->server->maxBuf > 64*1024) - ses->server->maxBuf = (64*1023); - pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); - pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); - - if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) - smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; - - capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | - CAP_EXTENDED_SECURITY; - if (ses->capabilities & CAP_UNICODE) { - smb_buffer->Flags2 |= SMBFLG2_UNICODE; - capabilities |= CAP_UNICODE; - } - if (ses->capabilities & CAP_STATUS32) { - smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; - capabilities |= CAP_STATUS32; - } - if (ses->capabilities & CAP_DFS) { - smb_buffer->Flags2 |= SMBFLG2_DFS; - capabilities |= CAP_DFS; - } - pSMB->req.Capabilities = cpu_to_le32(capabilities); - - pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength); - bcc_ptr = pByteArea(smb_buffer); - memcpy(bcc_ptr, SecurityBlob, SecurityBlobLength); - bcc_ptr += SecurityBlobLength; - - if (ses->capabilities & CAP_UNICODE) { - if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode strings */ - *bcc_ptr = 0; - bcc_ptr++; - } - bytes_returned = - cifs_strtoUCS((__le16 *) bcc_ptr, user, 100, nls_codepage); - bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */ - bcc_ptr += 2; /* trailing null */ - if (domain == NULL) - bytes_returned = - cifs_strtoUCS((__le16 *) bcc_ptr, - "CIFS_LINUX_DOM", 32, nls_codepage); - else - bytes_returned = - cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64, - nls_codepage); - bcc_ptr += 2 * bytes_returned; - bcc_ptr += 2; - bytes_returned = - cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", - 32, nls_codepage); - bcc_ptr += 2 * bytes_returned; - bytes_returned = - cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32, - nls_codepage); - bcc_ptr += 2 * bytes_returned; - bcc_ptr += 2; - bytes_returned = - cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, - 64, nls_codepage); - bcc_ptr += 2 * bytes_returned; - bcc_ptr += 2; - } else { - strncpy(bcc_ptr, user, 200); - bcc_ptr += strnlen(user, 200); - *bcc_ptr = 0; - bcc_ptr++; - if (domain == NULL) { - strcpy(bcc_ptr, "CIFS_LINUX_DOM"); - bcc_ptr += strlen("CIFS_LINUX_DOM") + 1; - } else { - strncpy(bcc_ptr, domain, 64); - bcc_ptr += strnlen(domain, 64); - *bcc_ptr = 0; - bcc_ptr++; - } - strcpy(bcc_ptr, "Linux version "); - bcc_ptr += strlen("Linux version "); - strcpy(bcc_ptr, system_utsname.release); - bcc_ptr += strlen(system_utsname.release) + 1; - strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); - bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; - } - count = (long) bcc_ptr - (long) pByteArea(smb_buffer); - smb_buffer->smb_buf_length += count; - pSMB->req.ByteCount = cpu_to_le16(count); - - rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, - &bytes_returned, 1); - if (rc) { -/* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */ - } else if ((smb_buffer_response->WordCount == 3) - || (smb_buffer_response->WordCount == 4)) { - __u16 action = le16_to_cpu(pSMBr->resp.Action); - __u16 blob_len = - le16_to_cpu(pSMBr->resp.SecurityBlobLength); - if (action & GUEST_LOGIN) - cFYI(1, (" Guest login")); /* BB do we want to set anything in SesInfo struct ? */ - if (ses) { - ses->Suid = smb_buffer_response->Uid; /* UID left in wire format (le) */ - cFYI(1, ("UID = %d ", ses->Suid)); - bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */ - - /* BB Fix below to make endian neutral !! */ - - if ((pSMBr->resp.hdr.WordCount == 3) - || ((pSMBr->resp.hdr.WordCount == 4) - && (blob_len < - pSMBr->resp.ByteCount))) { - if (pSMBr->resp.hdr.WordCount == 4) { - bcc_ptr += - blob_len; - cFYI(1, - ("Security Blob Length %d ", - blob_len)); - } - - if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { - if ((long) (bcc_ptr) % 2) { - remaining_words = - (BCC(smb_buffer_response) - - 1) / 2; - bcc_ptr++; /* Unicode strings must be word aligned */ - } else { - remaining_words = - BCC - (smb_buffer_response) / 2; - } - len = - UniStrnlen((wchar_t *) bcc_ptr, - remaining_words - 1); -/* We look for obvious messed up bcc or strings in response so we do not go off - the end since (at least) WIN2K and Windows XP have a major bug in not null - terminating last Unicode string in response */ - if(ses->serverOS) - kfree(ses->serverOS); - ses->serverOS = - kzalloc(2 * (len + 1), GFP_KERNEL); - cifs_strfromUCS_le(ses->serverOS, - (__le16 *) - bcc_ptr, len, - nls_codepage); - bcc_ptr += 2 * (len + 1); - remaining_words -= len + 1; - ses->serverOS[2 * len] = 0; - ses->serverOS[1 + (2 * len)] = 0; - if (remaining_words > 0) { - len = UniStrnlen((wchar_t *)bcc_ptr, - remaining_words - - 1); - if(ses->serverNOS) - kfree(ses->serverNOS); - ses->serverNOS = - kzalloc(2 * (len + 1), - GFP_KERNEL); - cifs_strfromUCS_le(ses->serverNOS, - (__le16 *)bcc_ptr, - len, - nls_codepage); - bcc_ptr += 2 * (len + 1); - ses->serverNOS[2 * len] = 0; - ses->serverNOS[1 + (2 * len)] = 0; - remaining_words -= len + 1; - if (remaining_words > 0) { - len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); - /* last string not null terminated (e.g.Windows XP/2000) */ - if(ses->serverDomain) - kfree(ses->serverDomain); - ses->serverDomain = kzalloc(2*(len+1),GFP_KERNEL); - cifs_strfromUCS_le(ses->serverDomain, - (__le16 *)bcc_ptr, - len, nls_codepage); - bcc_ptr += 2*(len+1); - ses->serverDomain[2*len] = 0; - ses->serverDomain[1+(2*len)] = 0; - } /* else no more room so create dummy domain string */ - else { - if(ses->serverDomain) - kfree(ses->serverDomain); - ses->serverDomain = - kzalloc(2,GFP_KERNEL); - } - } else {/* no room use dummy domain&NOS */ - if(ses->serverDomain) - kfree(ses->serverDomain); - ses->serverDomain = kzalloc(2, GFP_KERNEL); - if(ses->serverNOS) - kfree(ses->serverNOS); - ses->serverNOS = kzalloc(2, GFP_KERNEL); - } - } else { /* ASCII */ - - len = strnlen(bcc_ptr, 1024); - if (((long) bcc_ptr + len) - (long) - pByteArea(smb_buffer_response) - <= BCC(smb_buffer_response)) { - if(ses->serverOS) - kfree(ses->serverOS); - ses->serverOS = kzalloc(len + 1, GFP_KERNEL); - strncpy(ses->serverOS, bcc_ptr, len); - - bcc_ptr += len; - bcc_ptr[0] = 0; /* null terminate the string */ - bcc_ptr++; - - len = strnlen(bcc_ptr, 1024); - if(ses->serverNOS) - kfree(ses->serverNOS); - ses->serverNOS = kzalloc(len + 1,GFP_KERNEL); - strncpy(ses->serverNOS, bcc_ptr, len); - bcc_ptr += len; - bcc_ptr[0] = 0; - bcc_ptr++; - - len = strnlen(bcc_ptr, 1024); - if(ses->serverDomain) - kfree(ses->serverDomain); - ses->serverDomain = kzalloc(len + 1, GFP_KERNEL); - strncpy(ses->serverDomain, bcc_ptr, len); - bcc_ptr += len; - bcc_ptr[0] = 0; - bcc_ptr++; - } else - cFYI(1, - ("Variable field of length %d extends beyond end of smb ", - len)); - } - } else { - cERROR(1, - (" Security Blob Length extends beyond end of SMB")); - } - } else { - cERROR(1, ("No session structure passed in.")); - } - } else { - cERROR(1, - (" Invalid Word count %d: ", - smb_buffer_response->WordCount)); - rc = -EIO; - } - - if (smb_buffer) - cifs_buf_release(smb_buffer); - - return rc; -} - -static int CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, struct cifsSesInfo *ses, int * pNTLMv2_flag, const struct nls_table *nls_codepage) @@ -3550,20 +3265,13 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, pSesInfo->server->secMode, pSesInfo->server->capabilities, pSesInfo->server->timeZone)); -#ifdef CONFIG_CIFS_EXPERIMENTAL - if(experimEnabled > 1) + if(experimEnabled < 2) rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info); - else -#endif - if (extended_security + else if (extended_security && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) && (pSesInfo->server->secType == NTLMSSP)) { - cFYI(1, ("New style sesssetup")); - rc = CIFSSpnegoSessSetup(xid, pSesInfo, - NULL /* security blob */, - 0 /* blob length */, - nls_info); + rc = -EOPNOTSUPP; } else if (extended_security && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) && (pSesInfo->server->secType == RawNTLMSSP)) { diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index c039b54..70e32a8 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -33,8 +33,6 @@ extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, unsigned char *p24); -#ifdef CONFIG_CIFS_EXPERIMENTAL - static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) { __u32 capabilities = 0; @@ -319,7 +317,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, __u32 capabilities; int count; int resp_buf_type = 0; - struct kvec iov[1]; + struct kvec iov[2]; /* BB split variable length info into 2nd iovec */ enum securityEnum type; __u16 action; int bytes_remaining; @@ -489,7 +487,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, } action = le16_to_cpu(pSMB->resp.Action); if (action & GUEST_LOGIN) - cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */ + cFYI(1, ("Guest login")); /* BB mark SesInfo struct? */ ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */ cFYI(1, ("UID = %d ", ses->Suid)); /* response can have either 3 or 4 word count - Samba sends 3 */ @@ -525,4 +523,3 @@ ssetup_exit: return rc; } -#endif /* CONFIG_CIFS_EXPERIMENTAL */ -- cgit v1.1 From 454e2398be9b9fa30433fccc548db34d19aa9958 Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 23 Jun 2006 02:02:57 -0700 Subject: [PATCH] VFS: Permit filesystem to override root dentry on mount Extend the get_sb() filesystem operation to take an extra argument that permits the VFS to pass in the target vfsmount that defines the mountpoint. The filesystem is then required to manually set the superblock and root dentry pointers. For most filesystems, this should be done with simple_set_mnt() which will set the superblock pointer and then set the root dentry to the superblock's s_root (as per the old default behaviour). The get_sb() op now returns an integer as there's now no need to return the superblock pointer. This patch permits a superblock to be implicitly shared amongst several mount points, such as can be done with NFS to avoid potential inode aliasing. In such a case, simple_set_mnt() would not be called, and instead the mnt_root and mnt_sb would be set directly. The patch also makes the following changes: (*) the get_sb_*() convenience functions in the core kernel now take a vfsmount pointer argument and return an integer, so most filesystems have to change very little. (*) If one of the convenience function is not used, then get_sb() should normally call simple_set_mnt() to instantiate the vfsmount. This will always return 0, and so can be tail-called from get_sb(). (*) generic_shutdown_super() now calls shrink_dcache_sb() to clean up the dcache upon superblock destruction rather than shrink_dcache_anon(). This is required because the superblock may now have multiple trees that aren't actually bound to s_root, but that still need to be cleaned up. The currently called functions assume that the whole tree is rooted at s_root, and that anonymous dentries are not the roots of trees which results in dentries being left unculled. However, with the way NFS superblock sharing are currently set to be implemented, these assumptions are violated: the root of the filesystem is simply a dummy dentry and inode (the real inode for '/' may well be inaccessible), and all the vfsmounts are rooted on anonymous[*] dentries with child trees. [*] Anonymous until discovered from another tree. (*) The documentation has been adjusted, including the additional bit of changing ext2_* into foo_* in the documentation. [akpm@osdl.org: convert ipath_fs, do other stuff] Signed-off-by: David Howells Acked-by: Al Viro Cc: Nathan Scott Cc: Roland Dreier Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/cifs/cifsfs.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index c262d88..08b3580 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -460,9 +460,9 @@ struct super_operations cifs_super_ops = { .remount_fs = cifs_remount, }; -static struct super_block * +static int cifs_get_sb(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) + int flags, const char *dev_name, void *data, struct vfsmount *mnt) { int rc; struct super_block *sb = sget(fs_type, NULL, set_anon_super, NULL); @@ -470,7 +470,7 @@ cifs_get_sb(struct file_system_type *fs_type, cFYI(1, ("Devname: %s flags: %d ", dev_name, flags)); if (IS_ERR(sb)) - return sb; + return PTR_ERR(sb); sb->s_flags = flags; @@ -478,10 +478,10 @@ cifs_get_sb(struct file_system_type *fs_type, if (rc) { up_write(&sb->s_umount); deactivate_super(sb); - return ERR_PTR(rc); + return rc; } sb->s_flags |= MS_ACTIVE; - return sb; + return simple_set_mnt(mnt, sb); } static ssize_t cifs_file_writev(struct file *file, const struct iovec *iov, -- cgit v1.1 From 726c334223180e3c0197cc980a432681370d4baf Mon Sep 17 00:00:00 2001 From: David Howells Date: Fri, 23 Jun 2006 02:02:58 -0700 Subject: [PATCH] VFS: Permit filesystem to perform statfs with a known root dentry Give the statfs superblock operation a dentry pointer rather than a superblock pointer. This complements the get_sb() patch. That reduced the significance of sb->s_root, allowing NFS to place a fake root there. However, NFS does require a dentry to use as a target for the statfs operation. This permits the root in the vfsmount to be used instead. linux/mount.h has been added where necessary to make allyesconfig build successfully. Interest has also been expressed for use with the FUSE and XFS filesystems. Signed-off-by: David Howells Acked-by: Al Viro Cc: Nathan Scott Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/cifs/cifsfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 08b3580..7520f46 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -166,8 +166,9 @@ cifs_put_super(struct super_block *sb) } static int -cifs_statfs(struct super_block *sb, struct kstatfs *buf) +cifs_statfs(struct dentry *dentry, struct kstatfs *buf) { + struct super_block *sb = dentry->d_sb; int xid; int rc = -EOPNOTSUPP; struct cifs_sb_info *cifs_sb; -- cgit v1.1 From 111ebb6e6f7bd7de6d722c5848e95621f43700d9 Mon Sep 17 00:00:00 2001 From: OGAWA Hirofumi Date: Fri, 23 Jun 2006 02:03:26 -0700 Subject: [PATCH] writeback: fix range handling When a writeback_control's `start' and `end' fields are used to indicate a one-byte-range starting at file offset zero, the required values of .start=0,.end=0 mean that the ->writepages() implementation has no way of telling that it is being asked to perform a range request. Because we're currently overloading (start == 0 && end == 0) to mean "this is not a write-a-range request". To make all this sane, the patch changes range of writeback_control. So caller does: If it is calling ->writepages() to write pages, it sets range (range_start/end or range_cyclic) always. And if range_cyclic is true, ->writepages() thinks the range is cyclic, otherwise it just uses range_start and range_end. This patch does, - Add LLONG_MAX, LLONG_MIN, ULLONG_MAX to include/linux/kernel.h -1 is usually ok for range_end (type is long long). But, if someone did, range_end += val; range_end is "val - 1" u64val = range_end >> bits; u64val is "~(0ULL)" or something, they are wrong. So, this adds LLONG_MAX to avoid nasty things, and uses LLONG_MAX for range_end. - All callers of ->writepages() sets range_start/end or range_cyclic. - Fix updates of ->writeback_index. It seems already bit strange. If it starts at 0 and ended by check of nr_to_write, this last index may reduce chance to scan end of file. So, this updates ->writeback_index only if range_cyclic is true or whole-file is scanned. Signed-off-by: OGAWA Hirofumi Cc: Nathan Scott Cc: Anton Altaparmakov Cc: Steven French Cc: "Vladimir V. Saveliev" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/cifs/file.c | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/file.c b/fs/cifs/file.c index e2b4ce1..487ea8b 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1079,9 +1079,9 @@ static int cifs_writepages(struct address_space *mapping, unsigned int bytes_written; struct cifs_sb_info *cifs_sb; int done = 0; - pgoff_t end = -1; + pgoff_t end; pgoff_t index; - int is_range = 0; + int range_whole = 0; struct kvec iov[32]; int len; int n_iov = 0; @@ -1122,16 +1122,14 @@ static int cifs_writepages(struct address_space *mapping, xid = GetXid(); pagevec_init(&pvec, 0); - if (wbc->sync_mode == WB_SYNC_NONE) + if (wbc->range_cyclic) { index = mapping->writeback_index; /* Start from prev offset */ - else { - index = 0; - scanned = 1; - } - if (wbc->start || wbc->end) { - index = wbc->start >> PAGE_CACHE_SHIFT; - end = wbc->end >> PAGE_CACHE_SHIFT; - is_range = 1; + end = -1; + } else { + index = wbc->range_start >> PAGE_CACHE_SHIFT; + end = wbc->range_end >> PAGE_CACHE_SHIFT; + if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) + range_whole = 1; scanned = 1; } retry: @@ -1167,7 +1165,7 @@ retry: break; } - if (unlikely(is_range) && (page->index > end)) { + if (!wbc->range_cyclic && page->index > end) { done = 1; unlock_page(page); break; @@ -1271,7 +1269,7 @@ retry: index = 0; goto retry; } - if (!is_range) + if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0)) mapping->writeback_index = index; FreeXid(xid); -- cgit v1.1 From 75e1fcc0b18df0a65ab113198e9dc0e98999a08c Mon Sep 17 00:00:00 2001 From: Miklos Szeredi Date: Fri, 23 Jun 2006 02:05:12 -0700 Subject: [PATCH] vfs: add lock owner argument to flush operation Pass the POSIX lock owner ID to the flush operation. This is useful for filesystems which don't want to store any locking state in inode->i_flock but want to handle locking/unlocking POSIX locks internally. FUSE is one such filesystem but I think it possible that some network filesystems would need this also. Also add a flag to indicate that a POSIX locking request was generated by close(), so filesystems using the above feature won't send an extra locking request in this case. Signed-off-by: Miklos Szeredi Cc: Trond Myklebust Cc: Al Viro Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/cifs/cifsfs.h | 2 +- fs/cifs/file.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index c98755d..d56c057 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -74,7 +74,7 @@ extern ssize_t cifs_user_write(struct file *file, const char __user *write_data, size_t write_size, loff_t * poffset); extern int cifs_lock(struct file *, int, struct file_lock *); extern int cifs_fsync(struct file *, struct dentry *, int); -extern int cifs_flush(struct file *); +extern int cifs_flush(struct file *, fl_owner_t id); extern int cifs_file_mmap(struct file * , struct vm_area_struct *); extern const struct file_operations cifs_dir_ops; extern int cifs_dir_open(struct inode *inode, struct file *file); diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 487ea8b..b4a18c1 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1417,7 +1417,7 @@ int cifs_fsync(struct file *file, struct dentry *dentry, int datasync) * As file closes, flush all cached write data for this inode checking * for write behind errors. */ -int cifs_flush(struct file *file) +int cifs_flush(struct file *file, fl_owner_t id) { struct inode * inode = file->f_dentry->d_inode; int rc = 0; -- cgit v1.1 From f90f00a358fe887fe5c3454897521064bdace7cc Mon Sep 17 00:00:00 2001 From: Steve French Date: Sun, 25 Jun 2006 15:59:32 +0000 Subject: [CIFS] Fix compile warning when CONFIG_CIFS_EXPERIMENTAL is off Signed-off-by: Steve French --- fs/cifs/cifsproto.h | 2 -- fs/cifs/cifssmb.c | 2 -- 2 files changed, 4 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 7ed06bf..a5ddc62 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -64,11 +64,9 @@ extern int map_smb_to_linux_error(struct smb_hdr *smb); extern void header_assemble(struct smb_hdr *, char /* command */ , const struct cifsTconInfo *, int /* length of fixed section (word count) in two byte units */); -#ifdef CONFIG_CIFS_EXPERIMENTAL extern int small_smb_init_no_tc(const int smb_cmd, const int wct, struct cifsSesInfo *ses, void ** request_buf); -#endif extern int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, const int stage, const struct nls_table *nls_cp); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 271a037..38f83db2 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -209,7 +209,6 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, return rc; } -#ifdef CONFIG_CIFS_EXPERIMENTAL int small_smb_init_no_tc(const int smb_command, const int wct, struct cifsSesInfo *ses, void **request_buf) @@ -235,7 +234,6 @@ small_smb_init_no_tc(const int smb_command, const int wct, return rc; } -#endif /* CONFIG_CIFS_EXPERIMENTAL */ /* If the return code is zero, this function must fill in request_buf pointer */ static int -- cgit v1.1 From cd49b492fe3fef0b6348f18001f0d73f2577eb01 Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 26 Jun 2006 04:22:36 +0000 Subject: [CIFS] remove some redundant null pointer checks some of them pointed out by Dave Jones Signed-off-by: Steve French --- fs/cifs/connect.c | 45 +++++++++++++++------------------------------ 1 file changed, 15 insertions(+), 30 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 01608bb..c0f98dd 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2173,8 +2173,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, if (remaining_words > 0) { len = UniStrnlen((wchar_t *)bcc_ptr, remaining_words-1); - if(ses->serverNOS) - kfree(ses->serverNOS); + kfree(ses->serverNOS); ses->serverNOS = kzalloc(2 * (len + 1),GFP_KERNEL); if(ses->serverNOS == NULL) goto sesssetup_nomem; @@ -2214,12 +2213,10 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, /* if these kcallocs fail not much we can do, but better to not fail the sesssetup itself */ - if(ses->serverDomain) - kfree(ses->serverDomain); + kfree(ses->serverDomain); ses->serverDomain = kzalloc(2, GFP_KERNEL); - if(ses->serverNOS) - kfree(ses->serverNOS); + kfree(ses->serverNOS); ses->serverNOS = kzalloc(2, GFP_KERNEL); } @@ -2228,8 +2225,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, if (((long) bcc_ptr + len) - (long) pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { - if(ses->serverOS) - kfree(ses->serverOS); + kfree(ses->serverOS); ses->serverOS = kzalloc(len + 1,GFP_KERNEL); if(ses->serverOS == NULL) goto sesssetup_nomem; @@ -2240,8 +2236,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr++; len = strnlen(bcc_ptr, 1024); - if(ses->serverNOS) - kfree(ses->serverNOS); + kfree(ses->serverNOS); ses->serverNOS = kzalloc(len + 1,GFP_KERNEL); if(ses->serverNOS == NULL) goto sesssetup_nomem; @@ -2508,8 +2503,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, bcc_ptr, remaining_words - 1); - if(ses->serverNOS) - kfree(ses->serverNOS); + kfree(ses->serverNOS); ses->serverNOS = kzalloc(2 * (len + 1), GFP_KERNEL); @@ -2527,8 +2521,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, if (remaining_words > 0) { len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ - if(ses->serverDomain) - kfree(ses->serverDomain); + kfree(ses->serverDomain); ses->serverDomain = kzalloc(2 * (len + @@ -2547,19 +2540,16 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, = 0; } /* else no more room so create dummy domain string */ else { - if(ses->serverDomain) - kfree(ses->serverDomain); + kfree(ses->serverDomain); ses->serverDomain = kzalloc(2, GFP_KERNEL); } } else { /* no room so create dummy domain and NOS string */ - if(ses->serverDomain); - kfree(ses->serverDomain); + kfree(ses->serverDomain); ses->serverDomain = kzalloc(2, GFP_KERNEL); - if(ses->serverNOS) - kfree(ses->serverNOS); + kfree(ses->serverNOS); ses->serverNOS = kzalloc(2, GFP_KERNEL); } @@ -2581,8 +2571,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, bcc_ptr++; len = strnlen(bcc_ptr, 1024); - if(ses->serverNOS) - kfree(ses->serverNOS); + kfree(ses->serverNOS); ses->serverNOS = kzalloc(len + 1, GFP_KERNEL); @@ -2592,8 +2581,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, bcc_ptr++; len = strnlen(bcc_ptr, 1024); - if(ses->serverDomain) - kfree(ses->serverDomain); + kfree(ses->serverDomain); ses->serverDomain = kzalloc(len + 1, GFP_KERNEL); @@ -2915,8 +2903,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr, remaining_words - 1); - if(ses->serverNOS) - kfree(ses->serverNOS); + kfree(ses->serverNOS); ses->serverNOS = kzalloc(2 * (len + 1), GFP_KERNEL); @@ -2969,8 +2956,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, if(ses->serverDomain) kfree(ses->serverDomain); ses->serverDomain = kzalloc(2, GFP_KERNEL); - if(ses->serverNOS) - kfree(ses->serverNOS); + kfree(ses->serverNOS); ses->serverNOS = kzalloc(2, GFP_KERNEL); } } else { /* ASCII */ @@ -2988,8 +2974,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr++; len = strnlen(bcc_ptr, 1024); - if(ses->serverNOS) - kfree(ses->serverNOS); + kfree(ses->serverNOS); ses->serverNOS = kzalloc(len+1,GFP_KERNEL); strncpy(ses->serverNOS, bcc_ptr, len); bcc_ptr += len; -- cgit v1.1 From 124a27fe32398a69d16bae374aeb17ad67a0ebbf Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Mon, 26 Jun 2006 13:47:59 +0000 Subject: [CIFS] Remove calls to to take f_owner.lock CIFS takes/releases f_owner.lock - why? It does not change anything in the fowner state. Remove this locking. Signed-off-by: Ingo Molnar Signed-off-by: Steve French --- fs/cifs/file.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 616b140..e9c1573 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -110,7 +110,6 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file, &pCifsInode->openFileList); } write_unlock(&GlobalSMBSeslock); - write_unlock(&file->f_owner.lock); if (pCifsInode->clientCanCacheRead) { /* we have the inode open somewhere else no need to discard cache data */ @@ -287,7 +286,6 @@ int cifs_open(struct inode *inode, struct file *file) goto out; } pCifsFile = cifs_init_private(file->private_data, inode, file, netfid); - write_lock(&file->f_owner.lock); write_lock(&GlobalSMBSeslock); list_add(&pCifsFile->tlist, &pTcon->openFileList); @@ -298,7 +296,6 @@ int cifs_open(struct inode *inode, struct file *file) &oplock, buf, full_path, xid); } else { write_unlock(&GlobalSMBSeslock); - write_unlock(&file->f_owner.lock); } if (oplock & CIFS_CREATE_ACTION) { @@ -477,7 +474,6 @@ int cifs_close(struct inode *inode, struct file *file) pTcon = cifs_sb->tcon; if (pSMBFile) { pSMBFile->closePend = TRUE; - write_lock(&file->f_owner.lock); if (pTcon) { /* no sense reconnecting to close a file that is already closed */ @@ -492,23 +488,18 @@ int cifs_close(struct inode *inode, struct file *file) the struct would be in each open file, but this should give enough time to clear the socket */ - write_unlock(&file->f_owner.lock); cERROR(1,("close with pending writes")); msleep(timeout); - write_lock(&file->f_owner.lock); timeout *= 4; } - write_unlock(&file->f_owner.lock); rc = CIFSSMBClose(xid, pTcon, pSMBFile->netfid); - write_lock(&file->f_owner.lock); } } write_lock(&GlobalSMBSeslock); list_del(&pSMBFile->flist); list_del(&pSMBFile->tlist); write_unlock(&GlobalSMBSeslock); - write_unlock(&file->f_owner.lock); kfree(pSMBFile->search_resume_name); kfree(file->private_data); file->private_data = NULL; -- cgit v1.1 From 750d1151a6c95ef9b9a188bb7cff6b80ee30da17 Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 27 Jun 2006 06:28:30 +0000 Subject: [CIFS] Fix allocation of buffers for new session setup routine to allow longer user and domain names and allow passing sec options on mount Signed-off-by: Steve French --- fs/cifs/CHANGES | 3 ++- fs/cifs/README | 5 ++++- fs/cifs/cifsglob.h | 1 + fs/cifs/cifssmb.c | 18 +++++++++++++----- fs/cifs/connect.c | 23 ++++++++++++++--------- fs/cifs/sess.c | 44 ++++++++++++++++++++++++-------------------- 6 files changed, 58 insertions(+), 36 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 79a202b..a61d17e 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -7,7 +7,8 @@ so we can do search (ls etc.) to OS/2. Do not send NTCreateX or recent levels of FindFirst unless server says it supports NT SMBs (instead use legacy equivalents from LANMAN dialect). Fix to allow NTLMv2 authentication support (now can use stronger password hashing -on mount if corresponding /proc/fs/cifs/SecurityFlags is set (0x4004) +on mount if corresponding /proc/fs/cifs/SecurityFlags is set (0x4004). +Allow override of global cifs security flags on mount via "sec=" option(s). Version 1.43 ------------ diff --git a/fs/cifs/README b/fs/cifs/README index 46c2cfa..7986d0d 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -443,7 +443,10 @@ A partial list of the supported mount options follows: SFU does). In the future the bottom 9 bits of the mode mode also will be emulated using queries of the security descriptor (ACL). -sec Security mode. Allowed values are: + sign Must use packet signing (helps avoid unwanted data modification + by intermediate systems in the route). Note that signing + does not work with lanman or plaintext authentication. + sec Security mode. Allowed values are: none attempt to connection as a null user (no name) krb5 Use Kerberos version 5 authentication krb5i Use Kerberos authentication and packet signing diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 87453a6b..6d7cf5f 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -186,6 +186,7 @@ struct cifsSesInfo { struct TCP_Server_Info *server; /* pointer to server info */ atomic_t inUse; /* # of mounts (tree connections) on this ses */ enum statusEnum status; + unsigned overrideSecFlg; /* if non-zero override global sec flags */ __u16 ipc_tid; /* special tid for connection to IPC share */ __u16 flags; char *serverOS; /* name of operating system underlying server */ diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 38f83db2..de405bf 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -396,6 +396,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) int i; struct TCP_Server_Info * server; u16 count; + unsigned int secFlags; if(ses->server) server = ses->server; @@ -407,9 +408,16 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) (void **) &pSMB, (void **) &pSMBr); if (rc) return rc; + + /* if any of auth flags (ie not sign or seal) are overriden use them */ + if(ses->overrideSecFlg & (~(CIFSSEC_MUST_SIGN | CIFSSEC_MUST_SEAL))) + secFlags = ses->overrideSecFlg; + else /* if override flags set only sign/seal OR them with global auth */ + secFlags = extended_security | ses->overrideSecFlg; + pSMB->hdr.Mid = GetNextMid(server); pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; - if((extended_security & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5) + if((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5) pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; count = 0; @@ -439,8 +447,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) && (pSMBr->DialectIndex == LANMAN_PROT)) { struct lanman_neg_rsp * rsp = (struct lanman_neg_rsp *)pSMBr; - if((extended_security & CIFSSEC_MAY_LANMAN) || - (extended_security & CIFSSEC_MAY_PLNTXT)) + if((secFlags & CIFSSEC_MAY_LANMAN) || + (secFlags & CIFSSEC_MAY_PLNTXT)) server->secType = LANMAN; else { cERROR(1, ("mount failed weak security disabled" @@ -498,12 +506,12 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) if((server->secMode & SECMODE_PW_ENCRYPT) == 0) #ifdef CONFIG_CIFS_WEAK_PW_HASH - if ((extended_security & CIFSSEC_MAY_PLNTXT) == 0) + if ((secFlags & CIFSSEC_MAY_PLNTXT) == 0) #endif /* CIFS_WEAK_PW_HASH */ cERROR(1,("Server requests plain text password" " but client support disabled")); - if(extended_security & CIFSSEC_MUST_NTLMV2) + if(secFlags & CIFSSEC_MUST_NTLMV2) server->secType = NTLMv2; else server->secType = NTLM; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index c0f98dd..876eb9e 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -915,32 +915,32 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) cERROR(1,("no security value specified")); continue; } else if (strnicmp(value, "krb5i", 5) == 0) { - vol->secFlg = CIFSSEC_MAY_KRB5 | + vol->secFlg |= CIFSSEC_MAY_KRB5 | CIFSSEC_MUST_SIGN; } else if (strnicmp(value, "krb5p", 5) == 0) { - /* vol->secFlg = CIFSSEC_MUST_SEAL | + /* vol->secFlg |= CIFSSEC_MUST_SEAL | CIFSSEC_MAY_KRB5; */ cERROR(1,("Krb5 cifs privacy not supported")); return 1; } else if (strnicmp(value, "krb5", 4) == 0) { - vol->secFlg = CIFSSEC_MAY_KRB5; + vol->secFlg |= CIFSSEC_MAY_KRB5; } else if (strnicmp(value, "ntlmv2i", 7) == 0) { - vol->secFlg = CIFSSEC_MAY_NTLMV2 | + vol->secFlg |= CIFSSEC_MAY_NTLMV2 | CIFSSEC_MUST_SIGN; } else if (strnicmp(value, "ntlmv2", 6) == 0) { - vol->secFlg = CIFSSEC_MAY_NTLMV2; + vol->secFlg |= CIFSSEC_MAY_NTLMV2; } else if (strnicmp(value, "ntlmi", 5) == 0) { - vol->secFlg = CIFSSEC_MAY_NTLM | + vol->secFlg |= CIFSSEC_MAY_NTLM | CIFSSEC_MUST_SIGN; } else if (strnicmp(value, "ntlm", 4) == 0) { /* ntlm is default so can be turned off too */ - vol->secFlg = CIFSSEC_MAY_NTLM; + vol->secFlg |= CIFSSEC_MAY_NTLM; } else if (strnicmp(value, "nontlm", 6) == 0) { /* BB is there a better way to do this? */ - vol->secFlg = CIFSSEC_MAY_NTLMV2; + vol->secFlg |= CIFSSEC_MAY_NTLMV2; #ifdef CONFIG_CIFS_WEAK_PW_HASH } else if (strnicmp(value, "lanman", 6) == 0) { - vol->secFlg = CIFSSEC_MAY_LANMAN; + vol->secFlg |= CIFSSEC_MAY_LANMAN; #endif } else if (strnicmp(value, "none", 4) == 0) { vol->nullauth = 1; @@ -1173,6 +1173,10 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) vol->no_psx_acl = 0; } else if (strnicmp(data, "noacl",5) == 0) { vol->no_psx_acl = 1; + } else if (strnicmp(data, "sign",4) == 0) { + vol->secFlg |= CIFSSEC_MUST_SIGN; +/* } else if (strnicmp(data, "seal",4) == 0) { + vol->secFlg |= CIFSSEC_MUST_SEAL; */ } else if (strnicmp(data, "direct",6) == 0) { vol->direct_io = 1; } else if (strnicmp(data, "forcedirectio",13) == 0) { @@ -1776,6 +1780,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, volume_info.domainname); } pSesInfo->linux_uid = volume_info.linux_uid; + pSesInfo->overrideSecFlg = volume_info.secFlg; down(&pSesInfo->sesSem); /* BB FIXME need to pass vol->secFlgs BB */ rc = cifs_setup_session(xid,pSesInfo, cifs_sb->local_nls); diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 70e32a8..7737edd 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -138,7 +138,7 @@ static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, strncpy(bcc_ptr, ses->userName, 300); } /* BB improve check for overflow */ - bcc_ptr += strnlen(ses->userName, 200); + bcc_ptr += strnlen(ses->userName, 300); *bcc_ptr = 0; bcc_ptr++; /* account for null termination */ @@ -313,11 +313,12 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, int wct; struct smb_hdr *smb_buf; char *bcc_ptr; + char *str_area; SESSION_SETUP_ANDX *pSMB; __u32 capabilities; int count; int resp_buf_type = 0; - struct kvec iov[2]; /* BB split variable length info into 2nd iovec */ + struct kvec iov[2]; enum securityEnum type; __u16 action; int bytes_remaining; @@ -351,7 +352,18 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, pSMB = (SESSION_SETUP_ANDX *)smb_buf; capabilities = cifs_ssetup_hdr(ses, pSMB); - bcc_ptr = pByteArea(smb_buf); + + /* we will send the SMB in two pieces, + a fixed length beginning part, and a + second part which will include the strings + and rest of bcc area, in order to avoid having + to do a large buffer 17K allocation */ + iov[0].iov_base = (char *)pSMB; + iov[0].iov_len = smb_buf->smb_buf_length + 4; + + /* 2000 big enough to fit max user, domain, NOS name etc. */ + str_area = kmalloc(2000, GFP_KERNEL); + bcc_ptr = str_area; if(type == LANMAN) { #ifdef CONFIG_CIFS_WEAK_PW_HASH @@ -365,10 +377,10 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, calc_lanman_hash(ses, lnm_session_key); -#ifdef CONFIG_CIFS_DEBUG2 +/* #ifdef CONFIG_CIFS_DEBUG2 cifs_dump_mem("cryptkey: ",ses->server->cryptKey, CIFS_SESS_KEY_SIZE); -#endif +#endif */ memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESS_KEY_SIZE); bcc_ptr += CIFS_SESS_KEY_SIZE; @@ -377,7 +389,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, changed to do higher than lanman dialect and we reconnected would we ever calc signing_key? */ - cERROR(1,("Negotiating LANMAN setting up strings")); + cFYI(1,("Negotiating LANMAN setting up strings")); /* Unicode not allowed for LANMAN dialects */ ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); #endif @@ -396,7 +408,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, if(first_time) /* should this be moved into common code with similar ntlmv2 path? */ - cifs_calculate_mac_key( ses->server->mac_signing_key, + cifs_calculate_mac_key(ses->server->mac_signing_key, ntlm_session_key, ses->password); /* copy session key */ @@ -454,23 +466,14 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, /* BB set password lengths */ } - count = (long) bcc_ptr - (long) pByteArea(smb_buf); + count = (long) bcc_ptr - (long) str_area; smb_buf->smb_buf_length += count; - /* if we switch to small buffers, count will need to be fewer - than 383 (strings less than 335 bytes) */ - BCC_LE(smb_buf) = cpu_to_le16(count); - - /* BB FIXME check for other non ntlm code paths */ - - /* BB check is this too big for a small smb? */ - - iov[0].iov_base = (char *)pSMB; - iov[0].iov_len = smb_buf->smb_buf_length + 4; - - rc = SendReceive2(xid, ses, iov, 1 /* num_iovecs */, &resp_buf_type, 0); + iov[1].iov_base = str_area; + iov[1].iov_len = count; + rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type, 0); /* SMB request buf freed in SendReceive2 */ cFYI(1,("ssetup rc from sendrecv2 is %d",rc)); @@ -515,6 +518,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,nls_cp); ssetup_exit: + kfree(str_area); if(resp_buf_type == CIFS_SMALL_BUFFER) { cFYI(1,("ssetup freeing small buf %p", iov[0].iov_base)); cifs_small_buf_release(iov[0].iov_base); -- cgit v1.1 From 0223cf0b10bdb3b557d8884b1a957cc64be843c3 Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 27 Jun 2006 19:50:57 +0000 Subject: [CIFS] Fix alignment of unicode strings in previous patch Signed-off-by: Steve French --- fs/cifs/sess.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 7737edd..b7d49c0 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -83,11 +83,11 @@ static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, /* BB FIXME add check that strings total less than 335 or will need to send them as arrays */ - /* align unicode strings, must be word aligned */ - if ((long) bcc_ptr % 2) { + /* unicode strings, must be word aligned before the call */ +/* if ((long) bcc_ptr % 2) { *bcc_ptr = 0; bcc_ptr++; - } + } */ /* copy user */ if(ses->userName == NULL) { /* BB what about null user mounts - check that we do this BB */ @@ -416,9 +416,14 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, bcc_ptr += CIFS_SESS_KEY_SIZE; memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESS_KEY_SIZE); bcc_ptr += CIFS_SESS_KEY_SIZE; - if(ses->capabilities & CAP_UNICODE) + if(ses->capabilities & CAP_UNICODE) { + /* unicode strings must be word aligned */ + if (iov[0].iov_len % 2) { + *bcc_ptr = 0; + bcc_ptr++; + } unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); - else + } else ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); } else if (type == NTLMv2) { char * v2_sess_key = @@ -455,9 +460,12 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, memcpy(bcc_ptr, (char *)v2_sess_key, sizeof(struct ntlmv2_resp)); bcc_ptr += sizeof(struct ntlmv2_resp); kfree(v2_sess_key); - if(ses->capabilities & CAP_UNICODE) + if(ses->capabilities & CAP_UNICODE) { + if(iov[0].iov_len % 2) { + *bcc_ptr = 0; + } bcc_ptr++; unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); - else + } else ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); } else /* NTLMSSP or SPNEGO */ { pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; -- cgit v1.1 From f40c562855294bf4e7268274d7461dc32c1e6b25 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 28 Jun 2006 00:13:38 +0000 Subject: [CIFS] Fix authentication choice so we do not force NTLMv2 unless the user specifies it is required or turns of ntlm Signed-off-by: Steve French --- fs/cifs/cifssmb.c | 10 +++++++--- fs/cifs/sess.c | 3 ++- 2 files changed, 9 insertions(+), 4 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index de405bf..19678c5 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -415,6 +415,8 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) else /* if override flags set only sign/seal OR them with global auth */ secFlags = extended_security | ses->overrideSecFlg; + cFYI(1,("secFlags 0x%x",secFlags)); + pSMB->hdr.Mid = GetNextMid(server); pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; if((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5) @@ -511,11 +513,13 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) cERROR(1,("Server requests plain text password" " but client support disabled")); - if(secFlags & CIFSSEC_MUST_NTLMV2) + if((secFlags & CIFSSEC_MUST_NTLMV2) == CIFSSEC_MUST_NTLMV2) server->secType = NTLMv2; - else + else if(secFlags & CIFSSEC_MAY_NTLM) server->secType = NTLM; - /* else krb5 ... */ + else if(secFlags & CIFSSEC_MAY_NTLMV2) + server->secType = NTLMv2; + /* else krb5 ... any others ... */ /* one byte, so no need to convert this or EncryptionKeyLen from little endian */ diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index b7d49c0..7202d53 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -323,11 +323,12 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, __u16 action; int bytes_remaining; - cFYI(1,("new sess setup")); if(ses == NULL) return -EINVAL; type = ses->server->secType; + + cFYI(1,("sess setup type %d",type)); if(type == LANMAN) { #ifndef CONFIG_CIFS_WEAK_PW_HASH /* LANMAN and plaintext are less secure and off by default. -- cgit v1.1 From f5e54d6e53a20cef45af7499e86164f0e0d16bb2 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Wed, 28 Jun 2006 04:26:44 -0700 Subject: [PATCH] mark address_space_operations const Same as with already do with the file operations: keep them in .rodata and prevents people from doing runtime patching. Signed-off-by: Christoph Hellwig Cc: Steven French Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- fs/cifs/cifsfs.h | 4 ++-- fs/cifs/file.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'fs/cifs') diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index a6384d8..8f75c6f 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -32,8 +32,8 @@ #define TRUE 1 #endif -extern struct address_space_operations cifs_addr_ops; -extern struct address_space_operations cifs_addr_ops_smallbuf; +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; diff --git a/fs/cifs/file.c b/fs/cifs/file.c index e9c1573..5861eb4 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1942,7 +1942,7 @@ static int cifs_prepare_write(struct file *file, struct page *page, return 0; } -struct address_space_operations cifs_addr_ops = { +const struct address_space_operations cifs_addr_ops = { .readpage = cifs_readpage, .readpages = cifs_readpages, .writepage = cifs_writepage, @@ -1959,7 +1959,7 @@ struct address_space_operations cifs_addr_ops = { * contain the header plus one complete page of data. Otherwise, we need * to leave cifs_readpages out of the address space operations. */ -struct address_space_operations cifs_addr_ops_smallbuf = { +const struct address_space_operations cifs_addr_ops_smallbuf = { .readpage = cifs_readpage, .writepage = cifs_writepage, .writepages = cifs_writepages, -- cgit v1.1 From 0418726bb5c7b5a70c7e7e82e860d5979d0c78cf Mon Sep 17 00:00:00 2001 From: Adrian Bunk Date: Fri, 30 Jun 2006 18:23:04 +0200 Subject: typo fixes: aquire -> acquire Signed-off-by: Adrian Bunk Acked-by: Mauro Carvalho Chehab --- fs/cifs/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/cifs') diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 5861eb4..944d2b9 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -324,7 +324,7 @@ out: return rc; } -/* Try to reaquire byte range locks that were released when session */ +/* Try to reacquire byte range locks that were released when session */ /* to server was lost */ static int cifs_relock_file(struct cifsFileInfo *cifsFile) { -- cgit v1.1 From 6ab3d5624e172c553004ecc862bfeac16d9d68b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rn=20Engel?= Date: Fri, 30 Jun 2006 19:25:36 +0200 Subject: Remove obsolete #include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jörn Engel Signed-off-by: Adrian Bunk --- fs/cifs/asn1.c | 1 - 1 file changed, 1 deletion(-) (limited to 'fs/cifs') diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c index 031cdf2..2e75883 100644 --- a/fs/cifs/asn1.c +++ b/fs/cifs/asn1.c @@ -17,7 +17,6 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include #include #include #include -- cgit v1.1