4 * SMB/CIFS session setup handling routines
6 * Copyright (c) International Business Machines Corp., 2006
7 * Author(s): Steve French (sfrench@us.ibm.com)
9 * This library is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as published
11 * by the Free Software Foundation; either version 2.1 of the License, or
12 * (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
17 * the GNU Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include "cifsproto.h"
27 #include "cifs_unicode.h"
28 #include "cifs_debug.h"
31 #include <linux/ctype.h>
32 #include <linux/utsname.h>
34 extern void SMBencrypt(unsigned char *passwd, unsigned char *c8,
37 extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
40 #ifdef CONFIG_CIFS_EXPERIMENTAL
42 static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
44 __u32 capabilities = 0;
46 /* init fields common to all four types of SessSetup */
47 /* note that header is initialized to zero in header_assemble */
48 pSMB->req.AndXCommand = 0xFF;
49 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
50 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
52 /* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */
54 /* BB verify whether signing required on neg or just on auth frame
57 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
58 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
60 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
61 pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
63 if (ses->capabilities & CAP_UNICODE) {
64 pSMB->req.hdr.Flags2 |= SMBFLG2_UNICODE;
65 capabilities |= CAP_UNICODE;
67 if (ses->capabilities & CAP_STATUS32) {
68 pSMB->req.hdr.Flags2 |= SMBFLG2_ERR_STATUS;
69 capabilities |= CAP_STATUS32;
71 if (ses->capabilities & CAP_DFS) {
72 pSMB->req.hdr.Flags2 |= SMBFLG2_DFS;
73 capabilities |= CAP_DFS;
75 if (ses->capabilities & CAP_UNIX) {
76 capabilities |= CAP_UNIX;
79 /* BB check whether to init vcnum BB */
83 void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
84 const struct nls_table * nls_cp)
86 char * bcc_ptr = *pbcc_area;
89 /* BB FIXME add check that strings total less
90 than 335 or will need to send them as arrays */
92 /* align unicode strings, must be word aligned */
93 if ((long) bcc_ptr % 2) {
98 if(ses->userName == NULL) {
99 /* BB what about null user mounts - check that we do this BB */
100 } else { /* 300 should be long enough for any conceivable user name */
101 bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->userName,
104 bcc_ptr += 2 * bytes_ret;
105 bcc_ptr += 2; /* account for null termination */
107 if(ses->domainName == NULL)
108 bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr,
109 "CIFS_LINUX_DOM", 32, nls_cp);
111 bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->domainName,
113 bcc_ptr += 2 * bytes_ret;
114 bcc_ptr += 2; /* account for null terminator */
116 /* Copy OS version */
117 bytes_ret = cifs_strtoUCS((__le16 *)bcc_ptr, "Linux version ", 32,
119 bcc_ptr += 2 * bytes_ret;
120 bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release,
122 bcc_ptr += 2 * bytes_ret;
123 bcc_ptr += 2; /* trailing null */
125 bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
127 bcc_ptr += 2 * bytes_ret;
128 bcc_ptr += 2; /* trailing null */
130 *pbcc_area = bcc_ptr;
133 void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
134 const struct nls_table * nls_cp)
136 char * bcc_ptr = *pbcc_area;
139 /* BB what about null user mounts - check that we do this BB */
141 if(ses->userName == NULL) {
142 /* BB what about null user mounts - check that we do this BB */
143 } else { /* 300 should be long enough for any conceivable user name */
144 strncpy(bcc_ptr, ses->userName, 300);
146 /* BB improve check for overflow */
147 bcc_ptr += strnlen(ses->userName, 200);
149 bcc_ptr++; /* account for null termination */
153 if(ses->domainName == NULL) {
154 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
155 bcc_ptr += 14; /* strlen(CIFS_LINUX_DOM) */
157 strncpy(bcc_ptr, ses->domainName, 256);
158 bcc_ptr += strnlen(ses->domainName, 256);
163 /* BB check for overflow here */
165 strcpy(bcc_ptr, "Linux version ");
166 bcc_ptr += strlen("Linux version ");
167 strcpy(bcc_ptr, system_utsname.release);
168 bcc_ptr += strlen(system_utsname.release) + 1;
170 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
171 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
173 *pbcc_area = bcc_ptr;
176 int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses,
177 const struct nls_table * nls_cp)
181 char * data = *pbcc_area;
185 cFYI(1,("bleft %d",bleft));
188 /* word align, if bytes remaining is not even */
193 words_left = bleft / 2;
195 /* save off server operating system */
196 len = UniStrnlen((wchar_t *) data, words_left);
198 /* We look for obvious messed up bcc or strings in response so we do not go off
199 the end since (at least) WIN2K and Windows XP have a major bug in not null
200 terminating last Unicode string in response */
201 if(len >= words_left)
205 kfree(ses->serverOS);
206 /* UTF-8 string will not grow more than four times as big as UCS-16 */
207 ses->serverOS = kzalloc(4 * len, GFP_KERNEL);
208 if(ses->serverOS != NULL) {
209 cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len,
212 data += 2 * (len + 1);
213 words_left -= len + 1;
215 /* save off server network operating system */
216 len = UniStrnlen((wchar_t *) data, words_left);
218 if(len >= words_left)
222 kfree(ses->serverNOS);
223 ses->serverNOS = kzalloc(4 * len, GFP_KERNEL); /* BB this is wrong length FIXME BB */
224 if(ses->serverNOS != NULL) {
225 cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len,
227 if(strncmp(ses->serverNOS, "NT LAN Manager 4",16) == 0) {
228 cFYI(1,("NT4 server"));
229 ses->flags |= CIFS_SES_NT4;
232 data += 2 * (len + 1);
233 words_left -= len + 1;
235 /* save off server domain */
236 len = UniStrnlen((wchar_t *) data, words_left);
241 if(ses->serverDomain)
242 kfree(ses->serverDomain);
243 ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); /* BB FIXME wrong length */
244 if(ses->serverDomain != NULL) {
245 cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len,
247 ses->serverDomain[2*len] = 0;
248 ses->serverDomain[(2*len) + 1] = 0;
250 data += 2 * (len + 1);
251 words_left -= len + 1;
253 cFYI(1,("words left: %d",words_left));
258 int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses,
259 const struct nls_table * nls_cp)
263 char * bcc_ptr = *pbcc_area;
265 cFYI(1,("decode sessetup ascii. bleft %d", bleft));
267 len = strnlen(bcc_ptr, bleft);
272 kfree(ses->serverOS);
274 ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
276 strncpy(ses->serverOS, bcc_ptr, len);
281 len = strnlen(bcc_ptr, bleft);
286 kfree(ses->serverNOS);
288 ses->serverNOS = kzalloc(len + 1, GFP_KERNEL);
290 strncpy(ses->serverNOS, bcc_ptr, len);
295 len = strnlen(bcc_ptr, bleft);
299 if(ses->serverDomain)
300 kfree(ses->serverDomain);
302 ses->serverDomain = kzalloc(len + 1, GFP_KERNEL);
304 strncpy(ses->serverOS, bcc_ptr, len);
309 cFYI(1,("ascii: bytes left %d",bleft));
315 CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
316 const struct nls_table *nls_cp)
321 struct smb_hdr *smb_buf;
323 SESSION_SETUP_ANDX *pSMB;
326 int resp_buf_type = 0;
328 enum securityEnum type;
335 type = ses->server->secType;
337 #ifndef CONFIG_CIFS_WEAK_PW_HASH
338 /* LANMAN and plaintext are less secure and off by default.
339 So we make this explicitly be turned on in kconfig (in the
340 build) and turned on at runtime (changed from the default)
341 in proc/fs/cifs or via mount parm. Unfortunately this is
342 needed for old Win (e.g. Win95), some obscure NAS and OS/2 */
345 wct = 10; /* lanman 2 style sessionsetup */
346 } else if(type == NTLM) /* NTLMv2 may retry NTLM */
347 wct = 13; /* old style NTLM sessionsetup */
348 else /* same size for negotiate or auth, NTLMSSP or extended security */
351 rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses,
356 pSMB = (SESSION_SETUP_ANDX *)smb_buf;
358 capabilities = cifs_ssetup_hdr(ses, pSMB);
359 bcc_ptr = pByteArea(smb_buf);
362 #ifdef CONFIG_CIFS_WEAK_PW_HASH
363 char lnm_session_key[CIFS_SESSION_KEY_SIZE];
364 char password_with_pad[CIFS_ENCPWD_SIZE];
366 /* no capabilities flags in old lanman negotiation */
368 pSMB->old_req.PasswordLength = CIFS_SESSION_KEY_SIZE;
369 /* BB calculate hash with password */
370 /* and copy into bcc */
372 memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
373 strncpy(password_with_pad, ses->password, CIFS_ENCPWD_SIZE);
375 /* calculate old style session key */
376 /* toupper may be less broken then repeatedly calling
377 nls_toupper would be, but neither handles multibyte code pages
378 but the only alternative would be converting to UCS-16 (Unicode)
379 uppercasing and converting back which is only worth doing if
380 we knew it were utf8. utf8 code page needs its own
381 toupper and tolower and strnicmp functions */
383 for(i = 0; i< CIFS_ENCPWD_SIZE; i++) {
384 password_with_pad[i] = toupper(password_with_pad[i]);
387 SMBencrypt(password_with_pad, ses->server->cryptKey,
390 #ifdef CONFIG_CIFS_DEBUG2
391 cifs_dump_mem("cryptkey: ",ses->server->cryptKey,
392 CIFS_SESSION_KEY_SIZE);
394 /* clear password before we return/free memory */
395 memset(password_with_pad, 0, CIFS_ENCPWD_SIZE);
396 memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESSION_KEY_SIZE);
397 bcc_ptr += CIFS_SESSION_KEY_SIZE;
399 /* can not sign if LANMAN negotiated so no need
400 to calculate signing key? but what if server
401 changed to do higher than lanman dialect and
402 we reconnected would we ever calc signing_key? */
404 cERROR(1,("Negotiating LANMAN setting up strings"));
405 /* Unicode not allowed for LANMAN dialects */
406 ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
408 } else if (type == NTLM) {
409 char ntlm_session_key[CIFS_SESSION_KEY_SIZE];
411 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
412 pSMB->req_no_secext.CaseInsensitivePasswordLength =
413 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
414 pSMB->req_no_secext.CaseSensitivePasswordLength =
415 cpu_to_le16(CIFS_SESSION_KEY_SIZE);
417 /* calculate session key */
418 SMBNTencrypt(ses->password, ses->server->cryptKey,
421 if(first_time) /* should this be moved into common code
422 with similar ntlmv2 path? */
423 cifs_calculate_mac_key(
424 ses->server->mac_signing_key,
425 ntlm_session_key, ses->password);
426 /* copy session key */
428 memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESSION_KEY_SIZE);
429 bcc_ptr += CIFS_SESSION_KEY_SIZE;
430 memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESSION_KEY_SIZE);
431 bcc_ptr += CIFS_SESSION_KEY_SIZE;
432 if(ses->capabilities & CAP_UNICODE)
433 unicode_ssetup_strings(&bcc_ptr, ses, nls_cp);
435 ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
436 } else /* NTLMSSP or SPNEGO */ {
437 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
438 capabilities |= CAP_EXTENDED_SECURITY;
439 pSMB->req.Capabilities = cpu_to_le32(capabilities);
440 /* BB set password lengths */
443 count = (long) bcc_ptr - (long) pByteArea(smb_buf);
444 smb_buf->smb_buf_length += count;
446 /* if we switch to small buffers, count will need to be fewer
447 than 383 (strings less than 335 bytes) */
449 BCC_LE(smb_buf) = cpu_to_le16(count);
452 /* BB FIXME check for other non ntlm code paths */
454 /* BB check is this too big for a small smb? */
456 iov[0].iov_base = (char *)pSMB;
457 iov[0].iov_len = smb_buf->smb_buf_length + 4;
459 rc = SendReceive2(xid, ses, iov, 1 /* num_iovecs */, &resp_buf_type, 0);
460 /* SMB request buf freed in SendReceive2 */
462 cFYI(1,("ssetup rc from sendrecv2 is %d",rc));
466 pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base;
467 smb_buf = (struct smb_hdr *)iov[0].iov_base;
469 if((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) {
471 cERROR(1,("bad word count %d", smb_buf->WordCount));
474 action = le16_to_cpu(pSMB->resp.Action);
475 if (action & GUEST_LOGIN)
476 cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
477 ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */
478 cFYI(1, ("UID = %d ", ses->Suid));
479 /* response can have either 3 or 4 word count - Samba sends 3 */
480 /* and lanman response is 3 */
481 bytes_remaining = BCC(smb_buf);
482 bcc_ptr = pByteArea(smb_buf);
484 if(smb_buf->WordCount == 4) {
486 blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength);
488 if(blob_len > bytes_remaining) {
489 cERROR(1,("bad security blob length %d", blob_len));
493 bytes_remaining -= blob_len;
496 /* BB check if Unicode and decode strings */
497 if(smb_buf->Flags2 & SMBFLG2_UNICODE)
498 rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining,
501 rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,nls_cp);
504 if(resp_buf_type == CIFS_SMALL_BUFFER) {
505 cFYI(1,("ssetup freeing small buf %p", iov[0].iov_base));
506 cifs_small_buf_release(iov[0].iov_base);
507 } else if(resp_buf_type == CIFS_LARGE_BUFFER)
508 cifs_buf_release(iov[0].iov_base);
512 #endif /* CONFIG_CIFS_EXPERIMENTAL */