From 8064ab4da104900505f33535d230ce0da5d18341 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 22 Aug 2007 22:12:07 +0000 Subject: [CIFS] cifs truncate missing a fix for private map COW race vmtruncate had added the same fix to handle the case of private pages being Copy on writed while truncate_inode_pages is going on Signed-off-by: Steve French --- fs/cifs/inode.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index dd4167762a8..97ccc513730 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1377,8 +1377,17 @@ static int cifs_vmtruncate(struct inode *inode, loff_t offset) } i_size_write(inode, offset); spin_unlock(&inode->i_lock); + /* + * unmap_mapping_range is called twice, first simply for efficiency + * so that truncate_inode_pages does fewer single-page unmaps. However + * after this first call, and before truncate_inode_pages finishes, + * it is possible for private pages to be COWed, which remain after + * truncate_inode_pages finishes, hence the second unmap_mapping_range + * call must be made for correctness. + */ unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); truncate_inode_pages(mapping, offset); + unmap_mapping_range(mapping, offset + PAGE_SIZE - 1, 0, 1); goto out_truncate; do_expand: -- cgit v1.2.3 From 95ba7362105646523ee712fd252ec2e34ccbec15 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Fri, 24 Aug 2007 00:23:36 +0000 Subject: [CIFS] Fix unbalanced call to GetXid/FreeXid Signed-off-by: Cyrill Gorcunov Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index cabb6a55d7d..2493cc4f9e7 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -346,7 +346,7 @@ int cifs_xquota_set(struct super_block *sb, int quota_type, qid_t qid, if (pTcon) { cFYI(1, ("set type: 0x%x id: %d", quota_type, qid)); } else { - return -EIO; + rc = -EIO; } FreeXid(xid); -- cgit v1.2.3 From 39db810cb6c1e7d1f2e43ae38b437b7ee72fe815 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Fri, 24 Aug 2007 03:16:51 +0000 Subject: [CIFS] Byte range unlock request to non-Unix server can unlock too much On a mount without posix extensions enabled, when an unlock request is made, the client can release more than is intended. To reproduce, on a CIFS mount without posix extensions enabled: 1) open file 2) do fcntl lock: start=0 len=1 3) do fcntl lock: start=2 len=1 4) do fcntl unlock: start=0 len=1 ...on the unlock call the client sends an unlock request to the server for both locks. The problem is a bad test in cifs_lock. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/CHANGES | 5 ++++- fs/cifs/file.c | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index bed6215c079..41e3b6a9397 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -6,7 +6,10 @@ done with "serverino" mount option). Add support for POSIX Unlink Samba supports newer POSIX CIFS Protocol Extensions). Add "nounix" mount option to allow disabling the CIFS Unix Extensions for just that mount. Fix hang on spinlock in find_writable_file (race when -reopening file after session crash). +reopening file after session crash). Byte range unlock request to +windows server could unlock more bytes (on server copy of file) +than intended if start of unlock request is well before start of +a previous byte range lock that we issued. Version 1.49 ------------ diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 894b1f7b299..f9bd8b83f40 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -767,7 +767,8 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) mutex_lock(&fid->lock_mutex); list_for_each_entry_safe(li, tmp, &fid->llist, llist) { if (pfLock->fl_start <= li->offset && - length >= li->length) { + (pflock->fl_start + length) >= + (li->offset + li->length)) { stored_rc = CIFSSMBLock(xid, pTcon, netfid, li->length, li->offset, -- cgit v1.2.3 From c19eb71020687e178b9fa564f4a8ac1880f87b10 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 24 Aug 2007 03:22:48 +0000 Subject: [CIFS] fix typo in previous Signed-off-by: Steve French --- fs/cifs/file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/file.c b/fs/cifs/file.c index f9bd8b83f40..26fa50858aa 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -767,7 +767,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *pfLock) mutex_lock(&fid->lock_mutex); list_for_each_entry_safe(li, tmp, &fid->llist, llist) { if (pfLock->fl_start <= li->offset && - (pflock->fl_start + length) >= + (pfLock->fl_start + length) >= (li->offset + li->length)) { stored_rc = CIFSSMBLock(xid, pTcon, netfid, -- cgit v1.2.3 From 8594c15ad226227aaf178b7cf57f2e7291684dd4 Mon Sep 17 00:00:00 2001 From: Andre Haupt Date: Thu, 30 Aug 2007 20:18:41 +0000 Subject: [CIFS][KJ] use abs() from kernel.h where appropriate Signed-off-by: Andrew Haupt Signed-off-by: Steve French --- fs/cifs/cifssmb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 8eb102f940d..4795143ff52 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -513,7 +513,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) (int)ts.tv_sec, (int)utc.tv_sec, (int)(utc.tv_sec - ts.tv_sec))); val = (int)(utc.tv_sec - ts.tv_sec); - seconds = val < 0 ? -val : val; + seconds = abs(val); result = (seconds / MIN_TZ_ADJ) * MIN_TZ_ADJ; remain = seconds % MIN_TZ_ADJ; if (remain >= (MIN_TZ_ADJ / 2)) -- cgit v1.2.3 From f01d5e14e764b14b6bf5512678523d009254b209 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 30 Aug 2007 21:13:31 +0000 Subject: [CIFS] fix for incorrect session reconnects cifs reconnect could end up happening incorrectly due to the small initial tcp recvmsg response. When the socket was within three bytes of being full and the recvmsg returned only 1 to 3 bytes of the initial 4 byte read of the RFC1001 length field. Fortunately this seems to be less common on more current kernels, but this fixes it so cifs tries to retrieve all 4 bytes of the initial tcp read. Signed-off-by: Shirish Pargoankar Signed-off-by: Steve French --- fs/cifs/connect.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 4af3588c1a9..8af993f8d0c 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -400,9 +400,11 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) iov.iov_len = 4; smb_msg.msg_control = NULL; smb_msg.msg_controllen = 0; + pdu_length = 4; /* enough to get RFC1001 header */ +incomplete_rcv: length = kernel_recvmsg(csocket, &smb_msg, - &iov, 1, 4, 0 /* BB see socket.h flags */); + &iov, 1, pdu_length, 0 /* BB other flags? */); if ( kthread_should_stop() ) { break; @@ -437,13 +439,12 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) wake_up(&server->response_q); continue; } else if (length < 4) { - cFYI(1, - ("Frame under four bytes received (%d bytes long)", + cFYI(1, ("less than four bytes received (%d bytes)", length)); + pdu_length -= length; cifs_reconnect(server); - csocket = server->ssocket; - wake_up(&server->response_q); - continue; + msleep(1); + goto incomplete_rcv; } /* The right amount was read from socket - 4 bytes */ -- cgit v1.2.3 From 26f57364d7cdef9d7ebe27c931fff5e4f21ffb1c Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 30 Aug 2007 22:09:15 +0000 Subject: [CIFS] formatting cleanup found by checkpatch Signed-off-by: Steve French --- fs/cifs/asn1.c | 10 ++++------ fs/cifs/cifsfs.c | 20 ++++++++++---------- fs/cifs/cifsfs.h | 2 +- fs/cifs/cifspdu.h | 6 +++--- fs/cifs/cifsproto.h | 2 +- fs/cifs/cifssmb.c | 44 ++++++++++++++++++++------------------------ fs/cifs/connect.c | 48 ++++++++++++++++++++---------------------------- fs/cifs/readdir.c | 2 +- fs/cifs/sess.c | 27 ++++++++++----------------- fs/cifs/transport.c | 24 ++++++++++-------------- 10 files changed, 80 insertions(+), 105 deletions(-) diff --git a/fs/cifs/asn1.c b/fs/cifs/asn1.c index f50a88d58f7..2a01f3ef96a 100644 --- a/fs/cifs/asn1.c +++ b/fs/cifs/asn1.c @@ -385,10 +385,9 @@ asn1_oid_decode(struct asn1_ctx *ctx, unsigned long *optr; size = eoc - ctx->pointer + 1; - *oid = kmalloc(size * sizeof (unsigned long), GFP_ATOMIC); - if (*oid == NULL) { + *oid = kmalloc(size * sizeof(unsigned long), GFP_ATOMIC); + if (*oid == NULL) return 0; - } optr = *oid; @@ -581,9 +580,8 @@ decode_negTokenInit(unsigned char *security_blob, int length, return 0; } else if ((cls != ASN1_UNI) || (con != ASN1_CON) || (tag != ASN1_SEQ)) { - cFYI(1, - ("Exit 6 cls = %d con = %d tag = %d end = %p (%d)", - cls, con, tag, end, *end)); + cFYI(1, ("cls = %d con = %d tag = %d end = %p (%d)", + cls, con, tag, end, *end)); } if (asn1_header_decode(&ctx, &end, &cls, &con, &tag) == 0) { diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 2493cc4f9e7..c7c3521aa7c 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -240,9 +240,9 @@ static int cifs_permission(struct inode *inode, int mask, struct nameidata *nd) cifs_sb = CIFS_SB(inode->i_sb); - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) { + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) return 0; - } else /* file mode might have been restricted at mount time + else /* file mode might have been restricted at mount time on the client (above and beyond ACL on servers) for servers which do not support setting and viewing mode bits, so allowing client to check permissions is useful */ @@ -716,7 +716,7 @@ static int cifs_init_inodecache(void) { cifs_inode_cachep = kmem_cache_create("cifs_inode_cache", - sizeof (struct cifsInodeInfo), + sizeof(struct cifsInodeInfo), 0, (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD), cifs_init_once); @@ -816,8 +816,8 @@ static int cifs_init_mids(void) { cifs_mid_cachep = kmem_cache_create("cifs_mpx_ids", - sizeof (struct mid_q_entry), 0, - SLAB_HWCACHE_ALIGN, NULL); + sizeof(struct mid_q_entry), 0, + SLAB_HWCACHE_ALIGN, NULL); if (cifs_mid_cachep == NULL) return -ENOMEM; @@ -829,8 +829,8 @@ cifs_init_mids(void) } cifs_oplock_cachep = kmem_cache_create("cifs_oplock_structs", - sizeof (struct oplock_q_entry), 0, - SLAB_HWCACHE_ALIGN, NULL); + sizeof(struct oplock_q_entry), 0, + SLAB_HWCACHE_ALIGN, NULL); if (cifs_oplock_cachep == NULL) { mempool_destroy(cifs_mid_poolp); kmem_cache_destroy(cifs_mid_cachep); @@ -882,7 +882,8 @@ static int cifs_oplock_thread(void *dummyarg) the call */ /* mutex_lock(&inode->i_mutex);*/ if (S_ISREG(inode->i_mode)) { - rc = filemap_fdatawrite(inode->i_mapping); + rc = + filemap_fdatawrite(inode->i_mapping); if (CIFS_I(inode)->clientCanCacheRead == 0) { filemap_fdatawait(inode->i_mapping); @@ -907,8 +908,7 @@ static int cifs_oplock_thread(void *dummyarg) 0 /* len */ , 0 /* offset */, 0, 0, LOCKING_ANDX_OPLOCK_RELEASE, 0 /* wait flag */); - cFYI(1, - ("Oplock release rc = %d ", rc)); + cFYI(1, ("Oplock release rc = %d", rc)); } } else spin_unlock(&GlobalMid_Lock); diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index a20de77a385..dd64cecd923 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -99,7 +99,7 @@ extern int cifs_setxattr(struct dentry *, const char *, const void *, size_t, int); 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, +extern int cifs_ioctl(struct inode *inode, struct file *filep, unsigned int command, unsigned long arg); #define CIFS_VERSION "1.50" #endif /* _CIFSFS_H */ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 6a2056e58ce..e975ce46115 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -360,10 +360,10 @@ struct smb_hdr { __u8 WordCount; } __attribute__((packed)); /* given a pointer to an smb_hdr retrieve the value of byte count */ -#define BCC(smb_var) ( *(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) ) -#define BCC_LE(smb_var) ( *(__le16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) ) ) +#define BCC(smb_var) ( *(__u16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount))) +#define BCC_LE(smb_var) ( *(__le16 *)((char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount))) /* given a pointer to an smb_hdr retrieve the pointer to the byte area */ -#define pByteArea(smb_var) ((unsigned char *)smb_var + sizeof(struct smb_hdr) + (2* smb_var->WordCount) + 2 ) +#define pByteArea(smb_var) ((unsigned char *)smb_var + sizeof(struct smb_hdr) + (2 * smb_var->WordCount) + 2) /* * Computer Name Length (since Netbios name was length 16 with last byte 0x20) diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 04a69dafedb..4ffae9d9291 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -304,7 +304,7 @@ extern int cifs_calculate_mac_key(struct mac_key *key, const char *rn, const char *pass); extern int CalcNTLMv2_partial_mac_key(struct cifsSesInfo *, const struct nls_table *); -extern void CalcNTLMv2_response(const struct cifsSesInfo *, char * ); +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 diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 4795143ff52..bb30455caab 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -94,9 +94,8 @@ static void mark_open_files_invalid(struct cifsTconInfo *pTcon) write_lock(&GlobalSMBSeslock); list_for_each_safe(tmp, tmp1, &pTcon->openFileList) { open_file = list_entry(tmp, struct cifsFileInfo, tlist); - if (open_file) { + if (open_file) open_file->invalidHandle = TRUE; - } } write_unlock(&GlobalSMBSeslock); /* BB Add call to invalidate_inodes(sb) for all superblocks mounted @@ -1112,7 +1111,7 @@ PsxCreat: } memcpy((char *) pRetData, (char *)psx_rsp + sizeof(OPEN_PSX_RSP), - sizeof (FILE_UNIX_BASIC_INFO)); + sizeof(FILE_UNIX_BASIC_INFO)); } psx_create_err: @@ -1193,9 +1192,9 @@ OldOpenRetry: } if (*pOplock & REQ_OPLOCK) pSMB->OpenFlags = cpu_to_le16(REQ_OPLOCK); - else if (*pOplock & REQ_BATCHOPLOCK) { + else if (*pOplock & REQ_BATCHOPLOCK) pSMB->OpenFlags = cpu_to_le16(REQ_BATCHOPLOCK); - } + pSMB->OpenFlags |= cpu_to_le16(REQ_MORE_INFO); /* BB fixme add conversion for access_flags to bits 0 - 2 of mode */ /* 0 = read @@ -1310,9 +1309,8 @@ openRetry: } if (*pOplock & REQ_OPLOCK) pSMB->OpenFlags = cpu_to_le32(REQ_OPLOCK); - else if (*pOplock & REQ_BATCHOPLOCK) { + else if (*pOplock & REQ_BATCHOPLOCK) pSMB->OpenFlags = cpu_to_le32(REQ_BATCHOPLOCK); - } pSMB->DesiredAccess = cpu_to_le32(access_flags); pSMB->AllocationSize = 0; /* set file as system file if special file such @@ -1446,11 +1444,11 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid, *nbytes = 0; } else { pReadData = (char *) (&pSMBr->hdr.Protocol) + - le16_to_cpu(pSMBr->DataOffset); -/* if (rc = copy_to_user(buf, pReadData, data_length)) { + le16_to_cpu(pSMBr->DataOffset); +/* if (rc = copy_to_user(buf, pReadData, data_length)) { cERROR(1,("Faulting on read rc = %d",rc)); rc = -EFAULT; - }*/ /* can not use copy_to_user when using page cache*/ + }*/ /* can not use copy_to_user when using page cache*/ if (*buf) memcpy(*buf, pReadData, data_length); } @@ -2538,7 +2536,7 @@ validate_ntransact(char *buf, char **ppparm, char **ppdata, cFYI(1, ("data starts after end of smb")); return -EINVAL; } else if (data_count + *ppdata > end_of_smb) { - cFYI(1,("data %p + count %d (%p) ends after end of smb %p start %p", + cFYI(1, ("data %p + count %d (%p) ends after end of smb %p start %p", *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); return -EINVAL; @@ -2615,7 +2613,7 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, reparse_buf->TargetNameOffset + reparse_buf->TargetNameLen) > end_of_smb) { - cFYI(1,("reparse buf goes beyond SMB")); + cFYI(1, ("reparse buf beyond SMB")); rc = -EIO; goto qreparse_out; } @@ -3883,12 +3881,10 @@ getDFSRetry: pSMB->hdr.Mid = GetNextMid(ses->server); pSMB->hdr.Tid = ses->ipc_tid; pSMB->hdr.Uid = ses->Suid; - if (ses->capabilities & CAP_STATUS32) { + if (ses->capabilities & CAP_STATUS32) pSMB->hdr.Flags2 |= SMBFLG2_ERR_STATUS; - } - if (ses->capabilities & CAP_DFS) { + if (ses->capabilities & CAP_DFS) pSMB->hdr.Flags2 |= SMBFLG2_DFS; - } if (ses->capabilities & CAP_UNICODE) { pSMB->hdr.Flags2 |= SMBFLG2_UNICODE; @@ -4265,7 +4261,7 @@ QFSAttributeRetry: *) (((char *) &pSMBr->hdr.Protocol) + data_offset); memcpy(&tcon->fsAttrInfo, response_data, - sizeof (FILE_SYSTEM_ATTRIBUTE_INFO)); + sizeof(FILE_SYSTEM_ATTRIBUTE_INFO)); } } cifs_buf_release(pSMB); @@ -4334,7 +4330,7 @@ QFSDeviceRetry: (((char *) &pSMBr->hdr.Protocol) + data_offset); memcpy(&tcon->fsDevInfo, response_data, - sizeof (FILE_SYSTEM_DEVICE_INFO)); + sizeof(FILE_SYSTEM_DEVICE_INFO)); } } cifs_buf_release(pSMB); @@ -4402,7 +4398,7 @@ QFSUnixRetry: *) (((char *) &pSMBr->hdr.Protocol) + data_offset); memcpy(&tcon->fsUnixInfo, response_data, - sizeof (FILE_SYSTEM_UNIX_INFO)); + sizeof(FILE_SYSTEM_UNIX_INFO)); } } cifs_buf_release(pSMB); @@ -4612,7 +4608,7 @@ SetEOFRetry: strncpy(pSMB->FileName, fileName, name_len); } params = 6 + name_len; - data_count = sizeof (struct file_end_of_file_info); + data_count = sizeof(struct file_end_of_file_info); pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxDataCount = cpu_to_le16(4100); pSMB->MaxSetupCount = 0; @@ -4800,7 +4796,7 @@ CIFSSMBSetFileTimes(const int xid, struct cifsTconInfo *tcon, data_offset = (char *) (&pSMB->hdr.Protocol) + offset; - count = sizeof (FILE_BASIC_INFO); + count = sizeof(FILE_BASIC_INFO); pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find max SMB PDU from sess */ pSMB->SetupCount = 1; @@ -4871,7 +4867,7 @@ SetTimesRetry: } params = 6 + name_len; - count = sizeof (FILE_BASIC_INFO); + count = sizeof(FILE_BASIC_INFO); pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ pSMB->MaxSetupCount = 0; @@ -4900,7 +4896,7 @@ SetTimesRetry: pSMB->InformationLevel = cpu_to_le16(SMB_SET_FILE_BASIC_INFO); pSMB->Reserved4 = 0; pSMB->hdr.smb_buf_length += byte_count; - memcpy(data_offset, data, sizeof (FILE_BASIC_INFO)); + memcpy(data_offset, data, sizeof(FILE_BASIC_INFO)); pSMB->ByteCount = cpu_to_le16(byte_count); rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); @@ -5003,7 +4999,7 @@ setPermsRetry: } params = 6 + name_len; - count = sizeof (FILE_UNIX_BASIC_INFO); + count = sizeof(FILE_UNIX_BASIC_INFO); pSMB->MaxParameterCount = cpu_to_le16(2); pSMB->MaxDataCount = cpu_to_le16(1000); /* BB find exact max SMB PDU from sess structure BB */ pSMB->MaxSetupCount = 0; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 8af993f8d0c..3dd2d23e064 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -124,7 +124,7 @@ cifs_reconnect(struct TCP_Server_Info *server) struct mid_q_entry *mid_entry; spin_lock(&GlobalMid_Lock); - if ( kthread_should_stop() ) { + if (kthread_should_stop()) { /* the demux thread will exit normally next time through the loop */ spin_unlock(&GlobalMid_Lock); @@ -151,9 +151,8 @@ cifs_reconnect(struct TCP_Server_Info *server) } list_for_each(tmp, &GlobalTreeConnectionList) { tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); - if ((tcon) && (tcon->ses) && (tcon->ses->server == server)) { + if ((tcon) && (tcon->ses) && (tcon->ses->server == server)) tcon->tidStatus = CifsNeedReconnect; - } } read_unlock(&GlobalSMBSeslock); /* do not want to be sending data on a socket we are freeing */ @@ -187,7 +186,7 @@ cifs_reconnect(struct TCP_Server_Info *server) spin_unlock(&GlobalMid_Lock); up(&server->tcpSem); - while ( (!kthread_should_stop()) && (server->tcpStatus != CifsGood)) { + while ((!kthread_should_stop()) && (server->tcpStatus != CifsGood)) { try_to_freeze(); if (server->protocolType == IPV6) { rc = ipv6_connect(&server->addr.sockAddr6, @@ -204,7 +203,7 @@ cifs_reconnect(struct TCP_Server_Info *server) } else { atomic_inc(&tcpSesReconnectCount); spin_lock(&GlobalMid_Lock); - if ( !kthread_should_stop() ) + if (!kthread_should_stop()) server->tcpStatus = CifsGood; server->sequence_number = 0; spin_unlock(&GlobalMid_Lock); @@ -358,11 +357,9 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) length = tcpSesAllocCount.counter; write_unlock(&GlobalSMBSeslock); complete(&cifsd_complete); - if (length > 1) { - mempool_resize(cifs_req_poolp, - length + cifs_min_rcv, - GFP_KERNEL); - } + if (length > 1) + mempool_resize(cifs_req_poolp, length + cifs_min_rcv, + GFP_KERNEL); set_freezable(); while (!kthread_should_stop()) { @@ -378,7 +375,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) } } else if (isLargeBuf) { /* we are reusing a dirty large buf, clear its start */ - memset(bigbuf, 0, sizeof (struct smb_hdr)); + memset(bigbuf, 0, sizeof(struct smb_hdr)); } if (smallbuf == NULL) { @@ -391,7 +388,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) } /* beginning of smb buffer is cleared in our buf_get */ } else /* if existing small buf clear beginning */ - memset(smallbuf, 0, sizeof (struct smb_hdr)); + memset(smallbuf, 0, sizeof(struct smb_hdr)); isLargeBuf = FALSE; isMultiRsp = FALSE; @@ -406,7 +403,7 @@ incomplete_rcv: kernel_recvmsg(csocket, &smb_msg, &iov, 1, pdu_length, 0 /* BB other flags? */); - if ( kthread_should_stop() ) { + if (kthread_should_stop()) { break; } else if (server->tcpStatus == CifsNeedReconnect) { cFYI(1, ("Reconnect after server stopped responding")); @@ -505,7 +502,7 @@ incomplete_rcv: /* else we have an SMB response */ if ((pdu_length > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4) || - (pdu_length < sizeof (struct smb_hdr) - 1 - 4)) { + (pdu_length < sizeof(struct smb_hdr) - 1 - 4)) { cERROR(1, ("Invalid size SMB length %d pdu_length %d", length, pdu_length+4)); cifs_reconnect(server); @@ -529,7 +526,7 @@ incomplete_rcv: total_read += length) { length = kernel_recvmsg(csocket, &smb_msg, &iov, 1, pdu_length - total_read, 0); - if ( kthread_should_stop() || + if (kthread_should_stop() || (length == -EINTR)) { /* then will exit */ reconnect = 2; @@ -632,9 +629,9 @@ multi_t2_fnd: /* Was previous buf put in mpx struct for multi-rsp? */ if (!isMultiRsp) { /* smb buffer will be freed by user thread */ - if (isLargeBuf) { + if (isLargeBuf) bigbuf = NULL; - } else + else smallbuf = NULL; } wake_up_process(task_to_wake); @@ -703,9 +700,8 @@ multi_t2_fnd: list_for_each(tmp, &GlobalSMBSessionList) { ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); - if (ses->server == server) { + if (ses->server == server) ses->status = CifsExiting; - } } spin_lock(&GlobalMid_Lock); @@ -715,9 +711,8 @@ multi_t2_fnd: cFYI(1, ("Clearing Mid 0x%x - waking up ", mid_entry->mid)); task_to_wake = mid_entry->tsk; - if (task_to_wake) { + if (task_to_wake) wake_up_process(task_to_wake); - } } } spin_unlock(&GlobalMid_Lock); @@ -750,18 +745,15 @@ multi_t2_fnd: list_for_each(tmp, &GlobalSMBSessionList) { ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); - if (ses->server == server) { + if (ses->server == server) ses->server = NULL; - } } write_unlock(&GlobalSMBSeslock); kfree(server); - if (length > 0) { - mempool_resize(cifs_req_poolp, - length + cifs_min_rcv, - GFP_KERNEL); - } + if (length > 0) + mempool_resize(cifs_req_poolp, length + cifs_min_rcv, + GFP_KERNEL); return 0; } diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 916df943133..b5a9bfff5e5 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -1067,7 +1067,7 @@ int cifs_readdir(struct file *file, void *direntry, filldir_t filldir) for (i = 0; (i < num_to_fill) && (rc == 0); i++) { if (current_entry == NULL) { /* evaluate whether this case is an error */ - cERROR(1,("past end of SMB num to fill %d i %d", + cERROR(1, ("past SMB end, num to fill %d i %d", num_to_fill, i)); break; } diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 892be9b4d1f..78797c0e076 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -67,9 +67,8 @@ static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) pSMB->req.hdr.Flags2 |= SMBFLG2_DFS; capabilities |= CAP_DFS; } - if (ses->capabilities & CAP_UNIX) { + if (ses->capabilities & CAP_UNIX) capabilities |= CAP_UNIX; - } /* BB check whether to init vcnum BB */ return capabilities; @@ -203,14 +202,11 @@ static int decode_unicode_ssetup(char **pbcc_area, int bleft, if (len >= words_left) return rc; - if (ses->serverOS) - kfree(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); - } + if (ses->serverOS != NULL) + cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len, nls_cp); data += 2 * (len + 1); words_left -= len + 1; @@ -220,8 +216,7 @@ static int decode_unicode_ssetup(char **pbcc_area, int bleft, if (len >= words_left) return rc; - if (ses->serverNOS) - kfree(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, @@ -240,8 +235,7 @@ static int decode_unicode_ssetup(char **pbcc_area, int bleft, if (len > words_left) return rc; - if (ses->serverDomain) - kfree(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, @@ -271,8 +265,7 @@ static int decode_ascii_ssetup(char **pbcc_area, int bleft, if (len >= bleft) return rc; - if (ses->serverOS) - kfree(ses->serverOS); + kfree(ses->serverOS); ses->serverOS = kzalloc(len + 1, GFP_KERNEL); if (ses->serverOS) @@ -289,8 +282,7 @@ static int decode_ascii_ssetup(char **pbcc_area, int bleft, if (len >= bleft) return rc; - if (ses->serverNOS) - kfree(ses->serverNOS); + kfree(ses->serverNOS); ses->serverNOS = kzalloc(len + 1, GFP_KERNEL); if (ses->serverNOS) @@ -479,7 +471,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, if (ses->capabilities & CAP_UNICODE) { if (iov[0].iov_len % 2) { *bcc_ptr = 0; - } bcc_ptr++; + bcc_ptr++; + } unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); } else ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 746bc9405db..6684926bf3d 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -55,7 +55,7 @@ AllocMidQEntry(const struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) if (temp == NULL) return temp; else { - memset(temp, 0, sizeof (struct mid_q_entry)); + memset(temp, 0, sizeof(struct mid_q_entry)); temp->mid = smb_buffer->Mid; /* always LE */ temp->pid = current->pid; temp->command = smb_buffer->Command; @@ -158,7 +158,7 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, iov.iov_len = len; smb_msg.msg_name = sin; - smb_msg.msg_namelen = sizeof (struct sockaddr); + smb_msg.msg_namelen = sizeof(struct sockaddr); smb_msg.msg_control = NULL; smb_msg.msg_controllen = 0; smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/ @@ -228,7 +228,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, return -ENOTSOCK; /* BB eventually add reconnect code here */ smb_msg.msg_name = sin; - smb_msg.msg_namelen = sizeof (struct sockaddr); + smb_msg.msg_namelen = sizeof(struct sockaddr); smb_msg.msg_control = NULL; smb_msg.msg_controllen = 0; smb_msg.msg_flags = MSG_DONTWAIT + MSG_NOSIGNAL; /* BB add more flags?*/ @@ -363,9 +363,8 @@ static int allocate_mid(struct cifsSesInfo *ses, struct smb_hdr *in_buf, } /* else ok - we are setting up session */ } *ppmidQ = AllocMidQEntry(in_buf, ses); - if (*ppmidQ == NULL) { + if (*ppmidQ == NULL) return -ENOMEM; - } return 0; } @@ -572,9 +571,8 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, rc = map_smb_to_linux_error(midQ->resp_buf); /* convert ByteCount if necessary */ - if (receive_len >= - sizeof (struct smb_hdr) - - 4 /* do not count RFC1001 header */ + + if (receive_len >= sizeof(struct smb_hdr) - 4 + /* do not count RFC1001 header */ + (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ ) BCC(midQ->resp_buf) = le16_to_cpu(BCC_LE(midQ->resp_buf)); @@ -752,9 +750,8 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, rc = map_smb_to_linux_error(out_buf); /* convert ByteCount if necessary */ - if (receive_len >= - sizeof (struct smb_hdr) - - 4 /* do not count RFC1001 header */ + + if (receive_len >= sizeof(struct smb_hdr) - 4 + /* do not count RFC1001 header */ + (2 * out_buf->WordCount) + 2 /* bcc */ ) BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); } else { @@ -996,9 +993,8 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, rc = map_smb_to_linux_error(out_buf); /* convert ByteCount if necessary */ - if (receive_len >= - sizeof (struct smb_hdr) - - 4 /* do not count RFC1001 header */ + + if (receive_len >= sizeof(struct smb_hdr) - 4 + /* do not count RFC1001 header */ + (2 * out_buf->WordCount) + 2 /* bcc */ ) BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); } else { -- cgit v1.2.3 From 77159b4df894f9e5e31f709fb0e5e52f6c1b1048 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 31 Aug 2007 01:10:17 +0000 Subject: [CIFS] Fix warnings shown by newer version of sparse Signed-off-by: Steve French --- fs/cifs/connect.c | 61 +++++++++++++++++++++++++------------------------------ fs/cifs/dir.c | 2 +- fs/cifs/inode.c | 4 ++-- fs/cifs/link.c | 2 +- 4 files changed, 32 insertions(+), 37 deletions(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 3dd2d23e064..f58fef5878c 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2972,36 +2972,32 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, SecurityBlob->DomainName.Length = 0; SecurityBlob->DomainName.MaximumLength = 0; } else { - __u16 len = - cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64, + __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64, nls_codepage); - len *= 2; + ln *= 2; SecurityBlob->DomainName.MaximumLength = - cpu_to_le16(len); + cpu_to_le16(ln); SecurityBlob->DomainName.Buffer = cpu_to_le32(SecurityBlobLength); - bcc_ptr += len; - SecurityBlobLength += len; - SecurityBlob->DomainName.Length = - cpu_to_le16(len); + bcc_ptr += ln; + SecurityBlobLength += ln; + SecurityBlob->DomainName.Length = cpu_to_le16(ln); } if (user == NULL) { SecurityBlob->UserName.Buffer = 0; SecurityBlob->UserName.Length = 0; SecurityBlob->UserName.MaximumLength = 0; } else { - __u16 len = - cifs_strtoUCS((__le16 *) bcc_ptr, user, 64, + __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64, nls_codepage); - len *= 2; + ln *= 2; SecurityBlob->UserName.MaximumLength = - cpu_to_le16(len); + cpu_to_le16(ln); SecurityBlob->UserName.Buffer = cpu_to_le32(SecurityBlobLength); - bcc_ptr += len; - SecurityBlobLength += len; - SecurityBlob->UserName.Length = - cpu_to_le16(len); + bcc_ptr += ln; + SecurityBlobLength += ln; + SecurityBlob->UserName.Length = cpu_to_le16(ln); } /* SecurityBlob->WorkstationName.Length = @@ -3045,33 +3041,32 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, SecurityBlob->DomainName.Length = 0; SecurityBlob->DomainName.MaximumLength = 0; } else { - __u16 len; + __u16 ln; negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED; strncpy(bcc_ptr, domain, 63); - len = strnlen(domain, 64); + ln = strnlen(domain, 64); SecurityBlob->DomainName.MaximumLength = - cpu_to_le16(len); + cpu_to_le16(ln); SecurityBlob->DomainName.Buffer = cpu_to_le32(SecurityBlobLength); - bcc_ptr += len; - SecurityBlobLength += len; - SecurityBlob->DomainName.Length = cpu_to_le16(len); + bcc_ptr += ln; + SecurityBlobLength += ln; + SecurityBlob->DomainName.Length = cpu_to_le16(ln); } if (user == NULL) { SecurityBlob->UserName.Buffer = 0; SecurityBlob->UserName.Length = 0; SecurityBlob->UserName.MaximumLength = 0; } else { - __u16 len; + __u16 ln; strncpy(bcc_ptr, user, 63); - len = strnlen(user, 64); - SecurityBlob->UserName.MaximumLength = - cpu_to_le16(len); + ln = strnlen(user, 64); + SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln); SecurityBlob->UserName.Buffer = - cpu_to_le32(SecurityBlobLength); - bcc_ptr += len; - SecurityBlobLength += len; - SecurityBlob->UserName.Length = cpu_to_le16(len); + cpu_to_le32(SecurityBlobLength); + bcc_ptr += ln; + SecurityBlobLength += ln; + SecurityBlob->UserName.Length = cpu_to_le16(ln); } /* BB fill in our workstation name if known BB */ @@ -3138,8 +3133,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, } else { remaining_words = BCC(smb_buffer_response) / 2; } - len = - UniStrnlen((wchar_t *) bcc_ptr,remaining_words - 1); + 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 */ @@ -3223,7 +3218,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, <= BCC(smb_buffer_response)) { if (ses->serverOS) kfree(ses->serverOS); - ses->serverOS = kzalloc(len + 1,GFP_KERNEL); + ses->serverOS = kzalloc(len + 1, GFP_KERNEL); strncpy(ses->serverOS,bcc_ptr, len); bcc_ptr += len; diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 4830acc86d7..db5287abc30 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -397,7 +397,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, /* BB Do not bother to decode buf since no local inode yet to put timestamps in, but we can reuse it safely */ - int bytes_written; + unsigned int bytes_written; struct win_dev *pdev; pdev = (struct win_dev *)buf; if (S_ISCHR(mode)) { diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 97ccc513730..66436f527c3 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1478,7 +1478,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) atomic_dec(&open_file->wrtPending); cFYI(1, ("SetFSize for attrs rc = %d", rc)); if ((rc == -EINVAL) || (rc == -EOPNOTSUPP)) { - int bytes_written; + unsigned int bytes_written; rc = CIFSSMBWrite(xid, pTcon, nfid, 0, attrs->ia_size, &bytes_written, NULL, NULL, @@ -1511,7 +1511,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); if (rc == 0) { - int bytes_written; + unsigned int bytes_written; rc = CIFSSMBWrite(xid, pTcon, netfid, 0, attrs->ia_size, diff --git a/fs/cifs/link.c b/fs/cifs/link.c index 6a85ef7b879..11f265726db 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -237,7 +237,7 @@ cifs_readlink(struct dentry *direntry, char __user *pBuffer, int buflen) char *tmp_path = NULL; char *tmpbuffer; unsigned char *referrals = NULL; - int num_referrals = 0; + unsigned int num_referrals = 0; int len; __u16 fid; -- cgit v1.2.3 From 15745320f374aa6cbfe4836b76469159c0f49640 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 7 Sep 2007 22:23:48 +0000 Subject: [CIFS] Fix oops in find_writable_file There was a case in which find_writable_file was not waiting long enough under heavy stress when writepages was racing with close of the file handle being used by the write. Signed-off-by: Steve French --- fs/cifs/file.c | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 26fa50858aa..b1807fd1ac4 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -467,7 +467,7 @@ reopen_error_exit: int cifs_close(struct inode *inode, struct file *file) { int rc = 0; - int xid; + int xid, timeout; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; struct cifsFileInfo *pSMBFile = @@ -485,9 +485,9 @@ int cifs_close(struct inode *inode, struct file *file) /* no sense reconnecting to close a file that is already closed */ if (pTcon->tidStatus != CifsNeedReconnect) { - int timeout = 2; + timeout = 2; while ((atomic_read(&pSMBFile->wrtPending) != 0) - && (timeout < 1000) ) { + && (timeout <= 2048)) { /* Give write a better chance to get to server ahead of the close. We do not want to add a wait_q here as it would @@ -522,6 +522,23 @@ int cifs_close(struct inode *inode, struct file *file) list_del(&pSMBFile->flist); list_del(&pSMBFile->tlist); write_unlock(&GlobalSMBSeslock); + timeout = 10; + /* We waited above to give the SMBWrite a chance to issue + on the wire (so we do not get SMBWrite returning EBADF + if writepages is racing with close. Note that writepages + does not specify a file handle, so it is possible for a file + to be opened twice, and the application close the "wrong" + file handle - in these cases we delay long enough to allow + the SMBWrite to get on the wire before the SMB Close. + We allow total wait here over 45 seconds, more than + oplock break time, and more than enough to allow any write + to complete on the server, or to time out on the client */ + while ((atomic_read(&pSMBFile->wrtPending) != 0) + && (timeout <= 50000)) { + cERROR(1, ("writes pending, delay free of handle")); + msleep(timeout); + timeout *= 8; + } kfree(pSMBFile->search_resume_name); kfree(file->private_data); file->private_data = NULL; @@ -1031,22 +1048,24 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) (open_file->pfile->f_flags & O_WRONLY))) { atomic_inc(&open_file->wrtPending); read_unlock(&GlobalSMBSeslock); - if ((open_file->invalidHandle) && - (!open_file->closePend) /* BB fixme -since the second clause can not be true remove it BB */) { + if (open_file->invalidHandle) { rc = cifs_reopen_file(open_file->pfile, FALSE); /* if it fails, try another handle - might be */ /* dangerous to hold up writepages with retry */ if (rc) { - cFYI(1, - ("failed on reopen file in wp")); + cFYI(1, ("wp failed on reopen file")); read_lock(&GlobalSMBSeslock); /* can not use this handle, no write pending on this one after all */ - atomic_dec - (&open_file->wrtPending); + atomic_dec(&open_file->wrtPending); continue; } } + if (open_file->closePend) { + read_lock(&GlobalSMBSeslock); + atomic_dec(&open_file->wrtPending); + continue; + } return open_file; } } -- cgit v1.2.3 From 4efa53f0907bb4378015c129a2c11b8d3a90bce2 Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 11 Sep 2007 05:50:53 +0000 Subject: [CIFS] lock inode open file list in close in case racing with open Harmless since it only protected turning off caching for the inode, but cleaner to lock around this in case we have a close racing with open. Signed-off-by: Shaggy CC: Cyrill Gorcunov Signed-off-by: Steve French --- fs/cifs/file.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/cifs/file.c b/fs/cifs/file.c index b1807fd1ac4..79254919386 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -545,6 +545,7 @@ int cifs_close(struct inode *inode, struct file *file) } else rc = -EBADF; + read_lock(&GlobalSMBSeslock); if (list_empty(&(CIFS_I(inode)->openFileList))) { cFYI(1, ("closing last open instance for inode %p", inode)); /* if the file is not open we do not know if we can cache info @@ -552,6 +553,7 @@ int cifs_close(struct inode *inode, struct file *file) CIFS_I(inode)->clientCanCacheRead = FALSE; CIFS_I(inode)->clientCanCacheAll = FALSE; } + read_unlock(&GlobalSMBSeslock); if ((rc == 0) && CIFS_I(inode)->write_behind_rc) rc = CIFS_I(inode)->write_behind_rc; FreeXid(xid); -- cgit v1.2.3 From a8cd925f74c3b1b6d1192f9e75f9d12cc2ab148a Mon Sep 17 00:00:00 2001 From: Jeff Date: Thu, 13 Sep 2007 18:38:50 +0000 Subject: [CIFS] Respect umask when using POSIX mkdir When making a directory with POSIX mkdir calls, cifs_mkdir does not respect the umask. This patch causes the new POSIX mkdir to create with the right mode Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/inode.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 66436f527c3..e800c0ef54f 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -919,6 +919,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) goto mkdir_out; } + mode &= ~current->fs->umask; rc = CIFSPOSIXCreate(xid, pTcon, SMB_O_DIRECTORY | SMB_O_CREAT, mode, NULL /* netfid */, pInfo, &oplock, full_path, cifs_sb->local_nls, -- cgit v1.2.3 From 638b250766272fcaaa0f7ed2776f58f4ac701914 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 15 Sep 2007 02:35:51 +0000 Subject: [CIFS] typo in earlier cifs_reconnect fix Signed-off-by: Steve French --- fs/cifs/connect.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index f58fef5878c..a83684d8eb5 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -439,7 +439,6 @@ incomplete_rcv: cFYI(1, ("less than four bytes received (%d bytes)", length)); pdu_length -= length; - cifs_reconnect(server); msleep(1); goto incomplete_rcv; } -- cgit v1.2.3 From 88f370a688e765de9755a343702ca04e6817e5f5 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 15 Sep 2007 03:01:17 +0000 Subject: [CIFS] Fix potential NULL pointer usage if kzalloc fails Potential problem was noticed by Cyrill Gorcunov CC: Cyrill Gorcunov Signed-off-by: Steve French --- fs/cifs/cifs_debug.c | 16 +++++++++------- fs/cifs/connect.c | 13 ++++++++----- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 1bf8cf522ad..0356694b5cd 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -209,13 +209,15 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, i++; tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType); - length = - sprintf(buf, - "\n%d) %s Uses: %d Type: %s DevInfo: 0x%x " - "Attributes: 0x%x\nPathComponentMax: %d Status: %d", - i, tcon->treeName, - atomic_read(&tcon->useCount), - tcon->nativeFileSystem, + length = sprintf(buf, "\n%d) %s Uses: %d ", i, + tcon->treeName, atomic_read(&tcon->useCount)); + buf += length; + if (tcon->nativeFileSystem) { + length = sprintf("Type: %s ", tcon->nativeFileSystem); + buf += length; + } + length = sprintf(buf, "DevInfo: 0x%x Attributes: 0x%x" + "\nPathComponentMax: %d Status: %d", le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics), le32_to_cpu(tcon->fsAttrInfo.Attributes), le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength), diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index a83684d8eb5..5f2ec194677 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -3386,9 +3386,11 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, kfree(tcon->nativeFileSystem); tcon->nativeFileSystem = kzalloc(length + 2, GFP_KERNEL); - cifs_strfromUCS_le(tcon->nativeFileSystem, - (__le16 *) bcc_ptr, - length, nls_codepage); + if (tcon->nativeFileSystem) + cifs_strfromUCS_le( + tcon->nativeFileSystem, + (__le16 *) bcc_ptr, + length, nls_codepage); bcc_ptr += 2 * length; bcc_ptr[0] = 0; /* null terminate the string */ bcc_ptr[1] = 0; @@ -3403,8 +3405,9 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, kfree(tcon->nativeFileSystem); tcon->nativeFileSystem = kzalloc(length + 1, GFP_KERNEL); - strncpy(tcon->nativeFileSystem, bcc_ptr, - length); + if (tcon->nativeFileSystem) + strncpy(tcon->nativeFileSystem, bcc_ptr, + length); } /* else do not bother copying these information fields*/ } -- cgit v1.2.3 From a23d30698190f05491a6096f027311f94d4d26d5 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 15 Sep 2007 03:43:47 +0000 Subject: [CIFS] missing field in debug output from previous fix Signed-off-by: Steve French --- fs/cifs/cifs_debug.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 0356694b5cd..56c5d9126f5 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -213,7 +213,8 @@ cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset, tcon->treeName, atomic_read(&tcon->useCount)); buf += length; if (tcon->nativeFileSystem) { - length = sprintf("Type: %s ", tcon->nativeFileSystem); + length = sprintf(buf, "Type: %s ", + tcon->nativeFileSystem); buf += length; } length = sprintf(buf, "DevInfo: 0x%x Attributes: 0x%x" -- cgit v1.2.3 From 5a07cdf86c1485b570789fb660c8ada7c2635b23 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sun, 16 Sep 2007 23:12:47 +0000 Subject: [CIFS] fix small memory leak in an error path in new posix mkdir There is a small memory leak in fs/cifs/inode.c::cifs_mkdir(). Storage for 'pInfo' is allocated with kzalloc(), but if the call to CIFSPOSIXCreate(...) happens to return 0 and pInfo->Type == -1, then we'll jump to the 'mkdir_get_info' label without freeing the storage allocated for 'pInfo'. This patch adds a kfree() call to free the storage just before jumping to the label, thus getting rid of the leak. Signed-off-by: Jesper Juhl Signed-off-by: Steve French --- fs/cifs/inode.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index e800c0ef54f..9dffa93d6bd 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -930,8 +930,10 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) d_drop(direntry); } else { int obj_type; - if (pInfo->Type == -1) /* no return info - go query */ + if (pInfo->Type == -1) /* no return info - go query */ { + kfree(pInfo); goto mkdir_get_info; + } /*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need to set uid/gid */ inc_nlink(inode); @@ -941,8 +943,10 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) direntry->d_op = &cifs_dentry_ops; newinode = new_inode(inode->i_sb); - if (newinode == NULL) + if (newinode == NULL) { + kfree(pInfo); goto mkdir_get_info; + } /* Is an i_ino of zero legal? */ /* Are there sanity checks we can use to ensure that the server is really filling in that field? */ -- cgit v1.2.3 From c45d707f67b82236fcf9ca2af31c264669368b9b Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 17 Sep 2007 02:04:21 +0000 Subject: [CIFS] Fallback to standard mkdir if server incorrectly claims support for posix ops Signed-off-by: Steve French --- fs/cifs/cifsfs.h | 2 +- fs/cifs/inode.c | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index dd64cecd923..13c53a4ee0f 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -101,5 +101,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.50" +#define CIFS_VERSION "1.51" #endif /* _CIFSFS_H */ diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 9dffa93d6bd..552d68b9d6f 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -925,7 +925,10 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) full_path, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); - if (rc) { + if (rc == -EOPNOTSUPP) { + kfree(pInfo); + goto mkdir_retry_old; + } else if (rc) { cFYI(1, ("posix mkdir returned 0x%x", rc)); d_drop(direntry); } else { @@ -977,7 +980,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) kfree(pInfo); goto mkdir_out; } - +mkdir_retry_old: /* BB add setting the equivalent of mode via CreateX w/ACLs */ rc = CIFSSMBMkDir(xid, pTcon, full_path, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); -- cgit v1.2.3 From 5a44b3190e3441986648ff664ef045685995324b Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 20 Sep 2007 15:16:24 +0000 Subject: [CIFS] Add warning message when broken server fails SetFSInfo call A reasonably common NAS server returns an error on the SetFSInfo of the Unix capabilities. Log a message for this alerting the user that the server may have problems with the Unix extensions, and telling them what they can do to workaround it. Unfortunately the server does not return other clues that we could easily use to turn the Unix Extension support off automatically in this case (since they claim to support it). Signed-off-by: Steve French --- fs/cifs/connect.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 5f2ec194677..73ed9fcab82 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1742,7 +1742,16 @@ void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon, cFYI(1, ("very large write cap")); #endif /* CIFS_DEBUG2 */ if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) { - cFYI(1, ("setting capabilities failed")); + if (vol_info == NULL) + cFYI(1, ("resetting capabilities failed")); + else + cERROR(1, ("Negotiating Unix capabilities " + "with the server failed. Consider " + "mounting with the Unix Extensions\n" + "disabled, if problems are found, " + "by specifying the nounix mount " + "option."); + } } } -- cgit v1.2.3 From 1e71f25d14d70f2bf607b40ab6d7e18daca57f36 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 20 Sep 2007 15:30:07 +0000 Subject: [CIFS] Print better error when server returns malformed QueryUnixInfo response Signed-off-by: Steve French --- fs/cifs/cifssmb.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index bb30455caab..f33c89c3603 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -3361,6 +3361,9 @@ UnixQPathInfoRetry: rc = validate_t2((struct smb_t2_rsp *)pSMBr); if (rc || (pSMBr->ByteCount < sizeof(FILE_UNIX_BASIC_INFO))) { + cERROR(1, ("Malformed FILE_UNIX_BASIC_INFO response.\n" + "Unix Extensions can be disabled on mount " + "by specifying the nosfu mount option.")); rc = -EIO; /* bad smb */ } else { __u16 data_offset = le16_to_cpu(pSMBr->t2.DataOffset); -- cgit v1.2.3 From 2224f4e5d5317552d48ce9059761148b1516ba5d Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 20 Sep 2007 15:37:29 +0000 Subject: [CIFS] fix typo in previous commit Signed-off-by: Steve French --- fs/cifs/connect.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 73ed9fcab82..5c3cc6487e5 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1750,7 +1750,7 @@ void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon, "mounting with the Unix Extensions\n" "disabled, if problems are found, " "by specifying the nounix mount " - "option."); + "option.")); } } -- cgit v1.2.3 From 442aa310f3bc49cf4e059da790fbae62411d50db Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 24 Sep 2007 20:25:46 +0000 Subject: [CIFS] Support for CIFS ACLs (part 1) Add code to be able to dump CIFS ACL information when Query Posix ACL with cifsacl mount parm enabled. Signed-off-by: Shirish Pargoankar Signed-off-by: Steve French --- fs/cifs/cifsacl.h | 34 ++++++++++++++++-- fs/cifs/cifsglob.h | 12 +++++++ fs/cifs/cifssmb.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++--- fs/cifs/connect.c | 4 +-- 4 files changed, 143 insertions(+), 8 deletions(-) diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h index 5eff35d6e56..97d03dc8169 100644 --- a/fs/cifs/cifsacl.h +++ b/fs/cifs/cifsacl.h @@ -22,12 +22,42 @@ #ifndef _CIFSACL_H #define _CIFSACL_H +struct cifs_ntsd { + __u16 revision; /* revision level */ + __u16 type; + __u32 osidoffset; + __u32 gsidoffset; + __u32 sacloffset; + __u32 dacloffset; +} __attribute__((packed)); + struct cifs_sid { __u8 revision; /* revision level */ - __u8 num_subauths; + __u8 num_auth; + __u8 authority[6]; + __u32 sub_auth[4]; + __u32 rid; +} __attribute__((packed)); + +struct cifs_acl { + __u16 revision; /* revision level */ + __u16 size; + __u32 num_aces; +} __attribute__((packed)); + +struct cifs_ntace { + __u8 type; + __u8 flags; + __u16 size; + __u32 access_req; +} __attribute__((packed)); + +struct cifs_ace { + __u8 revision; /* revision level */ + __u8 num_auth; __u8 authority[6]; __u32 sub_auth[4]; - /* next sub_auth if any ... */ + __u32 rid; } __attribute__((packed)); /* everyone */ diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index b98742fc3b5..bb468de4f47 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -19,6 +19,7 @@ #include #include #include "cifs_fs_sb.h" +#include "cifsacl.h" /* * The sizes of various internal tables and strings */ @@ -115,6 +116,17 @@ struct mac_key { } data; }; +struct cifs_cred { + int uid; + int gid; + int mode; + int cecount; + struct cifs_sid osid; + struct cifs_sid gsid; + struct cifs_ntace *ntaces; + struct cifs_ace *aces; +}; + /* ***************************************************************** * Except the CIFS PDUs themselves all the diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index f33c89c3603..46c2bb45512 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -3048,17 +3048,110 @@ static const struct cifs_sid sid_everyone = static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}}; +static void parse_sid(struct cifs_sid * psid, char * end_of_acl) +{ + /* BB need to add parm so we can store the SID BB */ + + /* validate that we do not go past end of acl */ + if (end_of_acl < (char *)psid + sizeof(struct cifs_sid)) { + cERROR(1, ("ACL to small to parse SID")); + return; + } +#ifdef CONFIG_CIFS_DEBUG2 + cFYI(1, ("revision %d num_auth %d First subauth 0x%x", + psid->revision, psid->num_auth, psid->sub_auth[0])); + + /* BB add length check to make sure that we do not have huge num auths + and therefore go off the end */ + cFYI(1, ("RID 0x%x", le32_to_cpu(psid->sub_auth[psid->num_auth]))); +#endif + return; +} + /* Convert CIFS ACL to POSIX form */ -static int parse_sec_desc(struct cifs_sid *psec_desc, int acl_len) +static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len) { - return 0; + int i; + int num_aces = 0; + int acl_size; + struct cifs_sid *owner_sid_ptr, *group_sid_ptr; + struct cifs_acl *dacl_ptr; /* no need for SACL ptr */ + struct cifs_ntace **ppntace; + struct cifs_ace **ppace; + char *acl_base; + char *end_of_acl = ((char *)pntsd) + acl_len; + + owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + + cpu_to_le32(pntsd->osidoffset)); + group_sid_ptr = (struct cifs_sid *)((char *)pntsd + + cpu_to_le32(pntsd->gsidoffset)); + dacl_ptr = (struct cifs_acl *)((char *)pntsd + + cpu_to_le32(pntsd->dacloffset)); +#ifdef CONFIG_CIFS_DEBUG2 + cFYI(1,("revision %d type 0x%x ooffset 0x%x goffset 0x%x " + "sacloffset 0x%x dacloffset 0x%x", pntsd->revision, pntsd->type, + pntsd->osidoffset, pntsd->gsidoffset, pntsd->sacloffset, + pntsd->dacloffset)); +#endif + parse_sid(owner_sid_ptr, end_of_acl); + parse_sid(group_sid_ptr, end_of_acl); + +/* cifscred->uid = owner_sid_ptr->rid; + cifscred->gid = group_sid_ptr->rid; + memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr, + sizeof (struct cifs_sid)); + memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr, + sizeof (struct cifs_sid)); */ + + num_aces = cpu_to_le32(dacl_ptr->num_aces); + cFYI(1, ("num aces %d", num_aces)); + if (num_aces > 0) { + ppntace = kmalloc(num_aces * sizeof(struct cifs_ntace *), + GFP_KERNEL); + ppace = kmalloc(num_aces * sizeof(struct cifs_ace *), + GFP_KERNEL); + +/* cifscred->cecount = dacl_ptr->num_aces; + cifscred->ntaces = kmalloc(num_aces * + sizeof(struct cifs_ntace *), GFP_KERNEL); + cifscred->aces = kmalloc(num_aces * + sizeof(struct cifs_ace *), GFP_KERNEL);*/ + + acl_base = (char *)dacl_ptr; + acl_size = sizeof(struct cifs_acl); + + for (i = 0; i < num_aces; ++i) { + ppntace[i] = (struct cifs_ntace *) + (acl_base + acl_size); + ppace[i] = (struct cifs_ace *) + ((char *)ppntace[i] + + sizeof(struct cifs_ntace)); + +/* memcpy((void *)(&(cifscred->ntaces[i])), + (void *)ntace_ptrptr[i], + sizeof(struct cifs_ntace)); + memcpy((void *)(&(cifscred->aces[i])), + (void *)ace_ptrptr[i], + sizeof(struct cifs_ace)); */ + + acl_base = (char *)ppntace[i]; + acl_size = cpu_to_le32(ppntace[i]->size); +#ifdef CONFIG_CIFS_DEBUG2 + cFYI(1, ("ACE revision:%d", ppace[i]->revision)); + } +#endif + kfree(ppace); + kfree(ppntace); + } + + return (0); } /* Get Security Descriptor (by handle) from remote server for a file or dir */ int CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, /* BB fix up return info */ char *acl_inf, const int buflen, - const int acl_type /* ACCESS/DEFAULT not sure implication */) + const int acl_type) { int rc = 0; int buf_type = 0; @@ -3088,7 +3181,7 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, if (rc) { cFYI(1, ("Send error in QuerySecDesc = %d", rc)); } else { /* decode response */ - struct cifs_sid *psec_desc; + struct cifs_ntsd *psec_desc; __le32 * parm; int parm_len; int data_len; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 5c3cc6487e5..e43cb880f54 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1742,9 +1742,9 @@ void reset_cifs_unix_caps(int xid, struct cifsTconInfo *tcon, cFYI(1, ("very large write cap")); #endif /* CIFS_DEBUG2 */ if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) { - if (vol_info == NULL) + if (vol_info == NULL) { cFYI(1, ("resetting capabilities failed")); - else + } else cERROR(1, ("Negotiating Unix capabilities " "with the server failed. Consider " "mounting with the Unix Extensions\n" -- cgit v1.2.3 From bcb020341a7d0fba6cd025f068d40f4ab5c36af8 Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 25 Sep 2007 16:17:24 +0000 Subject: [CIFS] move cifs acl code to new file and fix build break Signed-off-by: Steve French --- fs/cifs/Makefile | 2 +- fs/cifs/cifsacl.c | 134 ++++++++++++++++++++++++++++++++++++++++++++++++++++ fs/cifs/cifsacl.h | 2 +- fs/cifs/cifsproto.h | 1 + fs/cifs/cifssmb.c | 107 ----------------------------------------- 5 files changed, 137 insertions(+), 109 deletions(-) create mode 100644 fs/cifs/cifsacl.c diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile index 6ecd9d6ba3f..ff6ba8d823f 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 sess.o export.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 export.o cifsacl.o diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c new file mode 100644 index 00000000000..11ac13336ec --- /dev/null +++ b/fs/cifs/cifsacl.c @@ -0,0 +1,134 @@ +/* + * fs/cifs/cifsacl.c + * + * Copyright (C) International Business Machines Corp., 2007 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * Contains the routines for mapping CIFS/NTFS ACLs + * + * 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 + */ + +/* security id for everyone */ +static const struct cifs_sid sid_everyone = + {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}}; +/* group users */ +static const struct cifs_sid sid_user = + {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}}; + +static int parse_sid(struct cifs_sid *psid, char *end_of_acl) +{ + /* BB need to add parm so we can store the SID BB */ + + /* validate that we do not go past end of acl */ + if (end_of_acl < (char *)psid + sizeof(struct cifs_sid)) { + cERROR(1, ("ACL to small to parse SID")); + return -EINVAL; + } +#ifdef CONFIG_CIFS_DEBUG2 + cFYI(1, ("revision %d num_auth %d First subauth 0x%x", + psid->revision, psid->num_auth, psid->sub_auth[0])); + + /* BB add length check to make sure that we do not have huge num auths + and therefore go off the end */ + cFYI(1, ("RID 0x%x", le32_to_cpu(psid->sub_auth[psid->num_auth]))); +#endif + return 0; +} + +/* Convert CIFS ACL to POSIX form */ +int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len) +{ + int i; + int num_aces = 0; + int acl_size; + struct cifs_sid *owner_sid_ptr, *group_sid_ptr; + struct cifs_acl *dacl_ptr; /* no need for SACL ptr */ + struct cifs_ntace **ppntace; + struct cifs_ace **ppace; + char *acl_base; + char *end_of_acl = ((char *)pntsd) + acl_len; + + owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + + cpu_to_le32(pntsd->osidoffset)); + group_sid_ptr = (struct cifs_sid *)((char *)pntsd + + cpu_to_le32(pntsd->gsidoffset)); + dacl_ptr = (struct cifs_acl *)((char *)pntsd + + cpu_to_le32(pntsd->dacloffset)); +#ifdef CONFIG_CIFS_DEBUG2 + cFYI(1, ("revision %d type 0x%x ooffset 0x%x goffset 0x%x " + "sacloffset 0x%x dacloffset 0x%x", + pntsd->revision, pntsd->type, + pntsd->osidoffset, pntsd->gsidoffset, pntsd->sacloffset, + pntsd->dacloffset)); +#endif + rc = parse_sid(owner_sid_ptr, end_of_acl); + if (rc) + return rc; + + rc = parse_sid(group_sid_ptr, end_of_acl); + if (rc) + return rc; + +/* cifscred->uid = owner_sid_ptr->rid; + cifscred->gid = group_sid_ptr->rid; + memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr, + sizeof (struct cifs_sid)); + memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr, + sizeof (struct cifs_sid)); */ + + num_aces = cpu_to_le32(dacl_ptr->num_aces); + cFYI(1, ("num aces %d", num_aces)); + if (num_aces > 0) { + ppntace = kmalloc(num_aces * sizeof(struct cifs_ntace *), + GFP_KERNEL); + ppace = kmalloc(num_aces * sizeof(struct cifs_ace *), + GFP_KERNEL); + +/* cifscred->cecount = dacl_ptr->num_aces; + cifscred->ntaces = kmalloc(num_aces * + sizeof(struct cifs_ntace *), GFP_KERNEL); + cifscred->aces = kmalloc(num_aces * + sizeof(struct cifs_ace *), GFP_KERNEL);*/ + + acl_base = (char *)dacl_ptr; + acl_size = sizeof(struct cifs_acl); + + for (i = 0; i < num_aces; ++i) { + ppntace[i] = (struct cifs_ntace *) + (acl_base + acl_size); + ppace[i] = (struct cifs_ace *) + ((char *)ppntace[i] + + sizeof(struct cifs_ntace)); + +/* memcpy((void *)(&(cifscred->ntaces[i])), + (void *)ntace_ptrptr[i], + sizeof(struct cifs_ntace)); + memcpy((void *)(&(cifscred->aces[i])), + (void *)ace_ptrptr[i], + sizeof(struct cifs_ace)); */ + + acl_base = (char *)ppntace[i]; + acl_size = cpu_to_le32(ppntace[i]->size); +#ifdef CONFIG_CIFS_DEBUG2 + cFYI(1, ("ACE revision:%d", ppace[i]->revision)); +#endif + } + kfree(ppace); + kfree(ppntace); + } + + return (0); +} diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h index 97d03dc8169..b975ae11303 100644 --- a/fs/cifs/cifsacl.h +++ b/fs/cifs/cifsacl.h @@ -1,7 +1,7 @@ /* * fs/cifs/cifsacl.h * - * Copyright (c) International Business Machines Corp., 2005 + * Copyright (c) International Business Machines Corp., 2007 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 4ffae9d9291..7dbb79b8dd5 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -310,6 +310,7 @@ extern void setup_ntlmv2_rsp(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 parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len); 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 46c2bb45512..cc05a26ab07 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -3040,113 +3040,6 @@ GetExtAttrOut: #endif /* CONFIG_POSIX */ - -/* security id for everyone */ -static const struct cifs_sid sid_everyone = - {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}}; -/* group users */ -static const struct cifs_sid sid_user = - {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}}; - -static void parse_sid(struct cifs_sid * psid, char * end_of_acl) -{ - /* BB need to add parm so we can store the SID BB */ - - /* validate that we do not go past end of acl */ - if (end_of_acl < (char *)psid + sizeof(struct cifs_sid)) { - cERROR(1, ("ACL to small to parse SID")); - return; - } -#ifdef CONFIG_CIFS_DEBUG2 - cFYI(1, ("revision %d num_auth %d First subauth 0x%x", - psid->revision, psid->num_auth, psid->sub_auth[0])); - - /* BB add length check to make sure that we do not have huge num auths - and therefore go off the end */ - cFYI(1, ("RID 0x%x", le32_to_cpu(psid->sub_auth[psid->num_auth]))); -#endif - return; -} - -/* Convert CIFS ACL to POSIX form */ -static int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len) -{ - int i; - int num_aces = 0; - int acl_size; - struct cifs_sid *owner_sid_ptr, *group_sid_ptr; - struct cifs_acl *dacl_ptr; /* no need for SACL ptr */ - struct cifs_ntace **ppntace; - struct cifs_ace **ppace; - char *acl_base; - char *end_of_acl = ((char *)pntsd) + acl_len; - - owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + - cpu_to_le32(pntsd->osidoffset)); - group_sid_ptr = (struct cifs_sid *)((char *)pntsd + - cpu_to_le32(pntsd->gsidoffset)); - dacl_ptr = (struct cifs_acl *)((char *)pntsd + - cpu_to_le32(pntsd->dacloffset)); -#ifdef CONFIG_CIFS_DEBUG2 - cFYI(1,("revision %d type 0x%x ooffset 0x%x goffset 0x%x " - "sacloffset 0x%x dacloffset 0x%x", pntsd->revision, pntsd->type, - pntsd->osidoffset, pntsd->gsidoffset, pntsd->sacloffset, - pntsd->dacloffset)); -#endif - parse_sid(owner_sid_ptr, end_of_acl); - parse_sid(group_sid_ptr, end_of_acl); - -/* cifscred->uid = owner_sid_ptr->rid; - cifscred->gid = group_sid_ptr->rid; - memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr, - sizeof (struct cifs_sid)); - memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr, - sizeof (struct cifs_sid)); */ - - num_aces = cpu_to_le32(dacl_ptr->num_aces); - cFYI(1, ("num aces %d", num_aces)); - if (num_aces > 0) { - ppntace = kmalloc(num_aces * sizeof(struct cifs_ntace *), - GFP_KERNEL); - ppace = kmalloc(num_aces * sizeof(struct cifs_ace *), - GFP_KERNEL); - -/* cifscred->cecount = dacl_ptr->num_aces; - cifscred->ntaces = kmalloc(num_aces * - sizeof(struct cifs_ntace *), GFP_KERNEL); - cifscred->aces = kmalloc(num_aces * - sizeof(struct cifs_ace *), GFP_KERNEL);*/ - - acl_base = (char *)dacl_ptr; - acl_size = sizeof(struct cifs_acl); - - for (i = 0; i < num_aces; ++i) { - ppntace[i] = (struct cifs_ntace *) - (acl_base + acl_size); - ppace[i] = (struct cifs_ace *) - ((char *)ppntace[i] + - sizeof(struct cifs_ntace)); - -/* memcpy((void *)(&(cifscred->ntaces[i])), - (void *)ntace_ptrptr[i], - sizeof(struct cifs_ntace)); - memcpy((void *)(&(cifscred->aces[i])), - (void *)ace_ptrptr[i], - sizeof(struct cifs_ace)); */ - - acl_base = (char *)ppntace[i]; - acl_size = cpu_to_le32(ppntace[i]->size); -#ifdef CONFIG_CIFS_DEBUG2 - cFYI(1, ("ACE revision:%d", ppace[i]->revision)); - } -#endif - kfree(ppace); - kfree(ppntace); - } - - return (0); -} - /* Get Security Descriptor (by handle) from remote server for a file or dir */ int CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, -- cgit v1.2.3 From 65874007c36930317c7a56d814a6a3e2966daaa8 Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 25 Sep 2007 19:53:44 +0000 Subject: [CIFS] fix cut and paste error - missing defines cause cifsacl build error Signed-off-by: Steve French --- fs/cifs/cifsacl.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 11ac13336ec..90969104dd3 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -21,6 +21,13 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +#include +#include "cifspdu.h" +#include "cifsglob.h" +#include "cifsproto.h" +#include "cifs_debug.h" +#include "cifsacl.h" + /* security id for everyone */ static const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}}; @@ -51,7 +58,7 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl) /* Convert CIFS ACL to POSIX form */ int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len) { - int i; + int i, rc; int num_aces = 0; int acl_size; struct cifs_sid *owner_sid_ptr, *group_sid_ptr; -- cgit v1.2.3 From 407f61a2b482ab9a6d03549ab9513e4a823ae4a2 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 28 Sep 2007 06:53:39 +0000 Subject: [CIFS] Fix memory leak in statfs to very old servers We were allocating request buffers twice in the statfs path when mounted to very old (Windows 9x) servers. Signed-off-by: Steve French --- fs/cifs/CHANGES | 5 +++++ fs/cifs/cifssmb.c | 4 ---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 41e3b6a9397..ea359a0038d 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -1,3 +1,8 @@ +Version 1.51 +------------ +Fix memory leak in statfs when mounted to very old servers (e.g. +Windows 9x) + Version 1.50 ------------ Fix NTLMv2 signing. NFS server mounted over cifs works (if cifs mount is diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index cc05a26ab07..a6ff324bc13 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -4045,10 +4045,6 @@ oldQFSInfoRetry: (void **) &pSMBr); if (rc) return rc; - rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, - (void **) &pSMBr); - if (rc) - return rc; params = 2; /* level */ pSMB->TotalDataCount = 0; -- cgit v1.2.3 From 7f8ed420f80c91176dfd27c8089f22cab5c9ba78 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 28 Sep 2007 22:28:55 +0000 Subject: [CIFS] CIFS support for named pipes (part 1) This allows cifs to mount to ipc shares (IPC$) which will allow user space applications to layer over authenticated cifs connections (useful for Wine and others that would want to put DCE/RPC over CIFS or run CIFS named pipes) Acked-by: Rob Shearman Signed-off-by: Steve French --- fs/cifs/cifsglob.h | 2 ++ fs/cifs/connect.c | 18 ++++++++++++++++-- fs/cifs/dir.c | 2 +- fs/cifs/inode.c | 22 ++++++++++++++++++---- fs/cifs/misc.c | 1 - 5 files changed, 37 insertions(+), 8 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index bb468de4f47..f55be8efa26 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -291,6 +291,7 @@ struct cifsTconInfo { FILE_SYSTEM_DEVICE_INFO fsDevInfo; FILE_SYSTEM_ATTRIBUTE_INFO fsAttrInfo; /* ok if fs name truncated */ FILE_SYSTEM_UNIX_INFO fsUnixInfo; + unsigned ipc:1; /* set if connection to IPC$ eg for RPC/PIPES */ unsigned retry:1; unsigned nocase:1; unsigned unix_ext:1; /* if off disable Linux extensions to CIFS protocol @@ -341,6 +342,7 @@ struct cifsFileInfo { struct list_head llist; /* list of byte range locks we have. */ unsigned closePend:1; /* file is marked to close */ unsigned invalidHandle:1; /* file closed via session abend */ + unsigned messageMode:1 /* for pipes: is message or byte mode */ 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 */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index e43cb880f54..21cac15ed9a 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2186,8 +2186,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, tcon->ses = pSesInfo; /* do not care if following two calls succeed - informational */ - CIFSSMBQFSDeviceInfo(xid, tcon); - CIFSSMBQFSAttributeInfo(xid, tcon); + if (!tcon->ipc) { + CIFSSMBQFSDeviceInfo(xid, tcon); + CIFSSMBQFSAttributeInfo(xid, tcon); + } /* tell server which Unix caps we support */ if (tcon->ses->capabilities & CAP_UNIX) @@ -3385,6 +3387,18 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr = pByteArea(smb_buffer_response); length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2); /* skip service field (NB: this field is always ASCII) */ + if (length == 3) { + if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') && + (bcc_ptr[2] == 'C')) { + cFYI(1, ("IPC connection")); + tcon->ipc = 1; + } + } else if (length == 2) { + if ((bcc_ptr[0] == 'A') && (bcc_ptr[1] == ':')) { + /* the most common case */ + cFYI(1, ("disk share connection")); + } + } bcc_ptr += length + 1; strncpy(tcon->treeName, tree, MAX_TREE_SIZE); if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index db5287abc30..99321ab439d 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -3,7 +3,7 @@ * * vfs operations that deal with dentries * - * Copyright (C) International Business Machines Corp., 2002,2005 + * Copyright (C) International Business Machines Corp., 2002,2007 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 552d68b9d6f..ece17ca00d0 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -115,7 +115,7 @@ int cifs_get_inode_info_unix(struct inode **pinode, inode->i_mode = le64_to_cpu(findData.Permissions); /* since we set the inode type below we need to mask off to avoid strange results if bits set above */ - inode->i_mode &= ~S_IFMT; + inode->i_mode &= ~S_IFMT; if (type == UNIX_FILE) { inode->i_mode |= S_IFREG; } else if (type == UNIX_SYMLINK) { @@ -575,19 +575,33 @@ int cifs_get_inode_info(struct inode **pinode, return rc; } +static const struct inode_operations cifs_ipc_inode_ops = { + .lookup = cifs_lookup, +}; + /* gets root inode */ void cifs_read_inode(struct inode *inode) { - int xid; + int xid, rc; struct cifs_sb_info *cifs_sb; cifs_sb = CIFS_SB(inode->i_sb); xid = GetXid(); if (cifs_sb->tcon->unix_ext) - cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid); + rc = cifs_get_inode_info_unix(&inode, "", inode->i_sb, xid); else - cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid); + rc = cifs_get_inode_info(&inode, "", NULL, inode->i_sb, xid); + if (rc && cifs_sb->tcon->ipc) { + cFYI(1, ("ipc connection - fake read inode")); + inode->i_mode |= S_IFDIR; + inode->i_nlink = 2; + inode->i_op = &cifs_ipc_inode_ops; + inode->i_fop = &simple_dir_operations; + inode->i_uid = cifs_sb->mnt_uid; + inode->i_gid = cifs_sb->mnt_gid; + } + /* can not call macro FreeXid here since in a void func */ _FreeXid(xid); } diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 0bcec0844be..51ec681fe74 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -169,7 +169,6 @@ cifs_buf_get(void) void cifs_buf_release(void *buf_to_free) { - if (buf_to_free == NULL) { /* cFYI(1, ("Null buffer passed to cifs_buf_release"));*/ return; -- cgit v1.2.3 From 92ad9b93cd268371d1fc0edbd09383cc1c59be34 Mon Sep 17 00:00:00 2001 From: Steve French Date: Sat, 29 Sep 2007 05:21:58 +0000 Subject: [CIFS] named pipe support (part 2) Also fixes typo which could cause build break Signed-off-by: Steve French --- fs/cifs/CHANGES | 7 ++++++- fs/cifs/cifsglob.h | 2 +- fs/cifs/cifspdu.h | 8 ++++++++ fs/cifs/dir.c | 5 ++--- 4 files changed, 17 insertions(+), 5 deletions(-) diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index ea359a0038d..c8ad87de4a7 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -1,7 +1,12 @@ Version 1.51 ------------ Fix memory leak in statfs when mounted to very old servers (e.g. -Windows 9x) +Windows 9x). Add new feature "POSIX open" which allows servers +which support the current POSIX Extensions to provide better semantics +(e.g. delete for open files opened with posix open). Take into +account umask on posix mkdir not just older style mkdir. Add +ability to mount to IPC$ share (which allows CIFS named pipes to be +opened, read and written as if they were files). Version 1.50 ------------ diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index f55be8efa26..3fb046be9c0 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -342,7 +342,7 @@ struct cifsFileInfo { struct list_head llist; /* list of byte range locks we have. */ unsigned closePend:1; /* file is marked to close */ unsigned invalidHandle:1; /* file closed via session abend */ - unsigned messageMode:1 /* for pipes: is message or byte mode */ + unsigned messageMode:1; /* for pipes: message vs byte mode */ 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 */ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index e975ce46115..d2f0cf23bbb 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -716,6 +716,14 @@ typedef struct smb_com_findclose_req { #define REQ_OPENDIRONLY 0x00000008 #define REQ_EXTENDED_INFO 0x00000010 +/* File type */ +#define DISK_TYPE 0x0000 +#define BYTE_PIPE_TYPE 0x0001 +#define MESSAGE_PIPE_TYPE 0x0002 +#define PRINTER_TYPE 0x0003 +#define COMM_DEV_TYPE 0x0004 +#define UNKNOWN_TYPE 0xFFFF + typedef struct smb_com_open_req { /* also handles create */ struct smb_hdr hdr; /* wct = 24 */ __u8 AndXCommand; diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 99321ab439d..793404b1092 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -269,7 +269,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, CIFSSMBClose(xid, pTcon, fileHandle); } else if (newinode) { pCifsFile = - kzalloc(sizeof (struct cifsFileInfo), GFP_KERNEL); + kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); if (pCifsFile == NULL) goto cifs_create_out; @@ -450,8 +450,7 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, xid = GetXid(); - cFYI(1, - (" parent inode = 0x%p name is: %s and dentry = 0x%p", + cFYI(1, (" parent inode = 0x%p name is: %s and dentry = 0x%p", parent_dir_inode, direntry->d_name.name, direntry)); /* check whether path exists */ -- cgit v1.2.3 From 4084973dbae9a24e58598d6cdf60f0e5e4a3cabf Mon Sep 17 00:00:00 2001 From: Steve French Date: Mon, 1 Oct 2007 19:59:01 +0000 Subject: [CIFS] change misleading field name num_auth is really num_subauth in ACL terminology Signed-off-by: Steve French --- fs/cifs/cifsacl.c | 4 ++-- fs/cifs/cifsacl.h | 10 ++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 90969104dd3..9b84f373af1 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -46,11 +46,11 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl) } #ifdef CONFIG_CIFS_DEBUG2 cFYI(1, ("revision %d num_auth %d First subauth 0x%x", - psid->revision, psid->num_auth, psid->sub_auth[0])); + psid->revision, psid->num_subauth, psid->sub_auth[0])); /* BB add length check to make sure that we do not have huge num auths and therefore go off the end */ - cFYI(1, ("RID 0x%x", le32_to_cpu(psid->sub_auth[psid->num_auth]))); + cFYI(1, ("RID 0x%x", le32_to_cpu(psid->sub_auth[psid->num_subauth]))); #endif return 0; } diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h index b975ae11303..5e7b56738cc 100644 --- a/fs/cifs/cifsacl.h +++ b/fs/cifs/cifsacl.h @@ -33,10 +33,9 @@ struct cifs_ntsd { struct cifs_sid { __u8 revision; /* revision level */ - __u8 num_auth; + __u8 num_subauth; __u8 authority[6]; - __u32 sub_auth[4]; - __u32 rid; + __u32 sub_auth[0]; /* sub_auth[num_subauth] */ } __attribute__((packed)); struct cifs_acl { @@ -54,10 +53,9 @@ struct cifs_ntace { struct cifs_ace { __u8 revision; /* revision level */ - __u8 num_auth; + __u8 num_subauth; __u8 authority[6]; - __u32 sub_auth[4]; - __u32 rid; + __u32 sub_auth[0]; } __attribute__((packed)); /* everyone */ -- cgit v1.2.3 From 9b22b0b726c6e46048767728a0900c8c05f93c21 Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 2 Oct 2007 01:11:08 +0000 Subject: [CIFS] Reduce chance of list corruption in find_writable_file When find_writable_file is racing with close and the session to the server goes down, Shaggy noticed that there was a chance that an open file in the list of files off the inode could have been freed by close since cifs_reconnect can block (the spinlock thus not held). This means that we have to start over at the beginning of the list in some cases. There is a 2nd change that needs to be made later (pointed out by Jeremy Allison and Shaggy) in order to prevent cifs_close ever freeing the cifs per file info when a write is pending. Although we delay close from freeing this memory for sufficiently long for all known cases, ultimately on a very, very slow write overlapping a close pending we need to allow close to return (without freeing the cifs file info) and defer freeing the memory to be the responsibility of the (sloooow) write thread (presumably have to look at every place wrtPending is decremented - and add a flag for deferred free for after wrtPending goes to zero). Acked-by: Shaggy Acked-by: Shirish Pargaonkar Signed-off-by: Steve French --- fs/cifs/file.c | 54 +++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 79254919386..780c0e3e470 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1042,6 +1042,7 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) } read_lock(&GlobalSMBSeslock); +refind_writable: list_for_each_entry(open_file, &cifs_inode->openFileList, flist) { if (open_file->closePend) continue; @@ -1049,26 +1050,49 @@ struct cifsFileInfo *find_writable_file(struct cifsInodeInfo *cifs_inode) ((open_file->pfile->f_flags & O_RDWR) || (open_file->pfile->f_flags & O_WRONLY))) { atomic_inc(&open_file->wrtPending); + + if (!open_file->invalidHandle) { + /* found a good writable file */ + read_unlock(&GlobalSMBSeslock); + return open_file; + } + read_unlock(&GlobalSMBSeslock); - if (open_file->invalidHandle) { - rc = cifs_reopen_file(open_file->pfile, FALSE); - /* if it fails, try another handle - might be */ - /* dangerous to hold up writepages with retry */ - if (rc) { - cFYI(1, ("wp failed on reopen file")); + /* Had to unlock since following call can block */ + rc = cifs_reopen_file(open_file->pfile, FALSE); + if (!rc) { + if (!open_file->closePend) + return open_file; + else { /* start over in case this was deleted */ + /* since the list could be modified */ read_lock(&GlobalSMBSeslock); - /* can not use this handle, no write - pending on this one after all */ atomic_dec(&open_file->wrtPending); - continue; + goto refind_writable; } } - if (open_file->closePend) { - read_lock(&GlobalSMBSeslock); - atomic_dec(&open_file->wrtPending); - continue; - } - return open_file; + + /* if it fails, try another handle if possible - + (we can not do this if closePending since + loop could be modified - in which case we + have to start at the beginning of the list + again. Note that it would be bad + to hold up writepages here (rather than + in caller) with continuous retries */ + cFYI(1, ("wp failed on reopen file")); + read_lock(&GlobalSMBSeslock); + /* can not use this handle, no write + pending on this one after all */ + atomic_dec(&open_file->wrtPending); + + if (open_file->closePend) /* list could have changed */ + goto refind_writable; + /* else we simply continue to the next entry. Thus + we do not loop on reopen errors. If we + can not reopen the file, for example if we + reconnected to a server with another client + racing to delete or lock the file we would not + make progress if we restarted before the beginning + of the loop here. */ } } read_unlock(&GlobalSMBSeslock); -- cgit v1.2.3 From a8a11d399fc3c70f2aa645c7472235a06e8b8efa Mon Sep 17 00:00:00 2001 From: Mariusz Kozlowski Date: Wed, 3 Oct 2007 16:41:24 +0000 Subject: [CIFS] remove some redundant argument checks This patch does kmalloc + memset conversion to kzalloc and removes some redundant argument checks. Signed-off-by: Mariusz Kozlowski Signed-off-by: Andrew Morton Signed-off-by: Steve French --- fs/cifs/connect.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 21cac15ed9a..fc3a851357f 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -673,9 +673,8 @@ multi_t2_fnd: server->ssocket = NULL; } /* buffer usuallly freed in free_mid - need to free it here on exit */ - if (bigbuf != NULL) - cifs_buf_release(bigbuf); - if (smallbuf != NULL) + cifs_buf_release(bigbuf); + if (smallbuf) /* no sense logging a debug message if NULL */ cifs_small_buf_release(smallbuf); read_lock(&GlobalSMBSeslock); @@ -1910,8 +1909,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, return rc; } - srvTcp = kmalloc(sizeof (struct TCP_Server_Info), GFP_KERNEL); - if (srvTcp == NULL) { + srvTcp = kzalloc(sizeof(struct TCP_Server_Info), GFP_KERNEL); + if (!srvTcp) { rc = -ENOMEM; sock_release(csocket); kfree(volume_info.UNC); @@ -1920,7 +1919,6 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, FreeXid(xid); return rc; } else { - memset(srvTcp, 0, sizeof (struct TCP_Server_Info)); memcpy(&srvTcp->addr.sockAddr, &sin_server, sizeof (struct sockaddr_in)); atomic_set(&srvTcp->inFlight, 0); @@ -2529,8 +2527,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, sesssetup_nomem: /* do not return an error on nomem for the info strings, since that could make reconnection harder, and reconnection might be needed to free memory */ - if (smb_buffer) - cifs_buf_release(smb_buffer); + cifs_buf_release(smb_buffer); return rc; } @@ -2868,8 +2865,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, rc = -EIO; } - if (smb_buffer) - cifs_buf_release(smb_buffer); + cifs_buf_release(smb_buffer); return rc; } @@ -3277,8 +3273,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, rc = -EIO; } - if (smb_buffer) - cifs_buf_release(smb_buffer); + cifs_buf_release(smb_buffer); return rc; } @@ -3446,8 +3441,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, ses->ipc_tid = smb_buffer_response->Tid; } - if (smb_buffer) - cifs_buf_release(smb_buffer); + cifs_buf_release(smb_buffer); return rc; } -- cgit v1.2.3 From d0d66c443aefa51d5dbdd6a1d9b135a2a0e469cc Mon Sep 17 00:00:00 2001 From: Shirish Pargaonkar Date: Wed, 3 Oct 2007 18:22:19 +0000 Subject: [CIFS] CIFS ACL support (part 2) Signed-off-by: Shirish Pargaonkar Signed-off-by: Steve French --- fs/cifs/cifsacl.c | 203 +++++++++++++++++++++++++++++++++++++--------------- fs/cifs/cifsacl.h | 4 +- fs/cifs/cifsproto.h | 2 +- fs/cifs/cifssmb.c | 2 +- 4 files changed, 151 insertions(+), 60 deletions(-) diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 9b84f373af1..23bff0128e2 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -24,48 +24,178 @@ #include #include "cifspdu.h" #include "cifsglob.h" +#include "cifsacl.h" #include "cifsproto.h" #include "cifs_debug.h" -#include "cifsacl.h" /* security id for everyone */ static const struct cifs_sid sid_everyone = - {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}}; + {1, 1, {0, 0, 0, 0, 0, 0}, {}}; /* group users */ static const struct cifs_sid sid_user = - {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}}; + {1, 2 , {0, 0, 0, 0, 0, 5}, {}}; + +static void parse_ace(struct cifs_ace * pace, char * end_of_acl) +{ + int i; + int num_subauth; + __u32 *psub_auth; + + /* validate that we do not go past end of acl */ + if (end_of_acl < (char *)pace + sizeof(struct cifs_ace)) { + cERROR(1, ("ACL too small to parse ACE")); + return; + } + + num_subauth = cpu_to_le32(pace->num_subauth); + if (num_subauth) { + psub_auth = (__u32 *)((char *)pace + sizeof(struct cifs_ace)); +#ifdef CONFIG_CIFS_DEBUG2 + cFYI(1, ("ACE revision %d num_subauth %d", + pace->revision, pace->num_subauth)); + for (i = 0; i < num_subauth; ++i) { + cFYI(1, ("ACE sub_auth[%d]: 0x%x", i, + le32_to_cpu(psub_auth[i]))); + } + + /* BB add length check to make sure that we do not have huge + num auths and therefore go off the end */ + + cFYI(1, ("RID %d", le32_to_cpu(psub_auth[num_subauth-1]))); +#endif + } + + return; +} + +static void parse_ntace(struct cifs_ntace * pntace, char * end_of_acl) +{ + /* validate that we do not go past end of acl */ + if (end_of_acl < (char *)pntace + sizeof(struct cifs_ntace)) { + cERROR(1, ("ACL too small to parse NT ACE")); + return; + } + +#ifdef CONFIG_CIFS_DEBUG2 + cFYI(1, ("NTACE type %d flags 0x%x size %d, access Req 0x%x", + pntace->type, pntace->flags, pntace->size, + pntace->access_req)); +#endif + return; +} + + + +static void parse_dacl(struct cifs_acl * pdacl, char * end_of_acl) +{ + int i; + int num_aces = 0; + int acl_size; + char *acl_base; + struct cifs_ntace **ppntace; + struct cifs_ace **ppace; + + /* BB need to add parm so we can store the SID BB */ + + /* validate that we do not go past end of acl */ + if (end_of_acl < (char *)pdacl + pdacl->size) { + cERROR(1, ("ACL too small to parse DACL")); + return; + } + +#ifdef CONFIG_CIFS_DEBUG2 + cFYI(1, ("DACL revision %d size %d num aces %d", + pdacl->revision, pdacl->size, pdacl->num_aces)); +#endif + + acl_base = (char *)pdacl; + acl_size = sizeof(struct cifs_acl); + + num_aces = cpu_to_le32(pdacl->num_aces); + if (num_aces > 0) { + ppntace = kmalloc(num_aces * sizeof(struct cifs_ntace *), + GFP_KERNEL); + ppace = kmalloc(num_aces * sizeof(struct cifs_ace *), + GFP_KERNEL); + +/* cifscred->cecount = pdacl->num_aces; + cifscred->ntaces = kmalloc(num_aces * + sizeof(struct cifs_ntace *), GFP_KERNEL); + cifscred->aces = kmalloc(num_aces * + sizeof(struct cifs_ace *), GFP_KERNEL);*/ + + + for (i = 0; i < num_aces; ++i) { + ppntace[i] = (struct cifs_ntace *) + (acl_base + acl_size); + ppace[i] = (struct cifs_ace *) ((char *)ppntace[i] + + sizeof(struct cifs_ntace)); + + parse_ntace(ppntace[i], end_of_acl); + parse_ace(ppace[i], end_of_acl); + +/* memcpy((void *)(&(cifscred->ntaces[i])), + (void *)ppntace[i], + sizeof(struct cifs_ntace)); + memcpy((void *)(&(cifscred->aces[i])), + (void *)ppace[i], + sizeof(struct cifs_ace)); */ + + acl_base = (char *)ppntace[i]; + acl_size = cpu_to_le32(ppntace[i]->size); + } + + kfree(ppace); + kfree(ppntace); + } + + return; +} + static int parse_sid(struct cifs_sid *psid, char *end_of_acl) { + int i; + int num_subauth; + __u32 *psub_auth; + /* BB need to add parm so we can store the SID BB */ /* validate that we do not go past end of acl */ if (end_of_acl < (char *)psid + sizeof(struct cifs_sid)) { - cERROR(1, ("ACL to small to parse SID")); + cERROR(1, ("ACL too small to parse SID")); return -EINVAL; } + + num_subauth = cpu_to_le32(psid->num_subauth); + if (num_subauth) { + psub_auth = (__u32 *)((char *)psid + sizeof(struct cifs_sid)); #ifdef CONFIG_CIFS_DEBUG2 - cFYI(1, ("revision %d num_auth %d First subauth 0x%x", - psid->revision, psid->num_subauth, psid->sub_auth[0])); + cFYI(1, ("SID revision %d num_auth %d First subauth 0x%x", + psid->revision, psid->num_subauth, psid->sub_auth[0])); - /* BB add length check to make sure that we do not have huge num auths - and therefore go off the end */ - cFYI(1, ("RID 0x%x", le32_to_cpu(psid->sub_auth[psid->num_subauth]))); + for (i = 0; i < num_subauth; ++i) { + cFYI(1, ("SID sub_auth[%d]: 0x%x ", i, + le32_to_cpu(psub_auth[i]))); + } + + /* BB add length check to make sure that we do not have huge + num auths and therefore go off the end */ + cFYI(1, ("RID 0x%x", + le32_to_cpu(psid->sub_auth[psid->num_subauth]))); #endif + } + return 0; } + /* Convert CIFS ACL to POSIX form */ int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len) { - int i, rc; - int num_aces = 0; - int acl_size; + int rc; struct cifs_sid *owner_sid_ptr, *group_sid_ptr; struct cifs_acl *dacl_ptr; /* no need for SACL ptr */ - struct cifs_ntace **ppntace; - struct cifs_ace **ppace; - char *acl_base; char *end_of_acl = ((char *)pntsd) + acl_len; owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + @@ -89,6 +219,8 @@ int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len) if (rc) return rc; + parse_dacl(dacl_ptr, end_of_acl); + /* cifscred->uid = owner_sid_ptr->rid; cifscred->gid = group_sid_ptr->rid; memcpy((void *)(&(cifscred->osid)), (void *)owner_sid_ptr, @@ -96,46 +228,5 @@ int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len) memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr, sizeof (struct cifs_sid)); */ - num_aces = cpu_to_le32(dacl_ptr->num_aces); - cFYI(1, ("num aces %d", num_aces)); - if (num_aces > 0) { - ppntace = kmalloc(num_aces * sizeof(struct cifs_ntace *), - GFP_KERNEL); - ppace = kmalloc(num_aces * sizeof(struct cifs_ace *), - GFP_KERNEL); - -/* cifscred->cecount = dacl_ptr->num_aces; - cifscred->ntaces = kmalloc(num_aces * - sizeof(struct cifs_ntace *), GFP_KERNEL); - cifscred->aces = kmalloc(num_aces * - sizeof(struct cifs_ace *), GFP_KERNEL);*/ - - acl_base = (char *)dacl_ptr; - acl_size = sizeof(struct cifs_acl); - - for (i = 0; i < num_aces; ++i) { - ppntace[i] = (struct cifs_ntace *) - (acl_base + acl_size); - ppace[i] = (struct cifs_ace *) - ((char *)ppntace[i] + - sizeof(struct cifs_ntace)); - -/* memcpy((void *)(&(cifscred->ntaces[i])), - (void *)ntace_ptrptr[i], - sizeof(struct cifs_ntace)); - memcpy((void *)(&(cifscred->aces[i])), - (void *)ace_ptrptr[i], - sizeof(struct cifs_ace)); */ - - acl_base = (char *)ppntace[i]; - acl_size = cpu_to_le32(ppntace[i]->size); -#ifdef CONFIG_CIFS_DEBUG2 - cFYI(1, ("ACE revision:%d", ppace[i]->revision)); -#endif - } - kfree(ppace); - kfree(ppntace); - } - return (0); } diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h index 5e7b56738cc..bf297ea1905 100644 --- a/fs/cifs/cifsacl.h +++ b/fs/cifs/cifsacl.h @@ -44,14 +44,14 @@ struct cifs_acl { __u32 num_aces; } __attribute__((packed)); -struct cifs_ntace { +struct cifs_ntace { /* first part of ACE which contains perms */ __u8 type; __u8 flags; __u16 size; __u32 access_req; } __attribute__((packed)); -struct cifs_ace { +struct cifs_ace { /* last part of ACE which includes user info */ __u8 revision; /* revision level */ __u8 num_subauth; __u8 authority[6]; diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 7dbb79b8dd5..001f0dc7e60 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -310,7 +310,7 @@ extern void setup_ntlmv2_rsp(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 parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len); +extern int parse_sec_desc(struct cifs_ntsd *, int); 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 a6ff324bc13..90b8f8d64d6 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -34,10 +34,10 @@ #include #include "cifspdu.h" #include "cifsglob.h" +#include "cifsacl.h" #include "cifsproto.h" #include "cifs_unicode.h" #include "cifs_debug.h" -#include "cifsacl.h" #ifdef CONFIG_CIFS_POSIX static struct { -- cgit v1.2.3 From d12fd121afd4f87cbc7675f8f6b651d649534f15 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 3 Oct 2007 19:43:19 +0000 Subject: [CIFS] Cleanup formatting Signed-off-by: Steve French --- fs/cifs/cifsacl.c | 78 +++++++++++++++++++++++++++---------------------------- fs/cifs/xattr.c | 19 +++++++++----- 2 files changed, 51 insertions(+), 46 deletions(-) diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 23bff0128e2..52f9cb808fd 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -30,12 +30,12 @@ /* security id for everyone */ static const struct cifs_sid sid_everyone = - {1, 1, {0, 0, 0, 0, 0, 0}, {}}; + {1, 1, {0, 0, 0, 0, 0, 0}, {} }; /* group users */ static const struct cifs_sid sid_user = - {1, 2 , {0, 0, 0, 0, 0, 5}, {}}; + {1, 2 , {0, 0, 0, 0, 0, 5}, {} }; -static void parse_ace(struct cifs_ace * pace, char * end_of_acl) +static void parse_ace(struct cifs_ace *pace, char *end_of_acl) { int i; int num_subauth; @@ -50,27 +50,27 @@ static void parse_ace(struct cifs_ace * pace, char * end_of_acl) num_subauth = cpu_to_le32(pace->num_subauth); if (num_subauth) { psub_auth = (__u32 *)((char *)pace + sizeof(struct cifs_ace)); -#ifdef CONFIG_CIFS_DEBUG2 - cFYI(1, ("ACE revision %d num_subauth %d", - pace->revision, pace->num_subauth)); - for (i = 0; i < num_subauth; ++i) { - cFYI(1, ("ACE sub_auth[%d]: 0x%x", i, - le32_to_cpu(psub_auth[i]))); - } - - /* BB add length check to make sure that we do not have huge - num auths and therefore go off the end */ - - cFYI(1, ("RID %d", le32_to_cpu(psub_auth[num_subauth-1]))); -#endif - } - - return; -} - -static void parse_ntace(struct cifs_ntace * pntace, char * end_of_acl) -{ - /* validate that we do not go past end of acl */ +#ifdef CONFIG_CIFS_DEBUG2 + cFYI(1, ("ACE revision %d num_subauth %d", + pace->revision, pace->num_subauth)); + for (i = 0; i < num_subauth; ++i) { + cFYI(1, ("ACE sub_auth[%d]: 0x%x", i, + le32_to_cpu(psub_auth[i]))); + } + + /* BB add length check to make sure that we do not have huge + num auths and therefore go off the end */ + + cFYI(1, ("RID %d", le32_to_cpu(psub_auth[num_subauth-1]))); +#endif + } + + return; +} + +static void parse_ntace(struct cifs_ntace *pntace, char *end_of_acl) +{ + /* validate that we do not go past end of acl */ if (end_of_acl < (char *)pntace + sizeof(struct cifs_ntace)) { cERROR(1, ("ACL too small to parse NT ACE")); return; @@ -86,7 +86,7 @@ static void parse_ntace(struct cifs_ntace * pntace, char * end_of_acl) -static void parse_dacl(struct cifs_acl * pdacl, char * end_of_acl) +static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl) { int i; int num_aces = 0; @@ -118,11 +118,11 @@ static void parse_dacl(struct cifs_acl * pdacl, char * end_of_acl) ppace = kmalloc(num_aces * sizeof(struct cifs_ace *), GFP_KERNEL); -/* cifscred->cecount = pdacl->num_aces; - cifscred->ntaces = kmalloc(num_aces * - sizeof(struct cifs_ntace *), GFP_KERNEL); - cifscred->aces = kmalloc(num_aces * - sizeof(struct cifs_ace *), GFP_KERNEL);*/ +/* cifscred->cecount = pdacl->num_aces; + cifscred->ntaces = kmalloc(num_aces * + sizeof(struct cifs_ntace *), GFP_KERNEL); + cifscred->aces = kmalloc(num_aces * + sizeof(struct cifs_ace *), GFP_KERNEL);*/ for (i = 0; i < num_aces; ++i) { @@ -134,12 +134,12 @@ static void parse_dacl(struct cifs_acl * pdacl, char * end_of_acl) parse_ntace(ppntace[i], end_of_acl); parse_ace(ppace[i], end_of_acl); -/* memcpy((void *)(&(cifscred->ntaces[i])), - (void *)ppntace[i], - sizeof(struct cifs_ntace)); - memcpy((void *)(&(cifscred->aces[i])), - (void *)ppace[i], - sizeof(struct cifs_ace)); */ +/* memcpy((void *)(&(cifscred->ntaces[i])), + (void *)ppntace[i], + sizeof(struct cifs_ntace)); + memcpy((void *)(&(cifscred->aces[i])), + (void *)ppace[i], + sizeof(struct cifs_ace)); */ acl_base = (char *)ppntace[i]; acl_size = cpu_to_le32(ppntace[i]->size); @@ -176,12 +176,12 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl) for (i = 0; i < num_subauth; ++i) { cFYI(1, ("SID sub_auth[%d]: 0x%x ", i, - le32_to_cpu(psub_auth[i]))); + le32_to_cpu(psub_auth[i]))); } - /* BB add length check to make sure that we do not have huge + /* BB add length check to make sure that we do not have huge num auths and therefore go off the end */ - cFYI(1, ("RID 0x%x", + cFYI(1, ("RID 0x%x", le32_to_cpu(psid->sub_auth[psid->num_subauth]))); #endif } diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index f61e433d281..369e838bebd 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c @@ -261,21 +261,26 @@ ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); -/* else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { +#ifdef CONFIG_CIFS_EXPERIMENTAL + else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) { __u16 fid; int oplock = FALSE; - rc = CIFSSMBOpen(xid, pTcon, full_path, - FILE_OPEN, GENERIC_READ, 0, &fid, - &oplock, NULL, cifs_sb->local_nls, - cifs_sb->mnt_cifs_flags & - CIFS_MOUNT_MAP_SPECIAL_CHR); + if (experimEnabled) + rc = CIFSSMBOpen(xid, pTcon, full_path, + FILE_OPEN, GENERIC_READ, 0, &fid, + &oplock, NULL, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); + /* else rc is EOPNOTSUPP from above */ + if(rc == 0) { rc = CIFSSMBGetCIFSACL(xid, pTcon, fid, ea_value, buf_size, ACL_TYPE_ACCESS); CIFSSMBClose(xid, pTcon, fid); } - } */ /* BB enable after fixing up return data */ + } +#endif /* EXPERIMENTAL */ #else cFYI(1, ("query POSIX ACL not supported yet")); #endif /* CONFIG_CIFS_POSIX */ -- cgit v1.2.3 From a013689ddb2a4ba5f0452c053c0bf00bafb686f1 Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 4 Oct 2007 20:05:09 +0000 Subject: [CIFS] Fix cifsd so shuts down when signing fails during mount Fixes two problems: 1) we dropped down to negotiating lanman if we did not recognize the mechanism (krb5 e.g.) 2) we did not stop cifsd (thus will fail when doing rmod cifs with slab free errors) when we fail tcon but have a bad session (which is the case in which signing is required but we don't allow signing on the client) It also turns on extended security flag in the header when passing "sec=krb5" on mount command (although kerberos support is not done of course) Acked-by: Jeff Layton CC: Shaggy Signed-off-by: Steve French --- fs/cifs/cifs_debug.c | 11 ++++++++--- fs/cifs/cifsglob.h | 4 +++- fs/cifs/cifssmb.c | 23 ++++++++++++++++++++--- fs/cifs/connect.c | 12 +++++++++++- 4 files changed, 42 insertions(+), 8 deletions(-) diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 56c5d9126f5..73c4c419663 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -879,11 +879,16 @@ security_flags_write(struct file *file, const char __user *buffer, if (count < 3) { /* single char or single char followed by null */ c = flags_string[0]; - if (c == '0' || c == 'n' || c == 'N') + if (c == '0' || c == 'n' || c == 'N') { extended_security = CIFSSEC_DEF; /* default */ - else if (c == '1' || c == 'y' || c == 'Y') + return count; + } else if (c == '1' || c == 'y' || c == 'Y') { extended_security = CIFSSEC_MAX; - return count; + return count; + } else if (!isdigit(c)) { + cERROR(1, ("invalid flag %c", c)); + return -EINVAL; + } } /* else we have a number */ diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 3fb046be9c0..fbde55c569f 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -90,7 +90,8 @@ enum statusEnum { }; enum securityEnum { - LANMAN = 0, /* Legacy LANMAN auth */ + PLAINTXT = 0, /* Legacy with Plaintext passwords */ + LANMAN, /* Legacy LANMAN auth */ NTLM, /* Legacy NTLM012 auth with NTLM hash */ NTLMv2, /* Legacy NTLM auth with NTLMv2 hash */ RawNTLMSSP, /* NTLMSSP without SPNEGO */ @@ -499,6 +500,7 @@ require use of the stronger protocol */ #define CIFSSEC_DEF CIFSSEC_MAY_SIGN | CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 #define CIFSSEC_MAX CIFSSEC_MUST_SIGN | CIFSSEC_MUST_NTLMV2 +#define CIFSSEC_AUTH_MASK (CIFSSEC_MAY_NTLM | CIFSSEC_MAY_NTLMV2 | CIFSSEC_MAY_LANMAN | CIFSSEC_MAY_PLNTXT | CIFSSEC_MAY_KRB5) /* ***************************************************************** * All constants go here diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 90b8f8d64d6..fda8b249026 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -438,8 +438,13 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) pSMB->hdr.Mid = GetNextMid(server); pSMB->hdr.Flags2 |= (SMBFLG2_UNICODE | SMBFLG2_ERR_STATUS); + if ((secFlags & CIFSSEC_MUST_KRB5) == CIFSSEC_MUST_KRB5) pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; + else if ((secFlags & CIFSSEC_AUTH_MASK) == CIFSSEC_MAY_KRB5) { + cFYI(1, ("Kerberos only mechanism, enable extended security")); + pSMB->hdr.Flags2 |= SMBFLG2_EXT_SEC; + } count = 0; for (i = 0; i < CIFS_NUM_PROT; i++) { @@ -573,7 +578,20 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) server->secType = NTLM; else if (secFlags & CIFSSEC_MAY_NTLMV2) server->secType = NTLMv2; - /* else krb5 ... any others ... */ + else if (secFlags & CIFSSEC_MAY_KRB5) + server->secType = Kerberos; + else if (secFlags & CIFSSEC_MAY_LANMAN) + server->secType = LANMAN; +/* #ifdef CONFIG_CIFS_EXPERIMENTAL + else if (secFlags & CIFSSEC_MAY_PLNTXT) + server->secType = ?? +#endif */ + else { + rc = -EOPNOTSUPP; + cERROR(1, ("Invalid security type")); + goto neg_err_exit; + } + /* else ... any others ...? */ /* one byte, so no need to convert this or EncryptionKeyLen from little endian */ @@ -3089,8 +3107,7 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, goto qsec_out; pSMBr = (struct smb_com_ntransact_rsp *)iov[0].iov_base; - cERROR(1, ("smb %p parm %p data %p", - pSMBr, parm, psec_desc)); /* BB removeme BB */ + cFYI(1, ("smb %p parm %p data %p", pSMBr, parm, psec_desc)); if (le32_to_cpu(pSMBr->ParameterCount) != 4) { rc = -EIO; /* bad smb */ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index fc3a851357f..c0cd3ce56e9 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2172,8 +2172,18 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, if (tsk) kthread_stop(tsk); } - } else + } else { cFYI(1, ("No session or bad tcon")); + if ((pSesInfo->server) && + (pSesInfo->server->tsk)) { + struct task_struct *tsk; + force_sig(SIGKILL, + pSesInfo->server->tsk); + tsk = pSesInfo->server->tsk; + if (tsk) + kthread_stop(tsk); + } + } sesInfoFree(pSesInfo); /* pSesInfo = NULL; */ } -- cgit v1.2.3 From 297647c21f11dc1449f9bdb1601ae43e951bba0b Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 12 Oct 2007 04:11:59 +0000 Subject: [CIFS] CIFS ACL support part 3 Signed-off-by: Shirish Pargaonkar Signed-off-by: Steve French --- fs/cifs/CHANGES | 5 ++- fs/cifs/cifsacl.c | 120 +++++++++++++++++++++++++++++++++++++++++++++++++----- fs/cifs/cifsacl.h | 24 ++++++++--- fs/cifs/cifsfs.c | 4 -- fs/cifs/cifsfs.h | 7 +++- fs/cifs/cifssmb.c | 2 + fs/cifs/export.c | 1 + 7 files changed, 141 insertions(+), 22 deletions(-) diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index c8ad87de4a7..13071faf8af 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -6,7 +6,10 @@ which support the current POSIX Extensions to provide better semantics (e.g. delete for open files opened with posix open). Take into account umask on posix mkdir not just older style mkdir. Add ability to mount to IPC$ share (which allows CIFS named pipes to be -opened, read and written as if they were files). +opened, read and written as if they were files). When 1st tree +connect fails (e.g. due to signing negotiation failure) fix +leak that causes cifsd not to stop and rmmod to fail to cleanup +cifs_request_buffers pool. Version 1.50 ------------ diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 52f9cb808fd..43ab26fff39 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -28,6 +28,20 @@ #include "cifsproto.h" #include "cifs_debug.h" + +#ifdef CONFIG_CIFS_EXPERIMENTAL + +struct cifs_wksid wksidarr[NUM_WK_SIDS] = { + {{1, 0, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0} }, "null user"}, + {{1, 1, {0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0} }, "nobody"}, + {{1, 1, {0, 0, 0, 0, 0, 5}, {11, 0, 0, 0, 0} }, "net-users"}, + {{1, 1, {0, 0, 0, 0, 0, 5}, {18, 0, 0, 0, 0} }, "sys"}, + {{1, 2, {0, 0, 0, 0, 0, 5}, {32, 544, 0, 0, 0} }, "root"}, + {{1, 2, {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0, 0} }, "users"}, + {{1, 2, {0, 0, 0, 0, 0, 5}, {32, 546, 0, 0, 0} }, "guest"} +}; + + /* security id for everyone */ static const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {} }; @@ -35,33 +49,113 @@ static const struct cifs_sid sid_everyone = static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} }; + +int match_sid(struct cifs_sid *ctsid) +{ + int i, j; + int num_subauth, num_sat, num_saw; + struct cifs_sid *cwsid; + + if (!ctsid) + return (-1); + + for (i = 0; i < NUM_WK_SIDS; ++i) { + cwsid = &(wksidarr[i].cifssid); + + /* compare the revision */ + if (ctsid->revision != cwsid->revision) + continue; + + /* compare all of the six auth values */ + for (j = 0; j < 6; ++j) { + if (ctsid->authority[j] != cwsid->authority[j]) + break; + } + if (j < 6) + continue; /* all of the auth values did not match */ + + /* compare all of the subauth values if any */ + num_sat = cpu_to_le32(ctsid->num_subauth); + num_saw = cpu_to_le32(cwsid->num_subauth); + num_subauth = num_sat < num_saw ? num_sat : num_saw; + if (num_subauth) { + for (j = 0; j < num_subauth; ++j) { + if (ctsid->sub_auth[j] != cwsid->sub_auth[j]) + break; + } + if (j < num_subauth) + continue; /* all sub_auth values do not match */ + } + + cFYI(1, ("matching sid: %s\n", wksidarr[i].sidname)); + return (0); /* sids compare/match */ + } + + cFYI(1, ("No matching sid")); + return (-1); +} + + +int compare_sids(struct cifs_sid *ctsid, struct cifs_sid *cwsid) +{ + int i; + int num_subauth, num_sat, num_saw; + + if ((!ctsid) || (!cwsid)) + return (-1); + + /* compare the revision */ + if (ctsid->revision != cwsid->revision) + return (-1); + + /* compare all of the six auth values */ + for (i = 0; i < 6; ++i) { + if (ctsid->authority[i] != cwsid->authority[i]) + return (-1); + } + + /* compare all of the subauth values if any */ + num_sat = cpu_to_le32(ctsid->num_subauth); + num_saw = cpu_to_le32(cwsid->num_subauth); + num_subauth = num_sat < num_saw ? num_sat : num_saw; + if (num_subauth) { + for (i = 0; i < num_subauth; ++i) { + if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) + return (-1); + } + } + + return (0); /* sids compare/match */ +} + + static void parse_ace(struct cifs_ace *pace, char *end_of_acl) { int i; int num_subauth; - __u32 *psub_auth; /* validate that we do not go past end of acl */ + + /* XXX this if statement can be removed if (end_of_acl < (char *)pace + sizeof(struct cifs_ace)) { cERROR(1, ("ACL too small to parse ACE")); return; - } + } */ num_subauth = cpu_to_le32(pace->num_subauth); if (num_subauth) { - psub_auth = (__u32 *)((char *)pace + sizeof(struct cifs_ace)); #ifdef CONFIG_CIFS_DEBUG2 cFYI(1, ("ACE revision %d num_subauth %d", pace->revision, pace->num_subauth)); for (i = 0; i < num_subauth; ++i) { cFYI(1, ("ACE sub_auth[%d]: 0x%x", i, - le32_to_cpu(psub_auth[i]))); + le32_to_cpu(pace->sub_auth[i]))); } /* BB add length check to make sure that we do not have huge num auths and therefore go off the end */ - cFYI(1, ("RID %d", le32_to_cpu(psub_auth[num_subauth-1]))); + cFYI(1, ("RID %d", le32_to_cpu(pace->sub_auth[num_subauth-1]))); #endif } @@ -132,7 +226,13 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl) sizeof(struct cifs_ntace)); parse_ntace(ppntace[i], end_of_acl); - parse_ace(ppace[i], end_of_acl); + if (end_of_acl < ((char *)ppace[i] + + (ppntace[i]->size - + sizeof(struct cifs_ntace)))) { + cERROR(1, ("ACL too small to parse ACE")); + break; + } else + parse_ace(ppace[i], end_of_acl); /* memcpy((void *)(&(cifscred->ntaces[i])), (void *)ppntace[i], @@ -157,7 +257,6 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl) { int i; int num_subauth; - __u32 *psub_auth; /* BB need to add parm so we can store the SID BB */ @@ -169,20 +268,19 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl) num_subauth = cpu_to_le32(psid->num_subauth); if (num_subauth) { - psub_auth = (__u32 *)((char *)psid + sizeof(struct cifs_sid)); #ifdef CONFIG_CIFS_DEBUG2 cFYI(1, ("SID revision %d num_auth %d First subauth 0x%x", psid->revision, psid->num_subauth, psid->sub_auth[0])); for (i = 0; i < num_subauth; ++i) { cFYI(1, ("SID sub_auth[%d]: 0x%x ", i, - le32_to_cpu(psub_auth[i]))); + le32_to_cpu(psid->sub_auth[i]))); } /* BB add length check to make sure that we do not have huge num auths and therefore go off the end */ cFYI(1, ("RID 0x%x", - le32_to_cpu(psid->sub_auth[psid->num_subauth]))); + le32_to_cpu(psid->sub_auth[num_subauth-1]))); #endif } @@ -228,5 +326,7 @@ int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len) memcpy((void *)(&(cifscred->gsid)), (void *)group_sid_ptr, sizeof (struct cifs_sid)); */ + return (0); } +#endif /* CONFIG_CIFS_EXPERIMENTAL */ diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h index bf297ea1905..1b115641b72 100644 --- a/fs/cifs/cifsacl.h +++ b/fs/cifs/cifsacl.h @@ -22,6 +22,10 @@ #ifndef _CIFSACL_H #define _CIFSACL_H + +#define NUM_WK_SIDS 7 /* number of well known sids */ +#define SIDNAMELENGTH 20 /* long enough for the ones we care about */ + struct cifs_ntsd { __u16 revision; /* revision level */ __u16 type; @@ -35,7 +39,7 @@ struct cifs_sid { __u8 revision; /* revision level */ __u8 num_subauth; __u8 authority[6]; - __u32 sub_auth[0]; /* sub_auth[num_subauth] */ + __u32 sub_auth[5]; /* sub_auth[num_subauth] */ } __attribute__((packed)); struct cifs_acl { @@ -55,12 +59,20 @@ struct cifs_ace { /* last part of ACE which includes user info */ __u8 revision; /* revision level */ __u8 num_subauth; __u8 authority[6]; - __u32 sub_auth[0]; + __u32 sub_auth[5]; +} __attribute__((packed)); + +struct cifs_wksid { + struct cifs_sid cifssid; + char sidname[SIDNAMELENGTH]; } __attribute__((packed)); -/* everyone */ -/* extern const struct cifs_sid sid_everyone;*/ -/* group users */ -/* extern const struct cifs_sid sid_user;*/ +#ifdef CONFIG_CIFS_EXPERIMENTAL + +extern struct cifs_wksid wksidarr[NUM_WK_SIDS]; +extern int match_sid(struct cifs_sid *); +extern int compare_sids(struct cifs_sid *, struct cifs_sid *); + +#endif /* CONFIG_CIFS_EXPERIMENTAL */ #endif /* _CIFSACL_H */ diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index c7c3521aa7c..abca6b084ed 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -49,10 +49,6 @@ static struct quotactl_ops cifs_quotactl_ops; #endif /* QUOTA */ -#ifdef CONFIG_CIFS_EXPERIMENTAL -extern struct export_operations cifs_export_ops; -#endif /* EXPERIMENTAL */ - int cifsFYI = 0; int cifsERROR = 1; int traceSMB = 0; diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 13c53a4ee0f..0a3ee5a322b 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -1,7 +1,7 @@ /* * fs/cifs/cifsfs.h * - * Copyright (c) International Business Machines Corp., 2002, 2005 + * Copyright (c) International Business Machines Corp., 2002, 2007 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -101,5 +101,10 @@ 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); + +#ifdef CONFIG_CIFS_EXPERIMENTAL +extern struct export_operations cifs_export_ops; +#endif /* EXPERIMENTAL */ + #define CIFS_VERSION "1.51" #endif /* _CIFSFS_H */ diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index fda8b249026..eff3226b210 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -3058,6 +3058,7 @@ GetExtAttrOut: #endif /* CONFIG_POSIX */ +#ifdef CONFIG_CIFS_EXPERIMENTAL /* Get Security Descriptor (by handle) from remote server for a file or dir */ int CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, @@ -3129,6 +3130,7 @@ qsec_out: /* cifs_small_buf_release(pSMB); */ /* Freed earlier now in SendReceive2 */ return rc; } +#endif /* CONFIG_CIFS_EXPERIMENTAL */ /* Legacy Query Path Information call for lookup to old servers such as Win9x/WinME */ diff --git a/fs/cifs/export.c b/fs/cifs/export.c index 893fd0aebff..d614b91caec 100644 --- a/fs/cifs/export.c +++ b/fs/cifs/export.c @@ -43,6 +43,7 @@ #include #include "cifsglob.h" #include "cifs_debug.h" +#include "cifsfs.h" #ifdef CONFIG_CIFS_EXPERIMENTAL static struct dentry *cifs_get_parent(struct dentry *dentry) -- cgit v1.2.3 From 8f18c1316b71df76bb7076c392134864a18636c1 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 12 Oct 2007 18:54:12 +0000 Subject: [CIFS] remove compile warnings when debug disabled Signed-off-by: Steve French --- fs/cifs/cifsacl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 43ab26fff39..601587724f9 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -131,7 +131,6 @@ int compare_sids(struct cifs_sid *ctsid, struct cifs_sid *cwsid) static void parse_ace(struct cifs_ace *pace, char *end_of_acl) { - int i; int num_subauth; /* validate that we do not go past end of acl */ @@ -145,6 +144,7 @@ static void parse_ace(struct cifs_ace *pace, char *end_of_acl) num_subauth = cpu_to_le32(pace->num_subauth); if (num_subauth) { #ifdef CONFIG_CIFS_DEBUG2 + int i; cFYI(1, ("ACE revision %d num_subauth %d", pace->revision, pace->num_subauth)); for (i = 0; i < num_subauth; ++i) { @@ -255,7 +255,6 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl) static int parse_sid(struct cifs_sid *psid, char *end_of_acl) { - int i; int num_subauth; /* BB need to add parm so we can store the SID BB */ @@ -269,6 +268,7 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl) num_subauth = cpu_to_le32(psid->num_subauth); if (num_subauth) { #ifdef CONFIG_CIFS_DEBUG2 + int i; cFYI(1, ("SID revision %d num_auth %d First subauth 0x%x", psid->revision, psid->num_subauth, psid->sub_auth[0])); -- cgit v1.2.3 From 2c2130e16f0e134aa65515fd0c2436fda465b1b6 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 12 Oct 2007 19:10:28 +0000 Subject: [CIFS] remove two sparse warnings Signed-off-by: Cyrill Gorcunov Signed-off-by: Steve French --- fs/cifs/file.c | 4 ++-- fs/cifs/readdir.c | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/fs/cifs/file.c b/fs/cifs/file.c index 780c0e3e470..1e7e4c06d9e 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -1755,7 +1755,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, struct page *page; struct cifs_sb_info *cifs_sb; struct cifsTconInfo *pTcon; - int bytes_read = 0; + unsigned int bytes_read = 0; unsigned int read_size, i; char *smb_read_data = NULL; struct smb_com_read_rsp *pSMBr; @@ -1849,7 +1849,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, i += bytes_read >> PAGE_CACHE_SHIFT; cifs_stats_bytes_read(pTcon, bytes_read); - if ((int)(bytes_read & PAGE_CACHE_MASK) != bytes_read) { + if ((bytes_read & PAGE_CACHE_MASK) != bytes_read) { i++; /* account for partial page */ /* server copy of file can have smaller size diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index b5a9bfff5e5..3746580e970 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -121,7 +121,7 @@ static void AdjustForTZ(struct cifsTconInfo *tcon, struct inode *inode) static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, - char *buf, int *pobject_type, int isNewInode) + char *buf, unsigned int *pobject_type, int isNewInode) { loff_t local_size; struct timespec local_mtime; @@ -294,7 +294,7 @@ static void fill_in_inode(struct inode *tmp_inode, int new_buf_type, } static void unix_fill_in_inode(struct inode *tmp_inode, - FILE_UNIX_INFO *pfindData, int *pobject_type, int isNewInode) + FILE_UNIX_INFO *pfindData, unsigned int *pobject_type, int isNewInode) { loff_t local_size; struct timespec local_mtime; @@ -826,7 +826,7 @@ static int cifs_filldir(char *pfindEntry, struct file *file, int rc = 0; struct qstr qstring; struct cifsFileInfo *pCifsF; - unsigned obj_type; + unsigned int obj_type; ino_t inum; struct cifs_sb_info *cifs_sb; struct inode *tmp_inode; -- cgit v1.2.3 From 516897a208bc1423d561ce2ccce0624c3b652275 Mon Sep 17 00:00:00 2001 From: Steve French Date: Fri, 12 Oct 2007 19:24:06 +0000 Subject: [CIFS] fix build break when lanman not enabled Signed-off-by: Andrew Morton Signed-off-by: Steve French --- fs/cifs/cifsglob.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index fbde55c569f..61d617370e5 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -479,6 +479,9 @@ struct dir_notify_req { #ifdef CONFIG_CIFS_WEAK_PW_HASH #define CIFSSEC_MAY_LANMAN 0x00010 #define CIFSSEC_MAY_PLNTXT 0x00020 +#else +#define CIFSSEC_MAY_LANMAN 0 +#define CIFSSEC_MAY_PLNTXT 0 #endif /* weak passwords */ #define CIFSSEC_MAY_SEAL 0x00040 /* not supported yet */ -- cgit v1.2.3 From 8f2376adfb57d95973b64ecdf016937f436b9bf0 Mon Sep 17 00:00:00 2001 From: Cyril Gorcunov Date: Sun, 14 Oct 2007 17:58:43 +0000 Subject: [CIFS] Fix endian conversion problem in posix mkdir Signed-off-by: Cyrill Gorcunov Signed-off-by: Steve French --- fs/cifs/CHANGES | 3 ++- fs/cifs/cifsacl.h | 4 ++-- fs/cifs/cifsencrypt.c | 5 +++-- fs/cifs/cifssmb.c | 8 ++++---- fs/cifs/inode.c | 3 ++- 5 files changed, 13 insertions(+), 10 deletions(-) diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 13071faf8af..70c90c07edf 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -9,7 +9,8 @@ ability to mount to IPC$ share (which allows CIFS named pipes to be opened, read and written as if they were files). When 1st tree connect fails (e.g. due to signing negotiation failure) fix leak that causes cifsd not to stop and rmmod to fail to cleanup -cifs_request_buffers pool. +cifs_request_buffers pool. Fix problem with POSIX Open/Mkdir on +bigendian architectures. Version 1.50 ------------ diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h index 1b115641b72..0362cd11f03 100644 --- a/fs/cifs/cifsacl.h +++ b/fs/cifs/cifsacl.h @@ -51,8 +51,8 @@ struct cifs_acl { struct cifs_ntace { /* first part of ACE which contains perms */ __u8 type; __u8 flags; - __u16 size; - __u32 access_req; + __le16 size; + __le32 access_req; } __attribute__((packed)); struct cifs_ace { /* last part of ACE which includes user info */ diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 36272293027..632070b4275 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -345,7 +345,7 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses, user = kmalloc(2 + (len * 2), GFP_KERNEL); if (user == NULL) goto calc_exit_2; - len = cifs_strtoUCS(user, ses->userName, len, nls_cp); + len = cifs_strtoUCS((__le16 *)user, ses->userName, len, nls_cp); UniStrupr(user); hmac_md5_update((char *)user, 2*len, pctxt); @@ -356,7 +356,8 @@ static int calc_ntlmv2_hash(struct cifsSesInfo *ses, domain = kmalloc(2 + (len * 2), GFP_KERNEL); if (domain == NULL) goto calc_exit_1; - len = cifs_strtoUCS(domain, ses->domainName, len, nls_cp); + len = cifs_strtoUCS((__le16 *)domain, ses->domainName, len, + nls_cp); /* the following line was removed since it didn't work well with lower cased domain name that passed as an option. Maybe converting the domain name earlier makes sense */ diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index eff3226b210..b17983633a1 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1069,7 +1069,7 @@ PsxCreat: InformationLevel) - 4; offset = param_offset + params; pdata = (OPEN_PSX_REQ *)(((char *)&pSMB->hdr.Protocol) + offset); - pdata->Level = SMB_QUERY_FILE_UNIX_BASIC; + pdata->Level = cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC); pdata->Permissions = cpu_to_le64(mode); pdata->PosixOpenFlags = cpu_to_le32(posix_flags); pdata->OpenFlags = cpu_to_le32(*pOplock); @@ -1115,8 +1115,8 @@ PsxCreat: if (cpu_to_le32(FILE_CREATE) == psx_rsp->CreateAction) *pOplock |= CIFS_CREATE_ACTION; /* check to make sure response data is there */ - if (psx_rsp->ReturnedLevel != SMB_QUERY_FILE_UNIX_BASIC) { - pRetData->Type = -1; /* unknown */ + if (psx_rsp->ReturnedLevel != cpu_to_le16(SMB_QUERY_FILE_UNIX_BASIC)) { + pRetData->Type = cpu_to_le32(-1); /* unknown */ #ifdef CONFIG_CIFS_DEBUG2 cFYI(1, ("unknown type")); #endif @@ -1124,7 +1124,7 @@ PsxCreat: if (pSMBr->ByteCount < sizeof(OPEN_PSX_RSP) + sizeof(FILE_UNIX_BASIC_INFO)) { cERROR(1, ("Open response data too small")); - pRetData->Type = -1; + pRetData->Type = cpu_to_le32(-1); goto psx_create_err; } memcpy((char *) pRetData, diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index ece17ca00d0..cc119b278e5 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -947,7 +947,8 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) d_drop(direntry); } else { int obj_type; - if (pInfo->Type == -1) /* no return info - go query */ { + if (pInfo->Type == cpu_to_le32(-1)) { + /* no return info, go query for it */ kfree(pInfo); goto mkdir_get_info; } -- cgit v1.2.3 From 7111d2144f17155b66e89b3655fcddbedefcf8a6 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 16 Oct 2007 16:50:25 +0000 Subject: [CIFS] [CIFS] fix error message about packet signing When packet signing is disabled and the server requires it, cifs prints an error message. The current message refers to a file in /proc that no longer exists. Fix it to refer to the correct file. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifssmb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index b17983633a1..9eef7249250 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -661,8 +661,8 @@ signing_check: cFYI(1, ("Signing disabled")); if (server->secMode & SECMODE_SIGN_REQUIRED) cERROR(1, ("Server requires " - "/proc/fs/cifs/PacketSigningEnabled " - "to be on")); + "packet signing to be enabled in " + "/proc/fs/cifs/SecurityFlags.")); server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) { -- cgit v1.2.3 From e187e44eb8902089da0c7725d606b0e20fee981d Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 16 Oct 2007 17:10:44 +0000 Subject: [CIFS] parse server_GUID in SPNEGO negProt response SPNEGO NegProt response also contains a server_GUID. Parse it as we would for RawNTLMSSP. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifssmb.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 9eef7249250..14dabbbd813 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -621,22 +621,26 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) if ((pSMBr->hdr.Flags2 & SMBFLG2_EXT_SEC) && (server->capabilities & CAP_EXTENDED_SECURITY)) { count = pSMBr->ByteCount; - if (count < 16) + 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 + goto neg_err_exit; + } + + 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); + pSMBr->u.extended_response.GUID, + 16); + } + } else + memcpy(server->server_GUID, + pSMBr->u.extended_response.GUID, 16); + + if (count == 16) { + server->secType = RawNTLMSSP; } else { rc = decode_negTokenInit(pSMBr->u.extended_response. SecurityBlob, -- cgit v1.2.3 From 0d3a01fadacef5901005dc8f61688a8f0471dc79 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 16 Oct 2007 17:32:19 +0000 Subject: [CIFS] Break up unicode_sessetup string functions SPNEGO setup needs only some of these strings. Break up unicode_ssetup_strings so we can call them individually. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsglob.h | 8 +++++- fs/cifs/sess.c | 73 +++++++++++++++++++++++++++++++++++------------------- 2 files changed, 55 insertions(+), 26 deletions(-) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 61d617370e5..9b7762c754c 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -495,9 +495,15 @@ require use of the stronger protocol */ #ifdef CONFIG_CIFS_WEAK_PW_HASH #define CIFSSEC_MUST_LANMAN 0x10010 #define CIFSSEC_MUST_PLNTXT 0x20020 +#ifdef CONFIG_CIFS_UPCALL +#define CIFSSEC_MASK 0x3F03F /* allows weak security but also krb5 */ +#else #define CIFSSEC_MASK 0x37037 /* current flags supported if weak */ +#else /* do not allow weak pw hash */ +#ifdef CONFIG_CIFS_UPCALL +#define CIFSSEC_MASK 0x0F00F /* flags supported if no weak allowed */ #else -#define CIFSSEC_MASK 0x07007 /* flags supported if no weak config */ +#define CIFSSEC_MASK 0x07007 /* flags supported if no weak allowed */ #endif /* WEAK_PW_HASH */ #define CIFSSEC_MUST_SEAL 0x40040 /* not supported yet */ diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 78797c0e076..c74a064e782 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -74,6 +74,52 @@ static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) return capabilities; } +static void +unicode_oslm_strings(char **pbcc_area, const struct nls_table *nls_cp) +{ + char *bcc_ptr = *pbcc_area; + int bytes_ret = 0; + + /* 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, init_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; +} + +static void unicode_domain_string(char **pbcc_area, struct cifsSesInfo *ses, + const struct nls_table *nls_cp) +{ + char *bcc_ptr = *pbcc_area; + int bytes_ret = 0; + + /* copy domain */ + if (ses->domainName == NULL) { + /* Sending null domain better than using a bogus domain name (as + we did briefly in 2.6.18) since server will use its default */ + *bcc_ptr = 0; + *(bcc_ptr+1) = 0; + bytes_ret = 0; + } 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 */ + + *pbcc_area = bcc_ptr; +} + + static void unicode_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses, const struct nls_table *nls_cp) { @@ -99,32 +145,9 @@ static void unicode_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses, } bcc_ptr += 2 * bytes_ret; bcc_ptr += 2; /* account for null termination */ - /* copy domain */ - if (ses->domainName == NULL) { - /* Sending null domain better than using a bogus domain name (as - we did briefly in 2.6.18) since server will use its default */ - *bcc_ptr = 0; - *(bcc_ptr+1) = 0; - bytes_ret = 0; - } 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, init_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 */ + unicode_domain_string(&bcc_ptr, ses, nls_cp); + unicode_oslm_strings(&bcc_ptr, nls_cp); *pbcc_area = bcc_ptr; } -- cgit v1.2.3 From 6345a3a88012b0060ddeca8874e51cb442e1fb20 Mon Sep 17 00:00:00 2001 From: Cyrill Gorcunov Date: Tue, 16 Oct 2007 17:57:55 +0000 Subject: [CIFS] formatting fixes Signed-off-by: Cyrill Gorcunov Signed-off-by: Steve French --- fs/cifs/connect.c | 57 +++++++++++++++++++++++++------------------------------ 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index c0cd3ce56e9..494455ed435 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -1468,7 +1468,7 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, if (psin_server->sin_port) { /* user overrode default port */ rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) psin_server, - sizeof (struct sockaddr_in), 0); + sizeof(struct sockaddr_in), 0); if (rc >= 0) connected = 1; } @@ -1484,7 +1484,7 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) psin_server, - sizeof (struct sockaddr_in), 0); + sizeof(struct sockaddr_in), 0); if (rc >= 0) connected = 1; } @@ -1493,7 +1493,7 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, psin_server->sin_port = htons(RFC1001_PORT); rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) psin_server, - sizeof (struct sockaddr_in), 0); + sizeof(struct sockaddr_in), 0); if (rc >= 0) connected = 1; } @@ -1601,7 +1601,7 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket) if (psin_server->sin6_port) { /* user overrode default port */ rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) psin_server, - sizeof (struct sockaddr_in6), 0); + sizeof(struct sockaddr_in6), 0); if (rc >= 0) connected = 1; } @@ -1617,7 +1617,7 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket) rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) psin_server, - sizeof (struct sockaddr_in6), 0); + sizeof(struct sockaddr_in6), 0); if (rc >= 0) connected = 1; } @@ -1625,7 +1625,7 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket) if (!connected) { psin_server->sin6_port = htons(RFC1001_PORT); rc = (*csocket)->ops->connect(*csocket, (struct sockaddr *) - psin_server, sizeof (struct sockaddr_in6), 0); + psin_server, sizeof(struct sockaddr_in6), 0); if (rc >= 0) connected = 1; } @@ -1920,7 +1920,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, return rc; } else { memcpy(&srvTcp->addr.sockAddr, &sin_server, - sizeof (struct sockaddr_in)); + sizeof(struct sockaddr_in)); atomic_set(&srvTcp->inFlight, 0); /* BB Add code for ipv6 case too */ srvTcp->ssocket = csocket; @@ -2557,7 +2557,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, int remaining_words = 0; int bytes_returned = 0; int len; - int SecurityBlobLength = sizeof (NEGOTIATE_MESSAGE); + int SecurityBlobLength = sizeof(NEGOTIATE_MESSAGE); PNEGOTIATE_MESSAGE SecurityBlob; PCHALLENGE_MESSAGE SecurityBlob2; __u32 negotiate_flags, capabilities; @@ -2881,8 +2881,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, } static int CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, - char *ntlm_session_key, int ntlmv2_flag, - const struct nls_table *nls_codepage) + char *ntlm_session_key, int ntlmv2_flag, + const struct nls_table *nls_codepage) { struct smb_hdr *smb_buffer; struct smb_hdr *smb_buffer_response; @@ -2895,7 +2895,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, int remaining_words = 0; int bytes_returned = 0; int len; - int SecurityBlobLength = sizeof (AUTHENTICATE_MESSAGE); + int SecurityBlobLength = sizeof(AUTHENTICATE_MESSAGE); PAUTHENTICATE_MESSAGE SecurityBlob; __u32 negotiate_flags, capabilities; __u16 count; @@ -2910,8 +2910,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, return -ENOMEM; } smb_buffer_response = smb_buffer; - pSMB = (SESSION_SETUP_ANDX *) smb_buffer; - pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response; + pSMB = (SESSION_SETUP_ANDX *)smb_buffer; + pSMBr = (SESSION_SETUP_ANDX *)smb_buffer_response; /* send SMBsessionSetup here */ header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, @@ -2930,7 +2930,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | - CAP_EXTENDED_SECURITY; + CAP_EXTENDED_SECURITY; if (ses->capabilities & CAP_UNICODE) { smb_buffer->Flags2 |= SMBFLG2_UNICODE; capabilities |= CAP_UNICODE; @@ -2945,15 +2945,14 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, } pSMB->req.Capabilities = cpu_to_le32(capabilities); - bcc_ptr = (char *) &pSMB->req.SecurityBlob; - SecurityBlob = (PAUTHENTICATE_MESSAGE) bcc_ptr; + bcc_ptr = (char *)&pSMB->req.SecurityBlob; + SecurityBlob = (PAUTHENTICATE_MESSAGE)bcc_ptr; strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8); SecurityBlob->MessageType = NtLmAuthenticate; bcc_ptr += SecurityBlobLength; - negotiate_flags = - NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET | - NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO | - 0x80000000 | NTLMSSP_NEGOTIATE_128; + negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET | + NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO | + 0x80000000 | NTLMSSP_NEGOTIATE_128; if (sign_CIFS_PDUs) negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN; if (ntlmv2_flag) @@ -3104,12 +3103,11 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, 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)) { +/* 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); + __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); if (action & GUEST_LOGIN) cFYI(1, (" Guest login")); /* BB Should we set anything in SesInfo struct ? */ @@ -3263,22 +3261,19 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr[0] = 0; bcc_ptr++; } else - cFYI(1, - ("field of length %d " + cFYI(1, ("field of length %d " "extends beyond end of smb ", len)); } } else { - cERROR(1, - (" Security Blob extends beyond end " + cERROR(1, ("Security Blob extends beyond end " "of SMB")); } } else { cERROR(1, ("No session structure passed in.")); } } else { - cERROR(1, - (" Invalid Word count %d: ", + cERROR(1, ("Invalid Word count %d: ", smb_buffer_response->WordCount)); rc = -EIO; } -- cgit v1.2.3 From 016ec75f1a0c0e765fce65d794569979104f031d Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 16 Oct 2007 18:10:10 +0000 Subject: [CIFS] missing #endif from a previous patch Signed-off-by: Steve French --- fs/cifs/cifsglob.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 9b7762c754c..87f51f23276 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -499,11 +499,13 @@ require use of the stronger protocol */ #define CIFSSEC_MASK 0x3F03F /* allows weak security but also krb5 */ #else #define CIFSSEC_MASK 0x37037 /* current flags supported if weak */ +#endif /* UPCALL */ #else /* do not allow weak pw hash */ #ifdef CONFIG_CIFS_UPCALL #define CIFSSEC_MASK 0x0F00F /* flags supported if no weak allowed */ #else #define CIFSSEC_MASK 0x07007 /* flags supported if no weak allowed */ +#endif /* UPCALL */ #endif /* WEAK_PW_HASH */ #define CIFSSEC_MUST_SEAL 0x40040 /* not supported yet */ -- cgit v1.2.3 From af6f4612fdfd782c6d35272836a2b97e7e5b790e Mon Sep 17 00:00:00 2001 From: Steve French Date: Tue, 16 Oct 2007 18:40:37 +0000 Subject: [CIFS] Fix some endianness problems in new acl code Signed-off-by: Steve French --- fs/cifs/cifsacl.c | 28 ++++++++++++++-------------- fs/cifs/cifsacl.h | 23 +++++++++++------------ fs/cifs/cifssmb.c | 2 +- 3 files changed, 26 insertions(+), 27 deletions(-) diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 601587724f9..4735e9b4759 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -31,7 +31,7 @@ #ifdef CONFIG_CIFS_EXPERIMENTAL -struct cifs_wksid wksidarr[NUM_WK_SIDS] = { +static struct cifs_wksid wksidarr[NUM_WK_SIDS] = { {{1, 0, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0} }, "null user"}, {{1, 1, {0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0} }, "nobody"}, {{1, 1, {0, 0, 0, 0, 0, 5}, {11, 0, 0, 0, 0} }, "net-users"}, @@ -192,14 +192,15 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl) /* BB need to add parm so we can store the SID BB */ /* validate that we do not go past end of acl */ - if (end_of_acl < (char *)pdacl + pdacl->size) { + if (end_of_acl < (char *)pdacl + le16_to_cpu(pdacl->size)) { cERROR(1, ("ACL too small to parse DACL")); return; } #ifdef CONFIG_CIFS_DEBUG2 cFYI(1, ("DACL revision %d size %d num aces %d", - pdacl->revision, pdacl->size, pdacl->num_aces)); + le16_to_cpu(pdacl->revision), le16_to_cpu(pdacl->size), + le32_to_cpu(pdacl->num_aces))); #endif acl_base = (char *)pdacl; @@ -255,7 +256,6 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl) static int parse_sid(struct cifs_sid *psid, char *end_of_acl) { - int num_subauth; /* BB need to add parm so we can store the SID BB */ @@ -265,14 +265,13 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl) return -EINVAL; } - num_subauth = cpu_to_le32(psid->num_subauth); - if (num_subauth) { + if (psid->num_subauth) { #ifdef CONFIG_CIFS_DEBUG2 int i; cFYI(1, ("SID revision %d num_auth %d First subauth 0x%x", psid->revision, psid->num_subauth, psid->sub_auth[0])); - for (i = 0; i < num_subauth; ++i) { + for (i = 0; i < psid->num_subauth; i++) { cFYI(1, ("SID sub_auth[%d]: 0x%x ", i, le32_to_cpu(psid->sub_auth[i]))); } @@ -280,7 +279,7 @@ static int parse_sid(struct cifs_sid *psid, char *end_of_acl) /* BB add length check to make sure that we do not have huge num auths and therefore go off the end */ cFYI(1, ("RID 0x%x", - le32_to_cpu(psid->sub_auth[num_subauth-1]))); + le32_to_cpu(psid->sub_auth[psid->num_subauth-1]))); #endif } @@ -297,17 +296,18 @@ int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len) char *end_of_acl = ((char *)pntsd) + acl_len; owner_sid_ptr = (struct cifs_sid *)((char *)pntsd + - cpu_to_le32(pntsd->osidoffset)); + le32_to_cpu(pntsd->osidoffset)); group_sid_ptr = (struct cifs_sid *)((char *)pntsd + - cpu_to_le32(pntsd->gsidoffset)); + le32_to_cpu(pntsd->gsidoffset)); dacl_ptr = (struct cifs_acl *)((char *)pntsd + - cpu_to_le32(pntsd->dacloffset)); + le32_to_cpu(pntsd->dacloffset)); #ifdef CONFIG_CIFS_DEBUG2 cFYI(1, ("revision %d type 0x%x ooffset 0x%x goffset 0x%x " "sacloffset 0x%x dacloffset 0x%x", - pntsd->revision, pntsd->type, - pntsd->osidoffset, pntsd->gsidoffset, pntsd->sacloffset, - pntsd->dacloffset)); + pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset), + le32_to_cpu(pntsd->gsidoffset), + le32_to_cpu(pntsd->sacloffset), + le32_to_cpu(pntsd->dacloffset)); #endif rc = parse_sid(owner_sid_ptr, end_of_acl); if (rc) diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h index 0362cd11f03..fa01053fc5f 100644 --- a/fs/cifs/cifsacl.h +++ b/fs/cifs/cifsacl.h @@ -27,25 +27,25 @@ #define SIDNAMELENGTH 20 /* long enough for the ones we care about */ struct cifs_ntsd { - __u16 revision; /* revision level */ - __u16 type; - __u32 osidoffset; - __u32 gsidoffset; - __u32 sacloffset; - __u32 dacloffset; + __le16 revision; /* revision level */ + __le16 type; + __le32 osidoffset; + __le32 gsidoffset; + __le32 sacloffset; + __le32 dacloffset; } __attribute__((packed)); struct cifs_sid { __u8 revision; /* revision level */ __u8 num_subauth; __u8 authority[6]; - __u32 sub_auth[5]; /* sub_auth[num_subauth] */ + __le32 sub_auth[5]; /* sub_auth[num_subauth] */ /* BB FIXME endianness BB */ } __attribute__((packed)); struct cifs_acl { - __u16 revision; /* revision level */ - __u16 size; - __u32 num_aces; + __le16 revision; /* revision level */ + __le16 size; + __le32 num_aces; } __attribute__((packed)); struct cifs_ntace { /* first part of ACE which contains perms */ @@ -59,7 +59,7 @@ struct cifs_ace { /* last part of ACE which includes user info */ __u8 revision; /* revision level */ __u8 num_subauth; __u8 authority[6]; - __u32 sub_auth[5]; + __le32 sub_auth[5]; } __attribute__((packed)); struct cifs_wksid { @@ -69,7 +69,6 @@ struct cifs_wksid { #ifdef CONFIG_CIFS_EXPERIMENTAL -extern struct cifs_wksid wksidarr[NUM_WK_SIDS]; extern int match_sid(struct cifs_sid *); extern int compare_sids(struct cifs_sid *, struct cifs_sid *); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 14dabbbd813..d22af63e8f1 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -3121,7 +3121,7 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, /* BB check that data area is minimum length and as big as acl_len */ - acl_len = le32_to_cpu(*(__le32 *)parm); + acl_len = le32_to_cpu(*parm); /* BB check if (acl_len > bufsize) */ parse_sec_desc(psec_desc, acl_len); -- cgit v1.2.3 From ce51ae14ae141eacecf2801f9a3646a737ce64a0 Mon Sep 17 00:00:00 2001 From: Dave Kleikamp Date: Tue, 16 Oct 2007 21:35:39 +0000 Subject: [CIFS] endian fixes in new acl code Signed-off-by: Dave Kleikamp Signed-off-by: Steve French --- fs/cifs/cifsacl.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 4735e9b4759..9c4a29690cc 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -34,11 +34,11 @@ static struct cifs_wksid wksidarr[NUM_WK_SIDS] = { {{1, 0, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0} }, "null user"}, {{1, 1, {0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0} }, "nobody"}, - {{1, 1, {0, 0, 0, 0, 0, 5}, {11, 0, 0, 0, 0} }, "net-users"}, - {{1, 1, {0, 0, 0, 0, 0, 5}, {18, 0, 0, 0, 0} }, "sys"}, - {{1, 2, {0, 0, 0, 0, 0, 5}, {32, 544, 0, 0, 0} }, "root"}, - {{1, 2, {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0, 0} }, "users"}, - {{1, 2, {0, 0, 0, 0, 0, 5}, {32, 546, 0, 0, 0} }, "guest"} + {{1, 1, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(11), 0, 0, 0, 0} }, "net-users"}, + {{1, 1, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(18), 0, 0, 0, 0} }, "sys"}, + {{1, 2, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(32), cpu_to_le32(544), 0, 0, 0} }, "root"}, + {{1, 2, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(32), cpu_to_le32(545), 0, 0, 0} }, "users"}, + {{1, 2, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(32), cpu_to_le32(546), 0, 0, 0} }, "guest"} }; @@ -75,8 +75,8 @@ int match_sid(struct cifs_sid *ctsid) continue; /* all of the auth values did not match */ /* compare all of the subauth values if any */ - num_sat = cpu_to_le32(ctsid->num_subauth); - num_saw = cpu_to_le32(cwsid->num_subauth); + num_sat = ctsid->num_subauth; + num_saw = cwsid->num_subauth; num_subauth = num_sat < num_saw ? num_sat : num_saw; if (num_subauth) { for (j = 0; j < num_subauth; ++j) { @@ -141,7 +141,7 @@ static void parse_ace(struct cifs_ace *pace, char *end_of_acl) return; } */ - num_subauth = cpu_to_le32(pace->num_subauth); + num_subauth = pace->num_subauth; if (num_subauth) { #ifdef CONFIG_CIFS_DEBUG2 int i; @@ -228,7 +228,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl) parse_ntace(ppntace[i], end_of_acl); if (end_of_acl < ((char *)ppace[i] + - (ppntace[i]->size - + (le16_to_cpu(ppntace[i]->size) - sizeof(struct cifs_ntace)))) { cERROR(1, ("ACL too small to parse ACE")); break; @@ -243,7 +243,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl) sizeof(struct cifs_ace)); */ acl_base = (char *)ppntace[i]; - acl_size = cpu_to_le32(ppntace[i]->size); + acl_size = le16_to_cpu(ppntace[i]->size); } kfree(ppace); @@ -307,7 +307,7 @@ int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len) pntsd->revision, pntsd->type, le32_to_cpu(pntsd->osidoffset), le32_to_cpu(pntsd->gsidoffset), le32_to_cpu(pntsd->sacloffset), - le32_to_cpu(pntsd->dacloffset)); + le32_to_cpu(pntsd->dacloffset))); #endif rc = parse_sid(owner_sid_ptr, end_of_acl); if (rc) -- cgit v1.2.3 From adbc03587c17e8f50478c1d7744a454cfb9e0653 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 17 Oct 2007 02:12:46 +0000 Subject: [CIFS] endian fixes Signed-off-by: Steve French --- fs/cifs/cifsacl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index 9c4a29690cc..b1f448f2e07 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -115,8 +115,8 @@ int compare_sids(struct cifs_sid *ctsid, struct cifs_sid *cwsid) } /* compare all of the subauth values if any */ - num_sat = cpu_to_le32(ctsid->num_subauth); - num_saw = cpu_to_le32(cwsid->num_subauth); + num_sat = ctsid->num_subauth; + num_saw = cwsid->num_subauth); num_subauth = num_sat < num_saw ? num_sat : num_saw; if (num_subauth) { for (i = 0; i < num_subauth; ++i) { @@ -206,7 +206,7 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl) acl_base = (char *)pdacl; acl_size = sizeof(struct cifs_acl); - num_aces = cpu_to_le32(pdacl->num_aces); + num_aces = le32_to_cpu(pdacl->num_aces); if (num_aces > 0) { ppntace = kmalloc(num_aces * sizeof(struct cifs_ntace *), GFP_KERNEL); -- cgit v1.2.3 From adddd49ddf4ce5a5997f0695b194587290ea72e9 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 17 Oct 2007 02:48:17 +0000 Subject: [CIFS] build break Signed-off-by: Steve French --- fs/cifs/cifsacl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index b1f448f2e07..c46f26bcd8b 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -116,7 +116,7 @@ int compare_sids(struct cifs_sid *ctsid, struct cifs_sid *cwsid) /* compare all of the subauth values if any */ num_sat = ctsid->num_subauth; - num_saw = cwsid->num_subauth); + num_saw = cwsid->num_subauth; num_subauth = num_sat < num_saw ? num_sat : num_saw; if (num_subauth) { for (i = 0; i < num_subauth; ++i) { -- cgit v1.2.3 From c18c732ec6bf372aa959ca6534cbfc32e464defd Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 17 Oct 2007 18:01:11 +0000 Subject: [CIFS] fix bad handling of EAGAIN error on kernel_recvmsg in cifs_demultiplex_thread When kernel_recvmsg returns -EAGAIN or -ERESTARTSYS, then cifs_demultiplex_thread sleeps for a bit and then tries the read again. When it does this, it's not zeroing out the length and that throws off the value of total_read. Fix it to zero out the length. Can cause memory corruption: If kernel_recvmsg returns an error and total_read is a large enough value, then we'll end up going through the loop again. total_read will be a bogus value, as will (pdu_length-total_read). When this happens we end up calling kernel_recvmsg with a bogus value (possibly larger than the current iov_len). At that point, memcpy_toiovec can overrun iov. It will start walking up the stack, casting other things that are there to struct iovecs (since it assumes that it's been passed an array of them). Any pointer on the stack at an address above the kvec is a candidate for corruption here. Many thanks to Ulrich Obergfell for pointing this out. Signed-off-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/CHANGES | 3 ++- fs/cifs/connect.c | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 70c90c07edf..2459ef0a139 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -10,7 +10,8 @@ opened, read and written as if they were files). When 1st tree connect fails (e.g. due to signing negotiation failure) fix leak that causes cifsd not to stop and rmmod to fail to cleanup cifs_request_buffers pool. Fix problem with POSIX Open/Mkdir on -bigendian architectures. +bigendian architectures. Fix possible memory corruption when +EAGAIN returned on kern_recvmsg. Version 1.50 ------------ diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 494455ed435..676bbf2bb56 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -415,7 +415,10 @@ incomplete_rcv: msleep(1); /* minimum sleep to prevent looping allowing socket to clear and app threads to set tcpStatus CifsNeedReconnect if server hung */ - continue; + if (pdu_length < 4) + goto incomplete_rcv; + else + continue; } else if (length <= 0) { if (server->tcpStatus == CifsNew) { cFYI(1, ("tcp session abend after SMBnegprot")); @@ -543,6 +546,7 @@ incomplete_rcv: allowing socket to clear and app threads to set tcpStatus CifsNeedReconnect if server hung*/ + length = 0; continue; } else if (length <= 0) { cERROR(1, ("Received no data, expecting %d", -- cgit v1.2.3 From d5d18501090179d557a4ca976d1c30bfaf5de091 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 17 Oct 2007 21:31:52 +0000 Subject: [CIFS] Fix minor problems noticed by scan Coverity scan pointed out some minor possible errors. Signed-off-by: Steve French --- fs/cifs/cifsfs.c | 12 ++++++------ fs/cifs/netmisc.c | 5 ++++- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index abca6b084ed..91ba32861c8 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -308,15 +308,15 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) seq_printf(s, ",domain=%s", cifs_sb->tcon->ses->domainName); } + if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) || + !(cifs_sb->tcon->unix_ext)) + seq_printf(s, ",uid=%d", cifs_sb->mnt_uid); + if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) || + !(cifs_sb->tcon->unix_ext)) + seq_printf(s, ",gid=%d", cifs_sb->mnt_gid); } if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) seq_printf(s, ",posixpaths"); - if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_UID) || - !(cifs_sb->tcon->unix_ext)) - seq_printf(s, ",uid=%d", cifs_sb->mnt_uid); - if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_OVERR_GID) || - !(cifs_sb->tcon->unix_ext)) - seq_printf(s, ",gid=%d", cifs_sb->mnt_gid); seq_printf(s, ",rsize=%d", cifs_sb->rsize); seq_printf(s, ",wsize=%d", cifs_sb->wsize); } diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index 2bfed3f45d0..9ae4941cd61 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -899,8 +899,11 @@ struct timespec cnvrtDosUnixTm(__u16 date, __u16 time) cERROR(1, ("illegal hours %d", st->Hours)); days = sd->Day; month = sd->Month; - if ((days > 31) || (month > 12)) + if ((days > 31) || (month > 12)) { cERROR(1, ("illegal date, month %d day: %d", month, days)); + if (month > 12) + month = 12; + } month -= 1; days += total_days_of_prev_months[month]; days += 3652; /* account for difference in days between 1980 and 1970 */ -- cgit v1.2.3 From a750e77c21d75abd26fbbde2e104fd406566b6e5 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 17 Oct 2007 22:50:39 +0000 Subject: [CIFS] acl support part 4 Signed-off-by: Steve French --- fs/cifs/cifsacl.c | 19 ++++++++++--------- fs/cifs/cifsacl.h | 9 +++++++++ fs/cifs/cifspdu.h | 6 ++++++ 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index c46f26bcd8b..ecd6da9e9d3 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -95,23 +95,24 @@ int match_sid(struct cifs_sid *ctsid) return (-1); } - +/* if the two SIDs (roughly equivalent to a UUID for a user or group) are + the same returns 1, if they do not match returns 0 */ int compare_sids(struct cifs_sid *ctsid, struct cifs_sid *cwsid) { int i; int num_subauth, num_sat, num_saw; if ((!ctsid) || (!cwsid)) - return (-1); + return (0); /* compare the revision */ if (ctsid->revision != cwsid->revision) - return (-1); + return (0); /* compare all of the six auth values */ for (i = 0; i < 6; ++i) { if (ctsid->authority[i] != cwsid->authority[i]) - return (-1); + return (0); } /* compare all of the subauth values if any */ @@ -121,11 +122,11 @@ int compare_sids(struct cifs_sid *ctsid, struct cifs_sid *cwsid) if (num_subauth) { for (i = 0; i < num_subauth; ++i) { if (ctsid->sub_auth[i] != cwsid->sub_auth[i]) - return (-1); + return (0); } } - return (0); /* sids compare/match */ + return (1); /* sids compare/match */ } @@ -180,7 +181,8 @@ static void parse_ntace(struct cifs_ntace *pntace, char *end_of_acl) -static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl) +static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, + struct cifs_sid *pownersid, struct cifs_sid pgrpsid) { int i; int num_aces = 0; @@ -219,7 +221,6 @@ static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl) cifscred->aces = kmalloc(num_aces * sizeof(struct cifs_ace *), GFP_KERNEL);*/ - for (i = 0; i < num_aces; ++i) { ppntace[i] = (struct cifs_ntace *) (acl_base + acl_size); @@ -317,7 +318,7 @@ int parse_sec_desc(struct cifs_ntsd *pntsd, int acl_len) if (rc) return rc; - parse_dacl(dacl_ptr, end_of_acl); + parse_dacl(dacl_ptr, end_of_acl, owner_sid_ptr, group_sid_ptr); /* cifscred->uid = owner_sid_ptr->rid; cifscred->gid = group_sid_ptr->rid; diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h index fa01053fc5f..420f8781364 100644 --- a/fs/cifs/cifsacl.h +++ b/fs/cifs/cifsacl.h @@ -23,9 +23,18 @@ #define _CIFSACL_H +#define NUM_AUTHS 6 /* number of authority fields */ +#define NUM_SUBAUTHS 5 /* number of sub authority fields */ #define NUM_WK_SIDS 7 /* number of well known sids */ #define SIDNAMELENGTH 20 /* long enough for the ones we care about */ +#define READ_BIT 0x4 +#define WRITE_BIT 0x2 +#define EXEC_BIT 0x1 + +#define UBITSHIFT 6 +#define GBITSHIFT 3 + struct cifs_ntsd { __le16 revision; /* revision level */ __le16 type; diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index d2f0cf23bbb..c41ff74e912 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -215,6 +215,12 @@ /* file_execute, file_read_attributes*/ /* write_dac, and delete. */ +#define FILE_READ_RIGHTS (FILE_READ_DATA | FILE_READ_EA | FILE_READ_ATTRIBUTES) +#define FILE_WRITE_RIGHTS (FILE_WRITE_DATA | FILE_APPEND_DATA \ + | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES) +#define FILE_EXEC_RIGHTS (FILE_EXECUTE) + + /* * Invalid readdir handle */ -- cgit v1.2.3 From d628ddb62d3050e8e474aa3566bc6bafbe4b9c26 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 17 Oct 2007 23:06:07 +0000 Subject: [CIFS] fix typo Signed-off-by: Steve French --- fs/cifs/cifsacl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c index ecd6da9e9d3..e8e56353f5a 100644 --- a/fs/cifs/cifsacl.c +++ b/fs/cifs/cifsacl.c @@ -182,7 +182,7 @@ static void parse_ntace(struct cifs_ntace *pntace, char *end_of_acl) static void parse_dacl(struct cifs_acl *pdacl, char *end_of_acl, - struct cifs_sid *pownersid, struct cifs_sid pgrpsid) + struct cifs_sid *pownersid, struct cifs_sid *pgrpsid) { int i; int num_aces = 0; -- cgit v1.2.3 From abb63d6c3d3d0e4d93b63589135962091154be9b Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 18 Oct 2007 02:58:40 +0000 Subject: [CIFS] Return better error when server requires signing but client forbids Signed-off-by: Steve French --- fs/cifs/CHANGES | 3 ++- fs/cifs/cifssmb.c | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 2459ef0a139..3d419163c3d 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -11,7 +11,8 @@ connect fails (e.g. due to signing negotiation failure) fix leak that causes cifsd not to stop and rmmod to fail to cleanup cifs_request_buffers pool. Fix problem with POSIX Open/Mkdir on bigendian architectures. Fix possible memory corruption when -EAGAIN returned on kern_recvmsg. +EAGAIN returned on kern_recvmsg. Return better error if server +requires packet signing but client has disabled it. Version 1.50 ------------ diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index d22af63e8f1..2b2d4fec365 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -663,10 +663,12 @@ signing_check: /* MUST_SIGN already includes the MAY_SIGN FLAG so if this is zero it means that signing is disabled */ cFYI(1, ("Signing disabled")); - if (server->secMode & SECMODE_SIGN_REQUIRED) + if (server->secMode & SECMODE_SIGN_REQUIRED) { cERROR(1, ("Server requires " "packet signing to be enabled in " "/proc/fs/cifs/SecurityFlags.")); + rc = -EOPNOTSUPP; + } server->secMode &= ~(SECMODE_SIGN_ENABLED | SECMODE_SIGN_REQUIRED); } else if ((secFlags & CIFSSEC_MUST_SIGN) == CIFSSEC_MUST_SIGN) { -- cgit v1.2.3 From a761ac579b89bc1f00212a42401398108deba65c Mon Sep 17 00:00:00 2001 From: Steve French Date: Thu, 18 Oct 2007 21:45:27 +0000 Subject: [CIFS] log better errors on failed mounts Also returns more accurate errors to mount for the cases of account expired and password expired Acked-by: Jeff Layton Signed-off-by: Steve French --- fs/cifs/cifsproto.h | 5 +++-- fs/cifs/cifssmb.c | 10 +++++----- fs/cifs/netmisc.c | 28 ++++++++++++++++++---------- fs/cifs/sess.c | 3 ++- fs/cifs/smberr.h | 5 +++-- fs/cifs/transport.c | 10 ++++------ 6 files changed, 35 insertions(+), 26 deletions(-) diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 001f0dc7e60..1a883663b22 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -50,7 +50,8 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, int * /* bytes returned */ , const int long_op); extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, struct kvec *, int /* nvec to send */, - int * /* type of buf returned */ , const int long_op); + int * /* type of buf returned */ , const int long_op, + const int logError /* whether to log status code*/ ); extern int SendReceiveBlockingLock(const unsigned int /* xid */ , struct cifsTconInfo *, struct smb_hdr * /* input */ , @@ -65,7 +66,7 @@ extern unsigned int smbCalcSize_LE(struct smb_hdr *ptr); extern int decode_negTokenInit(unsigned char *security_blob, int length, enum securityEnum *secType); extern int cifs_inet_pton(int, char *source, void *dst); -extern int map_smb_to_linux_error(struct smb_hdr *smb); +extern int map_smb_to_linux_error(struct smb_hdr *smb, int logErr); extern void header_assemble(struct smb_hdr *, char /* command */ , const struct cifsTconInfo *, int /* length of fixed section (word count) in two byte units */); diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index 2b2d4fec365..f0d9a485d09 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -1446,9 +1446,8 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, const int netfid, iov[0].iov_base = (char *)pSMB; iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; - rc = SendReceive2(xid, tcon->ses, iov, - 1 /* num iovecs */, - &resp_buf_type, 0); + rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovecs */, + &resp_buf_type, 0 /* not long op */, 1 /* log err */ ); cifs_stats_inc(&tcon->num_reads); pSMBr = (READ_RSP *)iov[0].iov_base; if (rc) { @@ -1667,7 +1666,7 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, - long_op); + long_op, 0 /* do not log STATUS code */ ); cifs_stats_inc(&tcon->num_writes); if (rc) { cFYI(1, ("Send error Write2 = %d", rc)); @@ -3094,7 +3093,8 @@ CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, __u16 fid, iov[0].iov_base = (char *)pSMB; iov[0].iov_len = pSMB->hdr.smb_buf_length + 4; - rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, 0); + rc = SendReceive2(xid, tcon->ses, iov, 1 /* num iovec */, &buf_type, + 0 /* not long op */, 0 /* do not log STATUS codes */ ); cifs_stats_inc(&tcon->num_acl_get); if (rc) { cFYI(1, ("Send error in QuerySecDesc = %d", rc)); diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index 9ae4941cd61..f06359cb22e 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -114,10 +114,16 @@ static const struct smb_to_posix_error mapping_table_ERRSRV[] = { {ERRusempx, -EIO}, {ERRusestd, -EIO}, {ERR_NOTIFY_ENUM_DIR, -ENOBUFS}, - {ERRaccountexpired, -EACCES}, + {ERRnoSuchUser, -EACCES}, +/* {ERRaccountexpired, -EACCES}, {ERRbadclient, -EACCES}, {ERRbadLogonTime, -EACCES}, - {ERRpasswordExpired, -EACCES}, + {ERRpasswordExpired, -EACCES},*/ + {ERRaccountexpired, -EKEYEXPIRED}, + {ERRbadclient, -EACCES}, + {ERRbadLogonTime, -EACCES}, + {ERRpasswordExpired, -EKEYEXPIRED}, + {ERRnosupport, -EINVAL}, {0, 0} }; @@ -270,7 +276,7 @@ static const struct { from NT_STATUS_NO_SUCH_USER to NT_STATUS_LOGON_FAILURE during the session setup } */ { - ERRDOS, ERRnoaccess, NT_STATUS_NO_SUCH_USER}, { + ERRDOS, ERRnoaccess, NT_STATUS_NO_SUCH_USER}, { /* could map to 2238 */ ERRHRD, ERRgeneral, NT_STATUS_GROUP_EXISTS}, { ERRHRD, ERRgeneral, NT_STATUS_NO_SUCH_GROUP}, { ERRHRD, ERRgeneral, NT_STATUS_MEMBER_IN_GROUP}, { @@ -285,10 +291,10 @@ static const struct { ERRHRD, ERRgeneral, NT_STATUS_PASSWORD_RESTRICTION}, { ERRDOS, ERRnoaccess, NT_STATUS_LOGON_FAILURE}, { ERRHRD, ERRgeneral, NT_STATUS_ACCOUNT_RESTRICTION}, { - ERRSRV, 2241, NT_STATUS_INVALID_LOGON_HOURS}, { - ERRSRV, 2240, NT_STATUS_INVALID_WORKSTATION}, { + ERRSRV, ERRbadLogonTime, NT_STATUS_INVALID_LOGON_HOURS}, { + ERRSRV, ERRbadclient, NT_STATUS_INVALID_WORKSTATION}, { ERRSRV, ERRpasswordExpired, NT_STATUS_PASSWORD_EXPIRED}, { - ERRSRV, 2239, NT_STATUS_ACCOUNT_DISABLED}, { + ERRSRV, ERRaccountexpired, NT_STATUS_ACCOUNT_DISABLED}, { ERRHRD, ERRgeneral, NT_STATUS_NONE_MAPPED}, { ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LUIDS_REQUESTED}, { ERRHRD, ERRgeneral, NT_STATUS_LUIDS_EXHAUSTED}, { @@ -585,7 +591,7 @@ static const struct { ERRDOS, ERRnoaccess, NT_STATUS_TRUST_FAILURE}, { ERRHRD, ERRgeneral, NT_STATUS_MUTANT_LIMIT_EXCEEDED}, { ERRDOS, ERRnetlogonNotStarted, NT_STATUS_NETLOGON_NOT_STARTED}, { - ERRSRV, 2239, NT_STATUS_ACCOUNT_EXPIRED}, { + ERRSRV, ERRaccountexpired, NT_STATUS_ACCOUNT_EXPIRED}, { ERRHRD, ERRgeneral, NT_STATUS_POSSIBLE_DEADLOCK}, { ERRHRD, ERRgeneral, NT_STATUS_NETWORK_CREDENTIAL_CONFLICT}, { ERRHRD, ERRgeneral, NT_STATUS_REMOTE_SESSION_LIMIT}, { @@ -754,7 +760,7 @@ ntstatus_to_dos(__u32 ntstatus, __u8 * eclass, __u16 * ecode) } int -map_smb_to_linux_error(struct smb_hdr *smb) +map_smb_to_linux_error(struct smb_hdr *smb, int logErr) { unsigned int i; int rc = -EIO; /* if transport error smb error may not be set */ @@ -771,7 +777,9 @@ map_smb_to_linux_error(struct smb_hdr *smb) /* translate the newer STATUS codes to old style SMB errors * and then to POSIX errors */ __u32 err = le32_to_cpu(smb->Status.CifsError); - if (cifsFYI & CIFS_RC) + if (logErr && (err != (NT_STATUS_MORE_PROCESSING_REQUIRED))) + cifs_print_status(err); + else if (cifsFYI & CIFS_RC) cifs_print_status(err); ntstatus_to_dos(err, &smberrclass, &smberrcode); } else { @@ -813,7 +821,7 @@ map_smb_to_linux_error(struct smb_hdr *smb) } /* else ERRHRD class errors or junk - return EIO */ - cFYI(1, (" !!Mapping smb error code %d to POSIX err %d !!", + cFYI(1, ("Mapping smb error code %d to POSIX err %d", smberrcode, rc)); /* generic corrective action e.g. reconnect SMB session on diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index c74a064e782..899dc6078d9 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -513,7 +513,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, iov[1].iov_base = str_area; iov[1].iov_len = count; - rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type, 0); + rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type, + 0 /* not long op */, 1 /* log NT STATUS if any */ ); /* SMB request buf freed in SendReceive2 */ cFYI(1, ("ssetup rc from sendrecv2 is %d", rc)); diff --git a/fs/cifs/smberr.h b/fs/cifs/smberr.h index 2ef0be28882..7f50e8577c1 100644 --- a/fs/cifs/smberr.h +++ b/fs/cifs/smberr.h @@ -173,9 +173,10 @@ #define ERRusestd 251 /* temporarily unable to use either raw or mpx */ #define ERR_NOTIFY_ENUM_DIR 1024 +#define ERRnoSuchUser 2238 /* user account does not exist */ #define ERRaccountexpired 2239 -#define ERRbadclient 2240 -#define ERRbadLogonTime 2241 +#define ERRbadclient 2240 /* can not logon from this client */ +#define ERRbadLogonTime 2241 /* logon hours do not allow this */ #define ERRpasswordExpired 2242 #define ERRnetlogonNotStarted 2455 #define ERRnosupport 0xFFFF diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 6684926bf3d..7ed32b3cb78 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -418,7 +418,7 @@ static int wait_for_response(struct cifsSesInfo *ses, int SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, struct kvec *iov, int n_vec, int *pRespBufType /* ret */, - const int long_op) + const int long_op, const int logError) { int rc = 0; unsigned int receive_len; @@ -464,7 +464,6 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, wake_up(&ses->server->request_q); return rc; } - rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); midQ->midState = MID_REQUEST_SUBMITTED; @@ -567,8 +566,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, } /* BB special case reconnect tid and uid here? */ - /* BB special case Errbadpassword and pwdexpired here */ - rc = map_smb_to_linux_error(midQ->resp_buf); + rc = map_smb_to_linux_error(midQ->resp_buf, logError); /* convert ByteCount if necessary */ if (receive_len >= sizeof(struct smb_hdr) - 4 @@ -747,7 +745,7 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, *pbytes_returned = out_buf->smb_buf_length; /* BB special case reconnect tid and uid here? */ - rc = map_smb_to_linux_error(out_buf); + rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); /* convert ByteCount if necessary */ if (receive_len >= sizeof(struct smb_hdr) - 4 @@ -990,7 +988,7 @@ SendReceiveBlockingLock(const unsigned int xid, struct cifsTconInfo *tcon, *pbytes_returned = out_buf->smb_buf_length; /* BB special case reconnect tid and uid here? */ - rc = map_smb_to_linux_error(out_buf); + rc = map_smb_to_linux_error(out_buf, 0 /* no log */ ); /* convert ByteCount if necessary */ if (receive_len >= sizeof(struct smb_hdr) - 4 -- cgit v1.2.3