예제 #1
0
static int do_message_op(void)
{
	struct in_addr ip;
	struct nmb_name called, calling;
	fstring server_name;
	char name_type_hex[10];

	make_nmb_name(&calling, global_myname(), 0x0);
	make_nmb_name(&called , desthost, name_type);

	fstrcpy(server_name, desthost);
	snprintf(name_type_hex, sizeof(name_type_hex), "#%X", name_type);
	fstrcat(server_name, name_type_hex);

        zero_ip(&ip);

	if (!(cli=cli_initialise(NULL)) || (cli_set_port(cli, port) != port) ||
	    !cli_connect(cli, server_name, &ip)) {
		d_printf("Connection to %s failed\n", desthost);
		return 1;
	}

	if (!cli_session_request(cli, &calling, &called)) {
		d_printf("session request failed\n");
		cli_shutdown(cli);
		return 1;
	}

	send_message();
	cli_shutdown(cli);

	return 0;
}
예제 #2
0
파일: cliconnect.c 프로젝트: jophxy/samba
BOOL attempt_netbios_session_request(struct cli_state *cli, const char *srchost, const char *desthost,
                                     struct in_addr *pdest_ip)
{
	struct nmb_name calling, called;

	make_nmb_name(&calling, srchost, 0x0);

	/*
	 * If the called name is an IP address
	 * then use *SMBSERVER immediately.
	 */

	if(is_ipaddress(desthost))
		make_nmb_name(&called, "*SMBSERVER", 0x20);
	else
		make_nmb_name(&called, desthost, 0x20);

	if (!cli_session_request(cli, &calling, &called)) {
	
		struct nmb_name smbservername;

		make_nmb_name(&smbservername , "*SMBSERVER", 0x20);

		/*
		 * If the name wasn't *SMBSERVER then
		 * try with *SMBSERVER if the first name fails.
		 */

		if (nmb_name_equal(&called, &smbservername)) {

			/*
			 * The name used was *SMBSERVER, don't bother with another name.
			 */

			DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER with error %s.\n", 
				desthost, cli_errstr(cli) ));
			return False;
		}

		/*
		 * We need to close the connection here but can't call cli_shutdown as
		 * will free an allocated cli struct. cli_close_connection was invented
		 * for this purpose. JRA. Based on work by "Kim R. Pedersen" <*****@*****.**>.
		 */

		cli_close_connection(cli);

		if (!cli_initialise(cli) || !cli_connect(cli, desthost, pdest_ip) ||
       			!cli_session_request(cli, &calling, &smbservername)) {
			DEBUG(0,("attempt_netbios_session_request: %s rejected the session for name *SMBSERVER with error %s\n", 
				desthost, cli_errstr(cli) ));
			return False;
		}
	}

	return True;
}
예제 #3
0
/* check to see if smbd is running on localhost by trying to open a connection
   then closing it */
BOOL smbd_running(void)
{
	struct cli_state *cli;

	if ((cli = cli_initialise()) == NULL)
		return False;

	if (!cli_connect(cli, global_myname(), &loopback_ip)) {
		cli_shutdown(cli);
		return False;
	}

	cli_shutdown(cli);
	return True;
}
예제 #4
0
파일: diagnose.c 프로젝트: AllardJ/Tomato
/* check to see if smbd is running on localhost by trying to open a connection
   then closing it */
BOOL smbd_running(void)
{
	static struct cli_state cli;
	extern struct in_addr loopback_ip;

	if (!cli_initialise(&cli))
		return False;

	if (!cli_connect(&cli, "localhost", &loopback_ip)) {
		cli_shutdown(&cli);
		return False;
	}

	cli_shutdown(&cli);
	return True;
}
예제 #5
0
/****************************************************************************
support for server level security 
****************************************************************************/
struct cli_state *server_cryptkey(void)
{
	fstring desthost;
	struct in_addr dest_ip;
	extern fstring local_machine;
	char *p;

	if (!cli_initialise(&cli))
		return NULL;
	    
	for (p=strtok(lp_passwordserver(),LIST_SEP); p ; p = strtok(NULL,LIST_SEP)) {
		fstrcpy(desthost,p);
		standard_sub_basic(desthost);
		strupper(desthost);

                if(!resolve_name( desthost, &dest_ip)) {
			DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",p));
			continue;
		}

		if (ismyip(dest_ip)) {
			DEBUG(1,("Password server loop - disabling password server %s\n",p));
			continue;
		}

		if (cli_connect(&cli, desthost, &dest_ip)) {
			DEBUG(3,("connected to password server %s\n",p));
			break;
		}
	}

	if (!p) {
		DEBUG(1,("password server not available\n"));
		cli_shutdown(&cli);
		return NULL;
	}

	if (!cli_session_request(&cli, desthost, 0x20, local_machine)) {
		DEBUG(1,("%s rejected the session\n",desthost));
		cli_shutdown(&cli);
		return NULL;
	}

	DEBUG(3,("got session\n"));

	if (!cli_negprot(&cli)) {
		DEBUG(1,("%s rejected the negprot\n",desthost));
		cli_shutdown(&cli);
		return NULL;
	}

	if (cli.protocol < PROTOCOL_LANMAN2 ||
	    !(cli.sec_mode & 1)) {
		DEBUG(1,("%s isn't in user level security mode\n",desthost));
		cli_shutdown(&cli);
		return NULL;
	}

	DEBUG(3,("password server OK\n"));

