Esempio n. 1
0
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;
}
Esempio n. 2
0
File: clidfs.c Progetto: 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;
}