Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2edd6c5b authored by Steve French's avatar Steve French
Browse files

[CIFS] NTLMSSP support moving into new file, old dead code removed



Remove dead NTLMSSP support from connect.c prior to addition of
the new code to replace it.

Signed-off-by: default avatarSteve French <sfrench@us.ibm.com>
parent 051a2a0d
Loading
Loading
Loading
Loading
+0 −730
Original line number Diff line number Diff line
@@ -2605,736 +2605,6 @@ out:
	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,