	return &cli;
}
예제 #6
0
파일: clidfs.c 프로젝트: kleopatra999/finx
static struct cli_state *do_connect( const char *server, const char *share,
                                     BOOL show_sessetup )
{
	struct cli_state *c = NULL;
	struct nmb_name called, calling;
	const char *server_n;
	struct in_addr ip;
	pstring servicename;
	char *sharename;
	fstring newserver, newshare;
	NTSTATUS status;
	
	/* make a copy so we don't modify the global string 'service' */
	pstrcpy(servicename, share);
	sharename = servicename;
	if (*sharename == '\\') {
		server = sharename+2;
		sharename = strchr_m(server,'\\');
		if (!sharename) return NULL;
		*sharename = 0;
		sharename++;
	}

	server_n = server;
	
	zero_ip(&ip);

	make_nmb_name(&calling, global_myname(), 0x0);
	make_nmb_name(&called , server, name_type);

 again:
	zero_ip(&ip);
	if (have_ip) 
		ip = dest_ip;

	/* have to open a new connection */
	if (!(c=cli_initialise()) || (cli_set_port(c, port) != port)) {
		d_printf("Connection to %s failed\n", server_n);
		return NULL;
	}
	status = cli_connect(c, server_n, &ip);
	if (!NT_STATUS_IS_OK(status)) {
		d_printf("Connection to %s failed (Error %s)\n", server_n, nt_errstr(status));
		return NULL;
	}

	c->protocol = max_protocol;
	c->use_kerberos = use_kerberos;
	cli_setup_signing_state(c, signing_state);
		

	if (!cli_session_request(c, &calling, &called, NULL)) {
		char *p;
		d_printf("session request to %s failed (%s)\n", 
			 called.name, cli_errstr(c));
		cli_shutdown(c);
		c = NULL;
		if ((p=strchr_m(called.name, '.'))) {
			*p = 0;
			goto again;
		}
		if (strcmp(called.name, "*SMBSERVER")) {
			make_nmb_name(&called , "*SMBSERVER", 0x20);
			goto again;
		}
		return NULL;
	}

	DEBUG(4,(" session request ok\n"));

	if (!cli_negprot(c)) {
		d_printf("protocol negotiation failed\n");
		cli_shutdown(c);
		return NULL;
	}

	if (!got_pass) {
		char *pass = getpass("Password: "******"", "", 0, "", 0,
						       lp_workgroup()))) { 
			d_printf("session setup failed: %s\n", cli_errstr(c));
			if (NT_STATUS_V(cli_nt_error(c)) == 
			    NT_STATUS_V(NT_STATUS_MORE_PROCESSING_REQUIRED))
				d_printf("did you forget to run kinit?\n");
			cli_shutdown(c);
			return NULL;
		}
		d_printf("Anonymous login successful\n");
	}

	if ( show_sessetup ) {
		if (*c->server_domain) {
			DEBUG(0,("Domain=[%s] OS=[%s] Server=[%s]\n",
				c->server_domain,c->server_os,c->server_type));
		} else if (*c->server_os || *c->server_type){
			DEBUG(0,("OS=[%s] Server=[%s]\n",
				 c->server_os,c->server_type));
		}		
	}
	DEBUG(4,(" session setup ok\n"));

	/* here's the fun part....to support 'msdfs proxy' shares
	   (on Samba or windows) we have to issues a TRANS_GET_DFS_REFERRAL 
	   here before trying to connect to the original share.
	   check_dfs_proxy() will fail if it is a normal share. */

	if ( (c->capabilities & CAP_DFS) && cli_check_msdfs_proxy( c, sharename, newserver, newshare ) ) {
		cli_shutdown(c);
		return do_connect( newserver, newshare, False );
	}

	/* must be a normal share */

	if (!cli_send_tconX(c, sharename, "?????", password, strlen(password)+1)) {
		d_printf("tree connect failed: %s\n", cli_errstr(c));
		cli_shutdown(c);
		return NULL;
	}

	DEBUG(4,(" tconx ok\n"));

	return c;
}
예제 #7
0
static void sync_child(char *name, int nm_type, 
		       char *workgroup,
		       struct in_addr ip, bool local, bool servers,
		       char *fname)
{
	fstring unix_workgroup;
	struct cli_state *cli;
	uint32 local_type = local ? SV_TYPE_LOCAL_LIST_ONLY : 0;
	struct nmb_name called, calling;
	struct sockaddr_storage ss;
	NTSTATUS status;

	/* W2K DMB's return empty browse lists on port 445. Use 139.
	 * Patch from Andy Levine [email protected].
	 */

	cli = cli_initialise();
	if (!cli) {
		return;
	}

	cli_set_port(cli, 139);

	in_addr_to_sockaddr_storage(&ss, ip);
	status = cli_connect(cli, name, &ss);
	if (!NT_STATUS_IS_OK(status)) {
		cli_shutdown(cli);
		return;
	}

	make_nmb_name(&calling, get_local_machine_name(), 0x0);
	make_nmb_name(&called , name, nm_type);

	if (!cli_session_request(cli, &calling, &called)) {
		cli_shutdown(cli);
		return;
	}

	status = cli_negprot(cli);
	if (!NT_STATUS_IS_OK(status)) {
		cli_shutdown(cli);
		return;
	}

	if (!NT_STATUS_IS_OK(cli_session_setup(cli, "", "", 1, "", 0,
					       workgroup))) {
		cli_shutdown(cli);
		return;
	}

	if (!NT_STATUS_IS_OK(cli_tcon_andx(cli, "IPC$", "IPC", "", 1))) {
		cli_shutdown(cli);
		return;
	}

	/* All the cli_XX functions take UNIX character set. */
	fstrcpy(unix_workgroup, cli->server_domain ? cli->server_domain : workgroup);

	/* Fetch a workgroup list. */
	cli_NetServerEnum(cli, unix_workgroup,
			  local_type|SV_TYPE_DOMAIN_ENUM, 
			  callback, NULL);
	
	/* Now fetch a server list. */
	if (servers) {
		fstrcpy(unix_workgroup, workgroup);
		cli_NetServerEnum(cli, unix_workgroup, 
				  local?SV_TYPE_LOCAL_LIST_ONLY:SV_TYPE_ALL,
				  callback, NULL);
	}
	
	cli_shutdown(cli);
}
예제 #8
0
static SMBCSRV *
SMBC_server_internal(TALLOC_CTX *ctx,
            SMBCCTX *context,
            bool connect_if_not_found,
            const char *server,
            const char *share,
            char **pp_workgroup,
            char **pp_username,
            char **pp_password,
	    bool *in_cache)
{
	SMBCSRV *srv=NULL;
	char *workgroup = NULL;
	struct cli_state *c;
	struct nmb_name called, calling;
	const char *server_n = server;
	struct sockaddr_storage ss;
	int tried_reverse = 0;
        int port_try_first;
        int port_try_next;
        int is_ipc = (share != NULL && strcmp(share, "IPC$") == 0);
	uint32 fs_attrs = 0;
        const char *username_used;
 	NTSTATUS status;
	char *newserver, *newshare;
	
	zero_sockaddr(&ss);
	ZERO_STRUCT(c);
	*in_cache = false;

	if (server[0] == 0) {
		errno = EPERM;
		return NULL;
	}
	
        /* Look for a cached connection */
        srv = SMBC_find_server(ctx, context, server, share,
                               pp_workgroup, pp_username, pp_password);

        /*
         * If we found a connection and we're only allowed one share per
         * server...
         */
        if (srv &&
            *share != '\0' &&
            smbc_getOptionOneSharePerServer(context)) {
			
                /*
                 * ... then if there's no current connection to the share,
                 * connect to it.  SMBC_find_server(), or rather the function
                 * pointed to by context->get_cached_srv_fn which
                 * was called by SMBC_find_server(), will have issued a tree
                 * disconnect if the requested share is not the same as the
                 * one that was already connected.
                 */

		/*
		 * Use srv->cli->desthost and srv->cli->share instead of
		 * server and share below to connect to the actual share,
		 * i.e., a normal share or a referred share from
		 * 'msdfs proxy' share.
		 */
                if (srv->cli->cnum == (uint16) -1) {
                        /* Ensure we have accurate auth info */
			SMBC_call_auth_fn(ctx, context,
					  srv->cli->desthost,
					  srv->cli->share,
                                          pp_workgroup,
                                          pp_username,
                                          pp_password);

			if (!*pp_workgroup || !*pp_username || !*pp_password) {
				errno = ENOMEM;
				cli_shutdown(srv->cli);
				srv->cli = NULL;
				smbc_getFunctionRemoveCachedServer(context)(context,
                                                                            srv);
				return NULL;
			}

			/*
			 * We don't need to renegotiate encryption
			 * here as the encryption context is not per
			 * tid.
			 */

			status = cli_tcon_andx(srv->cli, srv->cli->share, "?????",
					       *pp_password,
					       strlen(*pp_password)+1);
			if (!NT_STATUS_IS_OK(status)) {
                                errno = map_errno_from_nt_status(status);
                                cli_shutdown(srv->cli);
				srv->cli = NULL;
                                smbc_getFunctionRemoveCachedServer(context)(context,
                                                                            srv);
                                srv = NULL;
                        }

                        /* Determine if this share supports case sensitivity */
                        if (is_ipc) {
                                DEBUG(4,
                                      ("IPC$ so ignore case sensitivity\n"));
                        } else if (!cli_get_fs_attr_info(c, &fs_attrs)) {
                                DEBUG(4, ("Could not retrieve "
                                          "case sensitivity flag: %s.\n",
                                          cli_errstr(c)));

                                /*
                                 * We can't determine the case sensitivity of
                                 * the share. We have no choice but to use the
                                 * user-specified case sensitivity setting.
                                 */
                                if (smbc_getOptionCaseSensitive(context)) {
                                        cli_set_case_sensitive(c, True);
                                } else {
                                        cli_set_case_sensitive(c, False);
                                }
                        } else {
                                DEBUG(4,
                                      ("Case sensitive: %s\n",
                                       (fs_attrs & FILE_CASE_SENSITIVE_SEARCH
                                        ? "True"
                                        : "False")));
                                cli_set_case_sensitive(
                                        c,
                                        (fs_attrs & FILE_CASE_SENSITIVE_SEARCH
                                         ? True
                                         : False));
                        }

                        /*
                         * Regenerate the dev value since it's based on both
                         * server and share
                         */
                        if (srv) {
                                srv->dev = (dev_t)(str_checksum(srv->cli->desthost) ^
                                                   str_checksum(srv->cli->share));
                        }
                }
        }
	
        /* If we have a connection... */
        if (srv) {
                /* ... then we're done here.  Give 'em what they came for. */
		*in_cache = true;
                goto done;
        }

        /* If we're not asked to connect when a connection doesn't exist... */
        if (! connect_if_not_found) {
                /* ... then we're done here. */
                return NULL;
        }

	if (!*pp_workgroup || !*pp_username || !*pp_password) {
		errno = ENOMEM;
		return NULL;
	}

	make_nmb_name(&calling, smbc_getNetbiosName(context), 0x0);
	make_nmb_name(&called , server, 0x20);

	DEBUG(4,("SMBC_server: server_n=[%s] server=[%s]\n", server_n, server));

	DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server));

