BOOL cli_check_msdfs_proxy( struct cli_state *cli, const char *sharename, fstring newserver, fstring newshare ) { CLIENT_DFS_REFERRAL *refs = NULL; size_t num_refs; uint16 consumed; pstring fullpath; BOOL res; uint16 cnum; pstring newextrapath; if ( !cli || !sharename ) return False; cnum = cli->cnum; /* special case. never check for a referral on the IPC$ share */ if ( strequal( sharename, "IPC$" ) ) { return False; } /* send a trans2_query_path_info to check for a referral */ pstr_sprintf( fullpath, "\\%s\\%s", cli->desthost, sharename ); /* check for the referral */ if (!cli_send_tconX(cli, "IPC$", "IPC", NULL, 0)) { return False; } res = cli_dfs_get_referral(cli, fullpath, &refs, &num_refs, &consumed); if (!cli_tdis(cli)) { SAFE_FREE( refs ); return False; } cli->cnum = cnum; if (!res || !num_refs ) { SAFE_FREE( refs ); return False; } split_dfs_path( refs[0].dfspath, newserver, newshare, newextrapath ); /* check that this is not a self-referral */ if ( strequal( cli->desthost, newserver ) && strequal( sharename, newshare ) ) { SAFE_FREE( refs ); return False; } SAFE_FREE( refs ); return True; }
BOOL cli_resolve_path( const char *mountpt, struct cli_state *rootcli, const char *path, struct cli_state **targetcli, pstring targetpath) { CLIENT_DFS_REFERRAL *refs = NULL; size_t num_refs; uint16 consumed; struct cli_state *cli_ipc; pstring dfs_path, cleanpath, extrapath; int pathlen; fstring server, share; struct cli_state *newcli; pstring newpath; pstring newmount; char *ppath, *temppath = NULL; SMB_STRUCT_STAT sbuf; uint32 attributes; if ( !rootcli || !path || !targetcli ) { return False; } /* Don't do anything if this is not a DFS root. */ if ( !rootcli->dfsroot) { *targetcli = rootcli; pstrcpy( targetpath, path ); return True; } *targetcli = NULL; /* Send a trans2_query_path_info to check for a referral. */ clean_path(path, cleanpath); cli_dfs_make_full_path(rootcli, cleanpath, dfs_path ); if (cli_qpathinfo_basic( rootcli, dfs_path, &sbuf, &attributes ) ) { /* This is an ordinary path, just return it. */ *targetcli = rootcli; pstrcpy( targetpath, path ); 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) ) { *targetcli = rootcli; pstrcpy( targetpath, path ); goto done; } /* We got an error, check for DFS referral. */ if ( !cli_dfs_check_error(rootcli, NT_STATUS_PATH_NOT_COVERED)) { return False; } /* Check for the referral. */ if ( !(cli_ipc = cli_cm_open( rootcli->desthost, "IPC$", False )) ) { return False; } if ( !cli_dfs_get_referral(cli_ipc, dfs_path, &refs, &num_refs, &consumed) || !num_refs ) { return False; } /* Just store the first referral for now. */ split_dfs_path( refs[0].dfspath, server, share, extrapath ); SAFE_FREE(refs); /* Make sure to recreate the original string including any wildcards. */ cli_dfs_make_full_path( rootcli, path, dfs_path); pathlen = strlen( dfs_path )*2; consumed = MIN(pathlen, consumed ); pstrcpy( targetpath, &dfs_path[consumed/2] ); dfs_path[consumed/2] = '\0'; /* * 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 */ if ( (*targetcli = cli_cm_open(server, share, False)) == NULL ) { d_printf("Unable to follow dfs referral [\\%s\\%s]\n", server, share ); return False; } if (strlen(extrapath) > 0) { string_append(&temppath, extrapath); string_append(&temppath, targetpath); pstrcpy( targetpath, temppath ); } /* 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 False; } ppath++; /* Now pointing at start of server name. */ if ((ppath = strchr_m( dfs_path, '\\' )) == NULL) { return False; } ppath++; /* Now pointing at start of share name. */ if ((ppath = strchr_m( ppath+1, '\\' )) == NULL) { return False; } ppath++; /* Now pointing at path component. */ pstr_sprintf( newmount, "%s\\%s", mountpt, ppath ); cli_cm_set_mntpoint( *targetcli, newmount ); /* Check for another dfs referral, note that we are not checking for loops here. */ if ( !strequal( targetpath, "\\" ) && !strequal( targetpath, "/")) { if ( cli_resolve_path( newmount, *targetcli, targetpath, &newcli, newpath ) ) { /* * When cli_resolve_path returns true here it's always * returning the complete path in newpath, so we're done * here. */ *targetcli = newcli; pstrcpy( targetpath, newpath ); return True; } } done: /* If returning True ensure we return a dfs root full path. */ if ( (*targetcli)->dfsroot ) { pstrcpy(dfs_path, targetpath ); cli_dfs_make_full_path( *targetcli, dfs_path, targetpath); } return True; }
bool cli_check_msdfs_proxy(TALLOC_CTX *ctx, struct cli_state *cli, const char *sharename, char **pp_newserver, char **pp_newshare, bool force_encrypt, const char *username, const char *password, const char *domain) { struct client_dfs_referral *refs = NULL; size_t num_refs = 0; size_t consumed = 0; char *fullpath = NULL; bool res; uint16 cnum; char *newextrapath = NULL; NTSTATUS status; const char *remote_name; if (!cli || !sharename) { return false; } remote_name = cli_state_remote_name(cli); cnum = cli_state_get_tid(cli); /* special case. never check for a referral on the IPC$ share */ if (strequal(sharename, "IPC$")) { return false; } /* send a trans2_query_path_info to check for a referral */ fullpath = talloc_asprintf(ctx, "\\%s\\%s", remote_name, sharename); if (!fullpath) { return false; } /* check for the referral */ if (!NT_STATUS_IS_OK(cli_tree_connect(cli, "IPC$", "IPC", NULL, 0))) { return false; } if (force_encrypt) { status = cli_cm_force_encryption(cli, username, password, lp_workgroup(), "IPC$"); if (!NT_STATUS_IS_OK(status)) { return false; } } status = cli_dfs_get_referral(ctx, cli, fullpath, &refs, &num_refs, &consumed); res = NT_STATUS_IS_OK(status); status = cli_tdis(cli); if (!NT_STATUS_IS_OK(status)) { return false; } cli_state_set_tid(cli, cnum); if (!res || !num_refs) { return false; } if (!refs[0].dfspath) { return false; } if (!split_dfs_path(ctx, refs[0].dfspath, pp_newserver, pp_newshare, &newextrapath)) { return false; } /* check that this is not a self-referral */ if (strequal(remote_name, *pp_newserver) && strequal(sharename, *pp_newshare)) { return false; } return true; }
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; }
BOOL cli_resolve_path( const char *mountpt, struct cli_state *rootcli, const char *path, struct cli_state **targetcli, pstring targetpath ) { CLIENT_DFS_REFERRAL *refs = NULL; size_t num_refs; uint16 consumed; struct cli_state *cli_ipc; pstring fullpath, cleanpath; int pathlen; fstring server, share; struct cli_state *newcli; pstring newpath; pstring newmount; char *ppath; SMB_STRUCT_STAT sbuf; uint32 attributes; *targetcli = NULL; if ( !rootcli || !path || !targetcli ) return False; /* send a trans2_query_path_info to check for a referral */ clean_path( cleanpath, path ); make_full_path( fullpath, rootcli->desthost, rootcli->share, cleanpath ); /* don't bother continuing if this is not a dfs root */ if ( !rootcli->dfsroot || cli_qpathinfo_basic( rootcli, cleanpath, &sbuf, &attributes ) ) { *targetcli = rootcli; pstrcpy( targetpath, path ); return True; } /* we got an error, check for DFS referral */ if ( !cli_dfs_check_error(rootcli) ) return False; /* check for the referral */ if ( !(cli_ipc = cli_cm_open( rootcli->desthost, "IPC$", False )) ) return False; if ( !cli_dfs_get_referral(cli_ipc, fullpath, &refs, &num_refs, &consumed) || !num_refs ) { return False; } /* just store the first referral for now Make sure to recreate the original string including any wildcards */ make_full_path( fullpath, rootcli->desthost, rootcli->share, path ); pathlen = strlen( fullpath )*2; consumed = MIN(pathlen, consumed ); pstrcpy( targetpath, &fullpath[consumed/2] ); split_dfs_path( refs[0].dfspath, server, share ); SAFE_FREE( refs ); /* open the connection to the target path */ if ( (*targetcli = cli_cm_open(server, share, False)) == NULL ) { d_printf("Unable to follow dfs referral [//%s/%s]\n", server, share ); return False; } /* parse out the consumed mount path */ /* trim off the \server\share\ */ fullpath[consumed/2] = '\0'; dos_clean_name( fullpath ); ppath = strchr_m( fullpath, '\\' ); ppath = strchr_m( ppath+1, '\\' ); ppath = strchr_m( ppath+1, '\\' ); ppath++; pstr_sprintf( newmount, "%s\\%s", mountpt, ppath ); cli_cm_set_mntpoint( *targetcli, newmount ); /* check for another dfs referral, note that we are not checking for loops here */ if ( !strequal( targetpath, "\\" ) ) { if ( cli_resolve_path( newmount, *targetcli, targetpath, &newcli, newpath ) ) { *targetcli = newcli; pstrcpy( targetpath, newpath ); } } return True; }