Loading fs/cifs/connect.c +0 −730 Original line number Diff line number Diff line Loading @@ -2605,736 +2605,6 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, return rc; } static int CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, struct cifsSesInfo *ses, bool *pNTLMv2_flag, const struct nls_table *nls_codepage) { struct smb_hdr *smb_buffer; struct smb_hdr *smb_buffer_response; SESSION_SETUP_ANDX *pSMB; SESSION_SETUP_ANDX *pSMBr; char *bcc_ptr; char *domain; int rc = 0; int remaining_words = 0; int bytes_returned = 0; int len; int SecurityBlobLength = sizeof(NEGOTIATE_MESSAGE); PNEGOTIATE_MESSAGE SecurityBlob; PCHALLENGE_MESSAGE SecurityBlob2; __u32 negotiate_flags, capabilities; __u16 count; cFYI(1, ("In NTLMSSP sesssetup (negotiate)")); if (ses == NULL) return -EINVAL; domain = ses->domainName; *pNTLMv2_flag = false; smb_buffer = cifs_buf_get(); if (smb_buffer == NULL) { return -ENOMEM; } smb_buffer_response = smb_buffer; pSMB = (SESSION_SETUP_ANDX *) smb_buffer; pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response; /* send SMBsessionSetup here */ header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, NULL /* no tCon exists yet */ , 12 /* wct */ ); smb_buffer->Mid = GetNextMid(ses->server); pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); pSMB->req.AndXCommand = 0xFF; pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | CAP_EXTENDED_SECURITY; if (ses->capabilities & CAP_UNICODE) { smb_buffer->Flags2 |= SMBFLG2_UNICODE; capabilities |= CAP_UNICODE; } if (ses->capabilities & CAP_STATUS32) { smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; capabilities |= CAP_STATUS32; } if (ses->capabilities & CAP_DFS) { smb_buffer->Flags2 |= SMBFLG2_DFS; capabilities |= CAP_DFS; } pSMB->req.Capabilities = cpu_to_le32(capabilities); bcc_ptr = (char *) &pSMB->req.SecurityBlob; SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr; strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8); SecurityBlob->MessageType = NtLmNegotiate; negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_56 | /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128; if (sign_CIFS_PDUs) negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN; /* setup pointers to domain name and workstation name */ bcc_ptr += SecurityBlobLength; SecurityBlob->WorkstationName.BufferOffset = 0; SecurityBlob->WorkstationName.Length = 0; SecurityBlob->WorkstationName.MaximumLength = 0; /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent along with username on auth request (ie the response to challenge) */ SecurityBlob->DomainName.BufferOffset = 0; SecurityBlob->DomainName.Length = 0; SecurityBlob->DomainName.MaximumLength = 0; if (ses->capabilities & CAP_UNICODE) { if ((long) bcc_ptr % 2) { *bcc_ptr = 0; bcc_ptr++; } bytes_returned = cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bytes_returned = cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; /* null terminate Linux version */ bytes_returned = cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, 64, nls_codepage); bcc_ptr += 2 * bytes_returned; *(bcc_ptr + 1) = 0; *(bcc_ptr + 2) = 0; bcc_ptr += 2; /* null terminate network opsys string */ *(bcc_ptr + 1) = 0; *(bcc_ptr + 2) = 0; bcc_ptr += 2; /* null domain */ } else { /* ASCII */ strcpy(bcc_ptr, "Linux version "); bcc_ptr += strlen("Linux version "); strcpy(bcc_ptr, utsname()->release); bcc_ptr += strlen(utsname()->release) + 1; strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; bcc_ptr++; /* empty domain field */ *bcc_ptr = 0; } SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags); pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength); count = (long) bcc_ptr - (long) pByteArea(smb_buffer); smb_buffer->smb_buf_length += count; pSMB->req.ByteCount = cpu_to_le16(count); rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &bytes_returned, CIFS_LONG_OP); if (smb_buffer_response->Status.CifsError == cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED)) rc = 0; if (rc) { /* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */ } else if ((smb_buffer_response->WordCount == 3) || (smb_buffer_response->WordCount == 4)) { __u16 action = le16_to_cpu(pSMBr->resp.Action); __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); if (action & GUEST_LOGIN) cFYI(1, ("Guest login")); /* Do we want to set anything in SesInfo struct when guest login? */ bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */ SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr; if (SecurityBlob2->MessageType != NtLmChallenge) { cFYI(1, ("Unexpected NTLMSSP message type received %d", SecurityBlob2->MessageType)); } else if (ses) { ses->Suid = smb_buffer_response->Uid; /* UID left in le format */ cFYI(1, ("UID = %d", ses->Suid)); if ((pSMBr->resp.hdr.WordCount == 3) || ((pSMBr->resp.hdr.WordCount == 4) && (blob_len < pSMBr->resp.ByteCount))) { if (pSMBr->resp.hdr.WordCount == 4) { bcc_ptr += blob_len; cFYI(1, ("Security Blob Length %d", blob_len)); } cFYI(1, ("NTLMSSP Challenge rcvd")); memcpy(ses->server->cryptKey, SecurityBlob2->Challenge, CIFS_CRYPTO_KEY_SIZE); /* NTLMV2 flag is not for NTLMv2 password hash */ /* if (SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2)) *pNTLMv2_flag = true; */ /* BB wrong */ if ((SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN)) || (sign_CIFS_PDUs > 1)) ses->server->secMode |= SECMODE_SIGN_REQUIRED; if ((SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs)) ses->server->secMode |= SECMODE_SIGN_ENABLED; if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { if ((long) (bcc_ptr) % 2) { remaining_words = (BCC(smb_buffer_response) - 1) / 2; /* Must word align unicode strings */ bcc_ptr++; } else { remaining_words = BCC (smb_buffer_response) / 2; } len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words - 1); /* 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 */ kfree(ses->serverOS); ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, (__le16 *) bcc_ptr, len, nls_codepage); bcc_ptr += 2 * (len + 1); remaining_words -= len + 1; ses->serverOS[2 * len] = 0; ses->serverOS[1 + (2 * len)] = 0; if (remaining_words > 0) { len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words - 1); kfree(ses->serverNOS); ses->serverNOS = kzalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses-> serverNOS, (__le16 *) bcc_ptr, len, nls_codepage); bcc_ptr += 2 * (len + 1); ses->serverNOS[2 * len] = 0; ses->serverNOS[1 + (2 * len)] = 0; remaining_words -= len + 1; if (remaining_words > 0) { len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); /* last string not always null terminated (for e.g. for Windows XP & 2000) */ kfree(ses->serverDomain); ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le (ses->serverDomain, (__le16 *)bcc_ptr, len, nls_codepage); bcc_ptr += 2 * (len + 1); ses->serverDomain[2*len] = 0; ses->serverDomain [1 + (2 * len)] = 0; } /* else no more room so create dummy domain string */ else { kfree(ses->serverDomain); ses->serverDomain = kzalloc(2, GFP_KERNEL); } } else { /* no room so create dummy domain and NOS string */ kfree(ses->serverDomain); ses->serverDomain = kzalloc(2, GFP_KERNEL); kfree(ses->serverNOS); ses->serverNOS = kzalloc(2, GFP_KERNEL); } } else { /* ASCII */ len = strnlen(bcc_ptr, 1024); if (((long) bcc_ptr + len) - (long) pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { kfree(ses->serverOS); ses->serverOS = kzalloc(len + 1, GFP_KERNEL); strncpy(ses->serverOS, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; /* null terminate string */ bcc_ptr++; len = strnlen(bcc_ptr, 1024); kfree(ses->serverNOS); ses->serverNOS = kzalloc(len + 1, GFP_KERNEL); strncpy(ses->serverNOS, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; bcc_ptr++; len = strnlen(bcc_ptr, 1024); kfree(ses->serverDomain); ses->serverDomain = kzalloc(len + 1, GFP_KERNEL); strncpy(ses->serverDomain, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; bcc_ptr++; } else cFYI(1, ("field of length %d " "extends beyond end of smb", len)); } } else { cERROR(1, ("Security Blob Length extends beyond" " end of SMB")); } } else { cERROR(1, ("No session structure passed in.")); } } else { cERROR(1, ("Invalid Word count %d:", smb_buffer_response->WordCount)); rc = -EIO; } cifs_buf_release(smb_buffer); return rc; } static int CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, char *ntlm_session_key, bool ntlmv2_flag, const struct nls_table *nls_codepage) { struct smb_hdr *smb_buffer; struct smb_hdr *smb_buffer_response; SESSION_SETUP_ANDX *pSMB; SESSION_SETUP_ANDX *pSMBr; char *bcc_ptr; char *user; char *domain; int rc = 0; int remaining_words = 0; int bytes_returned = 0; int len; int SecurityBlobLength = sizeof(AUTHENTICATE_MESSAGE); PAUTHENTICATE_MESSAGE SecurityBlob; __u32 negotiate_flags, capabilities; __u16 count; cFYI(1, ("In NTLMSSPSessSetup (Authenticate)")); if (ses == NULL) return -EINVAL; user = ses->userName; domain = ses->domainName; smb_buffer = cifs_buf_get(); if (smb_buffer == NULL) { return -ENOMEM; } smb_buffer_response = smb_buffer; pSMB = (SESSION_SETUP_ANDX *)smb_buffer; pSMBr = (SESSION_SETUP_ANDX *)smb_buffer_response; /* send SMBsessionSetup here */ header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, NULL /* no tCon exists yet */ , 12 /* wct */ ); smb_buffer->Mid = GetNextMid(ses->server); pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; pSMB->req.AndXCommand = 0xFF; pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); pSMB->req.hdr.Uid = ses->Suid; if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | CAP_EXTENDED_SECURITY; if (ses->capabilities & CAP_UNICODE) { smb_buffer->Flags2 |= SMBFLG2_UNICODE; capabilities |= CAP_UNICODE; } if (ses->capabilities & CAP_STATUS32) { smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; capabilities |= CAP_STATUS32; } if (ses->capabilities & CAP_DFS) { smb_buffer->Flags2 |= SMBFLG2_DFS; capabilities |= CAP_DFS; } pSMB->req.Capabilities = cpu_to_le32(capabilities); bcc_ptr = (char *)&pSMB->req.SecurityBlob; SecurityBlob = (PAUTHENTICATE_MESSAGE)bcc_ptr; strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8); SecurityBlob->MessageType = NtLmAuthenticate; bcc_ptr += SecurityBlobLength; negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO | NTLMSSP_NEGOTIATE_56 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_EXTENDED_SEC; if (sign_CIFS_PDUs) negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN; /* setup pointers to domain name and workstation name */ SecurityBlob->WorkstationName.BufferOffset = 0; SecurityBlob->WorkstationName.Length = 0; SecurityBlob->WorkstationName.MaximumLength = 0; SecurityBlob->SessionKey.Length = 0; SecurityBlob->SessionKey.MaximumLength = 0; SecurityBlob->SessionKey.BufferOffset = 0; SecurityBlob->LmChallengeResponse.Length = 0; SecurityBlob->LmChallengeResponse.MaximumLength = 0; SecurityBlob->LmChallengeResponse.BufferOffset = 0; SecurityBlob->NtChallengeResponse.Length = cpu_to_le16(CIFS_SESS_KEY_SIZE); SecurityBlob->NtChallengeResponse.MaximumLength = cpu_to_le16(CIFS_SESS_KEY_SIZE); memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE); SecurityBlob->NtChallengeResponse.BufferOffset = cpu_to_le32(SecurityBlobLength); SecurityBlobLength += CIFS_SESS_KEY_SIZE; bcc_ptr += CIFS_SESS_KEY_SIZE; if (ses->capabilities & CAP_UNICODE) { if (domain == NULL) { SecurityBlob->DomainName.BufferOffset = 0; SecurityBlob->DomainName.Length = 0; SecurityBlob->DomainName.MaximumLength = 0; } else { __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64, nls_codepage); ln *= 2; SecurityBlob->DomainName.MaximumLength = cpu_to_le16(ln); SecurityBlob->DomainName.BufferOffset = cpu_to_le32(SecurityBlobLength); bcc_ptr += ln; SecurityBlobLength += ln; SecurityBlob->DomainName.Length = cpu_to_le16(ln); } if (user == NULL) { SecurityBlob->UserName.BufferOffset = 0; SecurityBlob->UserName.Length = 0; SecurityBlob->UserName.MaximumLength = 0; } else { __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64, nls_codepage); ln *= 2; SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln); SecurityBlob->UserName.BufferOffset = cpu_to_le32(SecurityBlobLength); bcc_ptr += ln; SecurityBlobLength += ln; SecurityBlob->UserName.Length = cpu_to_le16(ln); } /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage); SecurityBlob->WorkstationName.Length *= 2; SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length); SecurityBlob->WorkstationName.BufferOffset = cpu_to_le32(SecurityBlobLength); bcc_ptr += SecurityBlob->WorkstationName.Length; SecurityBlobLength += SecurityBlob->WorkstationName.Length; SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */ if ((long) bcc_ptr % 2) { *bcc_ptr = 0; bcc_ptr++; } bytes_returned = cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bytes_returned = cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; /* null term version string */ bytes_returned = cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, 64, nls_codepage); bcc_ptr += 2 * bytes_returned; *(bcc_ptr + 1) = 0; *(bcc_ptr + 2) = 0; bcc_ptr += 2; /* null terminate network opsys string */ *(bcc_ptr + 1) = 0; *(bcc_ptr + 2) = 0; bcc_ptr += 2; /* null domain */ } else { /* ASCII */ if (domain == NULL) { SecurityBlob->DomainName.BufferOffset = 0; SecurityBlob->DomainName.Length = 0; SecurityBlob->DomainName.MaximumLength = 0; } else { __u16 ln; negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED; strncpy(bcc_ptr, domain, 63); ln = strnlen(domain, 64); SecurityBlob->DomainName.MaximumLength = cpu_to_le16(ln); SecurityBlob->DomainName.BufferOffset = cpu_to_le32(SecurityBlobLength); bcc_ptr += ln; SecurityBlobLength += ln; SecurityBlob->DomainName.Length = cpu_to_le16(ln); } if (user == NULL) { SecurityBlob->UserName.BufferOffset = 0; SecurityBlob->UserName.Length = 0; SecurityBlob->UserName.MaximumLength = 0; } else { __u16 ln; strncpy(bcc_ptr, user, 63); ln = strnlen(user, 64); SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln); SecurityBlob->UserName.BufferOffset = cpu_to_le32(SecurityBlobLength); bcc_ptr += ln; SecurityBlobLength += ln; SecurityBlob->UserName.Length = cpu_to_le16(ln); } /* BB fill in our workstation name if known BB */ strcpy(bcc_ptr, "Linux version "); bcc_ptr += strlen("Linux version "); strcpy(bcc_ptr, utsname()->release); bcc_ptr += strlen(utsname()->release) + 1; strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; bcc_ptr++; /* null domain */ *bcc_ptr = 0; } SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags); pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength); count = (long) bcc_ptr - (long) pByteArea(smb_buffer); smb_buffer->smb_buf_length += count; pSMB->req.ByteCount = cpu_to_le16(count); rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &bytes_returned, CIFS_LONG_OP); if (rc) { /* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */ } else if ((smb_buffer_response->WordCount == 3) || (smb_buffer_response->WordCount == 4)) { __u16 action = le16_to_cpu(pSMBr->resp.Action); __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); if (action & GUEST_LOGIN) cFYI(1, ("Guest login")); /* BB Should we set anything in SesInfo struct ? */ /* if (SecurityBlob2->MessageType != NtLm??) { cFYI("Unexpected message type on auth response is %d")); } */ if (ses) { cFYI(1, ("Check challenge UID %d vs auth response UID %d", ses->Suid, smb_buffer_response->Uid)); /* UID left in wire format */ ses->Suid = smb_buffer_response->Uid; bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */ if ((pSMBr->resp.hdr.WordCount == 3) || ((pSMBr->resp.hdr.WordCount == 4) && (blob_len < pSMBr->resp.ByteCount))) { if (pSMBr->resp.hdr.WordCount == 4) { bcc_ptr += blob_len; cFYI(1, ("Security Blob Length %d ", blob_len)); } cFYI(1, ("NTLMSSP response to Authenticate ")); if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { if ((long) (bcc_ptr) % 2) { remaining_words = (BCC(smb_buffer_response) - 1) / 2; bcc_ptr++; /* Unicode strings must be word aligned */ } else { remaining_words = BCC(smb_buffer_response) / 2; } len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words - 1); /* 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 */ kfree(ses->serverOS); ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, (__le16 *) bcc_ptr, len, nls_codepage); bcc_ptr += 2 * (len + 1); remaining_words -= len + 1; ses->serverOS[2 * len] = 0; ses->serverOS[1 + (2 * len)] = 0; if (remaining_words > 0) { len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words - 1); kfree(ses->serverNOS); ses->serverNOS = kzalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses-> serverNOS, (__le16 *) bcc_ptr, len, nls_codepage); bcc_ptr += 2 * (len + 1); ses->serverNOS[2 * len] = 0; ses->serverNOS[1+(2*len)] = 0; remaining_words -= len + 1; if (remaining_words > 0) { len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); /* last string not always null terminated (e.g. for Windows XP & 2000) */ kfree(ses->serverDomain); ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le (ses-> serverDomain, (__le16 *) bcc_ptr, len, nls_codepage); bcc_ptr += 2 * (len + 1); ses-> serverDomain[2 * len] = 0; ses-> serverDomain[1 + (2 * len)] = 0; } /* else no more room so create dummy domain string */ else { kfree(ses->serverDomain); ses->serverDomain = kzalloc(2,GFP_KERNEL); } } else { /* no room so create dummy domain and NOS string */ kfree(ses->serverDomain); ses->serverDomain = kzalloc(2, GFP_KERNEL); kfree(ses->serverNOS); ses->serverNOS = kzalloc(2, GFP_KERNEL); } } else { /* ASCII */ len = strnlen(bcc_ptr, 1024); if (((long) bcc_ptr + len) - (long) pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { kfree(ses->serverOS); ses->serverOS = kzalloc(len + 1, GFP_KERNEL); strncpy(ses->serverOS,bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; /* null terminate the string */ bcc_ptr++; len = strnlen(bcc_ptr, 1024); kfree(ses->serverNOS); ses->serverNOS = kzalloc(len+1, GFP_KERNEL); strncpy(ses->serverNOS, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; bcc_ptr++; len = strnlen(bcc_ptr, 1024); kfree(ses->serverDomain); ses->serverDomain = kzalloc(len+1, GFP_KERNEL); strncpy(ses->serverDomain, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; bcc_ptr++; } else cFYI(1, ("field of length %d " "extends beyond end of smb ", len)); } } else { cERROR(1, ("Security Blob extends beyond end " "of SMB")); } } else { cERROR(1, ("No session structure passed in.")); } } else { cERROR(1, ("Invalid Word count %d: ", smb_buffer_response->WordCount)); rc = -EIO; } cifs_buf_release(smb_buffer); return rc; } int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, const char *tree, struct cifsTconInfo *tcon, Loading Loading
fs/cifs/connect.c +0 −730 Original line number Diff line number Diff line Loading @@ -2605,736 +2605,6 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, return rc; } static int CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, struct cifsSesInfo *ses, bool *pNTLMv2_flag, const struct nls_table *nls_codepage) { struct smb_hdr *smb_buffer; struct smb_hdr *smb_buffer_response; SESSION_SETUP_ANDX *pSMB; SESSION_SETUP_ANDX *pSMBr; char *bcc_ptr; char *domain; int rc = 0; int remaining_words = 0; int bytes_returned = 0; int len; int SecurityBlobLength = sizeof(NEGOTIATE_MESSAGE); PNEGOTIATE_MESSAGE SecurityBlob; PCHALLENGE_MESSAGE SecurityBlob2; __u32 negotiate_flags, capabilities; __u16 count; cFYI(1, ("In NTLMSSP sesssetup (negotiate)")); if (ses == NULL) return -EINVAL; domain = ses->domainName; *pNTLMv2_flag = false; smb_buffer = cifs_buf_get(); if (smb_buffer == NULL) { return -ENOMEM; } smb_buffer_response = smb_buffer; pSMB = (SESSION_SETUP_ANDX *) smb_buffer; pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response; /* send SMBsessionSetup here */ header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, NULL /* no tCon exists yet */ , 12 /* wct */ ); smb_buffer->Mid = GetNextMid(ses->server); pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); pSMB->req.AndXCommand = 0xFF; pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | CAP_EXTENDED_SECURITY; if (ses->capabilities & CAP_UNICODE) { smb_buffer->Flags2 |= SMBFLG2_UNICODE; capabilities |= CAP_UNICODE; } if (ses->capabilities & CAP_STATUS32) { smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; capabilities |= CAP_STATUS32; } if (ses->capabilities & CAP_DFS) { smb_buffer->Flags2 |= SMBFLG2_DFS; capabilities |= CAP_DFS; } pSMB->req.Capabilities = cpu_to_le32(capabilities); bcc_ptr = (char *) &pSMB->req.SecurityBlob; SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr; strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8); SecurityBlob->MessageType = NtLmNegotiate; negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_56 | /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128; if (sign_CIFS_PDUs) negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN; /* setup pointers to domain name and workstation name */ bcc_ptr += SecurityBlobLength; SecurityBlob->WorkstationName.BufferOffset = 0; SecurityBlob->WorkstationName.Length = 0; SecurityBlob->WorkstationName.MaximumLength = 0; /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent along with username on auth request (ie the response to challenge) */ SecurityBlob->DomainName.BufferOffset = 0; SecurityBlob->DomainName.Length = 0; SecurityBlob->DomainName.MaximumLength = 0; if (ses->capabilities & CAP_UNICODE) { if ((long) bcc_ptr % 2) { *bcc_ptr = 0; bcc_ptr++; } bytes_returned = cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bytes_returned = cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; /* null terminate Linux version */ bytes_returned = cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, 64, nls_codepage); bcc_ptr += 2 * bytes_returned; *(bcc_ptr + 1) = 0; *(bcc_ptr + 2) = 0; bcc_ptr += 2; /* null terminate network opsys string */ *(bcc_ptr + 1) = 0; *(bcc_ptr + 2) = 0; bcc_ptr += 2; /* null domain */ } else { /* ASCII */ strcpy(bcc_ptr, "Linux version "); bcc_ptr += strlen("Linux version "); strcpy(bcc_ptr, utsname()->release); bcc_ptr += strlen(utsname()->release) + 1; strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; bcc_ptr++; /* empty domain field */ *bcc_ptr = 0; } SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags); pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength); count = (long) bcc_ptr - (long) pByteArea(smb_buffer); smb_buffer->smb_buf_length += count; pSMB->req.ByteCount = cpu_to_le16(count); rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &bytes_returned, CIFS_LONG_OP); if (smb_buffer_response->Status.CifsError == cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED)) rc = 0; if (rc) { /* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */ } else if ((smb_buffer_response->WordCount == 3) || (smb_buffer_response->WordCount == 4)) { __u16 action = le16_to_cpu(pSMBr->resp.Action); __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); if (action & GUEST_LOGIN) cFYI(1, ("Guest login")); /* Do we want to set anything in SesInfo struct when guest login? */ bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */ SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr; if (SecurityBlob2->MessageType != NtLmChallenge) { cFYI(1, ("Unexpected NTLMSSP message type received %d", SecurityBlob2->MessageType)); } else if (ses) { ses->Suid = smb_buffer_response->Uid; /* UID left in le format */ cFYI(1, ("UID = %d", ses->Suid)); if ((pSMBr->resp.hdr.WordCount == 3) || ((pSMBr->resp.hdr.WordCount == 4) && (blob_len < pSMBr->resp.ByteCount))) { if (pSMBr->resp.hdr.WordCount == 4) { bcc_ptr += blob_len; cFYI(1, ("Security Blob Length %d", blob_len)); } cFYI(1, ("NTLMSSP Challenge rcvd")); memcpy(ses->server->cryptKey, SecurityBlob2->Challenge, CIFS_CRYPTO_KEY_SIZE); /* NTLMV2 flag is not for NTLMv2 password hash */ /* if (SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2)) *pNTLMv2_flag = true; */ /* BB wrong */ if ((SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN)) || (sign_CIFS_PDUs > 1)) ses->server->secMode |= SECMODE_SIGN_REQUIRED; if ((SecurityBlob2->NegotiateFlags & cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs)) ses->server->secMode |= SECMODE_SIGN_ENABLED; if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { if ((long) (bcc_ptr) % 2) { remaining_words = (BCC(smb_buffer_response) - 1) / 2; /* Must word align unicode strings */ bcc_ptr++; } else { remaining_words = BCC (smb_buffer_response) / 2; } len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words - 1); /* 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 */ kfree(ses->serverOS); ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, (__le16 *) bcc_ptr, len, nls_codepage); bcc_ptr += 2 * (len + 1); remaining_words -= len + 1; ses->serverOS[2 * len] = 0; ses->serverOS[1 + (2 * len)] = 0; if (remaining_words > 0) { len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words - 1); kfree(ses->serverNOS); ses->serverNOS = kzalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses-> serverNOS, (__le16 *) bcc_ptr, len, nls_codepage); bcc_ptr += 2 * (len + 1); ses->serverNOS[2 * len] = 0; ses->serverNOS[1 + (2 * len)] = 0; remaining_words -= len + 1; if (remaining_words > 0) { len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); /* last string not always null terminated (for e.g. for Windows XP & 2000) */ kfree(ses->serverDomain); ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le (ses->serverDomain, (__le16 *)bcc_ptr, len, nls_codepage); bcc_ptr += 2 * (len + 1); ses->serverDomain[2*len] = 0; ses->serverDomain [1 + (2 * len)] = 0; } /* else no more room so create dummy domain string */ else { kfree(ses->serverDomain); ses->serverDomain = kzalloc(2, GFP_KERNEL); } } else { /* no room so create dummy domain and NOS string */ kfree(ses->serverDomain); ses->serverDomain = kzalloc(2, GFP_KERNEL); kfree(ses->serverNOS); ses->serverNOS = kzalloc(2, GFP_KERNEL); } } else { /* ASCII */ len = strnlen(bcc_ptr, 1024); if (((long) bcc_ptr + len) - (long) pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { kfree(ses->serverOS); ses->serverOS = kzalloc(len + 1, GFP_KERNEL); strncpy(ses->serverOS, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; /* null terminate string */ bcc_ptr++; len = strnlen(bcc_ptr, 1024); kfree(ses->serverNOS); ses->serverNOS = kzalloc(len + 1, GFP_KERNEL); strncpy(ses->serverNOS, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; bcc_ptr++; len = strnlen(bcc_ptr, 1024); kfree(ses->serverDomain); ses->serverDomain = kzalloc(len + 1, GFP_KERNEL); strncpy(ses->serverDomain, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; bcc_ptr++; } else cFYI(1, ("field of length %d " "extends beyond end of smb", len)); } } else { cERROR(1, ("Security Blob Length extends beyond" " end of SMB")); } } else { cERROR(1, ("No session structure passed in.")); } } else { cERROR(1, ("Invalid Word count %d:", smb_buffer_response->WordCount)); rc = -EIO; } cifs_buf_release(smb_buffer); return rc; } static int CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, char *ntlm_session_key, bool ntlmv2_flag, const struct nls_table *nls_codepage) { struct smb_hdr *smb_buffer; struct smb_hdr *smb_buffer_response; SESSION_SETUP_ANDX *pSMB; SESSION_SETUP_ANDX *pSMBr; char *bcc_ptr; char *user; char *domain; int rc = 0; int remaining_words = 0; int bytes_returned = 0; int len; int SecurityBlobLength = sizeof(AUTHENTICATE_MESSAGE); PAUTHENTICATE_MESSAGE SecurityBlob; __u32 negotiate_flags, capabilities; __u16 count; cFYI(1, ("In NTLMSSPSessSetup (Authenticate)")); if (ses == NULL) return -EINVAL; user = ses->userName; domain = ses->domainName; smb_buffer = cifs_buf_get(); if (smb_buffer == NULL) { return -ENOMEM; } smb_buffer_response = smb_buffer; pSMB = (SESSION_SETUP_ANDX *)smb_buffer; pSMBr = (SESSION_SETUP_ANDX *)smb_buffer_response; /* send SMBsessionSetup here */ header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, NULL /* no tCon exists yet */ , 12 /* wct */ ); smb_buffer->Mid = GetNextMid(ses->server); pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; pSMB->req.AndXCommand = 0xFF; pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); pSMB->req.hdr.Uid = ses->Suid; if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | CAP_EXTENDED_SECURITY; if (ses->capabilities & CAP_UNICODE) { smb_buffer->Flags2 |= SMBFLG2_UNICODE; capabilities |= CAP_UNICODE; } if (ses->capabilities & CAP_STATUS32) { smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; capabilities |= CAP_STATUS32; } if (ses->capabilities & CAP_DFS) { smb_buffer->Flags2 |= SMBFLG2_DFS; capabilities |= CAP_DFS; } pSMB->req.Capabilities = cpu_to_le32(capabilities); bcc_ptr = (char *)&pSMB->req.SecurityBlob; SecurityBlob = (PAUTHENTICATE_MESSAGE)bcc_ptr; strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8); SecurityBlob->MessageType = NtLmAuthenticate; bcc_ptr += SecurityBlobLength; negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO | NTLMSSP_NEGOTIATE_56 | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_EXTENDED_SEC; if (sign_CIFS_PDUs) negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN; /* setup pointers to domain name and workstation name */ SecurityBlob->WorkstationName.BufferOffset = 0; SecurityBlob->WorkstationName.Length = 0; SecurityBlob->WorkstationName.MaximumLength = 0; SecurityBlob->SessionKey.Length = 0; SecurityBlob->SessionKey.MaximumLength = 0; SecurityBlob->SessionKey.BufferOffset = 0; SecurityBlob->LmChallengeResponse.Length = 0; SecurityBlob->LmChallengeResponse.MaximumLength = 0; SecurityBlob->LmChallengeResponse.BufferOffset = 0; SecurityBlob->NtChallengeResponse.Length = cpu_to_le16(CIFS_SESS_KEY_SIZE); SecurityBlob->NtChallengeResponse.MaximumLength = cpu_to_le16(CIFS_SESS_KEY_SIZE); memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE); SecurityBlob->NtChallengeResponse.BufferOffset = cpu_to_le32(SecurityBlobLength); SecurityBlobLength += CIFS_SESS_KEY_SIZE; bcc_ptr += CIFS_SESS_KEY_SIZE; if (ses->capabilities & CAP_UNICODE) { if (domain == NULL) { SecurityBlob->DomainName.BufferOffset = 0; SecurityBlob->DomainName.Length = 0; SecurityBlob->DomainName.MaximumLength = 0; } else { __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64, nls_codepage); ln *= 2; SecurityBlob->DomainName.MaximumLength = cpu_to_le16(ln); SecurityBlob->DomainName.BufferOffset = cpu_to_le32(SecurityBlobLength); bcc_ptr += ln; SecurityBlobLength += ln; SecurityBlob->DomainName.Length = cpu_to_le16(ln); } if (user == NULL) { SecurityBlob->UserName.BufferOffset = 0; SecurityBlob->UserName.Length = 0; SecurityBlob->UserName.MaximumLength = 0; } else { __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64, nls_codepage); ln *= 2; SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln); SecurityBlob->UserName.BufferOffset = cpu_to_le32(SecurityBlobLength); bcc_ptr += ln; SecurityBlobLength += ln; SecurityBlob->UserName.Length = cpu_to_le16(ln); } /* SecurityBlob->WorkstationName.Length = cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage); SecurityBlob->WorkstationName.Length *= 2; SecurityBlob->WorkstationName.MaximumLength = cpu_to_le16(SecurityBlob->WorkstationName.Length); SecurityBlob->WorkstationName.BufferOffset = cpu_to_le32(SecurityBlobLength); bcc_ptr += SecurityBlob->WorkstationName.Length; SecurityBlobLength += SecurityBlob->WorkstationName.Length; SecurityBlob->WorkstationName.Length = cpu_to_le16(SecurityBlob->WorkstationName.Length); */ if ((long) bcc_ptr % 2) { *bcc_ptr = 0; bcc_ptr++; } bytes_returned = cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bytes_returned = cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32, nls_codepage); bcc_ptr += 2 * bytes_returned; bcc_ptr += 2; /* null term version string */ bytes_returned = cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, 64, nls_codepage); bcc_ptr += 2 * bytes_returned; *(bcc_ptr + 1) = 0; *(bcc_ptr + 2) = 0; bcc_ptr += 2; /* null terminate network opsys string */ *(bcc_ptr + 1) = 0; *(bcc_ptr + 2) = 0; bcc_ptr += 2; /* null domain */ } else { /* ASCII */ if (domain == NULL) { SecurityBlob->DomainName.BufferOffset = 0; SecurityBlob->DomainName.Length = 0; SecurityBlob->DomainName.MaximumLength = 0; } else { __u16 ln; negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED; strncpy(bcc_ptr, domain, 63); ln = strnlen(domain, 64); SecurityBlob->DomainName.MaximumLength = cpu_to_le16(ln); SecurityBlob->DomainName.BufferOffset = cpu_to_le32(SecurityBlobLength); bcc_ptr += ln; SecurityBlobLength += ln; SecurityBlob->DomainName.Length = cpu_to_le16(ln); } if (user == NULL) { SecurityBlob->UserName.BufferOffset = 0; SecurityBlob->UserName.Length = 0; SecurityBlob->UserName.MaximumLength = 0; } else { __u16 ln; strncpy(bcc_ptr, user, 63); ln = strnlen(user, 64); SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln); SecurityBlob->UserName.BufferOffset = cpu_to_le32(SecurityBlobLength); bcc_ptr += ln; SecurityBlobLength += ln; SecurityBlob->UserName.Length = cpu_to_le16(ln); } /* BB fill in our workstation name if known BB */ strcpy(bcc_ptr, "Linux version "); bcc_ptr += strlen("Linux version "); strcpy(bcc_ptr, utsname()->release); bcc_ptr += strlen(utsname()->release) + 1; strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; bcc_ptr++; /* null domain */ *bcc_ptr = 0; } SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags); pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength); count = (long) bcc_ptr - (long) pByteArea(smb_buffer); smb_buffer->smb_buf_length += count; pSMB->req.ByteCount = cpu_to_le16(count); rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &bytes_returned, CIFS_LONG_OP); if (rc) { /* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */ } else if ((smb_buffer_response->WordCount == 3) || (smb_buffer_response->WordCount == 4)) { __u16 action = le16_to_cpu(pSMBr->resp.Action); __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); if (action & GUEST_LOGIN) cFYI(1, ("Guest login")); /* BB Should we set anything in SesInfo struct ? */ /* if (SecurityBlob2->MessageType != NtLm??) { cFYI("Unexpected message type on auth response is %d")); } */ if (ses) { cFYI(1, ("Check challenge UID %d vs auth response UID %d", ses->Suid, smb_buffer_response->Uid)); /* UID left in wire format */ ses->Suid = smb_buffer_response->Uid; bcc_ptr = pByteArea(smb_buffer_response); /* response can have either 3 or 4 word count - Samba sends 3 */ if ((pSMBr->resp.hdr.WordCount == 3) || ((pSMBr->resp.hdr.WordCount == 4) && (blob_len < pSMBr->resp.ByteCount))) { if (pSMBr->resp.hdr.WordCount == 4) { bcc_ptr += blob_len; cFYI(1, ("Security Blob Length %d ", blob_len)); } cFYI(1, ("NTLMSSP response to Authenticate ")); if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { if ((long) (bcc_ptr) % 2) { remaining_words = (BCC(smb_buffer_response) - 1) / 2; bcc_ptr++; /* Unicode strings must be word aligned */ } else { remaining_words = BCC(smb_buffer_response) / 2; } len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words - 1); /* 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 */ kfree(ses->serverOS); ses->serverOS = kzalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses->serverOS, (__le16 *) bcc_ptr, len, nls_codepage); bcc_ptr += 2 * (len + 1); remaining_words -= len + 1; ses->serverOS[2 * len] = 0; ses->serverOS[1 + (2 * len)] = 0; if (remaining_words > 0) { len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words - 1); kfree(ses->serverNOS); ses->serverNOS = kzalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le(ses-> serverNOS, (__le16 *) bcc_ptr, len, nls_codepage); bcc_ptr += 2 * (len + 1); ses->serverNOS[2 * len] = 0; ses->serverNOS[1+(2*len)] = 0; remaining_words -= len + 1; if (remaining_words > 0) { len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); /* last string not always null terminated (e.g. for Windows XP & 2000) */ kfree(ses->serverDomain); ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); cifs_strfromUCS_le (ses-> serverDomain, (__le16 *) bcc_ptr, len, nls_codepage); bcc_ptr += 2 * (len + 1); ses-> serverDomain[2 * len] = 0; ses-> serverDomain[1 + (2 * len)] = 0; } /* else no more room so create dummy domain string */ else { kfree(ses->serverDomain); ses->serverDomain = kzalloc(2,GFP_KERNEL); } } else { /* no room so create dummy domain and NOS string */ kfree(ses->serverDomain); ses->serverDomain = kzalloc(2, GFP_KERNEL); kfree(ses->serverNOS); ses->serverNOS = kzalloc(2, GFP_KERNEL); } } else { /* ASCII */ len = strnlen(bcc_ptr, 1024); if (((long) bcc_ptr + len) - (long) pByteArea(smb_buffer_response) <= BCC(smb_buffer_response)) { kfree(ses->serverOS); ses->serverOS = kzalloc(len + 1, GFP_KERNEL); strncpy(ses->serverOS,bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; /* null terminate the string */ bcc_ptr++; len = strnlen(bcc_ptr, 1024); kfree(ses->serverNOS); ses->serverNOS = kzalloc(len+1, GFP_KERNEL); strncpy(ses->serverNOS, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; bcc_ptr++; len = strnlen(bcc_ptr, 1024); kfree(ses->serverDomain); ses->serverDomain = kzalloc(len+1, GFP_KERNEL); strncpy(ses->serverDomain, bcc_ptr, len); bcc_ptr += len; bcc_ptr[0] = 0; bcc_ptr++; } else cFYI(1, ("field of length %d " "extends beyond end of smb ", len)); } } else { cERROR(1, ("Security Blob extends beyond end " "of SMB")); } } else { cERROR(1, ("No session structure passed in.")); } } else { cERROR(1, ("Invalid Word count %d: ", smb_buffer_response->WordCount)); rc = -EIO; } cifs_buf_release(smb_buffer); return rc; } int CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, const char *tree, struct cifsTconInfo *tcon, Loading