libnet_join.c

来自「samba最新软件」· C语言 代码 · 共 1,213 行 · 第 1/3 页

C
1,213
字号
 * - 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_OpenUser ou;	struct samr_CreateUser2 cu;	struct policy_handle *u_handle = NULL;	struct samr_QueryUserInfo qui;	struct samr_UserInfo21 u_info21;	union libnet_SetPassword r2;	struct samr_GetUserPwInfo pwp;	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(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(samr_pipe, tmp_ctx, &sc);	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 automaticly find the domain name */			connect_with_info->out.domain_name = talloc_strdup(tmp_ctx, lp_workgroup(ctx->lp_ctx));			connect_with_info->out.realm = talloc_strdup(tmp_ctx, lp_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;		name.string = connect_with_info->out.domain_name;		l.in.connect_handle = &p_handle;		l.in.domain_name = &name;				status = dcerpc_samr_LookupDomain(samr_pipe, tmp_ctx, &l);		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(samr_pipe, tmp_ctx, &od);				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(samr_pipe, tmp_ctx, &cu);				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);		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(samr_pipe, tmp_ctx, &ln);		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(samr_pipe, tmp_ctx, &ou); 		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(samr_pipe, mem_ctx, &d);			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(samr_pipe, tmp_ctx, &cu);						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)) {		r->out.error_string = talloc_asprintf(mem_ctx,						      "samr_CreateUser2 for [%s] failed: %s",						      r->in.account_name, nt_errstr(status));		talloc_free(tmp_ctx);		return status;	}	/* prepare samr_QueryUserInfo (get flags) */	qui.in.user_handle = u_handle;	qui.in.level = 16;		status = dcerpc_samr_QueryUserInfo(samr_pipe, tmp_ctx, &qui);	if (!NT_STATUS_IS_OK(status)) {		r->out.error_string = talloc_asprintf(mem_ctx,						"samr_QueryUserInfo for [%s] failed: %s",						r->in.account_name,						nt_errstr(status));		talloc_free(tmp_ctx);		return status;	}		if (!qui.out.info) {		status = NT_STATUS_INVALID_PARAMETER;		r->out.error_string			= talloc_asprintf(mem_ctx,					  "samr_QueryUserInfo failed to return qui.out.info for [%s]: %s",					  r->in.account_name, nt_errstr(status));		talloc_free(tmp_ctx);		return status;	}	old_acct_flags = (qui.out.info->info16.acct_flags & (ACB_WSTRUST | ACB_SVRTRUST | ACB_DOMTRUST));	/* Possibly bail if the account is of the wrong type */	if (old_acct_flags	    != r->in.acct_type) {		const char *old_account_type, *new_account_type;		switch (old_acct_flags) {		case ACB_WSTRUST:			old_account_type = "domain member (member)";			break;		case ACB_SVRTRUST:			old_account_type = "domain controller (bdc)";			break;		case ACB_DOMTRUST:			old_account_type = "trusted domain";			break;		default:			return NT_STATUS_INVALID_PARAMETER;		}		switch (r->in.acct_type) {		case ACB_WSTRUST:			new_account_type = "domain member (member)";			break;		case ACB_SVRTRUST:			new_account_type = "domain controller (bdc)";			break;		case ACB_DOMTRUST:			new_account_type = "trusted domain";			break;		default:			return NT_STATUS_INVALID_PARAMETER;		}		if (!NT_STATUS_EQUAL(cu_status, NT_STATUS_USER_EXISTS)) {			/* We created a new user, but they didn't come out the right type?!? */			r->out.error_string				= talloc_asprintf(mem_ctx,						  "We asked to create a new machine account (%s) of type %s, "						  "but we got an account of type %s.  This is unexpected.  "						  "Perhaps delete the account and try again.",						  r->in.account_name, new_account_type, old_account_type);			talloc_free(tmp_ctx);			return NT_STATUS_INVALID_PARAMETER;		} else {			/* The account is of the wrong type, so bail */			/* TODO: We should allow a --force option to override, and redo this from the top setting r.in.recreate_account */			r->out.error_string				= talloc_asprintf(mem_ctx,						  "The machine account (%s) already exists in the domain %s, "						  "but is a %s.  You asked to join as a %s.  Please delete "						  "the account and try again.",						  r->in.account_name, connect_with_info->out.domain_name, old_account_type, new_account_type);			talloc_free(tmp_ctx);			return NT_STATUS_USER_EXISTS;		}	} else {		acct_flags = qui.out.info->info16.acct_flags;	}		acct_flags = (acct_flags & ~(ACB_DISABLED|ACB_PWNOTREQ));	/* Find out what password policy this user has */	pwp.in.user_handle = u_handle;	status = dcerpc_samr_GetUserPwInfo(samr_pipe, tmp_ctx, &pwp);					if (NT_STATUS_IS_OK(status)) {		policy_min_pw_len = pwp.out.info.min_password_length;	}		/* Grab a password of that minimum length */		password_str = generate_random_str(tmp_ctx, MAX(8, policy_min_pw_len));		/* set full_name and reset flags */	ZERO_STRUCT(u_info21);	u_info21.full_name.string	= r->in.account_name;	u_info21.acct_flags		= acct_flags;	u_info21.fields_present		= SAMR_FIELD_FULL_NAME | SAMR_FIELD_ACCT_FLAGS;	r2.samr_handle.level		= LIBNET_SET_PASSWORD_SAMR_HANDLE;	r2.samr_handle.in.account_name	= r->in.account_name;	r2.samr_handle.in.newpassword	= password_str;	r2.samr_handle.in.user_handle   = u_handle;	r2.samr_handle.in.dcerpc_pipe   = samr_pipe;	r2.samr_handle.in.info21	= &u_info21;	status = libnet_SetPassword(ctx, tmp_ctx, &r2);		if (!NT_STATUS_IS_OK(status)) {		r->out.error_string = talloc_steal(mem_ctx, r2.samr_handle.out.error_string);		talloc_free(tmp_ctx);		return status;	}	account_sid = dom_sid_add_rid(mem_ctx, connect_with_info->out.domain_sid, rid);	if (!account_sid) {		r->out.error_string = NULL;		talloc_free(tmp_ctx);		return NT_STATUS_NO_MEMORY;	}	/* Finish out by pushing various bits of status data out for the caller to use */	r->out.join_password = password_str;	talloc_steal(mem_ctx, r->out.join_password);	r->out.domain_sid = connect_with_info->out.domain_sid;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?