again:

	zero_sockaddr(&ss);

	/* have to open a new connection */
	if ((c = cli_initialise()) == NULL) {
		errno = ENOMEM;
		return NULL;
	}

        if (smbc_getOptionUseKerberos(context)) {
		c->use_kerberos = True;
	}

        if (smbc_getOptionFallbackAfterKerberos(context)) {
		c->fallback_after_kerberos = True;
	}

        if (smbc_getOptionUseCCache(context)) {
		c->use_ccache = True;
	}

	c->timeout = smbc_getTimeout(context);

        /*
         * Force use of port 139 for first try if share is $IPC, empty, or
         * null, so browse lists can work
         */
       if (share == NULL || *share == '\0' || is_ipc) {
                port_try_first = 139;
                port_try_next = 445;
       } else {
                port_try_first = 445;
                port_try_next = 139;
       }

	c->port = port_try_first;
	
	status = cli_connect(c, server_n, &ss);
	if (!NT_STATUS_IS_OK(status)) {

                /* First connection attempt failed.  Try alternate port. */
                c->port = port_try_next;

                status = cli_connect(c, server_n, &ss);
		if (!NT_STATUS_IS_OK(status)) {
			cli_shutdown(c);
			errno = ETIMEDOUT;
			return NULL;
		}
	}
	
	if (!cli_session_request(c, &calling, &called)) {
		cli_shutdown(c);
		if (strcmp(called.name, "*SMBSERVER")) {
			make_nmb_name(&called , "*SMBSERVER", 0x20);
			goto again;
		} else {  /* Try one more time, but ensure we don't loop */

			/* Only try this if server is an IP address ... */

			if (is_ipaddress(server) && !tried_reverse) {
				fstring remote_name;
				struct sockaddr_storage rem_ss;

				if (!interpret_string_addr(&rem_ss, server,
                                                           NI_NUMERICHOST)) {
					DEBUG(4, ("Could not convert IP address "
                                                  "%s to struct sockaddr_storage\n",
                                                  server));
					errno = ETIMEDOUT;
					return NULL;
				}

				tried_reverse++; /* Yuck */

				if (name_status_find("*", 0, 0,
                                                     &rem_ss, remote_name)) {
					make_nmb_name(&called,
                                                      remote_name,
                                                      0x20);
					goto again;
				}
			}
		}
		errno = ETIMEDOUT;
		return NULL;
	}

	DEBUG(4,(" session request ok\n"));
	

	status = cli_negprot(c);

	if (!NT_STATUS_IS_OK(status)) {
		cli_shutdown(c);
		errno = ETIMEDOUT;
		return NULL;
	}

        username_used = *pp_username;

	if (!NT_STATUS_IS_OK(cli_session_setup(c, username_used,
					       *pp_password,
                                               strlen(*pp_password),
					       *pp_password,
                                               strlen(*pp_password),
					       *pp_workgroup))) {
fprintf(stderr, "JerryLin: Libsmb_server.c->SMBC_server_internal: cli_session_setup fail with username=[%s], password=[%s]\n", username_used, *pp_password);
                /* Failed.  Try an anonymous login, if allowed by flags. */
                username_used = "";

                if (smbc_getOptionNoAutoAnonymousLogin(context) ||
                    !NT_STATUS_IS_OK(cli_session_setup(c, username_used,
                                                       *pp_password, 1,
                                                       *pp_password, 0,
                                                       *pp_workgroup))) {

                        cli_shutdown(c);
                        errno = EPERM;
                        return NULL;
                }
	}
	
	status = cli_init_creds(c, username_used,
				*pp_workgroup, *pp_password);
	if (!NT_STATUS_IS_OK(status)) {
		errno = map_errno_from_nt_status(status);
		cli_shutdown(c);
		return NULL;
	}

	DEBUG(4,(" session setup ok\n"));
	
	/* here's the fun part....to support 'msdfs proxy' shares
	   (on Samba or windows) we have to issues a TRANS_GET_DFS_REFERRAL
	   here before trying to connect to the original share.
	   cli_check_msdfs_proxy() will fail if it is a normal share. */

	if ((c->capabilities & CAP_DFS) &&
			cli_check_msdfs_proxy(ctx, c, share,
				&newserver, &newshare,
				/* FIXME: cli_check_msdfs_proxy() does
				   not support smbc_smb_encrypt_level type */
				context->internal->smb_encryption_level ?
					true : false,
				*pp_username,
				*pp_password,
				*pp_workgroup)) {
		cli_shutdown(c);
		srv = SMBC_server_internal(ctx, context, connect_if_not_found,
				newserver, newshare, pp_workgroup,
				pp_username, pp_password, in_cache);
		TALLOC_FREE(newserver);
		TALLOC_FREE(newshare);
		return srv;
	}
	
	/* must be a normal share */
	status = cli_tcon_andx(c, share, "?????", *pp_password,
			       strlen(*pp_password)+1);
	if (!NT_STATUS_IS_OK(status)) {
		errno = map_errno_from_nt_status(status);
		fprintf(stderr, "JerryLin: Libsmb_server.c->SMBC_server_internal: cli_tcon_andx return %08X, errno=[%d]\n", NT_STATUS_V(status), errno);
		cli_shutdown(c);
		return NULL;
	}
	
	DEBUG(4,(" tconx ok\n"));

        /* Determine if this share supports case sensitivity */
	if (is_ipc) {
                DEBUG(4, ("IPC$ so ignore case sensitivity\n"));
        } else if (!cli_get_fs_attr_info(c, &fs_attrs)) {
                DEBUG(4, ("Could not retrieve case sensitivity flag: %s.\n",
                          cli_errstr(c)));

                /*
                 * We can't determine the case sensitivity of the share. We
                 * have no choice but to use the user-specified case
                 * sensitivity setting.
                 */
                if (smbc_getOptionCaseSensitive(context)) {
                        cli_set_case_sensitive(c, True);
                } else {
                        cli_set_case_sensitive(c, False);
                }
	} else {
                DEBUG(4, ("Case sensitive: %s\n",
                          (fs_attrs & FILE_CASE_SENSITIVE_SEARCH
                           ? "True"
                           : "False")));
                cli_set_case_sensitive(c,
                                       (fs_attrs & FILE_CASE_SENSITIVE_SEARCH
                                        ? True
                                        : False));
        }
	

	if (context->internal->smb_encryption_level) {
		/* Attempt UNIX smb encryption. */
		if (!NT_STATUS_IS_OK(cli_force_encryption(c,
                                                          username_used,
                                                          *pp_password,
                                                          *pp_workgroup))) {

			/*
			 * context->smb_encryption_level == 1
			 * means don't fail if encryption can't be negotiated,
			 * == 2 means fail if encryption can't be negotiated.
			 */

			DEBUG(4,(" SMB encrypt failed\n"));

			if (context->internal->smb_encryption_level == 2) {
	                        cli_shutdown(c);
				errno = EPERM;
				return NULL;
			}
		}
		DEBUG(4,(" SMB encrypt ok\n"));
	}

	/*
	 * Ok, we have got a nice connection
	 * Let's allocate a server structure.
	 */

	srv = SMB_MALLOC_P(SMBCSRV);
	if (!srv) {
		cli_shutdown(c);
		errno = ENOMEM;
		return NULL;
	}

	ZERO_STRUCTP(srv);
	srv->cli = c;
	srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));
        srv->no_pathinfo = False;
        srv->no_pathinfo2 = False;
        srv->no_nt_session = False;

