diff options
Diffstat (limited to 'fs/cifs/connect.c')
-rw-r--r-- | fs/cifs/connect.c | 1357 |
1 files changed, 171 insertions, 1186 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 0de3b5615a22..4aa81a507b74 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * fs/cifs/connect.c | 2 | * fs/cifs/connect.c |
3 | * | 3 | * |
4 | * Copyright (C) International Business Machines Corp., 2002,2008 | 4 | * Copyright (C) International Business Machines Corp., 2002,2009 |
5 | * Author(s): Steve French (sfrench@us.ibm.com) | 5 | * Author(s): Steve French (sfrench@us.ibm.com) |
6 | * | 6 | * |
7 | * This library is free software; you can redistribute it and/or modify | 7 | * This library is free software; you can redistribute it and/or modify |
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/kthread.h> | 32 | #include <linux/kthread.h> |
33 | #include <linux/pagevec.h> | 33 | #include <linux/pagevec.h> |
34 | #include <linux/freezer.h> | 34 | #include <linux/freezer.h> |
35 | #include <linux/namei.h> | ||
35 | #include <asm/uaccess.h> | 36 | #include <asm/uaccess.h> |
36 | #include <asm/processor.h> | 37 | #include <asm/processor.h> |
37 | #include <net/ipv6.h> | 38 | #include <net/ipv6.h> |
@@ -978,6 +979,13 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
978 | return 1; | 979 | return 1; |
979 | } else if (strnicmp(value, "krb5", 4) == 0) { | 980 | } else if (strnicmp(value, "krb5", 4) == 0) { |
980 | vol->secFlg |= CIFSSEC_MAY_KRB5; | 981 | vol->secFlg |= CIFSSEC_MAY_KRB5; |
982 | #ifdef CONFIG_CIFS_EXPERIMENTAL | ||
983 | } else if (strnicmp(value, "ntlmsspi", 8) == 0) { | ||
984 | vol->secFlg |= CIFSSEC_MAY_NTLMSSP | | ||
985 | CIFSSEC_MUST_SIGN; | ||
986 | } else if (strnicmp(value, "ntlmssp", 7) == 0) { | ||
987 | vol->secFlg |= CIFSSEC_MAY_NTLMSSP; | ||
988 | #endif | ||
981 | } else if (strnicmp(value, "ntlmv2i", 7) == 0) { | 989 | } else if (strnicmp(value, "ntlmv2i", 7) == 0) { |
982 | vol->secFlg |= CIFSSEC_MAY_NTLMV2 | | 990 | vol->secFlg |= CIFSSEC_MAY_NTLMV2 | |
983 | CIFSSEC_MUST_SIGN; | 991 | CIFSSEC_MUST_SIGN; |
@@ -2214,9 +2222,58 @@ is_path_accessible(int xid, struct cifsTconInfo *tcon, | |||
2214 | return rc; | 2222 | return rc; |
2215 | } | 2223 | } |
2216 | 2224 | ||
2225 | static void | ||
2226 | cleanup_volume_info(struct smb_vol **pvolume_info) | ||
2227 | { | ||
2228 | struct smb_vol *volume_info; | ||
2229 | |||
2230 | if (!pvolume_info && !*pvolume_info) | ||
2231 | return; | ||
2232 | |||
2233 | volume_info = *pvolume_info; | ||
2234 | kzfree(volume_info->password); | ||
2235 | kfree(volume_info->UNC); | ||
2236 | kfree(volume_info->prepath); | ||
2237 | kfree(volume_info); | ||
2238 | *pvolume_info = NULL; | ||
2239 | return; | ||
2240 | } | ||
2241 | |||
2242 | #ifdef CONFIG_CIFS_DFS_UPCALL | ||
2243 | /* build_path_to_root returns full path to root when | ||
2244 | * we do not have an exiting connection (tcon) */ | ||
2245 | static char * | ||
2246 | build_unc_path_to_root(const struct smb_vol *volume_info, | ||
2247 | const struct cifs_sb_info *cifs_sb) | ||
2248 | { | ||
2249 | char *full_path; | ||
2250 | |||
2251 | int unc_len = strnlen(volume_info->UNC, MAX_TREE_SIZE + 1); | ||
2252 | full_path = kmalloc(unc_len + cifs_sb->prepathlen + 1, GFP_KERNEL); | ||
2253 | if (full_path == NULL) | ||
2254 | return ERR_PTR(-ENOMEM); | ||
2255 | |||
2256 | strncpy(full_path, volume_info->UNC, unc_len); | ||
2257 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) { | ||
2258 | int i; | ||
2259 | for (i = 0; i < unc_len; i++) { | ||
2260 | if (full_path[i] == '\\') | ||
2261 | full_path[i] = '/'; | ||
2262 | } | ||
2263 | } | ||
2264 | |||
2265 | if (cifs_sb->prepathlen) | ||
2266 | strncpy(full_path + unc_len, cifs_sb->prepath, | ||
2267 | cifs_sb->prepathlen); | ||
2268 | |||
2269 | full_path[unc_len + cifs_sb->prepathlen] = 0; /* add trailing null */ | ||
2270 | return full_path; | ||
2271 | } | ||
2272 | #endif | ||
2273 | |||
2217 | int | 2274 | int |
2218 | cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | 2275 | cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, |
2219 | char *mount_data, const char *devname) | 2276 | char *mount_data_global, const char *devname) |
2220 | { | 2277 | { |
2221 | int rc = 0; | 2278 | int rc = 0; |
2222 | int xid; | 2279 | int xid; |
@@ -2225,6 +2282,14 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
2225 | struct cifsTconInfo *tcon = NULL; | 2282 | struct cifsTconInfo *tcon = NULL; |
2226 | struct TCP_Server_Info *srvTcp = NULL; | 2283 | struct TCP_Server_Info *srvTcp = NULL; |
2227 | char *full_path; | 2284 | char *full_path; |
2285 | char *mount_data = mount_data_global; | ||
2286 | #ifdef CONFIG_CIFS_DFS_UPCALL | ||
2287 | struct dfs_info3_param *referrals = NULL; | ||
2288 | unsigned int num_referrals = 0; | ||
2289 | int referral_walks_count = 0; | ||
2290 | try_mount_again: | ||
2291 | #endif | ||
2292 | full_path = NULL; | ||
2228 | 2293 | ||
2229 | xid = GetXid(); | 2294 | xid = GetXid(); |
2230 | 2295 | ||
@@ -2371,11 +2436,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
2371 | } | 2436 | } |
2372 | } | 2437 | } |
2373 | 2438 | ||
2374 | /* check for null share name ie connect to dfs root */ | ||
2375 | if ((strchr(volume_info->UNC + 3, '\\') == NULL) | 2439 | if ((strchr(volume_info->UNC + 3, '\\') == NULL) |
2376 | && (strchr(volume_info->UNC + 3, '/') == NULL)) { | 2440 | && (strchr(volume_info->UNC + 3, '/') == NULL)) { |
2377 | /* rc = connect_to_dfs_path(...) */ | 2441 | cERROR(1, ("Missing share name")); |
2378 | cFYI(1, ("DFS root not supported")); | ||
2379 | rc = -ENODEV; | 2442 | rc = -ENODEV; |
2380 | goto mount_fail_check; | 2443 | goto mount_fail_check; |
2381 | } else { | 2444 | } else { |
@@ -2392,7 +2455,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
2392 | } | 2455 | } |
2393 | } | 2456 | } |
2394 | if (rc) | 2457 | if (rc) |
2395 | goto mount_fail_check; | 2458 | goto remote_path_check; |
2396 | tcon->seal = volume_info->seal; | 2459 | tcon->seal = volume_info->seal; |
2397 | write_lock(&cifs_tcp_ses_lock); | 2460 | write_lock(&cifs_tcp_ses_lock); |
2398 | list_add(&tcon->tcon_list, &pSesInfo->tcon_list); | 2461 | list_add(&tcon->tcon_list, &pSesInfo->tcon_list); |
@@ -2417,19 +2480,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
2417 | /* BB FIXME fix time_gran to be larger for LANMAN sessions */ | 2480 | /* BB FIXME fix time_gran to be larger for LANMAN sessions */ |
2418 | sb->s_time_gran = 100; | 2481 | sb->s_time_gran = 100; |
2419 | 2482 | ||
2420 | mount_fail_check: | 2483 | if (rc) |
2421 | /* on error free sesinfo and tcon struct if needed */ | 2484 | goto remote_path_check; |
2422 | if (rc) { | 2485 | |
2423 | /* If find_unc succeeded then rc == 0 so we can not end */ | ||
2424 | /* up accidently freeing someone elses tcon struct */ | ||
2425 | if (tcon) | ||
2426 | cifs_put_tcon(tcon); | ||
2427 | else if (pSesInfo) | ||
2428 | cifs_put_smb_ses(pSesInfo); | ||
2429 | else | ||
2430 | cifs_put_tcp_session(srvTcp); | ||
2431 | goto out; | ||
2432 | } | ||
2433 | cifs_sb->tcon = tcon; | 2486 | cifs_sb->tcon = tcon; |
2434 | 2487 | ||
2435 | /* do not care if following two calls succeed - informational */ | 2488 | /* do not care if following two calls succeed - informational */ |
@@ -2461,7 +2514,9 @@ mount_fail_check: | |||
2461 | cifs_sb->rsize = min(cifs_sb->rsize, | 2514 | cifs_sb->rsize = min(cifs_sb->rsize, |
2462 | (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)); | 2515 | (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)); |
2463 | 2516 | ||
2464 | if (!rc && cifs_sb->prepathlen) { | 2517 | remote_path_check: |
2518 | /* check if a whole path (including prepath) is not remote */ | ||
2519 | if (!rc && cifs_sb->prepathlen && tcon) { | ||
2465 | /* build_path_to_root works only when we have a valid tcon */ | 2520 | /* build_path_to_root works only when we have a valid tcon */ |
2466 | full_path = cifs_build_path_to_root(cifs_sb); | 2521 | full_path = cifs_build_path_to_root(cifs_sb); |
2467 | if (full_path == NULL) { | 2522 | if (full_path == NULL) { |
@@ -2469,1079 +2524,91 @@ mount_fail_check: | |||
2469 | goto mount_fail_check; | 2524 | goto mount_fail_check; |
2470 | } | 2525 | } |
2471 | rc = is_path_accessible(xid, tcon, cifs_sb, full_path); | 2526 | rc = is_path_accessible(xid, tcon, cifs_sb, full_path); |
2472 | if (rc) { | 2527 | if (rc != -EREMOTE) { |
2473 | cERROR(1, ("Path %s in not accessible: %d", | ||
2474 | full_path, rc)); | ||
2475 | kfree(full_path); | 2528 | kfree(full_path); |
2476 | goto mount_fail_check; | 2529 | goto mount_fail_check; |
2477 | } | 2530 | } |
2478 | kfree(full_path); | 2531 | kfree(full_path); |
2479 | } | 2532 | } |
2480 | 2533 | ||
2481 | /* volume_info->password is freed above when existing session found | 2534 | /* get referral if needed */ |
2482 | (in which case it is not needed anymore) but when new sesion is created | 2535 | if (rc == -EREMOTE) { |
2483 | the password ptr is put in the new session structure (in which case the | 2536 | #ifdef CONFIG_CIFS_DFS_UPCALL |
2484 | password will be freed at unmount time) */ | 2537 | if (referral_walks_count > MAX_NESTED_LINKS) { |
2485 | out: | 2538 | /* |
2486 | /* zero out password before freeing */ | 2539 | * BB: when we implement proper loop detection, |
2487 | if (volume_info) { | 2540 | * we will remove this check. But now we need it |
2488 | if (volume_info->password != NULL) { | 2541 | * to prevent an indefinite loop if 'DFS tree' is |
2489 | memset(volume_info->password, 0, | 2542 | * misconfigured (i.e. has loops). |
2490 | strlen(volume_info->password)); | 2543 | */ |
2491 | kfree(volume_info->password); | 2544 | rc = -ELOOP; |
2492 | } | 2545 | goto mount_fail_check; |
2493 | kfree(volume_info->UNC); | ||
2494 | kfree(volume_info->prepath); | ||
2495 | kfree(volume_info); | ||
2496 | } | ||
2497 | FreeXid(xid); | ||
2498 | return rc; | ||
2499 | } | ||
2500 | |||
2501 | static int | ||
2502 | CIFSSessSetup(unsigned int xid, struct cifsSesInfo *ses, | ||
2503 | char session_key[CIFS_SESS_KEY_SIZE], | ||
2504 | const struct nls_table *nls_codepage) | ||
2505 | { | ||
2506 | struct smb_hdr *smb_buffer; | ||
2507 | struct smb_hdr *smb_buffer_response; | ||
2508 | SESSION_SETUP_ANDX *pSMB; | ||
2509 | SESSION_SETUP_ANDX *pSMBr; | ||
2510 | char *bcc_ptr; | ||
2511 | char *user; | ||
2512 | char *domain; | ||
2513 | int rc = 0; | ||
2514 | int remaining_words = 0; | ||
2515 | int bytes_returned = 0; | ||
2516 | int len; | ||
2517 | __u32 capabilities; | ||
2518 | __u16 count; | ||
2519 | |||
2520 | cFYI(1, ("In sesssetup")); | ||
2521 | if (ses == NULL) | ||
2522 | return -EINVAL; | ||
2523 | user = ses->userName; | ||
2524 | domain = ses->domainName; | ||
2525 | smb_buffer = cifs_buf_get(); | ||
2526 | |||
2527 | if (smb_buffer == NULL) | ||
2528 | return -ENOMEM; | ||
2529 | |||
2530 | smb_buffer_response = smb_buffer; | ||
2531 | pSMBr = pSMB = (SESSION_SETUP_ANDX *) smb_buffer; | ||
2532 | |||
2533 | /* send SMBsessionSetup here */ | ||
2534 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, | ||
2535 | NULL /* no tCon exists yet */ , 13 /* wct */ ); | ||
2536 | |||
2537 | smb_buffer->Mid = GetNextMid(ses->server); | ||
2538 | pSMB->req_no_secext.AndXCommand = 0xFF; | ||
2539 | pSMB->req_no_secext.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); | ||
2540 | pSMB->req_no_secext.MaxMpxCount = cpu_to_le16(ses->server->maxReq); | ||
2541 | |||
2542 | if (ses->server->secMode & | ||
2543 | (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
2544 | smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | ||
2545 | |||
2546 | capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | | ||
2547 | CAP_LARGE_WRITE_X | CAP_LARGE_READ_X; | ||
2548 | if (ses->capabilities & CAP_UNICODE) { | ||
2549 | smb_buffer->Flags2 |= SMBFLG2_UNICODE; | ||
2550 | capabilities |= CAP_UNICODE; | ||
2551 | } | ||
2552 | if (ses->capabilities & CAP_STATUS32) { | ||
2553 | smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; | ||
2554 | capabilities |= CAP_STATUS32; | ||
2555 | } | ||
2556 | if (ses->capabilities & CAP_DFS) { | ||
2557 | smb_buffer->Flags2 |= SMBFLG2_DFS; | ||
2558 | capabilities |= CAP_DFS; | ||
2559 | } | ||
2560 | pSMB->req_no_secext.Capabilities = cpu_to_le32(capabilities); | ||
2561 | |||
2562 | pSMB->req_no_secext.CaseInsensitivePasswordLength = | ||
2563 | cpu_to_le16(CIFS_SESS_KEY_SIZE); | ||
2564 | |||
2565 | pSMB->req_no_secext.CaseSensitivePasswordLength = | ||
2566 | cpu_to_le16(CIFS_SESS_KEY_SIZE); | ||
2567 | bcc_ptr = pByteArea(smb_buffer); | ||
2568 | memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE); | ||
2569 | bcc_ptr += CIFS_SESS_KEY_SIZE; | ||
2570 | memcpy(bcc_ptr, (char *) session_key, CIFS_SESS_KEY_SIZE); | ||
2571 | bcc_ptr += CIFS_SESS_KEY_SIZE; | ||
2572 | |||
2573 | if (ses->capabilities & CAP_UNICODE) { | ||
2574 | if ((long) bcc_ptr % 2) { /* must be word aligned for Unicode */ | ||
2575 | *bcc_ptr = 0; | ||
2576 | bcc_ptr++; | ||
2577 | } | ||
2578 | if (user == NULL) | ||
2579 | bytes_returned = 0; /* skip null user */ | ||
2580 | else | ||
2581 | bytes_returned = | ||
2582 | cifs_strtoUCS((__le16 *) bcc_ptr, user, 100, | ||
2583 | nls_codepage); | ||
2584 | /* convert number of 16 bit words to bytes */ | ||
2585 | bcc_ptr += 2 * bytes_returned; | ||
2586 | bcc_ptr += 2; /* trailing null */ | ||
2587 | if (domain == NULL) | ||
2588 | bytes_returned = | ||
2589 | cifs_strtoUCS((__le16 *) bcc_ptr, | ||
2590 | "CIFS_LINUX_DOM", 32, nls_codepage); | ||
2591 | else | ||
2592 | bytes_returned = | ||
2593 | cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64, | ||
2594 | nls_codepage); | ||
2595 | bcc_ptr += 2 * bytes_returned; | ||
2596 | bcc_ptr += 2; | ||
2597 | bytes_returned = | ||
2598 | cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", | ||
2599 | 32, nls_codepage); | ||
2600 | bcc_ptr += 2 * bytes_returned; | ||
2601 | bytes_returned = | ||
2602 | cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, | ||
2603 | 32, nls_codepage); | ||
2604 | bcc_ptr += 2 * bytes_returned; | ||
2605 | bcc_ptr += 2; | ||
2606 | bytes_returned = | ||
2607 | cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, | ||
2608 | 64, nls_codepage); | ||
2609 | bcc_ptr += 2 * bytes_returned; | ||
2610 | bcc_ptr += 2; | ||
2611 | } else { | ||
2612 | if (user != NULL) { | ||
2613 | strncpy(bcc_ptr, user, 200); | ||
2614 | bcc_ptr += strnlen(user, 200); | ||
2615 | } | ||
2616 | *bcc_ptr = 0; | ||
2617 | bcc_ptr++; | ||
2618 | if (domain == NULL) { | ||
2619 | strcpy(bcc_ptr, "CIFS_LINUX_DOM"); | ||
2620 | bcc_ptr += strlen("CIFS_LINUX_DOM") + 1; | ||
2621 | } else { | ||
2622 | strncpy(bcc_ptr, domain, 64); | ||
2623 | bcc_ptr += strnlen(domain, 64); | ||
2624 | *bcc_ptr = 0; | ||
2625 | bcc_ptr++; | ||
2626 | } | ||
2627 | strcpy(bcc_ptr, "Linux version "); | ||
2628 | bcc_ptr += strlen("Linux version "); | ||
2629 | strcpy(bcc_ptr, utsname()->release); | ||
2630 | bcc_ptr += strlen(utsname()->release) + 1; | ||
2631 | strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); | ||
2632 | bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; | ||
2633 | } | ||
2634 | count = (long) bcc_ptr - (long) pByteArea(smb_buffer); | ||
2635 | smb_buffer->smb_buf_length += count; | ||
2636 | pSMB->req_no_secext.ByteCount = cpu_to_le16(count); | ||
2637 | |||
2638 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, | ||
2639 | &bytes_returned, CIFS_LONG_OP); | ||
2640 | if (rc) { | ||
2641 | /* rc = map_smb_to_linux_error(smb_buffer_response); now done in SendReceive */ | ||
2642 | } else if ((smb_buffer_response->WordCount == 3) | ||
2643 | || (smb_buffer_response->WordCount == 4)) { | ||
2644 | __u16 action = le16_to_cpu(pSMBr->resp.Action); | ||
2645 | __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); | ||
2646 | if (action & GUEST_LOGIN) | ||
2647 | cFYI(1, ("Guest login")); /* BB mark SesInfo struct? */ | ||
2648 | ses->Suid = smb_buffer_response->Uid; /* UID left in wire format | ||
2649 | (little endian) */ | ||
2650 | cFYI(1, ("UID = %d ", ses->Suid)); | ||
2651 | /* response can have either 3 or 4 word count - Samba sends 3 */ | ||
2652 | bcc_ptr = pByteArea(smb_buffer_response); | ||
2653 | if ((pSMBr->resp.hdr.WordCount == 3) | ||
2654 | || ((pSMBr->resp.hdr.WordCount == 4) | ||
2655 | && (blob_len < pSMBr->resp.ByteCount))) { | ||
2656 | if (pSMBr->resp.hdr.WordCount == 4) | ||
2657 | bcc_ptr += blob_len; | ||
2658 | |||
2659 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { | ||
2660 | if ((long) (bcc_ptr) % 2) { | ||
2661 | remaining_words = | ||
2662 | (BCC(smb_buffer_response) - 1) / 2; | ||
2663 | /* Unicode strings must be word | ||
2664 | aligned */ | ||
2665 | bcc_ptr++; | ||
2666 | } else { | ||
2667 | remaining_words = | ||
2668 | BCC(smb_buffer_response) / 2; | ||
2669 | } | ||
2670 | len = | ||
2671 | UniStrnlen((wchar_t *) bcc_ptr, | ||
2672 | remaining_words - 1); | ||
2673 | /* We look for obvious messed up bcc or strings in response so we do not go off | ||
2674 | the end since (at least) WIN2K and Windows XP have a major bug in not null | ||
2675 | terminating last Unicode string in response */ | ||
2676 | if (ses->serverOS) | ||
2677 | kfree(ses->serverOS); | ||
2678 | ses->serverOS = kzalloc(2 * (len + 1), | ||
2679 | GFP_KERNEL); | ||
2680 | if (ses->serverOS == NULL) | ||
2681 | goto sesssetup_nomem; | ||
2682 | cifs_strfromUCS_le(ses->serverOS, | ||
2683 | (__le16 *)bcc_ptr, | ||
2684 | len, nls_codepage); | ||
2685 | bcc_ptr += 2 * (len + 1); | ||
2686 | remaining_words -= len + 1; | ||
2687 | ses->serverOS[2 * len] = 0; | ||
2688 | ses->serverOS[1 + (2 * len)] = 0; | ||
2689 | if (remaining_words > 0) { | ||
2690 | len = UniStrnlen((wchar_t *)bcc_ptr, | ||
2691 | remaining_words-1); | ||
2692 | kfree(ses->serverNOS); | ||
2693 | ses->serverNOS = kzalloc(2 * (len + 1), | ||
2694 | GFP_KERNEL); | ||
2695 | if (ses->serverNOS == NULL) | ||
2696 | goto sesssetup_nomem; | ||
2697 | cifs_strfromUCS_le(ses->serverNOS, | ||
2698 | (__le16 *)bcc_ptr, | ||
2699 | len, nls_codepage); | ||
2700 | bcc_ptr += 2 * (len + 1); | ||
2701 | ses->serverNOS[2 * len] = 0; | ||
2702 | ses->serverNOS[1 + (2 * len)] = 0; | ||
2703 | if (strncmp(ses->serverNOS, | ||
2704 | "NT LAN Manager 4", 16) == 0) { | ||
2705 | cFYI(1, ("NT4 server")); | ||
2706 | ses->flags |= CIFS_SES_NT4; | ||
2707 | } | ||
2708 | remaining_words -= len + 1; | ||
2709 | if (remaining_words > 0) { | ||
2710 | len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); | ||
2711 | /* last string is not always null terminated | ||
2712 | (for e.g. for Windows XP & 2000) */ | ||
2713 | if (ses->serverDomain) | ||
2714 | kfree(ses->serverDomain); | ||
2715 | ses->serverDomain = | ||
2716 | kzalloc(2*(len+1), | ||
2717 | GFP_KERNEL); | ||
2718 | if (ses->serverDomain == NULL) | ||
2719 | goto sesssetup_nomem; | ||
2720 | cifs_strfromUCS_le(ses->serverDomain, | ||
2721 | (__le16 *)bcc_ptr, | ||
2722 | len, nls_codepage); | ||
2723 | bcc_ptr += 2 * (len + 1); | ||
2724 | ses->serverDomain[2*len] = 0; | ||
2725 | ses->serverDomain[1+(2*len)] = 0; | ||
2726 | } else { /* else no more room so create | ||
2727 | dummy domain string */ | ||
2728 | if (ses->serverDomain) | ||
2729 | kfree(ses->serverDomain); | ||
2730 | ses->serverDomain = | ||
2731 | kzalloc(2, GFP_KERNEL); | ||
2732 | } | ||
2733 | } else { /* no room so create dummy domain | ||
2734 | and NOS string */ | ||
2735 | |||
2736 | /* if these kcallocs fail not much we | ||
2737 | can do, but better to not fail the | ||
2738 | sesssetup itself */ | ||
2739 | kfree(ses->serverDomain); | ||
2740 | ses->serverDomain = | ||
2741 | kzalloc(2, GFP_KERNEL); | ||
2742 | kfree(ses->serverNOS); | ||
2743 | ses->serverNOS = | ||
2744 | kzalloc(2, GFP_KERNEL); | ||
2745 | } | ||
2746 | } else { /* ASCII */ | ||
2747 | len = strnlen(bcc_ptr, 1024); | ||
2748 | if (((long) bcc_ptr + len) - (long) | ||
2749 | pByteArea(smb_buffer_response) | ||
2750 | <= BCC(smb_buffer_response)) { | ||
2751 | kfree(ses->serverOS); | ||
2752 | ses->serverOS = kzalloc(len + 1, | ||
2753 | GFP_KERNEL); | ||
2754 | if (ses->serverOS == NULL) | ||
2755 | goto sesssetup_nomem; | ||
2756 | strncpy(ses->serverOS, bcc_ptr, len); | ||
2757 | |||
2758 | bcc_ptr += len; | ||
2759 | /* null terminate the string */ | ||
2760 | bcc_ptr[0] = 0; | ||
2761 | bcc_ptr++; | ||
2762 | |||
2763 | len = strnlen(bcc_ptr, 1024); | ||
2764 | kfree(ses->serverNOS); | ||
2765 | ses->serverNOS = kzalloc(len + 1, | ||
2766 | GFP_KERNEL); | ||
2767 | if (ses->serverNOS == NULL) | ||
2768 | goto sesssetup_nomem; | ||
2769 | strncpy(ses->serverNOS, bcc_ptr, len); | ||
2770 | bcc_ptr += len; | ||
2771 | bcc_ptr[0] = 0; | ||
2772 | bcc_ptr++; | ||
2773 | |||
2774 | len = strnlen(bcc_ptr, 1024); | ||
2775 | if (ses->serverDomain) | ||
2776 | kfree(ses->serverDomain); | ||
2777 | ses->serverDomain = kzalloc(len + 1, | ||
2778 | GFP_KERNEL); | ||
2779 | if (ses->serverDomain == NULL) | ||
2780 | goto sesssetup_nomem; | ||
2781 | strncpy(ses->serverDomain, bcc_ptr, | ||
2782 | len); | ||
2783 | bcc_ptr += len; | ||
2784 | bcc_ptr[0] = 0; | ||
2785 | bcc_ptr++; | ||
2786 | } else | ||
2787 | cFYI(1, | ||
2788 | ("Variable field of length %d " | ||
2789 | "extends beyond end of smb ", | ||
2790 | len)); | ||
2791 | } | ||
2792 | } else { | ||
2793 | cERROR(1, ("Security Blob Length extends beyond " | ||
2794 | "end of SMB")); | ||
2795 | } | 2546 | } |
2796 | } else { | 2547 | /* convert forward to back slashes in prepath here if needed */ |
2797 | cERROR(1, ("Invalid Word count %d: ", | 2548 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0) |
2798 | smb_buffer_response->WordCount)); | 2549 | convert_delimiter(cifs_sb->prepath, |
2799 | rc = -EIO; | 2550 | CIFS_DIR_SEP(cifs_sb)); |
2800 | } | 2551 | full_path = build_unc_path_to_root(volume_info, cifs_sb); |
2801 | sesssetup_nomem: /* do not return an error on nomem for the info strings, | 2552 | if (IS_ERR(full_path)) { |
2802 | since that could make reconnection harder, and | 2553 | rc = PTR_ERR(full_path); |
2803 | reconnection might be needed to free memory */ | 2554 | goto mount_fail_check; |
2804 | cifs_buf_release(smb_buffer); | ||
2805 | |||
2806 | return rc; | ||
2807 | } | ||
2808 | |||
2809 | static int | ||
2810 | CIFSNTLMSSPNegotiateSessSetup(unsigned int xid, | ||
2811 | struct cifsSesInfo *ses, bool *pNTLMv2_flag, | ||
2812 | const struct nls_table *nls_codepage) | ||
2813 | { | ||
2814 | struct smb_hdr *smb_buffer; | ||
2815 | struct smb_hdr *smb_buffer_response; | ||
2816 | SESSION_SETUP_ANDX *pSMB; | ||
2817 | SESSION_SETUP_ANDX *pSMBr; | ||
2818 | char *bcc_ptr; | ||
2819 | char *domain; | ||
2820 | int rc = 0; | ||
2821 | int remaining_words = 0; | ||
2822 | int bytes_returned = 0; | ||
2823 | int len; | ||
2824 | int SecurityBlobLength = sizeof(NEGOTIATE_MESSAGE); | ||
2825 | PNEGOTIATE_MESSAGE SecurityBlob; | ||
2826 | PCHALLENGE_MESSAGE SecurityBlob2; | ||
2827 | __u32 negotiate_flags, capabilities; | ||
2828 | __u16 count; | ||
2829 | |||
2830 | cFYI(1, ("In NTLMSSP sesssetup (negotiate)")); | ||
2831 | if (ses == NULL) | ||
2832 | return -EINVAL; | ||
2833 | domain = ses->domainName; | ||
2834 | *pNTLMv2_flag = false; | ||
2835 | smb_buffer = cifs_buf_get(); | ||
2836 | if (smb_buffer == NULL) { | ||
2837 | return -ENOMEM; | ||
2838 | } | ||
2839 | smb_buffer_response = smb_buffer; | ||
2840 | pSMB = (SESSION_SETUP_ANDX *) smb_buffer; | ||
2841 | pSMBr = (SESSION_SETUP_ANDX *) smb_buffer_response; | ||
2842 | |||
2843 | /* send SMBsessionSetup here */ | ||
2844 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, | ||
2845 | NULL /* no tCon exists yet */ , 12 /* wct */ ); | ||
2846 | |||
2847 | smb_buffer->Mid = GetNextMid(ses->server); | ||
2848 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | ||
2849 | pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); | ||
2850 | |||
2851 | pSMB->req.AndXCommand = 0xFF; | ||
2852 | pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); | ||
2853 | pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); | ||
2854 | |||
2855 | if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
2856 | smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | ||
2857 | |||
2858 | capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | | ||
2859 | CAP_EXTENDED_SECURITY; | ||
2860 | if (ses->capabilities & CAP_UNICODE) { | ||
2861 | smb_buffer->Flags2 |= SMBFLG2_UNICODE; | ||
2862 | capabilities |= CAP_UNICODE; | ||
2863 | } | ||
2864 | if (ses->capabilities & CAP_STATUS32) { | ||
2865 | smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; | ||
2866 | capabilities |= CAP_STATUS32; | ||
2867 | } | ||
2868 | if (ses->capabilities & CAP_DFS) { | ||
2869 | smb_buffer->Flags2 |= SMBFLG2_DFS; | ||
2870 | capabilities |= CAP_DFS; | ||
2871 | } | ||
2872 | pSMB->req.Capabilities = cpu_to_le32(capabilities); | ||
2873 | |||
2874 | bcc_ptr = (char *) &pSMB->req.SecurityBlob; | ||
2875 | SecurityBlob = (PNEGOTIATE_MESSAGE) bcc_ptr; | ||
2876 | strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8); | ||
2877 | SecurityBlob->MessageType = NtLmNegotiate; | ||
2878 | negotiate_flags = | ||
2879 | NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_NEGOTIATE_OEM | | ||
2880 | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | | ||
2881 | NTLMSSP_NEGOTIATE_56 | | ||
2882 | /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN | */ NTLMSSP_NEGOTIATE_128; | ||
2883 | if (sign_CIFS_PDUs) | ||
2884 | negotiate_flags |= NTLMSSP_NEGOTIATE_SIGN; | ||
2885 | /* if (ntlmv2_support) | ||
2886 | negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2;*/ | ||
2887 | /* setup pointers to domain name and workstation name */ | ||
2888 | bcc_ptr += SecurityBlobLength; | ||
2889 | |||
2890 | SecurityBlob->WorkstationName.Buffer = 0; | ||
2891 | SecurityBlob->WorkstationName.Length = 0; | ||
2892 | SecurityBlob->WorkstationName.MaximumLength = 0; | ||
2893 | |||
2894 | /* Domain not sent on first Sesssetup in NTLMSSP, instead it is sent | ||
2895 | along with username on auth request (ie the response to challenge) */ | ||
2896 | SecurityBlob->DomainName.Buffer = 0; | ||
2897 | SecurityBlob->DomainName.Length = 0; | ||
2898 | SecurityBlob->DomainName.MaximumLength = 0; | ||
2899 | if (ses->capabilities & CAP_UNICODE) { | ||
2900 | if ((long) bcc_ptr % 2) { | ||
2901 | *bcc_ptr = 0; | ||
2902 | bcc_ptr++; | ||
2903 | } | 2555 | } |
2904 | 2556 | ||
2905 | bytes_returned = | 2557 | cFYI(1, ("Getting referral for: %s", full_path)); |
2906 | cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", | 2558 | rc = get_dfs_path(xid, pSesInfo , full_path + 1, |
2907 | 32, nls_codepage); | 2559 | cifs_sb->local_nls, &num_referrals, &referrals, |
2908 | bcc_ptr += 2 * bytes_returned; | 2560 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); |
2909 | bytes_returned = | 2561 | if (!rc && num_referrals > 0) { |
2910 | cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32, | 2562 | char *fake_devname = NULL; |
2911 | nls_codepage); | 2563 | |
2912 | bcc_ptr += 2 * bytes_returned; | 2564 | if (mount_data != mount_data_global) |
2913 | bcc_ptr += 2; /* null terminate Linux version */ | 2565 | kfree(mount_data); |
2914 | bytes_returned = | 2566 | mount_data = cifs_compose_mount_options( |
2915 | cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, | 2567 | cifs_sb->mountdata, full_path + 1, |
2916 | 64, nls_codepage); | 2568 | referrals, &fake_devname); |
2917 | bcc_ptr += 2 * bytes_returned; | 2569 | kfree(fake_devname); |
2918 | *(bcc_ptr + 1) = 0; | 2570 | free_dfs_info_array(referrals, num_referrals); |
2919 | *(bcc_ptr + 2) = 0; | 2571 | |
2920 | bcc_ptr += 2; /* null terminate network opsys string */ | 2572 | if (tcon) |
2921 | *(bcc_ptr + 1) = 0; | 2573 | cifs_put_tcon(tcon); |
2922 | *(bcc_ptr + 2) = 0; | 2574 | else if (pSesInfo) |
2923 | bcc_ptr += 2; /* null domain */ | 2575 | cifs_put_smb_ses(pSesInfo); |
2924 | } else { /* ASCII */ | 2576 | |
2925 | strcpy(bcc_ptr, "Linux version "); | 2577 | cleanup_volume_info(&volume_info); |
2926 | bcc_ptr += strlen("Linux version "); | 2578 | FreeXid(xid); |
2927 | strcpy(bcc_ptr, utsname()->release); | 2579 | kfree(full_path); |
2928 | bcc_ptr += strlen(utsname()->release) + 1; | 2580 | referral_walks_count++; |
2929 | strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); | 2581 | goto try_mount_again; |
2930 | bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; | ||
2931 | bcc_ptr++; /* empty domain field */ | ||
2932 | *bcc_ptr = 0; | ||
2933 | } | ||
2934 | SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags); | ||
2935 | pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength); | ||
2936 | count = (long) bcc_ptr - (long) pByteArea(smb_buffer); | ||
2937 | smb_buffer->smb_buf_length += count; | ||
2938 | pSMB->req.ByteCount = cpu_to_le16(count); | ||
2939 | |||
2940 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, | ||
2941 | &bytes_returned, CIFS_LONG_OP); | ||
2942 | |||
2943 | if (smb_buffer_response->Status.CifsError == | ||
2944 | cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED)) | ||
2945 | rc = 0; | ||
2946 | |||
2947 | if (rc) { | ||
2948 | /* rc = map_smb_to_linux_error(smb_buffer_response); *//* done in SendReceive now */ | ||
2949 | } else if ((smb_buffer_response->WordCount == 3) | ||
2950 | || (smb_buffer_response->WordCount == 4)) { | ||
2951 | __u16 action = le16_to_cpu(pSMBr->resp.Action); | ||
2952 | __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); | ||
2953 | |||
2954 | if (action & GUEST_LOGIN) | ||
2955 | cFYI(1, ("Guest login")); | ||
2956 | /* Do we want to set anything in SesInfo struct when guest login? */ | ||
2957 | |||
2958 | bcc_ptr = pByteArea(smb_buffer_response); | ||
2959 | /* response can have either 3 or 4 word count - Samba sends 3 */ | ||
2960 | |||
2961 | SecurityBlob2 = (PCHALLENGE_MESSAGE) bcc_ptr; | ||
2962 | if (SecurityBlob2->MessageType != NtLmChallenge) { | ||
2963 | cFYI(1, ("Unexpected NTLMSSP message type received %d", | ||
2964 | SecurityBlob2->MessageType)); | ||
2965 | } else if (ses) { | ||
2966 | ses->Suid = smb_buffer_response->Uid; /* UID left in le format */ | ||
2967 | cFYI(1, ("UID = %d", ses->Suid)); | ||
2968 | if ((pSMBr->resp.hdr.WordCount == 3) | ||
2969 | || ((pSMBr->resp.hdr.WordCount == 4) | ||
2970 | && (blob_len < | ||
2971 | pSMBr->resp.ByteCount))) { | ||
2972 | |||
2973 | if (pSMBr->resp.hdr.WordCount == 4) { | ||
2974 | bcc_ptr += blob_len; | ||
2975 | cFYI(1, ("Security Blob Length %d", | ||
2976 | blob_len)); | ||
2977 | } | ||
2978 | |||
2979 | cFYI(1, ("NTLMSSP Challenge rcvd")); | ||
2980 | |||
2981 | memcpy(ses->server->cryptKey, | ||
2982 | SecurityBlob2->Challenge, | ||
2983 | CIFS_CRYPTO_KEY_SIZE); | ||
2984 | if (SecurityBlob2->NegotiateFlags & | ||
2985 | cpu_to_le32(NTLMSSP_NEGOTIATE_NTLMV2)) | ||
2986 | *pNTLMv2_flag = true; | ||
2987 | |||
2988 | if ((SecurityBlob2->NegotiateFlags & | ||
2989 | cpu_to_le32(NTLMSSP_NEGOTIATE_ALWAYS_SIGN)) | ||
2990 | || (sign_CIFS_PDUs > 1)) | ||
2991 | ses->server->secMode |= | ||
2992 | SECMODE_SIGN_REQUIRED; | ||
2993 | if ((SecurityBlob2->NegotiateFlags & | ||
2994 | cpu_to_le32(NTLMSSP_NEGOTIATE_SIGN)) && (sign_CIFS_PDUs)) | ||
2995 | ses->server->secMode |= | ||
2996 | SECMODE_SIGN_ENABLED; | ||
2997 | |||
2998 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { | ||
2999 | if ((long) (bcc_ptr) % 2) { | ||
3000 | remaining_words = | ||
3001 | (BCC(smb_buffer_response) | ||
3002 | - 1) / 2; | ||
3003 | /* Must word align unicode strings */ | ||
3004 | bcc_ptr++; | ||
3005 | } else { | ||
3006 | remaining_words = | ||
3007 | BCC | ||
3008 | (smb_buffer_response) / 2; | ||
3009 | } | ||
3010 | len = | ||
3011 | UniStrnlen((wchar_t *) bcc_ptr, | ||
3012 | remaining_words - 1); | ||
3013 | /* We look for obvious messed up bcc or strings in response so we do not go off | ||
3014 | the end since (at least) WIN2K and Windows XP have a major bug in not null | ||
3015 | terminating last Unicode string in response */ | ||
3016 | if (ses->serverOS) | ||
3017 | kfree(ses->serverOS); | ||
3018 | ses->serverOS = | ||
3019 | kzalloc(2 * (len + 1), GFP_KERNEL); | ||
3020 | cifs_strfromUCS_le(ses->serverOS, | ||
3021 | (__le16 *) | ||
3022 | bcc_ptr, len, | ||
3023 | nls_codepage); | ||
3024 | bcc_ptr += 2 * (len + 1); | ||
3025 | remaining_words -= len + 1; | ||
3026 | ses->serverOS[2 * len] = 0; | ||
3027 | ses->serverOS[1 + (2 * len)] = 0; | ||
3028 | if (remaining_words > 0) { | ||
3029 | len = UniStrnlen((wchar_t *) | ||
3030 | bcc_ptr, | ||
3031 | remaining_words | ||
3032 | - 1); | ||
3033 | kfree(ses->serverNOS); | ||
3034 | ses->serverNOS = | ||
3035 | kzalloc(2 * (len + 1), | ||
3036 | GFP_KERNEL); | ||
3037 | cifs_strfromUCS_le(ses-> | ||
3038 | serverNOS, | ||
3039 | (__le16 *) | ||
3040 | bcc_ptr, | ||
3041 | len, | ||
3042 | nls_codepage); | ||
3043 | bcc_ptr += 2 * (len + 1); | ||
3044 | ses->serverNOS[2 * len] = 0; | ||
3045 | ses->serverNOS[1 + | ||
3046 | (2 * len)] = 0; | ||
3047 | remaining_words -= len + 1; | ||
3048 | if (remaining_words > 0) { | ||
3049 | len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); | ||
3050 | /* last string not always null terminated | ||
3051 | (for e.g. for Windows XP & 2000) */ | ||
3052 | kfree(ses->serverDomain); | ||
3053 | ses->serverDomain = | ||
3054 | kzalloc(2 * | ||
3055 | (len + | ||
3056 | 1), | ||
3057 | GFP_KERNEL); | ||
3058 | cifs_strfromUCS_le | ||
3059 | (ses->serverDomain, | ||
3060 | (__le16 *)bcc_ptr, | ||
3061 | len, nls_codepage); | ||
3062 | bcc_ptr += | ||
3063 | 2 * (len + 1); | ||
3064 | ses->serverDomain[2*len] | ||
3065 | = 0; | ||
3066 | ses->serverDomain | ||
3067 | [1 + (2 * len)] | ||
3068 | = 0; | ||
3069 | } /* else no more room so create dummy domain string */ | ||
3070 | else { | ||
3071 | kfree(ses->serverDomain); | ||
3072 | ses->serverDomain = | ||
3073 | kzalloc(2, | ||
3074 | GFP_KERNEL); | ||
3075 | } | ||
3076 | } else { /* no room so create dummy domain and NOS string */ | ||
3077 | kfree(ses->serverDomain); | ||
3078 | ses->serverDomain = | ||
3079 | kzalloc(2, GFP_KERNEL); | ||
3080 | kfree(ses->serverNOS); | ||
3081 | ses->serverNOS = | ||
3082 | kzalloc(2, GFP_KERNEL); | ||
3083 | } | ||
3084 | } else { /* ASCII */ | ||
3085 | len = strnlen(bcc_ptr, 1024); | ||
3086 | if (((long) bcc_ptr + len) - (long) | ||
3087 | pByteArea(smb_buffer_response) | ||
3088 | <= BCC(smb_buffer_response)) { | ||
3089 | if (ses->serverOS) | ||
3090 | kfree(ses->serverOS); | ||
3091 | ses->serverOS = | ||
3092 | kzalloc(len + 1, | ||
3093 | GFP_KERNEL); | ||
3094 | strncpy(ses->serverOS, | ||
3095 | bcc_ptr, len); | ||
3096 | |||
3097 | bcc_ptr += len; | ||
3098 | bcc_ptr[0] = 0; /* null terminate string */ | ||
3099 | bcc_ptr++; | ||
3100 | |||
3101 | len = strnlen(bcc_ptr, 1024); | ||
3102 | kfree(ses->serverNOS); | ||
3103 | ses->serverNOS = | ||
3104 | kzalloc(len + 1, | ||
3105 | GFP_KERNEL); | ||
3106 | strncpy(ses->serverNOS, bcc_ptr, len); | ||
3107 | bcc_ptr += len; | ||
3108 | bcc_ptr[0] = 0; | ||
3109 | bcc_ptr++; | ||
3110 | |||
3111 | len = strnlen(bcc_ptr, 1024); | ||
3112 | kfree(ses->serverDomain); | ||
3113 | ses->serverDomain = | ||
3114 | kzalloc(len + 1, | ||
3115 | GFP_KERNEL); | ||
3116 | strncpy(ses->serverDomain, | ||
3117 | bcc_ptr, len); | ||
3118 | bcc_ptr += len; | ||
3119 | bcc_ptr[0] = 0; | ||
3120 | bcc_ptr++; | ||
3121 | } else | ||
3122 | cFYI(1, | ||
3123 | ("field of length %d " | ||
3124 | "extends beyond end of smb", | ||
3125 | len)); | ||
3126 | } | ||
3127 | } else { | ||
3128 | cERROR(1, ("Security Blob Length extends beyond" | ||
3129 | " end of SMB")); | ||
3130 | } | ||
3131 | } else { | ||
3132 | cERROR(1, ("No session structure passed in.")); | ||
3133 | } | 2582 | } |
3134 | } else { | 2583 | #else /* No DFS support, return error on mount */ |
3135 | cERROR(1, ("Invalid Word count %d:", | 2584 | rc = -EOPNOTSUPP; |
3136 | smb_buffer_response->WordCount)); | 2585 | #endif |
3137 | rc = -EIO; | ||
3138 | } | ||
3139 | |||
3140 | cifs_buf_release(smb_buffer); | ||
3141 | |||
3142 | return rc; | ||
3143 | } | ||
3144 | static int | ||
3145 | CIFSNTLMSSPAuthSessSetup(unsigned int xid, struct cifsSesInfo *ses, | ||
3146 | char *ntlm_session_key, bool ntlmv2_flag, | ||
3147 | const struct nls_table *nls_codepage) | ||
3148 | { | ||
3149 | struct smb_hdr *smb_buffer; | ||
3150 | struct smb_hdr *smb_buffer_response; | ||
3151 | SESSION_SETUP_ANDX *pSMB; | ||
3152 | SESSION_SETUP_ANDX *pSMBr; | ||
3153 | char *bcc_ptr; | ||
3154 | char *user; | ||
3155 | char *domain; | ||
3156 | int rc = 0; | ||
3157 | int remaining_words = 0; | ||
3158 | int bytes_returned = 0; | ||
3159 | int len; | ||
3160 | int SecurityBlobLength = sizeof(AUTHENTICATE_MESSAGE); | ||
3161 | PAUTHENTICATE_MESSAGE SecurityBlob; | ||
3162 | __u32 negotiate_flags, capabilities; | ||
3163 | __u16 count; | ||
3164 | |||
3165 | cFYI(1, ("In NTLMSSPSessSetup (Authenticate)")); | ||
3166 | if (ses == NULL) | ||
3167 | return -EINVAL; | ||
3168 | user = ses->userName; | ||
3169 | domain = ses->domainName; | ||
3170 | smb_buffer = cifs_buf_get(); | ||
3171 | if (smb_buffer == NULL) { | ||
3172 | return -ENOMEM; | ||
3173 | } | ||
3174 | smb_buffer_response = smb_buffer; | ||
3175 | pSMB = (SESSION_SETUP_ANDX *)smb_buffer; | ||
3176 | pSMBr = (SESSION_SETUP_ANDX *)smb_buffer_response; | ||
3177 | |||
3178 | /* send SMBsessionSetup here */ | ||
3179 | header_assemble(smb_buffer, SMB_COM_SESSION_SETUP_ANDX, | ||
3180 | NULL /* no tCon exists yet */ , 12 /* wct */ ); | ||
3181 | |||
3182 | smb_buffer->Mid = GetNextMid(ses->server); | ||
3183 | pSMB->req.hdr.Flags |= (SMBFLG_CASELESS | SMBFLG_CANONICAL_PATH_FORMAT); | ||
3184 | pSMB->req.hdr.Flags2 |= SMBFLG2_EXT_SEC; | ||
3185 | pSMB->req.AndXCommand = 0xFF; | ||
3186 | pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf); | ||
3187 | pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq); | ||
3188 | |||
3189 | pSMB->req.hdr.Uid = ses->Suid; | ||
3190 | |||
3191 | if (ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) | ||
3192 | smb_buffer->Flags2 |= SMBFLG2_SECURITY_SIGNATURE; | ||
3193 | |||
3194 | capabilities = CAP_LARGE_FILES | CAP_NT_SMBS | CAP_LEVEL_II_OPLOCKS | | ||
3195 | CAP_EXTENDED_SECURITY; | ||
3196 | if (ses->capabilities & CAP_UNICODE) { | ||
3197 | smb_buffer->Flags2 |= SMBFLG2_UNICODE; | ||
3198 | capabilities |= CAP_UNICODE; | ||
3199 | } | ||
3200 | if (ses->capabilities & CAP_STATUS32) { | ||
3201 | smb_buffer->Flags2 |= SMBFLG2_ERR_STATUS; | ||
3202 | capabilities |= CAP_STATUS32; | ||
3203 | } | 2586 | } |
3204 | if (ses->capabilities & CAP_DFS) { | ||
3205 | smb_buffer->Flags2 |= SMBFLG2_DFS; | ||
3206 | capabilities |= CAP_DFS; | ||
3207 | } | ||
3208 | pSMB->req.Capabilities = cpu_to_le32(capabilities); | ||
3209 | |||
3210 | bcc_ptr = (char *)&pSMB->req.SecurityBlob; | ||
3211 | SecurityBlob = (PAUTHENTICATE_MESSAGE)bcc_ptr; | ||
3212 | strncpy(SecurityBlob->Signature, NTLMSSP_SIGNATURE, 8); | ||
3213 | SecurityBlob->MessageType = NtLmAuthenticate; | ||
3214 | bcc_ptr += SecurityBlobLength; | ||
3215 | negotiate_flags = NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET | | ||
3216 | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_TARGET_INFO | | ||
3217 | 0x80000000 | NTLMSSP_NEGOTIATE_128; | ||
3218 | if (sign_CIFS_PDUs) | ||
3219 | negotiate_flags |= /* NTLMSSP_NEGOTIATE_ALWAYS_SIGN |*/ NTLMSSP_NEGOTIATE_SIGN; | ||
3220 | if (ntlmv2_flag) | ||
3221 | negotiate_flags |= NTLMSSP_NEGOTIATE_NTLMV2; | ||
3222 | |||
3223 | /* setup pointers to domain name and workstation name */ | ||
3224 | |||
3225 | SecurityBlob->WorkstationName.Buffer = 0; | ||
3226 | SecurityBlob->WorkstationName.Length = 0; | ||
3227 | SecurityBlob->WorkstationName.MaximumLength = 0; | ||
3228 | SecurityBlob->SessionKey.Length = 0; | ||
3229 | SecurityBlob->SessionKey.MaximumLength = 0; | ||
3230 | SecurityBlob->SessionKey.Buffer = 0; | ||
3231 | |||
3232 | SecurityBlob->LmChallengeResponse.Length = 0; | ||
3233 | SecurityBlob->LmChallengeResponse.MaximumLength = 0; | ||
3234 | SecurityBlob->LmChallengeResponse.Buffer = 0; | ||
3235 | |||
3236 | SecurityBlob->NtChallengeResponse.Length = | ||
3237 | cpu_to_le16(CIFS_SESS_KEY_SIZE); | ||
3238 | SecurityBlob->NtChallengeResponse.MaximumLength = | ||
3239 | cpu_to_le16(CIFS_SESS_KEY_SIZE); | ||
3240 | memcpy(bcc_ptr, ntlm_session_key, CIFS_SESS_KEY_SIZE); | ||
3241 | SecurityBlob->NtChallengeResponse.Buffer = | ||
3242 | cpu_to_le32(SecurityBlobLength); | ||
3243 | SecurityBlobLength += CIFS_SESS_KEY_SIZE; | ||
3244 | bcc_ptr += CIFS_SESS_KEY_SIZE; | ||
3245 | 2587 | ||
3246 | if (ses->capabilities & CAP_UNICODE) { | 2588 | mount_fail_check: |
3247 | if (domain == NULL) { | 2589 | /* on error free sesinfo and tcon struct if needed */ |
3248 | SecurityBlob->DomainName.Buffer = 0; | ||
3249 | SecurityBlob->DomainName.Length = 0; | ||
3250 | SecurityBlob->DomainName.MaximumLength = 0; | ||
3251 | } else { | ||
3252 | __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, domain, 64, | ||
3253 | nls_codepage); | ||
3254 | ln *= 2; | ||
3255 | SecurityBlob->DomainName.MaximumLength = | ||
3256 | cpu_to_le16(ln); | ||
3257 | SecurityBlob->DomainName.Buffer = | ||
3258 | cpu_to_le32(SecurityBlobLength); | ||
3259 | bcc_ptr += ln; | ||
3260 | SecurityBlobLength += ln; | ||
3261 | SecurityBlob->DomainName.Length = cpu_to_le16(ln); | ||
3262 | } | ||
3263 | if (user == NULL) { | ||
3264 | SecurityBlob->UserName.Buffer = 0; | ||
3265 | SecurityBlob->UserName.Length = 0; | ||
3266 | SecurityBlob->UserName.MaximumLength = 0; | ||
3267 | } else { | ||
3268 | __u16 ln = cifs_strtoUCS((__le16 *) bcc_ptr, user, 64, | ||
3269 | nls_codepage); | ||
3270 | ln *= 2; | ||
3271 | SecurityBlob->UserName.MaximumLength = | ||
3272 | cpu_to_le16(ln); | ||
3273 | SecurityBlob->UserName.Buffer = | ||
3274 | cpu_to_le32(SecurityBlobLength); | ||
3275 | bcc_ptr += ln; | ||
3276 | SecurityBlobLength += ln; | ||
3277 | SecurityBlob->UserName.Length = cpu_to_le16(ln); | ||
3278 | } | ||
3279 | |||
3280 | /* SecurityBlob->WorkstationName.Length = | ||
3281 | cifs_strtoUCS((__le16 *) bcc_ptr, "AMACHINE",64, nls_codepage); | ||
3282 | SecurityBlob->WorkstationName.Length *= 2; | ||
3283 | SecurityBlob->WorkstationName.MaximumLength = | ||
3284 | cpu_to_le16(SecurityBlob->WorkstationName.Length); | ||
3285 | SecurityBlob->WorkstationName.Buffer = | ||
3286 | cpu_to_le32(SecurityBlobLength); | ||
3287 | bcc_ptr += SecurityBlob->WorkstationName.Length; | ||
3288 | SecurityBlobLength += SecurityBlob->WorkstationName.Length; | ||
3289 | SecurityBlob->WorkstationName.Length = | ||
3290 | cpu_to_le16(SecurityBlob->WorkstationName.Length); */ | ||
3291 | |||
3292 | if ((long) bcc_ptr % 2) { | ||
3293 | *bcc_ptr = 0; | ||
3294 | bcc_ptr++; | ||
3295 | } | ||
3296 | bytes_returned = | ||
3297 | cifs_strtoUCS((__le16 *) bcc_ptr, "Linux version ", | ||
3298 | 32, nls_codepage); | ||
3299 | bcc_ptr += 2 * bytes_returned; | ||
3300 | bytes_returned = | ||
3301 | cifs_strtoUCS((__le16 *) bcc_ptr, utsname()->release, 32, | ||
3302 | nls_codepage); | ||
3303 | bcc_ptr += 2 * bytes_returned; | ||
3304 | bcc_ptr += 2; /* null term version string */ | ||
3305 | bytes_returned = | ||
3306 | cifs_strtoUCS((__le16 *) bcc_ptr, CIFS_NETWORK_OPSYS, | ||
3307 | 64, nls_codepage); | ||
3308 | bcc_ptr += 2 * bytes_returned; | ||
3309 | *(bcc_ptr + 1) = 0; | ||
3310 | *(bcc_ptr + 2) = 0; | ||
3311 | bcc_ptr += 2; /* null terminate network opsys string */ | ||
3312 | *(bcc_ptr + 1) = 0; | ||
3313 | *(bcc_ptr + 2) = 0; | ||
3314 | bcc_ptr += 2; /* null domain */ | ||
3315 | } else { /* ASCII */ | ||
3316 | if (domain == NULL) { | ||
3317 | SecurityBlob->DomainName.Buffer = 0; | ||
3318 | SecurityBlob->DomainName.Length = 0; | ||
3319 | SecurityBlob->DomainName.MaximumLength = 0; | ||
3320 | } else { | ||
3321 | __u16 ln; | ||
3322 | negotiate_flags |= NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED; | ||
3323 | strncpy(bcc_ptr, domain, 63); | ||
3324 | ln = strnlen(domain, 64); | ||
3325 | SecurityBlob->DomainName.MaximumLength = | ||
3326 | cpu_to_le16(ln); | ||
3327 | SecurityBlob->DomainName.Buffer = | ||
3328 | cpu_to_le32(SecurityBlobLength); | ||
3329 | bcc_ptr += ln; | ||
3330 | SecurityBlobLength += ln; | ||
3331 | SecurityBlob->DomainName.Length = cpu_to_le16(ln); | ||
3332 | } | ||
3333 | if (user == NULL) { | ||
3334 | SecurityBlob->UserName.Buffer = 0; | ||
3335 | SecurityBlob->UserName.Length = 0; | ||
3336 | SecurityBlob->UserName.MaximumLength = 0; | ||
3337 | } else { | ||
3338 | __u16 ln; | ||
3339 | strncpy(bcc_ptr, user, 63); | ||
3340 | ln = strnlen(user, 64); | ||
3341 | SecurityBlob->UserName.MaximumLength = cpu_to_le16(ln); | ||
3342 | SecurityBlob->UserName.Buffer = | ||
3343 | cpu_to_le32(SecurityBlobLength); | ||
3344 | bcc_ptr += ln; | ||
3345 | SecurityBlobLength += ln; | ||
3346 | SecurityBlob->UserName.Length = cpu_to_le16(ln); | ||
3347 | } | ||
3348 | /* BB fill in our workstation name if known BB */ | ||
3349 | |||
3350 | strcpy(bcc_ptr, "Linux version "); | ||
3351 | bcc_ptr += strlen("Linux version "); | ||
3352 | strcpy(bcc_ptr, utsname()->release); | ||
3353 | bcc_ptr += strlen(utsname()->release) + 1; | ||
3354 | strcpy(bcc_ptr, CIFS_NETWORK_OPSYS); | ||
3355 | bcc_ptr += strlen(CIFS_NETWORK_OPSYS) + 1; | ||
3356 | bcc_ptr++; /* null domain */ | ||
3357 | *bcc_ptr = 0; | ||
3358 | } | ||
3359 | SecurityBlob->NegotiateFlags = cpu_to_le32(negotiate_flags); | ||
3360 | pSMB->req.SecurityBlobLength = cpu_to_le16(SecurityBlobLength); | ||
3361 | count = (long) bcc_ptr - (long) pByteArea(smb_buffer); | ||
3362 | smb_buffer->smb_buf_length += count; | ||
3363 | pSMB->req.ByteCount = cpu_to_le16(count); | ||
3364 | |||
3365 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, | ||
3366 | &bytes_returned, CIFS_LONG_OP); | ||
3367 | if (rc) { | 2590 | if (rc) { |
3368 | /* rc = map_smb_to_linux_error(smb_buffer_response) done in SendReceive now */ | 2591 | if (mount_data != mount_data_global) |
3369 | } else if ((smb_buffer_response->WordCount == 3) || | 2592 | kfree(mount_data); |
3370 | (smb_buffer_response->WordCount == 4)) { | 2593 | /* If find_unc succeeded then rc == 0 so we can not end */ |
3371 | __u16 action = le16_to_cpu(pSMBr->resp.Action); | 2594 | /* up accidently freeing someone elses tcon struct */ |
3372 | __u16 blob_len = le16_to_cpu(pSMBr->resp.SecurityBlobLength); | 2595 | if (tcon) |
3373 | if (action & GUEST_LOGIN) | 2596 | cifs_put_tcon(tcon); |
3374 | cFYI(1, ("Guest login")); /* BB Should we set anything | 2597 | else if (pSesInfo) |
3375 | in SesInfo struct ? */ | 2598 | cifs_put_smb_ses(pSesInfo); |
3376 | /* if (SecurityBlob2->MessageType != NtLm??) { | 2599 | else |
3377 | cFYI("Unexpected message type on auth response is %d")); | 2600 | cifs_put_tcp_session(srvTcp); |
3378 | } */ | 2601 | goto out; |
3379 | |||
3380 | if (ses) { | ||
3381 | cFYI(1, | ||
3382 | ("Check challenge UID %d vs auth response UID %d", | ||
3383 | ses->Suid, smb_buffer_response->Uid)); | ||
3384 | /* UID left in wire format */ | ||
3385 | ses->Suid = smb_buffer_response->Uid; | ||
3386 | bcc_ptr = pByteArea(smb_buffer_response); | ||
3387 | /* response can have either 3 or 4 word count - Samba sends 3 */ | ||
3388 | if ((pSMBr->resp.hdr.WordCount == 3) | ||
3389 | || ((pSMBr->resp.hdr.WordCount == 4) | ||
3390 | && (blob_len < | ||
3391 | pSMBr->resp.ByteCount))) { | ||
3392 | if (pSMBr->resp.hdr.WordCount == 4) { | ||
3393 | bcc_ptr += | ||
3394 | blob_len; | ||
3395 | cFYI(1, | ||
3396 | ("Security Blob Length %d ", | ||
3397 | blob_len)); | ||
3398 | } | ||
3399 | |||
3400 | cFYI(1, | ||
3401 | ("NTLMSSP response to Authenticate ")); | ||
3402 | |||
3403 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { | ||
3404 | if ((long) (bcc_ptr) % 2) { | ||
3405 | remaining_words = | ||
3406 | (BCC(smb_buffer_response) | ||
3407 | - 1) / 2; | ||
3408 | bcc_ptr++; /* Unicode strings must be word aligned */ | ||
3409 | } else { | ||
3410 | remaining_words = BCC(smb_buffer_response) / 2; | ||
3411 | } | ||
3412 | len = UniStrnlen((wchar_t *) bcc_ptr, | ||
3413 | remaining_words - 1); | ||
3414 | /* We look for obvious messed up bcc or strings in response so we do not go off | ||
3415 | the end since (at least) WIN2K and Windows XP have a major bug in not null | ||
3416 | terminating last Unicode string in response */ | ||
3417 | if (ses->serverOS) | ||
3418 | kfree(ses->serverOS); | ||
3419 | ses->serverOS = | ||
3420 | kzalloc(2 * (len + 1), GFP_KERNEL); | ||
3421 | cifs_strfromUCS_le(ses->serverOS, | ||
3422 | (__le16 *) | ||
3423 | bcc_ptr, len, | ||
3424 | nls_codepage); | ||
3425 | bcc_ptr += 2 * (len + 1); | ||
3426 | remaining_words -= len + 1; | ||
3427 | ses->serverOS[2 * len] = 0; | ||
3428 | ses->serverOS[1 + (2 * len)] = 0; | ||
3429 | if (remaining_words > 0) { | ||
3430 | len = UniStrnlen((wchar_t *) | ||
3431 | bcc_ptr, | ||
3432 | remaining_words | ||
3433 | - 1); | ||
3434 | kfree(ses->serverNOS); | ||
3435 | ses->serverNOS = | ||
3436 | kzalloc(2 * (len + 1), | ||
3437 | GFP_KERNEL); | ||
3438 | cifs_strfromUCS_le(ses-> | ||
3439 | serverNOS, | ||
3440 | (__le16 *) | ||
3441 | bcc_ptr, | ||
3442 | len, | ||
3443 | nls_codepage); | ||
3444 | bcc_ptr += 2 * (len + 1); | ||
3445 | ses->serverNOS[2 * len] = 0; | ||
3446 | ses->serverNOS[1+(2*len)] = 0; | ||
3447 | remaining_words -= len + 1; | ||
3448 | if (remaining_words > 0) { | ||
3449 | len = UniStrnlen((wchar_t *) bcc_ptr, remaining_words); | ||
3450 | /* last string not always null terminated (e.g. for Windows XP & 2000) */ | ||
3451 | if (ses->serverDomain) | ||
3452 | kfree(ses->serverDomain); | ||
3453 | ses->serverDomain = | ||
3454 | kzalloc(2 * | ||
3455 | (len + | ||
3456 | 1), | ||
3457 | GFP_KERNEL); | ||
3458 | cifs_strfromUCS_le | ||
3459 | (ses-> | ||
3460 | serverDomain, | ||
3461 | (__le16 *) | ||
3462 | bcc_ptr, len, | ||
3463 | nls_codepage); | ||
3464 | bcc_ptr += | ||
3465 | 2 * (len + 1); | ||
3466 | ses-> | ||
3467 | serverDomain[2 | ||
3468 | * len] | ||
3469 | = 0; | ||
3470 | ses-> | ||
3471 | serverDomain[1 | ||
3472 | + | ||
3473 | (2 | ||
3474 | * | ||
3475 | len)] | ||
3476 | = 0; | ||
3477 | } /* else no more room so create dummy domain string */ | ||
3478 | else { | ||
3479 | if (ses->serverDomain) | ||
3480 | kfree(ses->serverDomain); | ||
3481 | ses->serverDomain = kzalloc(2,GFP_KERNEL); | ||
3482 | } | ||
3483 | } else { /* no room so create dummy domain and NOS string */ | ||
3484 | if (ses->serverDomain) | ||
3485 | kfree(ses->serverDomain); | ||
3486 | ses->serverDomain = kzalloc(2, GFP_KERNEL); | ||
3487 | kfree(ses->serverNOS); | ||
3488 | ses->serverNOS = kzalloc(2, GFP_KERNEL); | ||
3489 | } | ||
3490 | } else { /* ASCII */ | ||
3491 | len = strnlen(bcc_ptr, 1024); | ||
3492 | if (((long) bcc_ptr + len) - | ||
3493 | (long) pByteArea(smb_buffer_response) | ||
3494 | <= BCC(smb_buffer_response)) { | ||
3495 | if (ses->serverOS) | ||
3496 | kfree(ses->serverOS); | ||
3497 | ses->serverOS = kzalloc(len + 1, GFP_KERNEL); | ||
3498 | strncpy(ses->serverOS,bcc_ptr, len); | ||
3499 | |||
3500 | bcc_ptr += len; | ||
3501 | bcc_ptr[0] = 0; /* null terminate the string */ | ||
3502 | bcc_ptr++; | ||
3503 | |||
3504 | len = strnlen(bcc_ptr, 1024); | ||
3505 | kfree(ses->serverNOS); | ||
3506 | ses->serverNOS = kzalloc(len+1, | ||
3507 | GFP_KERNEL); | ||
3508 | strncpy(ses->serverNOS, | ||
3509 | bcc_ptr, len); | ||
3510 | bcc_ptr += len; | ||
3511 | bcc_ptr[0] = 0; | ||
3512 | bcc_ptr++; | ||
3513 | |||
3514 | len = strnlen(bcc_ptr, 1024); | ||
3515 | if (ses->serverDomain) | ||
3516 | kfree(ses->serverDomain); | ||
3517 | ses->serverDomain = | ||
3518 | kzalloc(len+1, | ||
3519 | GFP_KERNEL); | ||
3520 | strncpy(ses->serverDomain, | ||
3521 | bcc_ptr, len); | ||
3522 | bcc_ptr += len; | ||
3523 | bcc_ptr[0] = 0; | ||
3524 | bcc_ptr++; | ||
3525 | } else | ||
3526 | cFYI(1, ("field of length %d " | ||
3527 | "extends beyond end of smb ", | ||
3528 | len)); | ||
3529 | } | ||
3530 | } else { | ||
3531 | cERROR(1, ("Security Blob extends beyond end " | ||
3532 | "of SMB")); | ||
3533 | } | ||
3534 | } else { | ||
3535 | cERROR(1, ("No session structure passed in.")); | ||
3536 | } | ||
3537 | } else { | ||
3538 | cERROR(1, ("Invalid Word count %d: ", | ||
3539 | smb_buffer_response->WordCount)); | ||
3540 | rc = -EIO; | ||
3541 | } | 2602 | } |
3542 | 2603 | ||
3543 | cifs_buf_release(smb_buffer); | 2604 | /* volume_info->password is freed above when existing session found |
3544 | 2605 | (in which case it is not needed anymore) but when new sesion is created | |
2606 | the password ptr is put in the new session structure (in which case the | ||
2607 | password will be freed at unmount time) */ | ||
2608 | out: | ||
2609 | /* zero out password before freeing */ | ||
2610 | cleanup_volume_info(&volume_info); | ||
2611 | FreeXid(xid); | ||
3545 | return rc; | 2612 | return rc; |
3546 | } | 2613 | } |
3547 | 2614 | ||
@@ -3556,7 +2623,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
3556 | TCONX_RSP *pSMBr; | 2623 | TCONX_RSP *pSMBr; |
3557 | unsigned char *bcc_ptr; | 2624 | unsigned char *bcc_ptr; |
3558 | int rc = 0; | 2625 | int rc = 0; |
3559 | int length; | 2626 | int length, bytes_left; |
3560 | __u16 count; | 2627 | __u16 count; |
3561 | 2628 | ||
3562 | if (ses == NULL) | 2629 | if (ses == NULL) |
@@ -3644,14 +2711,22 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
3644 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, | 2711 | rc = SendReceive(xid, ses, smb_buffer, smb_buffer_response, &length, |
3645 | CIFS_STD_OP); | 2712 | CIFS_STD_OP); |
3646 | 2713 | ||
3647 | /* if (rc) rc = map_smb_to_linux_error(smb_buffer_response); */ | ||
3648 | /* above now done in SendReceive */ | 2714 | /* above now done in SendReceive */ |
3649 | if ((rc == 0) && (tcon != NULL)) { | 2715 | if ((rc == 0) && (tcon != NULL)) { |
2716 | bool is_unicode; | ||
2717 | |||
3650 | tcon->tidStatus = CifsGood; | 2718 | tcon->tidStatus = CifsGood; |
3651 | tcon->need_reconnect = false; | 2719 | tcon->need_reconnect = false; |
3652 | tcon->tid = smb_buffer_response->Tid; | 2720 | tcon->tid = smb_buffer_response->Tid; |
3653 | bcc_ptr = pByteArea(smb_buffer_response); | 2721 | bcc_ptr = pByteArea(smb_buffer_response); |
3654 | length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2); | 2722 | bytes_left = BCC(smb_buffer_response); |
2723 | length = strnlen(bcc_ptr, bytes_left - 2); | ||
2724 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) | ||
2725 | is_unicode = true; | ||
2726 | else | ||
2727 | is_unicode = false; | ||
2728 | |||
2729 | |||
3655 | /* skip service field (NB: this field is always ASCII) */ | 2730 | /* skip service field (NB: this field is always ASCII) */ |
3656 | if (length == 3) { | 2731 | if (length == 3) { |
3657 | if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') && | 2732 | if ((bcc_ptr[0] == 'I') && (bcc_ptr[1] == 'P') && |
@@ -3666,40 +2741,16 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
3666 | } | 2741 | } |
3667 | } | 2742 | } |
3668 | bcc_ptr += length + 1; | 2743 | bcc_ptr += length + 1; |
2744 | bytes_left -= (length + 1); | ||
3669 | strncpy(tcon->treeName, tree, MAX_TREE_SIZE); | 2745 | strncpy(tcon->treeName, tree, MAX_TREE_SIZE); |
3670 | if (smb_buffer->Flags2 & SMBFLG2_UNICODE) { | 2746 | |
3671 | length = UniStrnlen((wchar_t *) bcc_ptr, 512); | 2747 | /* mostly informational -- no need to fail on error here */ |
3672 | if ((bcc_ptr + (2 * length)) - | 2748 | tcon->nativeFileSystem = cifs_strndup_from_ucs(bcc_ptr, |
3673 | pByteArea(smb_buffer_response) <= | 2749 | bytes_left, is_unicode, |
3674 | BCC(smb_buffer_response)) { | 2750 | nls_codepage); |
3675 | kfree(tcon->nativeFileSystem); | 2751 | |
3676 | tcon->nativeFileSystem = | 2752 | cFYI(1, ("nativeFileSystem=%s", tcon->nativeFileSystem)); |
3677 | kzalloc(2*(length + 1), GFP_KERNEL); | 2753 | |
3678 | if (tcon->nativeFileSystem) | ||
3679 | cifs_strfromUCS_le( | ||
3680 | tcon->nativeFileSystem, | ||
3681 | (__le16 *) bcc_ptr, | ||
3682 | length, nls_codepage); | ||
3683 | bcc_ptr += 2 * length; | ||
3684 | bcc_ptr[0] = 0; /* null terminate the string */ | ||
3685 | bcc_ptr[1] = 0; | ||
3686 | bcc_ptr += 2; | ||
3687 | } | ||
3688 | /* else do not bother copying these information fields*/ | ||
3689 | } else { | ||
3690 | length = strnlen(bcc_ptr, 1024); | ||
3691 | if ((bcc_ptr + length) - | ||
3692 | pByteArea(smb_buffer_response) <= | ||
3693 | BCC(smb_buffer_response)) { | ||
3694 | kfree(tcon->nativeFileSystem); | ||
3695 | tcon->nativeFileSystem = | ||
3696 | kzalloc(length + 1, GFP_KERNEL); | ||
3697 | if (tcon->nativeFileSystem) | ||
3698 | strncpy(tcon->nativeFileSystem, bcc_ptr, | ||
3699 | length); | ||
3700 | } | ||
3701 | /* else do not bother copying these information fields*/ | ||
3702 | } | ||
3703 | if ((smb_buffer_response->WordCount == 3) || | 2754 | if ((smb_buffer_response->WordCount == 3) || |
3704 | (smb_buffer_response->WordCount == 7)) | 2755 | (smb_buffer_response->WordCount == 7)) |
3705 | /* field is in same location */ | 2756 | /* field is in same location */ |
@@ -3738,8 +2789,6 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, | |||
3738 | struct nls_table *nls_info) | 2789 | struct nls_table *nls_info) |
3739 | { | 2790 | { |
3740 | int rc = 0; | 2791 | int rc = 0; |
3741 | char ntlm_session_key[CIFS_SESS_KEY_SIZE]; | ||
3742 | bool ntlmv2_flag = false; | ||
3743 | int first_time = 0; | 2792 | int first_time = 0; |
3744 | struct TCP_Server_Info *server = pSesInfo->server; | 2793 | struct TCP_Server_Info *server = pSesInfo->server; |
3745 | 2794 | ||
@@ -3771,83 +2820,19 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, | |||
3771 | pSesInfo->capabilities = server->capabilities; | 2820 | pSesInfo->capabilities = server->capabilities; |
3772 | if (linuxExtEnabled == 0) | 2821 | if (linuxExtEnabled == 0) |
3773 | pSesInfo->capabilities &= (~CAP_UNIX); | 2822 | pSesInfo->capabilities &= (~CAP_UNIX); |
3774 | /* pSesInfo->sequence_number = 0;*/ | 2823 | |
3775 | cFYI(1, ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d", | 2824 | cFYI(1, ("Security Mode: 0x%x Capabilities: 0x%x TimeAdjust: %d", |
3776 | server->secMode, server->capabilities, server->timeAdj)); | 2825 | server->secMode, server->capabilities, server->timeAdj)); |
3777 | 2826 | ||
3778 | if (experimEnabled < 2) | 2827 | rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info); |
3779 | rc = CIFS_SessSetup(xid, pSesInfo, first_time, nls_info); | ||
3780 | else if (extended_security | ||
3781 | && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) | ||
3782 | && (server->secType == NTLMSSP)) { | ||
3783 | rc = -EOPNOTSUPP; | ||
3784 | } else if (extended_security | ||
3785 | && (pSesInfo->capabilities & CAP_EXTENDED_SECURITY) | ||
3786 | && (server->secType == RawNTLMSSP)) { | ||
3787 | cFYI(1, ("NTLMSSP sesssetup")); | ||
3788 | rc = CIFSNTLMSSPNegotiateSessSetup(xid, pSesInfo, &ntlmv2_flag, | ||
3789 | nls_info); | ||
3790 | if (!rc) { | ||
3791 | if (ntlmv2_flag) { | ||
3792 | char *v2_response; | ||
3793 | cFYI(1, ("more secure NTLM ver2 hash")); | ||
3794 | if (CalcNTLMv2_partial_mac_key(pSesInfo, | ||
3795 | nls_info)) { | ||
3796 | rc = -ENOMEM; | ||
3797 | goto ss_err_exit; | ||
3798 | } else | ||
3799 | v2_response = kmalloc(16 + 64 /* blob*/, | ||
3800 | GFP_KERNEL); | ||
3801 | if (v2_response) { | ||
3802 | CalcNTLMv2_response(pSesInfo, | ||
3803 | v2_response); | ||
3804 | /* if (first_time) | ||
3805 | cifs_calculate_ntlmv2_mac_key */ | ||
3806 | kfree(v2_response); | ||
3807 | /* BB Put dummy sig in SessSetup PDU? */ | ||
3808 | } else { | ||
3809 | rc = -ENOMEM; | ||
3810 | goto ss_err_exit; | ||
3811 | } | ||
3812 | |||
3813 | } else { | ||
3814 | SMBNTencrypt(pSesInfo->password, | ||
3815 | server->cryptKey, | ||
3816 | ntlm_session_key); | ||
3817 | |||
3818 | if (first_time) | ||
3819 | cifs_calculate_mac_key( | ||
3820 | &server->mac_signing_key, | ||
3821 | ntlm_session_key, | ||
3822 | pSesInfo->password); | ||
3823 | } | ||
3824 | /* for better security the weaker lanman hash not sent | ||
3825 | in AuthSessSetup so we no longer calculate it */ | ||
3826 | |||
3827 | rc = CIFSNTLMSSPAuthSessSetup(xid, pSesInfo, | ||
3828 | ntlm_session_key, | ||
3829 | ntlmv2_flag, | ||
3830 | nls_info); | ||
3831 | } | ||
3832 | } else { /* old style NTLM 0.12 session setup */ | ||
3833 | SMBNTencrypt(pSesInfo->password, server->cryptKey, | ||
3834 | ntlm_session_key); | ||
3835 | |||
3836 | if (first_time) | ||
3837 | cifs_calculate_mac_key(&server->mac_signing_key, | ||
3838 | ntlm_session_key, | ||
3839 | pSesInfo->password); | ||
3840 | |||
3841 | rc = CIFSSessSetup(xid, pSesInfo, ntlm_session_key, nls_info); | ||
3842 | } | ||
3843 | if (rc) { | 2828 | if (rc) { |
3844 | cERROR(1, ("Send error in SessSetup = %d", rc)); | 2829 | cERROR(1, ("Send error in SessSetup = %d", rc)); |
3845 | } else { | 2830 | } else { |
3846 | cFYI(1, ("CIFS Session Established successfully")); | 2831 | cFYI(1, ("CIFS Session Established successfully")); |
3847 | spin_lock(&GlobalMid_Lock); | 2832 | spin_lock(&GlobalMid_Lock); |
3848 | pSesInfo->status = CifsGood; | 2833 | pSesInfo->status = CifsGood; |
3849 | pSesInfo->need_reconnect = false; | 2834 | pSesInfo->need_reconnect = false; |
3850 | spin_unlock(&GlobalMid_Lock); | 2835 | spin_unlock(&GlobalMid_Lock); |
3851 | } | 2836 | } |
3852 | 2837 | ||
3853 | ss_err_exit: | 2838 | ss_err_exit: |