diff options
Diffstat (limited to 'fs/cifs/sess.c')
-rw-r--r-- | fs/cifs/sess.c | 249 |
1 files changed, 127 insertions, 122 deletions
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c index 758464630893..2ea027dda215 100644 --- a/fs/cifs/sess.c +++ b/fs/cifs/sess.c @@ -3,7 +3,7 @@ * * SMB/CIFS session setup handling routines * - * Copyright (c) International Business Machines Corp., 2006 + * Copyright (c) International Business Machines Corp., 2006, 2007 * Author(s): Steve French (sfrench@us.ibm.com) * * This library is free software; you can redistribute it and/or modify @@ -31,7 +31,7 @@ #include <linux/utsname.h> extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8, - unsigned char *p24); + unsigned char *p24); static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) { @@ -45,13 +45,14 @@ static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) /* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */ - /* BB verify whether signing required on neg or just on auth frame + /* BB verify whether signing required on neg or just on auth frame (and NTLM case) */ capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | CAP_LARGE_WRITE_X | CAP_LARGE_READ_X; - if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) + if (ses->server->secMode & + (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; if (ses->capabilities & CAP_UNICODE) { @@ -74,10 +75,10 @@ static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB) return capabilities; } -static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, - const struct nls_table * nls_cp) +static void unicode_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses, + const struct nls_table *nls_cp) { - char * bcc_ptr = *pbcc_area; + char *bcc_ptr = *pbcc_area; int bytes_ret = 0; /* BB FIXME add check that strings total less @@ -89,7 +90,7 @@ static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, bcc_ptr++; } */ /* copy user */ - if(ses->userName == NULL) { + if (ses->userName == NULL) { /* null user mount */ *bcc_ptr = 0; *(bcc_ptr+1) = 0; @@ -100,14 +101,14 @@ static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, bcc_ptr += 2 * bytes_ret; bcc_ptr += 2; /* account for null termination */ /* copy domain */ - if(ses->domainName == NULL) { + if (ses->domainName == NULL) { /* Sending null domain better than using a bogus domain name (as we did briefly in 2.6.18) since server will use its default */ *bcc_ptr = 0; *(bcc_ptr+1) = 0; bytes_ret = 0; } else - bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->domainName, + bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->domainName, 256, nls_cp); bcc_ptr += 2 * bytes_ret; bcc_ptr += 2; /* account for null terminator */ @@ -122,37 +123,37 @@ static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, bcc_ptr += 2; /* trailing null */ bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, - 32, nls_cp); + 32, nls_cp); bcc_ptr += 2 * bytes_ret; bcc_ptr += 2; /* trailing null */ *pbcc_area = bcc_ptr; } -static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, - const struct nls_table * nls_cp) +static void ascii_ssetup_strings(char **pbcc_area, struct cifsSesInfo *ses, + const struct nls_table *nls_cp) { - char * bcc_ptr = *pbcc_area; + char *bcc_ptr = *pbcc_area; /* copy user */ /* BB what about null user mounts - check that we do this BB */ - /* copy user */ - if(ses->userName == NULL) { - /* BB what about null user mounts - check that we do this BB */ - } else { /* 300 should be long enough for any conceivable user name */ - strncpy(bcc_ptr, ses->userName, 300); - } + /* copy user */ + if (ses->userName == NULL) { + /* BB what about null user mounts - check that we do this BB */ + } else { /* 300 should be long enough for any conceivable user name */ + strncpy(bcc_ptr, ses->userName, 300); + } /* BB improve check for overflow */ - bcc_ptr += strnlen(ses->userName, 300); + bcc_ptr += strnlen(ses->userName, 300); *bcc_ptr = 0; - bcc_ptr++; /* account for null termination */ + bcc_ptr++; /* account for null termination */ - /* copy domain */ - - if(ses->domainName != NULL) { - strncpy(bcc_ptr, ses->domainName, 256); + /* copy domain */ + + if (ses->domainName != NULL) { + strncpy(bcc_ptr, ses->domainName, 256); bcc_ptr += strnlen(ses->domainName, 256); - } /* else we will send a null domain name + } /* else we will send a null domain name so the server will default to its own domain */ *bcc_ptr = 0; bcc_ptr++; @@ -167,19 +168,20 @@ static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses, strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; - *pbcc_area = bcc_ptr; + *pbcc_area = bcc_ptr; } -static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses, - const struct nls_table * nls_cp) +static int decode_unicode_ssetup(char **pbcc_area, int bleft, + struct cifsSesInfo *ses, + const struct nls_table *nls_cp) { int rc = 0; int words_left, len; - char * data = *pbcc_area; + char *data = *pbcc_area; - cFYI(1,("bleft %d",bleft)); + cFYI(1, ("bleft %d", bleft)); /* SMB header is unaligned, so cifs servers word align start of @@ -189,7 +191,7 @@ static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInf their final Unicode string - in which case we now will not attempt to decode the byte of junk which follows it */ - + words_left = bleft / 2; /* save off server operating system */ @@ -198,14 +200,14 @@ static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInf /* We look for obvious messed up bcc or strings in response so we do not go off the end since (at least) WIN2K and Windows XP have a major bug in not null terminating last Unicode string in response */ - if(len >= words_left) + if (len >= words_left) return rc; - if(ses->serverOS) + if (ses->serverOS) kfree(ses->serverOS); /* UTF-8 string will not grow more than four times as big as UCS-16 */ ses->serverOS = kzalloc(4 * len, GFP_KERNEL); - if(ses->serverOS != NULL) { + if (ses->serverOS != NULL) { cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len, nls_cp); } @@ -215,67 +217,68 @@ static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInf /* save off server network operating system */ len = UniStrnlen((wchar_t *) data, words_left); - if(len >= words_left) + if (len >= words_left) return rc; - if(ses->serverNOS) + if (ses->serverNOS) kfree(ses->serverNOS); ses->serverNOS = kzalloc(4 * len, GFP_KERNEL); /* BB this is wrong length FIXME BB */ - if(ses->serverNOS != NULL) { + if (ses->serverNOS != NULL) { cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len, nls_cp); - if(strncmp(ses->serverNOS, "NT LAN Manager 4",16) == 0) { - cFYI(1,("NT4 server")); + if (strncmp(ses->serverNOS, "NT LAN Manager 4", 16) == 0) { + cFYI(1, ("NT4 server")); ses->flags |= CIFS_SES_NT4; } } data += 2 * (len + 1); words_left -= len + 1; - /* save off server domain */ - len = UniStrnlen((wchar_t *) data, words_left); - - if(len > words_left) - return rc; - - if(ses->serverDomain) - kfree(ses->serverDomain); - ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); /* BB FIXME wrong length */ - if(ses->serverDomain != NULL) { - cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len, - nls_cp); - ses->serverDomain[2*len] = 0; - ses->serverDomain[(2*len) + 1] = 0; - } - data += 2 * (len + 1); - words_left -= len + 1; - - cFYI(1,("words left: %d",words_left)); + /* save off server domain */ + len = UniStrnlen((wchar_t *) data, words_left); + + if (len > words_left) + return rc; + + if (ses->serverDomain) + kfree(ses->serverDomain); + ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); /* BB FIXME wrong length */ + if (ses->serverDomain != NULL) { + cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len, + nls_cp); + ses->serverDomain[2*len] = 0; + ses->serverDomain[(2*len) + 1] = 0; + } + data += 2 * (len + 1); + words_left -= len + 1; + + cFYI(1, ("words left: %d", words_left)); return rc; } -static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses, - const struct nls_table * nls_cp) +static int decode_ascii_ssetup(char **pbcc_area, int bleft, + struct cifsSesInfo *ses, + const struct nls_table *nls_cp) { int rc = 0; int len; - char * bcc_ptr = *pbcc_area; + char *bcc_ptr = *pbcc_area; + + cFYI(1, ("decode sessetup ascii. bleft %d", bleft)); - cFYI(1,("decode sessetup ascii. bleft %d", bleft)); - len = strnlen(bcc_ptr, bleft); - if(len >= bleft) + if (len >= bleft) return rc; - - if(ses->serverOS) + + if (ses->serverOS) kfree(ses->serverOS); ses->serverOS = kzalloc(len + 1, GFP_KERNEL); - if(ses->serverOS) + if (ses->serverOS) strncpy(ses->serverOS, bcc_ptr, len); - if(strncmp(ses->serverOS, "OS/2",4) == 0) { - cFYI(1,("OS/2 server")); + if (strncmp(ses->serverOS, "OS/2", 4) == 0) { + cFYI(1, ("OS/2 server")); ses->flags |= CIFS_SES_OS2; } @@ -283,34 +286,34 @@ static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo bleft -= len + 1; len = strnlen(bcc_ptr, bleft); - if(len >= bleft) + if (len >= bleft) return rc; - if(ses->serverNOS) + if (ses->serverNOS) kfree(ses->serverNOS); ses->serverNOS = kzalloc(len + 1, GFP_KERNEL); - if(ses->serverNOS) + if (ses->serverNOS) strncpy(ses->serverNOS, bcc_ptr, len); bcc_ptr += len + 1; bleft -= len + 1; - len = strnlen(bcc_ptr, bleft); - if(len > bleft) - return rc; + len = strnlen(bcc_ptr, bleft); + if (len > bleft) + return rc; /* 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)); + cFYI(1, ("ascii: bytes left %d", bleft)); return rc; } -int +int CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, const struct nls_table *nls_cp) { @@ -328,13 +331,13 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, __u16 action; int bytes_remaining; - if(ses == NULL) + if (ses == NULL) return -EINVAL; type = ses->server->secType; - cFYI(1,("sess setup type %d",type)); - if(type == LANMAN) { + 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. So we make this explicitly be turned on in kconfig (in the @@ -344,15 +347,15 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, return -EOPNOTSUPP; #endif wct = 10; /* lanman 2 style sessionsetup */ - } else if((type == NTLM) || (type == NTLMv2)) { + } else if ((type == NTLM) || (type == NTLMv2)) { /* For NTLMv2 failures eventually may need to retry NTLM */ wct = 13; /* old style NTLM sessionsetup */ - } else /* same size for negotiate or auth, NTLMSSP or extended security */ + } else /* same size: negotiate or auth, NTLMSSP or extended security */ wct = 12; rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses, (void **)&smb_buf); - if(rc) + if (rc) return rc; pSMB = (SESSION_SETUP_ANDX *)smb_buf; @@ -364,8 +367,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, 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; + 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); @@ -373,18 +376,18 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, ses->flags &= ~CIFS_SES_LANMAN; - if(type == LANMAN) { + if (type == LANMAN) { #ifdef CONFIG_CIFS_WEAK_PW_HASH char lnm_session_key[CIFS_SESS_KEY_SIZE]; /* no capabilities flags in old lanman negotiation */ - pSMB->old_req.PasswordLength = cpu_to_le16(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); - ses->flags |= CIFS_SES_LANMAN; + ses->flags |= CIFS_SES_LANMAN; /* #ifdef CONFIG_CIFS_DEBUG2 cifs_dump_mem("cryptkey: ",ses->server->cryptKey, CIFS_SESS_KEY_SIZE); @@ -397,10 +400,10 @@ 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? */ - cFYI(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 +#endif } else if (type == NTLM) { char ntlm_session_key[CIFS_SESS_KEY_SIZE]; @@ -409,38 +412,38 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, cpu_to_le16(CIFS_SESS_KEY_SIZE); pSMB->req_no_secext.CaseSensitivePasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE); - + /* calculate session key */ SMBNTencrypt(ses->password, ses->server->cryptKey, ntlm_session_key); - if(first_time) /* should this be moved into common code + 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 */ - memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESS_KEY_SIZE); + memcpy(bcc_ptr, (char *)ntlm_session_key, CIFS_SESS_KEY_SIZE); bcc_ptr += CIFS_SESS_KEY_SIZE; - memcpy(bcc_ptr, (char *)ntlm_session_key,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++; - } + bcc_ptr++; + } unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); } else ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); } else if (type == NTLMv2) { - char * v2_sess_key = + char *v2_sess_key = kmalloc(sizeof(struct ntlmv2_resp), GFP_KERNEL); /* BB FIXME change all users of v2_sess_key to struct ntlmv2_resp */ - if(v2_sess_key == NULL) { + if (v2_sess_key == NULL) { cifs_small_buf_release(smb_buf); return -ENOMEM; } @@ -456,8 +459,8 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, /* calculate session key */ setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp); - if(first_time) /* should this be moved into common code - with similar ntlmv2 path? */ + if (first_time) /* should this be moved into common code + with similar ntlmv2 path? */ /* cifs_calculate_ntlmv2_mac_key(ses->server->mac_signing_key, response BB FIXME, v2_sess_key); */ @@ -465,11 +468,12 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, /* memcpy(bcc_ptr, (char *)ntlm_session_key,LM2_SESS_KEY_SIZE); bcc_ptr += LM2_SESS_KEY_SIZE; */ - memcpy(bcc_ptr, (char *)v2_sess_key, sizeof(struct ntlmv2_resp)); + 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(iov[0].iov_len % 2) { + if (ses->capabilities & CAP_UNICODE) { + if (iov[0].iov_len % 2) { *bcc_ptr = 0; } bcc_ptr++; unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); @@ -488,20 +492,20 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, BCC_LE(smb_buf) = cpu_to_le16(count); iov[1].iov_base = str_area; - iov[1].iov_len = count; + 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)); - if(rc) + cFYI(1, ("ssetup rc from sendrecv2 is %d", rc)); + if (rc) goto ssetup_exit; pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base; smb_buf = (struct smb_hdr *)iov[0].iov_base; - if((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) { + if ((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) { rc = -EIO; - cERROR(1,("bad word count %d", smb_buf->WordCount)); + cERROR(1, ("bad word count %d", smb_buf->WordCount)); goto ssetup_exit; } action = le16_to_cpu(pSMB->resp.Action); @@ -514,31 +518,32 @@ CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, bytes_remaining = BCC(smb_buf); bcc_ptr = pByteArea(smb_buf); - if(smb_buf->WordCount == 4) { + if (smb_buf->WordCount == 4) { __u16 blob_len; blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength); bcc_ptr += blob_len; - if(blob_len > bytes_remaining) { - cERROR(1,("bad security blob length %d", blob_len)); + if (blob_len > bytes_remaining) { + cERROR(1, ("bad security blob length %d", blob_len)); rc = -EINVAL; goto ssetup_exit; } bytes_remaining -= blob_len; - } + } /* BB check if Unicode and decode strings */ - if(smb_buf->Flags2 & SMBFLG2_UNICODE) + if (smb_buf->Flags2 & SMBFLG2_UNICODE) rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses, nls_cp); else - rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,nls_cp); - + 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)); + 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); - } else if(resp_buf_type == CIFS_LARGE_BUFFER) + } else if (resp_buf_type == CIFS_LARGE_BUFFER) cifs_buf_release(iov[0].iov_base); return rc; |