[PATCH] knfsd: nfsd4: represent nfsv4 acl with array instead of linked list
[pandora-kernel.git] / fs / cifs / connect.c
index c787620..20ba7dc 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/delay.h>
 #include <linux/completion.h>
 #include <linux/pagevec.h>
+#include <linux/freezer.h>
 #include <asm/uaccess.h>
 #include <asm/processor.h>
 #include "cifspdu.h"
@@ -109,7 +110,7 @@ static int ipv6_connect(struct sockaddr_in6 *psin_server,
         * wake up waiters on reconnection? - (not needed currently)
         */
 
-int
+static int
 cifs_reconnect(struct TCP_Server_Info *server)
 {
        int rc = 0;
@@ -771,13 +772,18 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
        separator[0] = ',';
        separator[1] = 0; 
 
-       memset(vol->source_rfc1001_name,0x20,15);
-       for(i=0;i < strnlen(utsname()->nodename,15);i++) {
-               /* does not have to be a perfect mapping since the field is
-               informational, only used for servers that do not support
-               port 445 and it can be overridden at mount time */
-               vol->source_rfc1001_name[i] = 
-                       toupper(utsname()->nodename[i]);
+       if (Local_System_Name[0] != 0)
+               memcpy(vol->source_rfc1001_name, Local_System_Name,15);
+       else {
+               char *nodename = utsname()->nodename;
+               int n = strnlen(nodename,15);
+               memset(vol->source_rfc1001_name,0x20,15);
+               for(i=0 ; i < n ; i++) {
+                       /* does not have to be perfect mapping since field is
+                       informational, only used for servers that do not support
+                       port 445 and it can be overridden at mount time */
+                       vol->source_rfc1001_name[i] = toupper(nodename[i]);
+               }
        }
        vol->source_rfc1001_name[15] = 0;
        /* null target name indicates to use *SMBSERVR default called name
@@ -817,10 +823,13 @@ cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
                } else if (strnicmp(data, "nouser_xattr",12) == 0) {
                        vol->no_xattr = 1;
                } else if (strnicmp(data, "user", 4) == 0) {
-                       if (!value || !*value) {
+                       if (!value) {
                                printk(KERN_WARNING
                                       "CIFS: invalid or missing username\n");
                                return 1;       /* needs_arg; */
+                       } else if(!*value) {
+                               /* null user, ie anonymous, authentication */
+                               vol->nullauth = 1;
                        }
                        if (strnlen(value, 200) < 200) {
                                vol->username = value;
@@ -1604,6 +1613,76 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
        return rc;
 }
 
+void reset_cifs_unix_caps(int xid, struct cifsTconInfo * tcon, 
+                         struct super_block * sb, struct smb_vol * vol_info)
+{
+       /* if we are reconnecting then should we check to see if
+        * any requested capabilities changed locally e.g. via
+        * remount but we can not do much about it here
+        * if they have (even if we could detect it by the following)
+        * Perhaps we could add a backpointer to array of sb from tcon
+        * or if we change to make all sb to same share the same
+        * sb as NFS - then we only have one backpointer to sb.
+        * What if we wanted to mount the server share twice once with
+        * and once without posixacls or posix paths? */
+       __u64 saved_cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
+          
+        
+       if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
+               __u64 cap = le64_to_cpu(tcon->fsUnixInfo.Capability);
+               
+               /* check for reconnect case in which we do not
+                  want to change the mount behavior if we can avoid it */
+               if(vol_info == NULL) {
+                       /* turn off POSIX ACL and PATHNAMES if not set 
+                          originally at mount time */
+                       if ((saved_cap & CIFS_UNIX_POSIX_ACL_CAP) == 0)
+                               cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
+                       if ((saved_cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) == 0)
+                               cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
+                               
+
+                        
+                       
+               }
+               
+               cap &= CIFS_UNIX_CAP_MASK;
+               if(vol_info && vol_info->no_psx_acl)
+                       cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
+               else if(CIFS_UNIX_POSIX_ACL_CAP & cap) {
+                       cFYI(1,("negotiated posix acl support"));
+                       if(sb)
+                               sb->s_flags |= MS_POSIXACL;
+               }
+
+               if(vol_info && vol_info->posix_paths == 0)
+                       cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
+               else if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
+                       cFYI(1,("negotiate posix pathnames"));
+                       if(sb)
+                               CIFS_SB(sb)->mnt_cifs_flags |= 
+                                       CIFS_MOUNT_POSIX_PATHS;
+               }
+                       
+               cFYI(1,("Negotiate caps 0x%x",(int)cap));
+#ifdef CONFIG_CIFS_DEBUG2
+               if(cap & CIFS_UNIX_FCNTL_CAP)
+                       cFYI(1,("FCNTL cap"));
+               if(cap & CIFS_UNIX_EXTATTR_CAP)
+                       cFYI(1,("EXTATTR cap"));
+               if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
+                       cFYI(1,("POSIX path cap"));
+               if(cap & CIFS_UNIX_XATTR_CAP)
+                       cFYI(1,("XATTR cap"));
+               if(cap & CIFS_UNIX_POSIX_ACL_CAP)
+                       cFYI(1,("POSIX ACL cap"));
+#endif /* CIFS_DEBUG2 */
+               if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
+                       cFYI(1,("setting capabilities failed"));
+               }
+       }
+}
+
 int
 cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
           char *mount_data, const char *devname)
