diff options
Diffstat (limited to 'fs/cifs')
-rw-r--r-- | fs/cifs/CHANGES | 16 | ||||
-rw-r--r-- | fs/cifs/README | 42 | ||||
-rw-r--r-- | fs/cifs/TODO | 4 | ||||
-rw-r--r-- | fs/cifs/cifs_debug.c | 51 | ||||
-rw-r--r-- | fs/cifs/cifs_fs_sb.h | 5 | ||||
-rw-r--r-- | fs/cifs/cifs_unicode.c | 13 | ||||
-rw-r--r-- | fs/cifs/cifs_unicode.h | 6 | ||||
-rw-r--r-- | fs/cifs/cifs_uniupr.h | 2 | ||||
-rw-r--r-- | fs/cifs/cifsacl.h | 38 | ||||
-rw-r--r-- | fs/cifs/cifsencrypt.c | 57 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 158 | ||||
-rw-r--r-- | fs/cifs/cifsfs.h | 4 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 18 | ||||
-rw-r--r-- | fs/cifs/cifspdu.h | 107 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 23 | ||||
-rw-r--r-- | fs/cifs/cifssmb.c | 360 | ||||
-rw-r--r-- | fs/cifs/connect.c | 180 | ||||
-rw-r--r-- | fs/cifs/dir.c | 74 | ||||
-rw-r--r-- | fs/cifs/file.c | 81 | ||||
-rw-r--r-- | fs/cifs/inode.c | 268 | ||||
-rw-r--r-- | fs/cifs/misc.c | 36 | ||||
-rw-r--r-- | fs/cifs/netmisc.c | 4 | ||||
-rw-r--r-- | fs/cifs/readdir.c | 60 | ||||
-rw-r--r-- | fs/cifs/rfc1002pdu.h | 4 | ||||
-rw-r--r-- | fs/cifs/transport.c | 43 | ||||
-rw-r--r-- | fs/cifs/xattr.c | 22 |
26 files changed, 1273 insertions, 403 deletions
diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index eab3750..d335015 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -1,8 +1,22 @@ +Version 1.40 +------------ +Use fsuid (fsgid) more consistently instead of uid (gid). Improve performance +of readpages by eliminating one extra memcpy. Allow update of file size +from remote server even if file is open for write as long as mount is +directio. Recognize share mode security and send NTLM encrypted password +on tree connect if share mode negotiated. + Version 1.39 ------------ -Defer close of a file handle slightly if pending writes depend on that file handle +Defer close of a file handle slightly if pending writes depend on that handle (this reduces the EBADF bad file handle errors that can be logged under heavy stress on writes). Modify cifs Kconfig options to expose CONFIG_CIFS_STATS2 +Fix SFU style symlinks and mknod needed for servers which do not support the +CIFS Unix Extensions. Fix setfacl/getfacl on bigendian. Timeout negative +dentries so files that the client sees as deleted but that later get created +on the server will be recognized. Add client side permission check on setattr. +Timeout stuck requests better (where server has never responded or sent corrupt +responses) Version 1.38 ------------ diff --git a/fs/cifs/README b/fs/cifs/README index bb909418..b0070d1 100644 --- a/fs/cifs/README +++ b/fs/cifs/README @@ -278,7 +278,9 @@ A partial list of the supported mount options follows: (such as Windows), permissions can also be checked at the client, and a crude form of client side permission checking can be enabled by specifying file_mode and dir_mode on - the client + the client. Note that the mount.cifs helper must be + at version 1.10 or higher to support specifying the uid + (or gid) in non-numberic form. gid If CIFS Unix extensions are not supported by the server this overrides the default gid for inodes. file_mode If CIFS Unix extensions are not supported by the server @@ -345,7 +347,10 @@ A partial list of the supported mount options follows: client system. It is typically only needed when the server supports the CIFS Unix Extensions but the UIDs/GIDs on the client and server system do not match closely enough to allow - access by the user doing the mount. + access by the user doing the mount, but it may be useful with + non CIFS Unix Extension mounts for cases in which the default + mode is specified on the mount but is not to be enforced on the + client (e.g. perhaps when MultiUserMount is enabled) Note that this does not affect the normal ACL check on the target machine done by the server software (of the server ACL against the user name provided at mount time). @@ -368,15 +373,21 @@ A partial list of the supported mount options follows: setuids If the CIFS Unix extensions are negotiated with the server the client will attempt to set the effective uid and gid of the local process on newly created files, directories, and - devices (create, mkdir, mknod). + devices (create, mkdir, mknod). If the CIFS Unix Extensions + are not negotiated, for newly created files and directories + instead of using the default uid and gid specified on the + the mount, cache the new file's uid and gid locally which means + that the uid for the file can change when the inode is + reloaded (or the user remounts the share). nosetuids The client will not attempt to set the uid and gid on on newly created files, directories, and devices (create, mkdir, mknod) which will result in the server setting the uid and gid to the default (usually the server uid of the user who mounted the share). Letting the server (rather than - the client) set the uid and gid is the default. This - parameter has no effect if the CIFS Unix Extensions are not - negotiated. + the client) set the uid and gid is the default. If the CIFS + Unix Extensions are not negotiated then the uid and gid for + new files will appear to be the uid (gid) of the mounter or the + uid (gid) parameter specified on the mount. netbiosname When mounting to servers via port 139, specifies the RFC1001 source name to use to represent the client netbios machine name when doing the RFC1001 netbios session initialize. @@ -418,7 +429,24 @@ A partial list of the supported mount options follows: byte range locks). remount remount the share (often used to change from ro to rw mounts or vice versa) - + sfu When the CIFS Unix Extensions are not negotiated, attempt to + create device files and fifos in a format compatible with + Services for Unix (SFU). In addition retrieve bits 10-12 + of the mode via the SETFILEBITS extended attribute (as + SFU does). In the future the bottom 9 bits of the mode + mode also will be emulated using queries of the security + descriptor (ACL). +sec Security mode. Allowed values are: + none attempt to connection as a null user (no name) + krb5 Use Kerberos version 5 authentication + krb5i Use Kerberos authentication and packet signing + ntlm Use NTLM password hashing (default) + ntlmi Use NTLM password hashing with signing (if + /proc/fs/cifs/PacketSigningEnabled on or if + server requires signing also can be the default) + ntlmv2 Use NTLMv2 password hashing + ntlmv2i Use NTLMv2 password hashing with packet signing + The mount.cifs mount helper also accepts a few mount options before -o including: diff --git a/fs/cifs/TODO b/fs/cifs/TODO index c909298..fc34c74 100644 --- a/fs/cifs/TODO +++ b/fs/cifs/TODO @@ -1,4 +1,4 @@ -version 1.37 October 9, 2005 +Version 1.39 November 30, 2005 A Partial List of Missing Features ================================== @@ -58,7 +58,7 @@ o) Improve performance of readpages by sending more than one read at a time when 8 pages or more are requested. In conjuntion add support for async_cifs_readpages. -p) Add support for storing symlink and fifo info to Windows servers +p) Add support for storing symlink info to Windows servers in the Extended Attribute format their SFU clients would recognize. q) Finish fcntl D_NOTIFY support so kde and gnome file list windows diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 22a444a..f4124a3 100644 --- a/fs/cifs/cifs_debug.c +++ b/fs/cifs/cifs_debug.c @@ -219,6 +219,10 @@ cifs_stats_write(struct file *file, const char __user *buffer, if (c == '1' || c == 'y' || c == 'Y' || c == '0') { read_lock(&GlobalSMBSeslock); +#ifdef CONFIG_CIFS_STATS2 + atomic_set(&totBufAllocCount, 0); + atomic_set(&totSmBufAllocCount, 0); +#endif /* CONFIG_CIFS_STATS2 */ list_for_each(tmp, &GlobalTreeConnectionList) { tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); @@ -276,6 +280,14 @@ cifs_stats_read(char *buf, char **beginBuffer, off_t offset, smBufAllocCount.counter,cifs_min_small); length += item_length; buf += item_length; +#ifdef CONFIG_CIFS_STATS2 + item_length = sprintf(buf, "Total Large %d Small %d Allocations\n", + atomic_read(&totBufAllocCount), + atomic_read(&totSmBufAllocCount)); + length += item_length; + buf += item_length; +#endif /* CONFIG_CIFS_STATS2 */ + item_length = sprintf(buf,"Operations (MIDs): %d\n", midCount.counter); @@ -389,8 +401,8 @@ static read_proc_t ntlmv2_enabled_read; static write_proc_t ntlmv2_enabled_write; static read_proc_t packet_signing_enabled_read; static write_proc_t packet_signing_enabled_write; -static read_proc_t quotaEnabled_read; -static write_proc_t quotaEnabled_write; +static read_proc_t experimEnabled_read; +static write_proc_t experimEnabled_write; static read_proc_t linuxExtensionsEnabled_read; static write_proc_t linuxExtensionsEnabled_write; @@ -430,9 +442,9 @@ cifs_proc_init(void) pde->write_proc = oplockEnabled_write; pde = create_proc_read_entry("Experimental", 0, proc_fs_cifs, - quotaEnabled_read, NULL); + experimEnabled_read, NULL); if (pde) - pde->write_proc = quotaEnabled_write; + pde->write_proc = experimEnabled_write; pde = create_proc_read_entry("LinuxExtensionsEnabled", 0, proc_fs_cifs, linuxExtensionsEnabled_read, NULL); @@ -574,14 +586,13 @@ oplockEnabled_write(struct file *file, const char __user *buffer, } static int -quotaEnabled_read(char *page, char **start, off_t off, +experimEnabled_read(char *page, char **start, off_t off, int count, int *eof, void *data) { int len; len = sprintf(page, "%d\n", experimEnabled); -/* could also check if quotas are enabled in kernel - as a whole first */ + len -= off; *start = page + off; @@ -596,21 +607,23 @@ quotaEnabled_read(char *page, char **start, off_t off, return len; } static int -quotaEnabled_write(struct file *file, const char __user *buffer, +experimEnabled_write(struct file *file, const char __user *buffer, unsigned long count, void *data) { - char c; - int rc; + char c; + int rc; - rc = get_user(c, buffer); - if (rc) - return rc; - if (c == '0' || c == 'n' || c == 'N') - experimEnabled = 0; - else if (c == '1' || c == 'y' || c == 'Y') - experimEnabled = 1; + rc = get_user(c, buffer); + if (rc) + return rc; + if (c == '0' || c == 'n' || c == 'N') + experimEnabled = 0; + else if (c == '1' || c == 'y' || c == 'Y') + experimEnabled = 1; + else if (c == '2') + experimEnabled = 2; - return count; + return count; } static int @@ -620,8 +633,6 @@ linuxExtensionsEnabled_read(char *page, char **start, off_t off, int len; len = sprintf(page, "%d\n", linuxExtEnabled); -/* could also check if quotas are enabled in kernel - as a whole first */ len -= off; *start = page + off; diff --git a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h index f799f6f..ad58eb0 100644 --- a/fs/cifs/cifs_fs_sb.h +++ b/fs/cifs/cifs_fs_sb.h @@ -24,9 +24,10 @@ #define CIFS_MOUNT_DIRECT_IO 8 /* do not write nor read through page cache */ #define CIFS_MOUNT_NO_XATTR 0x10 /* if set - disable xattr support */ #define CIFS_MOUNT_MAP_SPECIAL_CHR 0x20 /* remap illegal chars in filenames */ -#define CIFS_MOUNT_POSIX_PATHS 0x40 /* Negotiate posix pathnames if possible. */ -#define CIFS_MOUNT_UNX_EMUL 0x80 /* Network compat with SFUnix emulation */ +#define CIFS_MOUNT_POSIX_PATHS 0x40 /* Negotiate posix pathnames if possible. */ +#define CIFS_MOUNT_UNX_EMUL 0x80 /* Network compat with SFUnix emulation */ #define CIFS_MOUNT_NO_BRL 0x100 /* No sending byte range locks to srv */ +#define CIFS_MOUNT_CIFS_ACL 0x200 /* send ACL requests to non-POSIX srv */ struct cifs_sb_info { struct cifsTconInfo *tcon; /* primary mount */ diff --git a/fs/cifs/cifs_unicode.c b/fs/cifs/cifs_unicode.c index 4e12053..d2b1282 100644 --- a/fs/cifs/cifs_unicode.c +++ b/fs/cifs/cifs_unicode.c @@ -1,7 +1,7 @@ /* * fs/cifs/cifs_unicode.c * - * Copyright (c) International Business Machines Corp., 2000,2002 + * Copyright (c) International Business Machines Corp., 2000,2005 * Modified by Steve French (sfrench@us.ibm.com) * * This program is free software; you can redistribute it and/or modify @@ -31,7 +31,7 @@ * */ int -cifs_strfromUCS_le(char *to, const wchar_t * from, /* LITTLE ENDIAN */ +cifs_strfromUCS_le(char *to, const __le16 * from, int len, const struct nls_table *codepage) { int i; @@ -60,25 +60,26 @@ cifs_strfromUCS_le(char *to, const wchar_t * from, /* LITTLE ENDIAN */ * */ int -cifs_strtoUCS(wchar_t * to, const char *from, int len, +cifs_strtoUCS(__le16 * to, const char *from, int len, const struct nls_table *codepage) { int charlen; int i; + wchar_t * wchar_to = (wchar_t *)to; /* needed to quiet sparse */ for (i = 0; len && *from; i++, from += charlen, len -= charlen) { /* works for 2.4.0 kernel or later */ - charlen = codepage->char2uni(from, len, &to[i]); + charlen = codepage->char2uni(from, len, &wchar_to[i]); if (charlen < 1) { cERROR(1, ("cifs_strtoUCS: char2uni returned %d", charlen)); /* A question mark */ - to[i] = (wchar_t)cpu_to_le16(0x003f); + to[i] = cpu_to_le16(0x003f); charlen = 1; } else - to[i] = (wchar_t)cpu_to_le16(to[i]); + to[i] = cpu_to_le16(wchar_to[i]); } diff --git a/fs/cifs/cifs_unicode.h b/fs/cifs/cifs_unicode.h index da8dde9..39e5b97 100644 --- a/fs/cifs/cifs_unicode.h +++ b/fs/cifs/cifs_unicode.h @@ -5,7 +5,7 @@ * Convert a unicode character to upper or lower case using * compressed tables. * - * Copyright (c) International Business Machines Corp., 2000,2002 + * Copyright (c) International Business Machines Corp., 2000,2005555555555555555555555555555555555555555555555555555555 * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -59,8 +59,8 @@ extern struct UniCaseRange UniLowerRange[]; #endif /* UNIUPR_NOLOWER */ #ifdef __KERNEL__ -int cifs_strfromUCS_le(char *, const wchar_t *, int, const struct nls_table *); -int cifs_strtoUCS(wchar_t *, const char *, int, const struct nls_table *); +int cifs_strfromUCS_le(char *, const __le16 *, int, const struct nls_table *); +int cifs_strtoUCS(__le16 *, const char *, int, const struct nls_table *); #endif /* diff --git a/fs/cifs/cifs_uniupr.h b/fs/cifs/cifs_uniupr.h index decd138..da2ad5b 100644 --- a/fs/cifs/cifs_uniupr.h +++ b/fs/cifs/cifs_uniupr.h @@ -242,7 +242,7 @@ static signed char UniCaseRangeLff20[27] = { /* * Lower Case Range */ -const static struct UniCaseRange CifsUniLowerRange[] = { +static const struct UniCaseRange CifsUniLowerRange[] = { 0x0380, 0x03ab, UniCaseRangeL0380, 0x0400, 0x042f, UniCaseRangeL0400, 0x0490, 0x04cb, UniCaseRangeL0490, diff --git a/fs/cifs/cifsacl.h b/fs/cifs/cifsacl.h new file mode 100644 index 0000000..d0776ac --- /dev/null +++ b/fs/cifs/cifsacl.h @@ -0,0 +1,38 @@ +/* + * fs/cifs/cifsacl.h + * + * Copyright (c) International Business Machines Corp., 2005 + * Author(s): Steve French (sfrench@us.ibm.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; either version 2.1 of the License, or + * (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See + * the GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef _CIFSACL_H +#define _CIFSACL_H + +struct cifs_sid { + __u8 revision; /* revision level */ + __u8 num_subauths; + __u8 authority[6]; + __u32 sub_auth[4]; + /* next sub_auth if any ... */ +} __attribute__((packed)); + +/* everyone */ +extern const struct cifs_sid sid_everyone; +/* group users */ +extern const struct cifs_sid sid_user; + +#endif /* _CIFSACL_H */ diff --git a/fs/cifs/cifsencrypt.c b/fs/cifs/cifsencrypt.c index 1959c7c..a2c2485 100644 --- a/fs/cifs/cifsencrypt.c +++ b/fs/cifs/cifsencrypt.c @@ -1,7 +1,7 @@ /* * fs/cifs/cifsencrypt.c * - * Copyright (C) International Business Machines Corp., 2003 + * Copyright (C) International Business Machines Corp., 2005 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -82,6 +82,59 @@ int cifs_sign_smb(struct smb_hdr * cifs_pdu, struct TCP_Server_Info * server, return rc; } +static int cifs_calc_signature2(const struct kvec * iov, int n_vec, + const char * key, char * signature) +{ + struct MD5Context context; + + if((iov == NULL) || (signature == NULL)) + return -EINVAL; + + MD5Init(&context); + MD5Update(&context,key,CIFS_SESSION_KEY_SIZE+16); + +/* MD5Update(&context,cifs_pdu->Protocol,cifs_pdu->smb_buf_length); */ /* BB FIXME BB */ + + MD5Final(signature,&context); + + return -EOPNOTSUPP; +/* return 0; */ +} + + +int cifs_sign_smb2(struct kvec * iov, int n_vec, struct TCP_Server_Info *server, + __u32 * pexpected_response_sequence_number) +{ + int rc = 0; + char smb_signature[20]; + struct smb_hdr * cifs_pdu = iov[0].iov_base; + + if((cifs_pdu == NULL) || (server == NULL)) + return -EINVAL; + + if((cifs_pdu->Flags2 & SMBFLG2_SECURITY_SIGNATURE) == 0) + return rc; + + spin_lock(&GlobalMid_Lock); + cifs_pdu->Signature.Sequence.SequenceNumber = + cpu_to_le32(server->sequence_number); + cifs_pdu->Signature.Sequence.Reserved = 0; + + *pexpected_response_sequence_number = server->sequence_number++; + server->sequence_number++; + spin_unlock(&GlobalMid_Lock); + + rc = cifs_calc_signature2(iov, n_vec, server->mac_signing_key, + smb_signature); + if(rc) + memset(cifs_pdu->Signature.SecuritySignature, 0, 8); + else + memcpy(cifs_pdu->Signature.SecuritySignature, smb_signature, 8); + + return rc; + +} + int cifs_verify_signature(struct smb_hdr * cifs_pdu, const char * mac_key, __u32 expected_sequence_number) { @@ -149,7 +202,7 @@ int CalcNTLMv2_partial_mac_key(struct cifsSesInfo * ses, struct nls_table * nls_ char temp_hash[16]; struct HMACMD5Context ctx; char * ucase_buf; - wchar_t * unicode_buf; + __le16 * unicode_buf; unsigned int i,user_name_len,dom_name_len; if(ses == NULL) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 682b023..79eeccd 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -32,6 +32,7 @@ #include <linux/seq_file.h> #include <linux/vfs.h> #include <linux/mempool.h> +#include <linux/delay.h> #include "cifsfs.h" #include "cifspdu.h" #define DECLARE_GLOBALS_HERE @@ -429,6 +430,11 @@ static void cifs_umount_begin(struct super_block * sblock) { cFYI(1,("wake up tasks now - umount begin not complete")); wake_up_all(&tcon->ses->server->request_q); + wake_up_all(&tcon->ses->server->response_q); + msleep(1); /* yield */ + /* we have to kick the requests once more */ + wake_up_all(&tcon->ses->server->response_q); + msleep(1); } /* BB FIXME - finish add checks for tidStatus BB */ @@ -483,56 +489,40 @@ cifs_get_sb(struct file_system_type *fs_type, return sb; } -static ssize_t -cifs_read_wrapper(struct file * file, char __user *read_data, size_t read_size, - loff_t * poffset) +static ssize_t cifs_file_writev(struct file *file, const struct iovec *iov, + unsigned long nr_segs, loff_t *ppos) { - if(file->f_dentry == NULL) - return -EIO; - else if(file->f_dentry->d_inode == NULL) - return -EIO; - - cFYI(1,("In read_wrapper size %zd at %lld",read_size,*poffset)); + struct inode *inode = file->f_dentry->d_inode; + ssize_t written; - if(CIFS_I(file->f_dentry->d_inode)->clientCanCacheRead) { - return generic_file_read(file,read_data,read_size,poffset); - } else { - /* BB do we need to lock inode from here until after invalidate? */ -/* if(file->f_dentry->d_inode->i_mapping) { - filemap_fdatawrite(file->f_dentry->d_inode->i_mapping); - filemap_fdatawait(file->f_dentry->d_inode->i_mapping); - }*/ -/* cifs_revalidate(file->f_dentry);*/ /* BB fixme */ - - /* BB we should make timer configurable - perhaps - by simply calling cifs_revalidate here */ - /* invalidate_remote_inode(file->f_dentry->d_inode);*/ - return generic_file_read(file,read_data,read_size,poffset); - } + written = generic_file_writev(file, iov, nr_segs, ppos); + if (!CIFS_I(inode)->clientCanCacheAll) + filemap_fdatawrite(inode->i_mapping); + return written; } -static ssize_t -cifs_write_wrapper(struct file * file, const char __user *write_data, - size_t write_size, loff_t * poffset) +static ssize_t cifs_file_aio_write(struct kiocb *iocb, const char __user *buf, + size_t count, loff_t pos) { + struct inode *inode = iocb->ki_filp->f_dentry->d_inode; ssize_t written; - if(file->f_dentry == NULL) - return -EIO; - else if(file->f_dentry->d_inode == NULL) - return -EIO; - - cFYI(1,("In write_wrapper size %zd at %lld",write_size,*poffset)); - - written = generic_file_write(file,write_data,write_size,poffset); - if(!CIFS_I(file->f_dentry->d_inode)->clientCanCacheAll) { - if(file->f_dentry->d_inode->i_mapping) { - filemap_fdatawrite(file->f_dentry->d_inode->i_mapping); - } - } + written = generic_file_aio_write(iocb, buf, count, pos); + if (!CIFS_I(inode)->clientCanCacheAll) + filemap_fdatawrite(inode->i_mapping); return written; } +static loff_t cifs_llseek(struct file *file, loff_t offset, int origin) +{ + /* origin == SEEK_END => we must revalidate the cached file length */ + if (origin == 2) { + int retval = cifs_revalidate(file->f_dentry); + if (retval < 0) + return (loff_t)retval; + } + return remote_llseek(file, offset, origin); +} static struct file_system_type cifs_fs_type = { .owner = THIS_MODULE, @@ -594,8 +584,12 @@ struct inode_operations cifs_symlink_inode_ops = { }; struct file_operations cifs_file_ops = { - .read = cifs_read_wrapper, - .write = cifs_write_wrapper, + .read = do_sync_read, + .write = do_sync_write, + .readv = generic_file_readv, + .writev = cifs_file_writev, + .aio_read = generic_file_aio_read, + .aio_write = cifs_file_aio_write, .open = cifs_open, .release = cifs_close, .lock = cifs_lock, @@ -603,15 +597,12 @@ struct file_operations cifs_file_ops = { .flush = cifs_flush, .mmap = cifs_file_mmap, .sendfile = generic_file_sendfile, + .llseek = cifs_llseek, #ifdef CONFIG_CIFS_POSIX .ioctl = cifs_ioctl, #endif /* CONFIG_CIFS_POSIX */ #ifdef CONFIG_CIFS_EXPERIMENTAL - .readv = generic_file_readv, - .writev = generic_file_writev, - .aio_read = generic_file_aio_read, - .aio_write = generic_file_aio_write, .dir_notify = cifs_dir_notify, #endif /* CONFIG_CIFS_EXPERIMENTAL */ }; @@ -630,12 +621,53 @@ struct file_operations cifs_file_direct_ops = { #ifdef CONFIG_CIFS_POSIX .ioctl = cifs_ioctl, #endif /* CONFIG_CIFS_POSIX */ + .llseek = cifs_llseek, +#ifdef CONFIG_CIFS_EXPERIMENTAL + .dir_notify = cifs_dir_notify, +#endif /* CONFIG_CIFS_EXPERIMENTAL */ +}; +struct file_operations cifs_file_nobrl_ops = { + .read = do_sync_read, + .write = do_sync_write, + .readv = generic_file_readv, + .writev = cifs_file_writev, + .aio_read = generic_file_aio_read, + .aio_write = cifs_file_aio_write, + .open = cifs_open, + .release = cifs_close, + .fsync = cifs_fsync, + .flush = cifs_flush, + .mmap = cifs_file_mmap, + .sendfile = generic_file_sendfile, + .llseek = cifs_llseek, +#ifdef CONFIG_CIFS_POSIX + .ioctl = cifs_ioctl, +#endif /* CONFIG_CIFS_POSIX */ #ifdef CONFIG_CIFS_EXPERIMENTAL .dir_notify = cifs_dir_notify, #endif /* CONFIG_CIFS_EXPERIMENTAL */ }; +struct file_operations cifs_file_direct_nobrl_ops = { + /* no mmap, no aio, no readv - + BB reevaluate whether they can be done with directio, no cache */ + .read = cifs_user_read, + .write = cifs_user_write, + .open = cifs_open, + .release = cifs_close, + .fsync = cifs_fsync, + .flush = cifs_flush, + .sendfile = generic_file_sendfile, /* BB removeme BB */ +#ifdef CONFIG_CIFS_POSIX + .ioctl = cifs_ioctl, +#endif /* CONFIG_CIFS_POSIX */ + .llseek = cifs_llseek, +#ifdef CONFIG_CIFS_EXPERIMENTAL + .dir_notify = cifs_dir_notify, +#endif /* CONFIG_CIFS_EXPERIMENTAL */ +}; + struct file_operations cifs_dir_ops = { .readdir = cifs_readdir, .release = cifs_closedir, @@ -714,7 +746,7 @@ cifs_init_request_bufs(void) kmem_cache_destroy(cifs_req_cachep); return -ENOMEM; } - /* 256 (MAX_CIFS_HDR_SIZE bytes is enough for most SMB responses and + /* MAX_CIFS_SMALL_BUFFER_SIZE bytes is enough for most SMB responses and almost all handle based requests (but not write response, nor is it sufficient for path based requests). A smaller size would have been more efficient (compacting multiple slab items on one 4k page) @@ -723,7 +755,8 @@ cifs_init_request_bufs(void) efficient to alloc 1 per page off the slab compared to 17K (5page) alloc of large cifs buffers even when page debugging is on */ cifs_sm_req_cachep = kmem_cache_create("cifs_small_rq", - MAX_CIFS_HDR_SIZE, 0, SLAB_HWCACHE_ALIGN, NULL, NULL); + MAX_CIFS_SMALL_BUFFER_SIZE, 0, SLAB_HWCACHE_ALIGN, + NULL, NULL); if (cifs_sm_req_cachep == NULL) { mempool_destroy(cifs_req_poolp); kmem_cache_destroy(cifs_req_cachep); @@ -841,9 +874,9 @@ static int cifs_oplock_thread(void * dummyarg) DeleteOplockQEntry(oplock_item); /* can not grab inode sem here since it would deadlock when oplock received on delete - since vfs_unlink holds the i_sem across + since vfs_unlink holds the i_mutex across the call */ - /* down(&inode->i_sem);*/ + /* mutex_lock(&inode->i_mutex);*/ if (S_ISREG(inode->i_mode)) { rc = filemap_fdatawrite(inode->i_mapping); if(CIFS_I(inode)->clientCanCacheRead == 0) { @@ -852,7 +885,7 @@ static int cifs_oplock_thread(void * dummyarg) } } else rc = 0; - /* up(&inode->i_sem);*/ + /* mutex_unlock(&inode->i_mutex);*/ if (rc) CIFS_I(inode)->write_behind_rc = rc; cFYI(1,("Oplock flush inode %p rc %d",inode,rc)); @@ -882,6 +915,9 @@ static int cifs_oplock_thread(void * dummyarg) static int cifs_dnotify_thread(void * dummyarg) { + struct list_head *tmp; + struct cifsSesInfo *ses; + daemonize("cifsdnotifyd"); allow_signal(SIGTERM); @@ -890,7 +926,19 @@ static int cifs_dnotify_thread(void * dummyarg) if(try_to_freeze()) continue; set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(39*HZ); + schedule_timeout(15*HZ); + read_lock(&GlobalSMBSeslock); + /* check if any stuck requests that need + to be woken up and wakeq so the + thread can wake up and error out */ + list_for_each(tmp, &GlobalSMBSessionList) { + ses = list_entry(tmp, struct cifsSesInfo, + cifsSessionList); + if(ses && ses->server && + atomic_read(&ses->server->inFlight)) + wake_up_all(&ses->server->response_q); + } + read_unlock(&GlobalSMBSeslock); } while(!signal_pending(current)); complete_and_exit (&cifs_dnotify_exited, 0); } @@ -920,6 +968,12 @@ init_cifs(void) atomic_set(&tconInfoReconnectCount, 0); atomic_set(&bufAllocCount, 0); + atomic_set(&smBufAllocCount, 0); +#ifdef CONFIG_CIFS_STATS2 + atomic_set(&totBufAllocCount, 0); + atomic_set(&totSmBufAllocCount, 0); +#endif /* CONFIG_CIFS_STATS2 */ + atomic_set(&midCount, 0); GlobalCurrentXid = 0; GlobalTotalActiveXid = 0; diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 1223fa8..821a8eb 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -63,6 +63,8 @@ extern struct inode_operations cifs_symlink_inode_ops; /* Functions related to files and directories */ extern struct file_operations cifs_file_ops; extern struct file_operations cifs_file_direct_ops; /* if directio mount */ +extern struct file_operations cifs_file_nobrl_ops; +extern struct file_operations cifs_file_direct_nobrl_ops; /* if directio mount */ extern int cifs_open(struct inode *inode, struct file *file); extern int cifs_close(struct inode *inode, struct file *file); extern int cifs_closedir(struct inode *inode, struct file *file); @@ -97,5 +99,5 @@ extern ssize_t cifs_getxattr(struct dentry *, const char *, void *, size_t); extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); extern int cifs_ioctl (struct inode * inode, struct file * filep, unsigned int command, unsigned long arg); -#define CIFS_VERSION "1.39" +#define CIFS_VERSION "1.40" #endif /* _CIFSFS_H */ diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 1ba08f8..7bed276 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -233,6 +233,8 @@ struct cifsTconInfo { atomic_t num_hardlinks; atomic_t num_symlinks; atomic_t num_locks; + atomic_t num_acl_get; + atomic_t num_acl_set; #ifdef CONFIG_CIFS_STATS2 unsigned long long time_writes; unsigned long long time_reads; @@ -285,6 +287,7 @@ struct cifs_search_info { unsigned endOfSearch:1; unsigned emptyDir:1; unsigned unicode:1; + unsigned smallBuf:1; /* so we know which buf_release function to call */ }; struct cifsFileInfo { @@ -420,7 +423,12 @@ struct dir_notify_req { #define MID_RESPONSE_RECEIVED 4 #define MID_RETRY_NEEDED 8 /* session closed while this request out */ #define MID_NO_RESP_NEEDED 0x10 -#define MID_SMALL_BUFFER 0x20 /* 112 byte response buffer instead of 4K */ + +/* Types of response buffer returned from SendReceive2 */ +#define CIFS_NO_BUFFER 0 /* Response buffer not returned */ +#define CIFS_SMALL_BUFFER 1 +#define CIFS_LARGE_BUFFER 2 +#define CIFS_IOVEC 4 /* array of response buffers */ /* ***************************************************************** @@ -505,8 +513,12 @@ GLOBAL_EXTERN atomic_t tcpSesReconnectCount; GLOBAL_EXTERN atomic_t tconInfoReconnectCount; /* Various Debug counters to remove someday (BB) */ -GLOBAL_EXTERN atomic_t bufAllocCount; -GLOBAL_EXTERN atomic_t smBufAllocCount; +GLOBAL_EXTERN atomic_t bufAllocCount; /* current number allocated */ +#ifdef CONFIG_CIFS_STATS2 +GLOBAL_EXTERN atomic_t totBufAllocCount; /* total allocated over all time */ +GLOBAL_EXTERN atomic_t totSmBufAllocCount; +#endif +GLOBAL_EXTERN atomic_t smBufAllocCount; GLOBAL_EXTERN atomic_t midCount; /* Misc globals */ diff --git a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h index 48a05b9..cc24710 100644 --- a/fs/cifs/cifspdu.h +++ b/fs/cifs/cifspdu.h @@ -1,7 +1,7 @@ /* * fs/cifs/cifspdu.h * - * Copyright (c) International Business Machines Corp., 2002 + * Copyright (c) International Business Machines Corp., 2002,2005 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -80,7 +80,11 @@ #define NT_TRANSACT_GET_USER_QUOTA 0x07 #define NT_TRANSACT_SET_USER_QUOTA 0x08 -#define MAX_CIFS_HDR_SIZE 256 /* is future chained NTCreateXReadX bigger? */ +#define MAX_CIFS_SMALL_BUFFER_SIZE 448 /* big enough for most */ +/* future chained NTCreateXReadX bigger, but for time being NTCreateX biggest */ +/* among the requests (NTCreateX response is bigger with wct of 34) */ +#define MAX_CIFS_HDR_SIZE 0x58 /* 4 len + 32 hdr + (2*24 wct) + 2 bct + 2 pad */ +#define CIFS_SMALL_PATH 120 /* allows for (448-88)/3 */ /* internal cifs vfs structures */ /***************************************************************** @@ -524,7 +528,7 @@ typedef union smb_com_session_setup_andx { /* STRING PrimaryDomain */ /* STRING NativeOS */ /* STRING NativeLanMan */ - } __attribute__((packed)) old_req; /* pre-NTLM (LANMAN2.1) request format */ + } __attribute__((packed)) old_req; /* pre-NTLM (LANMAN2.1) req format */ struct { /* default (NTLM) response format */ struct smb_hdr hdr; /* wct = 3 */ @@ -536,7 +540,7 @@ typedef union smb_com_session_setup_andx { unsigned char NativeOS[1]; /* followed by */ /* unsigned char * NativeLanMan; */ /* unsigned char * PrimaryDomain; */ - } __attribute__((packed)) old_resp; /* pre-NTLM (LANMAN2.1) response format */ + } __attribute__((packed)) old_resp; /* pre-NTLM (LANMAN2.1) response */ } __attribute__((packed)) SESSION_SETUP_ANDX; #define CIFS_NETWORK_OPSYS "CIFS VFS Client for Linux" @@ -603,7 +607,9 @@ typedef struct smb_com_logoff_andx_rsp { __u16 ByteCount; } __attribute__((packed)) LOGOFF_ANDX_RSP; -typedef union smb_com_tree_disconnect { /* as an altetnative can use flag on tree_connect PDU to effect disconnect *//* probably the simplest SMB PDU */ +typedef union smb_com_tree_disconnect { /* as an altetnative can use flag on + tree_connect PDU to effect disconnect */ + /* tdis is probably simplest SMB PDU */ struct { struct smb_hdr hdr; /* wct = 0 */ __u16 ByteCount; /* bcc = 0 */ @@ -1001,10 +1007,49 @@ typedef struct smb_com_setattr_rsp { /* empty wct response to setattr */ -/***************************************************/ -/* NT Transact structure defintions follow */ -/* Currently only ioctl and notify are implemented */ -/***************************************************/ +/*******************************************************/ +/* NT Transact structure defintions follow */ +/* Currently only ioctl, acl (get security descriptor) */ +/* and notify are implemented */ +/*******************************************************/ +typedef struct smb_com_ntransact_req { + struct smb_hdr hdr; /* wct >= 19 */ + __u8 MaxSetupCount; + __u16 Reserved; + __le32 TotalParameterCount; + __le32 TotalDataCount; + __le32 MaxParameterCount; + __le32 MaxDataCount; + __le32 ParameterCount; + __le32 ParameterOffset; + __le32 DataCount; + __le32 DataOffset; + __u8 SetupCount; /* four setup words follow subcommand */ + /* SNIA spec incorrectly included spurious pad here */ + __le16 SubCommand; /* 2 = IOCTL/FSCTL */ + /* SetupCount words follow then */ + __le16 ByteCount; + __u8 Pad[3]; + __u8 Parms[0]; +} __attribute__((packed)) NTRANSACT_REQ; + +typedef struct smb_com_ntransact_rsp { + struct smb_hdr hdr; /* wct = 18 */ + __u8 Reserved[3]; + __le32 TotalParameterCount; + __le32 TotalDataCount; + __le32 ParameterCount; + __le32 ParameterOffset; + __le32 ParameterDisplacement; + __le32 DataCount; + __le32 DataOffset; + __le32 DataDisplacement; + __u8 SetupCount; /* 0 */ + __u16 ByteCount; + /* __u8 Pad[3]; */ + /* parms and data follow */ +} __attribute__((packed)) NTRANSACT_RSP; + typedef struct smb_com_transaction_ioctl_req { struct smb_hdr hdr; /* wct = 23 */ __u8 MaxSetupCount; @@ -1019,11 +1064,11 @@ typedef struct smb_com_transaction_ioctl_req { __le32 DataOffset; __u8 SetupCount; /* four setup words follow subcommand */ /* SNIA spec incorrectly included spurious pad here */ - __le16 SubCommand;/* 2 = IOCTL/FSCTL */ + __le16 SubCommand; /* 2 = IOCTL/FSCTL */ __le32 FunctionCode; __u16 Fid; - __u8 IsFsctl; /* 1 = File System Control, 0 = device control (IOCTL)*/ - __u8 IsRootFlag; /* 1 = apply command to root of share (must be DFS share)*/ + __u8 IsFsctl; /* 1 = File System Control 0 = device control (IOCTL) */ + __u8 IsRootFlag; /* 1 = apply command to root of share (must be DFS) */ __le16 ByteCount; __u8 Pad[3]; __u8 Data[1]; @@ -1043,9 +1088,35 @@ typedef struct smb_com_transaction_ioctl_rsp { __u8 SetupCount; /* 1 */ __le16 ReturnedDataLen; __u16 ByteCount; - __u8 Pad[3]; } __attribute__((packed)) TRANSACT_IOCTL_RSP; +#define CIFS_ACL_OWNER 1 +#define CIFS_ACL_GROUP 2 +#define CIFS_ACL_DACL 4 +#define CIFS_ACL_SACL 8 + +typedef struct smb_com_transaction_qsec_req { + struct smb_hdr hdr; /* wct = 19 */ + __u8 MaxSetupCount; + __u16 Reserved; + __le32 TotalParameterCount; + __le32 TotalDataCount; + __le32 MaxParameterCount; + __le32 MaxDataCount; + __le32 ParameterCount; + __le32 ParameterOffset; + __le32 DataCount; + __le32 DataOffset; + __u8 SetupCount; /* no setup words follow subcommand */ + /* SNIA spec incorrectly included spurious pad here */ + __le16 SubCommand; /* 6 = QUERY_SECURITY_DESC */ + __le16 ByteCount; /* bcc = 3 + 8 */ + __u8 Pad[3]; + __u16 Fid; + __u16 Reserved2; + __le32 AclFlags; +} __attribute__((packed)) QUERY_SEC_DESC_REQ; + typedef struct smb_com_transaction_change_notify_req { struct smb_hdr hdr; /* wct = 23 */ __u8 MaxSetupCount; @@ -1066,10 +1137,12 @@ typedef struct smb_com_transaction_change_notify_req { __u8 WatchTree; /* 1 = Monitor subdirectories */ __u8 Reserved2; __le16 ByteCount; -/* __u8 Pad[3];*/ +/* __u8 Pad[3];*/ /* __u8 Data[1];*/ } __attribute__((packed)) TRANSACT_CHANGE_NOTIFY_REQ; +/* BB eventually change to use generic ntransact rsp struct + and validation routine */ typedef struct smb_com_transaction_change_notify_rsp { struct smb_hdr hdr; /* wct = 18 */ __u8 Reserved[3]; @@ -2025,6 +2098,12 @@ typedef struct { } __attribute__((packed)) FILE_BOTH_DIRECTORY_INFO; /* level 0x104 FF response data area */ +struct win_dev { + unsigned char type[8]; /* IntxCHR or IntxBLK */ + __le64 major; + __le64 minor; +} __attribute__((packed)); + struct gea { unsigned char name_len; char name[1]; diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index 1b73f4f..3c03aad 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h @@ -48,8 +48,8 @@ extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *, struct smb_hdr * /* out */ , int * /* bytes returned */ , const int long_op); extern int SendReceive2(const unsigned int /* xid */ , struct cifsSesInfo *, - struct kvec *, int /* nvec */, - int * /* bytes returned */ , const int long_op); + struct kvec *, int /* nvec to send */, + int * /* type of buf returned */ , const int long_op); extern int checkSMBhdr(struct smb_hdr *smb, __u16 mid); extern int checkSMB(struct smb_hdr *smb, __u16 mid, int length); extern int is_valid_oplock_break(struct smb_hdr *smb); @@ -93,11 +93,12 @@ extern int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, const struct nls_table *); extern int CIFSFindFirst(const int xid, struct cifsTconInfo *tcon, - const char *searchName, const struct nls_table *nls_codepage, - __u16 *searchHandle, struct cifs_search_info * psrch_inf, int map, const char dirsep); + const char *searchName, const struct nls_table *nls_codepage, + __u16 *searchHandle, struct cifs_search_info * psrch_inf, + int map, const char dirsep); extern int CIFSFindNext(const int xid, struct cifsTconInfo *tcon, - __u16 searchHandle, struct cifs_search_info * psrch_inf); + __u16 searchHandle, struct cifs_search_info * psrch_inf); extern int CIFSFindClose(const int, struct cifsTconInfo *tcon, const __u16 search_handle); @@ -230,19 +231,18 @@ extern int CIFSSMBClose(const int xid, struct cifsTconInfo *tcon, const int smb_file_id); extern int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, - const int netfid, unsigned int count, - const __u64 lseek, unsigned int *nbytes, char **buf); + const int netfid, unsigned int count, + const __u64 lseek, unsigned int *nbytes, char **buf, + int * return_buf_type); extern int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, const int netfid, const unsigned int count, const __u64 lseek, unsigned int *nbytes, const char *buf, const char __user *ubuf, const int long_op); -#ifdef CONFIG_CIFS_EXPERIMENTAL extern int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, const int netfid, const unsigned int count, const __u64 offset, unsigned int *nbytes, struct kvec *iov, const int nvec, const int long_op); -#endif /* CONFIG_CIFS_EXPERIMENTAL */ extern int CIFSGetSrvInodeNumber(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, __u64 * inode_number, const struct nls_table *nls_codepage, @@ -269,6 +269,8 @@ extern void tconInfoFree(struct cifsTconInfo *); extern int cifs_reconnect(struct TCP_Server_Info *server); extern int cifs_sign_smb(struct smb_hdr *, struct TCP_Server_Info *,__u32 *); +extern int cifs_sign_smb2(struct kvec *iov, int n_vec, struct TCP_Server_Info *, + __u32 *); extern int cifs_verify_signature(struct smb_hdr *, const char * mac_key, __u32 expected_sequence_number); extern int cifs_calculate_mac_key(char * key,const char * rn,const char * pass); @@ -297,6 +299,9 @@ extern int CIFSSMBSetEA(const int xid, struct cifsTconInfo *tcon, const char *fileName, const char * ea_name, const void * ea_value, const __u16 ea_value_len, const struct nls_table *nls_codepage, int remap_special_chars); +extern int CIFSSMBGetCIFSACL(const int xid, struct cifsTconInfo *tcon, + __u16 fid, char *acl_inf, const int buflen, + const int acl_type /* ACCESS vs. DEFAULT */); extern int CIFSSMBGetPosixACL(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, char *acl_inf, const int buflen,const int acl_type, diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c index a53c596..217323b 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c @@ -37,6 +37,7 @@ #include "cifsproto.h" #include "cifs_unicode.h" #include "cifs_debug.h" +#include "cifsacl.h" #ifdef CONFIG_CIFS_POSIX static struct { @@ -90,6 +91,18 @@ small_smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, check for tcp and smb session status done differently for those three - in the calling routine */ if(tcon) { + if(tcon->tidStatus == CifsExiting) { + /* only tree disconnect, open, and write, + (and ulogoff which does not have tcon) + are allowed as we start force umount */ + if((smb_command != SMB_COM_WRITE_ANDX) && + (smb_command != SMB_COM_OPEN_ANDX) && + (smb_command != SMB_COM_TREE_DISCONNECT)) { + cFYI(1,("can not send cmd %d while umounting", + smb_command)); + return -ENODEV; + } + } if((tcon->ses) && (tcon->ses->status != CifsExiting) && (tcon->ses->server)){ struct nls_table *nls_codepage; @@ -187,6 +200,19 @@ smb_init(int smb_command, int wct, struct cifsTconInfo *tcon, check for tcp and smb session status done differently for those three - in the calling routine */ if(tcon) { + if(tcon->tidStatus == CifsExiting) { + /* only tree disconnect, open, and write, + (and ulogoff which does not have tcon) + are allowed as we start force umount */ + if((smb_command != SMB_COM_WRITE_ANDX) && + (smb_command != SMB_COM_OPEN_ANDX) && + (smb_command != SMB_COM_TREE_DISCONNECT)) { + cFYI(1,("can not send cmd %d while umounting", + smb_command)); + return -ENODEV; + } + } + if((tcon->ses) && (tcon->ses->status != CifsExiting) && (tcon->ses->server)){ struct nls_table *nls_codepage; @@ -347,8 +373,10 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) rc = SendReceive(xid, ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); if (rc == 0) { - server->secMode = pSMBr->SecurityMode; - server->secType = NTLM; /* BB override default for + server->secMode = pSMBr->SecurityMode; + if((server->secMode & SECMODE_USER) == 0) + cFYI(1,("share mode security")); + server->secType = NTLM; /* BB override default for NTLMv2 or kerberos v5 */ /* one byte - no need to convert this or EncryptionKeyLen from little endian */ @@ -358,7 +386,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) min(le32_to_cpu(pSMBr->MaxBufferSize), (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE); server->maxRw = le32_to_cpu(pSMBr->MaxRawSize); - cFYI(0, ("Max buf = %d ", ses->server->maxBuf)); + cFYI(0, ("Max buf = %d", ses->server->maxBuf)); GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey); server->capabilities = le32_to_cpu(pSMBr->Capabilities); server->timeZone = le16_to_cpu(pSMBr->ServerTimeZone); @@ -386,8 +414,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses) (server->server_GUID, pSMBr->u.extended_response. GUID, 16) != 0) { - cFYI(1, - ("UID of server does not match previous connection to same ip address")); + cFYI(1, ("server UID changed")); memcpy(server-> server_GUID, pSMBr->u. @@ -933,21 +960,19 @@ openRetry: return rc; } -/* If no buffer passed in, then caller wants to do the copy - as in the case of readpages so the SMB buffer must be - freed by the caller */ - int CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, - const int netfid, const unsigned int count, - const __u64 lseek, unsigned int *nbytes, char **buf) + const int netfid, const unsigned int count, + const __u64 lseek, unsigned int *nbytes, char **buf, + int * pbuf_type) { int rc = -EACCES; READ_REQ *pSMB = NULL; READ_RSP *pSMBr = NULL; char *pReadData = NULL; - int bytes_returned; int wct; + int resp_buf_type = 0; + struct kvec iov[1]; cFYI(1,("Reading %d bytes on fid %d",count,netfid)); if(tcon->ses->capabilities & CAP_LARGE_FILES) @@ -956,8 +981,7 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, wct = 10; /* old style read */ *nbytes = 0; - rc = smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB, - (void **) &pSMBr); + rc = small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **) &pSMB); if (rc) return rc; @@ -965,13 +989,13 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, if (tcon->ses->server == NULL) return -ECONNABORTED; - pSMB->AndXCommand = 0xFF; /* none */ + pSMB->AndXCommand = 0xFF; /* none */ pSMB->Fid = netfid; pSMB->OffsetLow = cpu_to_le32(lseek & 0xFFFFFFFF); if(wct == 12) pSMB->OffsetHigh = cpu_to_le32(lseek >> 32); - else if((lseek >> 32) > 0) /* can not handle this big offset for old */ - return -EIO; + else if((lseek >> 32) > 0) /* can not handle this big offset for old */ + return -EIO; pSMB->Remaining = 0; pSMB->MaxCount = cpu_to_le16(count & 0xFFFF); @@ -980,14 +1004,18 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, pSMB->ByteCount = 0; /* no need to do le conversion since 0 */ else { /* old style read */ - struct smb_com_readx_req * pSMBW = + struct smb_com_readx_req * pSMBW = (struct smb_com_readx_req *)pSMB; - pSMBW->ByteCount = 0; + pSMBW->ByteCount = 0; } - - rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, - (struct smb_hdr *) pSMBr, &bytes_returned, 0); + + 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); cifs_stats_inc(&tcon->num_reads); + pSMBr = (READ_RSP *)iov[0].iov_base; if (rc) { cERROR(1, ("Send error in read = %d", rc)); } else { @@ -997,33 +1025,43 @@ CIFSSMBRead(const int xid, struct cifsTconInfo *tcon, *nbytes = data_length; /*check that DataLength would not go beyond end of SMB */ - if ((data_length > CIFSMaxBufSize) + if ((data_length > CIFSMaxBufSize) || (data_length > count)) { cFYI(1,("bad length %d for count %d",data_length,count)); rc = -EIO; *nbytes = 0; } else { - pReadData = - (char *) (&pSMBr->hdr.Protocol) + + pReadData = (char *) (&pSMBr->hdr.Protocol) + 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*/ +/* 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*/ if(*buf) - memcpy(*buf,pReadData,data_length); + memcpy(*buf,pReadData,data_length); } } - if(*buf) - cifs_buf_release(pSMB); - else - *buf = (char *)pSMB; - /* Note: On -EAGAIN error only caller can retry on handle based calls + cifs_small_buf_release(pSMB); + if(*buf) { + if(resp_buf_type == CIFS_SMALL_BUFFER) + cifs_small_buf_release(iov[0].iov_base); + else if(resp_buf_type == CIFS_LARGE_BUFFER) + cifs_buf_release(iov[0].iov_base); + } else /* return buffer to caller to free */ /* BB FIXME how do we tell caller if it is not a large buffer */ { + *buf = iov[0].iov_base; + if(resp_buf_type == CIFS_SMALL_BUFFER) + *pbuf_type = CIFS_SMALL_BUFFER; + else if(resp_buf_type == CIFS_LARGE_BUFFER) + *pbuf_type = CIFS_LARGE_BUFFER; + } + + /* Note: On -EAGAIN error only caller can retry on handle based calls since file handle passed in no longer valid */ return rc; } + int CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, const int netfid, const unsigned int count, @@ -1130,7 +1168,6 @@ CIFSSMBWrite(const int xid, struct cifsTconInfo *tcon, return rc; } -#ifdef CONFIG_CIFS_EXPERIMENTAL int CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, const int netfid, const unsigned int count, @@ -1139,10 +1176,12 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, { int rc = -EACCES; WRITE_REQ *pSMB = NULL; - int bytes_returned, wct; + int wct; int smb_hdr_len; + int resp_buf_type = 0; + + cFYI(1,("write2 at %lld %d bytes", (long long)offset, count)); - cFYI(1,("write2 at %lld %d bytes",offset,count)); /* BB removeme BB */ if(tcon->ses->capabilities & CAP_LARGE_FILES) wct = 14; else @@ -1183,22 +1222,34 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, pSMBW->ByteCount = cpu_to_le16(count + 5); } iov[0].iov_base = pSMB; - iov[0].iov_len = smb_hdr_len + 4; + if(wct == 14) + iov[0].iov_len = smb_hdr_len + 4; + else /* wct == 12 pad bigger by four bytes */ + iov[0].iov_len = smb_hdr_len + 8; + - rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &bytes_returned, + rc = SendReceive2(xid, tcon->ses, iov, n_vec + 1, &resp_buf_type, long_op); cifs_stats_inc(&tcon->num_writes); if (rc) { cFYI(1, ("Send error Write2 = %d", rc)); *nbytes = 0; + } else if(resp_buf_type == 0) { + /* presumably this can not happen, but best to be safe */ + rc = -EIO; + *nbytes = 0; } else { - WRITE_RSP * pSMBr = (WRITE_RSP *)pSMB; + WRITE_RSP * pSMBr = (WRITE_RSP *)iov[0].iov_base; *nbytes = le16_to_cpu(pSMBr->CountHigh); *nbytes = (*nbytes) << 16; *nbytes += le16_to_cpu(pSMBr->Count); - } + } cifs_small_buf_release(pSMB); + if(resp_buf_type == CIFS_SMALL_BUFFER) + cifs_small_buf_release(iov[0].iov_base); + else if(resp_buf_type == CIFS_LARGE_BUFFER) + cifs_buf_release(iov[0].iov_base); /* Note: On -EAGAIN error only caller can retry on handle based calls since file handle passed in no longer valid */ @@ -1207,8 +1258,6 @@ CIFSSMBWrite2(const int xid, struct cifsTconInfo *tcon, } -#endif /* CIFS_EXPERIMENTAL */ - int CIFSSMBLock(const int xid, struct cifsTconInfo *tcon, const __u16 smb_file_id, const __u64 len, @@ -1553,7 +1602,7 @@ createSymLinkRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, fromName, PATH_MAX + cifs_strtoUCS((__le16 *) pSMB->FileName, fromName, PATH_MAX /* find define for this maxpathcomponent */ , nls_codepage); name_len++; /* trailing null */ @@ -1577,7 +1626,7 @@ createSymLinkRetry: data_offset = (char *) (&pSMB->hdr.Protocol) + offset; if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len_target = - cifs_strtoUCS((wchar_t *) data_offset, toName, PATH_MAX + cifs_strtoUCS((__le16 *) data_offset, toName, PATH_MAX /* find define for this maxpathcomponent */ , nls_codepage); name_len_target++; /* trailing null */ @@ -1803,7 +1852,7 @@ querySymLinkRetry: if (pSMB->hdr.Flags2 & SMBFLG2_UNICODE) { name_len = - cifs_strtoUCS((wchar_t *) pSMB->FileName, searchName, PATH_MAX + cifs_strtoUCS((__le16 *) pSMB->FileName, searchName, PATH_MAX /* find define for this maxpathcomponent */ , nls_codepage); name_len++; /* trailing null */ @@ -1860,7 +1909,7 @@ querySymLinkRetry: min_t(const int, buflen,count) / 2); /* BB FIXME investigate remapping reserved chars here */ cifs_strfromUCS_le(symlinkinfo, - (wchar_t *) ((char *)&pSMBr->hdr.Protocol + + (__le16 *) ((char *)&pSMBr->hdr.Protocol + data_offset), name_len, nls_codepage); } else { @@ -1879,6 +1928,90 @@ querySymLinkRetry: return rc; } +/* Initialize NT TRANSACT SMB into small smb request buffer. + This assumes that all NT TRANSACTS that we init here have + total parm and data under about 400 bytes (to fit in small cifs + buffer size), which is the case so far, it easily fits. NB: + Setup words themselves and ByteCount + MaxSetupCount (size of returned setup area) and + MaxParameterCount (returned parms size) must be set by caller */ +static int +smb_init_ntransact(const __u16 sub_command, const int setup_count, + const int parm_len, struct cifsTconInfo *tcon, + void ** ret_buf) +{ + int rc; + __u32 temp_offset; + struct smb_com_ntransact_req * pSMB; + + rc = small_smb_init(SMB_COM_NT_TRANSACT, 19 + setup_count, tcon, + (void **)&pSMB); + if (rc) + return rc; + *ret_buf = (void *)pSMB; + pSMB->Reserved = 0; + pSMB->TotalParameterCount = cpu_to_le32(parm_len); + pSMB->TotalDataCount = 0; + pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf - + MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); + pSMB->ParameterCount = pSMB->TotalParameterCount; + pSMB->DataCount = pSMB->TotalDataCount; + temp_offset = offsetof(struct smb_com_ntransact_req, Parms) + + (setup_count * 2) - 4 /* for rfc1001 length itself */; + pSMB->ParameterOffset = cpu_to_le32(temp_offset); + pSMB->DataOffset = cpu_to_le32(temp_offset + parm_len); + pSMB->SetupCount = setup_count; /* no need to le convert byte fields */ + pSMB->SubCommand = cpu_to_le16(sub_command); + return 0; +} + +static int +validate_ntransact(char * buf, char ** ppparm, char ** ppdata, + int * pdatalen, int * pparmlen) +{ + char * end_of_smb; + __u32 data_count, data_offset, parm_count, parm_offset; + struct smb_com_ntransact_rsp * pSMBr; + + if(buf == NULL) + return -EINVAL; + + pSMBr = (struct smb_com_ntransact_rsp *)buf; + + /* ByteCount was converted from little endian in SendReceive */ + end_of_smb = 2 /* sizeof byte count */ + pSMBr->ByteCount + + (char *)&pSMBr->ByteCount; + + + data_offset = le32_to_cpu(pSMBr->DataOffset); + data_count = le32_to_cpu(pSMBr->DataCount); + parm_offset = le32_to_cpu(pSMBr->ParameterOffset); + parm_count = le32_to_cpu(pSMBr->ParameterCount); + + *ppparm = (char *)&pSMBr->hdr.Protocol + parm_offset; + *ppdata = (char *)&pSMBr->hdr.Protocol + data_offset; + + /* should we also check that parm and data areas do not overlap? */ + if(*ppparm > end_of_smb) { + cFYI(1,("parms start after end of smb")); + return -EINVAL; + } else if(parm_count + *ppparm > end_of_smb) { + cFYI(1,("parm end after end of smb")); + return -EINVAL; + } else if(*ppdata > end_of_smb) { + 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", + *ppdata, data_count, (data_count + *ppdata), end_of_smb, pSMBr)); /* BB FIXME */ + return -EINVAL; + } else if(parm_count + data_count > pSMBr->ByteCount) { + cFYI(1,("parm count and data count larger than SMB")); + return -EINVAL; + } + return 0; +} + int CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, const unsigned char *searchName, @@ -1901,7 +2034,8 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, pSMB->TotalDataCount = 0; pSMB->MaxParameterCount = cpu_to_le32(2); /* BB find exact data count max from sess structure BB */ - pSMB->MaxDataCount = cpu_to_le32(4000); + pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf - + MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); pSMB->MaxSetupCount = 4; pSMB->Reserved = 0; pSMB->ParameterOffset = 0; @@ -1928,7 +2062,9 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, rc = -EIO; /* bad smb */ else { if(data_count && (data_count < 2048)) { - char * end_of_smb = pSMBr->ByteCount + (char *)&pSMBr->ByteCount; + char * end_of_smb = 2 /* sizeof byte count */ + + pSMBr->ByteCount + + (char *)&pSMBr->ByteCount; struct reparse_data * reparse_buf = (struct reparse_data *) ((char *)&pSMBr->hdr.Protocol + data_offset); @@ -1951,7 +2087,7 @@ CIFSSMBQueryReparseLinkInfo(const int xid, struct cifsTconInfo *tcon, reparse_buf->TargetNameOffset), min(buflen/2, reparse_buf->TargetNameLen / 2)); cifs_strfromUCS_le(symlinkinfo, - (wchar_t *) (reparse_buf->LinkNamesBuf + + (__le16 *) (reparse_buf->LinkNamesBuf + reparse_buf->TargetNameOffset), name_len, nls_codepage); } else { /* ASCII names */ @@ -1983,9 +2119,9 @@ qreparse_out: static void cifs_convert_ace(posix_acl_xattr_entry * ace, struct cifs_posix_ace * cifs_ace) { /* u8 cifs fields do not need le conversion */ - ace->e_perm = (__u16)cifs_ace->cifs_e_perm; - ace->e_tag = (__u16)cifs_ace->cifs_e_tag; - ace->e_id = (__u32)le64_to_cpu(cifs_ace->cifs_uid); + ace->e_perm = cpu_to_le16(cifs_ace->cifs_e_perm); + ace->e_tag = cpu_to_le16(cifs_ace->cifs_e_tag); + ace->e_id = cpu_to_le32(le64_to_cpu(cifs_ace->cifs_uid)); /* cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id)); */ return; @@ -2037,7 +2173,7 @@ static int cifs_copy_posix_acl(char * trgt,char * src, const int buflen, } else if(size > buflen) { return -ERANGE; } else /* buffer big enough */ { - local_acl->a_version = POSIX_ACL_XATTR_VERSION; + local_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION); for(i = 0;i < count ;i++) { cifs_convert_ace(&local_acl->a_entries[i],pACE); pACE ++; @@ -2051,14 +2187,14 @@ static __u16 convert_ace_to_cifs_ace(struct cifs_posix_ace * cifs_ace, { __u16 rc = 0; /* 0 = ACL converted ok */ - cifs_ace->cifs_e_perm = (__u8)cpu_to_le16(local_ace->e_perm); - cifs_ace->cifs_e_tag = (__u8)cpu_to_le16(local_ace->e_tag); + cifs_ace->cifs_e_perm = le16_to_cpu(local_ace->e_perm); + cifs_ace->cifs_e_tag = le16_to_cpu(local_ace->e_tag); /* BB is there a better way to handle the large uid? */ - if(local_ace->e_id == -1) { + if(local_ace->e_id == cpu_to_le32(-1)) { /* Probably no need to le convert -1 on any arch but can not hurt */ cifs_ace->cifs_uid = cpu_to_le64(-1); } else - cifs_ace->cifs_uid = (__u64)cpu_to_le32(local_ace->e_id); + cifs_ace->cifs_uid = cpu_to_le64(le32_to_cpu(local_ace->e_id)); /*cFYI(1,("perm %d tag %d id %d",ace->e_perm,ace->e_tag,ace->e_id));*/ return rc; } @@ -2078,16 +2214,17 @@ static __u16 ACL_to_cifs_posix(char * parm_data,const char * pACL,const int bufl count = posix_acl_xattr_count((size_t)buflen); cFYI(1,("setting acl with %d entries from buf of length %d and version of %d", - count,buflen,local_acl->a_version)); - if(local_acl->a_version != 2) { - cFYI(1,("unknown POSIX ACL version %d",local_acl->a_version)); + count, buflen, le32_to_cpu(local_acl->a_version))); + if(le32_to_cpu(local_acl->a_version) != 2) { + cFYI(1,("unknown POSIX ACL version %d", + le32_to_cpu(local_acl->a_version))); return 0; } cifs_acl->version = cpu_to_le16(1); if(acl_type == ACL_TYPE_ACCESS) - cifs_acl->access_entry_count = count; + cifs_acl->access_entry_count = cpu_to_le16(count); else if(acl_type == ACL_TYPE_DEFAULT) - cifs_acl->default_entry_count = count; + cifs_acl->default_entry_count = cpu_to_le16(count); else { cFYI(1,("unknown ACL type %d",acl_type)); return 0; @@ -2171,6 +2308,7 @@ queryAclRetry: rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, (struct smb_hdr *) pSMBr, &bytes_returned, 0); + cifs_stats_inc(&tcon->num_acl_get); if (rc) { cFYI(1, ("Send error in Query POSIX ACL = %d", rc)); } else { @@ -2358,6 +2496,92 @@ GetExtAttrOut: #endif /* CONFIG_POSIX */ + +/* security id for everyone */ +const struct cifs_sid sid_everyone = {1, 1, {0, 0, 0, 0, 0, 0}, {0, 0, 0, 0}}; +/* group users */ +const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {32, 545, 0, 0}}; + +/* Convert CIFS ACL to POSIX form */ +static int parse_sec_desc(struct cifs_sid * psec_desc, int acl_len) +{ + 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 */) +{ + int rc = 0; + int buf_type = 0; + QUERY_SEC_DESC_REQ * pSMB; + struct kvec iov[1]; + + cFYI(1, ("GetCifsACL")); + + rc = smb_init_ntransact(NT_TRANSACT_QUERY_SECURITY_DESC, 0, + 8 /* parm len */, tcon, (void **) &pSMB); + if (rc) + return rc; + + pSMB->MaxParameterCount = cpu_to_le32(4); + /* BB TEST with big acls that might need to be e.g. larger than 16K */ + pSMB->MaxSetupCount = 0; + pSMB->Fid = fid; /* file handle always le */ + pSMB->AclFlags = cpu_to_le32(CIFS_ACL_OWNER | CIFS_ACL_GROUP | + CIFS_ACL_DACL); + pSMB->ByteCount = cpu_to_le16(11); /* 3 bytes pad + 8 bytes parm */ + pSMB->hdr.smb_buf_length += 11; + 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); + cifs_stats_inc(&tcon->num_acl_get); + if (rc) { + cFYI(1, ("Send error in QuerySecDesc = %d", rc)); + } else { /* decode response */ + struct cifs_sid * psec_desc; + __le32 * parm; + int parm_len; + int data_len; + int acl_len; + struct smb_com_ntransact_rsp * pSMBr; + +/* validate_nttransact */ + rc = validate_ntransact(iov[0].iov_base, (char **)&parm, + (char **)&psec_desc, + &parm_len, &data_len); + + if(rc) + 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 */ + + if (le32_to_cpu(pSMBr->ParameterCount) != 4) { + rc = -EIO; /* bad smb */ + goto qsec_out; + } + +/* BB check that data area is minimum length and as big as acl_len */ + + acl_len = le32_to_cpu(*(__le32 *)parm); + /* BB check if(acl_len > bufsize) */ + + parse_sec_desc(psec_desc, acl_len); + } +qsec_out: + if(buf_type == CIFS_SMALL_BUFFER) + cifs_small_buf_release(iov[0].iov_base); + else if(buf_type == CIFS_LARGE_BUFFER) + cifs_buf_release(iov[0].iov_base); + cifs_small_buf_release(pSMB); + return rc; +} + + /* Legacy Query Path Information call for lookup to old servers such as Win9x/WinME */ int SMBQueryInformation(const int xid, struct cifsTconInfo *tcon, @@ -3203,7 +3427,7 @@ getDFSRetry: temp = ((char *)referrals) + le16_to_cpu(referrals->DfsPathOffset); if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) { cifs_strfromUCS_le(*targetUNCs, - (wchar_t *) temp, name_len, nls_codepage); + (__le16 *) temp, name_len, nls_codepage); } else { strncpy(*targetUNCs,temp,name_len); } @@ -4256,7 +4480,7 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, { int rc = 0; struct smb_com_transaction_change_notify_req * pSMB = NULL; - struct smb_com_transaction_change_notify_rsp * pSMBr = NULL; + struct smb_com_ntransaction_change_notify_rsp * pSMBr = NULL; struct dir_notify_req *dnotify_req; int bytes_returned; @@ -4271,6 +4495,10 @@ int CIFSSMBNotify(const int xid, struct cifsTconInfo *tcon, pSMB->MaxParameterCount = cpu_to_le32(2); /* BB find exact data count max from sess structure BB */ pSMB->MaxDataCount = 0; /* same in little endian or be */ +/* BB VERIFY verify which is correct for above BB */ + pSMB->MaxDataCount = cpu_to_le32((tcon->ses->server->maxBuf - + MAX_CIFS_HDR_SIZE) & 0xFFFFFF00); + pSMB->MaxSetupCount = 4; pSMB->Reserved = 0; pSMB->ParameterOffset = 0; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 2cb6207..88f60aa 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -76,12 +76,19 @@ struct smb_vol { unsigned setuids:1; unsigned noperm:1; unsigned no_psx_acl:1; /* set if posix acl support should be disabled */ + unsigned cifs_acl:1; unsigned no_xattr:1; /* set if xattr (EA) support should be disabled*/ unsigned server_ino:1; /* use inode numbers from server ie UniqueId */ unsigned direct_io:1; unsigned remap:1; /* set to remap seven reserved chars in filenames */ unsigned posix_paths:1; /* unset to not ask for posix pathnames. */ unsigned sfu_emul:1; + unsigned krb5:1; + unsigned ntlm:1; + unsigned ntlmv2:1; + unsigned nullauth:1; /* attempt to authenticate with null user */ + unsigned sign:1; + unsigned seal:1; /* encrypt */ unsigned nocase; /* request case insensitive filenames */ unsigned nobrl; /* disable sending byte range locks to srv */ unsigned int rsize; @@ -508,7 +515,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server) /* else length ok */ reconnect = 0; - if(pdu_length > MAX_CIFS_HDR_SIZE - 4) { + if(pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE - 4) { isLargeBuf = TRUE; memcpy(bigbuf, smallbuf, 4); smb_buffer = bigbuf; @@ -777,7 +784,7 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) /* vol->retry default is 0 (i.e. "soft" limited retry not hard retry) */ vol->rw = TRUE; - + vol->ntlm = TRUE; /* default is always to request posix paths. */ vol->posix_paths = 1; @@ -903,6 +910,39 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) printk(KERN_WARNING "CIFS: ip address too long\n"); return 1; } + } else if (strnicmp(data, "sec", 3) == 0) { + if (!value || !*value) { + cERROR(1,("no security value specified")); + continue; + } else if (strnicmp(value, "krb5i", 5) == 0) { + vol->sign = 1; + vol->krb5 = 1; + } else if (strnicmp(value, "krb5p", 5) == 0) { + /* vol->seal = 1; + vol->krb5 = 1; */ + cERROR(1,("Krb5 cifs privacy not supported")); + return 1; + } else if (strnicmp(value, "krb5", 4) == 0) { + vol->krb5 = 1; + } else if (strnicmp(value, "ntlmv2i", 7) == 0) { + vol->ntlmv2 = 1; + vol->sign = 1; + } else if (strnicmp(value, "ntlmv2", 6) == 0) { + vol->ntlmv2 = 1; + } else if (strnicmp(value, "ntlmi", 5) == 0) { + vol->ntlm = 1; + vol->sign = 1; + } else if (strnicmp(value, "ntlm", 4) == 0) { + /* ntlm is default so can be turned off too */ + vol->ntlm = 1; + } else if (strnicmp(value, "nontlm", 6) == 0) { + vol->ntlm = 0; + } else if (strnicmp(value, "none", 4) == 0) { + vol->nullauth = 1; + } else { + cERROR(1,("bad security option: %s", value)); + return 1; + } } else if ((strnicmp(data, "unc", 3) == 0) || (strnicmp(data, "target", 6) == 0) || (strnicmp(data, "path", 4) == 0)) { @@ -1120,6 +1160,10 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol) vol->server_ino = 1; } else if (strnicmp(data, "noserverino",9) == 0) { vol->server_ino = 0; + } else if (strnicmp(data, "cifsacl",7) == 0) { + vol->cifs_acl = 1; + } else if (strnicmp(data, "nocifsacl", 9) == 0) { + vol->cifs_acl = 0; } else if (strnicmp(data, "acl",3) == 0) { vol->no_psx_acl = 0; } else if (strnicmp(data, "noacl",5) == 0) { @@ -1546,7 +1590,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, cFYI(1, ("Username: %s ", volume_info.username)); } else { - cifserror("No username specified "); + cifserror("No username specified"); /* In userspace mount helper we can get user name from alternate locations such as env variables and files on disk */ kfree(volume_info.UNC); @@ -1587,7 +1631,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, return -EINVAL; } else /* which servers DFS root would we conect to */ { cERROR(1, - ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified ")); + ("CIFS mount error: No UNC path (e.g. -o unc=//192.168.1.100/public) specified")); kfree(volume_info.UNC); kfree(volume_info.password); FreeXid(xid); @@ -1626,7 +1670,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, if (srvTcp) { - cFYI(1, ("Existing tcp session with server found ")); + cFYI(1, ("Existing tcp session with server found")); } else { /* create socket */ if(volume_info.port) sin_server.sin_port = htons(volume_info.port); @@ -1689,11 +1733,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, if (existingCifsSes) { pSesInfo = existingCifsSes; - cFYI(1, ("Existing smb sess found ")); + cFYI(1, ("Existing smb sess found")); kfree(volume_info.password); /* volume_info.UNC freed at end of function */ } else if (!rc) { - cFYI(1, ("Existing smb sess not found ")); + cFYI(1, ("Existing smb sess not found")); pSesInfo = sesInfoAlloc(); if (pSesInfo == NULL) rc = -ENOMEM; @@ -1751,7 +1795,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, cifs_sb->mnt_gid = volume_info.linux_gid; cifs_sb->mnt_file_mode = volume_info.file_mode; cifs_sb->mnt_dir_mode = volume_info.dir_mode; - cFYI(1,("file mode: 0x%x dir mode: 0x%x",cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode)); + cFYI(1,("file mode: 0x%x dir mode: 0x%x", + cifs_sb->mnt_file_mode,cifs_sb->mnt_dir_mode)); if(volume_info.noperm) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM; @@ -1767,6 +1812,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL; if(volume_info.nobrl) cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL; + if(volume_info.cifs_acl) + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL; if(volume_info.direct_io) { cFYI(1,("mounting share using direct i/o")); @@ -1777,7 +1824,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, find_unc(sin_server.sin_addr.s_addr, volume_info.UNC, volume_info.username); if (tcon) { - cFYI(1, ("Found match on UNC path ")); + cFYI(1, ("Found match on UNC path")); /* we can have only one retry value for a connection to a share so for resources mounted more than once to the same server share the last value passed in @@ -1926,7 +1973,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, __u32 capabilities; __u16 count; - cFYI(1, ("In sesssetup ")); + cFYI(1, ("In sesssetup")); if(ses == NULL) return -EINVAL; user = ses->userName; @@ -1986,32 +2033,32 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, bytes_returned = 0; /* skill null user */ else bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, + cifs_strtoUCS((__le16 *) bcc_ptr, user, 100, nls_codepage); /* convert number of 16 bit words to bytes */ bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; /* trailing null */ if (domain == NULL) bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, + cifs_strtoUCS((__le16 *) bcc_ptr, "CIFS_LINUX_DOM", 32, nls_codepage); else bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64, + cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ", + cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, + cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS, + cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, 64, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; @@ -2081,7 +2128,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, if(ses->serverOS == NULL) goto sesssetup_nomem; cifs_strfromUCS_le(ses->serverOS, - (wchar_t *)bcc_ptr, len,nls_codepage); + (__le16 *)bcc_ptr, len,nls_codepage); bcc_ptr += 2 * (len + 1); remaining_words -= len + 1; ses->serverOS[2 * len] = 0; @@ -2093,7 +2140,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, if(ses->serverNOS == NULL) goto sesssetup_nomem; cifs_strfromUCS_le(ses->serverNOS, - (wchar_t *)bcc_ptr,len,nls_codepage); + (__le16 *)bcc_ptr,len,nls_codepage); bcc_ptr += 2 * (len + 1); ses->serverNOS[2 * len] = 0; ses->serverNOS[1 + (2 * len)] = 0; @@ -2111,7 +2158,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, if(ses->serverDomain == NULL) goto sesssetup_nomem; cifs_strfromUCS_le(ses->serverDomain, - (wchar_t *)bcc_ptr,len,nls_codepage); + (__le16 *)bcc_ptr,len,nls_codepage); bcc_ptr += 2 * (len + 1); ses->serverDomain[2*len] = 0; ses->serverDomain[1+(2*len)] = 0; @@ -2255,30 +2302,30 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr++; } bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, user, 100, nls_codepage); + cifs_strtoUCS((__le16 *) bcc_ptr, user, 100, nls_codepage); bcc_ptr += 2 * bytes_returned; /* convert num of 16 bit words to bytes */ bcc_ptr += 2; /* trailing null */ if (domain == NULL) bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, + cifs_strtoUCS((__le16 *) bcc_ptr, "CIFS_LINUX_DOM", 32, nls_codepage); else bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64, + cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ", + cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32, + cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS, + cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, 64, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; @@ -2357,7 +2404,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, - (wchar_t *) + (__le16 *) bcc_ptr, len, nls_codepage); bcc_ptr += 2 * (len + 1); @@ -2372,7 +2419,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, kzalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverNOS, - (wchar_t *)bcc_ptr, + (__le16 *)bcc_ptr, len, nls_codepage); bcc_ptr += 2 * (len + 1); @@ -2384,9 +2431,8 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses, /* last string is not always null terminated (for e.g. for Windows XP & 2000) */ ses->serverDomain = kzalloc(2*(len+1),GFP_KERNEL); cifs_strfromUCS_le(ses->serverDomain, - (wchar_t *)bcc_ptr, - len, - nls_codepage); + (__le16 *)bcc_ptr, + len, nls_codepage); bcc_ptr += 2*(len+1); ses->serverDomain[2*len] = 0; ses->serverDomain[1+(2*len)] = 0; @@ -2560,16 +2606,16 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, } bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ", + cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32, + cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; /* null terminate Linux version */ bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS, + cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, 64, nls_codepage); bcc_ptr += 2 * bytes_returned; *(bcc_ptr + 1) = 0; @@ -2673,7 +2719,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, - (wchar_t *) + (__le16 *) bcc_ptr, len, nls_codepage); bcc_ptr += 2 * (len + 1); @@ -2690,7 +2736,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, GFP_KERNEL); cifs_strfromUCS_le(ses-> serverNOS, - (wchar_t *) + (__le16 *) bcc_ptr, len, nls_codepage); @@ -2708,23 +2754,15 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, 1), GFP_KERNEL); cifs_strfromUCS_le - (ses-> - serverDomain, - (wchar_t *) - bcc_ptr, len, - nls_codepage); + (ses->serverDomain, + (__le16 *)bcc_ptr, + len, nls_codepage); bcc_ptr += 2 * (len + 1); - ses-> - serverDomain[2 - * len] + ses->serverDomain[2*len] = 0; - ses-> - serverDomain[1 - + - (2 - * - len)] + ses->serverDomain + [1 + (2 * len)] = 0; } /* else no more room so create dummy domain string */ else @@ -2903,7 +2941,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, SecurityBlob->DomainName.MaximumLength = 0; } else { __u16 len = - cifs_strtoUCS((wchar_t *) bcc_ptr, domain, 64, + cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64, nls_codepage); len *= 2; SecurityBlob->DomainName.MaximumLength = @@ -2921,7 +2959,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, SecurityBlob->UserName.MaximumLength = 0; } else { __u16 len = - cifs_strtoUCS((wchar_t *) bcc_ptr, user, 64, + cifs_strtoUCS((__le16 *) bcc_ptr, user, 64, nls_codepage); len *= 2; SecurityBlob->UserName.MaximumLength = @@ -2934,7 +2972,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, cpu_to_le16(len); } - /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((wchar_t *) bcc_ptr, "AMACHINE",64, nls_codepage); + /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage); SecurityBlob->WorkstationName.Length *= 2; SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length); SecurityBlob->WorkstationName.Buffer = cpu_to_le32(SecurityBlobLength); @@ -2947,16 +2985,16 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, bcc_ptr++; } bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, "Linux version ", + cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32, + cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; /* null term version string */ bytes_returned = - cifs_strtoUCS((wchar_t *) bcc_ptr, CIFS_NETWORK_OPSYS, + cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, 64, nls_codepage); bcc_ptr += 2 * bytes_returned; *(bcc_ptr + 1) = 0; @@ -3069,7 +3107,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, - (wchar_t *) + (__le16 *) bcc_ptr, len, nls_codepage); bcc_ptr += 2 * (len + 1); @@ -3086,7 +3124,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, GFP_KERNEL); cifs_strfromUCS_le(ses-> serverNOS, - (wchar_t *) + (__le16 *) bcc_ptr, len, nls_codepage); @@ -3105,7 +3143,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, cifs_strfromUCS_le (ses-> serverDomain, - (wchar_t *) + (__le16 *) bcc_ptr, len, nls_codepage); bcc_ptr += @@ -3211,9 +3249,26 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, pSMB->AndXCommand = 0xFF; pSMB->Flags = cpu_to_le16(TCON_EXTENDED_SECINFO); - pSMB->PasswordLength = cpu_to_le16(1); /* minimum */ bcc_ptr = &pSMB->Password[0]; - bcc_ptr++; /* skip password */ + if((ses->server->secMode) & SECMODE_USER) { + pSMB->PasswordLength = cpu_to_le16(1); /* minimum */ + bcc_ptr++; /* skip password */ + } else { + pSMB->PasswordLength = cpu_to_le16(CIFS_SESSION_KEY_SIZE); + /* BB FIXME add code to fail this if NTLMv2 or Kerberos + specified as required (when that support is added to + the vfs in the future) as only NTLM or the much + weaker LANMAN (which we do not send) is accepted + by Samba (not sure whether other servers allow + NTLMv2 password here) */ + SMBNTencrypt(ses->password, + ses->server->cryptKey, + bcc_ptr); + + bcc_ptr += CIFS_SESSION_KEY_SIZE; + *bcc_ptr = 0; + bcc_ptr++; /* align */ + } if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; @@ -3227,11 +3282,10 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, if (ses->capabilities & CAP_UNICODE) { smb_buffer->Flags2 |= SMBFLG2_UNICODE; length = - cifs_strtoUCS((wchar_t *) bcc_ptr, tree, 100, nls_codepage); + cifs_strtoUCS((__le16 *) bcc_ptr, tree, 100, nls_codepage); bcc_ptr += 2 * length; /* convert num of 16 bit words to bytes */ bcc_ptr += 2; /* skip trailing null */ } else { /* ASCII */ - strcpy(bcc_ptr, tree); bcc_ptr += strlen(tree) + 1; } @@ -3263,7 +3317,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, tcon->nativeFileSystem = kzalloc(length + 2, GFP_KERNEL); cifs_strfromUCS_le(tcon->nativeFileSystem, - (wchar_t *) bcc_ptr, + (__le16 *) bcc_ptr, length, nls_codepage); bcc_ptr += 2 * length; bcc_ptr[0] = 0; /* null terminate the string */ diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 8dfe717..fed55e3 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,2003 + * Copyright (C) International Business Machines Corp., 2002,2005 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -200,8 +200,8 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, (oplock & CIFS_CREATE_ACTION)) if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, - (__u64)current->euid, - (__u64)current->egid, + (__u64)current->fsuid, + (__u64)current->fsgid, 0 /* dev */, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & @@ -228,8 +228,15 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, else { rc = cifs_get_inode_info(&newinode, full_path, buf, inode->i_sb,xid); - if(newinode) + if(newinode) { newinode->i_mode = mode; + if((oplock & CIFS_CREATE_ACTION) && + (cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_SET_UID)) { + newinode->i_uid = current->fsuid; + newinode->i_gid = current->fsgid; + } + } } if (rc != 0) { @@ -292,7 +299,8 @@ cifs_create_out: return rc; } -int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t device_number) +int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, + dev_t device_number) { int rc = -EPERM; int xid; @@ -317,7 +325,7 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev else if (pTcon->ses->capabilities & CAP_UNIX) { if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { rc = CIFSSMBUnixSetPerms(xid, pTcon, full_path, - mode,(__u64)current->euid,(__u64)current->egid, + mode,(__u64)current->fsuid,(__u64)current->fsgid, device_number, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); @@ -368,7 +376,34 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, dev_t dev if(!rc) { /* BB Do not bother to decode buf since no - local inode yet to put timestamps in */ + local inode yet to put timestamps in, + but we can reuse it safely */ + int bytes_written; + struct win_dev *pdev; + pdev = (struct win_dev *)buf; + if(S_ISCHR(mode)) { + memcpy(pdev->type, "IntxCHR", 8); + pdev->major = + cpu_to_le64(MAJOR(device_number)); + pdev->minor = + cpu_to_le64(MINOR(device_number)); + rc = CIFSSMBWrite(xid, pTcon, + fileHandle, + sizeof(struct win_dev), + 0, &bytes_written, (char *)pdev, + NULL, 0); + } else if(S_ISBLK(mode)) { + memcpy(pdev->type, "IntxBLK", 8); + pdev->major = + cpu_to_le64(MAJOR(device_number)); + pdev->minor = + cpu_to_le64(MINOR(device_number)); + rc = CIFSSMBWrite(xid, pTcon, + fileHandle, + sizeof(struct win_dev), + 0, &bytes_written, (char *)pdev, + NULL, 0); + } /* else if(S_ISFIFO */ CIFSSMBClose(xid, pTcon, fileHandle); d_drop(direntry); } @@ -437,12 +472,20 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, struct name direntry->d_op = &cifs_dentry_ops; d_add(direntry, newInode); - /* since paths are not looked up by component - the parent directories are presumed to be good here */ + /* since paths are not looked up by component - the parent + directories are presumed to be good here */ renew_parental_timestamps(direntry); } else if (rc == -ENOENT) { rc = 0; + direntry->d_time = jiffies; + if (pTcon->nocase) + direntry->d_op = &cifs_ci_dentry_ops; + else + direntry->d_op = &cifs_dentry_ops; d_add(direntry, NULL); + /* if it was once a directory (but how can we tell?) we could do + shrink_dcache_parent(direntry); */ } else { cERROR(1,("Error 0x%x on cifs_get_inode_info in lookup of %s", rc,full_path)); @@ -461,21 +504,20 @@ cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd) { int isValid = 1; -/* lock_kernel(); *//* surely we do not want to lock the kernel for a whole network round trip which could take seconds */ - if (direntry->d_inode) { if (cifs_revalidate(direntry)) { - /* unlock_kernel(); */ return 0; } } else { - cFYI(1, - ("In cifs_d_revalidate with no inode but name = %s and dentry 0x%p", - direntry->d_name.name, direntry)); + cFYI(1, ("neg dentry 0x%p name = %s", + direntry, direntry->d_name.name)); + if(time_after(jiffies, direntry->d_time + HZ) || + !lookupCacheEnabled) { + d_drop(direntry); + isValid = 0; + } } -/* unlock_kernel(); */ - return isValid; } diff --git a/fs/cifs/file.c b/fs/cifs/file.c index da4f5e1..77c990f0 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c @@ -127,8 +127,7 @@ static inline int cifs_open_inode_helper(struct inode *inode, struct file *file, if (file->f_dentry->d_inode->i_mapping) { /* BB no need to lock inode until after invalidate since namei code should already have it locked? */ - filemap_fdatawrite(file->f_dentry->d_inode->i_mapping); - filemap_fdatawait(file->f_dentry->d_inode->i_mapping); + filemap_write_and_wait(file->f_dentry->d_inode->i_mapping); } cFYI(1, ("invalidating remote inode since open detected it " "changed")); @@ -419,8 +418,7 @@ static int cifs_reopen_file(struct inode *inode, struct file *file, pCifsInode = CIFS_I(inode); if (pCifsInode) { if (can_flush) { - filemap_fdatawrite(inode->i_mapping); - filemap_fdatawait(inode->i_mapping); + filemap_write_and_wait(inode->i_mapping); /* temporarily disable caching while we go to server to get inode info */ pCifsInode->clientCanCacheAll = FALSE; @@ -489,8 +487,10 @@ int cifs_close(struct inode *inode, struct file *file) the struct would be in each open file, but this should give enough time to clear the socket */ + write_unlock(&file->f_owner.lock); cERROR(1,("close with pending writes")); msleep(timeout); + write_lock(&file->f_owner.lock); timeout *= 4; } write_unlock(&file->f_owner.lock); @@ -553,13 +553,13 @@ int cifs_closedir(struct inode *inode, struct file *file) } ptmp = pCFileStruct->srch_inf.ntwrk_buf_start; if (ptmp) { - /* BB removeme BB */ cFYI(1, ("freeing smb buf in srch struct in closedir")); + cFYI(1, ("closedir free smb buf in srch struct")); pCFileStruct->srch_inf.ntwrk_buf_start = NULL; cifs_buf_release(ptmp); } ptmp = pCFileStruct->search_resume_name; if (ptmp) { - /* BB removeme BB */ cFYI(1, ("freeing resume name in closedir")); + cFYI(1, ("closedir free resume name")); pCFileStruct->search_resume_name = NULL; kfree(ptmp); } @@ -868,10 +868,9 @@ static ssize_t cifs_write(struct file *file, const char *write_data, if (rc != 0) break; } -#ifdef CONFIG_CIFS_EXPERIMENTAL /* BB FIXME We can not sign across two buffers yet */ - if((experimEnabled) && ((pTcon->ses->server->secMode & - (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0)) { + if((pTcon->ses->server->secMode & + (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) == 0) { struct kvec iov[2]; unsigned int len; @@ -887,7 +886,6 @@ static ssize_t cifs_write(struct file *file, const char *write_data, iov, 1, long_op); } else /* BB FIXME fixup indentation of line below */ -#endif rc = CIFSSMBWrite(xid, pTcon, open_file->netfid, min_t(const int, cifs_sb->wsize, @@ -1024,7 +1022,6 @@ static int cifs_partialpagewrite(struct page *page, unsigned from, unsigned to) return rc; } -#ifdef CONFIG_CIFS_EXPERIMENTAL static int cifs_writepages(struct address_space *mapping, struct writeback_control *wbc) { @@ -1227,7 +1224,6 @@ retry: return rc; } -#endif static int cifs_writepage(struct page* page, struct writeback_control *wbc) { @@ -1426,6 +1422,7 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, rc = -EAGAIN; smb_read_data = NULL; while (rc == -EAGAIN) { + int buf_type = CIFS_NO_BUFFER; if ((open_file->invalidHandle) && (!open_file->closePend)) { rc = cifs_reopen_file(file->f_dentry->d_inode, @@ -1434,20 +1431,22 @@ ssize_t cifs_user_read(struct file *file, char __user *read_data, break; } rc = CIFSSMBRead(xid, pTcon, - open_file->netfid, - current_read_size, *poffset, - &bytes_read, &smb_read_data); + open_file->netfid, + current_read_size, *poffset, + &bytes_read, &smb_read_data, + &buf_type); pSMBr = (struct smb_com_read_rsp *)smb_read_data; if (copy_to_user(current_offset, smb_read_data + 4 /* RFC1001 hdr */ + le16_to_cpu(pSMBr->DataOffset), bytes_read)) { rc = -EFAULT; - FreeXid(xid); - return rc; - } + } if (smb_read_data) { - cifs_buf_release(smb_read_data); + if(buf_type == CIFS_SMALL_BUFFER) + cifs_small_buf_release(smb_read_data); + else if(buf_type == CIFS_LARGE_BUFFER) + cifs_buf_release(smb_read_data); smb_read_data = NULL; } } @@ -1480,6 +1479,7 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, int xid; char *current_offset; struct cifsFileInfo *open_file; + int buf_type = CIFS_NO_BUFFER; xid = GetXid(); cifs_sb = CIFS_SB(file->f_dentry->d_sb); @@ -1516,9 +1516,10 @@ static ssize_t cifs_read(struct file *file, char *read_data, size_t read_size, break; } rc = CIFSSMBRead(xid, pTcon, - open_file->netfid, - current_read_size, *poffset, - &bytes_read, ¤t_offset); + open_file->netfid, + current_read_size, *poffset, + &bytes_read, ¤t_offset, + &buf_type); } if (rc || (bytes_read == 0)) { if (total_read) { @@ -1616,6 +1617,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, struct smb_com_read_rsp *pSMBr; struct pagevec lru_pvec; struct cifsFileInfo *open_file; + int buf_type = CIFS_NO_BUFFER; xid = GetXid(); if (file->private_data == NULL) { @@ -1672,14 +1674,17 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, } rc = CIFSSMBRead(xid, pTcon, - open_file->netfid, - read_size, offset, - &bytes_read, &smb_read_data); - + open_file->netfid, + read_size, offset, + &bytes_read, &smb_read_data, + &buf_type); /* BB more RC checks ? */ if (rc== -EAGAIN) { if (smb_read_data) { - cifs_buf_release(smb_read_data); + if(buf_type == CIFS_SMALL_BUFFER) + cifs_small_buf_release(smb_read_data); + else if(buf_type == CIFS_LARGE_BUFFER) + cifs_buf_release(smb_read_data); smb_read_data = NULL; } } @@ -1736,7 +1741,10 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, break; } if (smb_read_data) { - cifs_buf_release(smb_read_data); + if(buf_type == CIFS_SMALL_BUFFER) + cifs_small_buf_release(smb_read_data); + else if(buf_type == CIFS_LARGE_BUFFER) + cifs_buf_release(smb_read_data); smb_read_data = NULL; } bytes_read = 0; @@ -1746,7 +1754,10 @@ static int cifs_readpages(struct file *file, struct address_space *mapping, /* need to free smb_read_data buf before exit */ if (smb_read_data) { - cifs_buf_release(smb_read_data); + if(buf_type == CIFS_SMALL_BUFFER) + cifs_small_buf_release(smb_read_data); + else if(buf_type == CIFS_LARGE_BUFFER) + cifs_buf_release(smb_read_data); smb_read_data = NULL; } @@ -1825,10 +1836,20 @@ int is_size_safe_to_change(struct cifsInodeInfo *cifsInode) open_file = find_writable_file(cifsInode); if(open_file) { + struct cifs_sb_info *cifs_sb; + /* there is not actually a write pending so let this handle go free and allow it to be closable if needed */ atomic_dec(&open_file->wrtPending); + + cifs_sb = CIFS_SB(cifsInode->vfs_inode.i_sb); + if ( cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO ) { + /* since no page cache to corrupt on directio + we can change size safely */ + return 1; + } + return 0; } else return 1; @@ -1873,9 +1894,7 @@ struct address_space_operations cifs_addr_ops = { .readpage = cifs_readpage, .readpages = cifs_readpages, .writepage = cifs_writepage, -#ifdef CONFIG_CIFS_EXPERIMENTAL .writepages = cifs_writepages, -#endif .prepare_write = cifs_prepare_write, .commit_write = cifs_commit_write, .set_page_dirty = __set_page_dirty_nobuffers, diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 923d071..5935991 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -41,7 +41,7 @@ int cifs_get_inode_info_unix(struct inode **pinode, char *tmp_path; pTcon = cifs_sb->tcon; - cFYI(1, (" Getting info on %s ", search_path)); + cFYI(1, ("Getting info on %s ", search_path)); /* could have done a find first instead but this returns more info */ rc = CIFSSMBUnixQPathInfo(xid, pTcon, search_path, &findData, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & @@ -97,9 +97,9 @@ int cifs_get_inode_info_unix(struct inode **pinode, inode = *pinode; cifsInfo = CIFS_I(inode); - cFYI(1, (" Old time %ld ", cifsInfo->time)); + cFYI(1, ("Old time %ld ", cifsInfo->time)); cifsInfo->time = jiffies; - cFYI(1, (" New time %ld ", cifsInfo->time)); + cFYI(1, ("New time %ld ", cifsInfo->time)); /* this is ok to set on every inode revalidate */ atomic_set(&cifsInfo->inUse,1); @@ -111,6 +111,9 @@ int cifs_get_inode_info_unix(struct inode **pinode, inode->i_ctime = cifs_NTtimeToUnix(le64_to_cpu(findData.LastStatusChange)); 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; if (type == UNIX_FILE) { inode->i_mode |= S_IFREG; } else if (type == UNIX_SYMLINK) { @@ -129,6 +132,10 @@ int cifs_get_inode_info_unix(struct inode **pinode, inode->i_mode |= S_IFIFO; } else if (type == UNIX_SOCKET) { inode->i_mode |= S_IFSOCK; + } else { + /* safest to call it a file if we do not know */ + inode->i_mode |= S_IFREG; + cFYI(1,("unknown type %d",type)); } inode->i_uid = le64_to_cpu(findData.Uid); inode->i_gid = le64_to_cpu(findData.Gid); @@ -155,34 +162,39 @@ int cifs_get_inode_info_unix(struct inode **pinode, } if (num_of_bytes < end_of_file) - cFYI(1, ("allocation size less than end of file ")); + cFYI(1, ("allocation size less than end of file")); cFYI(1, ("Size %ld and blocks %ld", (unsigned long) inode->i_size, inode->i_blocks)); if (S_ISREG(inode->i_mode)) { - cFYI(1, (" File inode ")); + cFYI(1, ("File inode")); inode->i_op = &cifs_file_inode_ops; - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) - inode->i_fop = &cifs_file_direct_ops; - else + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) + inode->i_fop = + &cifs_file_direct_nobrl_ops; + else + inode->i_fop = &cifs_file_direct_ops; + } else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) + inode->i_fop = &cifs_file_nobrl_ops; + else /* not direct, send byte range locks */ inode->i_fop = &cifs_file_ops; - if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) - inode->i_fop->lock = NULL; + inode->i_data.a_ops = &cifs_addr_ops; /* check if server can support readpages */ if(pTcon->ses->server->maxBuf < 4096 + MAX_CIFS_HDR_SIZE) inode->i_data.a_ops->readpages = NULL; } else if (S_ISDIR(inode->i_mode)) { - cFYI(1, (" Directory inode")); + cFYI(1, ("Directory inode")); inode->i_op = &cifs_dir_inode_ops; inode->i_fop = &cifs_dir_ops; } else if (S_ISLNK(inode->i_mode)) { - cFYI(1, (" Symbolic Link inode ")); + cFYI(1, ("Symbolic Link inode")); inode->i_op = &cifs_symlink_inode_ops; /* tmp_inode->i_fop = */ /* do not need to set to anything */ } else { - cFYI(1, (" Init special inode ")); + cFYI(1, ("Init special inode")); init_special_inode(inode, inode->i_mode, inode->i_rdev); } @@ -190,6 +202,112 @@ int cifs_get_inode_info_unix(struct inode **pinode, return rc; } +static int decode_sfu_inode(struct inode * inode, __u64 size, + const unsigned char *path, + struct cifs_sb_info *cifs_sb, int xid) +{ + int rc; + int oplock = FALSE; + __u16 netfid; + struct cifsTconInfo *pTcon = cifs_sb->tcon; + char buf[24]; + unsigned int bytes_read; + char * pbuf; + + pbuf = buf; + + if(size == 0) { + inode->i_mode |= S_IFIFO; + return 0; + } else if (size < 8) { + return -EINVAL; /* EOPNOTSUPP? */ + } + + rc = CIFSSMBOpen(xid, pTcon, path, FILE_OPEN, GENERIC_READ, + CREATE_NOT_DIR, &netfid, &oplock, NULL, + cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_MAP_SPECIAL_CHR); + if (rc==0) { + int buf_type = CIFS_NO_BUFFER; + /* Read header */ + rc = CIFSSMBRead(xid, pTcon, + netfid, + 24 /* length */, 0 /* offset */, + &bytes_read, &pbuf, &buf_type); + if((rc == 0) && (bytes_read >= 8)) { + if(memcmp("IntxBLK", pbuf, 8) == 0) { + cFYI(1,("Block device")); + inode->i_mode |= S_IFBLK; + if(bytes_read == 24) { + /* we have enough to decode dev num */ + __u64 mjr; /* major */ + __u64 mnr; /* minor */ + mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); + mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); + inode->i_rdev = MKDEV(mjr, mnr); + } + } else if(memcmp("IntxCHR", pbuf, 8) == 0) { + cFYI(1,("Char device")); + inode->i_mode |= S_IFCHR; + if(bytes_read == 24) { + /* we have enough to decode dev num */ + __u64 mjr; /* major */ + __u64 mnr; /* minor */ + mjr = le64_to_cpu(*(__le64 *)(pbuf+8)); + mnr = le64_to_cpu(*(__le64 *)(pbuf+16)); + inode->i_rdev = MKDEV(mjr, mnr); + } + } else if(memcmp("IntxLNK", pbuf, 7) == 0) { + cFYI(1,("Symlink")); + inode->i_mode |= S_IFLNK; + } else { + inode->i_mode |= S_IFREG; /* file? */ + rc = -EOPNOTSUPP; + } + } else { + inode->i_mode |= S_IFREG; /* then it is a file */ + rc = -EOPNOTSUPP; /* or some unknown SFU type */ + } + CIFSSMBClose(xid, pTcon, netfid); + } + return rc; + +} + +#define SFBITS_MASK (S_ISVTX | S_ISGID | S_ISUID) /* SETFILEBITS valid bits */ + +static int get_sfu_uid_mode(struct inode * inode, + const unsigned char *path, + struct cifs_sb_info *cifs_sb, int xid) +{ +#ifdef CONFIG_CIFS_XATTR + ssize_t rc; + char ea_value[4]; + __u32 mode; + + rc = CIFSSMBQueryEA(xid, cifs_sb->tcon, path, "SETFILEBITS", + ea_value, 4 /* size of buf */, cifs_sb->local_nls, + cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); + if(rc < 0) + return (int)rc; + else if (rc > 3) { + mode = le32_to_cpu(*((__le32 *)ea_value)); + inode->i_mode &= ~SFBITS_MASK; + cFYI(1,("special bits 0%o org mode 0%o", mode, inode->i_mode)); + inode->i_mode = (mode & SFBITS_MASK) | inode->i_mode; + cFYI(1,("special mode bits 0%o", mode)); + return 0; + } else { + return 0; + } +#else + return -EOPNOTSUPP; +#endif + + +} + int cifs_get_inode_info(struct inode **pinode, const unsigned char *search_path, FILE_ALL_INFO *pfindData, struct super_block *sb, int xid) @@ -202,7 +320,7 @@ int cifs_get_inode_info(struct inode **pinode, char *buf = NULL; pTcon = cifs_sb->tcon; - cFYI(1,("Getting info on %s ", search_path)); + cFYI(1,("Getting info on %s", search_path)); if ((pfindData == NULL) && (*pinode != NULL)) { if (CIFS_I(*pinode)->clientCanCacheRead) { @@ -303,9 +421,9 @@ int cifs_get_inode_info(struct inode **pinode, inode = *pinode; cifsInfo = CIFS_I(inode); cifsInfo->cifsAttrs = attr; - cFYI(1, (" Old time %ld ", cifsInfo->time)); + cFYI(1, ("Old time %ld ", cifsInfo->time)); cifsInfo->time = jiffies; - cFYI(1, (" New time %ld ", cifsInfo->time)); + cFYI(1, ("New time %ld ", cifsInfo->time)); /* blksize needs to be multiple of two. So safer to default to blksize and blkbits set in superblock so 2**blkbits and blksize @@ -319,13 +437,15 @@ int cifs_get_inode_info(struct inode **pinode, cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastWriteTime)); inode->i_ctime = cifs_NTtimeToUnix(le64_to_cpu(pfindData->ChangeTime)); - cFYI(0, (" Attributes came in as 0x%x ", attr)); + cFYI(0, ("Attributes came in as 0x%x ", attr)); /* set default mode. will override for dirs below */ if (atomic_read(&cifsInfo->inUse) == 0) /* new inode, can safely set these fields */ inode->i_mode = cifs_sb->mnt_file_mode; - + else /* since we set the inode type below we need to mask off + to avoid strange results if type changes and both get orred in */ + inode->i_mode &= ~S_IFMT; /* if (attr & ATTR_REPARSE) */ /* We no longer handle these as symlinks because we could not follow them due to the absolute path with drive letter */ @@ -340,10 +460,16 @@ int cifs_get_inode_info(struct inode **pinode, (pfindData->EndOfFile == 0)) { inode->i_mode = cifs_sb->mnt_file_mode; inode->i_mode |= S_IFIFO; -/* BB Finish for SFU style symlinks and devies */ -/* } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && - (cifsInfo->cifsAttrs & ATTR_SYSTEM) && ) */ - +/* BB Finish for SFU style symlinks and devices */ + } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && + (cifsInfo->cifsAttrs & ATTR_SYSTEM)) { + if (decode_sfu_inode(inode, + le64_to_cpu(pfindData->EndOfFile), + search_path, + cifs_sb, xid)) { + cFYI(1,("Unrecognized sfu inode type")); + } + cFYI(1,("sfu mode 0%o",inode->i_mode)); } else { inode->i_mode |= S_IFREG; /* treat the dos attribute of read-only as read-only @@ -368,7 +494,10 @@ int cifs_get_inode_info(struct inode **pinode, /* BB fill in uid and gid here? with help from winbind? or retrieve from NTFS stream extended attribute */ - if (atomic_read(&cifsInfo->inUse) == 0) { + if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) { + /* fill in uid, gid, mode from server ACL */ + get_sfu_uid_mode(inode, search_path, cifs_sb, xid); + } else if (atomic_read(&cifsInfo->inUse) == 0) { inode->i_uid = cifs_sb->mnt_uid; inode->i_gid = cifs_sb->mnt_gid; /* set so we do not keep refreshing these fields with @@ -377,24 +506,29 @@ int cifs_get_inode_info(struct inode **pinode, } if (S_ISREG(inode->i_mode)) { - cFYI(1, (" File inode ")); + cFYI(1, ("File inode")); inode->i_op = &cifs_file_inode_ops; - if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) - inode->i_fop = &cifs_file_direct_ops; - else + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { + if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) + inode->i_fop = + &cifs_file_direct_nobrl_ops; + else + inode->i_fop = &cifs_file_direct_ops; + } else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) + inode->i_fop = &cifs_file_nobrl_ops; + else /* not direct, send byte range locks */ inode->i_fop = &cifs_file_ops; - if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) - inode->i_fop->lock = NULL; + inode->i_data.a_ops = &cifs_addr_ops; if(pTcon->ses->server->maxBuf < 4096 + MAX_CIFS_HDR_SIZE) inode->i_data.a_ops->readpages = NULL; } else if (S_ISDIR(inode->i_mode)) { - cFYI(1, (" Directory inode ")); + cFYI(1, ("Directory inode")); inode->i_op = &cifs_dir_inode_ops; inode->i_fop = &cifs_dir_ops; } else if (S_ISLNK(inode->i_mode)) { - cFYI(1, (" Symbolic Link inode ")); + cFYI(1, ("Symbolic Link inode")); inode->i_op = &cifs_symlink_inode_ops; } else { init_special_inode(inode, inode->i_mode, @@ -431,7 +565,7 @@ int cifs_unlink(struct inode *inode, struct dentry *direntry) struct cifsInodeInfo *cifsInode; FILE_BASIC_INFO *pinfo_buf; - cFYI(1, (" cifs_unlink, inode = 0x%p with ", inode)); + cFYI(1, ("cifs_unlink, inode = 0x%p with ", inode)); xid = GetXid(); @@ -577,7 +711,7 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) char *full_path = NULL; struct inode *newinode = NULL; - cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p ", mode, inode)); + cFYI(1, ("In cifs_mkdir, mode = 0x%x inode = 0x%p", mode, inode)); xid = GetXid(); @@ -617,8 +751,8 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) { CIFSSMBUnixSetPerms(xid, pTcon, full_path, mode, - (__u64)current->euid, - (__u64)current->egid, + (__u64)current->fsuid, + (__u64)current->fsgid, 0 /* dev_t */, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & @@ -635,6 +769,17 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) /* BB to be implemented via Windows secrty descriptors eg CIFSSMBWinSetPerms(xid, pTcon, full_path, mode, -1, -1, local_nls); */ + if(direntry->d_inode) { + direntry->d_inode->i_mode = mode; + direntry->d_inode->i_mode |= S_IFDIR; + if(cifs_sb->mnt_cifs_flags & + CIFS_MOUNT_SET_UID) { + direntry->d_inode->i_uid = + current->fsuid; + direntry->d_inode->i_gid = + current->fsgid; + } + } } } kfree(full_path); @@ -651,7 +796,7 @@ int cifs_rmdir(struct inode *inode, struct dentry *direntry) char *full_path = NULL; struct cifsInodeInfo *cifsInode; - cFYI(1, (" cifs_rmdir, inode = 0x%p with ", inode)); + cFYI(1, ("cifs_rmdir, inode = 0x%p with ", inode)); xid = GetXid(); @@ -896,9 +1041,9 @@ int cifs_revalidate(struct dentry *direntry) } /* can not grab this sem since kernel filesys locking documentation - indicates i_sem may be taken by the kernel on lookup and rename - which could deadlock if we grab the i_sem here as well */ -/* down(&direntry->d_inode->i_sem);*/ + indicates i_mutex may be taken by the kernel on lookup and rename + which could deadlock if we grab the i_mutex here as well */ +/* mutex_lock(&direntry->d_inode->i_mutex);*/ /* need to write out dirty pages here */ if (direntry->d_inode->i_mapping) { /* do we need to lock inode until after invalidate completes @@ -906,17 +1051,23 @@ int cifs_revalidate(struct dentry *direntry) filemap_fdatawrite(direntry->d_inode->i_mapping); } if (invalidate_inode) { - if (direntry->d_inode->i_mapping) - filemap_fdatawait(direntry->d_inode->i_mapping); - /* may eventually have to do this for open files too */ - if (list_empty(&(cifsInode->openFileList))) { - /* Has changed on server - flush read ahead pages */ - cFYI(1, ("Invalidating read ahead data on " - "closed file")); - invalidate_remote_inode(direntry->d_inode); + /* shrink_dcache not necessary now that cifs dentry ops + are exported for negative dentries */ +/* if(S_ISDIR(direntry->d_inode->i_mode)) + shrink_dcache_parent(direntry); */ + if (S_ISREG(direntry->d_inode->i_mode)) { + if (direntry->d_inode->i_mapping) + filemap_fdatawait(direntry->d_inode->i_mapping); + /* may eventually have to do this for open files too */ + if (list_empty(&(cifsInode->openFileList))) { + /* changed on server - flush read ahead pages */ + cFYI(1, ("Invalidating read ahead data on " + "closed file")); + invalidate_remote_inode(direntry->d_inode); + } } } -/* up(&direntry->d_inode->i_sem); */ +/* mutex_unlock(&direntry->d_inode->i_mutex); */ kfree(full_path); FreeXid(xid); @@ -970,11 +1121,22 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) xid = GetXid(); - cFYI(1, (" In cifs_setattr, name = %s attrs->iavalid 0x%x ", + cFYI(1, ("In cifs_setattr, name = %s attrs->iavalid 0x%x ", direntry->d_name.name, attrs->ia_valid)); + cifs_sb = CIFS_SB(direntry->d_inode->i_sb); pTcon = cifs_sb->tcon; + if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_PERM) == 0) { + /* check if we have permission to change attrs */ + rc = inode_change_ok(direntry->d_inode, attrs); + if(rc < 0) { + FreeXid(xid); + return rc; + } else + rc = 0; + } + down(&direntry->d_sb->s_vfs_rename_sem); full_path = build_path_from_dentry(direntry); up(&direntry->d_sb->s_vfs_rename_sem); @@ -987,8 +1149,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) /* BB check if we need to refresh inode from server now ? BB */ /* need to flush data before changing file size on server */ - filemap_fdatawrite(direntry->d_inode->i_mapping); - filemap_fdatawait(direntry->d_inode->i_mapping); + filemap_write_and_wait(direntry->d_inode->i_mapping); if (attrs->ia_valid & ATTR_SIZE) { /* To avoid spurious oplock breaks from server, in the case of @@ -1014,7 +1175,9 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) 1 /* 45 seconds */); cFYI(1,("Wrt seteof rc %d", rc)); } - } + } else + rc = -EINVAL; + if (rc != 0) { /* Set file size by pathname rather than by handle either because no valid, writeable file handle for @@ -1086,6 +1249,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); else if (attrs->ia_valid & ATTR_MODE) { + rc = 0; if ((mode & S_IWUGO) == 0) /* not writeable */ { if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0) time_buf.Attributes = diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 34a0669..812c6bb 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -1,7 +1,7 @@ /* * fs/cifs/misc.c * - * Copyright (C) International Business Machines Corp., 2002,2004 + * Copyright (C) International Business Machines Corp., 2002,2005 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -161,6 +161,9 @@ cifs_buf_get(void) if (ret_buf) { memset(ret_buf, 0, sizeof(struct smb_hdr) + 3); atomic_inc(&bufAllocCount); +#ifdef CONFIG_CIFS_STATS2 + atomic_inc(&totBufAllocCount); +#endif /* CONFIG_CIFS_STATS2 */ } return ret_buf; @@ -195,6 +198,10 @@ cifs_small_buf_get(void) /* No need to clear memory here, cleared in header assemble */ /* memset(ret_buf, 0, sizeof(struct smb_hdr) + 27);*/ atomic_inc(&smBufAllocCount); +#ifdef CONFIG_CIFS_STATS2 + atomic_inc(&totSmBufAllocCount); +#endif /* CONFIG_CIFS_STATS2 */ + } return ret_buf; } @@ -292,7 +299,7 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , struct cifsSesInfo * ses; char *temp = (char *) buffer; - memset(temp,0,MAX_CIFS_HDR_SIZE); + memset(temp,0,256); /* bigger than MAX_CIFS_HDR_SIZE */ buffer->smb_buf_length = (2 * word_count) + sizeof (struct smb_hdr) - @@ -348,12 +355,12 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , /* BB Add support for establishing new tCon and SMB Session */ /* with userid/password pairs found on the smb session */ /* for other target tcp/ip addresses BB */ - if(current->uid != treeCon->ses->linux_uid) { - cFYI(1,("Multiuser mode and UID did not match tcon uid ")); + if(current->fsuid != treeCon->ses->linux_uid) { + cFYI(1,("Multiuser mode and UID did not match tcon uid")); read_lock(&GlobalSMBSeslock); list_for_each(temp_item, &GlobalSMBSessionList) { ses = list_entry(temp_item, struct cifsSesInfo, cifsSessionList); - if(ses->linux_uid == current->uid) { + if(ses->linux_uid == current->fsuid) { if(ses->server == treeCon->ses->server) { cFYI(1,("found matching uid substitute right smb_uid")); buffer->Uid = ses->Suid; @@ -397,12 +404,12 @@ checkSMBhdr(struct smb_hdr *smb, __u16 mid) if(smb->Command == SMB_COM_LOCKING_ANDX) return 0; else - cERROR(1, ("Rcvd Request not response ")); + cERROR(1, ("Rcvd Request not response")); } } else { /* bad signature or mid */ if (*(__le32 *) smb->Protocol != cpu_to_le32(0x424d53ff)) cERROR(1, - ("Bad protocol string signature header %x ", + ("Bad protocol string signature header %x", *(unsigned int *) smb->Protocol)); if (mid != smb->Mid) cERROR(1, ("Mids do not match")); @@ -417,7 +424,7 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length) __u32 len = smb->smb_buf_length; __u32 clc_len; /* calculated length */ cFYI(0, - ("Entering checkSMB with Length: %x, smb_buf_length: %x ", + ("Entering checkSMB with Length: %x, smb_buf_length: %x", length, len)); if (((unsigned int)length < 2 + sizeof (struct smb_hdr)) || (len > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4)) { @@ -451,9 +458,16 @@ checkSMB(struct smb_hdr *smb, __u16 mid, int length) cERROR(1, ("bad smb size detected for Mid=%d", smb->Mid)); /* Windows XP can return a few bytes too much, presumably an illegal pad, at the end of byte range lock responses - so we allow for up to eight byte pad, as long as actual + so we allow for that three byte pad, as long as actual received length is as long or longer than calculated length */ - if((4+len > clc_len) && (len <= clc_len + 3)) + /* We have now had to extend this more, since there is a + case in which it needs to be bigger still to handle a + malformed response to transact2 findfirst from WinXP when + access denied is returned and thus bcc and wct are zero + but server says length is 0x21 bytes too long as if the server + forget to reset the smb rfc1001 length when it reset the + wct and bcc to minimum size and drop the t2 parms and data */ + if((4+len > clc_len) && (len <= clc_len + 512)) return 0; else return 1; @@ -678,7 +692,7 @@ cifsConvertToUCS(__le16 * target, const char *source, int maxlen, __u16 temp; if(!mapChars) - return cifs_strtoUCS((wchar_t *) target, source, PATH_MAX, cp); + return cifs_strtoUCS(target, source, PATH_MAX, cp); for(i = 0, j = 0; i < maxlen; j++) { src_char = source[i]; diff --git a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c index f781468..5de74d2 100644 --- a/fs/cifs/netmisc.c +++ b/fs/cifs/netmisc.c @@ -330,7 +330,7 @@ static const struct { ERRHRD, ERRgeneral, NT_STATUS_ACCOUNT_RESTRICTION}, { ERRSRV, 2241, NT_STATUS_INVALID_LOGON_HOURS}, { ERRSRV, 2240, NT_STATUS_INVALID_WORKSTATION}, { - ERRSRV, 2242, NT_STATUS_PASSWORD_EXPIRED}, { + ERRSRV, ERRpasswordExpired, NT_STATUS_PASSWORD_EXPIRED}, { ERRSRV, 2239, NT_STATUS_ACCOUNT_DISABLED}, { ERRHRD, ERRgeneral, NT_STATUS_NONE_MAPPED}, { ERRHRD, ERRgeneral, NT_STATUS_TOO_MANY_LUIDS_REQUESTED}, { @@ -676,7 +676,7 @@ static const struct { ERRDOS, 193, NT_STATUS_IMAGE_CHECKSUM_MISMATCH}, { ERRHRD, ERRgeneral, NT_STATUS_LOST_WRITEBEHIND_DATA}, { ERRHRD, ERRgeneral, NT_STATUS_CLIENT_SERVER_PARAMETERS_INVALID}, { - ERRSRV, 2242, NT_STATUS_PASSWORD_MUST_CHANGE}, { + ERRSRV, ERRpasswordExpired, NT_STATUS_PASSWORD_MUST_CHANGE}, { ERRHRD, ERRgeneral, NT_STATUS_NOT_FOUND}, { ERRHRD, ERRgeneral, NT_STATUS_NOT_TINY_STREAM}, { ERRHRD, ERRgeneral, NT_STATUS_RECOVERY_FAILURE}, { diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index a86bd1c..288cc04 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -142,6 +142,11 @@ static void fill_in_inode(struct inode *tmp_inode, tmp_inode->i_gid = cifs_sb->mnt_gid; /* set default mode. will override for dirs below */ tmp_inode->i_mode = cifs_sb->mnt_file_mode; + } else { + /* mask off the type bits since it gets set + below and we do not want to get two type + bits set */ + tmp_inode->i_mode &= ~S_IFMT; } if (attr & ATTR_DIRECTORY) { @@ -152,12 +157,18 @@ static void fill_in_inode(struct inode *tmp_inode, } tmp_inode->i_mode |= S_IFDIR; } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && - (attr & ATTR_SYSTEM) && (end_of_file == 0)) { - *pobject_type = DT_FIFO; - tmp_inode->i_mode |= S_IFIFO; -/* BB Finish for SFU style symlinks and devies */ -/* } else if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UNX_EMUL) && - (attr & ATTR_SYSTEM) && ) { */ + (attr & ATTR_SYSTEM)) { + if (end_of_file == 0) { + *pobject_type = DT_FIFO; + tmp_inode->i_mode |= S_IFIFO; + } else { + /* rather than get the type here, we mark the + inode as needing revalidate and get the real type + (blk vs chr vs. symlink) later ie in lookup */ + *pobject_type = DT_REG; + tmp_inode->i_mode |= S_IFREG; + cifsInfo->time = 0; + } /* we no longer mark these because we could not follow them */ /* } else if (attr & ATTR_REPARSE) { *pobject_type = DT_LNK; @@ -193,12 +204,17 @@ static void fill_in_inode(struct inode *tmp_inode, if (S_ISREG(tmp_inode->i_mode)) { cFYI(1, ("File inode")); tmp_inode->i_op = &cifs_file_inode_ops; - if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) - tmp_inode->i_fop = &cifs_file_direct_ops; + if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { + if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) + tmp_inode->i_fop = &cifs_file_direct_nobrl_ops; + else + tmp_inode->i_fop = &cifs_file_direct_ops; + + } else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) + tmp_inode->i_fop = &cifs_file_nobrl_ops; else tmp_inode->i_fop = &cifs_file_ops; - if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) - tmp_inode->i_fop->lock = NULL; + tmp_inode->i_data.a_ops = &cifs_addr_ops; if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server->maxBuf < @@ -258,6 +274,9 @@ static void unix_fill_in_inode(struct inode *tmp_inode, cifs_NTtimeToUnix(le64_to_cpu(pfindData->LastStatusChange)); tmp_inode->i_mode = le64_to_cpu(pfindData->Permissions); + /* since we set the inode type below we need to mask off type + to avoid strange results if bits above were corrupt */ + tmp_inode->i_mode &= ~S_IFMT; if (type == UNIX_FILE) { *pobject_type = DT_REG; tmp_inode->i_mode |= S_IFREG; @@ -283,6 +302,11 @@ static void unix_fill_in_inode(struct inode *tmp_inode, } else if (type == UNIX_SOCKET) { *pobject_type = DT_SOCK; tmp_inode->i_mode |= S_IFSOCK; + } else { + /* safest to just call it a file */ + *pobject_type = DT_REG; + tmp_inode->i_mode |= S_IFREG; + cFYI(1,("unknown inode type %d",type)); } tmp_inode->i_uid = le64_to_cpu(pfindData->Uid); @@ -302,12 +326,18 @@ static void unix_fill_in_inode(struct inode *tmp_inode, if (S_ISREG(tmp_inode->i_mode)) { cFYI(1, ("File inode")); tmp_inode->i_op = &cifs_file_inode_ops; - if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) - tmp_inode->i_fop = &cifs_file_direct_ops; + + if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DIRECT_IO) { + if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) + tmp_inode->i_fop = &cifs_file_direct_nobrl_ops; + else + tmp_inode->i_fop = &cifs_file_direct_ops; + + } else if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) + tmp_inode->i_fop = &cifs_file_nobrl_ops; else tmp_inode->i_fop = &cifs_file_ops; - if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_BRL) - tmp_inode->i_fop->lock = NULL; + tmp_inode->i_data.a_ops = &cifs_addr_ops; if((cifs_sb->tcon) && (cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->server->maxBuf < @@ -699,7 +729,7 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst, (__le16 *)filename, len/2, nlt); else pqst->len = cifs_strfromUCS_le((char *)pqst->name, - (wchar_t *)filename,len/2,nlt); + (__le16 *)filename,len/2,nlt); } else { pqst->name = filename; pqst->len = len; diff --git a/fs/cifs/rfc1002pdu.h b/fs/cifs/rfc1002pdu.h index 9222033..aede606 100644 --- a/fs/cifs/rfc1002pdu.h +++ b/fs/cifs/rfc1002pdu.h @@ -24,11 +24,11 @@ /* NB: unlike smb/cifs packets, the RFC1002 structures are big endian */ /* RFC 1002 session packet types */ -#define RFC1002_SESSION_MESASAGE 0x00 +#define RFC1002_SESSION_MESSAGE 0x00 #define RFC1002_SESSION_REQUEST 0x81 #define RFC1002_POSITIVE_SESSION_RESPONSE 0x82 #define RFC1002_NEGATIVE_SESSION_RESPONSE 0x83 -#define RFC1002_RETARGET_SESSION_RESPONSE 0x83 +#define RFC1002_RETARGET_SESSION_RESPONSE 0x84 #define RFC1002_SESSION_KEEP_ALIVE 0x85 /* RFC 1002 flags (only one defined */ diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 981ea0d..7b98792 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -206,7 +206,6 @@ smb_send(struct socket *ssocket, struct smb_hdr *smb_buffer, return rc; } -#ifdef CONFIG_CIFS_EXPERIMENTAL static int smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, struct sockaddr *sin) @@ -299,7 +298,7 @@ smb_send2(struct socket *ssocket, struct kvec *iov, int n_vec, int SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, - struct kvec *iov, int n_vec, int *pbytes_returned, + struct kvec *iov, int n_vec, int * pRespBufType /* ret */, const int long_op) { int rc = 0; @@ -307,6 +306,8 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, unsigned long timeout; struct mid_q_entry *midQ; struct smb_hdr *in_buf = iov[0].iov_base; + + *pRespBufType = CIFS_NO_BUFFER; /* no response buf yet */ if (ses == NULL) { cERROR(1,("Null smb session")); @@ -392,8 +393,7 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, return -ENOMEM; } -/* BB FIXME */ -/* rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); */ + rc = cifs_sign_smb2(iov, n_vec, ses->server, &midQ->sequence_number); midQ->midState = MID_REQUEST_SUBMITTED; #ifdef CONFIG_CIFS_STATS2 @@ -489,21 +489,23 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, receive_len, xid)); rc = -EIO; } else { /* rcvd frame is ok */ - if (midQ->resp_buf && (midQ->midState == MID_RESPONSE_RECEIVED)) { - in_buf->smb_buf_length = receive_len; - /* BB verify that length would not overrun small buf */ - memcpy((char *)in_buf + 4, - (char *)midQ->resp_buf + 4, - receive_len); - dump_smb(in_buf, 80); + iov[0].iov_base = (char *)midQ->resp_buf; + if(midQ->largeBuf) + *pRespBufType = CIFS_LARGE_BUFFER; + else + *pRespBufType = CIFS_SMALL_BUFFER; + iov[0].iov_len = receive_len + 4; + iov[1].iov_len = 0; + + dump_smb(midQ->resp_buf, 80); /* convert the length into a more usable form */ if((receive_len > 24) && (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))) { - rc = cifs_verify_signature(in_buf, + rc = cifs_verify_signature(midQ->resp_buf, ses->server->mac_signing_key, midQ->sequence_number+1); if(rc) { @@ -512,17 +514,19 @@ SendReceive2(const unsigned int xid, struct cifsSesInfo *ses, } } - *pbytes_returned = in_buf->smb_buf_length; - /* BB special case reconnect tid and uid here? */ - rc = map_smb_to_linux_error(in_buf); + /* BB special case Errbadpassword and pwdexpired here */ + 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 */ + - (2 * in_buf->WordCount) + 2 /* bcc */ ) - BCC(in_buf) = le16_to_cpu(BCC(in_buf)); + (2 * midQ->resp_buf->WordCount) + 2 /* bcc */ ) + BCC(midQ->resp_buf) = + le16_to_cpu(BCC_LE(midQ->resp_buf)); + midQ->resp_buf = NULL; /* mark it so will not be freed + by DeleteMidQEntry */ } else { rc = -EIO; cFYI(1,("Bad MID state?")); @@ -548,7 +552,6 @@ out_unlock2: return rc; } -#endif /* CIFS_EXPERIMENTAL */ int SendReceive(const unsigned int xid, struct cifsSesInfo *ses, @@ -786,10 +789,10 @@ SendReceive(const unsigned int xid, struct cifsSesInfo *ses, sizeof (struct smb_hdr) - 4 /* do not count RFC1001 header */ + (2 * out_buf->WordCount) + 2 /* bcc */ ) - BCC(out_buf) = le16_to_cpu(BCC(out_buf)); + BCC(out_buf) = le16_to_cpu(BCC_LE(out_buf)); } else { rc = -EIO; - cERROR(1,("Bad MID state? ")); + cERROR(1,("Bad MID state?")); } } cifs_no_response_exit: diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index f375f87..777e336 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c @@ -254,7 +254,8 @@ ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name, rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value, buf_size, cifs_sb->local_nls, cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); - } else if(strncmp(ea_name,POSIX_ACL_XATTR_ACCESS,strlen(POSIX_ACL_XATTR_ACCESS)) == 0) { + } else if(strncmp(ea_name,POSIX_ACL_XATTR_ACCESS, + strlen(POSIX_ACL_XATTR_ACCESS)) == 0) { #ifdef CONFIG_CIFS_POSIX if(sb->s_flags & MS_POSIXACL) rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, @@ -262,10 +263,27 @@ 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) { + __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(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 */ + #else cFYI(1,("query POSIX ACL not supported yet")); #endif /* CONFIG_CIFS_POSIX */ - } else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT,strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) { + } else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT, + strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) { #ifdef CONFIG_CIFS_POSIX if(sb->s_flags & MS_POSIXACL) rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, |