blob: c039b54206aa7dd45d80d49dc63027d1f91d45a3 [file] [log] [blame]
Steve French39798772006-05-31 22:40:51 +00001/*
2 * fs/cifs/sess.c
3 *
4 * SMB/CIFS session setup handling routines
5 *
6 * Copyright (c) International Business Machines Corp., 2006
7 * Author(s): Steve French (sfrench@us.ibm.com)
8 *
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.
13 *
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.
18 *
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
22 */
23
24#include "cifspdu.h"
25#include "cifsglob.h"
26#include "cifsproto.h"
27#include "cifs_unicode.h"
28#include "cifs_debug.h"
29#include "ntlmssp.h"
30#include "nterr.h"
Steve French9c535882006-06-01 05:09:10 +000031#include <linux/utsname.h>
Steve French39798772006-05-31 22:40:51 +000032
Steve French39798772006-05-31 22:40:51 +000033extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
34 unsigned char *p24);
35
36#ifdef CONFIG_CIFS_EXPERIMENTAL
37
38static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
39{
40 __u32 capabilities = 0;
41
42 /* init fields common to all four types of SessSetup */
43 /* note that header is initialized to zero in header_assemble */
44 pSMB->req.AndXCommand = 0xFF;
45 pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
46 pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
47
48 /* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */
49
50 /* BB verify whether signing required on neg or just on auth frame
51 (and NTLM case) */
52
53 capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS |
54 CAP_LARGE_WRITE_X | CAP_LARGE_READ_X;
55
56 if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
57 pSMB->req.hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
58
59 if (ses->capabilities & CAP_UNICODE) {
60 pSMB->req.hdr.Flags2 |= SMBFLG2_UNICODE;
61 capabilities |= CAP_UNICODE;
62 }
63 if (ses->capabilities & CAP_STATUS32) {
64 pSMB->req.hdr.Flags2 |= SMBFLG2_ERR_STATUS;
65 capabilities |= CAP_STATUS32;
66 }
67 if (ses->capabilities & CAP_DFS) {
68 pSMB->req.hdr.Flags2 |= SMBFLG2_DFS;
69 capabilities |= CAP_DFS;
70 }
71 if (ses->capabilities & CAP_UNIX) {
72 capabilities |= CAP_UNIX;
73 }
74
75 /* BB check whether to init vcnum BB */
76 return capabilities;
77}
78
Steve French7c7b25b2006-06-01 19:20:10 +000079static void unicode_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
Steve French39798772006-05-31 22:40:51 +000080 const struct nls_table * nls_cp)
81{
82 char * bcc_ptr = *pbcc_area;
83 int bytes_ret = 0;
84
85 /* BB FIXME add check that strings total less
86 than 335 or will need to send them as arrays */
87
88 /* align unicode strings, must be word aligned */
89 if ((long) bcc_ptr % 2) {
90 *bcc_ptr = 0;
91 bcc_ptr++;
92 }
93 /* copy user */
94 if(ses->userName == NULL) {
95 /* BB what about null user mounts - check that we do this BB */
96 } else { /* 300 should be long enough for any conceivable user name */
97 bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->userName,
98 300, nls_cp);
99 }
100 bcc_ptr += 2 * bytes_ret;
101 bcc_ptr += 2; /* account for null termination */
102 /* copy domain */
103 if(ses->domainName == NULL)
104 bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr,
105 "CIFS_LINUX_DOM", 32, nls_cp);
106 else
107 bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, ses->domainName,
108 256, nls_cp);
109 bcc_ptr += 2 * bytes_ret;
110 bcc_ptr += 2; /* account for null terminator */
111
112 /* Copy OS version */
113 bytes_ret = cifs_strtoUCS((__le16 *)bcc_ptr, "Linux version ", 32,
114 nls_cp);
115 bcc_ptr += 2 * bytes_ret;
116 bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, system_utsname.release,
117 32, nls_cp);
118 bcc_ptr += 2 * bytes_ret;
119 bcc_ptr += 2; /* trailing null */
120
121 bytes_ret = cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS,
122 32, nls_cp);
123 bcc_ptr += 2 * bytes_ret;
124 bcc_ptr += 2; /* trailing null */
125
126 *pbcc_area = bcc_ptr;
127}
128
Steve French7c7b25b2006-06-01 19:20:10 +0000129static void ascii_ssetup_strings(char ** pbcc_area, struct cifsSesInfo *ses,
Steve French39798772006-05-31 22:40:51 +0000130 const struct nls_table * nls_cp)
131{
132 char * bcc_ptr = *pbcc_area;
133
134 /* copy user */
135 /* BB what about null user mounts - check that we do this BB */
136 /* copy user */
137 if(ses->userName == NULL) {
138 /* BB what about null user mounts - check that we do this BB */
139 } else { /* 300 should be long enough for any conceivable user name */
140 strncpy(bcc_ptr, ses->userName, 300);
141 }
142 /* BB improve check for overflow */
143 bcc_ptr += strnlen(ses->userName, 200);
144 *bcc_ptr = 0;
145 bcc_ptr++; /* account for null termination */
146
147 /* copy domain */
148
149 if(ses->domainName == NULL) {
150 strcpy(bcc_ptr, "CIFS_LINUX_DOM");
151 bcc_ptr += 14; /* strlen(CIFS_LINUX_DOM) */
152 } else {
153 strncpy(bcc_ptr, ses->domainName, 256);
154 bcc_ptr += strnlen(ses->domainName, 256);
155 }
156 *bcc_ptr = 0;
157 bcc_ptr++;
158
159 /* BB check for overflow here */
160
161 strcpy(bcc_ptr, "Linux version ");
162 bcc_ptr += strlen("Linux version ");
163 strcpy(bcc_ptr, system_utsname.release);
164 bcc_ptr += strlen(system_utsname.release) + 1;
165
166 strcpy(bcc_ptr, CIFS_NETWORK_OPSYS);
167 bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1;
168
169 *pbcc_area = bcc_ptr;
170}
171
Steve French7c7b25b2006-06-01 19:20:10 +0000172static int decode_unicode_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses,
Steve French39798772006-05-31 22:40:51 +0000173 const struct nls_table * nls_cp)
174{
175 int rc = 0;
176 int words_left, len;
177 char * data = *pbcc_area;
178
179
180
181 cFYI(1,("bleft %d",bleft));
182
183
184 /* word align, if bytes remaining is not even */
185 if(bleft % 2) {
186 bleft--;
187 data++;
188 }
189 words_left = bleft / 2;
190
191 /* save off server operating system */
192 len = UniStrnlen((wchar_t *) data, words_left);
193
194/* We look for obvious messed up bcc or strings in response so we do not go off
195 the end since (at least) WIN2K and Windows XP have a major bug in not null
196 terminating last Unicode string in response */
197 if(len >= words_left)
198 return rc;
199
200 if(ses->serverOS)
201 kfree(ses->serverOS);
202 /* UTF-8 string will not grow more than four times as big as UCS-16 */
203 ses->serverOS = kzalloc(4 * len, GFP_KERNEL);
204 if(ses->serverOS != NULL) {
205 cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len,
206 nls_cp);
207 }
208 data += 2 * (len + 1);
209 words_left -= len + 1;
210
211 /* save off server network operating system */
212 len = UniStrnlen((wchar_t *) data, words_left);
213
214 if(len >= words_left)
215 return rc;
216
217 if(ses->serverNOS)
218 kfree(ses->serverNOS);
219 ses->serverNOS = kzalloc(4 * len, GFP_KERNEL); /* BB this is wrong length FIXME BB */
220 if(ses->serverNOS != NULL) {
221 cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len,
222 nls_cp);
223 if(strncmp(ses->serverNOS, "NT LAN Manager 4",16) == 0) {
224 cFYI(1,("NT4 server"));
225 ses->flags |= CIFS_SES_NT4;
226 }
227 }
228 data += 2 * (len + 1);
229 words_left -= len + 1;
230
231 /* save off server domain */
232 len = UniStrnlen((wchar_t *) data, words_left);
233
234 if(len > words_left)
235 return rc;
236
237 if(ses->serverDomain)
238 kfree(ses->serverDomain);
239 ses->serverDomain = kzalloc(2 * (len + 1), GFP_KERNEL); /* BB FIXME wrong length */
240 if(ses->serverDomain != NULL) {
241 cifs_strfromUCS_le(ses->serverDomain, (__le16 *)data, len,
242 nls_cp);
243 ses->serverDomain[2*len] = 0;
244 ses->serverDomain[(2*len) + 1] = 0;
245 }
246 data += 2 * (len + 1);
247 words_left -= len + 1;
248
249 cFYI(1,("words left: %d",words_left));
250
251 return rc;
252}
253
Steve French7c7b25b2006-06-01 19:20:10 +0000254static int decode_ascii_ssetup(char ** pbcc_area, int bleft, struct cifsSesInfo *ses,
Steve French39798772006-05-31 22:40:51 +0000255 const struct nls_table * nls_cp)
256{
257 int rc = 0;
258 int len;
259 char * bcc_ptr = *pbcc_area;
260
261 cFYI(1,("decode sessetup ascii. bleft %d", bleft));
262
263 len = strnlen(bcc_ptr, bleft);
264 if(len >= bleft)
265 return rc;
266
267 if(ses->serverOS)
268 kfree(ses->serverOS);
269
270 ses->serverOS = kzalloc(len + 1, GFP_KERNEL);
271 if(ses->serverOS)
272 strncpy(ses->serverOS, bcc_ptr, len);
273
274 bcc_ptr += len + 1;
275 bleft -= len + 1;
276
277 len = strnlen(bcc_ptr, bleft);
278 if(len >= bleft)
279 return rc;
280
281 if(ses->serverNOS)
282 kfree(ses->serverNOS);
283
284 ses->serverNOS = kzalloc(len + 1, GFP_KERNEL);
285 if(ses->serverNOS)
286 strncpy(ses->serverNOS, bcc_ptr, len);
287
288 bcc_ptr += len + 1;
289 bleft -= len + 1;
290
291 len = strnlen(bcc_ptr, bleft);
292 if(len > bleft)
293 return rc;
294
295 if(ses->serverDomain)
296 kfree(ses->serverDomain);
297
298 ses->serverDomain = kzalloc(len + 1, GFP_KERNEL);
299 if(ses->serverOS)
300 strncpy(ses->serverOS, bcc_ptr, len);
301
302 bcc_ptr += len + 1;
303 bleft -= len + 1;
304
305 cFYI(1,("ascii: bytes left %d",bleft));
306
307 return rc;
308}
309
310int
311CIFS_SessSetup(unsigned int xid, struct cifsSesInfo *ses, int first_time,
312 const struct nls_table *nls_cp)
313{
314 int rc = 0;
315 int wct;
Steve French39798772006-05-31 22:40:51 +0000316 struct smb_hdr *smb_buf;
317 char *bcc_ptr;
318 SESSION_SETUP_ANDX *pSMB;
319 __u32 capabilities;
320 int count;
321 int resp_buf_type = 0;
322 struct kvec iov[1];
323 enum securityEnum type;
324 __u16 action;
325 int bytes_remaining;
Steve French254e55e2006-06-04 05:53:15 +0000326
327 cFYI(1,("new sess setup"));
Steve French39798772006-05-31 22:40:51 +0000328 if(ses == NULL)
329 return -EINVAL;
330
331 type = ses->server->secType;
332 if(type == LANMAN) {
333#ifndef CONFIG_CIFS_WEAK_PW_HASH
334 /* LANMAN and plaintext are less secure and off by default.
335 So we make this explicitly be turned on in kconfig (in the
336 build) and turned on at runtime (changed from the default)
337 in proc/fs/cifs or via mount parm. Unfortunately this is
338 needed for old Win (e.g. Win95), some obscure NAS and OS/2 */
339 return -EOPNOTSUPP;
340#endif
341 wct = 10; /* lanman 2 style sessionsetup */
Steve French9312f672006-06-04 22:21:07 +0000342 } else if((type == NTLM) || (type == NTLMv2)) {
343 /* For NTLMv2 failures eventually may need to retry NTLM */
Steve French39798772006-05-31 22:40:51 +0000344 wct = 13; /* old style NTLM sessionsetup */
Steve French9312f672006-06-04 22:21:07 +0000345 } else /* same size for negotiate or auth, NTLMSSP or extended security */
Steve French39798772006-05-31 22:40:51 +0000346 wct = 12;
347
348 rc = small_smb_init_no_tc(SMB_COM_SESSION_SETUP_ANDX, wct, ses,
349 (void **)&smb_buf);
350 if(rc)
351 return rc;
352
353 pSMB = (SESSION_SETUP_ANDX *)smb_buf;
354
355 capabilities = cifs_ssetup_hdr(ses, pSMB);
356 bcc_ptr = pByteArea(smb_buf);
357
358 if(type == LANMAN) {
359#ifdef CONFIG_CIFS_WEAK_PW_HASH
Steve French7c7b25b2006-06-01 19:20:10 +0000360 char lnm_session_key[CIFS_SESS_KEY_SIZE];
Steve French39798772006-05-31 22:40:51 +0000361
362 /* no capabilities flags in old lanman negotiation */
363
Steve French7c7b25b2006-06-01 19:20:10 +0000364 pSMB->old_req.PasswordLength = CIFS_SESS_KEY_SIZE;
Steve French39798772006-05-31 22:40:51 +0000365 /* BB calculate hash with password */
366 /* and copy into bcc */
367
Steve French7c7b25b2006-06-01 19:20:10 +0000368 calc_lanman_hash(ses, lnm_session_key);
Steve French39798772006-05-31 22:40:51 +0000369
370#ifdef CONFIG_CIFS_DEBUG2
371 cifs_dump_mem("cryptkey: ",ses->server->cryptKey,
Steve French7c7b25b2006-06-01 19:20:10 +0000372 CIFS_SESS_KEY_SIZE);
Steve French39798772006-05-31 22:40:51 +0000373#endif
Steve French7c7b25b2006-06-01 19:20:10 +0000374 memcpy(bcc_ptr, (char *)lnm_session_key, CIFS_SESS_KEY_SIZE);
375 bcc_ptr += CIFS_SESS_KEY_SIZE;
Steve French39798772006-05-31 22:40:51 +0000376
377 /* can not sign if LANMAN negotiated so no need
378 to calculate signing key? but what if server
379 changed to do higher than lanman dialect and
380 we reconnected would we ever calc signing_key? */
381
382 cERROR(1,("Negotiating LANMAN setting up strings"));
383 /* Unicode not allowed for LANMAN dialects */
384 ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
385#endif
386 } else if (type == NTLM) {
Steve French7c7b25b2006-06-01 19:20:10 +0000387 char ntlm_session_key[CIFS_SESS_KEY_SIZE];
Steve French39798772006-05-31 22:40:51 +0000388
389 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
390 pSMB->req_no_secext.CaseInsensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +0000391 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve French39798772006-05-31 22:40:51 +0000392 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve French7c7b25b2006-06-01 19:20:10 +0000393 cpu_to_le16(CIFS_SESS_KEY_SIZE);
Steve French39798772006-05-31 22:40:51 +0000394
395 /* calculate session key */
396 SMBNTencrypt(ses->password, ses->server->cryptKey,
397 ntlm_session_key);
398
399 if(first_time) /* should this be moved into common code
400 with similar ntlmv2 path? */
Steve French7c7b25b2006-06-01 19:20:10 +0000401 cifs_calculate_mac_key( ses->server->mac_signing_key,
Steve French39798772006-05-31 22:40:51 +0000402 ntlm_session_key, ses->password);
403 /* copy session key */
404
Steve French7c7b25b2006-06-01 19:20:10 +0000405 memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESS_KEY_SIZE);
406 bcc_ptr += CIFS_SESS_KEY_SIZE;
407 memcpy(bcc_ptr, (char *)ntlm_session_key,CIFS_SESS_KEY_SIZE);
408 bcc_ptr += CIFS_SESS_KEY_SIZE;
409 if(ses->capabilities & CAP_UNICODE)
410 unicode_ssetup_strings(&bcc_ptr, ses, nls_cp);
411 else
412 ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
413 } else if (type == NTLMv2) {
Steve French6d027cf2006-06-05 16:26:05 +0000414 char * v2_sess_key =
415 kmalloc(sizeof(struct ntlmv2_resp), GFP_KERNEL);
Steve Frenchf64b23a2006-06-05 05:27:37 +0000416
417 /* BB FIXME change all users of v2_sess_key to
418 struct ntlmv2_resp */
Steve French7c7b25b2006-06-01 19:20:10 +0000419
420 if(v2_sess_key == NULL) {
421 cifs_small_buf_release(smb_buf);
422 return -ENOMEM;
423 }
424
425 pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities);
426
427 /* LM2 password would be here if we supported it */
428 pSMB->req_no_secext.CaseInsensitivePasswordLength = 0;
429 /* cpu_to_le16(LM2_SESS_KEY_SIZE); */
430
431 pSMB->req_no_secext.CaseSensitivePasswordLength =
Steve Frenchf64b23a2006-06-05 05:27:37 +0000432 cpu_to_le16(sizeof(struct ntlmv2_resp));
Steve French7c7b25b2006-06-01 19:20:10 +0000433
434 /* calculate session key */
Steve French1717ffc2006-06-08 05:41:32 +0000435 setup_ntlmv2_rsp(ses, v2_sess_key, nls_cp);
Steve French7c7b25b2006-06-01 19:20:10 +0000436 if(first_time) /* should this be moved into common code
437 with similar ntlmv2 path? */
438 /* cifs_calculate_ntlmv2_mac_key(ses->server->mac_signing_key,
439 response BB FIXME, v2_sess_key); */
440
441 /* copy session key */
442
443 /* memcpy(bcc_ptr, (char *)ntlm_session_key,LM2_SESS_KEY_SIZE);
444 bcc_ptr += LM2_SESS_KEY_SIZE; */
Steve Frenchf64b23a2006-06-05 05:27:37 +0000445 memcpy(bcc_ptr, (char *)v2_sess_key, sizeof(struct ntlmv2_resp));
446 bcc_ptr += sizeof(struct ntlmv2_resp);
447 kfree(v2_sess_key);
Steve French39798772006-05-31 22:40:51 +0000448 if(ses->capabilities & CAP_UNICODE)
449 unicode_ssetup_strings(&bcc_ptr, ses, nls_cp);
450 else
451 ascii_ssetup_strings(&bcc_ptr, ses, nls_cp);
452 } else /* NTLMSSP or SPNEGO */ {
453 pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC;
454 capabilities |= CAP_EXTENDED_SECURITY;
455 pSMB->req.Capabilities = cpu_to_le32(capabilities);
456 /* BB set password lengths */
457 }
458
459 count = (long) bcc_ptr - (long) pByteArea(smb_buf);
460 smb_buf->smb_buf_length += count;
461
462 /* if we switch to small buffers, count will need to be fewer
463 than 383 (strings less than 335 bytes) */
464
465 BCC_LE(smb_buf) = cpu_to_le16(count);
466
467
468 /* BB FIXME check for other non ntlm code paths */
469
470 /* BB check is this too big for a small smb? */
471
472 iov[0].iov_base = (char *)pSMB;
473 iov[0].iov_len = smb_buf->smb_buf_length + 4;
474
475 rc = SendReceive2(xid, ses, iov, 1 /* num_iovecs */, &resp_buf_type, 0);
476 /* SMB request buf freed in SendReceive2 */
477
478 cFYI(1,("ssetup rc from sendrecv2 is %d",rc));
479 if(rc)
480 goto ssetup_exit;
481
482 pSMB = (SESSION_SETUP_ANDX *)iov[0].iov_base;
483 smb_buf = (struct smb_hdr *)iov[0].iov_base;
484
485 if((smb_buf->WordCount != 3) && (smb_buf->WordCount != 4)) {
486 rc = -EIO;
487 cERROR(1,("bad word count %d", smb_buf->WordCount));
488 goto ssetup_exit;
489 }
490 action = le16_to_cpu(pSMB->resp.Action);
491 if (action & GUEST_LOGIN)
492 cFYI(1, (" Guest login")); /* BB mark SesInfo struct? */
493 ses->Suid = smb_buf->Uid; /* UID left in wire format (le) */
494 cFYI(1, ("UID = %d ", ses->Suid));
495 /* response can have either 3 or 4 word count - Samba sends 3 */
496 /* and lanman response is 3 */
497 bytes_remaining = BCC(smb_buf);
498 bcc_ptr = pByteArea(smb_buf);
499
500 if(smb_buf->WordCount == 4) {
501 __u16 blob_len;
502 blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength);
503 bcc_ptr += blob_len;
504 if(blob_len > bytes_remaining) {
505 cERROR(1,("bad security blob length %d", blob_len));
506 rc = -EINVAL;
507 goto ssetup_exit;
508 }
509 bytes_remaining -= blob_len;
510 }
511
512 /* BB check if Unicode and decode strings */
513 if(smb_buf->Flags2 & SMBFLG2_UNICODE)
514 rc = decode_unicode_ssetup(&bcc_ptr, bytes_remaining,
515 ses, nls_cp);
516 else
517 rc = decode_ascii_ssetup(&bcc_ptr, bytes_remaining, ses,nls_cp);
518
519ssetup_exit:
520 if(resp_buf_type == CIFS_SMALL_BUFFER) {
521 cFYI(1,("ssetup freeing small buf %p", iov[0].iov_base));
522 cifs_small_buf_release(iov[0].iov_base);
523 } else if(resp_buf_type == CIFS_LARGE_BUFFER)
524 cifs_buf_release(iov[0].iov_base);
525
526 return rc;
527}
528#endif /* CONFIG_CIFS_EXPERIMENTAL */