vserver 1.9.5.x5
[linux-2.6.git] / fs / cifs / connect.c
index e548bb3..ff8a4df 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/string.h>
 #include <linux/list.h>
 #include <linux/wait.h>
-#include <linux/version.h>
 #include <linux/ipv6.h>
 #include <linux/pagemap.h>
 #include <linux/ctype.h>
@@ -58,6 +57,7 @@ struct smb_vol {
        char *domainname;
        char *UNC;
        char *UNCip;
+       char *in6_addr;  /* ipv6 address as human readable form of in6_addr */
        char *iocharset;  /* local code page for mapping to and from Unicode */
        char source_rfc1001_name[16]; /* netbios name of client */
        uid_t linux_uid;
@@ -69,6 +69,9 @@ struct smb_vol {
        unsigned intr:1;
        unsigned setuids:1;
        unsigned noperm:1;
+       unsigned no_psx_acl:1; /* set if posix acl support should be disabled */
+       unsigned server_ino:1; /* use inode numbers from server ie UniqueId */
+       unsigned direct_io:1;
        unsigned int rsize;
        unsigned int wsize;
        unsigned int sockopt;
@@ -213,7 +216,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
        write_unlock(&GlobalSMBSeslock);
        if(length  > 1) {
                mempool_resize(cifs_req_poolp,
-                       length + CIFS_MIN_RCV_POOL,
+                       length + cifs_min_rcv,
                        GFP_KERNEL);
        }
 
@@ -250,7 +253,8 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                        cFYI(1,("call to reconnect done"));
                        csocket = server->ssocket;
                        continue;
-               } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)) {
+               } else if ((length == -ERESTARTSYS) || (length == -EAGAIN)
+                               || ((length > 0) && (length <= 3)) ) {
                        set_current_state(TASK_INTERRUPTIBLE);
                        schedule_timeout(1); /* minimum sleep to prevent looping
                                allowing socket to clear and app threads to set
@@ -276,7 +280,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                }
 
                pdu_length = 4 + ntohl(smb_buffer->smb_buf_length);
-               /* Ony read pdu_length after below checks for too short (due
+               /* Only read pdu_length after below checks for too short (due
                   to e.g. int overflow) and too long ie beyond end of buf */
                cFYI(1, ("Peek length rcvd: 0x%x beginning 0x%x)", length, pdu_length));
 
@@ -326,18 +330,24 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
                                csocket = server->ssocket;
                                continue;
                        } else {
-                               if ((length != sizeof (struct smb_hdr) - 1)
-                                   || (pdu_length >
-                                       CIFS_MAX_MSGSIZE + MAX_CIFS_HDR_SIZE)
+                               if (length < 16) {
+                                       /* We can not validate the SMB unless 
+                                       at least this much of SMB available
+                                       so give the socket time to copy
+                                       a few more bytes and retry */ 
+                                       set_current_state(TASK_INTERRUPTIBLE);
+                                       schedule_timeout(10);
+                                       continue;
+                               } else if( (pdu_length >
+                                       CIFSMaxBufSize + MAX_CIFS_HDR_SIZE)
                                    || (pdu_length <
                                        sizeof (struct smb_hdr) - 1)
-                                   ||
-                                   (checkSMBhdr
+                                   || (checkSMBhdr
                                     (smb_buffer, smb_buffer->Mid))) {
                                        cERROR(1,
-                                           ("Invalid size or format for SMB found with length %d and pdu_lenght %d",
+                                           ("Invalid size or format for SMB found with length %d and pdu_length %d",
                                                length, pdu_length));
-                                       cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr));
+                                       cifs_dump_mem("Received Data is: ",temp,sizeof(struct smb_hdr)+3);
                                        /* could we fix this network corruption by finding next 
                                                smb header (instead of killing the session) and
                                                restart reading from next valid SMB found? */
@@ -485,7 +495,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
        write_unlock(&GlobalSMBSeslock);
        if(length  > 0) {
                mempool_resize(cifs_req_poolp,
-                       length + CIFS_MIN_RCV_POOL,
+                       length + cifs_min_rcv,
                        GFP_KERNEL);
        }
 
@@ -505,7 +515,7 @@ cifs_kcalloc(size_t size, int type)
 }
 
 static int
-cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol)
+cifs_parse_mount_options(char *options, const char *devname,struct smb_vol *vol)
 {
        char *value;
        char *data;
@@ -692,7 +702,12 @@ cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol
                                vol->file_mode =
                                        simple_strtoul(value, &value, 0);
                        }
-               } else if (strnicmp(data, "dir_mode", 3) == 0) {
+               } else if (strnicmp(data, "dir_mode", 4) == 0) {
+                       if (value && *value) {
+                               vol->dir_mode =
+                                       simple_strtoul(value, &value, 0);
+                       }
+               } else if (strnicmp(data, "dirmode", 4) == 0) {
                        if (value && *value) {
                                vol->dir_mode =
                                        simple_strtoul(value, &value, 0);
@@ -742,6 +757,8 @@ cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol
                        /* ignore */
                } else if (strnicmp(data, "version", 3) == 0) {
                        /* ignore */
+               } else if (strnicmp(data, "guest",5) == 0) {
+                       /* ignore */
                } else if (strnicmp(data, "rw", 2) == 0) {
                        vol->rw = TRUE;
                } else if ((strnicmp(data, "suid", 4) == 0) ||
@@ -780,6 +797,27 @@ cifs_parse_mount_options(char *options, const char *devname, struct smb_vol *vol
                        vol->intr = 0;
                } else if (strnicmp(data, "intr", 4) == 0) {
                        vol->intr = 1;
+               } else if (strnicmp(data, "serverino",7) == 0) {
+                       vol->server_ino = 1;
+               } else if (strnicmp(data, "noserverino",9) == 0) {
+                       vol->server_ino = 0;
+               } else if (strnicmp(data, "acl",3) == 0) {
+                       vol->no_psx_acl = 0;
+               } else if (strnicmp(data, "noacl",5) == 0) {
+                       vol->no_psx_acl = 1;
+               } else if (strnicmp(data, "direct",6) == 0) {
+                       vol->direct_io = 1;
+               } else if (strnicmp(data, "forcedirectio",13) == 0) {
+                       vol->direct_io = 1;
+               } else if (strnicmp(data, "in6_addr",8) == 0) {
+                       if (!value || !*value) {
+                               vol->in6_addr = NULL;
+                       } else if (strnlen(value, 49) == 48) {
+                               vol->in6_addr = value;
+                       } else {
+                               printk(KERN_WARNING "CIFS: ip v6 address not 48 characters long\n");
+                               return 1;
+                       }
                } else if (strnicmp(data, "noac", 4) == 0) {
                        printk(KERN_WARNING "CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
                } else
@@ -1393,6 +1431,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
                if(volume_info.setuids)
                        cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
+               if(volume_info.server_ino)
+                       cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
+               if(volume_info.direct_io) {
+                       cERROR(1,("mounting share using direct i/o"));
+                       cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
+               }
 
                tcon =
                    find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
@@ -1444,6 +1488,8 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                        sb->s_maxbytes = (u64) 1 << 31; /* 2 GB */
        }
 
+       sb->s_time_gran = 100;
+
 /* on error free sesinfo and tcon struct if needed */
        if (rc) {
                /* if session setup failed, use count is zero but
@@ -1482,8 +1528,16 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
                /* do not care if following two calls succeed - informational only */
                CIFSSMBQFSDeviceInfo(xid, tcon, cifs_sb->local_nls);
                CIFSSMBQFSAttributeInfo(xid, tcon, cifs_sb->local_nls);
-               if (tcon->ses->capabilities & CAP_UNIX)
-                       CIFSSMBQFSUnixInfo(xid, tcon, cifs_sb->local_nls);
+               if (tcon->ses->capabilities & CAP_UNIX) {
+                       if(!CIFSSMBQFSUnixInfo(xid, tcon, cifs_sb->local_nls)) {
+                               if(!volume_info.no_psx_acl) {
+                                       if(CIFS_UNIX_POSIX_ACL_CAP & 
+                                          le64_to_cpu(tcon->fsUnixInfo.Capability))
+                                               cFYI(1,("server negotiated posix acl support"));
+                                               sb->s_flags |= MS_POSIXACL;
+                               }
+                       }
+               }
        }
 
        /* volume_info.password is freed above when existing session found
@@ -1552,14 +1606,15 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                capabilities |= CAP_DFS;
        }
        pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
-       /* pSMB->req_no_secext.CaseInsensitivePasswordLength =
-          CIFS_SESSION_KEY_SIZE; */
-       pSMB->req_no_secext.CaseInsensitivePasswordLength = 0;
+
+       pSMB->req_no_secext.CaseInsensitivePasswordLength = 
+               cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+
        pSMB->req_no_secext.CaseSensitivePasswordLength =
            cpu_to_le16(CIFS_SESSION_KEY_SIZE);
        bcc_ptr = pByteArea(smb_buffer);
-       /* memcpy(bcc_ptr, (char *) lm_session_key, CIFS_SESSION_KEY_SIZE);
-          bcc_ptr += CIFS_SESSION_KEY_SIZE; */
+       memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
+       bcc_ptr += CIFS_SESSION_KEY_SIZE;
        memcpy(bcc_ptr, (char *) session_key, CIFS_SESSION_KEY_SIZE);
        bcc_ptr += CIFS_SESSION_KEY_SIZE;
 
@@ -1591,7 +1646,7 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                  32, nls_codepage);
                bcc_ptr += 2 * bytes_returned;
                bytes_returned =
-                   cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
+                   cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
                                  nls_codepage);
                bcc_ptr += 2 * bytes_returned;
                bcc_ptr += 2;
