libnet_join.c

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

C
1,213
字号
/*    Unix SMB/CIFS implementation.      Copyright (C) Stefan Metzmacher	2004   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005   Copyright (C) Brad Henry 2005    This program is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; either version 3 of the License, or   (at your option) any later version.      This program is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.      You should have received a copy of the GNU General Public License   along with this program.  If not, see <http://www.gnu.org/licenses/>.*/#include "includes.h"#include "libnet/libnet.h"#include "librpc/gen_ndr/ndr_drsuapi_c.h"#include "lib/ldb/include/ldb.h"#include "lib/ldb/include/ldb_errors.h"#include "param/secrets.h"#include "dsdb/samdb/samdb.h"#include "ldb_wrap.h"#include "util/util_ldb.h"#include "libcli/security/security.h"#include "auth/credentials/credentials.h"#include "auth/credentials/credentials_krb5.h"#include "librpc/gen_ndr/ndr_samr_c.h"#include "param/param.h"/* * complete a domain join, when joining to a AD domain: * 1.) connect and bind to the DRSUAPI pipe * 2.) do a DsCrackNames() to find the machine account dn * 3.) connect to LDAP * 4.) do an ldap search to find the "msDS-KeyVersionNumber" of the machine account * 5.) set the servicePrincipalName's of the machine account via LDAP, (maybe we should use DsWriteAccountSpn()...) * 6.) do a DsCrackNames() to find the domain dn * 7.) find out Site specific stuff, look at libnet_JoinSite() for details */static NTSTATUS libnet_JoinADSDomain(struct libnet_context *ctx, struct libnet_JoinDomain *r){	NTSTATUS status;	TALLOC_CTX *tmp_ctx;	const char *realm = r->out.realm;	struct dcerpc_binding *samr_binding = r->out.samr_binding;	struct dcerpc_pipe *drsuapi_pipe;	struct dcerpc_binding *drsuapi_binding;	struct drsuapi_DsBind r_drsuapi_bind;	struct drsuapi_DsCrackNames r_crack_names;	struct drsuapi_DsNameString names[1];	struct policy_handle drsuapi_bind_handle;	struct GUID drsuapi_bind_guid;	struct ldb_context *remote_ldb;	struct ldb_dn *account_dn;	const char *account_dn_str;	const char *remote_ldb_url;	struct ldb_result *res;	struct ldb_message *msg;	int ret, rtn;	const char * const attrs[] = {		"msDS-KeyVersionNumber",		"servicePrincipalName",		"dNSHostName",		"objectGUID",		NULL,	};	r->out.error_string = NULL;		/* We need to convert between a samAccountName and domain to a	 * DN in the directory.  The correct way to do this is with	 * DRSUAPI CrackNames */	/* Fiddle with the bindings, so get to DRSUAPI on	 * NCACN_IP_TCP, sealed */	tmp_ctx = talloc_named(r, 0, "libnet_JoinADSDomain temp context");  	if (!tmp_ctx) {		r->out.error_string = NULL;		return NT_STATUS_NO_MEMORY;	}	                                           	drsuapi_binding = talloc(tmp_ctx, struct dcerpc_binding);	if (!drsuapi_binding) {		r->out.error_string = NULL;		talloc_free(tmp_ctx);		return NT_STATUS_NO_MEMORY;	}		*drsuapi_binding = *samr_binding;	/* DRSUAPI is only available on IP_TCP, and locally on NCALRPC */	if (drsuapi_binding->transport != NCALRPC) {		drsuapi_binding->transport = NCACN_IP_TCP;	}	drsuapi_binding->endpoint = NULL;	drsuapi_binding->flags |= DCERPC_SEAL;	status = dcerpc_pipe_connect_b(tmp_ctx, 				       &drsuapi_pipe,				       drsuapi_binding,				       &ndr_table_drsuapi,				       ctx->cred, 				       ctx->event_ctx,				       ctx->lp_ctx);	if (!NT_STATUS_IS_OK(status)) {		r->out.error_string = talloc_asprintf(r,					"Connection to DRSUAPI pipe of PDC of domain '%s' failed: %s",					r->out.domain_name,					nt_errstr(status));		talloc_free(tmp_ctx);		return status;	}	/* get a DRSUAPI pipe handle */	GUID_from_string(DRSUAPI_DS_BIND_GUID, &drsuapi_bind_guid);	r_drsuapi_bind.in.bind_guid = &drsuapi_bind_guid;	r_drsuapi_bind.in.bind_info = NULL;	r_drsuapi_bind.out.bind_handle = &drsuapi_bind_handle;	status = dcerpc_drsuapi_DsBind(drsuapi_pipe, tmp_ctx, &r_drsuapi_bind);	if (!NT_STATUS_IS_OK(status)) {		if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {			r->out.error_string				= talloc_asprintf(r,						  "dcerpc_drsuapi_DsBind failed - %s", 						  dcerpc_errstr(tmp_ctx, drsuapi_pipe->last_fault_code));			talloc_free(tmp_ctx);			return status;		} else {			r->out.error_string				= talloc_asprintf(r,						  "dcerpc_drsuapi_DsBind failed - %s", 						  nt_errstr(status));			talloc_free(tmp_ctx);			return status;		}	} else if (!W_ERROR_IS_OK(r_drsuapi_bind.out.result)) {		r->out.error_string				= talloc_asprintf(r,						  "DsBind failed - %s", 						  win_errstr(r_drsuapi_bind.out.result));			talloc_free(tmp_ctx);		return NT_STATUS_UNSUCCESSFUL;	}	/* Actually 'crack' the names */	ZERO_STRUCT(r_crack_names);	r_crack_names.in.bind_handle		= &drsuapi_bind_handle;	r_crack_names.in.level			= 1;	r_crack_names.in.req.req1.codepage	= 1252; /* western european */	r_crack_names.in.req.req1.language	= 0x00000407; /* german */	r_crack_names.in.req.req1.count		= 1;	r_crack_names.in.req.req1.names		= names;	r_crack_names.in.req.req1.format_flags	= DRSUAPI_DS_NAME_FLAG_NO_FLAGS;	r_crack_names.in.req.req1.format_offered= DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY;	r_crack_names.in.req.req1.format_desired= DRSUAPI_DS_NAME_FORMAT_FQDN_1779;	names[0].str = dom_sid_string(tmp_ctx, r->out.account_sid);	if (!names[0].str) {		r->out.error_string = NULL;		talloc_free(tmp_ctx);		return NT_STATUS_NO_MEMORY;	}	status = dcerpc_drsuapi_DsCrackNames(drsuapi_pipe, tmp_ctx, &r_crack_names);	if (!NT_STATUS_IS_OK(status)) {		if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {			r->out.error_string				= talloc_asprintf(r,						  "dcerpc_drsuapi_DsCrackNames for [%s] failed - %s", 						  names[0].str,						  dcerpc_errstr(tmp_ctx, drsuapi_pipe->last_fault_code));			talloc_free(tmp_ctx);			return status;		} else {			r->out.error_string				= talloc_asprintf(r,						  "dcerpc_drsuapi_DsCrackNames for [%s] failed - %s", 						  names[0].str,						  nt_errstr(status));			talloc_free(tmp_ctx);			return status;		}	} else if (!W_ERROR_IS_OK(r_crack_names.out.result)) {		r->out.error_string				= talloc_asprintf(r,						  "DsCrackNames failed - %s", win_errstr(r_crack_names.out.result));		talloc_free(tmp_ctx);		return NT_STATUS_UNSUCCESSFUL;	} else if (r_crack_names.out.level != 1 		   || !r_crack_names.out.ctr.ctr1 		   || r_crack_names.out.ctr.ctr1->count != 1) {		r->out.error_string = talloc_asprintf(r, "DsCrackNames failed");		talloc_free(tmp_ctx);		return NT_STATUS_INVALID_PARAMETER;	} else if (r_crack_names.out.ctr.ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {		r->out.error_string = talloc_asprintf(r, "DsCrackNames failed: %d", r_crack_names.out.ctr.ctr1->array[0].status);		talloc_free(tmp_ctx);		return NT_STATUS_UNSUCCESSFUL;	} else if (r_crack_names.out.ctr.ctr1->array[0].result_name == NULL) {		r->out.error_string = talloc_asprintf(r, "DsCrackNames failed: no result name");		talloc_free(tmp_ctx);		return NT_STATUS_INVALID_PARAMETER;	}	/* Store the DN of our machine account. */	account_dn_str = r_crack_names.out.ctr.ctr1->array[0].result_name;	/* Now we know the user's DN, open with LDAP, read and modify a few things */	remote_ldb_url = talloc_asprintf(tmp_ctx, "ldap://%s", 					 drsuapi_binding->target_hostname);	if (!remote_ldb_url) {		r->out.error_string = NULL;		talloc_free(tmp_ctx);		return NT_STATUS_NO_MEMORY;	}	remote_ldb = ldb_wrap_connect(tmp_ctx, ctx->event_ctx, ctx->lp_ctx, 				      remote_ldb_url, 				      NULL, ctx->cred, 0, NULL);	if (!remote_ldb) {		r->out.error_string = NULL;		talloc_free(tmp_ctx);		return NT_STATUS_UNSUCCESSFUL;	}	account_dn = ldb_dn_new(tmp_ctx, remote_ldb, account_dn_str);	if (! ldb_dn_validate(account_dn)) {		r->out.error_string = talloc_asprintf(r, "Invalid account dn: %s",						      account_dn_str);		talloc_free(tmp_ctx);		return NT_STATUS_UNSUCCESSFUL;	}	/* search for the user's record */	ret = ldb_search(remote_ldb, account_dn, LDB_SCOPE_BASE, 			 NULL, attrs, &res);	if (ret != LDB_SUCCESS) {		r->out.error_string = talloc_asprintf(r, "ldb_search for %s failed - %s",						      account_dn_str, ldb_errstring(remote_ldb));		talloc_free(tmp_ctx);		return NT_STATUS_UNSUCCESSFUL;	}	talloc_steal(tmp_ctx, res);	if (res->count != 1) {		r->out.error_string = talloc_asprintf(r, "ldb_search for %s failed - found %d entries",						      account_dn_str, res->count);		talloc_free(tmp_ctx);		return NT_STATUS_UNSUCCESSFUL;	}	/* Prepare a new message, for the modify */	msg = ldb_msg_new(tmp_ctx);	if (!msg) {		r->out.error_string = NULL;		talloc_free(tmp_ctx);		return NT_STATUS_NO_MEMORY;	}	msg->dn = res->msgs[0]->dn;	{		int i;		const char *service_principal_name[6];		const char *dns_host_name = strlower_talloc(tmp_ctx, 							    talloc_asprintf(tmp_ctx, 									    "%s.%s", 									    r->in.netbios_name, 									    realm));		if (!dns_host_name) {			r->out.error_string = NULL;			talloc_free(tmp_ctx);			return NT_STATUS_NO_MEMORY;		}		service_principal_name[0] = talloc_asprintf(tmp_ctx, "host/%s", dns_host_name);		service_principal_name[1] = talloc_asprintf(tmp_ctx, "host/%s", strlower_talloc(tmp_ctx, r->in.netbios_name));		service_principal_name[2] = talloc_asprintf(tmp_ctx, "host/%s/%s", dns_host_name, realm);		service_principal_name[3] = talloc_asprintf(tmp_ctx, "host/%s/%s", strlower_talloc(tmp_ctx, r->in.netbios_name), realm);		service_principal_name[4] = talloc_asprintf(tmp_ctx, "host/%s/%s", dns_host_name, r->out.domain_name);		service_principal_name[5] = talloc_asprintf(tmp_ctx, "host/%s/%s", strlower_talloc(tmp_ctx, r->in.netbios_name), r->out.domain_name);				for (i=0; i < ARRAY_SIZE(service_principal_name); i++) {			if (!service_principal_name[i]) {				r->out.error_string = NULL;				talloc_free(tmp_ctx);				return NT_STATUS_NO_MEMORY;			}			rtn = samdb_msg_add_string(remote_ldb, tmp_ctx, msg, "servicePrincipalName", service_principal_name[i]);			if (rtn == -1) {				r->out.error_string = NULL;				talloc_free(tmp_ctx);				return NT_STATUS_NO_MEMORY;			}		}		rtn = samdb_msg_add_string(remote_ldb, tmp_ctx, msg, "dNSHostName", dns_host_name);		if (rtn == -1) {			r->out.error_string = NULL;			talloc_free(tmp_ctx);			return NT_STATUS_NO_MEMORY;		}		rtn = samdb_replace(remote_ldb, tmp_ctx, msg);		if (rtn != 0) {			r->out.error_string				= talloc_asprintf(r, 						  "Failed to replace entries on %s", 						  ldb_dn_get_linearized(msg->dn));			talloc_free(tmp_ctx);			return NT_STATUS_INTERNAL_DB_CORRUPTION;		}	}					/* DsCrackNames to find out the DN of the domain. */	r_crack_names.in.req.req1.format_offered = DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT;	r_crack_names.in.req.req1.format_desired = DRSUAPI_DS_NAME_FORMAT_FQDN_1779;	names[0].str = talloc_asprintf(tmp_ctx, "%s\\", r->out.domain_name);	if (!names[0].str) {		r->out.error_string = NULL;		talloc_free(tmp_ctx);		return NT_STATUS_NO_MEMORY;	}	status = dcerpc_drsuapi_DsCrackNames(drsuapi_pipe, tmp_ctx, &r_crack_names);	if (!NT_STATUS_IS_OK(status)) {		if (NT_STATUS_EQUAL(status, NT_STATUS_NET_WRITE_FAULT)) {			r->out.error_string				= talloc_asprintf(r,						  "dcerpc_drsuapi_DsCrackNames for [%s] failed - %s", 						  r->in.domain_name, 						  dcerpc_errstr(tmp_ctx, drsuapi_pipe->last_fault_code));			talloc_free(tmp_ctx);			return status;		} else {			r->out.error_string				= talloc_asprintf(r,						  "dcerpc_drsuapi_DsCrackNames for [%s] failed - %s", 						  r->in.domain_name, 						  nt_errstr(status));			talloc_free(tmp_ctx);			return status;		}	} else if (!W_ERROR_IS_OK(r_crack_names.out.result)) {		r->out.error_string			= talloc_asprintf(r,					  "DsCrackNames failed - %s", win_errstr(r_crack_names.out.result));		talloc_free(tmp_ctx);		return NT_STATUS_UNSUCCESSFUL;	} else if (r_crack_names.out.level != 1 		   || !r_crack_names.out.ctr.ctr1 		   || r_crack_names.out.ctr.ctr1->count != 1		   || !r_crack_names.out.ctr.ctr1->array[0].result_name		  		   || r_crack_names.out.ctr.ctr1->array[0].status != DRSUAPI_DS_NAME_STATUS_OK) {		r->out.error_string = talloc_asprintf(r, "DsCrackNames failed");		talloc_free(tmp_ctx);		return NT_STATUS_UNSUCCESSFUL;	}	/* Store the account DN. */	r->out.account_dn_str = account_dn_str;	talloc_steal(r, account_dn_str);	/* Store the domain DN. */	r->out.domain_dn_str = r_crack_names.out.ctr.ctr1->array[0].result_name;	talloc_steal(r, r_crack_names.out.ctr.ctr1->array[0].result_name);	/* Store the KVNO of the account, critical for some kerberos	 * operations */	r->out.kvno = ldb_msg_find_attr_as_uint(res->msgs[0], "msDS-KeyVersionNumber", 0);	/* Store the account GUID. */	r->out.account_guid = samdb_result_guid(res->msgs[0], "objectGUID");	if (r->in.acct_type == ACB_SVRTRUST) {		status = libnet_JoinSite(ctx, remote_ldb, r);	}	talloc_free(tmp_ctx);	return status;}/* * 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

⌨️ 快捷键说明

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