示例#1
0
static bool test_connect_service(struct torture_context *tctx,
				 struct libnet_context *ctx,
				 const struct ndr_interface_table *iface,
				 const char *binding_string,
				 const char *hostname,
				 const enum libnet_RpcConnect_level level,
				 bool badcreds, NTSTATUS expected_status)
{
	NTSTATUS status;
	struct libnet_RpcConnect connect_r;
	ZERO_STRUCT(connect_r);

	connect_r.level            = level;
	connect_r.in.binding       = binding_string;
	connect_r.in.name          = hostname;
	connect_r.in.dcerpc_iface  = iface;

	/* if bad credentials are needed, set baduser%badpassword instead
	   of default commandline-passed credentials */
	if (badcreds) {
		cli_credentials_set_username(ctx->cred, "baduser", CRED_SPECIFIED);
		cli_credentials_set_password(ctx->cred, "badpassword", CRED_SPECIFIED);
	}

	status = libnet_RpcConnect(ctx, ctx, &connect_r);

	if (!NT_STATUS_EQUAL(status, expected_status)) {
		torture_comment(tctx, "Connecting to rpc service %s on %s.\n\tFAILED. Expected: %s."
		       "Received: %s\n",
		       connect_r.in.dcerpc_iface->name, connect_r.in.binding, nt_errstr(expected_status),
		       nt_errstr(status));

		return false;
	}

	torture_comment(tctx, "PASSED. Expected: %s, received: %s\n", nt_errstr(expected_status),
	       nt_errstr(status));

	if (connect_r.level == LIBNET_RPC_CONNECT_DC_INFO && NT_STATUS_IS_OK(status)) {
		torture_comment(tctx, "Domain Controller Info:\n");
		torture_comment(tctx, "\tDomain Name:\t %s\n", connect_r.out.domain_name);
		torture_comment(tctx, "\tDomain SID:\t %s\n", dom_sid_string(ctx, connect_r.out.domain_sid));
		torture_comment(tctx, "\tRealm:\t\t %s\n", connect_r.out.realm);
		torture_comment(tctx, "\tGUID:\t\t %s\n", GUID_string(ctx, connect_r.out.guid));

	} else if (!NT_STATUS_IS_OK(status)) {
		torture_comment(tctx, "Error string: %s\n", connect_r.out.error_string);
	}

	return true;
}
示例#2
0
NTSTATUS libnet_AddShare(struct libnet_context *ctx,
			 TALLOC_CTX *mem_ctx, struct libnet_AddShare *r)
{
	NTSTATUS status;
	struct libnet_RpcConnect c;
	struct srvsvc_NetShareAdd s;
	union srvsvc_NetShareInfo info;

	c.level              = LIBNET_RPC_CONNECT_SERVER;
	c.in.name            = r->in.server_name;
	c.in.dcerpc_iface    = &ndr_table_srvsvc;

	status = libnet_RpcConnect(ctx, mem_ctx, &c);
	if (!NT_STATUS_IS_OK(status)) {
		r->out.error_string = talloc_asprintf(mem_ctx,
						      "Connection to SRVSVC pipe of server %s "
						      "failed: %s",
						      r->in.server_name, nt_errstr(status));
		return status;
	}

	info.info2		= &r->in.share;

	s.in.level 		= 2;
	s.in.info		= &info;
	s.in.server_unc		= talloc_asprintf(mem_ctx, "\\\\%s", r->in.server_name);
 
	status = dcerpc_srvsvc_NetShareAdd(c.out.dcerpc_pipe, mem_ctx, &s);	

	if (!NT_STATUS_IS_OK(status)) {
		r->out.error_string = talloc_asprintf(mem_ctx,
						      "srvsvc_NetShareAdd '%s' on server '%s' failed"
						      ": %s",
						      r->in.share.name, r->in.server_name, 
						      nt_errstr(status));
	} else if (!W_ERROR_IS_OK(s.out.result)) {
		r->out.error_string = talloc_asprintf(mem_ctx,
						      "srvsvc_NetShareAdd '%s' on server '%s' failed"
						      ": %s",
						      r->in.share.name, r->in.server_name, 
						      win_errstr(s.out.result));
		status = werror_to_ntstatus(s.out.result);
	}

	talloc_free(c.out.dcerpc_pipe);
	
	return status;
}
示例#3
0
/*
 * do a domain join using DCERPC/SAMR calls
 * - connect to the LSA pipe, to try and find out information about the domain
 * - create a secondary connection to SAMR pipe
 * - do a samr_Connect to get a policy handle
 * - do a samr_LookupDomain to get the domain sid
 * - do a samr_OpenDomain to get a domain handle
 * - do a samr_CreateAccount to try and get a new account 
 * 
 * If that fails, do:
 * - do a samr_LookupNames to get the users rid
 * - do a samr_OpenUser to get a user handle
 * - potentially delete and recreate the user
 * - assert the account is of the right type with samrQueryUserInfo
 * 
 * - call libnet_SetPassword_samr_handle to set the password,
 *   and pass a samr_UserInfo21 struct to set full_name and the account flags
 *
 * - do some ADS specific things when we join as Domain Controller,
 *    look at libnet_joinADSDomain() for the details
 */