@@ -1637,6 +1716,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                /* BB fixme parse for domain name here */
                cFYI(1, ("Username: %s ", volume_info.username));
 
+       } else if (volume_info.nullauth) {
+               cFYI(1,("null user"));
        } else {
                cifserror("No username specified");
         /* In userspace mount helper we can get user name from alternate
@@ -1917,20 +1998,25 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        if (tcon == NULL)
                                rc = -ENOMEM;
                        else {
-                               /* check for null share name ie connect to dfs root */
+                               /* check for null share name ie connecting to 
+                                * dfs root */
 
-                               /* BB check if this works for exactly length three strings */
+                               /* BB check if this works for exactly length 
+                                * three strings */
                                if ((strchr(volume_info.UNC + 3, '\\') == NULL)
                                    && (strchr(volume_info.UNC + 3, '/') ==
                                        NULL)) {
                                        rc = connect_to_dfs_path(xid, pSesInfo,
-                                                       "", cifs_sb->local_nls,
-                                                       cifs_sb->mnt_cifs_flags & 
-                                                         CIFS_MOUNT_MAP_SPECIAL_CHR);
+                                               "", cifs_sb->local_nls,
+                                               cifs_sb->mnt_cifs_flags & 
+                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
                                        kfree(volume_info.UNC);
                                        FreeXid(xid);
                                        return -ENODEV;
                                } else {
+                                       /* BB Do we need to wrap sesSem around
+                                        * this TCon call and Unix SetFS as
+                                        * we do on SessSetup and reconnect? */
                                        rc = CIFSTCon(xid, pSesInfo, 
                                                volume_info.UNC,
                                                tcon, cifs_sb->local_nls);
@@ -1951,6 +2037,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
        }
 
+       /* BB FIXME fix time_gran to be larger for LANMAN sessions */
        sb->s_time_gran = 100;
 
 /* on error free sesinfo and tcon struct if needed */
@@ -1995,45 +2082,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                /* do not care if following two calls succeed - informational */
                CIFSSMBQFSDeviceInfo(xid, tcon);
                CIFSSMBQFSAttributeInfo(xid, tcon);
-
-               if (tcon->ses->capabilities & CAP_UNIX) {
-                       if(!CIFSSMBQFSUnixInfo(xid, tcon)) {
-                               __u64 cap = 
-                                      le64_to_cpu(tcon->fsUnixInfo.Capability);
-                               cap &= CIFS_UNIX_CAP_MASK;
-                               if(volume_info.no_psx_acl)
-                                       cap &= ~CIFS_UNIX_POSIX_ACL_CAP;
-                               else if(CIFS_UNIX_POSIX_ACL_CAP & cap) {
-                                       cFYI(1,("negotiated posix acl support"));
-                                       sb->s_flags |= MS_POSIXACL;
-                               }
-
-                               if(volume_info.posix_paths == 0)
-                                       cap &= ~CIFS_UNIX_POSIX_PATHNAMES_CAP;
-                               else if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP) {
-                                       cFYI(1,("negotiate posix pathnames"));
-                                       cifs_sb->mnt_cifs_flags |= 
-                                               CIFS_MOUNT_POSIX_PATHS;
-                               }
-                                       
-                               cFYI(1,("Negotiate caps 0x%x",(int)cap));
-#ifdef CONFIG_CIFS_DEBUG2
-                               if(cap & CIFS_UNIX_FCNTL_CAP)
-                                       cFYI(1,("FCNTL cap"));
-                               if(cap & CIFS_UNIX_EXTATTR_CAP)
-                                       cFYI(1,("EXTATTR cap"));
-                               if(cap & CIFS_UNIX_POSIX_PATHNAMES_CAP)
-                                       cFYI(1,("POSIX path cap"));
-                               if(cap & CIFS_UNIX_XATTR_CAP)
-                                       cFYI(1,("XATTR cap"));
-                               if(cap & CIFS_UNIX_POSIX_ACL_CAP)
-                                       cFYI(1,("POSIX ACL cap"));
-#endif /* CIFS_DEBUG2 */
-                               if (CIFSSMBSetFSUnixInfo(xid, tcon, cap)) {
-                                       cFYI(1,("setting capabilities failed"));
-                               }
-                       }
-               }
+               
+               /* tell server which Unix caps we support */
+               if (tcon->ses->capabilities & CAP_UNIX)
+                       reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
+               
                if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
                        cifs_sb->wsize = min(cifs_sb->wsize,
                                             (tcon->ses->server->maxBuf -
@@ -3215,7 +3268,9 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
                        }
                        /* else do not bother copying these informational fields */
                }
