diff options
| -rw-r--r-- | fs/cifs/connect.c | 152 |
1 files changed, 120 insertions, 32 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index b173b0171712..2e7a4ea26ab9 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
| @@ -2214,9 +2214,56 @@ is_path_accessible(int xid, struct cifsTconInfo *tcon, | |||
| 2214 | return rc; | 2214 | return rc; |
| 2215 | } | 2215 | } |
| 2216 | 2216 | ||
| 2217 | static void | ||
| 2218 | cleanup_volume_info(struct smb_vol **pvolume_info) | ||
| 2219 | { | ||
| 2220 | struct smb_vol *volume_info; | ||
| 2221 | |||
| 2222 | if (!pvolume_info && !*pvolume_info) | ||
| 2223 | return; | ||
| 2224 | |||
| 2225 | volume_info = *pvolume_info; | ||
| 2226 | kzfree(volume_info->password); | ||
| 2227 | kfree(volume_info->UNC); | ||
| 2228 | kfree(volume_info->prepath); | ||
| 2229 | kfree(volume_info); | ||
| 2230 | *pvolume_info = NULL; | ||
| 2231 | return; | ||
| 2232 | } | ||
| 2233 | |||
| 2234 | /* build_path_to_root returns full path to root when | ||
| 2235 | * we do not have an exiting connection (tcon) */ | ||
| 2236 | static char * | ||
| 2237 | build_unc_path_to_root(const struct smb_vol *volume_info, | ||
| 2238 | const struct cifs_sb_info *cifs_sb) | ||
| 2239 | { | ||
| 2240 | char *full_path; | ||
| 2241 | |||
| 2242 | int unc_len = strnlen(volume_info->UNC, MAX_TREE_SIZE + 1); | ||
| 2243 | full_path = kmalloc(unc_len + cifs_sb->prepathlen + 1, GFP_KERNEL); | ||
| 2244 | if (full_path == NULL) | ||
| 2245 | return ERR_PTR(-ENOMEM); | ||
| 2246 | |||
| 2247 | strncpy(full_path, volume_info->UNC, unc_len); | ||
| 2248 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) { | ||
| 2249 | int i; | ||
| 2250 | for (i = 0; i < unc_len; i++) { | ||
| 2251 | if (full_path[i] == '\\') | ||
| 2252 | full_path[i] = '/'; | ||
| 2253 | } | ||
| 2254 | } | ||
| 2255 | |||
| 2256 | if (cifs_sb->prepathlen) | ||
| 2257 | strncpy(full_path + unc_len, cifs_sb->prepath, | ||
| 2258 | cifs_sb->prepathlen); | ||
| 2259 | |||
| 2260 | full_path[unc_len + cifs_sb->prepathlen] = 0; /* add trailing null */ | ||
| 2261 | return full_path; | ||
| 2262 | } | ||
| 2263 | |||
| 2217 | int | 2264 | int |
| 2218 | cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | 2265 | cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, |
| 2219 | char *mount_data, const char *devname) | 2266 | char *mount_data_global, const char *devname) |
| 2220 | { | 2267 | { |
| 2221 | int rc = 0; | 2268 | int rc = 0; |
| 2222 | int xid; | 2269 | int xid; |
| @@ -2225,6 +2272,13 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 2225 | struct cifsTconInfo *tcon = NULL; | 2272 | struct cifsTconInfo *tcon = NULL; |
| 2226 | struct TCP_Server_Info *srvTcp = NULL; | 2273 | struct TCP_Server_Info *srvTcp = NULL; |
| 2227 | char *full_path; | 2274 | char *full_path; |
| 2275 | struct dfs_info3_param *referrals = NULL; | ||
| 2276 | unsigned int num_referrals = 0; | ||
| 2277 | |||
| 2278 | char *mount_data = mount_data_global; | ||
| 2279 | |||
| 2280 | try_mount_again: | ||
| 2281 | full_path = NULL; | ||
| 2228 | 2282 | ||
| 2229 | xid = GetXid(); | 2283 | xid = GetXid(); |
| 2230 | 2284 | ||
| @@ -2371,11 +2425,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 2371 | } | 2425 | } |
| 2372 | } | 2426 | } |
| 2373 | 2427 | ||
| 2374 | /* check for null share name ie connect to dfs root */ | ||
| 2375 | if ((strchr(volume_info->UNC + 3, '\\') == NULL) | 2428 | if ((strchr(volume_info->UNC + 3, '\\') == NULL) |
| 2376 | && (strchr(volume_info->UNC + 3, '/') == NULL)) { | 2429 | && (strchr(volume_info->UNC + 3, '/') == NULL)) { |
| 2377 | /* rc = connect_to_dfs_path(...) */ | 2430 | cERROR(1, ("Missing share name")); |
| 2378 | cFYI(1, ("DFS root not supported")); | ||
| 2379 | rc = -ENODEV; | 2431 | rc = -ENODEV; |
| 2380 | goto mount_fail_check; | 2432 | goto mount_fail_check; |
| 2381 | } else { | 2433 | } else { |
| @@ -2392,7 +2444,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 2392 | } | 2444 | } |
| 2393 | } | 2445 | } |
| 2394 | if (rc) | 2446 | if (rc) |
| 2395 | goto mount_fail_check; | 2447 | goto remote_path_check; |
| 2396 | tcon->seal = volume_info->seal; | 2448 | tcon->seal = volume_info->seal; |
| 2397 | write_lock(&cifs_tcp_ses_lock); | 2449 | write_lock(&cifs_tcp_ses_lock); |
| 2398 | list_add(&tcon->tcon_list, &pSesInfo->tcon_list); | 2450 | list_add(&tcon->tcon_list, &pSesInfo->tcon_list); |
| @@ -2417,19 +2469,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 */ | 2469 | /* BB FIXME fix time_gran to be larger for LANMAN sessions */ |
| 2418 | sb->s_time_gran = 100; | 2470 | sb->s_time_gran = 100; |
| 2419 | 2471 | ||
| 2420 | mount_fail_check: | 2472 | if (rc) |
| 2421 | /* on error free sesinfo and tcon struct if needed */ | 2473 | goto remote_path_check; |
| 2422 | if (rc) { | 2474 | |
| 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; | 2475 | cifs_sb->tcon = tcon; |
| 2434 | 2476 | ||
| 2435 | /* do not care if following two calls succeed - informational */ | 2477 | /* do not care if following two calls succeed - informational */ |
| @@ -2461,7 +2503,9 @@ mount_fail_check: | |||
| 2461 | cifs_sb->rsize = min(cifs_sb->rsize, | 2503 | cifs_sb->rsize = min(cifs_sb->rsize, |
| 2462 | (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)); | 2504 | (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)); |
| 2463 | 2505 | ||
| 2464 | if (!rc && cifs_sb->prepathlen) { | 2506 | remote_path_check: |
| 2507 | /* check if a whole path (including prepath) is not remote */ | ||
| 2508 | if (!rc && cifs_sb->prepathlen && tcon) { | ||
| 2465 | /* build_path_to_root works only when we have a valid tcon */ | 2509 | /* build_path_to_root works only when we have a valid tcon */ |
| 2466 | full_path = cifs_build_path_to_root(cifs_sb); | 2510 | full_path = cifs_build_path_to_root(cifs_sb); |
| 2467 | if (full_path == NULL) { | 2511 | if (full_path == NULL) { |
| @@ -2469,31 +2513,75 @@ mount_fail_check: | |||
| 2469 | goto mount_fail_check; | 2513 | goto mount_fail_check; |
| 2470 | } | 2514 | } |
| 2471 | rc = is_path_accessible(xid, tcon, cifs_sb, full_path); | 2515 | rc = is_path_accessible(xid, tcon, cifs_sb, full_path); |
| 2472 | if (rc) { | 2516 | if (rc != -EREMOTE) { |
| 2473 | cERROR(1, ("Path %s in not accessible: %d", | ||
| 2474 | full_path, rc)); | ||
| 2475 | kfree(full_path); | 2517 | kfree(full_path); |
| 2476 | goto mount_fail_check; | 2518 | goto mount_fail_check; |
| 2477 | } | 2519 | } |
| 2478 | kfree(full_path); | 2520 | kfree(full_path); |
| 2479 | } | 2521 | } |
| 2480 | 2522 | ||
| 2523 | /* get referral if needed */ | ||
| 2524 | if (rc == -EREMOTE) { | ||
| 2525 | /* convert forward to back slashes in prepath here if needed */ | ||
| 2526 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0) | ||
| 2527 | convert_delimiter(cifs_sb->prepath, | ||
| 2528 | CIFS_DIR_SEP(cifs_sb)); | ||
| 2529 | full_path = build_unc_path_to_root(volume_info, cifs_sb); | ||
| 2530 | if (IS_ERR(full_path)) { | ||
| 2531 | rc = PTR_ERR(full_path); | ||
| 2532 | goto mount_fail_check; | ||
| 2533 | } | ||
| 2534 | |||
| 2535 | cFYI(1, ("Getting referral for: %s", full_path)); | ||
| 2536 | rc = get_dfs_path(xid, pSesInfo , full_path + 1, | ||
| 2537 | cifs_sb->local_nls, &num_referrals, &referrals, | ||
| 2538 | cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR); | ||
| 2539 | if (!rc && num_referrals > 0) { | ||
| 2540 | char *fake_devname = NULL; | ||
| 2541 | |||
| 2542 | if (mount_data != mount_data_global) | ||
| 2543 | kfree(mount_data); | ||
| 2544 | mount_data = cifs_compose_mount_options( | ||
| 2545 | cifs_sb->mountdata, full_path + 1, | ||
| 2546 | referrals, &fake_devname); | ||
| 2547 | kfree(fake_devname); | ||
| 2548 | free_dfs_info_array(referrals, num_referrals); | ||
| 2549 | |||
| 2550 | if (tcon) | ||
| 2551 | cifs_put_tcon(tcon); | ||
| 2552 | else if (pSesInfo) | ||
| 2553 | cifs_put_smb_ses(pSesInfo); | ||
| 2554 | |||
| 2555 | cleanup_volume_info(&volume_info); | ||
| 2556 | FreeXid(xid); | ||
| 2557 | kfree(full_path); | ||
| 2558 | goto try_mount_again; | ||
| 2559 | } | ||
| 2560 | } | ||
| 2561 | |||
| 2562 | mount_fail_check: | ||
| 2563 | /* on error free sesinfo and tcon struct if needed */ | ||
| 2564 | if (rc) { | ||
| 2565 | if (mount_data != mount_data_global) | ||
| 2566 | kfree(mount_data); | ||
| 2567 | /* If find_unc succeeded then rc == 0 so we can not end */ | ||
| 2568 | /* up accidently freeing someone elses tcon struct */ | ||
| 2569 | if (tcon) | ||
| 2570 | cifs_put_tcon(tcon); | ||
| 2571 | else if (pSesInfo) | ||
| 2572 | cifs_put_smb_ses(pSesInfo); | ||
| 2573 | else | ||
| 2574 | cifs_put_tcp_session(srvTcp); | ||
| 2575 | goto out; | ||
| 2576 | } | ||
| 2577 | |||
| 2481 | /* volume_info->password is freed above when existing session found | 2578 | /* volume_info->password is freed above when existing session found |
| 2482 | (in which case it is not needed anymore) but when new sesion is created | 2579 | (in which case it is not needed anymore) but when new sesion is created |
| 2483 | the password ptr is put in the new session structure (in which case the | 2580 | the password ptr is put in the new session structure (in which case the |
| 2484 | password will be freed at unmount time) */ | 2581 | password will be freed at unmount time) */ |
| 2485 | out: | 2582 | out: |
| 2486 | /* zero out password before freeing */ | 2583 | /* zero out password before freeing */ |
| 2487 | if (volume_info) { | 2584 | cleanup_volume_info(&volume_info); |
| 2488 | if (volume_info->password != NULL) { | ||
| 2489 | memset(volume_info->password, 0, | ||
| 2490 | strlen(volume_info->password)); | ||
| 2491 | kfree(volume_info->password); | ||
| 2492 | } | ||
| 2493 | kfree(volume_info->UNC); | ||
| 2494 | kfree(volume_info->prepath); | ||
| 2495 | kfree(volume_info); | ||
| 2496 | } | ||
| 2497 | FreeXid(xid); | 2585 | FreeXid(xid); |
| 2498 | return rc; | 2586 | return rc; |
| 2499 | } | 2587 | } |