NTSTATUS libnet_JoinDomain(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_JoinDomain *r)
{
	TALLOC_CTX *tmp_ctx;

	NTSTATUS status, cu_status;

	struct libnet_RpcConnect *connect_with_info;
	struct dcerpc_pipe *samr_pipe;

	struct samr_Connect sc;
	struct policy_handle p_handle;
	struct samr_OpenDomain od;
	struct policy_handle d_handle;
	struct samr_LookupNames ln;
	struct samr_Ids rids, types;
	struct samr_OpenUser ou;
	struct samr_CreateUser2 cu;
	struct policy_handle *u_handle = NULL;
	struct samr_QueryUserInfo qui;
	union samr_UserInfo *uinfo;
	struct samr_UserInfo21 u_info21;
	union libnet_SetPassword r2;
	struct samr_GetUserPwInfo pwp;
	struct samr_PwInfo info;
	struct lsa_String samr_account_name;
	
	uint32_t acct_flags, old_acct_flags;
	uint32_t rid, access_granted;
	int policy_min_pw_len = 0;

	struct dom_sid *account_sid = NULL;
	const char *password_str = NULL;
	
	r->out.error_string = NULL;
	r2.samr_handle.out.error_string = NULL;
	
	tmp_ctx = talloc_named(mem_ctx, 0, "libnet_Join temp context");
	if (!tmp_ctx) {
		r->out.error_string = NULL;
		return NT_STATUS_NO_MEMORY;
	}
	
	u_handle = talloc(tmp_ctx, struct policy_handle);
	if (!u_handle) {
		r->out.error_string = NULL;
		talloc_free(tmp_ctx);
		return NT_STATUS_NO_MEMORY;
	}
	
	connect_with_info = talloc_zero(tmp_ctx, struct libnet_RpcConnect);
	if (!connect_with_info) {
		r->out.error_string = NULL;
		talloc_free(tmp_ctx);
		return NT_STATUS_NO_MEMORY;
	}

	/* prepare connect to the SAMR pipe of PDC */
	if (r->in.level == LIBNET_JOINDOMAIN_AUTOMATIC) {
		connect_with_info->in.binding = NULL;
		connect_with_info->in.name    = r->in.domain_name;
	} else {
		connect_with_info->in.binding = r->in.binding;
		connect_with_info->in.name    = NULL;
	}

	/* This level makes a connection to the LSA pipe on the way,
	 * to get some useful bits of information about the domain */
	connect_with_info->level              = LIBNET_RPC_CONNECT_DC_INFO;
	connect_with_info->in.dcerpc_iface    = &ndr_table_samr;

	/*
	  establish the SAMR connection
	*/
	status = libnet_RpcConnect(ctx, tmp_ctx, connect_with_info);
	if (!NT_STATUS_IS_OK(status)) {
		if (r->in.binding) {
			r->out.error_string = talloc_asprintf(mem_ctx,
							      "Connection to SAMR pipe of DC %s failed: %s",
							      r->in.binding, connect_with_info->out.error_string);
		} else {
			r->out.error_string = talloc_asprintf(mem_ctx,
							      "Connection to SAMR pipe of PDC for %s failed: %s",
							      r->in.domain_name, connect_with_info->out.error_string);
		}
		talloc_free(tmp_ctx);
		return status;
	}

	samr_pipe = connect_with_info->out.dcerpc_pipe;

	status = dcerpc_pipe_auth(tmp_ctx, &samr_pipe,
				  connect_with_info->out.dcerpc_pipe->binding, 
				  &ndr_table_samr, ctx->cred, ctx->lp_ctx);
	if (!NT_STATUS_IS_OK(status)) {
		r->out.error_string = talloc_asprintf(mem_ctx,
						"SAMR bind failed: %s",
						nt_errstr(status));
		talloc_free(tmp_ctx);
		return status;
	}

	/* prepare samr_Connect */
	ZERO_STRUCT(p_handle);
	sc.in.system_name = NULL;
	sc.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
	sc.out.connect_handle = &p_handle;

	/* 2. do a samr_Connect to get a policy handle */
	status = dcerpc_samr_Connect_r(samr_pipe->binding_handle, tmp_ctx, &sc);
	if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(sc.out.result)) {
		status = sc.out.result;
	}
	if (!NT_STATUS_IS_OK(status)) {
		r->out.error_string = talloc_asprintf(mem_ctx,
						"samr_Connect failed: %s",
						nt_errstr(status));
		talloc_free(tmp_ctx);
		return status;
	}

	/* If this is a connection on ncacn_ip_tcp to Win2k3 SP1, we don't get back this useful info */
	if (!connect_with_info->out.domain_name) {
		if (r->in.level == LIBNET_JOINDOMAIN_AUTOMATIC) {
			connect_with_info->out.domain_name = talloc_strdup(tmp_ctx, r->in.domain_name);
		} else {
			/* Bugger, we just lost our way to automatically find the domain name */
			connect_with_info->out.domain_name = talloc_strdup(tmp_ctx, lpcfg_workgroup(ctx->lp_ctx));
			connect_with_info->out.realm = talloc_strdup(tmp_ctx, lpcfg_realm(ctx->lp_ctx));
		}
	}

	/* Perhaps we didn't get a SID above, because we are against ncacn_ip_tcp */
	if (!connect_with_info->out.domain_sid) {
		struct lsa_String name;
		struct samr_LookupDomain l;
		struct dom_sid2 *sid = NULL;
		name.string = connect_with_info->out.domain_name;
		l.in.connect_handle = &p_handle;
		l.in.domain_name = &name;
		l.out.sid = &sid;
		
		status = dcerpc_samr_LookupDomain_r(samr_pipe->binding_handle, tmp_ctx, &l);
		if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(l.out.result)) {
			status = l.out.result;
		}
		if (!NT_STATUS_IS_OK(status)) {
			r->out.error_string = talloc_asprintf(mem_ctx,
							      "SAMR LookupDomain failed: %s",
							      nt_errstr(status));
			talloc_free(tmp_ctx);
			return status;
		}
		connect_with_info->out.domain_sid = *l.out.sid;
	}

	/* prepare samr_OpenDomain */
	ZERO_STRUCT(d_handle);
	od.in.connect_handle = &p_handle;
	od.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
	od.in.sid = connect_with_info->out.domain_sid;
	od.out.domain_handle = &d_handle;

	/* do a samr_OpenDomain to get a domain handle */
	status = dcerpc_samr_OpenDomain_r(samr_pipe->binding_handle, tmp_ctx, &od);
	if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(od.out.result)) {
		status = od.out.result;
	}
	if (!NT_STATUS_IS_OK(status)) {
		r->out.error_string = talloc_asprintf(mem_ctx,
						      "samr_OpenDomain for [%s] failed: %s",
						      dom_sid_string(tmp_ctx, connect_with_info->out.domain_sid),
						      nt_errstr(status));
		talloc_free(tmp_ctx);
		return status;
	}
	
	/* prepare samr_CreateUser2 */
	ZERO_STRUCTP(u_handle);
	cu.in.domain_handle  = &d_handle;
	cu.in.access_mask     = SEC_FLAG_MAXIMUM_ALLOWED;
	samr_account_name.string = r->in.account_name;
	cu.in.account_name    = &samr_account_name;
	cu.in.acct_flags      = r->in.acct_type;
	cu.out.user_handle    = u_handle;
	cu.out.rid            = &rid;
	cu.out.access_granted = &access_granted;

	/* do a samr_CreateUser2 to get an account handle, or an error */
	cu_status = dcerpc_samr_CreateUser2_r(samr_pipe->binding_handle, tmp_ctx, &cu);
	if (NT_STATUS_IS_OK(cu_status) && !NT_STATUS_IS_OK(cu.out.result)) {
		cu_status = cu.out.result;
	}
	status = cu_status;
	if (NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS)) {
		/* prepare samr_LookupNames */
		ln.in.domain_handle = &d_handle;
		ln.in.num_names = 1;
		ln.in.names = talloc_array(tmp_ctx, struct lsa_String, 1);
		ln.out.rids = &rids;
		ln.out.types = &types;
		if (!ln.in.names) {
			r->out.error_string = NULL;
			talloc_free(tmp_ctx);
			return NT_STATUS_NO_MEMORY;
		}
		ln.in.names[0].string = r->in.account_name;
		
		/* 5. do a samr_LookupNames to get the users rid */
		status = dcerpc_samr_LookupNames_r(samr_pipe->binding_handle, tmp_ctx, &ln);
		if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(ln.out.result)) {
			status = ln.out.result;
		}
		if (!NT_STATUS_IS_OK(status)) {
			r->out.error_string = talloc_asprintf(mem_ctx,
						"samr_LookupNames for [%s] failed: %s",
						r->in.account_name,
						nt_errstr(status));
			talloc_free(tmp_ctx);
			return status;
		}
		
		/* check if we got one RID for the user */
		if (ln.out.rids->count != 1) {
			r->out.error_string = talloc_asprintf(mem_ctx,
							      "samr_LookupNames for [%s] returns %d RIDs",
							      r->in.account_name, ln.out.rids->count);
			talloc_free(tmp_ctx);
			return NT_STATUS_INVALID_PARAMETER;
		}
		
		/* prepare samr_OpenUser */
		ZERO_STRUCTP(u_handle);
		ou.in.domain_handle = &d_handle;
		ou.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
		ou.in.rid = ln.out.rids->ids[0];
		rid = ou.in.rid;
		ou.out.user_handle = u_handle;
		
		/* 6. do a samr_OpenUser to get a user handle */
		status = dcerpc_samr_OpenUser_r(samr_pipe->binding_handle, tmp_ctx, &ou);
		if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(ou.out.result)) {
			status = ou.out.result;
		}
		if (!NT_STATUS_IS_OK(status)) {
			r->out.error_string = talloc_asprintf(mem_ctx,
							"samr_OpenUser for [%s] failed: %s",
							r->in.account_name,
							nt_errstr(status));
			talloc_free(tmp_ctx);
			return status;
		}

		if (r->in.recreate_account) {
			struct samr_DeleteUser d;
			d.in.user_handle = u_handle;
			d.out.user_handle = u_handle;
			status = dcerpc_samr_DeleteUser_r(samr_pipe->binding_handle, mem_ctx, &d);
			if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(d.out.result)) {
				status = d.out.result;
			}
			if (!NT_STATUS_IS_OK(status)) {
				r->out.error_string = talloc_asprintf(mem_ctx,
								      "samr_DeleteUser (for recreate) of [%s] failed: %s",
								      r->in.account_name,
								      nt_errstr(status));
				talloc_free(tmp_ctx);
				return status;
			}

			/* We want to recreate, so delete and another samr_CreateUser2 */
			
			/* &cu filled in above */
			status = dcerpc_samr_CreateUser2_r(samr_pipe->binding_handle, tmp_ctx, &cu);
			if (NT_STATUS_IS_OK(status) && !NT_STATUS_IS_OK(cu.out.result)) {
				status = cu.out.result;
			}
			if (!NT_STATUS_IS_OK(status)) {
				r->out.error_string = talloc_asprintf(mem_ctx,
								      "samr_CreateUser2 (recreate) for [%s] failed: %s",
								      r->in.account_name, nt_errstr(status));
				talloc_free(tmp_ctx);
				return status;
			}
		}
	} else if (!NT_STATUS_IS_OK(status)) {
示例#4
0
NTSTATUS libnet_SamSync_netlogon(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, struct libnet_SamSync *r)
{
	NTSTATUS nt_status, dbsync_nt_status;
	TALLOC_CTX *samsync_ctx, *loop_ctx, *delta_ctx;
	struct netlogon_creds_CredentialState *creds;
	struct netr_DatabaseSync dbsync;
	struct netr_Authenticator credential, return_authenticator;
	struct netr_DELTA_ENUM_ARRAY *delta_enum_array = NULL;
	struct cli_credentials *machine_account;
	struct dcerpc_pipe *p;
	struct libnet_context *machine_net_ctx;
	struct libnet_RpcConnect *c;
	struct libnet_SamSync_state *state;
	const enum netr_SamDatabaseID database_ids[] = {SAM_DATABASE_DOMAIN, SAM_DATABASE_BUILTIN, SAM_DATABASE_PRIVS}; 
	unsigned int i;

	samsync_ctx = talloc_named(mem_ctx, 0, "SamSync top context");

	if (!r->in.machine_account) { 
		machine_account = cli_credentials_init(samsync_ctx);
		if (!machine_account) {
			talloc_free(samsync_ctx);
			return NT_STATUS_NO_MEMORY;
		}
		cli_credentials_set_conf(machine_account, ctx->lp_ctx);
		nt_status = cli_credentials_set_machine_account(machine_account, ctx->lp_ctx);
		if (!NT_STATUS_IS_OK(nt_status)) {
			r->out.error_string = talloc_strdup(mem_ctx, "Could not obtain machine account password - are we joined to the domain?");
			talloc_free(samsync_ctx);
			return nt_status;
		}
	} else {
		machine_account = r->in.machine_account;
	}

	/* We cannot do this unless we are a BDC.  Check, before we get odd errors later */
	if (cli_credentials_get_secure_channel_type(machine_account) != SEC_CHAN_BDC) {
		r->out.error_string
			= talloc_asprintf(mem_ctx, 
					  "Our join to domain %s is not as a BDC (%d), please rejoin as a BDC",
					  cli_credentials_get_domain(machine_account),
					  cli_credentials_get_secure_channel_type(machine_account));
		talloc_free(samsync_ctx);
		return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
	}

	c = talloc_zero(samsync_ctx, struct libnet_RpcConnect);
	if (!c) {
		r->out.error_string = NULL;
		talloc_free(samsync_ctx);
		return NT_STATUS_NO_MEMORY;
	}

	c->level              = LIBNET_RPC_CONNECT_DC_INFO;
	if (r->in.binding_string) {
		c->in.binding = r->in.binding_string;
		c->in.name    = NULL;
	} else {
		c->in.binding = NULL;
		c->in.name    = cli_credentials_get_domain(machine_account);
	}
	
	/* prepare connect to the NETLOGON pipe of PDC */
	c->in.dcerpc_iface      = &ndr_table_netlogon;

	/* We must do this as the machine, not as any command-line
	 * user.  So we override the credentials in the
	 * libnet_context */
	machine_net_ctx = talloc(samsync_ctx, struct libnet_context);
	if (!machine_net_ctx) {
		r->out.error_string = NULL;
		talloc_free(samsync_ctx);
		return NT_STATUS_NO_MEMORY;
	}
	*machine_net_ctx = *ctx;
	machine_net_ctx->cred = machine_account;

	/* connect to the NETLOGON pipe of the PDC */
	nt_status = libnet_RpcConnect(machine_net_ctx, samsync_ctx, c);
	if (!NT_STATUS_IS_OK(nt_status)) {
		if (r->in.binding_string) {
			r->out.error_string = talloc_asprintf(mem_ctx,
							      "Connection to NETLOGON pipe of DC %s failed: %s",
							      r->in.binding_string, c->out.error_string);
		} else {
			r->out.error_string = talloc_asprintf(mem_ctx,
							      "Connection to NETLOGON pipe of DC for %s failed: %s",
							      c->in.name, c->out.error_string);
		}
		talloc_free(samsync_ctx);
		return nt_status;
	}

	/* This makes a new pipe, on which we can do schannel.  We
	 * should do this in the RpcConnect code, but the abstaction
	 * layers do not suit yet */

	nt_status = dcerpc_secondary_connection(c->out.dcerpc_pipe, &p,
						c->out.dcerpc_pipe->binding);

	if (!NT_STATUS_IS_OK(nt_status)) {
		r->out.error_string = talloc_asprintf(mem_ctx,
						      "Secondary connection to NETLOGON pipe of DC %s failed: %s",
						      dcerpc_server_name(p), nt_errstr(nt_status));
		talloc_free(samsync_ctx);
		return nt_status;
	}

	nt_status = dcerpc_bind_auth_schannel(samsync_ctx, p, &ndr_table_netlogon,
					      machine_account, ctx->lp_ctx, DCERPC_AUTH_LEVEL_PRIVACY);

	if (!NT_STATUS_IS_OK(nt_status)) {
		r->out.error_string = talloc_asprintf(mem_ctx,
						      "SCHANNEL authentication to NETLOGON pipe of DC %s failed: %s",
						      dcerpc_server_name(p), nt_errstr(nt_status));
		talloc_free(samsync_ctx);
		return nt_status;
	}

	state = talloc(samsync_ctx, struct libnet_SamSync_state);
	if (!state) {
		r->out.error_string = NULL;
		talloc_free(samsync_ctx);
		return nt_status;
	}		

	state->domain_name     = c->out.domain_name;
	state->domain_sid      = c->out.domain_sid;
	state->realm           = c->out.realm;
	state->domain_guid     = c->out.guid;
	state->machine_net_ctx = machine_net_ctx;
	state->netlogon_pipe   = p;

	/* initialise the callback layer.  It may wish to contact the
	 * server with ldap, now we know the name */
	
	if (r->in.init_fn) {
		char *error_string;
		nt_status = r->in.init_fn(samsync_ctx, 
					  r->in.fn_ctx,
					  state, 
					  &error_string); 
		if (!NT_STATUS_IS_OK(nt_status)) {
			r->out.error_string = talloc_steal(mem_ctx, error_string);
			talloc_free(samsync_ctx);
			return nt_status;
		}
	}

	/* get NETLOGON credentials */

	nt_status = dcerpc_schannel_creds(p->conn->security_state.generic_state, samsync_ctx, &creds);
	if (!NT_STATUS_IS_OK(nt_status)) {
		r->out.error_string = talloc_strdup(mem_ctx, "Could not obtain NETLOGON credentials from DCERPC/GENSEC layer");
		talloc_free(samsync_ctx);
		return nt_status;
	}

	/* Setup details for the synchronisation */

	ZERO_STRUCT(return_authenticator);

	dbsync.in.logon_server = talloc_asprintf(samsync_ctx, "\\\\%s", dcerpc_server_name(p));
	dbsync.in.computername = cli_credentials_get_workstation(machine_account);
	dbsync.in.preferredmaximumlength = (uint32_t)-1;
	dbsync.in.return_authenticator = &return_authenticator;
	dbsync.out.return_authenticator = &return_authenticator;
	dbsync.out.delta_enum_array = &delta_enum_array;

	for (i=0;i< ARRAY_SIZE(database_ids); i++) {

		uint32_t sync_context = 0;

		dbsync.in.database_id = database_ids[i];
		dbsync.in.sync_context = &sync_context;
		dbsync.out.sync_context = &sync_context;
		
		do {
			uint32_t d;
			loop_ctx = talloc_named(samsync_ctx, 0, "DatabaseSync loop context");
			netlogon_creds_client_authenticator(creds, &credential);

			dbsync.in.credential = &credential;
			
			dbsync_nt_status = dcerpc_netr_DatabaseSync_r(p->binding_handle, loop_ctx, &dbsync);
			if (NT_STATUS_IS_OK(dbsync_nt_status) && !NT_STATUS_IS_OK(dbsync.out.result)) {
				dbsync_nt_status = dbsync.out.result;
			}
			if (!NT_STATUS_IS_OK(dbsync_nt_status) &&
			    !NT_STATUS_EQUAL(dbsync_nt_status, STATUS_MORE_ENTRIES)) {
				r->out.error_string = talloc_asprintf(mem_ctx, "DatabaseSync failed - %s", nt_errstr(nt_status));
				talloc_free(samsync_ctx);
				return nt_status;
			}
			
			if (!netlogon_creds_client_check(creds, &dbsync.out.return_authenticator->cred)) {
				r->out.error_string = talloc_strdup(mem_ctx, "Credential chaining on incoming DatabaseSync failed");
				talloc_free(samsync_ctx);
				return NT_STATUS_ACCESS_DENIED;
			}
			
			dbsync.in.sync_context = dbsync.out.sync_context;
			
			/* For every single remote 'delta' entry: */
			for (d=0; d < delta_enum_array->num_deltas; d++) {
				char *error_string = NULL;
				delta_ctx = talloc_named(loop_ctx, 0, "DatabaseSync delta context");
				/* 'Fix' elements, by decrypting and
				 * de-obfuscating the data */
				nt_status = samsync_fix_delta(delta_ctx, 
							      creds, 
							      dbsync.in.database_id,
							      &delta_enum_array->delta_enum[d]);
				if (!NT_STATUS_IS_OK(nt_status)) {
					r->out.error_string = talloc_steal(mem_ctx, error_string);
					talloc_free(samsync_ctx);
					return nt_status;
				}

				/* Now call the callback.  This will
				 * do something like print the data or
				 * write to an ldb */
				nt_status = r->in.delta_fn(delta_ctx, 
							   r->in.fn_ctx,
							   dbsync.in.database_id,
							   &delta_enum_array->delta_enum[d],
							   &error_string);
				if (!NT_STATUS_IS_OK(nt_status)) {
					r->out.error_string = talloc_steal(mem_ctx, error_string);
					talloc_free(samsync_ctx);
					return nt_status;
				}
				talloc_free(delta_ctx);
			}
			talloc_free(loop_ctx);
		} while (NT_STATUS_EQUAL(dbsync_nt_status, STATUS_MORE_ENTRIES));
		
		if (!NT_STATUS_IS_OK(dbsync_nt_status)) {
			r->out.error_string = talloc_asprintf(mem_ctx, "libnet_SamSync_netlogon failed: unexpected inconsistancy. Should not get error %s here", nt_errstr(nt_status));
			talloc_free(samsync_ctx);
			return dbsync_nt_status;
		}
		nt_status = NT_STATUS_OK;
	}
	talloc_free(samsync_ctx);
	return nt_status;
}
示例#5
0
/*
 * get the remote time of a server via srvsvc_NetRemoteTOD
 */
static NTSTATUS libnet_RemoteTOD_srvsvc(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_RemoteTOD *r)
{
        NTSTATUS status;
	struct libnet_RpcConnect c;
	struct srvsvc_NetRemoteTOD tod;
	struct srvsvc_NetRemoteTODInfo *info = NULL;
	struct tm tm;

	ZERO_STRUCT(c);

	/* prepare connect to the SRVSVC pipe of a timeserver */
	c.level             = LIBNET_RPC_CONNECT_SERVER;
	c.in.name           = r->srvsvc.in.server_name;
	c.in.dcerpc_iface   = &ndr_table_srvsvc;

	/* 1. connect to the SRVSVC pipe of a timeserver */
	status = libnet_RpcConnect(ctx, mem_ctx, &c);
	if (!NT_STATUS_IS_OK(status)) {
		r->srvsvc.out.error_string = talloc_asprintf(mem_ctx,
						"Connection to SRVSVC pipe of server '%s' failed: %s",
						r->srvsvc.in.server_name, nt_errstr(status));
		return status;
	}

	/* prepare srvsvc_NetrRemoteTOD */
	tod.in.server_unc = talloc_asprintf(mem_ctx, "\\%s", c.in.name);
	tod.out.info = &info;

	/* 2. try srvsvc_NetRemoteTOD */
	status = dcerpc_srvsvc_NetRemoteTOD(c.out.dcerpc_pipe, mem_ctx, &tod);
	if (!NT_STATUS_IS_OK(status)) {
		r->srvsvc.out.error_string = talloc_asprintf(mem_ctx,
						"srvsvc_NetrRemoteTOD on server '%s' failed: %s",
						r->srvsvc.in.server_name, nt_errstr(status));
		goto disconnect;
	}

	/* check result of srvsvc_NetrRemoteTOD */
	if (!W_ERROR_IS_OK(tod.out.result)) {
		r->srvsvc.out.error_string = talloc_asprintf(mem_ctx,
						"srvsvc_NetrRemoteTOD on server '%s' failed: %s",
						r->srvsvc.in.server_name, win_errstr(tod.out.result));
		status = werror_to_ntstatus(tod.out.result);
		goto disconnect;
	}

	/* need to set the out parameters */
	tm.tm_sec = (int)info->secs;
	tm.tm_min = (int)info->mins;
	tm.tm_hour = (int)info->hours;
	tm.tm_mday = (int)info->day;
	tm.tm_mon = (int)info->month -1;
	tm.tm_year = (int)info->year - 1900;
	tm.tm_wday = -1;
	tm.tm_yday = -1;
	tm.tm_isdst = -1;

	r->srvsvc.out.time = timegm(&tm);
	r->srvsvc.out.time_zone = info->timezone * 60;

	goto disconnect;

disconnect:
	/* close connection */
	talloc_free(c.out.dcerpc_pipe);

	return status;
}
示例#6
0
NTSTATUS libnet_ListShares(struct libnet_context *ctx, 
			   TALLOC_CTX *mem_ctx, struct libnet_ListShares *r)
{
	NTSTATUS status;
	struct libnet_RpcConnect c;
	struct srvsvc_NetShareEnumAll s;
	struct srvsvc_NetShareInfoCtr info_ctr;
	uint32_t resume_handle = 0;
	uint32_t totalentries = 0;
	struct srvsvc_NetShareCtr0 ctr0;
	struct srvsvc_NetShareCtr1 ctr1;
	struct srvsvc_NetShareCtr2 ctr2;
	struct srvsvc_NetShareCtr501 ctr501;
	struct srvsvc_NetShareCtr502 ctr502;

	c.level               = LIBNET_RPC_CONNECT_SERVER;
	c.in.name             = r->in.server_name;
	c.in.dcerpc_iface     = &ndr_table_srvsvc;

	s.in.server_unc = talloc_asprintf(mem_ctx, "\\\\%s", c.in.name);

	status = libnet_RpcConnect(ctx, mem_ctx, &c);
	if (!NT_STATUS_IS_OK(status)) {
		r->out.error_string = talloc_asprintf(mem_ctx,
						      "Connection to SRVSVC pipe of server %s "
						      "failed: %s",
						      r->in.server_name,
						      nt_errstr(status));
		return status;
	}

	info_ctr.level = r->in.level;
	switch (info_ctr.level) {
	case 0:
		info_ctr.ctr.ctr0 = &ctr0;
		ZERO_STRUCT(ctr0);
		break;
	case 1:
		info_ctr.ctr.ctr1 = &ctr1;
		ZERO_STRUCT(ctr1);
		break;
	case 2:
		info_ctr.ctr.ctr2 = &ctr2;
		ZERO_STRUCT(ctr2);
		break;
	case 501:
		info_ctr.ctr.ctr501 = &ctr501;
		ZERO_STRUCT(ctr501);
		break;
	case 502:
		info_ctr.ctr.ctr502 = &ctr502;
		ZERO_STRUCT(ctr502);
		break;
	default:
		r->out.error_string = talloc_asprintf(mem_ctx,
						      "libnet_ListShares: Invalid info level requested: %d",
						      info_ctr.level);
		return NT_STATUS_INVALID_PARAMETER;
	}
	s.in.max_buffer = ~0;
	s.in.resume_handle = &resume_handle;
	s.in.info_ctr = &info_ctr;
	s.out.info_ctr = &info_ctr;
	s.out.totalentries = &totalentries;

	status = dcerpc_srvsvc_NetShareEnumAll(c.out.dcerpc_pipe, mem_ctx, &s);
	
	if (!NT_STATUS_IS_OK(status)) {
		r->out.error_string = talloc_asprintf(mem_ctx,
						      "srvsvc_NetShareEnumAll on server '%s' failed"
						      ": %s",
						      r->in.server_name, nt_errstr(status));
		goto disconnect;
	}

	if (!W_ERROR_IS_OK(s.out.result) && !W_ERROR_EQUAL(s.out.result, WERR_MORE_DATA)) {
		r->out.error_string = talloc_asprintf(mem_ctx,
						      "srvsvc_NetShareEnumAll on server '%s' failed: %s",
						      r->in.server_name, win_errstr(s.out.result));
		goto disconnect;
	}

	r->out.ctr = s.out.info_ctr->ctr;

disconnect:
	talloc_free(c.out.dcerpc_pipe);

	return status;	
}
示例#7
0
/*
 * set a password with DCERPC/SAMR calls
 * 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation)
 *    is it correct to contact the the pdc of the domain of the user who's password should be set?
 * 2. do a samr_Connect to get a policy handle
 * 3. do a samr_LookupDomain to get the domain sid
 * 4. do a samr_OpenDomain to get a domain handle
 * 5. do a samr_LookupNames to get the users rid
 * 6. do a samr_OpenUser to get a user handle
 * 7  call libnet_SetPassword_samr_handle to set the password
 */
static NTSTATUS libnet_SetPassword_samr(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_SetPassword *r)
{
	NTSTATUS status;
	struct libnet_RpcConnect c;
	struct samr_Connect sc;
	struct policy_handle p_handle;
	struct samr_LookupDomain ld;
	struct dom_sid2 *sid = NULL;
	struct lsa_String d_name;
	struct samr_OpenDomain od;
	struct policy_handle d_handle;
	struct samr_LookupNames ln;
	struct samr_Ids rids, types;
	struct samr_OpenUser ou;
	struct policy_handle u_handle;
	union libnet_SetPassword r2;

	ZERO_STRUCT(c);
	/* prepare connect to the SAMR pipe of users domain PDC */
	c.level               = LIBNET_RPC_CONNECT_PDC;
	c.in.name             = r->samr.in.domain_name;
	c.in.dcerpc_iface     = &ndr_table_samr;
	
	/* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */
	status = libnet_RpcConnect(ctx, mem_ctx, &c);
	if (!NT_STATUS_IS_OK(status)) {
		r->samr.out.error_string = talloc_asprintf(mem_ctx,
							   "Connection to SAMR pipe of PDC of domain '%s' failed: %s",
							   r->samr.in.domain_name, nt_errstr(status));
		return status;
	}

	/* prepare samr_Connect */
	ZERO_STRUCT(p_handle);
	sc.in.system_name = NULL;
	sc.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
	sc.out.connect_handle = &p_handle;

	/* 2. do a samr_Connect to get a policy handle */
	status = dcerpc_samr_Connect(c.out.dcerpc_pipe, mem_ctx, &sc);
	if (!NT_STATUS_IS_OK(status)) {
		r->samr.out.error_string = talloc_asprintf(mem_ctx,
						"samr_Connect failed: %s",
						nt_errstr(status));
		goto disconnect;
	}

	/* prepare samr_LookupDomain */
	d_name.string = r->samr.in.domain_name;
	ld.in.connect_handle = &p_handle;
	ld.in.domain_name = &d_name;
	ld.out.sid = &sid;

	/* 3. do a samr_LookupDomain to get the domain sid */
	status = dcerpc_samr_LookupDomain(c.out.dcerpc_pipe, mem_ctx, &ld);
	if (!NT_STATUS_IS_OK(status)) {
		r->samr.out.error_string = talloc_asprintf(mem_ctx,
						"samr_LookupDomain for [%s] failed: %s",
						r->samr.in.domain_name, nt_errstr(status));
		goto disconnect;
	}

	/* prepare samr_OpenDomain */
	ZERO_STRUCT(d_handle);
	od.in.connect_handle = &p_handle;
	od.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
	od.in.sid = *ld.out.sid;
	od.out.domain_handle = &d_handle;

	/* 4. do a samr_OpenDomain to get a domain handle */
	status = dcerpc_samr_OpenDomain(c.out.dcerpc_pipe, mem_ctx, &od);
	if (!NT_STATUS_IS_OK(status)) {
		r->samr.out.error_string = talloc_asprintf(mem_ctx,
						"samr_OpenDomain for [%s] failed: %s",
						r->samr.in.domain_name, nt_errstr(status));
		goto disconnect;
	}

	/* prepare samr_LookupNames */
	ln.in.domain_handle = &d_handle;
	ln.in.num_names = 1;
	ln.in.names = talloc_array(mem_ctx, struct lsa_String, 1);
	ln.out.rids = &rids;
	ln.out.types = &types;
	if (!ln.in.names) {
		r->samr.out.error_string = "Out of Memory";
		return NT_STATUS_NO_MEMORY;
	}
	ln.in.names[0].string = r->samr.in.account_name;

	/* 5. do a samr_LookupNames to get the users rid */
	status = dcerpc_samr_LookupNames(c.out.dcerpc_pipe, mem_ctx, &ln);
	if (!NT_STATUS_IS_OK(status)) {
		r->samr.out.error_string = talloc_asprintf(mem_ctx,
						"samr_LookupNames for [%s] failed: %s",
						r->samr.in.account_name, nt_errstr(status));
		goto disconnect;
	}

	/* check if we got one RID for the user */
	if (ln.out.rids->count != 1) {
		r->samr.out.error_string = talloc_asprintf(mem_ctx,
						"samr_LookupNames for [%s] returns %d RIDs",
						r->samr.in.account_name, ln.out.rids->count);
		status = NT_STATUS_INVALID_PARAMETER;
		goto disconnect;	
	}

	/* prepare samr_OpenUser */
	ZERO_STRUCT(u_handle);
	ou.in.domain_handle = &d_handle;
	ou.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
	ou.in.rid = ln.out.rids->ids[0];
	ou.out.user_handle = &u_handle;

	/* 6. do a samr_OpenUser to get a user handle */
	status = dcerpc_samr_OpenUser(c.out.dcerpc_pipe, mem_ctx, &ou);
	if (!NT_STATUS_IS_OK(status)) {
		r->samr.out.error_string = talloc_asprintf(mem_ctx,
						"samr_OpenUser for [%s] failed: %s",
						r->samr.in.account_name, nt_errstr(status));
		goto disconnect;
	}

	r2.samr_handle.level		= LIBNET_SET_PASSWORD_SAMR_HANDLE;
	r2.samr_handle.in.account_name	= r->samr.in.account_name;
	r2.samr_handle.in.newpassword	= r->samr.in.newpassword;
	r2.samr_handle.in.user_handle   = &u_handle;
	r2.samr_handle.in.dcerpc_pipe   = c.out.dcerpc_pipe;
	r2.samr_handle.in.info21	= NULL;

	status = libnet_SetPassword(ctx, mem_ctx, &r2);

	r->generic.out.error_string = r2.samr_handle.out.error_string;

disconnect:
	/* close connection */
	talloc_free(c.out.dcerpc_pipe);

	return status;
}
示例#8
0
/*
 * do a password change using DCERPC/SAMR calls
 * 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation)
 * 2. try samr_ChangePasswordUser3
 * 3. try samr_ChangePasswordUser2
 * 4. try samr_OemChangePasswordUser2
 * (not yet: 5. try samr_ChangePasswordUser)
 */
static NTSTATUS libnet_ChangePassword_samr(struct libnet_context *ctx, TALLOC_CTX *mem_ctx, union libnet_ChangePassword *r)
{
        NTSTATUS status;
	struct libnet_RpcConnect c;
#if 0
	struct policy_handle user_handle;
	struct samr_Password hash1, hash2, hash3, hash4, hash5, hash6;
	struct samr_ChangePasswordUser pw;
#endif
	struct samr_OemChangePasswordUser2 oe2;
	struct samr_ChangePasswordUser2 pw2;
	struct samr_ChangePasswordUser3 pw3;
	struct lsa_String server, account;
	struct lsa_AsciiString a_server, a_account;
	struct samr_CryptPassword nt_pass, lm_pass;
	struct samr_Password nt_verifier, lm_verifier;
	uint8_t old_nt_hash[16], new_nt_hash[16];
	uint8_t old_lm_hash[16], new_lm_hash[16];
	struct samr_DomInfo1 *dominfo = NULL;
	struct userPwdChangeFailureInformation *reject = NULL;

	ZERO_STRUCT(c);

	/* prepare connect to the SAMR pipe of the users domain PDC */
	c.level                    = LIBNET_RPC_CONNECT_PDC;
	c.in.name                  = r->samr.in.domain_name;
	c.in.dcerpc_iface     	   = &ndr_table_samr;
	c.in.dcerpc_flags          = DCERPC_ANON_FALLBACK;

	/* 1. connect to the SAMR pipe of users domain PDC (maybe a standalone server or workstation) */
	status = libnet_RpcConnect(ctx, mem_ctx, &c);
	if (!NT_STATUS_IS_OK(status)) {
		r->samr.out.error_string = talloc_asprintf(mem_ctx,
						"Connection to SAMR pipe of PDC of domain '%s' failed: %s",
						r->samr.in.domain_name, nt_errstr(status));
		return status;
	}

	/* prepare password change for account */
	server.string = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(c.out.dcerpc_pipe));
	account.string = r->samr.in.account_name;

	E_md4hash(r->samr.in.oldpassword, old_nt_hash);
	E_md4hash(r->samr.in.newpassword, new_nt_hash);

	E_deshash(r->samr.in.oldpassword, old_lm_hash);
	E_deshash(r->samr.in.newpassword, new_lm_hash);

	/* prepare samr_ChangePasswordUser3 */
	encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_UNICODE);
	arcfour_crypt(lm_pass.data, old_nt_hash, 516);
	E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);

	encode_pw_buffer(nt_pass.data,  r->samr.in.newpassword, STR_UNICODE);
	arcfour_crypt(nt_pass.data, old_nt_hash, 516);
	E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash);

	pw3.in.server = &server;
	pw3.in.account = &account;
	pw3.in.nt_password = &nt_pass;
	pw3.in.nt_verifier = &nt_verifier;
	pw3.in.lm_change = 1;
	pw3.in.lm_password = &lm_pass;
	pw3.in.lm_verifier = &lm_verifier;
	pw3.in.password3 = NULL;
	pw3.out.dominfo = &dominfo;
	pw3.out.reject = &reject;

	/* 2. try samr_ChangePasswordUser3 */
	status = dcerpc_samr_ChangePasswordUser3(c.out.dcerpc_pipe, mem_ctx, &pw3);
	if (!NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
		if (!NT_STATUS_IS_OK(status)) {
			r->samr.out.error_string = talloc_asprintf(mem_ctx,
								   "samr_ChangePasswordUser3 failed: %s",
								   nt_errstr(status));
			r->samr.out.error_string = talloc_asprintf(mem_ctx,
								   "samr_ChangePasswordUser3 for '%s\\%s' failed: %s",
								   r->samr.in.domain_name, r->samr.in.account_name, 
								   nt_errstr(status));
		}
		goto disconnect;
	} 

	/* prepare samr_ChangePasswordUser2 */
	encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_ASCII|STR_TERMINATE);
	arcfour_crypt(lm_pass.data, old_lm_hash, 516);
	E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);

	encode_pw_buffer(nt_pass.data, r->samr.in.newpassword, STR_UNICODE);
	arcfour_crypt(nt_pass.data, old_nt_hash, 516);
	E_old_pw_hash(new_nt_hash, old_nt_hash, nt_verifier.hash);

	pw2.in.server = &server;
	pw2.in.account = &account;
	pw2.in.nt_password = &nt_pass;
	pw2.in.nt_verifier = &nt_verifier;
	pw2.in.lm_change = 1;
	pw2.in.lm_password = &lm_pass;
	pw2.in.lm_verifier = &lm_verifier;

	/* 3. try samr_ChangePasswordUser2 */
	status = dcerpc_samr_ChangePasswordUser2(c.out.dcerpc_pipe, mem_ctx, &pw2);
	if (!NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
		if (!NT_STATUS_IS_OK(status)) {
			r->samr.out.error_string = talloc_asprintf(mem_ctx,
								   "samr_ChangePasswordUser2 for '%s\\%s' failed: %s",
								   r->samr.in.domain_name, r->samr.in.account_name, 
								   nt_errstr(status));
		}
		goto disconnect;
	}


	/* prepare samr_OemChangePasswordUser2 */
	a_server.string = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(c.out.dcerpc_pipe));
	a_account.string = r->samr.in.account_name;

	encode_pw_buffer(lm_pass.data, r->samr.in.newpassword, STR_ASCII);
	arcfour_crypt(lm_pass.data, old_lm_hash, 516);
	E_old_pw_hash(new_lm_hash, old_lm_hash, lm_verifier.hash);

	oe2.in.server = &a_server;
	oe2.in.account = &a_account;
	oe2.in.password = &lm_pass;
	oe2.in.hash = &lm_verifier;

	/* 4. try samr_OemChangePasswordUser2 */
	status = dcerpc_samr_OemChangePasswordUser2(c.out.dcerpc_pipe, mem_ctx, &oe2);
	if (!NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {
		if (!NT_STATUS_IS_OK(oe2.out.result)) {
			r->samr.out.error_string = talloc_asprintf(mem_ctx,
								   "samr_OemChangePasswordUser2 for '%s\\%s' failed: %s",
								   r->samr.in.domain_name, r->samr.in.account_name, 
								   nt_errstr(status));
		}
		goto disconnect;
	}

#if 0
	/* prepare samr_ChangePasswordUser */
	E_old_pw_hash(new_lm_hash, old_lm_hash, hash1.hash);
	E_old_pw_hash(old_lm_hash, new_lm_hash, hash2.hash);
	E_old_pw_hash(new_nt_hash, old_nt_hash, hash3.hash);
	E_old_pw_hash(old_nt_hash, new_nt_hash, hash4.hash);
	E_old_pw_hash(old_lm_hash, new_nt_hash, hash5.hash);
	E_old_pw_hash(old_nt_hash, new_lm_hash, hash6.hash);

	/* TODO: ask for a user_handle */
	pw.in.handle = &user_handle;
	pw.in.lm_present = 1;
	pw.in.old_lm_crypted = &hash1;
	pw.in.new_lm_crypted = &hash2;
	pw.in.nt_present = 1;
	pw.in.old_nt_crypted = &hash3;
	pw.in.new_nt_crypted = &hash4;
	pw.in.cross1_present = 1;
	pw.in.nt_cross = &hash5;
	pw.in.cross2_present = 1;
	pw.in.lm_cross = &hash6;

	/* 5. try samr_ChangePasswordUser */
	status = dcerpc_samr_ChangePasswordUser(c.pdc.out.dcerpc_pipe, mem_ctx, &pw);
	if (!NT_STATUS_IS_OK(status)) {
		r->samr.out.error_string = talloc_asprintf(mem_ctx,
						"samr_ChangePasswordUser failed: %s",
						nt_errstr(status));
		goto disconnect;
	}

	/* check result of samr_ChangePasswordUser */
	if (!NT_STATUS_IS_OK(pw.out.result)) {
		r->samr.out.error_string = talloc_asprintf(mem_ctx,
						"samr_ChangePasswordUser for '%s\\%s' failed: %s",
						r->samr.in.domain_name, r->samr.in.account_name, 
						nt_errstr(pw.out.result));
		if (NT_STATUS_EQUAL(pw.out.result, NT_STATUS_PASSWORD_RESTRICTION)) {
			status = pw.out.result;
			goto disconnect;
		}
		goto disconnect;
	}
#endif
disconnect:
	/* close connection */
	talloc_free(c.out.dcerpc_pipe);

	return status;
}