#include "cifs_debug.h"
#include "ntlmssp.h"
#include "nterr.h"
-#include <linux/ctype.h>
-
-extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
- unsigned char *p24);
+#include <linux/utsname.h>
extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
unsigned char *p24);
-#ifdef CONFIG_CIFS_EXPERIMENTAL
-
static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
{
__u32 capabilities = 0;
return capabilities;
}
-void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
+static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
const struct nls_table * nls_cp)
{
char * bcc_ptr = *pbcc_area;
/* BB FIXME add check that strings total less
than 335 or will need to send them as arrays */
- /* align unicode strings, must be word aligned */
- if ((long) bcc_ptr % 2) {
+ /* unicode strings, must be word aligned before the call */
+/* if ((long) bcc_ptr % 2) {
*bcc_ptr = 0;
bcc_ptr++;
- }
+ } */
/* copy user */
if(ses->userName == NULL) {
/* BB what about null user mounts - check that we do this BB */
bytes_ret = cifs_strtoUCS((__le16 *)bcc_ptr, "Linux version ", 32,
nls_cp);
bcc_ptr += 2 * bytes_ret;
- bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release,
+ bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, init_utsname()->release,
32, nls_cp);
bcc_ptr += 2 * bytes_ret;
bcc_ptr += 2; /* trailing null */
*pbcc_area = bcc_ptr;
}
-void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
+static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
const struct nls_table * nls_cp)
{
char * bcc_ptr = *pbcc_area;
strncpy(bcc_ptr, ses->userName, 300);
}
/* BB improve check for overflow */
- bcc_ptr += strnlen(ses->userName, 200);
+ bcc_ptr += strnlen(ses->userName, 300);
*bcc_ptr = 0;
bcc_ptr++; /* account for null termination */
strcpy(bcc_ptr, "Linux version ");
bcc_ptr += strlen("Linux version ");
- strcpy(bcc_ptr, system_utsname.release);
- bcc_ptr += strlen(system_utsname.release) + 1;
+ strcpy(bcc_ptr, init_utsname()->release);
+ bcc_ptr += strlen(init_utsname()->release) + 1;
strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
*pbcc_area = bcc_ptr;
}
-int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses,
+static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses,
const struct nls_table * nls_cp)
{
int rc = 0;
return rc;
}
-int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses,
+static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses,
const struct nls_table * nls_cp)
{
int rc = 0;
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;
if(len > bleft)
return rc;
- if(ses->serverDomain)
- kfree(ses->serverDomain);
-
- ses->serverDomain = kzalloc(len + 1, GFP_KERNEL);
- if(ses->serverOS)
- strncpy(ses->serverOS, bcc_ptr, len);
-
- bcc_ptr += len + 1;
- bleft -= len + 1;
-
+ /* 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;
{
int rc = 0;
int wct;
- int i;
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[1];
+ 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.
return -EOPNOTSUPP;
#endif
wct = 10; /* lanman 2 style sessionsetup */
- } else if(type == NTLM) /* NTLMv2 may retry NTLM */
+ } else if((type == NTLM) || (type == NTLMv2)) {
+ /* For NTLMv2 failures eventually may need to retry NTLM */
wct = 13; /* old style NTLM sessionsetup */
- else /* same size for negotiate or auth, NTLMSSP or extended security */
+ } else /* same size for negotiate or auth, NTLMSSP or extended security */
wct = 12;
rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses,
pSMB = (SESSION_SETUP_ANDX *)smb_buf;
capabilities = cifs_ssetup_hdr(ses, pSMB);
- bcc_ptr = pByteArea(smb_buf);
+
+ /* 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);
+ bcc_ptr = str_area;
+
+ ses->flags &= ~CIFS_SES_LANMAN;
if(type == LANMAN) {
#ifdef CONFIG_CIFS_WEAK_PW_HASH
- char lnm_session_key[CIFS_SESSION_KEY_SIZE];
- char password_with_pad[CIFS_ENCPWD_SIZE];
+ char lnm_session_key[CIFS_SESS_KEY_SIZE];
/* no capabilities flags in old lanman negotiation */
- pSMB->old_req.PasswordLength = CIFS_SESSION_KEY_SIZE;
+ pSMB->old_req.PasswordLength = cpu_to_le16(CIFS_SESS_KEY_SIZE);
/* BB calculate hash with password */
/* and copy into bcc */
- memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
- strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE);
-
- /* calculate old style session key */
- /* toupper may be less broken then repeatedly calling
- nls_toupper would be, but neither handles multibyte code pages
- but the only alternative would be converting to UCS-16 (Unicode)
- uppercasing and converting back which is only worth doing if
- we knew it were utf8. utf8 code page needs its own
- toupper and tolower and strnicmp functions */
-
- for(i = 0; i< CIFS_ENCPWD_SIZE; i++) {
- password_with_pad[i] = toupper(password_with_pad[i]);
- }
-
- SMBencrypt(password_with_pad, ses->server->cryptKey,
- lnm_session_key);
-
-#ifdef CONFIG_CIFS_DEBUG2
+ calc_lanman_hash(ses, lnm_session_key);
+ ses->flags |= CIFS_SES_LANMAN;
+/* #ifdef CONFIG_CIFS_DEBUG2
cifs_dump_mem("cryptkey: ",ses->server->cryptKey,
- CIFS_SESSION_KEY_SIZE);
-#endif
- /* clear password before we return/free memory */
- memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
- memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESSION_KEY_SIZE);
- bcc_ptr += CIFS_SESSION_KEY_SIZE;
+ 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? */
- cERROR(1,("Negotiating LANMAN setting up strings"));
+ cFYI(1,("Negotiating LANMAN setting up strings"));
/* Unicode not allowed for LANMAN dialects */
ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
#endif
} else if (type == NTLM) {
- char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
+ 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_SESSION_KEY_SIZE);
+ cpu_to_le16(CIFS_SESS_KEY_SIZE);
pSMB->req_no_secext.CaseSensitivePasswordLength =
- cpu_to_le16(CIFS_SESSION_KEY_SIZE);
+ cpu_to_le16(CIFS_SESS_KEY_SIZE);
/* calculate session key */
SMBNTencrypt(ses->password, ses->server->cryptKey,
if(first_time) /* should this be moved into common code
with similar ntlmv2 path? */
- cifs_calculate_mac_key(
- ses->server->mac_signing_key,
+ cifs_calculate_mac_key(ses->server->mac_signing_key,
ntlm_session_key, ses->password);
/* copy session key */
- memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESSION_KEY_SIZE);
- bcc_ptr += CIFS_SESSION_KEY_SIZE;
- memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESSION_KEY_SIZE);
- bcc_ptr += CIFS_SESSION_KEY_SIZE;
- if(ses->capabilities & CAP_UNICODE)
+ 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
+ } 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;
/* BB set password lengths */
}
- count = (long) bcc_ptr - (long) pByteArea(smb_buf);
+ count = (long) bcc_ptr - (long) str_area;
smb_buf->smb_buf_length += count;
- /* if we switch to small buffers, count will need to be fewer
- than 383 (strings less than 335 bytes) */
-
BCC_LE(smb_buf) = cpu_to_le16(count);
-
- /* BB FIXME check for other non ntlm code paths */
-
- /* BB check is this too big for a small smb? */
-
- iov[0].iov_base = (char *)pSMB;
- iov[0].iov_len = smb_buf->smb_buf_length + 4;
-
- rc = SendReceive2(xid, ses, iov, 1 /* num_iovecs */, &resp_buf_type, 0);
+ 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));
}
action = le16_to_cpu(pSMB->resp.Action);
if (action & GUEST_LOGIN)
- cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
+ 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 */
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);
return rc;
}
-#endif /* CONFIG_CIFS_EXPERIMENTAL */