@@ -1618,8 +1673,8 @@ CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                }
                strcpy(bcc_ptr, "Linux version ");
                bcc_ptr += strlen("Linux version ");
-               strcpy(bcc_ptr, UTS_RELEASE);
-               bcc_ptr += strlen(UTS_RELEASE) + 1;
+               strcpy(bcc_ptr, system_utsname.release);
+               bcc_ptr += strlen(system_utsname.release) + 1;
                strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
                bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
        }
@@ -1835,7 +1890,7 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                  32, nls_codepage);
                bcc_ptr += 2 * bytes_returned;
                bytes_returned =
-                   cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
+                   cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
                                  nls_codepage);
                bcc_ptr += 2 * bytes_returned;
                bcc_ptr += 2;
@@ -1860,8 +1915,8 @@ CIFSSpnegoSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                }
                strcpy(bcc_ptr, "Linux version ");
                bcc_ptr += strlen("Linux version ");
-               strcpy(bcc_ptr, UTS_RELEASE);
-               bcc_ptr += strlen(UTS_RELEASE) + 1;
+               strcpy(bcc_ptr, system_utsname.release);
+               bcc_ptr += strlen(system_utsname.release) + 1;
                strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
                bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
        }
@@ -2124,7 +2179,7 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
                                  32, nls_codepage);
                bcc_ptr += 2 * bytes_returned;
                bytes_returned =