done:
	if (!pp_workgroup || !*pp_workgroup || !**pp_workgroup) {
		workgroup = talloc_strdup(ctx, smbc_getWorkgroup(context));
	} else {
		workgroup = *pp_workgroup;
	}
	if(!workgroup) {
		return NULL;
	}

	/* set the credentials to make DFS work */
	smbc_set_credentials_with_fallback(context,
					   workgroup,
				    	   *pp_username,
				   	   *pp_password);

	return srv;
}
예제 #9
0
static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain,
				      const int sockfd,
				      const int pipe_index,
				      const char *controller,
				      struct cli_state **cli,
				      BOOL *retry)
{
	char *machine_password, *machine_krb5_principal;
	char *ipc_username, *ipc_domain, *ipc_password;

	BOOL got_mutex;
	BOOL add_failed_connection = True;

	NTSTATUS result = NT_STATUS_UNSUCCESSFUL;

	struct sockaddr peeraddr;
	socklen_t peeraddr_len;

	struct sockaddr_in *peeraddr_in = (struct sockaddr_in *)&peeraddr;

	machine_password = secrets_fetch_machine_password(lp_workgroup(), NULL,
							  NULL);
	
	if (asprintf(&machine_krb5_principal, "%s$@%s", global_myname(),
		     lp_realm()) == -1) {
		SAFE_FREE(machine_password);
		return NT_STATUS_NO_MEMORY;
	}

	cm_get_ipc_userpass(&ipc_username, &ipc_domain, &ipc_password);

	*retry = True;

	got_mutex = secrets_named_mutex(controller,
					WINBIND_SERVER_MUTEX_WAIT_TIME);

	if (!got_mutex) {
		DEBUG(0,("cm_open_connection: mutex grab failed for %s\n",
			 controller));
		result = NT_STATUS_POSSIBLE_DEADLOCK;
		goto done;
	}

	if ((*cli = cli_initialise(NULL)) == NULL) {
		DEBUG(1, ("Could not cli_initialize\n"));
		result = NT_STATUS_NO_MEMORY;
		goto done;
	}

	(*cli)->timeout = 10000; 	/* 10 seconds */
	(*cli)->fd = sockfd;
	fstrcpy((*cli)->desthost, controller);
	(*cli)->use_kerberos = True;

	peeraddr_len = sizeof(peeraddr);

	if ((getpeername((*cli)->fd, &peeraddr, &peeraddr_len) != 0) ||
	    (peeraddr_len != sizeof(struct sockaddr_in)) ||
	    (peeraddr_in->sin_family != PF_INET))
	{
		DEBUG(0,("cm_prepare_connection: %s\n", strerror(errno)));
		goto done;
	}

	if (ntohs(peeraddr_in->sin_port) == 139) {
		struct nmb_name calling;
		struct nmb_name called;

		make_nmb_name(&calling, global_myname(), 0x0);
		make_nmb_name(&called, "*SMBSERVER", 0x20);

		if (!cli_session_request(*cli, &calling, &called)) {
			DEBUG(8, ("cli_session_request failed for %s\n",
				  controller));
			goto done;
		}
	}

	cli_setup_signing_state(*cli, Undefined);

	if (!cli_negprot(*cli)) {
		DEBUG(1, ("cli_negprot failed\n"));
		cli_shutdown(*cli);
		goto done;
	}

	/* Krb5 session */
			
	if ((lp_security() == SEC_ADS) 
	    && ((*cli)->protocol >= PROTOCOL_NT1 &&
		(*cli)->capabilities & CAP_EXTENDED_SECURITY)) {

		ADS_STATUS ads_status;
		(*cli)->use_kerberos = True;
		DEBUG(5, ("connecting to %s from %s with kerberos principal "
			  "[%s]\n", controller, global_myname(),
			  machine_krb5_principal));

		ads_status = cli_session_setup_spnego(*cli,
						      machine_krb5_principal, 
						      machine_password, 
						      lp_workgroup());

		if (!ADS_ERR_OK(ads_status))
			DEBUG(4,("failed kerberos session setup with %s\n",
				 ads_errstr(ads_status)));

		result = ads_ntstatus(ads_status);
	}

	if (NT_STATUS_IS_OK(result))
		goto session_setup_done;

	/* Fall back to non-kerberos session setup */

	(*cli)->use_kerberos = False;

	if ((((*cli)->sec_mode & NEGOTIATE_SECURITY_CHALLENGE_RESPONSE) != 0) &&
	    (strlen(ipc_username) > 0)) {

		/* Only try authenticated if we have a username */

		DEBUG(5, ("connecting to %s from %s with username "
			  "[%s]\\[%s]\n",  controller, global_myname(),
			  ipc_domain, ipc_username));

		if (cli_session_setup(*cli, ipc_username,
				      ipc_password, strlen(ipc_password)+1,
				      ipc_password, strlen(ipc_password)+1,
				      ipc_domain)) {
			DEBUG(5, ("authenticated session setup failed\n"));
			goto session_setup_done;
		}
	}

	/* Fall back to anonymous connection, this might fail later */

	if (cli_session_setup(*cli, "", NULL, 0, NULL, 0, "")) {
		DEBUG(5, ("Connected anonymously\n"));
		goto session_setup_done;
	}

	result = cli_nt_error(*cli);

	if (NT_STATUS_IS_OK(result))
		result = NT_STATUS_UNSUCCESSFUL;

	/* We can't session setup */

	goto done;

 session_setup_done:

	if (!cli_send_tconX(*cli, "IPC$", "IPC", "", 0)) {

		result = cli_nt_error(*cli);

		DEBUG(1,("failed tcon_X with %s\n", nt_errstr(result)));

		if (NT_STATUS_IS_OK(result))
			result = NT_STATUS_UNSUCCESSFUL;

		cli_shutdown(*cli);
		goto done;
	}

	secrets_named_mutex_release(controller);
	got_mutex = False;
	*retry = False;

	/* Windows 2003 SP1 does not lie LsaOpenPolicy() over schannel.
	   Returns RPC_NT_CANNOT_SUPPPORT (0xc0020041) for that call.
	   So just drop it on the lsarpc pipe */

	if ( (domain->primary || IS_DC) && (pipe_index!=PI_LSARPC) ) {
		NTSTATUS status = setup_schannel( *cli, domain->name );
		if (!NT_STATUS_IS_OK(status)) {
			DEBUG(3,("schannel refused - continuing without "
				 "schannel (%s)\n", nt_errstr(status)));
		}
	}

	/* set the domain if empty; needed for schannel connections */
	if ( !*(*cli)->domain )
		fstrcpy( (*cli)->domain, domain->name );

	if ( !cli_nt_session_open (*cli, pipe_index) ) {

		result = NT_STATUS_PIPE_NOT_AVAILABLE;

		/* This might be a NT4 DC */
		if ( is_win2k_pipe(pipe_index) )
			add_failed_connection = False;

		cli_shutdown(*cli);
		goto done;
	}

	result = NT_STATUS_OK;
	add_failed_connection = False;

 done:
	if (got_mutex)
		secrets_named_mutex_release(controller);

	SAFE_FREE(machine_password);
	SAFE_FREE(machine_krb5_principal);
	SAFE_FREE(ipc_username);
	SAFE_FREE(ipc_domain);
	SAFE_FREE(ipc_password);

	if (add_failed_connection)
		add_failed_connection_entry(domain->name, controller, result);

	return result;
}
예제 #10
0
int vscan_send_warning_message(const char *filename, const char *virname, const char *ipaddr) {
    struct in_addr ip;
    struct sockaddr_storage ss;

        struct nmb_name called, calling;
	pstring myname;
	pstring message;
	pstring shortfilename;
	char* lastslash;

	static pstring lastfile;
	static pstring lastip;

	#if SAMBA_VERSION_MAJOR==3
	fstrcpy(remote_machine, get_remote_machine_name());
	DEBUG(5, ("remote machine is: %s\n", remote_machine));
	#endif

	/* Only notify once for a given virus/ip combo - otherwise the
	 * scanner will go crazy reaccessing the file and sending
	 * messages once the user hits the "okay" button */
	if (strncmp(lastfile,filename,sizeof(pstring)) == 0) {
		if (strncmp(lastip,ipaddr,sizeof(pstring)) == 0) {
			DEBUG(5,("Both IP and Filename are the same, not notifying\n"));
			return 0;
		}
	}

	ZERO_ARRAY(lastfile);
	ZERO_ARRAY(lastip);
	pstrcpy(lastfile,filename);
	pstrcpy(lastip,ipaddr);

	ZERO_ARRAY(myname);
	pstrcpy(myname,myhostname());

	ZERO_ARRAY(username);
	/* could make this configurable */
	snprintf(username,sizeof(pstring)-1,"%s VIRUS SCANNER",myname);

	/* We need to get the real ip structure from the ip string
	 * is this info already available somewhere else in samba? */
       	zero_ip_v4(&ip);
	if (inet_aton(ipaddr,&ip) == 0) {
               	DEBUG(5,("Cannot resolve ip address %s\n", ipaddr));
               	return 1;
	}
    in_addr_to_sockaddr_storage(&ss, ip);


       	make_nmb_name(&calling, myname, 0x0);
       	make_nmb_name(&called , remote_machine, name_type);

	 if (!(cli=cli_initialise())) {
               	DEBUG(5,("Connection to %s failed\n", remote_machine));
               	return 1;
       	}
        cli_set_port(cli, port);
     if (!NT_STATUS_IS_OK(cli_connect(cli, remote_machine, &ss))) {
               	DEBUG(5,("Connection to %s failed\n", remote_machine));
               	return 1;
    }

       	if (!cli_session_request(cli, &calling, &called)) {
               	DEBUG(5,("session request failed\n"));
               	cli_shutdown(cli);
               	return 1;
       	}

	ZERO_ARRAY(shortfilename);
	/* we don't want the entire filename, otherwise the message service may choke
	 * so we chop off the path up to the very last forward-slash
	 * assumption: unix-style pathnames in filename (don't know if there's a
	 * portable file-separator variable... */
	lastslash = strrchr(filename,'/');
	if (lastslash != NULL && lastslash != filename) {
		pstrcpy(shortfilename,lastslash+1);
	} else {
		pstrcpy(shortfilename,filename);
	}

	ZERO_ARRAY(message);
	/* could make the message configurable and language specific? */
	snprintf(message,sizeof(pstring)-1,
		"%s IS INFECTED WITH VIRUS  %s.\r\n\r\nAccess will be denied.\r\nPlease contact your system administrator",
		shortfilename, virname);

	/* actually send the message... */
       	send_message(message);

       	cli_shutdown(cli);
	
        return 0;
}
예제 #11
0
/***************************************************** 
return a connection to a server
*******************************************************/
static struct cli_state *connect_one(char *share, int snum)
{
	struct cli_state *c;
	struct nmb_name called, calling;
	char *server_n;
	fstring server;
	struct in_addr ip;
	fstring myname;
	static int count;

	fstrcpy(server,share+2);
	share = strchr_m(server,'\\');
	if (!share) return NULL;
	*share = 0;
	share++;

	server_n = server;
	
        zero_ip(&ip);

	slprintf(myname,sizeof(myname), "lock-%lu-%u", (unsigned long)getpid(), count++);

	make_nmb_name(&calling, myname, 0x0);
	make_nmb_name(&called , server, 0x20);

 again:
        zero_ip(&ip);

	/* have to open a new connection */
	if (!(c=cli_initialise(NULL)) || !cli_connect(c, server_n, &ip)) {
		DEBUG(0,("Connection to %s failed\n", server_n));
		return NULL;
	}

	c->use_kerberos = use_kerberos;

	if (!cli_session_request(c, &calling, &called)) {
		DEBUG(0,("session request to %s failed\n", called.name));
		cli_shutdown(c);
		if (strcmp(called.name, "*SMBSERVER")) {
			make_nmb_name(&called , "*SMBSERVER", 0x20);
			goto again;
		}
		return NULL;
	}

	DEBUG(4,(" session request ok\n"));

	if (!cli_negprot(c)) {
		DEBUG(0,("protocol negotiation failed\n"));
		cli_shutdown(c);
		return NULL;
	}