-               if(smb_buffer_response->WordCount == 3)
+               if((smb_buffer_response->WordCount == 3) ||
+                        (smb_buffer_response->WordCount == 7))
+                       /* field is in same location */
                        tcon->Flags = le16_to_cpu(pSMBr->OptionalSupport);
                else
                        tcon->Flags = 0;
@@ -3312,19 +3367,21 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                first_time = 1;
        }
        if (!rc) {
+               pSesInfo->flags = 0;
                pSesInfo->capabilities = pSesInfo->server->capabilities;
                if(linuxExtEnabled == 0)
                        pSesInfo->capabilities &= (~CAP_UNIX);
        /*      pSesInfo->sequence_number = 0;*/
-               cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x Time Zone: %d",
+               cFYI(1,("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d",
                        pSesInfo->server->secMode,
                        pSesInfo->server->capabilities,
-                       pSesInfo->server->timeZone));
+                       pSesInfo->server->timeAdj));
                if(experimEnabled < 2)
                        rc = CIFS_SessSetup(xid, pSesInfo,
                                            first_time, nls_info);
                else if (extended_security
-                               && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY)
+                               && (pSesInfo->capabilities 
+                                       & CAP_EXTENDED_SECURITY)
                                && (pSesInfo->server->secType == NTLMSSP)) {
                        rc = -EOPNOTSUPP;
                } else if (extended_security
@@ -3338,7 +3395,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
                        if (!rc) {
                                if(ntlmv2_flag) {
                                        char * v2_response;
-                                       cFYI(1,("Can use more secure NTLM version 2 password hash"));
+                                       cFYI(1,("more secure NTLM ver2 hash"));
                                        if(CalcNTLMv2_partial_mac_key(pSesInfo, 
                                                nls_info)) {
                                                rc = -ENOMEM;