static struct cli_state *server_cryptkey(TALLOC_CTX *mem_ctx) { struct cli_state *cli = NULL; char *desthost = NULL; struct sockaddr_storage dest_ss; const char *p; char *pserver = NULL; bool connected_ok = False; struct named_mutex *mutex = NULL; NTSTATUS status; pserver = talloc_strdup(mem_ctx, lp_passwordserver()); p = pserver; while(next_token_talloc(mem_ctx, &p, &desthost, LIST_SEP)) { desthost = talloc_sub_basic(mem_ctx, current_user_info.smb_name, current_user_info.domain, desthost); if (!desthost) { return NULL; } strupper_m(desthost); if (strequal(desthost, myhostname())) { DEBUG(1,("Password server loop - disabling " "password server %s\n", desthost)); continue; } if(!resolve_name( desthost, &dest_ss, 0x20, false)) { DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",desthost)); continue; } if (ismyaddr((struct sockaddr *)(void *)&dest_ss)) { DEBUG(1,("Password server loop - disabling password server %s\n",desthost)); continue; } /* we use a mutex to prevent two connections at once - when a Win2k PDC get two connections where one hasn't completed a session setup yet it will send a TCP reset to the first connection (tridge) */ mutex = grab_named_mutex(talloc_tos(), desthost, 10); if (mutex == NULL) { return NULL; } status = cli_connect_nb(desthost, &dest_ss, 0, 0x20, lp_netbios_name(), Undefined, &cli); if (NT_STATUS_IS_OK(status)) { DEBUG(3,("connected to password server %s\n",desthost)); connected_ok = True; break; } DEBUG(10,("server_cryptkey: failed to connect to server %s. Error %s\n", desthost, nt_errstr(status) )); TALLOC_FREE(mutex); } if (!connected_ok) { DEBUG(0,("password server not available\n")); return NULL; } /* security = server just can't function with spnego */ cli->use_spnego = False; DEBUG(3,("got session\n")); status = cli_negprot(cli); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(mutex); DEBUG(1, ("%s rejected the negprot: %s\n", desthost, nt_errstr(status))); cli_shutdown(cli); return NULL; } if (cli_state_protocol(cli) < PROTOCOL_LANMAN2 || !(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL)) { TALLOC_FREE(mutex); DEBUG(1,("%s isn't in user level security mode\n",desthost)); cli_shutdown(cli); return NULL; } /* Get the first session setup done quickly, to avoid silly Win2k bugs. (The next connection to the server will kill this one... */ status = cli_session_setup(cli, "", "", 0, "", 0, ""); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(mutex); DEBUG(0,("%s rejected the initial session setup (%s)\n", desthost, nt_errstr(status))); cli_shutdown(cli); return NULL; } TALLOC_FREE(mutex); DEBUG(3,("password server OK\n")); return cli; }
NTSTATUS cli_resolve_path(TALLOC_CTX *ctx, const char *mountpt, const struct user_auth_info *dfs_auth_info, struct cli_state *rootcli, const char *path, struct cli_state **targetcli, char **pp_targetpath) { struct client_dfs_referral *refs = NULL; size_t num_refs = 0; size_t consumed = 0; struct cli_state *cli_ipc = NULL; char *dfs_path = NULL; char *cleanpath = NULL; char *extrapath = NULL; int pathlen; char *server = NULL; char *share = NULL; struct cli_state *newcli = NULL; char *newpath = NULL; char *newmount = NULL; char *ppath = NULL; SMB_STRUCT_STAT sbuf; uint32 attributes; NTSTATUS status; if ( !rootcli || !path || !targetcli ) { return NT_STATUS_INVALID_PARAMETER; } /* Don't do anything if this is not a DFS root. */ if ( !rootcli->dfsroot) { *targetcli = rootcli; *pp_targetpath = talloc_strdup(ctx, path); if (!*pp_targetpath) { return NT_STATUS_NO_MEMORY; } return NT_STATUS_OK; } *targetcli = NULL; /* Send a trans2_query_path_info to check for a referral. */ cleanpath = clean_path(ctx, path); if (!cleanpath) { return NT_STATUS_NO_MEMORY; } dfs_path = cli_dfs_make_full_path(ctx, rootcli, cleanpath); if (!dfs_path) { return NT_STATUS_NO_MEMORY; } status = cli_qpathinfo_basic( rootcli, dfs_path, &sbuf, &attributes); if (NT_STATUS_IS_OK(status)) { /* This is an ordinary path, just return it. */ *targetcli = rootcli; *pp_targetpath = talloc_strdup(ctx, path); if (!*pp_targetpath) { return NT_STATUS_NO_MEMORY; } goto done; } /* Special case where client asked for a path that does not exist */ if (cli_dfs_check_error(rootcli, NT_STATUS_OBJECT_NAME_NOT_FOUND, status)) { *targetcli = rootcli; *pp_targetpath = talloc_strdup(ctx, path); if (!*pp_targetpath) { return NT_STATUS_NO_MEMORY; } goto done; } /* We got an error, check for DFS referral. */ if (!cli_dfs_check_error(rootcli, NT_STATUS_PATH_NOT_COVERED, status)) { return status; } /* Check for the referral. */ status = cli_cm_open(ctx, rootcli, cli_state_remote_name(rootcli), "IPC$", dfs_auth_info, false, cli_state_encryption_on(rootcli), cli_state_protocol(rootcli), 0, 0x20, &cli_ipc); if (!NT_STATUS_IS_OK(status)) { return status; } status = cli_dfs_get_referral(ctx, cli_ipc, dfs_path, &refs, &num_refs, &consumed); if (!NT_STATUS_IS_OK(status) || !num_refs) { return status; } /* Just store the first referral for now. */ if (!refs[0].dfspath) { return NT_STATUS_NOT_FOUND; } if (!split_dfs_path(ctx, refs[0].dfspath, &server, &share, &extrapath)) { return NT_STATUS_NOT_FOUND; } /* Make sure to recreate the original string including any wildcards. */ dfs_path = cli_dfs_make_full_path(ctx, rootcli, path); if (!dfs_path) { return NT_STATUS_NO_MEMORY; } pathlen = strlen(dfs_path); consumed = MIN(pathlen, consumed); *pp_targetpath = talloc_strdup(ctx, &dfs_path[consumed]); if (!*pp_targetpath) { return NT_STATUS_NO_MEMORY; } dfs_path[consumed] = '\0'; /* * *pp_targetpath is now the unconsumed part of the path. * dfs_path is now the consumed part of the path * (in \server\share\path format). */ /* Open the connection to the target server & share */ status = cli_cm_open(ctx, rootcli, server, share, dfs_auth_info, false, cli_state_encryption_on(rootcli), cli_state_protocol(rootcli), 0, 0x20, targetcli); if (!NT_STATUS_IS_OK(status)) { d_printf("Unable to follow dfs referral [\\%s\\%s]\n", server, share ); return status; } if (extrapath && strlen(extrapath) > 0) { /* EMC Celerra NAS version 5.6.50 (at least) doesn't appear to */ /* put the trailing \ on the path, so to be save we put one in if needed */ if (extrapath[strlen(extrapath)-1] != '\\' && **pp_targetpath != '\\') { *pp_targetpath = talloc_asprintf(ctx, "%s\\%s", extrapath, *pp_targetpath); } else { *pp_targetpath = talloc_asprintf(ctx, "%s%s", extrapath, *pp_targetpath); } if (!*pp_targetpath) { return NT_STATUS_NO_MEMORY; } } /* parse out the consumed mount path */ /* trim off the \server\share\ */ ppath = dfs_path; if (*ppath != '\\') { d_printf("cli_resolve_path: " "dfs_path (%s) not in correct format.\n", dfs_path ); return NT_STATUS_NOT_FOUND; } ppath++; /* Now pointing at start of server name. */ if ((ppath = strchr_m( dfs_path, '\\' )) == NULL) { return NT_STATUS_NOT_FOUND; } ppath++; /* Now pointing at start of share name. */ if ((ppath = strchr_m( ppath+1, '\\' )) == NULL) { return NT_STATUS_NOT_FOUND; } ppath++; /* Now pointing at path component. */ newmount = talloc_asprintf(ctx, "%s\\%s", mountpt, ppath ); if (!newmount) { return NT_STATUS_NOT_FOUND; } cli_set_mntpoint(*targetcli, newmount); /* Check for another dfs referral, note that we are not checking for loops here. */ if (!strequal(*pp_targetpath, "\\") && !strequal(*pp_targetpath, "/")) { status = cli_resolve_path(ctx, newmount, dfs_auth_info, *targetcli, *pp_targetpath, &newcli, &newpath); if (NT_STATUS_IS_OK(status)) { /* * When cli_resolve_path returns true here it's always * returning the complete path in newpath, so we're done * here. */ *targetcli = newcli; *pp_targetpath = newpath; return status; } } done: /* If returning true ensure we return a dfs root full path. */ if ((*targetcli)->dfsroot) { dfs_path = talloc_strdup(ctx, *pp_targetpath); if (!dfs_path) { return NT_STATUS_NO_MEMORY; } *pp_targetpath = cli_dfs_make_full_path(ctx, *targetcli, dfs_path); if (*pp_targetpath == NULL) { return NT_STATUS_NO_MEMORY; } } return NT_STATUS_OK; }