libnet_samsync_ldb.c

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

C
1,250
字号
/*    Unix SMB/CIFS implementation.      Extract the user/system database from a remote SamSync server   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005   Copyright (C) Andrew Tridgell 2004   Copyright (C) Volker Lendecke 2004      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 "libcli/ldap/ldap_ndr.h"#include "dsdb/samdb/samdb.h"#include "auth/auth.h"#include "util/util_ldb.h"#include "librpc/gen_ndr/ndr_misc.h"#include "ldb_wrap.h"#include "libcli/security/security.h"#include "librpc/rpc/dcerpc.h"#include "param/param.h"struct samsync_ldb_secret {	struct samsync_ldb_secret *prev, *next;	DATA_BLOB secret;	char *name;	NTTIME mtime;};struct samsync_ldb_trusted_domain {	struct samsync_ldb_trusted_domain *prev, *next;        struct dom_sid *sid;	char *name;};struct samsync_ldb_state {	/* Values from the LSA lookup */	const struct libnet_SamSync_state *samsync_state;	struct dom_sid *dom_sid[3];	struct ldb_context *sam_ldb, *remote_ldb;	struct ldb_dn *base_dn[3];	struct samsync_ldb_secret *secrets;	struct samsync_ldb_trusted_domain *trusted_domains;};static NTSTATUS samsync_ldb_add_foreignSecurityPrincipal(TALLOC_CTX *mem_ctx,							 struct samsync_ldb_state *state,							 struct dom_sid *sid,							 struct ldb_dn **fsp_dn,							 char **error_string){	const char *sidstr = dom_sid_string(mem_ctx, sid);	/* We assume that ForeignSecurityPrincipals are under the BASEDN of the main domain */	struct ldb_dn *basedn = samdb_search_dn(state->sam_ldb, mem_ctx,						state->base_dn[SAM_DATABASE_DOMAIN],						"(&(objectClass=container)(cn=ForeignSecurityPrincipals))");	struct ldb_message *msg;	int ret;	if (!sidstr) {		return NT_STATUS_NO_MEMORY;	}	if (basedn == NULL) {		*error_string = talloc_asprintf(mem_ctx, 						"Failed to find DN for "						"ForeignSecurityPrincipal container under %s",						ldb_dn_get_linearized(state->base_dn[SAM_DATABASE_DOMAIN]));		return NT_STATUS_INTERNAL_DB_CORRUPTION;	}		msg = ldb_msg_new(mem_ctx);	if (msg == NULL) {		return NT_STATUS_NO_MEMORY;	}	/* add core elements to the ldb_message for the alias */	msg->dn = basedn;	if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))		return NT_STATUS_UNSUCCESSFUL;		samdb_msg_add_string(state->sam_ldb, mem_ctx, msg,			     "objectClass",			     "foreignSecurityPrincipal");	*fsp_dn = msg->dn;	/* create the alias */	ret = ldb_add(state->sam_ldb, msg);	if (ret != 0) {		*error_string = talloc_asprintf(mem_ctx, "Failed to create foreignSecurityPrincipal "						"record %s: %s",						ldb_dn_get_linearized(msg->dn),						ldb_errstring(state->sam_ldb));		return NT_STATUS_INTERNAL_DB_CORRUPTION;	}	return NT_STATUS_OK;}static NTSTATUS samsync_ldb_handle_domain(TALLOC_CTX *mem_ctx,					  struct samsync_ldb_state *state,					  enum netr_SamDatabaseID database,					  struct netr_DELTA_ENUM *delta,					  char **error_string) {	struct netr_DELTA_DOMAIN *domain = delta->delta_union.domain;	const char *domain_name = domain->domain_name.string;	struct ldb_message *msg;	int ret;		msg = ldb_msg_new(mem_ctx);	if (msg == NULL) {		return NT_STATUS_NO_MEMORY;	}	if (database == SAM_DATABASE_DOMAIN) {		struct ldb_dn *partitions_basedn;		const char *domain_attrs[] =  {"nETBIOSName", "nCName", NULL};		struct ldb_message **msgs_domain;		int ret_domain;		partitions_basedn = samdb_partitions_dn(state->sam_ldb, mem_ctx);		ret_domain = gendb_search(state->sam_ldb, mem_ctx, partitions_basedn, &msgs_domain, domain_attrs,					  "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))", 					  domain_name);		if (ret_domain == -1) {			*error_string = talloc_asprintf(mem_ctx, "gendb_search for domain failed: %s", ldb_errstring(state->sam_ldb));			return NT_STATUS_INTERNAL_DB_CORRUPTION;		}				if (ret_domain != 1) {			*error_string = talloc_asprintf(mem_ctx, "Failed to find existing domain record for %s: %d results", domain_name,							ret_domain);			return NT_STATUS_NO_SUCH_DOMAIN;				}		state->base_dn[database] = samdb_result_dn(state->sam_ldb, state, msgs_domain[0], "nCName", NULL);		if (state->dom_sid[database]) {			/* Update the domain sid with the incoming			 * domain (found on LSA pipe, database sid may			 * be random) */			samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, 					      msg, "objectSid", state->dom_sid[database]);		} else {			/* Well, we will have to use the one from the database */			state->dom_sid[database] = samdb_search_dom_sid(state->sam_ldb, state,									state->base_dn[database], 									"objectSid", NULL);		}		if (state->samsync_state->domain_guid) {			enum ndr_err_code ndr_err;			struct ldb_val v;			ndr_err = ndr_push_struct_blob(&v, msg, NULL, 						       state->samsync_state->domain_guid,							 (ndr_push_flags_fn_t)ndr_push_GUID);			if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {				*error_string = talloc_asprintf(mem_ctx, "ndr_push of domain GUID failed!");				return ndr_map_error2ntstatus(ndr_err);			}						ldb_msg_add_value(msg, "objectGUID", &v, NULL);		}	} else if (database == SAM_DATABASE_BUILTIN) {		/* work out the builtin_dn - useful for so many calls its worth		   fetching here */		const char *dnstring = samdb_search_string(state->sam_ldb, mem_ctx, NULL,							   "distinguishedName", "objectClass=builtinDomain");		state->base_dn[database] = ldb_dn_new(state, state->sam_ldb, dnstring);		if ( ! ldb_dn_validate(state->base_dn[database])) {			return NT_STATUS_INTERNAL_ERROR;		}	} else {		/* PRIVs DB */		return NT_STATUS_INVALID_PARAMETER;	}	msg->dn = talloc_reference(mem_ctx, state->base_dn[database]);	if (!msg->dn) {		return NT_STATUS_NO_MEMORY;	}	samdb_msg_add_string(state->sam_ldb, mem_ctx, 			     msg, "oEMInformation", domain->comment.string);	samdb_msg_add_int64(state->sam_ldb, mem_ctx, 			    msg, "forceLogoff", domain->force_logoff_time);	samdb_msg_add_uint(state->sam_ldb, mem_ctx, 			   msg, "minPwdLen", domain->min_password_length);	samdb_msg_add_int64(state->sam_ldb, mem_ctx, 			    msg, "maxPwdAge", domain->max_password_age);	samdb_msg_add_int64(state->sam_ldb, mem_ctx, 			    msg, "minPwdAge", domain->min_password_age);	samdb_msg_add_uint(state->sam_ldb, mem_ctx, 			   msg, "pwdHistoryLength", domain->password_history_length);	samdb_msg_add_uint64(state->sam_ldb, mem_ctx, 			     msg, "modifiedCount", 			     domain->sequence_num);	samdb_msg_add_uint64(state->sam_ldb, mem_ctx, 			     msg, "creationTime", domain->domain_create_time);	/* TODO: Account lockout, password properties */		ret = samdb_replace(state->sam_ldb, mem_ctx, msg);	if (ret) {		return NT_STATUS_INTERNAL_ERROR;	}	return NT_STATUS_OK;}static NTSTATUS samsync_ldb_handle_user(TALLOC_CTX *mem_ctx,					struct samsync_ldb_state *state,					enum netr_SamDatabaseID database,					struct netr_DELTA_ENUM *delta,					char **error_string) {	uint32_t rid = delta->delta_id_union.rid;	struct netr_DELTA_USER *user = delta->delta_union.user;	const char *container, *obj_class;	char *cn_name;	int cn_name_len;	const struct dom_sid *user_sid;	struct ldb_message *msg;	struct ldb_message **msgs;	struct ldb_message **remote_msgs = NULL;	int ret, i;	uint32_t acb;	bool add = false;	const char *attrs[] = { NULL };	/* we may change this to a global search, then fill in only the things not in ldap later */	const char *remote_attrs[] = { "userPrincipalName", "servicePrincipalName", 				       "msDS-KeyVersionNumber", "objectGUID", NULL};	user_sid = dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid);	if (!user_sid) {		return NT_STATUS_NO_MEMORY;	}	msg = ldb_msg_new(mem_ctx);	if (msg == NULL) {		return NT_STATUS_NO_MEMORY;	}	msg->dn = NULL;	/* search for the user, by rid */	ret = gendb_search(state->sam_ldb, mem_ctx, state->base_dn[database],			   &msgs, attrs, "(&(objectClass=user)(objectSid=%s))", 			   ldap_encode_ndr_dom_sid(mem_ctx, user_sid));	if (ret == -1) {		*error_string = talloc_asprintf(mem_ctx, "LDB for user %s failed: %s", 						dom_sid_string(mem_ctx, user_sid),						ldb_errstring(state->sam_ldb));		return NT_STATUS_INTERNAL_DB_CORRUPTION;	} else if (ret == 0) {		add = true;	} else if (ret > 1) {		*error_string = talloc_asprintf(mem_ctx, "More than one user with SID: %s in local LDB", 						dom_sid_string(mem_ctx, user_sid));		return NT_STATUS_INTERNAL_DB_CORRUPTION;	} else {		msg->dn = msgs[0]->dn;		talloc_steal(msg, msgs[0]->dn);	}	/* and do the same on the remote database */	if (state->remote_ldb) {		ret = gendb_search(state->remote_ldb, mem_ctx, state->base_dn[database],				   &remote_msgs, remote_attrs, "(&(objectClass=user)(objectSid=%s))", 				   ldap_encode_ndr_dom_sid(mem_ctx, user_sid));				if (ret == -1) {			*error_string = talloc_asprintf(mem_ctx, "remote LDAP for user %s failed: %s", 							dom_sid_string(mem_ctx, user_sid),							ldb_errstring(state->remote_ldb));			return NT_STATUS_INTERNAL_DB_CORRUPTION;		} else if (ret == 0) {			*error_string = talloc_asprintf(mem_ctx, "User exists in samsync but not in remote LDAP domain! (base: %s, SID: %s)", 							ldb_dn_get_linearized(state->base_dn[database]),							dom_sid_string(mem_ctx, user_sid));			return NT_STATUS_NO_SUCH_USER;		} else if (ret > 1) {			*error_string = talloc_asprintf(mem_ctx, "More than one user in remote LDAP domain with SID: %s", 							dom_sid_string(mem_ctx, user_sid));			return NT_STATUS_INTERNAL_DB_CORRUPTION;						/* Try to put things in the same location as the remote server */		} else if (add) {			msg->dn = remote_msgs[0]->dn;			talloc_steal(msg, remote_msgs[0]->dn);		}	}	cn_name   = talloc_strdup(mem_ctx, user->account_name.string);	NT_STATUS_HAVE_NO_MEMORY(cn_name);	cn_name_len = strlen(cn_name);#define ADD_OR_DEL(type, attrib, field) do {				\		if (user->field) {					\			samdb_msg_add_ ## type(state->sam_ldb, mem_ctx, msg, \					       attrib, user->field);	\		} else if (!add) {					\			samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg, \					     attrib);			\		}							\        } while (0);        ADD_OR_DEL(string, "samAccountName", account_name.string);        ADD_OR_DEL(string, "displayName", full_name.string);	if (samdb_msg_add_dom_sid(state->sam_ldb, mem_ctx, msg, 				  "objectSid", dom_sid_add_rid(mem_ctx, state->dom_sid[database], rid))) {		return NT_STATUS_NO_MEMORY; 	}        ADD_OR_DEL(uint, "primaryGroupID", primary_gid);        ADD_OR_DEL(string, "homeDirectory", home_directory.string);        ADD_OR_DEL(string, "homeDrive", home_drive.string);        ADD_OR_DEL(string, "scriptPath", logon_script.string);	ADD_OR_DEL(string, "description", description.string);	ADD_OR_DEL(string, "userWorkstations", workstations.string);	ADD_OR_DEL(uint64, "lastLogon", last_logon);	ADD_OR_DEL(uint64, "lastLogoff", last_logoff);	if (samdb_msg_add_logon_hours(state->sam_ldb, mem_ctx, msg, "logonHours", &user->logon_hours) != 0) { 		return NT_STATUS_NO_MEMORY; 	}	ADD_OR_DEL(uint, "badPwdCount", bad_password_count);	ADD_OR_DEL(uint, "logonCount", logon_count);	ADD_OR_DEL(uint64, "pwdLastSet", last_password_change);	ADD_OR_DEL(uint64, "accountExpires", acct_expiry);		if (samdb_msg_add_acct_flags(state->sam_ldb, mem_ctx, msg, 				     "userAccountControl", user->acct_flags) != 0) { 		return NT_STATUS_NO_MEMORY; 	} 		if (!add) {		/* Passwords.  Ensure there is no plaintext stored against		 * this entry, as we only have hashes */		samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  				     "sambaPassword"); 	}	if (user->lm_password_present) {		samdb_msg_add_hash(state->sam_ldb, mem_ctx, msg,  				   "dBCSPwd", &user->lmpassword);	} else if (!add) {		samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  				     "dBCSPwd"); 	}	if (user->nt_password_present) {		samdb_msg_add_hash(state->sam_ldb, mem_ctx, msg,  				   "unicodePwd", &user->ntpassword);	} else if (!add) {		samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  				     "unicodePwd"); 	}	    	ADD_OR_DEL(string, "comment", comment.string);	ADD_OR_DEL(string, "userParameters", parameters.string);	ADD_OR_DEL(uint, "countryCode", country_code);	ADD_OR_DEL(uint, "codePage", code_page);        ADD_OR_DEL(string, "profilePath", profile_path.string);#undef ADD_OR_DEL	for (i=0; remote_attrs[i]; i++) {		struct ldb_message_element *el = ldb_msg_find_element(remote_msgs[0], remote_attrs[i]);		if (!el) {			samdb_msg_add_delete(state->sam_ldb, mem_ctx, msg,  					     remote_attrs[i]); 		} else {			ldb_msg_add(msg, el, LDB_FLAG_MOD_REPLACE);		}	}	acb = user->acct_flags;	if (acb & (ACB_WSTRUST)) {		cn_name[cn_name_len - 1] = '\0';		container = "Computers";		obj_class = "computer";			} else if (acb & ACB_SVRTRUST) {		if (cn_name[cn_name_len - 1] != '$') {			return NT_STATUS_FOOBAR;				}		cn_name[cn_name_len - 1] = '\0';		container = "Domain Controllers";		obj_class = "computer";

⌨️ 快捷键说明

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