	if (!got_pass) {
		char *pass = getpass("Password: "******"session setup failed: %s\n", cli_errstr(c)));
		return NULL;
	}

	/*
	 * These next two lines are needed to emulate
	 * old client behaviour for people who have
	 * scripts based on client output.
	 * QUESTION ? Do we want to have a 'client compatibility
	 * mode to turn these on/off ? JRA.
	 */

	if (*c->server_domain || *c->server_os || *c->server_type)
		DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
			c->server_domain,c->server_os,c->server_type));
	
	DEBUG(4,(" session setup ok\n"));

	if (!cli_send_tconX(c, share, "?????",
			    password[snum], strlen(password[snum])+1)) {
		DEBUG(0,("tree connect failed: %s\n", cli_errstr(c)));
		cli_shutdown(c);
		return NULL;
	}

	DEBUG(4,(" tconx ok\n"));

	c->use_oplocks = use_oplocks;

	return c;
}
예제 #12
0
파일: cliconnect.c 프로젝트: jophxy/samba
NTSTATUS cli_full_connection(struct cli_state **output_cli, 
			     const char *my_name, const char *dest_host, 
			     struct in_addr *dest_ip, int port,
			     const char *service, const char *service_type,
			     const char *user, const char *domain, 
			     const char *password, int pass_len) 
{
	struct ntuser_creds creds;
	NTSTATUS nt_status;
	struct nmb_name calling;
	struct nmb_name called;
	struct cli_state *cli;
	struct in_addr ip;
	
	if (!output_cli)
		DEBUG(0, ("output_cli is NULL!?!"));

	*output_cli = NULL;
	
	make_nmb_name(&calling, my_name, 0x0);
	make_nmb_name(&called , dest_host, 0x20);

again:

	if (!(cli = cli_initialise(NULL)))
		return NT_STATUS_NO_MEMORY;
	
	if (cli_set_port(cli, port) != port) {
		cli_shutdown(cli);
		return NT_STATUS_UNSUCCESSFUL;
	}

	ip = *dest_ip;
	
	DEBUG(3,("Connecting to host=%s share=%s\n", dest_host, service));
	
	if (!cli_connect(cli, dest_host, &ip)) {
		DEBUG(1,("cli_establish_connection: failed to connect to %s (%s)\n",
			 nmb_namestr(&called), inet_ntoa(*dest_ip)));
		cli_shutdown(cli);
		return NT_STATUS_UNSUCCESSFUL;
	}

	if (!cli_session_request(cli, &calling, &called)) {
		char *p;
		DEBUG(1,("session request to %s failed (%s)\n", 
			 called.name, cli_errstr(cli)));
		cli_shutdown(cli);
		if ((p=strchr(called.name, '.')) && !is_ipaddress(called.name)) {
			*p = 0;
			goto again;
		}
		if (strcmp(called.name, "*SMBSERVER")) {
			make_nmb_name(&called , "*SMBSERVER", 0x20);
			goto again;
		}
		return NT_STATUS_UNSUCCESSFUL;
	}

	if (!cli_negprot(cli)) {
		DEBUG(1,("failed negprot\n"));
		nt_status = NT_STATUS_UNSUCCESSFUL;
		cli_shutdown(cli);
		return nt_status;
	}

	if (!cli_session_setup(cli, user, password, pass_len, password, pass_len, 
			       domain)) {
		DEBUG(1,("failed session setup\n"));
		nt_status = cli_nt_error(cli);
		cli_shutdown(cli);
		if (NT_STATUS_IS_OK(nt_status)) 
			nt_status = NT_STATUS_UNSUCCESSFUL;
		return nt_status;
	} 

	if (service) {
		if (!cli_send_tconX(cli, service, service_type,
				    password, pass_len)) {
			DEBUG(1,("failed tcon_X\n"));
			nt_status = cli_nt_error(cli);
			cli_shutdown(cli);
			if (NT_STATUS_IS_OK(nt_status)) 
				nt_status = NT_STATUS_UNSUCCESSFUL;
			return nt_status;
		}
	}

	init_creds(&creds, user, domain, password, pass_len);
	cli_init_creds(cli, &creds);

	*output_cli = cli;
	return NT_STATUS_OK;
}
예제 #13
0
파일: clidfs.c 프로젝트: hajuuk/R7000
static struct cli_state *do_connect( const char *server, const char *share,
                                     BOOL show_sessetup )
{
	struct cli_state *c;
	struct nmb_name called, calling;
	const char *server_n;
	struct in_addr ip;
	pstring servicename;
	char *sharename;
	
	/* make a copy so we don't modify the global string 'service' */
	pstrcpy(servicename, share);
	sharename = servicename;
	if (*sharename == '\\') {
		server = sharename+2;
		sharename = strchr_m(server,'\\');
		if (!sharename) return NULL;
		*sharename = 0;
		sharename++;
	}

	server_n = server;
	
	zero_ip(&ip);

	make_nmb_name(&calling, global_myname(), 0x0);
	make_nmb_name(&called , server, name_type);

 again:
	zero_ip(&ip);
	if (have_ip) 
		ip = dest_ip;

	/* have to open a new connection */
	if (!(c=cli_initialise(NULL)) || (cli_set_port(c, port) != port) ||
	    !cli_connect(c, server_n, &ip)) {
		d_printf("Connection to %s failed\n", server_n);
		return NULL;
	}

	c->protocol = max_protocol;
	c->use_kerberos = use_kerberos;
	cli_setup_signing_state(c, signing_state);
		

	if (!cli_session_request(c, &calling, &called)) {
		char *p;
		d_printf("session request to %s failed (%s)\n", 
			 called.name, cli_errstr(c));
		cli_shutdown(c);
		if ((p=strchr_m(called.name, '.'))) {
			*p = 0;
			goto again;
		}
		if (strcmp(called.name, "*SMBSERVER")) {
			make_nmb_name(&called , "*SMBSERVER", 0x20);
			goto again;
		}
		return NULL;
	}

	DEBUG(4,(" session request ok\n"));

	if (!cli_negprot(c)) {
		d_printf("protocol negotiation failed\n");
		cli_shutdown(c);
		return NULL;
	}

	if (!got_pass) {
		char *pass = getpass("Password: "******"", "", 0, "", 0, lp_workgroup())) { 
			d_printf("session setup failed: %s\n", cli_errstr(c));
			if (NT_STATUS_V(cli_nt_error(c)) == 
			    NT_STATUS_V(NT_STATUS_MORE_PROCESSING_REQUIRED))
				d_printf("did you forget to run kinit?\n");
			cli_shutdown(c);
			return NULL;
		}
		d_printf("Anonymous login successful\n");
	}

	if ( show_sessetup ) {
		if (*c->server_domain) {
			DEBUG(0,("Domain=[%s] OS=[%s] Server=[%s]\n",
				c->server_domain,c->server_os,c->server_type));
		} else if (*c->server_os || *c->server_type){
			DEBUG(0,("OS=[%s] Server=[%s]\n",
				 c->server_os,c->server_type));
		}		
	}
	DEBUG(4,(" session setup ok\n"));

	if (!cli_send_tconX(c, sharename, "?????",
			    password, strlen(password)+1)) {
		d_printf("tree connect failed: %s\n", cli_errstr(c));
		cli_shutdown(c);
		return NULL;
	}

	DEBUG(4,(" tconx ok\n"));

	return c;
}
예제 #14
0
/****************************************************************************
initialise smb client structure
****************************************************************************/
void rpcclient_init(void)
{
	memset((char *)smb_cli, '\0', sizeof(smb_cli));
	cli_initialise(smb_cli);
	smb_cli->capabilities |= CAP_NT_SMBS;
}
예제 #15
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;

	if (!(cli = cli_initialise()))
		return NULL;

	/* security = server just can't function with spnego */
	cli->use_spnego = False;

        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(!resolve_name( desthost, &dest_ss, 0x20, false)) {
			DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",desthost));
			continue;
		}

		if (ismyaddr((struct sockaddr *)&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) {
			cli_shutdown(cli);
			return NULL;
		}

		status = cli_connect(cli, desthost, &dest_ss);
		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"));
		cli_shutdown(cli);
		return NULL;
	}

	if (!attempt_netbios_session_request(&cli, global_myname(),
					     desthost, &dest_ss)) {
		TALLOC_FREE(mutex);
		DEBUG(1,("password server fails session request\n"));
		cli_shutdown(cli);
		return NULL;
	}

	if (strequal(desthost,myhostname())) {
		exit_server_cleanly("Password server loop!");
	}

	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->protocol < 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;
}
예제 #16
0
NTSTATUS remote_password_change(const char *remote_machine, const char *user_name, 
				const char *old_passwd, const char *new_passwd,
				char **err_str)
{
	struct nmb_name calling, called;
	struct cli_state *cli;
	struct rpc_pipe_client *pipe_hnd;
	struct sockaddr_storage ss;

	NTSTATUS result;
	bool pass_must_change = False;

	*err_str = NULL;

	if(!resolve_name( remote_machine, &ss, 0x20)) {
		asprintf(err_str, "Unable to find an IP address for machine "
			 "%s.\n", remote_machine);
		return NT_STATUS_UNSUCCESSFUL;
	}
 
	cli = cli_initialise();
	if (!cli) {
		return NT_STATUS_NO_MEMORY;
	}

	result = cli_connect(cli, remote_machine, &ss);
	if (!NT_STATUS_IS_OK(result)) {
		asprintf(err_str, "Unable to connect to SMB server on "
			 "machine %s. Error was : %s.\n",
			 remote_machine, nt_errstr(result));
		cli_shutdown(cli);
		return result;
	}
  
	make_nmb_name(&calling, global_myname() , 0x0);
	make_nmb_name(&called , remote_machine, 0x20);
	
	if (!cli_session_request(cli, &calling, &called)) {
		asprintf(err_str, "machine %s rejected the session setup. "
			 "Error was : %s.\n",
			 remote_machine, cli_errstr(cli) );
		result = cli_nt_error(cli);
		cli_shutdown(cli);
		return result;
	}
  
	cli->protocol = PROTOCOL_NT1;

	if (!cli_negprot(cli)) {
		asprintf(err_str, "machine %s rejected the negotiate "
			 "protocol. Error was : %s.\n",        
			 remote_machine, cli_errstr(cli) );
		result = cli_nt_error(cli);
		cli_shutdown(cli);
		return result;
	}
  
	/* Given things like SMB signing, restrict anonymous and the like, 
	   try an authenticated connection first */
	result = cli_session_setup(cli, user_name,
				   old_passwd, strlen(old_passwd)+1,
				   old_passwd, strlen(old_passwd)+1, "");

	if (!NT_STATUS_IS_OK(result)) {

		/* Password must change or Password expired are the only valid
		 * error conditions here from where we can proceed, the rest like
		 * account locked out or logon failure will lead to errors later
		 * anyway */

		if (!NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) &&
		    !NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED)) {
			asprintf(err_str, "Could not connect to machine %s: "
				 "%s\n", remote_machine, cli_errstr(cli));
			cli_shutdown(cli);
			return result;
		}

		pass_must_change = True;

		/*
		 * We should connect as the anonymous user here, in case
		 * the server has "must change password" checked...
		 * Thanks to <*****@*****.**> for this fix.
		 */

		result = cli_session_setup(cli, "", "", 0, "", 0, "");

		if (!NT_STATUS_IS_OK(result)) {
			asprintf(err_str, "machine %s rejected the session "
				 "setup. Error was : %s.\n",        
				 remote_machine, cli_errstr(cli) );
			cli_shutdown(cli);
			return result;
		}

		cli_init_creds(cli, "", "", NULL);
	} else {
		cli_init_creds(cli, user_name, "", old_passwd);
	}

	if (!cli_send_tconX(cli, "IPC$", "IPC", "", 1)) {
		asprintf(err_str, "machine %s rejected the tconX on the IPC$ "
			 "share. Error was : %s.\n",
			 remote_machine, cli_errstr(cli) );
		result = cli_nt_error(cli);
		cli_shutdown(cli);
		return result;
	}

	/* Try not to give the password away too easily */

	if (!pass_must_change) {
		pipe_hnd = cli_rpc_pipe_open_ntlmssp(cli,
						PI_SAMR,
						PIPE_AUTH_LEVEL_PRIVACY,
						"", /* what domain... ? */
						user_name,
						old_passwd,
						&result);
	} else {
		/*
		 * If the user password must be changed the ntlmssp bind will
		 * fail the same way as the session setup above did. The
		 * difference ist that with a pipe bind we don't get a good
		 * error message, the result will be that the rpc call below
		 * will just fail. So we do it anonymously, there's no other
		 * way.
		 */
		pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &result);
	}

	if (!pipe_hnd) {
		if (lp_client_lanman_auth()) {
			/* Use the old RAP method. */
			if (!cli_oem_change_password(cli, user_name, new_passwd, old_passwd)) {
				asprintf(err_str, "machine %s rejected the "
					 "password change: Error was : %s.\n",
					 remote_machine, cli_errstr(cli) );
				result = cli_nt_error(cli);
				cli_shutdown(cli);
				return result;
			}
		} else {
			asprintf(err_str, "SAMR connection to machine %s "
				 "failed. Error was %s, but LANMAN password "
				 "changed are disabled\n",
				 nt_errstr(result), remote_machine);
			result = cli_nt_error(cli);
			cli_shutdown(cli);
			return result;
		}
	}

	if (NT_STATUS_IS_OK(result = rpccli_samr_chgpasswd_user(pipe_hnd, pipe_hnd->mem_ctx, user_name, 
							     new_passwd, old_passwd))) {
		/* Great - it all worked! */
		cli_shutdown(cli);
		return NT_STATUS_OK;

	} else if (!(NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) 
		     || NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))) {
		/* it failed, but for reasons such as wrong password, too short etc ... */
		
		asprintf(err_str, "machine %s rejected the password change: "
			 "Error was : %s.\n",
			 remote_machine, get_friendly_nt_error_msg(result));
		cli_shutdown(cli);
		return result;
	}

	/* OK, that failed, so try again... */
	cli_rpc_pipe_close(pipe_hnd);
	
	/* Try anonymous NTLMSSP... */
	cli_init_creds(cli, "", "", NULL);
	
	result = NT_STATUS_UNSUCCESSFUL;
	
	/* OK, this is ugly, but... try an anonymous pipe. */
	pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &result);

	if ( pipe_hnd &&
		(NT_STATUS_IS_OK(result = rpccli_samr_chgpasswd_user(pipe_hnd,
						pipe_hnd->mem_ctx,
						user_name, 
						new_passwd,
						old_passwd)))) {
		/* Great - it all worked! */
		cli_shutdown(cli);
		return NT_STATUS_OK;
	} else {
		if (!(NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) 
		      || NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))) {
			/* it failed, but again it was due to things like new password too short */

			asprintf(err_str, "machine %s rejected the "
				 "(anonymous) password change: Error was : "
				 "%s.\n", remote_machine,
				 get_friendly_nt_error_msg(result));
			cli_shutdown(cli);
			return result;
		}
		
		/* We have failed to change the user's password, and we think the server
		   just might not support SAMR password changes, so fall back */
		
		if (lp_client_lanman_auth()) {
			/* Use the old RAP method. */
			if (cli_oem_change_password(cli, user_name, new_passwd, old_passwd)) {
				/* SAMR failed, but the old LanMan protocol worked! */

				cli_shutdown(cli);
				return NT_STATUS_OK;
			}
			asprintf(err_str, "machine %s rejected the password "
				 "change: Error was : %s.\n",
				 remote_machine, cli_errstr(cli) );
			result = cli_nt_error(cli);
			cli_shutdown(cli);
			return result;
		} else {
			asprintf(err_str, "SAMR connection to machine %s "
				 "failed. Error was %s, but LANMAN password "
				 "changed are disabled\n",
				nt_errstr(result), remote_machine);
			cli_shutdown(cli);
			return NT_STATUS_UNSUCCESSFUL;
		}
	}
}
예제 #17
0
파일: masktest.c 프로젝트: AllardJ/Tomato
/***************************************************** 
return a connection to a server
*******************************************************/
struct cli_state *connect_one(char *share)
{
	struct cli_state *c;
	struct nmb_name called, calling;
	char *server_n;
	char *server;
	struct in_addr ip;
	extern struct in_addr ipzero;

