From 701f3b0b3837b0830a4e1a9a2cdfe41bfbf78ef5 Mon Sep 17 00:00:00 2001 From: Steve French Date: Wed, 16 Jul 2003 10:36:51 -0500 Subject: Fix inverted kmalloc parm ordering (noticed by Zwane) that caused oops on mounts of long server names (reported on bugzilla). Fix multiuser mount option. --- fs/cifs/CHANGES | 9 +++++++++ fs/cifs/TODO | 17 +++++++++-------- fs/cifs/cifsfs.c | 2 +- fs/cifs/cifsglob.h | 3 ++- fs/cifs/connect.c | 7 ++++--- fs/cifs/misc.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ fs/cifs/transport.c | 6 +++++- 7 files changed, 77 insertions(+), 14 deletions(-) diff --git a/fs/cifs/CHANGES b/fs/cifs/CHANGES index 6b9ac0a61665..031e2073d78d 100644 --- a/fs/cifs/CHANGES +++ b/fs/cifs/CHANGES @@ -1,3 +1,12 @@ +Version 0.83 +------------ +Fix oops when mounting to long server names caused by inverted parms to kmalloc. +Fix MultiuserMount (/proc/fs/cifs configuration setting) so that when enabled +we will choose a cifs user session (smb uid) that better matches the local +uid if a) the mount uid does not match the current uid and b) we have another +session to the same server (ip address) for a different mount which +matches the current local uid. + Version 0.82 ------------ Add support for mknod of block or character devices. Fix oplock diff --git a/fs/cifs/TODO b/fs/cifs/TODO index 28a2c85fb926..034ee77dd391 100644 --- a/fs/cifs/TODO +++ b/fs/cifs/TODO @@ -17,9 +17,12 @@ c) multi-user mounts - multiplexed sessionsetups over single vc d) Kerberos/SPNEGO session setup support - (started) -e) NTLMv2 authentication and MD5-HMAC signing SMB PDUs - (mostly implemented) - signing necessary for some Windows 2003 servers in domain - mode. +e) NTLMv2 authentication (mostly implemented) + +f) MD5-HMAC signing SMB PDUs when SPNEGO style SessionSetup +used (Kerberos or NTLMSSP). Signing alreadyimplemented for NTLM + and raw NTLMSSP already. This is important when enabling + extended security and mounting to Windows 2003 Servers f) Directory entry caching relies on a 1 second timer, rather than using FindNotify or equivalent. - (started) @@ -43,11 +46,9 @@ extra copy in/out of the socket buffers in some cases. m) finish support for IPv6 -n) send oplock break response when sent (oplock currently disabled in -/proc/fs/cifs) - -o) reduces the oplock breaks coming from windows). Piggyback identical -file opens on top of each other by incrementing reference count rather +o) Better optimize open (and pathbased setfilesize) to reduce the +oplock breaks coming from windows srv. Piggyback identical file +opens on top of each other by incrementing reference count rather than resending (helps reduce server resource utilization and avoid spurious oplock breaks). diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 5bba77c54433..0b8e3ba92647 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -230,7 +230,7 @@ cifs_show_options(struct seq_file *s, struct vfsmount *m) if (cifs_sb) { if (cifs_sb->tcon) { seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName); - if (cifs_sb->tcon->ses->userName) + if ((cifs_sb->tcon->ses) && (cifs_sb->tcon->ses->userName)) seq_printf(s, ",username=%s", cifs_sb->tcon->ses->userName); if(cifs_sb->tcon->ses->domainName) diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 5b0ae3bc20cb..6d65f4c71e1f 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h @@ -155,7 +155,8 @@ struct cifsSesInfo { char *serverOS; /* name of operating system underlying the server */ char *serverNOS; /* name of network operating system that the server is running */ char *serverDomain; /* security realm of server */ - int Suid; /* needed for user level security */ + int Suid; /* remote smb uid */ + uid_t linux_uid; /* local Linux uid */ int capabilities; char serverName[SERVER_NAME_LEN_WITH_NULL * 2]; /* BB make bigger for tcp names - will ipv6 and sctp addresses fit here?? */ char userName[MAX_USERNAME_SIZE + 1]; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index a7220c051534..7c4e046b401d 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -405,7 +405,7 @@ parse_mount_options(char *options, const char *devname, struct smb_vol *vol) return 1; /* needs_arg; */ } if ((temp_len = strnlen(value, 300)) < 300) { - vol->UNC = kmalloc(GFP_KERNEL, temp_len); + vol->UNC = kmalloc(temp_len+1,GFP_KERNEL); strcpy(vol->UNC,value); if (strncmp(vol->UNC, "//", 2) == 0) { vol->UNC[0] = '\\'; @@ -482,7 +482,7 @@ parse_mount_options(char *options, const char *devname, struct smb_vol *vol) return 1; } if ((temp_len = strnlen(devname, 300)) < 300) { - vol->UNC = kmalloc(GFP_KERNEL, temp_len); + vol->UNC = kmalloc(temp_len+1,GFP_KERNEL); strcpy(vol->UNC,devname); if (strncmp(vol->UNC, "//", 2) == 0) { vol->UNC[0] = '\\'; @@ -860,7 +860,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, FreeXid(xid); return -EINVAL; } - /* BB add support to use the multiuser_mount flag BB */ + existingCifsSes = find_tcp_session(sin_server.sin_addr.s_addr, volume_info.username, &srvTcp); @@ -926,6 +926,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, if (volume_info.domainname) strncpy(pSesInfo->domainName, volume_info.domainname,MAX_USERNAME_SIZE); + pSesInfo->linux_uid = volume_info.linux_uid; rc = setup_session(xid,pSesInfo, cifs_sb->local_nls); if(!rc) diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 896c18d1a7f5..7f3a5b905732 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c @@ -190,6 +190,8 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , { int i; __u32 tmp; + struct list_head* temp_item; + struct cifsSesInfo * ses; char *temp = (char *) buffer; for (i = 0; i < MAX_CIFS_HDR_SIZE; i++) { @@ -225,7 +227,52 @@ header_assemble(struct smb_hdr *buffer, char smb_command /* command */ , if (treeCon->ses->capabilities & CAP_STATUS32) { buffer->Flags2 |= SMBFLG2_ERR_STATUS; } + buffer->Uid = treeCon->ses->Suid; /* always in LE format */ + if(multiuser_mount != 0) { + /* For the multiuser case, there are few obvious technically */ + /* possible mechanisms to match the local linux user (uid) */ + /* to a valid remote smb user (smb_uid): */ + /* 1) Query Winbind (or other local pam/nss daemon */ + /* for userid/password/logon_domain or credential */ + /* 2) Query Winbind for uid to sid to username mapping */ + /* and see if we have a matching password for existing*/ + /* session for that user perhas getting password by */ + /* adding a new pam_cifs module that stores passwords */ + /* so that the cifs vfs can get at that for all logged*/ + /* on users */ + /* 3) (Which is the mechanism we have chosen) */ + /* Search through sessions to the same server for a */ + /* a match on the uid that was passed in on mount */ + /* with the current processes uid (or euid?) and use */ + /* that smb uid. If no existing smb session for */ + /* that uid found, use the default smb session ie */ + /* the smb session for the volume mounted which is */ + /* the same as would be used if the multiuser mount */ + /* flag were disabled. */ + + /* 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 ")); + 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->server == treeCon->ses->server) { + cFYI(1,("found matching uid substitute right smb_uid")); + buffer->Uid = ses->Suid; + break; + } else { + /* BB eventually call setup_session here */ + cFYI(1,("local UID found but smb sess with this server does not exist")); + } + } + } + read_unlock(&GlobalSMBSeslock); + } + } } if (treeCon->Flags & SMB_SHARE_IS_IN_DFS) buffer->Flags2 |= SMBFLG2_DFS; diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c index 9273610cc7a8..7a667c06e3b1 100644 --- a/fs/cifs/transport.c +++ b/fs/cifs/transport.c @@ -45,6 +45,11 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) cERROR(1, ("Null session passed in to AllocMidQEntry ")); return NULL; } + if (ses->server == NULL) { + cERROR(1, ("Null TCP session in AllocMidQEntry")); + return NULL; + } + temp = (struct mid_q_entry *) kmem_cache_alloc(cifs_mid_cachep, SLAB_KERNEL); if (temp == NULL) @@ -65,7 +70,6 @@ AllocMidQEntry(struct smb_hdr *smb_buffer, struct cifsSesInfo *ses) /* Should we wake up tcp thread first? BB */ timeout = wait_event_interruptible_timeout(ses->server->response_q, (ses->server->tcpStatus == CifsGood), timeout); - cFYI(1,("timeout (after reconnection wait) %d",timeout)); } if (ses->server->tcpStatus == CifsGood) { -- cgit v1.2.3