X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=fs%2Fcifs%2Fsess.c;h=a8a083543ba050fa65cceee9a302c9b733f68311;hb=12e36b2f41b6cbc67386fcb9c59c32a3e2033905;hp=70e32a81c213e0267dd3fc76a3d83f479e493c5f;hpb=189acaaef81b1d71aedd0d28810de24160c2e781;p=linux-2.6 diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 70e32a81c2..a8a083543b 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -83,11 +83,11 @@ static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, /* BB FIXME add check that strings total less than 335 or will need to send them as arrays */ - /* align unicode strings, must be word aligned */ - if ((long) bcc_ptr % 2) { + /* unicode strings, must be word aligned before the call */ +/* if ((long) bcc_ptr % 2) { *bcc_ptr = 0; bcc_ptr++; - } + } */ /* copy user */ if(ses->userName == NULL) { /* BB what about null user mounts - check that we do this BB */ @@ -111,7 +111,7 @@ static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, bytes_ret = cifs_strtoUCS((__le16 *)bcc_ptr, "Linux version ", 32, nls_cp); bcc_ptr += 2 * bytes_ret; - bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release, + bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, init_utsname()->release, 32, nls_cp); bcc_ptr += 2 * bytes_ret; bcc_ptr += 2; /* trailing null */ @@ -138,7 +138,7 @@ static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, strncpy(bcc_ptr, ses->userName, 300); } /* BB improve check for overflow */ - bcc_ptr += strnlen(ses->userName, 200); + bcc_ptr += strnlen(ses->userName, 300); *bcc_ptr = 0; bcc_ptr++; /* account for null termination */ @@ -158,8 +158,8 @@ static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, strcpy(bcc_ptr, "Linux version "); bcc_ptr += strlen("Linux version "); - strcpy(bcc_ptr, system_utsname.release); - bcc_ptr += strlen(system_utsname.release) + 1; + strcpy(bcc_ptr, init_utsname()->release); + bcc_ptr += strlen(init_utsname()->release) + 1; strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; @@ -268,6 +268,10 @@ static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo ses->serverOS = kzalloc(len + 1, GFP_KERNEL); if(ses->serverOS) strncpy(ses->serverOS, bcc_ptr, len); + if(strncmp(ses->serverOS, "OS/2",4) == 0) { + cFYI(1,("OS/2 server")); + ses->flags |= CIFS_SES_OS2; + } bcc_ptr += len + 1; bleft -= len + 1; @@ -290,16 +294,11 @@ static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo if(len > bleft) return rc; - if(ses->serverDomain) - kfree(ses->serverDomain); - - ses->serverDomain = kzalloc(len + 1, GFP_KERNEL); - if(ses->serverOS) - strncpy(ses->serverOS, bcc_ptr, len); - - bcc_ptr += len + 1; - bleft -= len + 1; - + /* No domain field in LANMAN case. Domain is + returned by old servers in the SMB negprot response */ + /* BB For newer servers which do not support Unicode, + but thus do return domain here we could add parsing + for it later, but it is not very important */ cFYI(1,("ascii: bytes left %d",bleft)); return rc; @@ -313,20 +312,22 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, int wct; struct smb_hdr *smb_buf; char *bcc_ptr; + char *str_area; SESSION_SETUP_ANDX *pSMB; __u32 capabilities; int count; int resp_buf_type = 0; - struct kvec iov[2]; /* BB split variable length info into 2nd iovec */ + struct kvec iov[2]; enum securityEnum type; __u16 action; int bytes_remaining; - cFYI(1,("new sess setup")); if(ses == NULL) return -EINVAL; type = ses->server->secType; + + cFYI(1,("sess setup type %d",type)); if(type == LANMAN) { #ifndef CONFIG_CIFS_WEAK_PW_HASH /* LANMAN and plaintext are less secure and off by default. @@ -351,7 +352,20 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, pSMB = (SESSION_SETUP_ANDX *)smb_buf; capabilities = cifs_ssetup_hdr(ses, pSMB); - bcc_ptr = pByteArea(smb_buf); + + /* we will send the SMB in two pieces, + a fixed length beginning part, and a + second part which will include the strings + and rest of bcc area, in order to avoid having + to do a large buffer 17K allocation */ + iov[0].iov_base = (char *)pSMB; + iov[0].iov_len = smb_buf->smb_buf_length + 4; + + /* 2000 big enough to fit max user, domain, NOS name etc. */ + str_area = kmalloc(2000, GFP_KERNEL); + bcc_ptr = str_area; + + ses->flags &= ~CIFS_SES_LANMAN; if(type == LANMAN) { #ifdef CONFIG_CIFS_WEAK_PW_HASH @@ -359,16 +373,16 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, /* no capabilities flags in old lanman negotiation */ - pSMB->old_req.PasswordLength = CIFS_SESS_KEY_SIZE; + pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE); /* BB calculate hash with password */ /* and copy into bcc */ calc_lanman_hash(ses, lnm_session_key); - -#ifdef CONFIG_CIFS_DEBUG2 + ses->flags |= CIFS_SES_LANMAN; +/* #ifdef CONFIG_CIFS_DEBUG2 cifs_dump_mem("cryptkey: ",ses->server->cryptKey, CIFS_SESS_KEY_SIZE); -#endif +#endif */ memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESS_KEY_SIZE); bcc_ptr += CIFS_SESS_KEY_SIZE; @@ -377,7 +391,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, changed to do higher than lanman dialect and we reconnected would we ever calc signing_key? */ - cERROR(1,("Negotiating LANMAN setting up strings")); + cFYI(1,("Negotiating LANMAN setting up strings")); /* Unicode not allowed for LANMAN dialects */ ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); #endif @@ -396,7 +410,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, if(first_time) /* should this be moved into common code with similar ntlmv2 path? */ - cifs_calculate_mac_key( ses->server->mac_signing_key, + cifs_calculate_mac_key(ses->server->mac_signing_key, ntlm_session_key, ses->password); /* copy session key */ @@ -404,9 +418,14 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, bcc_ptr += CIFS_SESS_KEY_SIZE; memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESS_KEY_SIZE); bcc_ptr += CIFS_SESS_KEY_SIZE; - if(ses->capabilities & CAP_UNICODE) + if(ses->capabilities & CAP_UNICODE) { + /* unicode strings must be word aligned */ + if (iov[0].iov_len % 2) { + *bcc_ptr = 0; + bcc_ptr++; + } unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); - else + } else ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); } else if (type == NTLMv2) { char * v2_sess_key = @@ -443,9 +462,12 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, memcpy(bcc_ptr, (char *)v2_sess_key, sizeof(struct ntlmv2_resp)); bcc_ptr += sizeof(struct ntlmv2_resp); kfree(v2_sess_key); - if(ses->capabilities & CAP_UNICODE) + if(ses->capabilities & CAP_UNICODE) { + if(iov[0].iov_len % 2) { + *bcc_ptr = 0; + } bcc_ptr++; unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); - else + } else ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); } else /* NTLMSSP or SPNEGO */ { pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; @@ -454,23 +476,14 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, /* BB set password lengths */ } - count = (long) bcc_ptr - (long) pByteArea(smb_buf); + count = (long) bcc_ptr - (long) str_area; smb_buf->smb_buf_length += count; - /* if we switch to small buffers, count will need to be fewer - than 383 (strings less than 335 bytes) */ - BCC_LE(smb_buf) = cpu_to_le16(count); - - /* BB FIXME check for other non ntlm code paths */ - - /* BB check is this too big for a small smb? */ - - iov[0].iov_base = (char *)pSMB; - iov[0].iov_len = smb_buf->smb_buf_length + 4; - - rc = SendReceive2(xid, ses, iov, 1 /* num_iovecs */, &resp_buf_type, 0); + iov[1].iov_base = str_area; + iov[1].iov_len = count; + rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type, 0); /* SMB request buf freed in SendReceive2 */ cFYI(1,("ssetup rc from sendrecv2 is %d",rc)); @@ -515,6 +528,7 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,nls_cp); ssetup_exit: + kfree(str_area); if(resp_buf_type == CIFS_SMALL_BUFFER) { cFYI(1,("ssetup freeing small buf %p", iov[0].iov_base)); cifs_small_buf_release(iov[0].iov_base);