📄 sess.c
字号:
ses->serverOS = kzalloc(len + 1, GFP_KERNEL); if (ses->serverOS) strncpy(ses->serverOS, bcc_ptr, len); if (strncmp(ses->serverOS, "OS/2", 4) == 0) { cFYI(1, ("OS/2 server")); ses->flags |= CIFS_SES_OS2; } bcc_ptr += len + 1; bleft -= len + 1; len = strnlen(bcc_ptr, bleft); if (len >= bleft) return rc; kfree(ses->serverNOS); ses->serverNOS = kzalloc(len + 1, GFP_KERNEL); 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; /* No domain field in LANMAN case. Domain is returned by old servers in the SMB negprot response */ /* BB For newer servers which do not support Unicode, but thus do return domain here we could add parsing for it later, but it is not very important */ cFYI(1, ("ascii: bytes left %d", bleft)); return rc;}intCIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time, const struct nls_table *nls_cp){ int rc = 0; int wct; struct smb_hdr *smb_buf; char *bcc_ptr; char *str_area; SESSION_SETUP_ANDX *pSMB; __u32 capabilities; int count; int resp_buf_type = 0; struct kvec iov[2]; enum securityEnum type; __u16 action; int bytes_remaining; if (ses == NULL) return -EINVAL; type = ses->server->secType; cFYI(1, ("sess setup type %d", type)); if (type == LANMAN) {#ifndef CONFIG_CIFS_WEAK_PW_HASH /* LANMAN and plaintext are less secure and off by default. 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 */ return -EOPNOTSUPP;#endif wct = 10; /* lanman 2 style sessionsetup */ } else if ((type == NTLM) || (type == NTLMv2)) { /* For NTLMv2 failures eventually may need to retry NTLM */ wct = 13; /* old style NTLM sessionsetup */ } 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) return rc; pSMB = (SESSION_SETUP_ANDX *)smb_buf; capabilities = cifs_ssetup_hdr(ses, pSMB); /* we will send the SMB in two pieces, a fixed length beginning part, and a second part which will include the strings and rest of bcc area, in order to avoid having to do a large buffer 17K allocation */ iov[0].iov_base = (char *)pSMB; iov[0].iov_len = smb_buf->smb_buf_length + 4; /* 2000 big enough to fit max user, domain, NOS name etc. */ str_area = kmalloc(2000, GFP_KERNEL); if (str_area == NULL) { cifs_small_buf_release(smb_buf); return -ENOMEM; } bcc_ptr = str_area; ses->flags &= ~CIFS_SES_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); /* BB calculate hash with password */ /* and copy into bcc */ calc_lanman_hash(ses, lnm_session_key); ses->flags |= CIFS_SES_LANMAN;/* #ifdef CONFIG_CIFS_DEBUG2 cifs_dump_mem("cryptkey: ",ses->server->cryptKey, CIFS_SESS_KEY_SIZE);#endif */ memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESS_KEY_SIZE); bcc_ptr += CIFS_SESS_KEY_SIZE; /* can not sign if LANMAN negotiated so no need to calculate signing key? but what if server changed to do higher than lanman dialect and we reconnected would we ever calc signing_key? */ cFYI(1, ("Negotiating LANMAN setting up strings")); /* Unicode not allowed for LANMAN dialects */ ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);#endif } else if (type == NTLM) { char ntlm_session_key[CIFS_SESS_KEY_SIZE]; pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); pSMB->req_no_secext.CaseInsensitivePasswordLength = 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 with similar ntlmv2 path? */ 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); bcc_ptr += CIFS_SESS_KEY_SIZE; memcpy(bcc_ptr, (char *)ntlm_session_key, CIFS_SESS_KEY_SIZE); bcc_ptr += CIFS_SESS_KEY_SIZE; if (ses->capabilities & CAP_UNICODE) { /* unicode strings must be word aligned */ if (iov[0].iov_len % 2) { *bcc_ptr = 0; bcc_ptr++; } unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); } else ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); } else if (type == NTLMv2) { 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) { cifs_small_buf_release(smb_buf); return -ENOMEM; } pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); /* LM2 password would be here if we supported it */ pSMB->req_no_secext.CaseInsensitivePasswordLength = 0; /* cpu_to_le16(LM2_SESS_KEY_SIZE); */ pSMB->req_no_secext.CaseSensitivePasswordLength = cpu_to_le16(sizeof(struct ntlmv2_resp)); /* 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? */ /* cifs_calculate_ntlmv2_mac_key(ses->server->mac_signing_key, response BB FIXME, v2_sess_key); */ /* copy session key */ /* 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)); bcc_ptr += sizeof(struct ntlmv2_resp); kfree(v2_sess_key); if (ses->capabilities & CAP_UNICODE) { if (iov[0].iov_len % 2) { *bcc_ptr = 0; bcc_ptr++; } unicode_ssetup_strings(&bcc_ptr, ses, nls_cp); } else ascii_ssetup_strings(&bcc_ptr, ses, nls_cp); } else /* NTLMSSP or SPNEGO */ { pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; capabilities |= CAP_EXTENDED_SECURITY; pSMB->req.Capabilities = cpu_to_le32(capabilities); /* BB set password lengths */ } count = (long) bcc_ptr - (long) str_area; smb_buf->smb_buf_length += count; BCC_LE(smb_buf) = cpu_to_le16(count); iov[1].iov_base = str_area; iov[1].iov_len = count; rc = SendReceive2(xid, ses, iov, 2 /* num_iovecs */, &resp_buf_type, 0); /* SMB request buf freed in SendReceive2 */ cFYI(1, ("ssetup rc from sendrecv2 is %d", rc)); 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)) { rc = -EIO; cERROR(1, ("bad word count %d", smb_buf->WordCount)); goto ssetup_exit; } action = le16_to_cpu(pSMB->resp.Action); if (action & GUEST_LOGIN) cFYI(1, ("Guest login")); /* BB mark SesInfo struct? */ ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */ cFYI(1, ("UID = %d ", ses->Suid)); /* response can have either 3 or 4 word count - Samba sends 3 */ /* and lanman response is 3 */ bytes_remaining = BCC(smb_buf); bcc_ptr = pByteArea(smb_buf); 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)); rc = -EINVAL; goto ssetup_exit; } bytes_remaining -= blob_len; } /* BB check if Unicode and decode strings */ 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);ssetup_exit: kfree(str_area); if (resp_buf_type == CIFS_SMALL_BUFFER) { cFYI(1, ("ssetup freeing small buf %p", iov[0].iov_base)); cifs_small_buf_release(iov[0].iov_base); } else if (resp_buf_type == CIFS_LARGE_BUFFER) cifs_buf_release(iov[0].iov_base); return rc;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -