Example #1
0
File: clidfs.c Project: ekohl/samba
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;
}
Example #2
0
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;
}
Example #3
0
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;
}