	server = share+2;
	share = strchr(server,'\\');
	if (!share) return NULL;
	*share = 0;
	share++;

	server_n = server;
	
	ip = ipzero;

	make_nmb_name(&calling, "masktest", 0x0, "");
	make_nmb_name(&called , server, 0x20, "");

 again:
	ip = ipzero;

	/* have to open a new connection */
	if (!(c=cli_initialise(NULL)) || (cli_set_port(c, 139) == 0) ||
	    !cli_connect(c, server_n, &ip)) {
		DEBUG(0,("Connection to %s failed\n", server_n));
		return NULL;
	}

	if (!cli_session_request(c, &calling, &called)) {
		DEBUG(0,("session request to %s failed\n", called.name));
		cli_shutdown(c);
		if (strcmp(called.name, "*SMBSERVER")) {
			make_nmb_name(&called , "*SMBSERVER", 0x20, "");
			goto again;
		}
		return NULL;
	}

	DEBUG(4,(" session request ok\n"));

	if (!cli_negprot(c)) {
		DEBUG(0,("protocol negotiation failed\n"));
		cli_shutdown(c);
		return NULL;
	}

	if (!got_pass) {
		char *pass = getpass("Password: "******"session setup failed: %s\n", cli_errstr(c)));
		return NULL;
	}

	/*
	 * These next two lines are needed to emulate
	 * old client behaviour for people who have
	 * scripts based on client output.
	 * QUESTION ? Do we want to have a 'client compatibility
	 * mode to turn these on/off ? JRA.
	 */

	if (*c->server_domain || *c->server_os || *c->server_type)
		DEBUG(1,("Domain=[%s] OS=[%s] Server=[%s]\n",
			c->server_domain,c->server_os,c->server_type));
	
	DEBUG(4,(" session setup ok\n"));

	if (!cli_send_tconX(c, share, "?????",
			    password, strlen(password)+1)) {
		DEBUG(0,("tree connect failed: %s\n", cli_errstr(c)));
		cli_shutdown(c);
		return NULL;
	}

	DEBUG(4,(" tconx ok\n"));

	return c;
}
예제 #18
0
static struct cli_state *server_cryptkey(TALLOC_CTX *mem_ctx)
{
	struct cli_state *cli = NULL;
	fstring desthost;
	struct in_addr dest_ip;
	const char *p;
	char *pserver;
	BOOL connected_ok = False;

	if (!(cli = cli_initialise()))
		return NULL;

	/* security = server just can't function with spnego */
	cli->use_spnego = False;

        pserver = talloc_strdup(mem_ctx, lp_passwordserver());
	p = pserver;

        while(next_token( &p, desthost, LIST_SEP, sizeof(desthost))) {
		standard_sub_basic(current_user_info.smb_name, current_user_info.domain,
				   desthost, sizeof(desthost));
		strupper_m(desthost);

		if(!resolve_name( desthost, &dest_ip, 0x20)) {
			DEBUG(1,("server_cryptkey: Can't resolve address for %s\n",desthost));
			continue;
		}

		if (ismyip(dest_ip)) {
			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) */

		if (!grab_server_mutex(desthost)) {
			return NULL;
		}

		if (cli_connect(cli, desthost, &dest_ip)) {
			DEBUG(3,("connected to password server %s\n",desthost));
			connected_ok = True;
			break;
		}
	}