-                   cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
+                   cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
                                  nls_codepage);
                bcc_ptr += 2 * bytes_returned;
                bcc_ptr += 2;   /* null terminate Linux version */
@@ -2141,8 +2196,8 @@ CIFSNTLMSSPNegotiateSessSetup(unsigned int xid,
        } else {                /* ASCII */
                strcpy(bcc_ptr, "Linux version ");
                bcc_ptr += strlen("Linux version ");
-               strcpy(bcc_ptr, UTS_RELEASE);
-               bcc_ptr += strlen(UTS_RELEASE) + 1;
+               strcpy(bcc_ptr, system_utsname.release);
+               bcc_ptr += strlen(system_utsname.release) + 1;
                strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
                bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
                bcc_ptr++;      /* empty domain field */
@@ -2509,7 +2564,7 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
                                  32, nls_codepage);
                bcc_ptr += 2 * bytes_returned;
                bytes_returned =
-                   cifs_strtoUCS((wchar_t *) bcc_ptr, UTS_RELEASE, 32,
+                   cifs_strtoUCS((wchar_t *) bcc_ptr, system_utsname.release, 32,
                                  nls_codepage);
                bcc_ptr += 2 * bytes_returned;
                bcc_ptr += 2;   /* null term version string */
@@ -2561,8 +2616,8 @@ CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses,
 
                strcpy(bcc_ptr, "Linux version ");
                bcc_ptr += strlen("Linux version ");
-               strcpy(bcc_ptr, UTS_RELEASE);
-               bcc_ptr += strlen(UTS_RELEASE) + 1;
+               strcpy(bcc_ptr, system_utsname.release);
+               bcc_ptr += strlen(system_utsname.release) + 1;
                strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
                bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
                bcc_ptr++;      /* null domain */