mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	cifs: Separate rawntlmssp auth from CIFS_SessSetup()
Separate rawntlmssp authentication from CIFS_SessSetup(). Also cleanup CIFS_SessSetup() since we no longer do any auth within it. Signed-off-by: Sachin Prabhu <sprabhu@redhat.com> Reviewed-by: Shirish Pargaonkar <spargaonkar@suse.com> Signed-off-by: Steve French <smfrench@gmail.com>
This commit is contained in:
		
							parent
							
								
									ee03c646dd
								
							
						
					
					
						commit
						cc87c47d9d
					
				
					 1 changed files with 301 additions and 265 deletions
				
			
		
							
								
								
									
										566
									
								
								fs/cifs/sess.c
									
									
									
									
									
								
							
							
						
						
									
										566
									
								
								fs/cifs/sess.c
									
									
									
									
									
								
							| 
						 | 
				
			
			@ -1113,39 +1113,262 @@ sess_auth_kerberos(struct sess_data *sess_data)
 | 
			
		|||
}
 | 
			
		||||
#endif /* ! CONFIG_CIFS_UPCALL */
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
 | 
			
		||||
	       const struct nls_table *nls_cp)
 | 
			
		||||
/*
 | 
			
		||||
 * The required kvec buffers have to be allocated before calling this
 | 
			
		||||
 * function.
 | 
			
		||||
 */
 | 
			
		||||
static int
 | 
			
		||||