	if (!connected_ok) {
		release_server_mutex();
		DEBUG(0,("password server not available\n"));
		cli_shutdown(cli);
		return NULL;
	}
	
	if (!attempt_netbios_session_request(&cli, global_myname(), 
					     desthost, &dest_ip)) {
		release_server_mutex();
		DEBUG(1,("password server fails session request\n"));
		cli_shutdown(cli);
		return NULL;
	}
	
	if (strequal(desthost,myhostname())) {
		exit_server_cleanly("Password server loop!");
	}
	
	DEBUG(3,("got session\n"));

	if (!cli_negprot(cli)) {
		DEBUG(1,("%s rejected the negprot\n",desthost));
		release_server_mutex();
		cli_shutdown(cli);
		return NULL;
	}

	if (cli->protocol < PROTOCOL_LANMAN2 ||
	    !(cli->sec_mode & NEGOTIATE_SECURITY_USER_LEVEL)) {
		DEBUG(1,("%s isn't in user level security mode\n",desthost));
		release_server_mutex();
		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... 
	*/

	if (!NT_STATUS_IS_OK(cli_session_setup(cli, "", "", 0, "", 0,
					       ""))) {
		DEBUG(0,("%s rejected the initial session setup (%s)\n",
			 desthost, cli_errstr(cli)));
		release_server_mutex();
		cli_shutdown(cli);
		return NULL;
	}
	
	release_server_mutex();

	DEBUG(3,("password server OK\n"));
	
	return cli;
}
예제 #19
0
파일: smbw.c 프로젝트: livebox/livebox2
/***************************************************** 
return a connection to a server (existing or new)
*******************************************************/
struct smbw_server *smbw_server(char *server, char *share)
{
	struct smbw_server *srv=NULL;
	struct cli_state c;
	char *username;
	char *password;
	char *workgroup;
	struct nmb_name called, calling;
	char *p, *server_n = server;
	fstring group;
	pstring ipenv;
	struct in_addr ip;

	zero_ip(&ip);
	ZERO_STRUCT(c);

	get_auth_data_fn(server, share, &workgroup, &username, &password);

	/* try to use an existing connection */
	for (srv=smbw_srvs;srv;srv=srv->next) {
		if (strcmp(server,srv->server_name)==0 &&
		    strcmp(share,srv->share_name)==0 &&
		    strcmp(workgroup,srv->workgroup)==0 &&
		    strcmp(username, srv->username) == 0) 
			return srv;
	}

	if (server[0] == 0) {
		errno = EPERM;
		return NULL;
	}

	make_nmb_name(&calling, global_myname, 0x0);
	make_nmb_name(&called , server, 0x20);

	DEBUG(4,("server_n=[%s] server=[%s]\n", server_n, server));

	if ((p=strchr(server_n,'#')) && 
	    (strcmp(p+1,"1D")==0 || strcmp(p+1,"01")==0)) {
		struct in_addr sip;
		pstring s;

		fstrcpy(group, server_n);
		p = strchr(group,'#');
		*p = 0;
		
		/* cache the workgroup master lookup */
		slprintf(s,sizeof(s)-1,"MASTER_%s", group);
		if (!(server_n = smbw_getshared(s))) {
			if (!find_master_ip(group, &sip)) {
				errno = ENOENT;
				return NULL;
			}
			fstrcpy(group, inet_ntoa(sip));
			server_n = group;
			smbw_setshared(s,server_n);
		}
	}

	DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n, server));

 again:
	slprintf(ipenv,sizeof(ipenv)-1,"HOST_%s", server_n);

	zero_ip(&ip);
	if ((p=smbw_getshared(ipenv))) {
		ip = *(interpret_addr2(p));
	}

	/* have to open a new connection */
	if (!cli_initialise(&c) || !cli_connect(&c, server_n, &ip)) {
		errno = ENOENT;
		return NULL;
	}

	if (!cli_session_request(&c, &calling, &called)) {
		cli_shutdown(&c);
		if (strcmp(called.name, "*SMBSERVER")) {
			make_nmb_name(&called , "*SMBSERVER", 0x20);
			goto again;
		}
		errno = ENOENT;
		return NULL;
	}

	DEBUG(4,(" session request ok\n"));

	if (!cli_negprot(&c)) {
		cli_shutdown(&c);
		errno = ENOENT;
		return NULL;
	}

	if (!cli_session_setup(&c, username, 
			       password, strlen(password),
			       password, strlen(password),
			       workgroup) &&
	    /* try an anonymous login if it failed */
	    !cli_session_setup(&c, "", "", 1,"", 0, workgroup)) {
		cli_shutdown(&c);
		errno = EPERM;
		return NULL;
	}

	DEBUG(4,(" session setup ok\n"));

	if (!cli_send_tconX(&c, share, "?????",
			    password, strlen(password)+1)) {
		errno = smbw_errno(&c);
		cli_shutdown(&c);
		return NULL;
	}

	smbw_setshared(ipenv,inet_ntoa(ip));
	
	DEBUG(4,(" tconx ok\n"));

	srv = (struct smbw_server *)malloc(sizeof(*srv));
	if (!srv) {
		errno = ENOMEM;
		goto failed;
	}

	ZERO_STRUCTP(srv);

	srv->cli = c;

	srv->dev = (dev_t)(str_checksum(server) ^ str_checksum(share));

	srv->server_name = strdup(server);
	if (!srv->server_name) {
		errno = ENOMEM;
		goto failed;
	}

	srv->share_name = strdup(share);
	if (!srv->share_name) {
		errno = ENOMEM;
		goto failed;
	}

	srv->workgroup = strdup(workgroup);
	if (!srv->workgroup) {
		errno = ENOMEM;
		goto failed;
	}

	srv->username = strdup(username);
	if (!srv->username) {
		errno = ENOMEM;
		goto failed;
	}

	/* some programs play with file descriptors fairly intimately. We
	   try to get out of the way by duping to a high fd number */
	if (fcntl(SMBW_CLI_FD + srv->cli.fd, F_GETFD) && errno == EBADF) {
		if (dup2(srv->cli.fd,SMBW_CLI_FD+srv->cli.fd) == 
		    srv->cli.fd+SMBW_CLI_FD) {
			close(srv->cli.fd);
			srv->cli.fd += SMBW_CLI_FD;
		}
	}

	DLIST_ADD(smbw_srvs, srv);

	return srv;

 failed:
	cli_shutdown(&c);
	if (!srv) return NULL;

	SAFE_FREE(srv->server_name);
	SAFE_FREE(srv->share_name);
	SAFE_FREE(srv);
	return NULL;
}
예제 #20
0
/*************************************************************
change a password on a remote machine using IPC calls
*************************************************************/
BOOL remote_password_change(const char *remote_machine, const char *user_name, 
			    const char *old_passwd, const char *new_passwd,
			    char *err_str, size_t err_str_len)
{
	struct nmb_name calling, called;
	struct cli_state cli;
	struct in_addr ip;

	*err_str = '\0';

	if(!resolve_name( remote_machine, &ip, 0x20)) {
		slprintf(err_str, err_str_len-1, "unable to find an IP address for machine %s.\n",
			remote_machine );
		return False;
	}
 
	ZERO_STRUCT(cli);
 
	if (!cli_initialise(&cli) || !cli_connect(&cli, remote_machine, &ip)) {
		slprintf(err_str, err_str_len-1, "unable to connect to SMB server on machine %s. Error was : %s.\n",
			remote_machine, cli_errstr(&cli) );
		return False;
	}
  
	make_nmb_name(&calling, global_myname() , 0x0);
	make_nmb_name(&called , remote_machine, 0x20);
	
	if (!cli_session_request(&cli, &calling, &called)) {
		slprintf(err_str, err_str_len-1, "machine %s rejected the session setup. Error was : %s.\n",
			remote_machine, cli_errstr(&cli) );
		cli_shutdown(&cli);
		return False;
	}
  
	cli.protocol = PROTOCOL_NT1;

	if (!cli_negprot(&cli)) {
		slprintf(err_str, err_str_len-1, "machine %s rejected the negotiate protocol. Error was : %s.\n",        
			remote_machine, cli_errstr(&cli) );
		cli_shutdown(&cli);
		return False;
	}
  
	/*
	 * We should connect as the anonymous user here, in case
	 * the server has "must change password" checked...
	 * Thanks to <*****@*****.**> for this fix.
	 */

	if (!cli_session_setup(&cli, "", "", 0, "", 0, "")) {
		slprintf(err_str, err_str_len-1, "machine %s rejected the session setup. Error was : %s.\n",        
			remote_machine, cli_errstr(&cli) );
		cli_shutdown(&cli);
		return False;
	}               

	if (!cli_send_tconX(&cli, "IPC$", "IPC", "", 1)) {
		slprintf(err_str, err_str_len-1, "machine %s rejected the tconX on the IPC$ share. Error was : %s.\n",
			remote_machine, cli_errstr(&cli) );
		cli_shutdown(&cli);
		return False;
	}

	if(!cli_oem_change_password(&cli, user_name, new_passwd, old_passwd)) {
		slprintf(err_str, err_str_len-1, "machine %s rejected the password change: Error was : %s.\n",
			remote_machine, cli_errstr(&cli) );
		cli_shutdown(&cli);
		return False;
	}
	
	cli_shutdown(&cli);
	return True;
}
예제 #21
0
static int join_domain_byuser(char *domain, const char *remote,
			      char *username, char *password)
{
	/* libsmb variables */

	pstring pdc_name;
	struct nmb_name calling, called;
	struct ntuser_creds creds;
	struct cli_state cli;
	fstring acct_name;
	struct in_addr dest_ip;
	TALLOC_CTX *mem_ctx;

	/* rpc variables */

	POLICY_HND lsa_pol, sam_pol, domain_pol, user_pol;
	DOM_SID domain_sid;
	uint32 user_rid;

	/* Password stuff */

	char *machine_pwd;
	int plen = 0;
	uchar pwbuf[516], ntpw[16], sess_key[16];
	SAM_USERINFO_CTR ctr;
	SAM_USER_INFO_24 p24;
	SAM_USER_INFO_10 p10;

	/* Misc */

	NTSTATUS result;
	int retval = 1;

	pstrcpy(pdc_name, remote ? remote : "");

	/* Connect to remote machine */

	ZERO_STRUCT(cli);
	ZERO_STRUCT(creds);
	ZERO_STRUCT(dest_ip); /* Make sure no nasty surprises */

	if (!(mem_ctx = talloc_init())) {
		DEBUG(0, ("Could not initialise talloc context\n"));
		goto done;
	}

	if (!cli_initialise(&cli)) {
		DEBUG(0, ("Could not initialise client structure\n"));
		goto done;
	}

	init_rpcclient_creds(&creds, username, domain, password);
	cli_init_creds(&cli, &creds);

	/*
	 * If we are given a remote machine assume this is the PDC.
	 */
	
	if(remote == NULL || !strcmp(remote, "*")) {
                struct in_addr *ip_list;
                int addr_count;
                if (!get_dc_list(True /* PDC only*/, domain, &ip_list, &addr_count)) {
			fprintf(stderr, "Unable to find the domain controller for domain %s.\n", domain);
			return 1;
		}
		if ((addr_count < 1) || (is_zero_ip(ip_list[0]))) {
			fprintf(stderr, "Incorrect entries returned when finding the domain controller for domain %s.\n", domain);
			return 1;
		}

		if (!lookup_dc_name(global_myname, domain, &ip_list[0], pdc_name)) {
			fprintf(stderr, "Unable to lookup the name for the domain controller for domain %s.\n", domain);
			return 1;
		}
		dest_ip = ip_list[0];
	}

	make_nmb_name(&called, pdc_name, 0x20);
	make_nmb_name(&calling, dns_to_netbios_name(global_myname), 0);

	if (!cli_establish_connection(&cli, pdc_name, &dest_ip, &calling, 
				      &called, "IPC$", "IPC", False, True)) {
		if (!NT_STATUS_IS_OK(cli_nt_error(&cli))) {
			DEBUG(0, ("Error connecting to %s - %s\n", pdc_name,cli_errstr(&cli)));
		} else {
			DEBUG(0, ("Error connecting to %s\n", pdc_name));
		}
		goto done;
	}

	/* Fetch domain sid */

	if (!cli_nt_session_open(&cli, PIPE_LSARPC)) {
		DEBUG(0, ("Error connecting to SAM pipe\n"));
		goto done;
	}


	CHECK_RPC_ERR(cli_lsa_open_policy(&cli, mem_ctx, True,
					  SEC_RIGHTS_MAXIMUM_ALLOWED,
					  &lsa_pol),
		      "error opening lsa policy handle");

	CHECK_RPC_ERR(cli_lsa_query_info_policy(&cli, mem_ctx, &lsa_pol,
						5, domain, &domain_sid),
		      "error querying info policy");

	cli_lsa_close(&cli, mem_ctx, &lsa_pol);

	cli_nt_session_close(&cli); /* Done with this pipe */

	/* Create domain user */

	if (!cli_nt_session_open(&cli, PIPE_SAMR)) {
		DEBUG(0, ("Error connecting to SAM pipe\n"));
		goto done;
	}

	CHECK_RPC_ERR(cli_samr_connect(&cli, mem_ctx, 
				       SEC_RIGHTS_MAXIMUM_ALLOWED,
				       &sam_pol),
		      "could not connect to SAM database");

	
	CHECK_RPC_ERR(cli_samr_open_domain(&cli, mem_ctx, &sam_pol,
					   SEC_RIGHTS_MAXIMUM_ALLOWED,
					   &domain_sid, &domain_pol),
		      "could not open domain");

	/* Create domain user */

	fstrcpy(acct_name, global_myname);
	fstrcat(acct_name, "$");

	strlower(acct_name);

	{
		uint32 unknown = 0xe005000b;

		result = cli_samr_create_dom_user(&cli, mem_ctx, &domain_pol,
						  acct_name, ACB_WSTRUST,
						  unknown, &user_pol, 
						  &user_rid);
	}


	if (NT_STATUS_IS_OK(result)) {

		/* We *must* do this.... don't ask... */
	  
		CHECK_RPC_ERR_DEBUG(cli_samr_close(&cli, mem_ctx, &user_pol), ("error closing user policy"));
		result = NT_STATUS_USER_EXISTS;
	}

	if (NT_STATUS_V(result) == NT_STATUS_V(NT_STATUS_USER_EXISTS)) {
		uint32 num_rids, *name_types, *user_rids;
		uint32 flags = 0x3e8;
		const char *names;
		
		/* Look up existing rid */
		
		names = (char *)&acct_name[0];

		CHECK_RPC_ERR_DEBUG(
			cli_samr_lookup_names(&cli, mem_ctx,
					      &domain_pol, flags,
					      1, &names, &num_rids,
					      &user_rids, &name_types),
			("error looking up rid for user %s: %s\n",
			 acct_name, get_nt_error_msg(result)));

		if (name_types[0] != SID_NAME_USER) {
			DEBUG(0, ("%s is not a user account\n", acct_name));
			goto done;
		}

		user_rid = user_rids[0];
		
		/* Open handle on user */

		CHECK_RPC_ERR_DEBUG(
			cli_samr_open_user(&cli, mem_ctx, &domain_pol,
					   SEC_RIGHTS_MAXIMUM_ALLOWED,
					   user_rid, &user_pol),
			("could not re-open existing user %s: %s\n",
			 acct_name, get_nt_error_msg(result)));
		
	} else if (!NT_STATUS_IS_OK(result)) {
		DEBUG(0, ("error creating domain user: %s\n",
			  get_nt_error_msg(result)));
		goto done;
	}

	/* Create a random machine account password */

	{
		UNISTR2 upw;	/* Unicode password */

		upw.buffer = (uint16 *)talloc_zero(mem_ctx, 0xc * 
						   sizeof(uint16));

		upw.uni_str_len = 0xc;
		upw.uni_max_len = 0xc;

		machine_pwd = (char *)upw.buffer;
		plen = upw.uni_str_len * 2;
		generate_random_buffer((unsigned char *)machine_pwd, plen, True);

		encode_pw_buffer((char *)pwbuf, machine_pwd, plen, False);

		mdfour( ntpw, (unsigned char *)upw.buffer, plen);
	}

	/* Set password on machine account */

	ZERO_STRUCT(ctr);
	ZERO_STRUCT(p24);

	init_sam_user_info24(&p24, (char *)pwbuf,24);

	ctr.switch_value = 24;
	ctr.info.id24 = &p24;

	/* I don't think this is quite the right place for this
	   calculation.  It should be moved somewhere where the credentials
	   are calculated. )-: */

	mdfour(sess_key, cli.pwd.smb_nt_pwd, 16);

	CHECK_RPC_ERR(cli_samr_set_userinfo(&cli, mem_ctx, &user_pol, 24, 
					    sess_key, &ctr),
		      "error setting trust account password");

	/* Why do we have to try to (re-)set the ACB to be the same as what
	   we passed in the samr_create_dom_user() call?  When a NT
	   workstation is joined to a domain by an administrator the
	   acb_info is set to 0x80.  For a normal user with "Add
	   workstations to the domain" rights the acb_info is 0x84.  I'm
	   not sure whether it is supposed to make a difference or not.  NT
	   seems to cope with either value so don't bomb out if the set
	   userinfo2 level 0x10 fails.  -tpot */

	ZERO_STRUCT(ctr);
	ctr.switch_value = 0x10;
	ctr.info.id10 = &p10;

	init_sam_user_info10(&p10, ACB_WSTRUST);

	/* Ignoring the return value is necessary for joining a domain
	   as a normal user with "Add workstation to domain" privilege. */

	result = cli_samr_set_userinfo2(&cli, mem_ctx, &user_pol, 0x10, 
					sess_key, &ctr);

	/* Now store the secret in the secrets database */

	strupper(domain);

	if (!secrets_store_domain_sid(domain, &domain_sid) ||
	    !secrets_store_trust_account_password(domain, ntpw)) {
		DEBUG(0, ("error storing domain secrets\n"));
		goto done;
	}

	retval = 0;		/* Success! */

 done:
	/* Close down pipe - this will clean up open policy handles */

	if (cli.nt_pipe_fnum)
		cli_nt_session_close(&cli);

	/* Display success or failure */

	if (retval != 0) {
		trust_password_delete(domain);
		fprintf(stderr,"Unable to join domain %s.\n",domain);
	} else {
		printf("Joined domain %s.\n",domain);
	}
	
	return retval;
}