_sess_auth_rawntlmssp_assemble_req(struct sess_data *sess_data)
 | 
			
		||||
{
 | 
			
		||||
	int rc = 0;
 | 
			
		||||
	int wct;
 | 
			
		||||
	struct smb_hdr *smb_buf;
 | 
			
		||||
	char *bcc_ptr;
 | 
			
		||||
	char *str_area;
 | 
			
		||||
	SESSION_SETUP_ANDX *pSMB;
 | 
			
		||||
	struct cifs_ses *ses = sess_data->ses;
 | 
			
		||||
	__u32 capabilities;
 | 
			
		||||
	__u16 count;
 | 
			
		||||
	int resp_buf_type;
 | 
			
		||||
	struct kvec iov[3];
 | 
			
		||||
	enum securityEnum type;
 | 
			
		||||
	__u16 action, bytes_remaining;
 | 
			
		||||
	__le32 phase = NtLmNegotiate; /* NTLMSSP, if needed, is multistage */
 | 
			
		||||
	u16 blob_len;
 | 
			
		||||
	char *ntlmsspblob = NULL;
 | 
			
		||||
	struct sess_data *sess_data;
 | 
			
		||||
	char *bcc_ptr;
 | 
			
		||||
 | 
			
		||||
	if (ses == NULL) {
 | 
			
		||||
		WARN(1, "%s: ses == NULL!", __func__);
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
 | 
			
		||||
	smb_buf = (struct smb_hdr *)pSMB;
 | 
			
		||||
 | 
			
		||||
	capabilities = cifs_ssetup_hdr(ses, pSMB);
 | 
			
		||||
	if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) {
 | 
			
		||||
		cifs_dbg(VFS, "NTLMSSP requires Unicode support\n");
 | 
			
		||||
		return -ENOSYS;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sess_data = kzalloc(sizeof(struct sess_data), GFP_KERNEL);
 | 
			
		||||
	if (!sess_data)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
	sess_data->xid = xid;
 | 
			
		||||
	sess_data->ses = ses;
 | 
			
		||||
	sess_data->buf0_type = CIFS_NO_BUFFER;
 | 
			
		||||
	sess_data->nls_cp = (struct nls_table *) nls_cp;
 | 
			
		||||
	pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
 | 
			
		||||
	capabilities |= CAP_EXTENDED_SECURITY;
 | 
			
		||||
	pSMB->req.Capabilities |= cpu_to_le32(capabilities);
 | 
			
		||||
 | 
			
		||||
	bcc_ptr = sess_data->iov[2].iov_base;
 | 
			
		||||
	/* unicode strings must be word aligned */
 | 
			
		||||
	if ((sess_data->iov[0].iov_len + sess_data->iov[1].iov_len) % 2) {
 | 
			
		||||
		*bcc_ptr = 0;
 | 
			
		||||
		bcc_ptr++;
 | 
			
		||||
	}
 | 
			
		||||
	unicode_oslm_strings(&bcc_ptr, sess_data->nls_cp);
 | 
			
		||||
 | 
			
		||||
	sess_data->iov[2].iov_len = (long) bcc_ptr -
 | 
			
		||||
					(long) sess_data->iov[2].iov_base;
 | 
			
		||||
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data);
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
sess_auth_rawntlmssp_negotiate(struct sess_data *sess_data)
 | 
			
		||||
{
 | 
			
		||||
	int rc;
 | 
			
		||||
	struct smb_hdr *smb_buf;
 | 
			
		||||
	SESSION_SETUP_ANDX *pSMB;
 | 
			
		||||
	struct cifs_ses *ses = sess_data->ses;
 | 
			
		||||
	__u16 bytes_remaining;
 | 
			
		||||
	char *bcc_ptr;
 | 
			
		||||
	u16 blob_len;
 | 
			
		||||
 | 
			
		||||
	cifs_dbg(FYI, "rawntlmssp session setup negotiate phase\n");
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * if memory allocation is successful, caller of this function
 | 
			
		||||
	 * frees it.
 | 
			
		||||
	 */
 | 
			
		||||
	ses->ntlmssp = kmalloc(sizeof(struct ntlmssp_auth), GFP_KERNEL);
 | 
			
		||||
	if (!ses->ntlmssp) {
 | 
			
		||||
		rc = -ENOMEM;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
	ses->ntlmssp->sesskey_per_smbsess = false;
 | 
			
		||||
 | 
			
		||||
	/* wct = 12 */
 | 
			
		||||
	rc = sess_alloc_buffer(sess_data, 12);
 | 
			
		||||
	if (rc)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
 | 
			
		||||
 | 
			
		||||
	/* Build security blob before we assemble the request */
 | 
			
		||||
	build_ntlmssp_negotiate_blob(pSMB->req.SecurityBlob, ses);
 | 
			
		||||
	sess_data->iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE);
 | 
			
		||||
	sess_data->iov[1].iov_base = pSMB->req.SecurityBlob;
 | 
			
		||||
	pSMB->req.SecurityBlobLength = cpu_to_le16(sizeof(NEGOTIATE_MESSAGE));
 | 
			
		||||
 | 
			
		||||
	rc = _sess_auth_rawntlmssp_assemble_req(sess_data);
 | 
			
		||||
	if (rc)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	rc = sess_sendreceive(sess_data);
 | 
			
		||||
 | 
			
		||||
	pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
 | 
			
		||||
	smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base;
 | 
			
		||||
 | 
			
		||||
	/* If true, rc here is expected and not an error */
 | 
			
		||||
	if (sess_data->buf0_type != CIFS_NO_BUFFER &&
 | 
			
		||||
	    smb_buf->Status.CifsError ==
 | 
			
		||||
			cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))
 | 
			
		||||
		rc = 0;
 | 
			
		||||
 | 
			
		||||
	if (rc)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	cifs_dbg(FYI, "rawntlmssp session setup challenge phase\n");
 | 
			
		||||
 | 
			
		||||
	if (smb_buf->WordCount != 4) {
 | 
			
		||||
		rc = -EIO;
 | 
			
		||||
		cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount);
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	ses->Suid = smb_buf->Uid;   /* UID left in wire format (le) */
 | 
			
		||||
	cifs_dbg(FYI, "UID = %llu\n", ses->Suid);
 | 
			
		||||
 | 
			
		||||
	bytes_remaining = get_bcc(smb_buf);
 | 
			
		||||
	bcc_ptr = pByteArea(smb_buf);
 | 
			
		||||
 | 
			
		||||
	blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength);
 | 
			
		||||
	if (blob_len > bytes_remaining) {
 | 
			
		||||
		cifs_dbg(VFS, "bad security blob length %d\n",
 | 
			
		||||
				blob_len);
 | 
			
		||||
		rc = -EINVAL;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rc = decode_ntlmssp_challenge(bcc_ptr, blob_len, ses);
 | 
			
		||||
out:
 | 
			
		||||
	sess_free_buffer(sess_data);
 | 
			
		||||
 | 
			
		||||
	if (!rc) {
 | 
			
		||||
		sess_data->func = sess_auth_rawntlmssp_authenticate;
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* Else error. Cleanup */
 | 
			
		||||
	kfree(ses->auth_key.response);
 | 
			
		||||
	ses->auth_key.response = NULL;
 | 
			
		||||
	kfree(ses->ntlmssp);
 | 
			
		||||
	ses->ntlmssp = NULL;
 | 
			
		||||
 | 
			
		||||
	sess_data->func = NULL;
 | 
			
		||||
	sess_data->result = rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data)
 | 
			
		||||
{
 | 
			
		||||
	int rc;
 | 
			
		||||
	struct smb_hdr *smb_buf;
 | 
			
		||||
	SESSION_SETUP_ANDX *pSMB;
 | 
			
		||||
	struct cifs_ses *ses = sess_data->ses;
 | 
			
		||||
	__u16 bytes_remaining;
 | 
			
		||||
	char *bcc_ptr;
 | 
			
		||||
	char *ntlmsspblob = NULL;
 | 
			
		||||
	u16 blob_len;
 | 
			
		||||
 | 
			
		||||
	cifs_dbg(FYI, "rawntlmssp session setup authenticate phase\n");
 | 
			
		||||
 | 
			
		||||
	/* wct = 12 */
 | 
			
		||||
	rc = sess_alloc_buffer(sess_data, 12);
 | 
			
		||||
	if (rc)
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	/* Build security blob before we assemble the request */
 | 
			
		||||
	pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
 | 
			
		||||
	smb_buf = (struct smb_hdr *)pSMB;
 | 
			
		||||
	/*
 | 
			
		||||
	 * 5 is an empirical value, large enough to hold
 | 
			
		||||
	 * authenticate message plus max 10 of av paris,
 | 
			
		||||
	 * domain, user, workstation names, flags, etc.
 | 
			
		||||
	 */
 | 
			
		||||
	ntlmsspblob = kzalloc(5*sizeof(struct _AUTHENTICATE_MESSAGE),
 | 
			
		||||
				GFP_KERNEL);
 | 
			
		||||
	if (!ntlmsspblob) {
 | 
			
		||||
		rc = -ENOMEM;
 | 
			
		||||
		goto out;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	rc = build_ntlmssp_auth_blob(ntlmsspblob,
 | 
			
		||||
					&blob_len, ses, sess_data->nls_cp);
 | 
			
		||||
	if (rc)
 | 
			
		||||
		goto out_free_ntlmsspblob;
 | 
			
		||||
	sess_data->iov[1].iov_len = blob_len;
 | 
			
		||||
	sess_data->iov[1].iov_base = ntlmsspblob;
 | 
			
		||||
	pSMB->req.SecurityBlobLength = cpu_to_le16(blob_len);
 | 
			
		||||
	/*
 | 
			
		||||
	 * Make sure that we tell the server that we are using
 | 
			
		||||
	 * the uid that it just gave us back on the response
 | 
			
		||||
	 * (challenge)
 | 
			
		||||
	 */
 | 
			
		||||
	smb_buf->Uid = ses->Suid;
 | 
			
		||||
 | 
			
		||||
	rc = _sess_auth_rawntlmssp_assemble_req(sess_data);
 | 
			
		||||
	if (rc)
 | 
			
		||||
		goto out_free_ntlmsspblob;
 | 
			
		||||
 | 
			
		||||
	rc = sess_sendreceive(sess_data);
 | 
			
		||||
	if (rc)
 | 
			
		||||
		goto out_free_ntlmsspblob;
 | 
			
		||||
 | 
			
		||||
	pSMB = (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base;
 | 
			
		||||
	smb_buf = (struct smb_hdr *)sess_data->iov[0].iov_base;
 | 
			
		||||
	if (smb_buf->WordCount != 4) {
 | 
			
		||||
		rc = -EIO;
 | 
			
		||||
		cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount);
 | 
			
		||||
		goto out_free_ntlmsspblob;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (le16_to_cpu(pSMB->resp.Action) & GUEST_LOGIN)
 | 
			
		||||
		cifs_dbg(FYI, "Guest login\n"); /* BB mark SesInfo struct? */
 | 
			
		||||
 | 
			
		||||
	bytes_remaining = get_bcc(smb_buf);
 | 
			
		||||
	bcc_ptr = pByteArea(smb_buf);
 | 
			
		||||
	blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength);
 | 
			
		||||
	if (blob_len > bytes_remaining) {
 | 
			
		||||
		cifs_dbg(VFS, "bad security blob length %d\n",
 | 
			
		||||
				blob_len);
 | 
			
		||||
		rc = -EINVAL;
 | 
			
		||||
		goto out_free_ntlmsspblob;
 | 
			
		||||
	}
 | 
			
		||||
	bcc_ptr += blob_len;
 | 
			
		||||
	bytes_remaining -= blob_len;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* BB check if Unicode and decode strings */
 | 
			
		||||
	if (bytes_remaining == 0) {
 | 
			
		||||
		/* no string area to decode, do nothing */
 | 
			
		||||
	} else if (smb_buf->Flags2 & SMBFLG2_UNICODE) {
 | 
			
		||||
		/* unicode string area must be word-aligned */
 | 
			
		||||
		if (((unsigned long) bcc_ptr - (unsigned long) smb_buf) % 2) {
 | 
			
		||||
			++bcc_ptr;
 | 
			
		||||
			--bytes_remaining;
 | 
			
		||||
		}
 | 
			
		||||
		decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses,
 | 
			
		||||
				      sess_data->nls_cp);
 | 
			
		||||
	} else {
 | 
			
		||||
		decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,
 | 
			
		||||
				    sess_data->nls_cp);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
out_free_ntlmsspblob:
 | 
			
		||||
	kfree(ntlmsspblob);
 | 
			
		||||
out:
 | 
			
		||||
	sess_free_buffer(sess_data);
 | 
			
		||||
 | 
			
		||||
	 if (!rc)
 | 
			
		||||
		rc = sess_establish_session(sess_data);
 | 
			
		||||
 | 
			
		||||
	/* Cleanup */
 | 
			
		||||
	kfree(ses->auth_key.response);
 | 
			
		||||
	ses->auth_key.response = NULL;
 | 
			
		||||
	kfree(ses->ntlmssp);
 | 
			
		||||
	ses->ntlmssp = NULL;
 | 
			
		||||
 | 
			
		||||
	sess_data->func = NULL;
 | 
			
		||||
	sess_data->result = rc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int select_sec(struct cifs_ses *ses, struct sess_data *sess_data)
 | 
			
		||||
{
 | 
			
		||||
	int type;
 | 
			
		||||
 | 
			
		||||
	type = select_sectype(ses->server, ses->sectype);
 | 
			
		||||
	cifs_dbg(FYI, "sess setup type %d\n", type);
 | 
			
		||||
| 
						 | 
				
			
			@ -1157,261 +1380,74 @@ CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
 | 
			
		|||
 | 
			
		||||
	switch (type) {
 | 
			
		||||
	case LANMAN:
 | 
			
		||||
		sess_auth_lanman(sess_data);
 | 
			
		||||
		goto out;
 | 
			
		||||
		/* LANMAN and plaintext are less secure and off by default.
 | 
			
		||||
		 * So we make this explicitly be turned on in kconfig (in the
 | 
			
		||||
		 * build) and turned on at runtime (changed from the default)
 | 
			
		||||
		 * in proc/fs/cifs or via mount parm.  Unfortunately this is
 | 
			
		||||
		 * needed for old Win (e.g. Win95), some obscure NAS and OS/2 */
 | 
			
		||||
#ifdef CONFIG_CIFS_WEAK_PW_HASH
 | 
			
		||||
		sess_data->func = sess_auth_lanman;
 | 
			
		||||
		break;
 | 
			
		||||
#else
 | 
			
		||||
		return -EOPNOTSUPP;
 | 
			
		||||
#endif
 | 
			
		||||
	case NTLM:
 | 
			
		||||
		sess_auth_ntlm(sess_data);
 | 
			
		||||
		goto out;
 | 
			
		||||
		sess_data->func = sess_auth_ntlm;
 | 
			
		||||
		break;
 | 
			
		||||
	case NTLMv2:
 | 
			
		||||
		sess_auth_ntlmv2(sess_data);
 | 
			
		||||
		goto out;
 | 
			
		||||
		sess_data->func = sess_auth_ntlmv2;
 | 
			
		||||
		break;
 | 
			
		||||
	case Kerberos:
 | 
			
		||||
		sess_auth_kerberos(sess_data);
 | 
			
		||||
		goto out;
 | 
			
		||||
#ifdef CONFIG_CIFS_UPCALL
 | 
			
		||||
		sess_data->func = sess_auth_kerberos;
 | 
			
		||||
		break;
 | 
			
		||||
#else
 | 
			
		||||
		cifs_dbg(VFS, "Kerberos negotiated but upcall support disabled!\n");
 | 
			
		||||
		return -ENOSYS;
 | 
			
		||||
		break;
 | 
			
		||||
#endif /* CONFIG_CIFS_UPCALL */
 | 
			
		||||
	case RawNTLMSSP:
 | 
			
		||||
		sess_data->func = sess_auth_rawntlmssp_negotiate;
 | 
			
		||||
		break;
 | 
			
		||||
	default:
 | 
			
		||||
		cifs_dbg(FYI, "Continuing with CIFS_SessSetup\n");
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (type == RawNTLMSSP) {
 | 
			
		||||
		/* if memory allocation is successful, caller of this function
 | 
			
		||||
		 * frees it.
 | 
			
		||||
		 */
 | 
			
		||||
		ses->ntlmssp = kmalloc(sizeof(struct ntlmssp_auth), GFP_KERNEL);
 | 
			
		||||
		if (!ses->ntlmssp)
 | 
			
		||||
			return -ENOMEM;
 | 
			
		||||
		ses->ntlmssp->sesskey_per_smbsess = false;
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
ssetup_ntlmssp_authenticate:
 | 
			
		||||
	if (phase == NtLmChallenge)
 | 
			
		||||
		phase = NtLmAuthenticate; /* if ntlmssp, now final phase */
 | 
			
		||||
 | 
			
		||||
	/* 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)
 | 
			
		||||
		return rc;
 | 
			
		||||
 | 
			
		||||
	pSMB = (SESSION_SETUP_ANDX *)smb_buf;
 | 
			
		||||
 | 
			
		||||
	capabilities = cifs_ssetup_hdr(ses, pSMB);
 | 
			
		||||
 | 
			
		||||
	/* we will send the SMB in three pieces:
 | 
			
		||||
	a fixed length beginning part, an optional
 | 
			
		||||
	SPNEGO blob (which can be zero length), and a
 | 
			
		||||
	last part which will include the strings
 | 
			
		||||
	and rest of bcc area. This allows us to avoid
 | 
			
		||||
	a large buffer 17K allocation */
 | 
			
		||||
	iov[0].iov_base = (char *)pSMB;
 | 
			
		||||
	iov[0].iov_len = be32_to_cpu(smb_buf->smb_buf_length) + 4;
 | 
			
		||||
 | 
			
		||||
	/* setting this here allows the code at the end of the function
 | 
			
		||||
	   to free the request buffer if there's an error */
 | 
			
		||||
	resp_buf_type = CIFS_SMALL_BUFFER;
 | 
			
		||||
 | 
			
		||||
	/* 2000 big enough to fit max user, domain, NOS name etc. */
 | 
			
		||||
	str_area = kmalloc(2000, GFP_KERNEL);
 | 
			
		||||
	if (str_area == NULL) {
 | 
			
		||||
		rc = -ENOMEM;
 | 
			
		||||
		goto ssetup_exit;
 | 
			
		||||
	}
 | 
			
		||||
	bcc_ptr = str_area;
 | 
			
		||||
 | 
			
		||||
	iov[1].iov_base = NULL;
 | 
			
		||||
	iov[1].iov_len = 0;
 | 
			
		||||
 | 
			
		||||
	if (type == RawNTLMSSP) {
 | 
			
		||||
		if ((pSMB->req.hdr.Flags2 & SMBFLG2_UNICODE) == 0) {
 | 
			
		||||
			cifs_dbg(VFS, "NTLMSSP requires Unicode support\n");
 | 
			
		||||
			rc = -ENOSYS;
 | 
			
		||||
			goto ssetup_exit;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		cifs_dbg(FYI, "ntlmssp session setup phase %d\n", phase);
 | 
			
		||||
		pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
 | 
			
		||||
		capabilities |= CAP_EXTENDED_SECURITY;
 | 
			
		||||
		pSMB->req.Capabilities |= cpu_to_le32(capabilities);
 | 
			
		||||
		switch(phase) {
 | 
			
		||||
		case NtLmNegotiate:
 | 
			
		||||
			build_ntlmssp_negotiate_blob(
 | 
			
		||||
				pSMB->req.SecurityBlob, ses);
 | 
			
		||||
			iov[1].iov_len = sizeof(NEGOTIATE_MESSAGE);
 | 
			
		||||
			iov[1].iov_base = pSMB->req.SecurityBlob;
 | 
			
		||||
			pSMB->req.SecurityBlobLength =
 | 
			
		||||
				cpu_to_le16(sizeof(NEGOTIATE_MESSAGE));
 | 
			
		||||
			break;
 | 
			
		||||
		case NtLmAuthenticate:
 | 
			
		||||
			/*
 | 
			
		||||
			 * 5 is an empirical value, large enough to hold
 | 
			
		||||
			 * authenticate message plus max 10 of av paris,
 | 
			
		||||
			 * domain, user, workstation names, flags, etc.
 | 
			
		||||
			 */
 | 
			
		||||
			ntlmsspblob = kzalloc(
 | 
			
		||||
				5*sizeof(struct _AUTHENTICATE_MESSAGE),
 | 
			
		||||
				GFP_KERNEL);
 | 
			
		||||
			if (!ntlmsspblob) {
 | 
			
		||||
				rc = -ENOMEM;
 | 
			
		||||
				goto ssetup_exit;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			rc = build_ntlmssp_auth_blob(ntlmsspblob,
 | 
			
		||||
						&blob_len, ses, nls_cp);
 | 
			
		||||
			if (rc)
 | 
			
		||||
				goto ssetup_exit;
 | 
			
		||||
			iov[1].iov_len = blob_len;
 | 
			
		||||
			iov[1].iov_base = ntlmsspblob;
 | 
			
		||||
			pSMB->req.SecurityBlobLength = cpu_to_le16(blob_len);
 | 
			
		||||
			/*
 | 
			
		||||
			 * Make sure that we tell the server that we are using
 | 
			
		||||
			 * the uid that it just gave us back on the response
 | 
			
		||||
			 * (challenge)
 | 
			
		||||
			 */
 | 
			
		||||
			smb_buf->Uid = ses->Suid;
 | 
			
		||||
			break;
 | 
			
		||||
		default:
 | 
			
		||||
			cifs_dbg(VFS, "invalid phase %d\n", phase);
 | 
			
		||||
			rc = -ENOSYS;
 | 
			
		||||
			goto ssetup_exit;
 | 
			
		||||
		}
 | 
			
		||||
		/* unicode strings must be word aligned */
 | 
			
		||||
		if ((iov[0].iov_len + iov[1].iov_len) % 2) {
 | 
			
		||||
			*bcc_ptr = 0;
 | 
			
		||||
			bcc_ptr++;
 | 
			
		||||
		}
 | 
			
		||||
		unicode_oslm_strings(&bcc_ptr, nls_cp);
 | 
			
		||||
	} else {
 | 
			
		||||
		cifs_dbg(VFS, "secType %d not supported!\n", type);
 | 
			
		||||
		rc = -ENOSYS;
 | 
			
		||||
		goto ssetup_exit;
 | 
			
		||||
		return -ENOSYS;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	iov[2].iov_base = str_area;
 | 
			
		||||
	iov[2].iov_len = (long) bcc_ptr - (long) str_area;
 | 
			
		||||
	return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
	count = iov[1].iov_len + iov[2].iov_len;
 | 
			
		||||
	smb_buf->smb_buf_length =
 | 
			
		||||
		cpu_to_be32(be32_to_cpu(smb_buf->smb_buf_length) + count);
 | 
			
		||||
int CIFS_SessSetup(const unsigned int xid, struct cifs_ses *ses,
 | 
			
		||||
		    const struct nls_table *nls_cp)
 | 
			
		||||
{
 | 
			
		||||
	int rc = 0;
 | 
			
		||||
	struct sess_data *sess_data;
 | 
			
		||||
 | 
			
		||||
	put_bcc(count, smb_buf);
 | 
			
		||||
 | 
			
		||||
	rc = SendReceive2(xid, ses, iov, 3 /* num_iovecs */, &resp_buf_type,
 | 
			
		||||
			  CIFS_LOG_ERROR);
 | 
			
		||||
	/* SMB request buf freed in SendReceive2 */
 | 
			
		||||
 | 
			
		||||
	pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base;
 | 
			
		||||
	smb_buf = (struct smb_hdr *)iov[0].iov_base;
 | 
			
		||||
 | 
			
		||||
	if ((type == RawNTLMSSP) && (resp_buf_type != CIFS_NO_BUFFER) &&
 | 
			
		||||
	    (smb_buf->Status.CifsError ==
 | 
			
		||||
			cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED))) {
 | 
			
		||||
		if (phase != NtLmNegotiate) {
 | 
			
		||||
			cifs_dbg(VFS, "Unexpected more processing error\n");
 | 
			
		||||
			goto ssetup_exit;
 | 
			
		||||
		}
 | 
			
		||||
		/* NTLMSSP Negotiate sent now processing challenge (response) */
 | 
			
		||||
		phase = NtLmChallenge; /* process ntlmssp challenge */
 | 
			
		||||
		rc = 0; /* MORE_PROC rc is not an error here, but expected */
 | 
			
		||||
	if (ses == NULL) {
 | 
			
		||||
		WARN(1, "%s: ses == NULL!", __func__);
 | 
			
		||||
		return -EINVAL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	sess_data = kzalloc(sizeof(struct sess_data), GFP_KERNEL);
 | 
			
		||||
	if (!sess_data)
 | 
			
		||||
		return -ENOMEM;
 | 
			
		||||
 | 
			
		||||
	rc = select_sec(ses, sess_data);
 | 
			
		||||
	if (rc)
 | 
			
		||||
		goto ssetup_exit;
 | 
			
		||||
		goto out;
 | 
			
		||||
 | 
			
		||||
	if (smb_buf->WordCount != 4) {
 | 
			
		||||
		rc = -EIO;
 | 
			
		||||
		cifs_dbg(VFS, "bad word count %d\n", smb_buf->WordCount);
 | 
			
		||||
		goto ssetup_exit;
 | 
			
		||||
	}
 | 
			
		||||
	action = le16_to_cpu(pSMB->resp.Action);
 | 
			
		||||
	if (action & GUEST_LOGIN)
 | 
			
		||||
		cifs_dbg(FYI, "Guest login\n"); /* BB mark SesInfo struct? */
 | 
			
		||||
	ses->Suid = smb_buf->Uid;   /* UID left in wire format (le) */
 | 
			
		||||
	cifs_dbg(FYI, "UID = %llu\n", ses->Suid);
 | 
			
		||||
	/* response can have either 3 or 4 word count - Samba sends 3 */
 | 
			
		||||
	/* and lanman response is 3 */
 | 
			
		||||
	bytes_remaining = get_bcc(smb_buf);
 | 
			
		||||
	bcc_ptr = pByteArea(smb_buf);
 | 
			
		||||
	sess_data->xid = xid;
 | 
			
		||||
	sess_data->ses = ses;
 | 
			
		||||
	sess_data->buf0_type = CIFS_NO_BUFFER;
 | 
			
		||||
	sess_data->nls_cp = (struct nls_table *) nls_cp;
 | 
			
		||||
 | 
			
		||||
	blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength);
 | 
			
		||||
	if (blob_len > bytes_remaining) {
 | 
			
		||||
		cifs_dbg(VFS, "bad security blob length %d\n",
 | 
			
		||||
			 blob_len);
 | 
			
		||||
		rc = -EINVAL;
 | 
			
		||||
		goto ssetup_exit;
 | 
			
		||||
	}
 | 
			
		||||
	if (phase == NtLmChallenge) {
 | 
			
		||||
		rc = decode_ntlmssp_challenge(bcc_ptr, blob_len, ses);
 | 
			
		||||
		if (rc)
 | 
			
		||||
			goto ssetup_exit;
 | 
			
		||||
	}
 | 
			
		||||
	bcc_ptr += blob_len;
 | 
			
		||||
	bytes_remaining -= blob_len;
 | 
			
		||||
	while (sess_data->func)
 | 
			
		||||
		sess_data->func(sess_data);
 | 
			
		||||
 | 
			
		||||
	/* BB check if Unicode and decode strings */
 | 
			
		||||
	if (bytes_remaining == 0) {
 | 
			
		||||
		/* no string area to decode, do nothing */
 | 
			
		||||
	} else if (smb_buf->Flags2 & SMBFLG2_UNICODE) {
 | 
			
		||||
		/* unicode string area must be word-aligned */
 | 
			
		||||
		if (((unsigned long) bcc_ptr - (unsigned long) smb_buf) % 2) {
 | 
			
		||||
			++bcc_ptr;
 | 
			
		||||
			--bytes_remaining;
 | 
			
		||||
		}
 | 
			
		||||
		decode_unicode_ssetup(&bcc_ptr, bytes_remaining, ses, nls_cp);
 | 
			
		||||
	} else {
 | 
			
		||||
		decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses, nls_cp);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
ssetup_exit:
 | 
			
		||||
	kfree(str_area);
 | 
			
		||||
	kfree(ntlmsspblob);
 | 
			
		||||
	ntlmsspblob = NULL;
 | 
			
		||||
	if (resp_buf_type == CIFS_SMALL_BUFFER) {
 | 
			
		||||
		cifs_dbg(FYI, "ssetup freeing small buf %p\n", iov[0].iov_base);
 | 
			
		||||
		cifs_small_buf_release(iov[0].iov_base);
 | 
			
		||||
	} else if (resp_buf_type == CIFS_LARGE_BUFFER)
 | 
			
		||||
		cifs_buf_release(iov[0].iov_base);
 | 
			
		||||
 | 
			
		||||
	/* if ntlmssp, and negotiate succeeded, proceed to authenticate phase */
 | 
			
		||||
	if ((phase == NtLmChallenge) && (rc == 0))
 | 
			
		||||
		goto ssetup_ntlmssp_authenticate;
 | 
			
		||||
 | 
			
		||||
	if (!rc) {
 | 
			
		||||
		mutex_lock(&ses->server->srv_mutex);
 | 
			
		||||
		if (!ses->server->session_estab) {
 | 
			
		||||
			if (ses->server->sign) {
 | 
			
		||||
				ses->server->session_key.response =
 | 
			
		||||
					kmemdup(ses->auth_key.response,
 | 
			
		||||
					ses->auth_key.len, GFP_KERNEL);
 | 
			
		||||
				if (!ses->server->session_key.response) {
 | 
			
		||||
					rc = -ENOMEM;
 | 
			
		||||
					mutex_unlock(&ses->server->srv_mutex);
 | 
			
		||||
					goto keycp_exit;
 | 
			
		||||
				}
 | 
			
		||||
				ses->server->session_key.len =
 | 
			
		||||
							ses->auth_key.len;
 | 
			
		||||
			}
 | 
			
		||||
			ses->server->sequence_number = 0x2;
 | 
			
		||||
			ses->server->session_estab = true;
 | 
			
		||||
		}
 | 
			
		||||
		mutex_unlock(&ses->server->srv_mutex);
 | 
			
		||||
 | 
			
		||||
		cifs_dbg(FYI, "CIFS session established successfully\n");
 | 
			
		||||
		spin_lock(&GlobalMid_Lock);
 | 
			
		||||
		ses->status = CifsGood;
 | 
			
		||||
		ses->need_reconnect = false;
 | 
			
		||||
		spin_unlock(&GlobalMid_Lock);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
keycp_exit:
 | 
			
		||||
	kfree(ses->auth_key.response);
 | 
			
		||||
	ses->auth_key.response = NULL;
 | 
			
		||||
	kfree(ses->ntlmssp);
 | 
			
		||||
 | 
			
		||||
	return rc;
 | 
			
		||||
	/* Store result before we free sess_data */
 | 
			
		||||
	rc = sess_data->result;
 | 
			
		||||
 | 
			
		||||
out:
 | 
			
		||||
	rc = sess_data->result;
 | 
			
		||||
	kfree(sess_data);
 | 
			
		||||
	return rc;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue