예제 #1
0
/**
 * Fill in credentials for the machine trust account, from the secrets database.
 *
 * @param cred Credentials structure to fill in
 * @retval NTSTATUS error detailing any failure
 */
static NTSTATUS cli_credentials_set_secrets_lct(struct cli_credentials *cred,
						struct loadparm_context *lp_ctx,
						struct ldb_context *ldb,
						const char *base,
						const char *filter,
						time_t secrets_tdb_last_change_time,
						const char *secrets_tdb_password,
						char **error_string)
{
	TALLOC_CTX *mem_ctx;

	int ldb_ret;
	struct ldb_message *msg;

	const char *machine_account;
	const char *password;
	const char *domain;
	const char *realm;
	enum netr_SchannelType sct;
	const char *salt_principal;
	char *keytab;
	const struct ldb_val *whenChanged;
	time_t lct;

	/* ok, we are going to get it now, don't recurse back here */
	cred->machine_account_pending = false;

	/* some other parts of the system will key off this */
	cred->machine_account = true;

	mem_ctx = talloc_named(cred, 0, "cli_credentials_set_secrets from ldb");

	if (!ldb) {
		/* Local secrets are stored in secrets.ldb */
		ldb = secrets_db_connect(mem_ctx, lp_ctx);
		if (!ldb) {
			*error_string = talloc_strdup(cred, "Could not open secrets.ldb");
			talloc_free(mem_ctx);
			return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
		}
	}

	ldb_ret = dsdb_search_one(ldb, mem_ctx, &msg,
				  ldb_dn_new(mem_ctx, ldb, base),
				  LDB_SCOPE_SUBTREE,
				  NULL, 0, "%s", filter);

	if (ldb_ret != LDB_SUCCESS) {
		*error_string = talloc_asprintf(cred, "Could not find entry to match filter: '%s' base: '%s': %s: %s",
						filter, base ? base : "",
						ldb_strerror(ldb_ret), ldb_errstring(ldb));
		talloc_free(mem_ctx);
		return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
	}

	password = ldb_msg_find_attr_as_string(msg, "secret", NULL);

	whenChanged = ldb_msg_find_ldb_val(msg, "whenChanged");
	if (!whenChanged || ldb_val_to_time(whenChanged, &lct) != LDB_SUCCESS) {
		/* This attribute is mandetory */
		talloc_free(mem_ctx);
		return NT_STATUS_NOT_FOUND;
	}

	/* Don't set secrets.ldb info if the secrets.tdb entry was more recent */
	if (lct < secrets_tdb_last_change_time) {
		talloc_free(mem_ctx);
		return NT_STATUS_NOT_FOUND;
	}

	if (lct == secrets_tdb_last_change_time && secrets_tdb_password && strcmp(password, secrets_tdb_password) != 0) {
		talloc_free(mem_ctx);
		return NT_STATUS_NOT_FOUND;
	}

	cli_credentials_set_password_last_changed_time(cred, lct);

	machine_account = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL);

	if (!machine_account) {
		machine_account = ldb_msg_find_attr_as_string(msg, "servicePrincipalName", NULL);

		if (!machine_account) {
			const char *ldap_bind_dn = ldb_msg_find_attr_as_string(msg, "ldapBindDn", NULL);
			if (!ldap_bind_dn) {
				*error_string = talloc_asprintf(cred,
								"Could not find 'samAccountName', "
								"'servicePrincipalName' or "
								"'ldapBindDn' in secrets record: %s",
								ldb_dn_get_linearized(msg->dn));
				talloc_free(mem_ctx);
				return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
			} else {
				/* store bind dn in credentials */
				cli_credentials_set_bind_dn(cred, ldap_bind_dn);
			}
		}
	}

	salt_principal = ldb_msg_find_attr_as_string(msg, "saltPrincipal", NULL);
	cli_credentials_set_salt_principal(cred, salt_principal);

	sct = ldb_msg_find_attr_as_int(msg, "secureChannelType", 0);
	if (sct) {
		cli_credentials_set_secure_channel_type(cred, sct);
	}

	if (!password) {
		const struct ldb_val *nt_password_hash = ldb_msg_find_ldb_val(msg, "unicodePwd");
		struct samr_Password hash;
		ZERO_STRUCT(hash);
		if (nt_password_hash) {
			memcpy(hash.hash, nt_password_hash->data,
			       MIN(nt_password_hash->length, sizeof(hash.hash)));

			cli_credentials_set_nt_hash(cred, &hash, CRED_SPECIFIED);
		} else {
			cli_credentials_set_password(cred, NULL, CRED_SPECIFIED);
		}
	} else {
		cli_credentials_set_password(cred, password, CRED_SPECIFIED);
	}

	domain = ldb_msg_find_attr_as_string(msg, "flatname", NULL);
	if (domain) {
		cli_credentials_set_domain(cred, domain, CRED_SPECIFIED);
	}

	realm = ldb_msg_find_attr_as_string(msg, "realm", NULL);
	if (realm) {
		cli_credentials_set_realm(cred, realm, CRED_SPECIFIED);
	}

	if (machine_account) {
		cli_credentials_set_username(cred, machine_account, CRED_SPECIFIED);
	}

	cli_credentials_set_kvno(cred, ldb_msg_find_attr_as_int(msg, "msDS-KeyVersionNumber", 0));

	/* If there was an external keytab specified by reference in
	 * the LDB, then use this.  Otherwise we will make one up
	 * (chewing CPU time) from the password */
	keytab = keytab_name_from_msg(cred, ldb, msg);
	if (keytab) {
		cli_credentials_set_keytab_name(cred, lp_ctx, keytab, CRED_SPECIFIED);
		talloc_free(keytab);
	}
	talloc_free(mem_ctx);

	return NT_STATUS_OK;
}
예제 #2
0
WERROR dsdb_extended_replicated_objects_commit(struct ldb_context *ldb,
					       struct dsdb_extended_replicated_objects *objects,
					       uint64_t *notify_uSN)
{
	struct ldb_result *ext_res;
	int ret;
	uint64_t seq_num1, seq_num2;

	/* TODO: handle linked attributes */

	/* wrap the extended operation in a transaction 
	   See [MS-DRSR] 3.3.2 Transactions
	 */
	ret = ldb_transaction_start(ldb);
	if (ret != LDB_SUCCESS) {
		DEBUG(0,(__location__ " Failed to start transaction\n"));
		return WERR_FOOBAR;
	}

	ret = dsdb_load_partition_usn(ldb, objects->partition_dn, &seq_num1);
	if (ret != LDB_SUCCESS) {
		DEBUG(0,(__location__ " Failed to load partition uSN\n"));
		ldb_transaction_cancel(ldb);
		return WERR_FOOBAR;		
	}

	ret = ldb_extended(ldb, DSDB_EXTENDED_REPLICATED_OBJECTS_OID, objects, &ext_res);
	if (ret != LDB_SUCCESS) {
		DEBUG(0,("Failed to apply records: %s: %s\n",
			 ldb_errstring(ldb), ldb_strerror(ret)));
		ldb_transaction_cancel(ldb);
		return WERR_FOOBAR;
	}
	talloc_free(ext_res);

	ret = ldb_transaction_prepare_commit(ldb);
	if (ret != LDB_SUCCESS) {
		DEBUG(0,(__location__ " Failed to prepare commit of transaction\n"));
		return WERR_FOOBAR;
	}

	ret = dsdb_load_partition_usn(ldb, objects->partition_dn, &seq_num2);
	if (ret != LDB_SUCCESS) {
		DEBUG(0,(__location__ " Failed to load partition uSN\n"));
		ldb_transaction_cancel(ldb);
		return WERR_FOOBAR;		
	}

	/* if this replication partner didn't need to be notified
	   before this transaction then it still doesn't need to be
	   notified, as the changes came from this server */	
	if (seq_num2 > seq_num1 && seq_num1 <= *notify_uSN) {
		*notify_uSN = seq_num2;
	}

	ret = ldb_transaction_commit(ldb);
	if (ret != LDB_SUCCESS) {
		DEBUG(0,(__location__ " Failed to commit transaction\n"));
		return WERR_FOOBAR;
	}


	DEBUG(2,("Replicated %u objects (%u linked attributes) for %s\n",
		 objects->num_objects, objects->linked_attributes_count,
		 ldb_dn_get_linearized(objects->partition_dn)));
		 
	return WERR_OK;
}
예제 #3
0
/**
 * Loads dsdb_schema from ldb connection using remote prefixMap.
 * Schema will be loaded only if:
 *  - ldb has no attached schema
 *  - reload_schema is true
 *
 * This function is to be used in tests that use GetNCChanges() function
 */
bool drs_util_dsdb_schema_load_ldb(struct torture_context *tctx,
				   struct ldb_context *ldb,
				   const struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr,
				   bool reload_schema)
{
	int i, ret;
	WERROR werr;
	const char *err_msg;
	struct ldb_result *a_res;
	struct ldb_result *c_res;
	struct ldb_dn *schema_dn;
	struct dsdb_schema *ldap_schema;

	ldap_schema = dsdb_get_schema(ldb, NULL);
	if (ldap_schema && !reload_schema) {
		return true;
	}

	schema_dn = ldb_get_schema_basedn(ldb);
	torture_assert(tctx, schema_dn != NULL,
		       talloc_asprintf(tctx, "ldb_get_schema_basedn() failed: %s", ldb_errstring(ldb)));

	ldap_schema = dsdb_new_schema(ldb);
	torture_assert(tctx, ldap_schema != NULL, "dsdb_new_schema() failed!");

	werr = dsdb_load_prefixmap_from_drsuapi(ldap_schema, mapping_ctr);
	torture_assert_werr_ok(tctx, werr,
			       "Failed to construct prefixMap from drsuapi data");

	/*
	 * load the attribute definitions
	 */
	ret = ldb_search(ldb, ldap_schema, &a_res,
			 schema_dn, LDB_SCOPE_ONELEVEL, NULL,
			 "(objectClass=attributeSchema)");
	if (ret != LDB_SUCCESS) {
		err_msg = talloc_asprintf(tctx,
					  "failed to search attributeSchema objects: %s",
					  ldb_errstring(ldb));
		torture_fail(tctx, err_msg);
	}

	/*
	 * load the objectClass definitions
	 */
	ret = ldb_search(ldb, ldap_schema, &c_res,
			 schema_dn, LDB_SCOPE_ONELEVEL, NULL,
			 "(objectClass=classSchema)");
	if (ret != LDB_SUCCESS) {
		err_msg = talloc_asprintf(tctx,
					  "failed to search classSchema objects: %s",
					  ldb_errstring(ldb));
		torture_fail(tctx, err_msg);
	}

	/* Build schema */
	for (i=0; i < a_res->count; i++) {
		werr = dsdb_attribute_from_ldb(ldb, ldap_schema, a_res->msgs[i]);
		torture_assert_werr_ok(tctx, werr,
				       talloc_asprintf(tctx,
						       "dsdb_attribute_from_ldb() failed for: %s",
						       ldb_dn_get_linearized(a_res->msgs[i]->dn)));
	}

	for (i=0; i < c_res->count; i++) {
		werr = dsdb_class_from_ldb(ldap_schema, c_res->msgs[i]);
		torture_assert_werr_ok(tctx, werr,
				       talloc_asprintf(tctx,
						       "dsdb_class_from_ldb() failed for: %s",
						       ldb_dn_get_linearized(c_res->msgs[i]->dn)));
	}

	talloc_free(a_res);
	talloc_free(c_res);

	ret = dsdb_set_schema(ldb, ldap_schema);
	if (ret != LDB_SUCCESS) {
		torture_fail(tctx,
			     talloc_asprintf(tctx, "dsdb_set_schema() failed: %s", ldb_strerror(ret)));
	}

	return true;
}
예제 #4
0
파일: ldb_tdb.c 프로젝트: GSam/samba
static int ltdb_add_internal(struct ldb_module *module,
			     const struct ldb_message *msg,
			     bool check_single_value)
{
	struct ldb_context *ldb = ldb_module_get_ctx(module);
	int ret = LDB_SUCCESS;
	unsigned int i, j;

	for (i=0;i<msg->num_elements;i++) {
		struct ldb_message_element *el = &msg->elements[i];
		const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(ldb, el->name);

		if (el->num_values == 0) {
			ldb_asprintf_errstring(ldb, "attribute '%s' on '%s' specified, but with 0 values (illegal)",
					       el->name, ldb_dn_get_linearized(msg->dn));
			return LDB_ERR_CONSTRAINT_VIOLATION;
		}
		if (check_single_value &&
				el->num_values > 1 &&
				ldb_tdb_single_valued(a, el)) {
			ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s specified more than once",
					       el->name, ldb_dn_get_linearized(msg->dn));
			return LDB_ERR_CONSTRAINT_VIOLATION;
		}

		/* Do not check "@ATTRIBUTES" for duplicated values */
		if (ldb_dn_is_special(msg->dn) &&
		    ldb_dn_check_special(msg->dn, LTDB_ATTRIBUTES)) {
			continue;
		}

		/* TODO: This is O(n^2) - replace with more efficient check */
		for (j=0; j<el->num_values; j++) {
			if (ldb_msg_find_val(el, &el->values[j]) != &el->values[j]) {
				ldb_asprintf_errstring(ldb,
						       "attribute '%s': value #%u on '%s' provided more than once",
						       el->name, j, ldb_dn_get_linearized(msg->dn));
				return LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
			}
		}
	}

	ret = ltdb_store(module, msg, TDB_INSERT);
	if (ret != LDB_SUCCESS) {
		if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
			ldb_asprintf_errstring(ldb,
					       "Entry %s already exists",
					       ldb_dn_get_linearized(msg->dn));
		}
		return ret;
	}

	ret = ltdb_index_add_new(module, msg);
	if (ret != LDB_SUCCESS) {
		return ret;
	}

	ret = ltdb_modified(module, msg->dn);

	return ret;
}
예제 #5
0
/**
   \details Initialize and create a message object

   \param mem_ctx pointer to the memory context to use for allocation
   \param ldb_ctx pointer to the ldb context
   \param messageID the identifier of the message to create
   \param folderID the identifier of the folder where the message is created
   \param message_object pointer on pointer to the message object to return

   \return MAPI_E_SUCCESS on success, otherwise MAPI error
 */
_PUBLIC_ enum MAPISTATUS openchangedb_message_create(TALLOC_CTX *mem_ctx, struct ldb_context *ldb_ctx,
						     uint64_t messageID, uint64_t folderID, bool fai,
						     void **message_object)
{
	enum MAPISTATUS			retval;
	struct openchangedb_message	*msg;
	struct ldb_dn			*basedn;
	char				*dn;
	char				*parentDN;
	char				*mailboxDN;
	int				i;

	/* Sanity checks */
	OPENCHANGE_RETVAL_IF(!ldb_ctx, MAPI_E_NOT_INITIALIZED, NULL);
	OPENCHANGE_RETVAL_IF(!message_object, MAPI_E_NOT_INITIALIZED, NULL);
	
	/* Retrieve distinguishedName of parent folder */
	retval = openchangedb_get_distinguishedName(mem_ctx, ldb_ctx, folderID, &parentDN);
	OPENCHANGE_RETVAL_IF(retval, retval, NULL);

	/* Retrieve mailboxDN of parent folder */
	retval = openchangedb_get_mailboxDN(mem_ctx, ldb_ctx, folderID, &mailboxDN);
	if (retval) {
		mailboxDN = NULL;
	}
	
	dn = talloc_asprintf(mem_ctx, "CN=%"PRIu64",%s", messageID, parentDN);
	OPENCHANGE_RETVAL_IF(!dn, MAPI_E_NOT_ENOUGH_MEMORY, NULL);
	basedn = ldb_dn_new(mem_ctx, ldb_ctx, dn);
	talloc_free(dn);

	OPENCHANGE_RETVAL_IF(!ldb_dn_validate(basedn), MAPI_E_BAD_VALUE, NULL);

	msg = talloc_zero(mem_ctx, struct openchangedb_message);
	OPENCHANGE_RETVAL_IF(!msg, MAPI_E_NOT_ENOUGH_MEMORY, NULL);

	msg->status = OPENCHANGEDB_MESSAGE_CREATE;
	msg->folderID = folderID;
	msg->messageID = messageID;
	msg->ldb_ctx = ldb_ctx;
	msg->msg = NULL;
	msg->res = NULL;

	msg->msg = ldb_msg_new((TALLOC_CTX *)msg);
	OPENCHANGE_RETVAL_IF(!msg->msg, MAPI_E_NOT_ENOUGH_MEMORY, msg);

	msg->msg->dn = ldb_dn_copy((TALLOC_CTX *)msg->msg, basedn);

	/* Add openchangedb required attributes */
	ldb_msg_add_string(msg->msg, "objectClass", fai ? "faiMessage" : "systemMessage");
	ldb_msg_add_fmt(msg->msg, "cn", "%"PRIu64, messageID);
	ldb_msg_add_fmt(msg->msg, "PidTagParentFolderId", "%"PRIu64, folderID);
	ldb_msg_add_fmt(msg->msg, "PidTagMessageId", "%"PRIu64, messageID);
	ldb_msg_add_fmt(msg->msg, "distinguishedName", "%s", ldb_dn_get_linearized(msg->msg->dn));
	if (mailboxDN) {
		ldb_msg_add_string(msg->msg, "mailboxDN", mailboxDN);
	}

	/* Add required properties as described in [MS_OXCMSG] 3.2.5.2 */
	ldb_msg_add_string(msg->msg, "PidTagDisplayBcc", "");
	ldb_msg_add_string(msg->msg, "PidTagDisplayCc", "");
	ldb_msg_add_string(msg->msg, "PidTagDisplayTo", "");
	/* PidTagMessageSize */
	/* PidTagSecurityDescriptor */
	/* ldb_msg_add_string(msg->msg, "PidTagCreationTime", ""); */
	/* ldb_msg_add_string(msg->msg, "PidTagLastModificationTime", ""); */
	/* PidTagSearchKey */
	/* PidTagMessageLocalId */
	/* PidTagCreatorName */
	/* PidTagCreatorEntryId */
	ldb_msg_add_fmt(msg->msg, "PidTagHasNamedProperties", "%d", 0x0);
	/* PidTagLocaleId same as PidTagMessageLocaleId */
	/* PidTagLocalCommitTime same as PidTagCreationTime */

	/* Set LDB flag */
	for (i = 0; i < msg->msg->num_elements; i++) {
		msg->msg->elements[i].flags = LDB_FLAG_MOD_ADD;
	}

	*message_object = (void *)msg;

	return MAPI_E_SUCCESS;
}
예제 #6
0
/*
  samr_OemChangePasswordUser2
*/
NTSTATUS dcesrv_samr_OemChangePasswordUser2(struct dcesrv_call_state *dce_call,
					    TALLOC_CTX *mem_ctx,
					    struct samr_OemChangePasswordUser2 *r)
{
	NTSTATUS status;
	DATA_BLOB new_password, new_unicode_password;
	char *new_pass;
	struct samr_CryptPassword *pwbuf = r->in.password;
	struct ldb_context *sam_ctx;
	struct ldb_dn *user_dn;
	int ret;
	struct ldb_message **res;
	const char * const attrs[] = { "objectSid", "dBCSPwd", NULL };
	struct samr_Password *lm_pwd;
	DATA_BLOB lm_pwd_blob;
	uint8_t new_lm_hash[16];
	struct samr_Password lm_verifier;
	size_t unicode_pw_len;

	if (pwbuf == NULL) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	if (r->in.hash == NULL) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	/* this call can only work with lanman auth */
	if (!lpcfg_lanman_auth(dce_call->conn->dce_ctx->lp_ctx)) {
		return NT_STATUS_WRONG_PASSWORD;
	}

	/* Connect to a SAMDB with system privileges for fetching the old pw
	 * hashes. */
	sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
				dce_call->conn->dce_ctx->lp_ctx,
				system_session(dce_call->conn->dce_ctx->lp_ctx), 0);
	if (sam_ctx == NULL) {
		return NT_STATUS_INVALID_SYSTEM_SERVICE;
	}

	/* we need the users dn and the domain dn (derived from the
	   user SID). We also need the current lm password hash in
	   order to decrypt the incoming password */
	ret = gendb_search(sam_ctx,
			   mem_ctx, NULL, &res, attrs,
			   "(&(sAMAccountName=%s)(objectclass=user))",
			   r->in.account->string);
	if (ret != 1) {
		/* Don't give the game away:  (don't allow anonymous users to prove the existance of usernames) */
		return NT_STATUS_WRONG_PASSWORD;
	}

	user_dn = res[0]->dn;

	status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx,
					res[0], &lm_pwd, NULL);
	if (!NT_STATUS_IS_OK(status) || !lm_pwd) {
		return NT_STATUS_WRONG_PASSWORD;
	}

	/* decrypt the password we have been given */
	lm_pwd_blob = data_blob(lm_pwd->hash, sizeof(lm_pwd->hash));
	arcfour_crypt_blob(pwbuf->data, 516, &lm_pwd_blob);
	data_blob_free(&lm_pwd_blob);

	if (!extract_pw_from_buffer(mem_ctx, pwbuf->data, &new_password)) {
		DEBUG(3,("samr: failed to decode password buffer\n"));
		return NT_STATUS_WRONG_PASSWORD;
	}

	if (!convert_string_talloc_convenience(mem_ctx, lpcfg_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx),
				  CH_DOS, CH_UNIX,
				  (const char *)new_password.data,
				  new_password.length,
				  (void **)&new_pass, NULL, false)) {
		DEBUG(3,("samr: failed to convert incoming password buffer to unix charset\n"));
		return NT_STATUS_WRONG_PASSWORD;
	}

	if (!convert_string_talloc_convenience(mem_ctx, lpcfg_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx),
					       CH_DOS, CH_UTF16,
					       (const char *)new_password.data,
					       new_password.length,
					       (void **)&new_unicode_password.data, &unicode_pw_len, false)) {
		DEBUG(3,("samr: failed to convert incoming password buffer to UTF16 charset\n"));
		return NT_STATUS_WRONG_PASSWORD;
	}
	new_unicode_password.length = unicode_pw_len;

	E_deshash(new_pass, new_lm_hash);
	E_old_pw_hash(new_lm_hash, lm_pwd->hash, lm_verifier.hash);
	if (memcmp(lm_verifier.hash, r->in.hash->hash, 16) != 0) {
		return NT_STATUS_WRONG_PASSWORD;
	}

	/* Connect to a SAMDB with user privileges for the password change */
	sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
				dce_call->conn->dce_ctx->lp_ctx,
				dce_call->conn->auth_state.session_info, 0);
	if (sam_ctx == NULL) {
		return NT_STATUS_INVALID_SYSTEM_SERVICE;
	}

	/* Start transaction */
	ret = ldb_transaction_start(sam_ctx);
	if (ret != LDB_SUCCESS) {
		DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
		return NT_STATUS_TRANSACTION_ABORTED;
	}

	/* Performs the password modification. We pass the old hashes read out
	 * from the database since they were already checked against the user-
	 * provided ones. */
	status = samdb_set_password(sam_ctx, mem_ctx,
				    user_dn, NULL,
				    &new_unicode_password,
				    NULL, NULL,
				    lm_pwd, NULL, /* this is a user password change */
				    NULL,
				    NULL);
	if (!NT_STATUS_IS_OK(status)) {
		ldb_transaction_cancel(sam_ctx);
		return status;
	}

	/* And this confirms it in a transaction commit */
	ret = ldb_transaction_commit(sam_ctx);
	if (ret != LDB_SUCCESS) {
		DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
			 ldb_dn_get_linearized(user_dn),
			 ldb_errstring(sam_ctx)));
		return NT_STATUS_TRANSACTION_ABORTED;
	}

	return NT_STATUS_OK;
}
예제 #7
0
/*
  samr_ChangePasswordUser
*/
NTSTATUS dcesrv_samr_ChangePasswordUser(struct dcesrv_call_state *dce_call,
					TALLOC_CTX *mem_ctx,
					struct samr_ChangePasswordUser *r)
{
	struct dcesrv_handle *h;
	struct samr_account_state *a_state;
	struct ldb_context *sam_ctx;
	struct ldb_message **res;
	int ret;
	struct samr_Password new_lmPwdHash, new_ntPwdHash, checkHash;
	struct samr_Password *lm_pwd, *nt_pwd;
	NTSTATUS status = NT_STATUS_OK;
	const char * const attrs[] = { "dBCSPwd", "unicodePwd" , NULL };

	DCESRV_PULL_HANDLE(h, r->in.user_handle, SAMR_HANDLE_USER);

	a_state = h->data;

	/* basic sanity checking on parameters.  Do this before any database ops */
	if (!r->in.lm_present || !r->in.nt_present ||
	    !r->in.old_lm_crypted || !r->in.new_lm_crypted ||
	    !r->in.old_nt_crypted || !r->in.new_nt_crypted) {
		/* we should really handle a change with lm not
		   present */
		return NT_STATUS_INVALID_PARAMETER_MIX;
	}

	/* Connect to a SAMDB with system privileges for fetching the old pw
	 * hashes. */
	sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
				dce_call->conn->dce_ctx->lp_ctx,
				system_session(dce_call->conn->dce_ctx->lp_ctx), 0);
	if (sam_ctx == NULL) {
		return NT_STATUS_INVALID_SYSTEM_SERVICE;
	}

	/* fetch the old hashes */
	ret = gendb_search_dn(sam_ctx, mem_ctx,
			      a_state->account_dn, &res, attrs);
	if (ret != 1) {
		return NT_STATUS_WRONG_PASSWORD;
	}

	status = samdb_result_passwords(mem_ctx,
					dce_call->conn->dce_ctx->lp_ctx,
					res[0], &lm_pwd, &nt_pwd);
	if (!NT_STATUS_IS_OK(status) || !nt_pwd) {
		return NT_STATUS_WRONG_PASSWORD;
	}

	/* decrypt and check the new lm hash */
	if (lm_pwd) {
		D_P16(lm_pwd->hash, r->in.new_lm_crypted->hash, new_lmPwdHash.hash);
		D_P16(new_lmPwdHash.hash, r->in.old_lm_crypted->hash, checkHash.hash);
		if (memcmp(checkHash.hash, lm_pwd, 16) != 0) {
			return NT_STATUS_WRONG_PASSWORD;
		}
	}

	/* decrypt and check the new nt hash */
	D_P16(nt_pwd->hash, r->in.new_nt_crypted->hash, new_ntPwdHash.hash);
	D_P16(new_ntPwdHash.hash, r->in.old_nt_crypted->hash, checkHash.hash);
	if (memcmp(checkHash.hash, nt_pwd, 16) != 0) {
		return NT_STATUS_WRONG_PASSWORD;
	}

	/* The NT Cross is not required by Win2k3 R2, but if present
	   check the nt cross hash */
	if (r->in.cross1_present && r->in.nt_cross && lm_pwd) {
		D_P16(lm_pwd->hash, r->in.nt_cross->hash, checkHash.hash);
		if (memcmp(checkHash.hash, new_ntPwdHash.hash, 16) != 0) {
			return NT_STATUS_WRONG_PASSWORD;
		}
	}

	/* The LM Cross is not required by Win2k3 R2, but if present
	   check the lm cross hash */
	if (r->in.cross2_present && r->in.lm_cross && lm_pwd) {
		D_P16(nt_pwd->hash, r->in.lm_cross->hash, checkHash.hash);
		if (memcmp(checkHash.hash, new_lmPwdHash.hash, 16) != 0) {
			return NT_STATUS_WRONG_PASSWORD;
		}
	}

	/* Start a SAM with user privileges for the password change */
	sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
				dce_call->conn->dce_ctx->lp_ctx,
				dce_call->conn->auth_state.session_info, 0);
	if (sam_ctx == NULL) {
		return NT_STATUS_INVALID_SYSTEM_SERVICE;
	}

	/* Start transaction */
	ret = ldb_transaction_start(sam_ctx);
	if (ret != LDB_SUCCESS) {
		DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
		return NT_STATUS_TRANSACTION_ABORTED;
	}

	/* Performs the password modification. We pass the old hashes read out
	 * from the database since they were already checked against the user-
	 * provided ones. */
	status = samdb_set_password(sam_ctx, mem_ctx,
				    a_state->account_dn,
				    a_state->domain_state->domain_dn,
				    NULL, &new_lmPwdHash, &new_ntPwdHash,
				    lm_pwd, nt_pwd, /* this is a user password change */
				    NULL,
				    NULL);
	if (!NT_STATUS_IS_OK(status)) {
		ldb_transaction_cancel(sam_ctx);
		return status;
	}

	/* And this confirms it in a transaction commit */
	ret = ldb_transaction_commit(sam_ctx);
	if (ret != LDB_SUCCESS) {
		DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
			 ldb_dn_get_linearized(a_state->account_dn),
			 ldb_errstring(sam_ctx)));
		return NT_STATUS_TRANSACTION_ABORTED;
	}

	return NT_STATUS_OK;
}
예제 #8
0
파일: libnet_join.c 프로젝트: gojdic/samba
/*
 * 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			= talloc(r, union drsuapi_DsNameRequest);
	if (!r_crack_names.in.req) {
		r->out.error_string = NULL;
		talloc_free(tmp_ctx);
		return NT_STATUS_NO_MEMORY;
	}
	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;
	}

	r_crack_names.out.ctr			= talloc(r, union drsuapi_DsNameCtr);
	r_crack_names.out.level_out		= talloc(r, int32_t);
	if (!r_crack_names.out.ctr || !r_crack_names.out.level_out) {
		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_out != 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, tmp_ctx, &res,
			 account_dn, LDB_SCOPE_BASE, attrs, NULL);
	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;
	}

	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_out != 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;
}
예제 #9
0
WERROR dsdb_origin_objects_commit(struct ldb_context *ldb,
				  TALLOC_CTX *mem_ctx,
				  const struct drsuapi_DsReplicaObjectListItem *first_object,
				  uint32_t *_num,
				  uint32_t dsdb_repl_flags,
				  struct drsuapi_DsReplicaObjectIdentifier2 **_ids)
{
	WERROR status;
	const struct dsdb_schema *schema;
	const struct drsuapi_DsReplicaObjectListItem *cur;
	struct ldb_message **objects;
	struct drsuapi_DsReplicaObjectIdentifier2 *ids;
	uint32_t i;
	uint32_t num_objects = 0;
	const char * const attrs[] = {
		"objectGUID",
		"objectSid",
		NULL
	};
	struct ldb_result *res;
	int ret;

	for (cur = first_object; cur; cur = cur->next_object) {
		num_objects++;
	}

	if (num_objects == 0) {
		return WERR_OK;
	}

	ret = ldb_transaction_start(ldb);
	if (ret != LDB_SUCCESS) {
		return WERR_DS_INTERNAL_FAILURE;
	}

	objects	= talloc_array(mem_ctx, struct ldb_message *,
			       num_objects);
	if (objects == NULL) {
		status = WERR_NOMEM;
		goto cancel;
	}

	schema = dsdb_get_schema(ldb, objects);
	if (!schema) {
		return WERR_DS_SCHEMA_NOT_LOADED;
	}

	for (i=0, cur = first_object; cur; cur = cur->next_object, i++) {
		status = dsdb_origin_object_convert(ldb, schema, cur,
						    objects, &objects[i]);
		if (!W_ERROR_IS_OK(status)) {
			goto cancel;
		}
	}

	ids = talloc_array(mem_ctx,
			   struct drsuapi_DsReplicaObjectIdentifier2,
			   num_objects);
	if (ids == NULL) {
		status = WERR_NOMEM;
		goto cancel;
	}

	if (dsdb_repl_flags & DSDB_REPL_FLAG_ADD_NCNAME) {
		/* check for possible NC creation */
		for (i=0; i < num_objects; i++) {
			struct ldb_message *msg = objects[i];
			struct ldb_message_element *el;
			struct ldb_dn *nc_dn;

			if (ldb_msg_check_string_attribute(msg, "objectClass", "crossRef") == 0) {
				continue;
			}
			el = ldb_msg_find_element(msg, "nCName");
			if (el == NULL || el->num_values != 1) {
				continue;
			}
			nc_dn = ldb_dn_from_ldb_val(objects, ldb, &el->values[0]);
			if (!ldb_dn_validate(nc_dn)) {
				continue;
			}
			ret = dsdb_create_partial_replica_NC(ldb, nc_dn);
			if (ret != LDB_SUCCESS) {
				status = WERR_DS_INTERNAL_FAILURE;
				goto cancel;
			}
		}
	}

	for (i=0; i < num_objects; i++) {
		struct dom_sid *sid = NULL;
		struct ldb_request *add_req;

		DEBUG(6,(__location__ ": adding %s\n", 
			 ldb_dn_get_linearized(objects[i]->dn)));

		ret = ldb_build_add_req(&add_req,
					ldb,
					objects,
					objects[i],
					NULL,
					NULL,
					ldb_op_default_callback,
					NULL);
		if (ret != LDB_SUCCESS) {
			status = WERR_DS_INTERNAL_FAILURE;
			goto cancel;
		}

		ret = ldb_request_add_control(add_req, LDB_CONTROL_RELAX_OID, true, NULL);
		if (ret != LDB_SUCCESS) {
			status = WERR_DS_INTERNAL_FAILURE;
			goto cancel;
		}
		
		ret = ldb_request(ldb, add_req);
		if (ret == LDB_SUCCESS) {
			ret = ldb_wait(add_req->handle, LDB_WAIT_ALL);
		}
		if (ret != LDB_SUCCESS) {
			DEBUG(0,(__location__ ": Failed add of %s - %s\n",
				 ldb_dn_get_linearized(objects[i]->dn), ldb_errstring(ldb)));
			status = WERR_DS_INTERNAL_FAILURE;
			goto cancel;
		}

		talloc_free(add_req);

		ret = ldb_search(ldb, objects, &res, objects[i]->dn,
				 LDB_SCOPE_BASE, attrs,
				 "(objectClass=*)");
		if (ret != LDB_SUCCESS) {
			status = WERR_DS_INTERNAL_FAILURE;
			goto cancel;
		}
		ids[i].guid = samdb_result_guid(res->msgs[0], "objectGUID");
		sid = samdb_result_dom_sid(objects, res->msgs[0], "objectSid");
		if (sid) {
			ids[i].sid = *sid;
		} else {
			ZERO_STRUCT(ids[i].sid);
		}
	}

	ret = ldb_transaction_commit(ldb);
	if (ret != LDB_SUCCESS) {
		return WERR_DS_INTERNAL_FAILURE;
	}

	talloc_free(objects);

	*_num = num_objects;
	*_ids = ids;
	return WERR_OK;

cancel:
	talloc_free(objects);
	ldb_transaction_cancel(ldb);
	return status;
}
예제 #10
0
파일: cracknames.c 프로젝트: endisd/samba
WERROR DsCrackNameOneName(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
                          uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,
                          const char *name, struct drsuapi_DsNameInfo1 *info1)
{
    krb5_error_code ret;
    const char *domain_filter = NULL;
    const char *result_filter = NULL;
    struct ldb_dn *name_dn = NULL;

    struct smb_krb5_context *smb_krb5_context = NULL;

    info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
    info1->dns_domain_name = NULL;
    info1->result_name = NULL;

    if (!name) {
        return WERR_INVALID_PARAM;
    }

    /* TODO: - fill the correct names in all cases!
     *       - handle format_flags
     */

    /* here we need to set the domain_filter and/or the result_filter */
    switch (format_offered) {
    case DRSUAPI_DS_NAME_FORMAT_UNKNOWN:
    {
        int i;
        enum drsuapi_DsNameFormat formats[] = {
            DRSUAPI_DS_NAME_FORMAT_FQDN_1779, DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL,
            DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT, DRSUAPI_DS_NAME_FORMAT_CANONICAL,
            DRSUAPI_DS_NAME_FORMAT_GUID, DRSUAPI_DS_NAME_FORMAT_DISPLAY,
            DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL,
            DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY,
            DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX
        };
        WERROR werr;
        for (i=0; i < ARRAY_SIZE(formats); i++) {
            werr = DsCrackNameOneName(sam_ctx, mem_ctx, format_flags, formats[i], format_desired, name, info1);
            if (!W_ERROR_IS_OK(werr)) {
                return werr;
            }
            if (info1->status != DRSUAPI_DS_NAME_STATUS_NOT_FOUND) {
                return werr;
            }
        }
        return werr;
    }

    case DRSUAPI_DS_NAME_FORMAT_CANONICAL:
    case DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX:
    {
        char *str, *s, *account;

        if (strlen(name) == 0) {
            info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
            return WERR_OK;
        }

        str = talloc_strdup(mem_ctx, name);
        W_ERROR_HAVE_NO_MEMORY(str);

        if (format_offered == DRSUAPI_DS_NAME_FORMAT_CANONICAL_EX) {
            /* Look backwards for the \n, and replace it with / */
            s = strrchr(str, '\n');
            if (!s) {
                info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
                return WERR_OK;
            }
            s[0] = '/';
        }

        s = strchr(str, '/');
        if (!s) {
            /* there must be at least one / */
            info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
            return WERR_OK;
        }

        s[0] = '\0';
        s++;

        domain_filter = talloc_asprintf(mem_ctx, "(&(objectClass=crossRef)(ncName=%s))",
                                        ldb_dn_get_linearized(samdb_dns_domain_to_dn(sam_ctx, mem_ctx, str)));
        W_ERROR_HAVE_NO_MEMORY(domain_filter);

        /* There may not be anything after the domain component (search for the domain itself) */
        if (s[0]) {

            account = strrchr(s, '/');
            if (!account) {
                account = s;
            } else {
                account++;
            }
            account = ldb_binary_encode_string(mem_ctx, account);
            W_ERROR_HAVE_NO_MEMORY(account);
            result_filter = talloc_asprintf(mem_ctx, "(name=%s)",
                                            account);
            W_ERROR_HAVE_NO_MEMORY(result_filter);
        }
        break;
    }
    case DRSUAPI_DS_NAME_FORMAT_NT4_ACCOUNT: {
        char *p;
        char *domain;
        const char *account = NULL;

        domain = talloc_strdup(mem_ctx, name);
        W_ERROR_HAVE_NO_MEMORY(domain);

        p = strchr(domain, '\\');
        if (!p) {
            /* invalid input format */
            info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
            return WERR_OK;
        }
        p[0] = '\0';

        if (p[1]) {
            account = &p[1];
        }

        domain_filter = talloc_asprintf(mem_ctx,
                                        "(&(&(nETBIOSName=%s)(objectclass=crossRef))(ncName=*))",
                                        ldb_binary_encode_string(mem_ctx, domain));
        W_ERROR_HAVE_NO_MEMORY(domain_filter);
        if (account) {
            result_filter = talloc_asprintf(mem_ctx, "(sAMAccountName=%s)",
                                            ldb_binary_encode_string(mem_ctx, account));
            W_ERROR_HAVE_NO_MEMORY(result_filter);
        }

        talloc_free(domain);
        break;
    }

    /* A LDAP DN as a string */
    case DRSUAPI_DS_NAME_FORMAT_FQDN_1779: {
        domain_filter = NULL;
        name_dn = ldb_dn_new(mem_ctx, sam_ctx, name);
        if (! ldb_dn_validate(name_dn)) {
            info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
            return WERR_OK;
        }
        break;
    }

    /* A GUID as a string */
    case DRSUAPI_DS_NAME_FORMAT_GUID: {
        struct GUID guid;
        char *ldap_guid;
        NTSTATUS nt_status;
        domain_filter = NULL;

        nt_status = GUID_from_string(name, &guid);
        if (!NT_STATUS_IS_OK(nt_status)) {
            info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
            return WERR_OK;
        }

        ldap_guid = ldap_encode_ndr_GUID(mem_ctx, &guid);
        if (!ldap_guid) {
            return WERR_NOMEM;
        }
        result_filter = talloc_asprintf(mem_ctx, "(objectGUID=%s)",
                                        ldap_guid);
        W_ERROR_HAVE_NO_MEMORY(result_filter);
        break;
    }
    case DRSUAPI_DS_NAME_FORMAT_DISPLAY: {
        domain_filter = NULL;

        result_filter = talloc_asprintf(mem_ctx, "(|(displayName=%s)(samAccountName=%s))",
                                        ldb_binary_encode_string(mem_ctx, name),
                                        ldb_binary_encode_string(mem_ctx, name));
        W_ERROR_HAVE_NO_MEMORY(result_filter);
        break;
    }

    /* A S-1234-5678 style string */
    case DRSUAPI_DS_NAME_FORMAT_SID_OR_SID_HISTORY: {
        struct dom_sid *sid = dom_sid_parse_talloc(mem_ctx, name);
        char *ldap_sid;

        domain_filter = NULL;
        if (!sid) {
            info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
            return WERR_OK;
        }
        ldap_sid = ldap_encode_ndr_dom_sid(mem_ctx,
                                           sid);
        if (!ldap_sid) {
            return WERR_NOMEM;
        }
        result_filter = talloc_asprintf(mem_ctx, "(objectSid=%s)",
                                        ldap_sid);
        W_ERROR_HAVE_NO_MEMORY(result_filter);
        break;
    }
    case DRSUAPI_DS_NAME_FORMAT_USER_PRINCIPAL: {
        krb5_principal principal;
        char *unparsed_name;

        ret = smb_krb5_init_context(mem_ctx,
                                    ldb_get_event_context(sam_ctx),
                                    (struct loadparm_context *)ldb_get_opaque(sam_ctx, "loadparm"),
                                    &smb_krb5_context);

        if (ret) {
            return WERR_NOMEM;
        }

        /* Ensure we reject compleate junk first */
        ret = krb5_parse_name(smb_krb5_context->krb5_context, name, &principal);
        if (ret) {
            info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
            return WERR_OK;
        }

        domain_filter = NULL;

        /* By getting the unparsed name here, we ensure the escaping is correct (and trust the client less) */
        ret = krb5_unparse_name(smb_krb5_context->krb5_context, principal, &unparsed_name);
        if (ret) {
            krb5_free_principal(smb_krb5_context->krb5_context, principal);
            return WERR_NOMEM;
        }

        krb5_free_principal(smb_krb5_context->krb5_context, principal);

        /* The ldb_binary_encode_string() here avoid LDAP filter injection attacks */
        result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(userPrincipalName=%s))",
                                        ldb_binary_encode_string(mem_ctx, unparsed_name));

        free(unparsed_name);
        W_ERROR_HAVE_NO_MEMORY(result_filter);
        break;
    }
    case DRSUAPI_DS_NAME_FORMAT_SERVICE_PRINCIPAL: {
        krb5_principal principal;
        char *unparsed_name_short;
        char *service;

        ret = smb_krb5_init_context(mem_ctx,
                                    ldb_get_event_context(sam_ctx),
                                    (struct loadparm_context *)ldb_get_opaque(sam_ctx, "loadparm"),
                                    &smb_krb5_context);

        if (ret) {
            return WERR_NOMEM;
        }

        ret = krb5_parse_name(smb_krb5_context->krb5_context, name, &principal);
        if (ret == 0 && principal->name.name_string.len < 2) {
            info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
            krb5_free_principal(smb_krb5_context->krb5_context, principal);
            return WERR_OK;
        }
        ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name,
                                    KRB5_PRINCIPAL_PARSE_NO_REALM, &principal);
        if (ret) {
            krb5_free_principal(smb_krb5_context->krb5_context, principal);

            return dns_domain_from_principal(mem_ctx, smb_krb5_context,
                                             name, info1);
        }

        domain_filter = NULL;

        ret = krb5_unparse_name_flags(smb_krb5_context->krb5_context, principal,
                                      KRB5_PRINCIPAL_UNPARSE_NO_REALM, &unparsed_name_short);
        if (ret) {
            krb5_free_principal(smb_krb5_context->krb5_context, principal);
            return WERR_NOMEM;
        }

        service = principal->name.name_string.val[0];
        if ((principal->name.name_string.len == 2) && (strcasecmp(service, "host") == 0)) {
            /* the 'cn' attribute is just the leading part of the name */
            char *computer_name;
            computer_name = talloc_strndup(mem_ctx, principal->name.name_string.val[1],
                                           strcspn(principal->name.name_string.val[1], "."));
            if (computer_name == NULL) {
                return WERR_NOMEM;
            }

            result_filter = talloc_asprintf(mem_ctx, "(|(&(servicePrincipalName=%s)(objectClass=user))(&(cn=%s)(objectClass=computer)))",
                                            ldb_binary_encode_string(mem_ctx, unparsed_name_short),
                                            ldb_binary_encode_string(mem_ctx, computer_name));
        } else {
            result_filter = talloc_asprintf(mem_ctx, "(&(servicePrincipalName=%s)(objectClass=user))",
                                            ldb_binary_encode_string(mem_ctx, unparsed_name_short));
        }
        krb5_free_principal(smb_krb5_context->krb5_context, principal);
        free(unparsed_name_short);
        W_ERROR_HAVE_NO_MEMORY(result_filter);

        break;
    }
    default: {
        info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
        return WERR_OK;
    }

    }

    if (format_flags & DRSUAPI_DS_NAME_FLAG_SYNTACTICAL_ONLY) {
        return DsCrackNameOneSyntactical(mem_ctx, format_offered, format_desired,
                                         name_dn, name, info1);
    }

    return DsCrackNameOneFilter(sam_ctx, mem_ctx,
                                smb_krb5_context,
                                format_flags, format_offered, format_desired,
                                name_dn, name,
                                domain_filter, result_filter,
                                info1);
}
예제 #11
0
/*
  remember an established session key for a netr server authentication
  use a simple ldb structure
*/
NTSTATUS schannel_store_session_key_ldb(TALLOC_CTX *mem_ctx,
					struct ldb_context *ldb,
					struct creds_CredentialState *creds)
{
	struct ldb_message *msg;
	struct ldb_val val, seed, client_state, server_state;
	char *f;
	char *sct;
	int ret;

	f = talloc_asprintf(mem_ctx, "%u", (unsigned int)creds->negotiate_flags);

	if (f == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	sct = talloc_asprintf(mem_ctx, "%u", (unsigned int)creds->secure_channel_type);

	if (sct == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	msg = ldb_msg_new(ldb);
	if (msg == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	msg->dn = ldb_dn_new_fmt(msg, ldb, "computerName=%s", creds->computer_name);
	if ( ! msg->dn) {
		return NT_STATUS_NO_MEMORY;
	}

	val.data = creds->session_key;
	val.length = sizeof(creds->session_key);

	seed.data = creds->seed.data;
	seed.length = sizeof(creds->seed.data);

	client_state.data = creds->client.data;
	client_state.length = sizeof(creds->client.data);
	server_state.data = creds->server.data;
	server_state.length = sizeof(creds->server.data);

	ldb_msg_add_string(msg, "objectClass", "schannelState");
	ldb_msg_add_value(msg, "sessionKey", &val, NULL);
	ldb_msg_add_value(msg, "seed", &seed, NULL);
	ldb_msg_add_value(msg, "clientState", &client_state, NULL);
	ldb_msg_add_value(msg, "serverState", &server_state, NULL);
	ldb_msg_add_string(msg, "negotiateFlags", f);
	ldb_msg_add_string(msg, "secureChannelType", sct);
	ldb_msg_add_string(msg, "accountName", creds->account_name);
	ldb_msg_add_string(msg, "computerName", creds->computer_name);
	ldb_msg_add_string(msg, "flatname", creds->domain);
	samdb_msg_add_dom_sid(ldb, mem_ctx, msg, "objectSid", creds->sid);

	ldb_delete(ldb, msg->dn);

	ret = ldb_add(ldb, msg);

	if (ret != 0) {
		DEBUG(0,("Unable to add %s to session key db - %s\n", 
			 ldb_dn_get_linearized(msg->dn), ldb_errstring(ldb)));
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}

	return NT_STATUS_OK;
}
예제 #12
0
파일: cracknames.c 프로젝트: endisd/samba
static WERROR DsCrackNameUPN(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
                             struct smb_krb5_context *smb_krb5_context,
                             uint32_t format_flags, uint32_t format_offered, uint32_t format_desired,
                             const char *name, struct drsuapi_DsNameInfo1 *info1)
{
    int ldb_ret;
    WERROR status;
    const char *domain_filter = NULL;
    const char *result_filter = NULL;
    krb5_error_code ret;
    krb5_principal principal;
    const char *realm;
    char *unparsed_name_short;
    const char *domain_attrs[] = { NULL };
    struct ldb_result *domain_res = NULL;

    /* Prevent recursion */
    if (!name) {
        info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
        return WERR_OK;
    }

    ret = krb5_parse_name_flags(smb_krb5_context->krb5_context, name,
                                KRB5_PRINCIPAL_PARSE_REQUIRE_REALM, &principal);
    if (ret) {
        info1->status = DRSUAPI_DS_NAME_STATUS_NOT_FOUND;
        return WERR_OK;
    }

    realm = krb5_principal_get_realm(smb_krb5_context->krb5_context, principal);

    ldb_ret = ldb_search(sam_ctx, mem_ctx, &domain_res,
                         samdb_partitions_dn(sam_ctx, mem_ctx),
                         LDB_SCOPE_ONELEVEL,
                         domain_attrs,
                         "(&(&(|(&(dnsRoot=%s)(nETBIOSName=*))(nETBIOSName=%s))(objectclass=crossRef))(ncName=*))",
                         ldb_binary_encode_string(mem_ctx, realm),
                         ldb_binary_encode_string(mem_ctx, realm));

    if (ldb_ret != LDB_SUCCESS) {
        DEBUG(2, ("DsCrackNameUPN domain ref search failed: %s", ldb_errstring(sam_ctx)));
        info1->status = DRSUAPI_DS_NAME_STATUS_RESOLVE_ERROR;
        return WERR_OK;
    }

    switch (domain_res->count) {
    case 1:
        break;
    case 0:
        return dns_domain_from_principal(mem_ctx, smb_krb5_context,
                                         name, info1);
    default:
        info1->status = DRSUAPI_DS_NAME_STATUS_NOT_UNIQUE;
        return WERR_OK;
    }

    ret = krb5_unparse_name_flags(smb_krb5_context->krb5_context, principal,
                                  KRB5_PRINCIPAL_UNPARSE_NO_REALM, &unparsed_name_short);
    krb5_free_principal(smb_krb5_context->krb5_context, principal);

    if (ret) {
        free(unparsed_name_short);
        return WERR_NOMEM;
    }

    /* This may need to be extended for more userPrincipalName variations */
    result_filter = talloc_asprintf(mem_ctx, "(&(objectClass=user)(samAccountName=%s))",
                                    ldb_binary_encode_string(mem_ctx, unparsed_name_short));

    domain_filter = talloc_asprintf(mem_ctx, "(distinguishedName=%s)", ldb_dn_get_linearized(domain_res->msgs[0]->dn));

    if (!result_filter || !domain_filter) {
        free(unparsed_name_short);
        return WERR_NOMEM;
    }
    status = DsCrackNameOneFilter(sam_ctx, mem_ctx,
                                  smb_krb5_context,
                                  format_flags, format_offered, format_desired,
                                  NULL, unparsed_name_short, domain_filter, result_filter,
                                  info1);
    free(unparsed_name_short);

    return status;
}
예제 #13
0
파일: rdn_name.c 프로젝트: 0x24bin/winexe-1
static int rdn_name_add(struct ldb_module *module, struct ldb_request *req)
{
	struct ldb_context *ldb;
	struct ldb_request *down_req;
	struct rename_context *ac;
	struct ldb_message *msg;
	struct ldb_message_element *attribute;
	const struct ldb_schema_attribute *a;
	const char *rdn_name;
	struct ldb_val rdn_val;
	int i, ret;

	ldb = ldb_module_get_ctx(module);

	/* do not manipulate our control entries */
	if (ldb_dn_is_special(req->op.add.message->dn)) {
		return ldb_next_request(module, req);
	}

	ac = talloc_zero(req, struct rename_context);
	if (ac == NULL) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	ac->module = module;
	ac->req = req;

	msg = ldb_msg_copy_shallow(req, req->op.add.message);
	if (msg == NULL) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	rdn_name = ldb_dn_get_rdn_name(msg->dn);
	if (rdn_name == NULL) {
		return LDB_ERR_OPERATIONS_ERROR;
	}
	
	rdn_val = ldb_val_dup(msg, ldb_dn_get_rdn_val(msg->dn));
	
	/* Perhaps someone above us tried to set this? */
	if ((attribute = rdn_name_find_attribute(msg, "name")) != NULL ) {
		attribute->num_values = 0;
	}

	if (ldb_msg_add_value(msg, "name", &rdn_val, NULL) != 0) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	attribute = rdn_name_find_attribute(msg, rdn_name);

	if (!attribute) {
		if (ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL) != 0) {
			return LDB_ERR_OPERATIONS_ERROR;
		}
	} else {
		a = ldb_schema_attribute_by_name(ldb, rdn_name);

		for (i = 0; i < attribute->num_values; i++) {
			ret = a->syntax->comparison_fn(ldb, msg,
					&rdn_val, &attribute->values[i]);
			if (ret == 0) {
				/* overwrite so it matches in case */
				attribute->values[i] = rdn_val;
				break;
			}
		}
		if (i == attribute->num_values) {
			char *rdn_errstring = talloc_asprintf(ac,
				"RDN mismatch on %s: %s (%.*s) should match one of:", 
				ldb_dn_get_linearized(msg->dn), rdn_name, 
				(int)rdn_val.length, (const char *)rdn_val.data);
			for (i = 0; i < attribute->num_values; i++) {
				rdn_errstring = talloc_asprintf_append(
					rdn_errstring, " (%.*s)",
					(int)attribute->values[i].length, 
					(const char *)attribute->values[i].data);
			}
			ldb_set_errstring(ldb, rdn_errstring);
			/* Match AD's error here */
			return LDB_ERR_INVALID_DN_SYNTAX;
		}
	}

	ret = ldb_build_add_req(&down_req, ldb, req,
				msg,
				req->controls,
				ac, rdn_name_add_callback,
				req);
	if (ret != LDB_SUCCESS) {
		return ret;
	}

	talloc_steal(down_req, msg);

	/* go on with the call chain */
	return ldb_next_request(module, down_req);
}
예제 #14
0
static int dsdb_schema_set_attributes(struct ldb_context *ldb, struct dsdb_schema *schema, bool write_attributes)
{
	int ret = LDB_SUCCESS;
	struct ldb_result *res;
	struct ldb_result *res_idx;
	struct dsdb_attribute *attr;
	struct ldb_message *mod_msg;
	TALLOC_CTX *mem_ctx;
	struct ldb_message *msg;
	struct ldb_message *msg_idx;

	/* setup our own attribute name to schema handler */
	ldb_schema_attribute_set_override_handler(ldb, dsdb_attribute_handler_override, schema);

	if (!write_attributes) {
		return ret;
	}

	mem_ctx = talloc_new(ldb);
	if (!mem_ctx) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	msg = ldb_msg_new(mem_ctx);
	if (!msg) {
		ldb_oom(ldb);
		goto op_error;
	}
	msg_idx = ldb_msg_new(mem_ctx);
	if (!msg_idx) {
		ldb_oom(ldb);
		goto op_error;
	}
	msg->dn = ldb_dn_new(msg, ldb, "@ATTRIBUTES");
	if (!msg->dn) {
		ldb_oom(ldb);
		goto op_error;
	}
	msg_idx->dn = ldb_dn_new(msg, ldb, "@INDEXLIST");
	if (!msg_idx->dn) {
		ldb_oom(ldb);
		goto op_error;
	}

	ret = ldb_msg_add_string(msg_idx, "@IDXONE", "1");
	if (ret != LDB_SUCCESS) {
		goto op_error;
	}

	for (attr = schema->attributes; attr; attr = attr->next) {
		const char *syntax = attr->syntax->ldb_syntax;
		
		if (!syntax) {
			syntax = attr->syntax->ldap_oid;
		}

		/* Write out a rough approximation of the schema as an @ATTRIBUTES value, for bootstrapping */
		if (strcmp(syntax, LDB_SYNTAX_INTEGER) == 0) {
			ret = ldb_msg_add_string(msg, attr->lDAPDisplayName, "INTEGER");
		} else if (strcmp(syntax, LDB_SYNTAX_DIRECTORY_STRING) == 0) {
			ret = ldb_msg_add_string(msg, attr->lDAPDisplayName, "CASE_INSENSITIVE");
		} 
		if (ret != LDB_SUCCESS) {
			break;
		}

		if (attr->searchFlags & SEARCH_FLAG_ATTINDEX) {
			ret = ldb_msg_add_string(msg_idx, "@IDXATTR", attr->lDAPDisplayName);
			if (ret != LDB_SUCCESS) {
				break;
			}
		}
	}

	if (ret != LDB_SUCCESS) {
		talloc_free(mem_ctx);
		return ret;
	}

	/* Try to avoid churning the attributes too much - we only want to do this if they have changed */
	ret = ldb_search(ldb, mem_ctx, &res, msg->dn, LDB_SCOPE_BASE, NULL, "dn=%s", ldb_dn_get_linearized(msg->dn));
	if (ret == LDB_ERR_NO_SUCH_OBJECT) {
		ret = ldb_add(ldb, msg);
	} else if (ret != LDB_SUCCESS) {
	} else if (res->count != 1) {
		ret = ldb_add(ldb, msg);
	} else {
		ret = LDB_SUCCESS;
		/* Annoyingly added to our search results */
		ldb_msg_remove_attr(res->msgs[0], "distinguishedName");
		
		mod_msg = ldb_msg_diff(ldb, res->msgs[0], msg);
		if (mod_msg->num_elements > 0) {
			ret = samdb_replace(ldb, mem_ctx, mod_msg);
		}
	}

	if (ret == LDB_ERR_OPERATIONS_ERROR || ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS || ret == LDB_ERR_INVALID_DN_SYNTAX) {
		/* We might be on a read-only DB or LDAP */
		ret = LDB_SUCCESS;
	}
	if (ret != LDB_SUCCESS) {
		talloc_free(mem_ctx);
		return ret;
	}

	/* Now write out the indexs, as found in the schema (if they have changed) */

	ret = ldb_search(ldb, mem_ctx, &res_idx, msg_idx->dn, LDB_SCOPE_BASE, NULL, "dn=%s", ldb_dn_get_linearized(msg_idx->dn));
	if (ret == LDB_ERR_NO_SUCH_OBJECT) {
		ret = ldb_add(ldb, msg_idx);
	} else if (ret != LDB_SUCCESS) {
	} else if (res_idx->count != 1) {
		ret = ldb_add(ldb, msg_idx);
	} else {
		ret = LDB_SUCCESS;
		/* Annoyingly added to our search results */
		ldb_msg_remove_attr(res_idx->msgs[0], "distinguishedName");

		mod_msg = ldb_msg_diff(ldb, res_idx->msgs[0], msg_idx);
		if (mod_msg->num_elements > 0) {
			ret = samdb_replace(ldb, mem_ctx, mod_msg);
		}
	}
	if (ret == LDB_ERR_OPERATIONS_ERROR || ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS || ret == LDB_ERR_INVALID_DN_SYNTAX) {
		/* We might be on a read-only DB */
		ret = LDB_SUCCESS;
	}
	talloc_free(mem_ctx);
	return ret;

op_error:
	talloc_free(mem_ctx);
	return LDB_ERR_OPERATIONS_ERROR;
}
예제 #15
0
errno_t sysdb_update_subdomains(struct sss_domain_info *domain)
{
    int i;
    errno_t ret;
    TALLOC_CTX *tmp_ctx;
    struct ldb_result *res;
    const char *attrs[] = {"cn",
                           SYSDB_SUBDOMAIN_REALM,
                           SYSDB_SUBDOMAIN_FLAT,
                           SYSDB_SUBDOMAIN_ID,
                           SYSDB_SUBDOMAIN_MPG,
                           SYSDB_SUBDOMAIN_ENUM,
                           SYSDB_SUBDOMAIN_FOREST,
                           NULL};
    struct sss_domain_info *dom;
    struct ldb_dn *basedn;
    const char *name;
    const char *realm;
    const char *flat;
    const char *id;
    const char *forest;
    bool mpg;
    bool enumerate;

    tmp_ctx = talloc_new(NULL);
    if (tmp_ctx == NULL) {
        ret = ENOMEM;
        goto done;
    }

    basedn = ldb_dn_new(tmp_ctx, domain->sysdb->ldb, SYSDB_BASE);
    if (basedn == NULL) {
        ret = EIO;
        goto done;
    }
    ret = ldb_search(domain->sysdb->ldb, tmp_ctx, &res,
                     basedn, LDB_SCOPE_ONELEVEL,
                     attrs, "objectclass=%s", SYSDB_SUBDOMAIN_CLASS);
    if (ret != LDB_SUCCESS) {
        ret = EIO;
        goto done;
    }

    /* disable all domains,
     * let the search result refresh any that are still valid */
    for (dom = domain->subdomains; dom; dom = get_next_domain(dom, false)) {
        dom->disabled = true;
    }

    if (res->count == 0) {
        ret = EOK;
        goto done;
    }

    for (i = 0; i < res->count; i++) {

        name = ldb_msg_find_attr_as_string(res->msgs[i], "cn", NULL);
        if (name == NULL) {
            DEBUG(SSSDBG_MINOR_FAILURE,
                  "The object [%s] doesn't have a name\n",
                   ldb_dn_get_linearized(res->msgs[i]->dn));
            ret = EINVAL;
            goto done;
        }

        realm = ldb_msg_find_attr_as_string(res->msgs[i],
                                            SYSDB_SUBDOMAIN_REALM, NULL);

        flat = ldb_msg_find_attr_as_string(res->msgs[i],
                                           SYSDB_SUBDOMAIN_FLAT, NULL);

        id = ldb_msg_find_attr_as_string(res->msgs[i],
                                         SYSDB_SUBDOMAIN_ID, NULL);

        mpg = ldb_msg_find_attr_as_bool(res->msgs[i],
                                        SYSDB_SUBDOMAIN_MPG, false);

        enumerate = ldb_msg_find_attr_as_bool(res->msgs[i],
                                              SYSDB_SUBDOMAIN_ENUM, false);

        forest = ldb_msg_find_attr_as_string(res->msgs[i],
                                             SYSDB_SUBDOMAIN_FOREST, NULL);

        /* explicitly use dom->next as we need to check 'disabled' domains */
        for (dom = domain->subdomains; dom; dom = dom->next) {
            if (strcasecmp(dom->name, name) == 0) {
                dom->disabled = false;
                /* in theory these may change, but it should never happen */
                if (strcasecmp(dom->realm, realm) != 0) {
                    DEBUG(SSSDBG_TRACE_INTERNAL,
                          "Realm name changed from [%s] to [%s]!\n",
                           dom->realm, realm);
                    talloc_zfree(dom->realm);
                    dom->realm = talloc_strdup(dom, realm);
                    if (dom->realm == NULL) {
                        ret = ENOMEM;
                        goto done;
                    }
                }
                if (strcasecmp(dom->flat_name, flat) != 0) {
                    DEBUG(SSSDBG_TRACE_INTERNAL,
                          "Flat name changed from [%s] to [%s]!\n",
                           dom->flat_name, flat);
                    talloc_zfree(dom->flat_name);
                    dom->flat_name = talloc_strdup(dom, flat);
                    if (dom->flat_name == NULL) {
                        ret = ENOMEM;
                        goto done;
                    }
                }
                if (strcasecmp(dom->domain_id, id) != 0) {
                    DEBUG(SSSDBG_TRACE_INTERNAL,
                          "Domain changed from [%s] to [%s]!\n",
                           dom->domain_id, id);
                    talloc_zfree(dom->domain_id);
                    dom->domain_id = talloc_strdup(dom, id);
                    if (dom->domain_id == NULL) {
                        ret = ENOMEM;
                        goto done;
                    }
                }

                if (dom->mpg != mpg) {
                    DEBUG(SSSDBG_TRACE_INTERNAL,
                          "MPG state change from [%s] to [%s]!\n",
                           dom->mpg ? "true" : "false",
                           mpg ? "true" : "false");
                    dom->mpg = mpg;
                }

                if (dom->enumerate != enumerate) {
                    DEBUG(SSSDBG_TRACE_INTERNAL,
                          "MPG state change from [%s] to [%s]!\n",
                           dom->enumerate ? "true" : "false",
                           enumerate ? "true" : "false");
                    dom->enumerate = enumerate;
                }

                if ((dom->forest == NULL && forest != NULL)
                        || (dom->forest != NULL && forest != NULL
                            && strcasecmp(dom->forest, forest) != 0)) {
                    DEBUG(SSSDBG_TRACE_INTERNAL,
                          "Forest changed from [%s] to [%s]!\n",
                           dom->forest, forest);
                    talloc_zfree(dom->forest);
                    dom->forest = talloc_strdup(dom, forest);
                    if (dom->forest == NULL) {
                        ret = ENOMEM;
                        goto done;
                    }
                }

                break;
            }
        }
        /* If not found in loop it is a new subdomain */
        if (dom == NULL) {
            dom = new_subdomain(domain, domain, name, realm,
                                flat, id, mpg, enumerate, forest);
            if (dom == NULL) {
                ret = ENOMEM;
                goto done;
            }
            DLIST_ADD_END(domain->subdomains, dom, struct sss_domain_info *);
        }
    }
예제 #16
0
WERROR dsdb_repl_resolve_working_schema(struct ldb_context *ldb,
					TALLOC_CTX *mem_ctx,
					struct dsdb_schema_prefixmap *pfm_remote,
					uint32_t cycle_before_switching,
					struct dsdb_schema *initial_schema,
					struct dsdb_schema *resulting_schema,
					uint32_t object_count,
					const struct drsuapi_DsReplicaObjectListItemEx *first_object)
{
	struct schema_list {
		struct schema_list *next, *prev;
		const struct drsuapi_DsReplicaObjectListItemEx *obj;
	};
	struct schema_list *schema_list = NULL, *schema_list_item, *schema_list_next_item;
	WERROR werr;
	struct dsdb_schema *working_schema;
	const struct drsuapi_DsReplicaObjectListItemEx *cur;
	DATA_BLOB empty_key = data_blob_null;
	int ret, pass_no;
	uint32_t ignore_attids[] = {
			DRSUAPI_ATTID_auxiliaryClass,
			DRSUAPI_ATTID_mayContain,
			DRSUAPI_ATTID_mustContain,
			DRSUAPI_ATTID_possSuperiors,
			DRSUAPI_ATTID_systemPossSuperiors,
			DRSUAPI_ATTID_INVALID
	};

	/* create a list of objects yet to be converted */
	for (cur = first_object; cur; cur = cur->next_object) {
		schema_list_item = talloc(mem_ctx, struct schema_list);
		if (schema_list_item == NULL) {
			return WERR_NOMEM;
		}

		schema_list_item->obj = cur;
		DLIST_ADD_END(schema_list, schema_list_item, struct schema_list);
	}

	/* resolve objects until all are resolved and in local schema */
	pass_no = 1;
	working_schema = initial_schema;

	while (schema_list) {
		uint32_t converted_obj_count = 0;
		uint32_t failed_obj_count = 0;

		if (resulting_schema != working_schema) {
			/*
			 * If the selfmade schema is not the schema used to
			 * translate and validate replicated object,
			 * Which means that we are using the bootstrap schema
			 * Then we add attributes and classes that were already
			 * translated to the working schema, the idea is that
			 * we might need to add new attributes and classes
			 * to be able to translate critical replicated objects
			 * and without that we wouldn't be able to translate them
			 */
			werr = dsdb_repl_merge_working_schema(ldb,
							working_schema,
							resulting_schema);
			if (!W_ERROR_IS_OK(werr)) {
				return werr;
			}
		}

		for (schema_list_item = schema_list;
		     schema_list_item;
		     schema_list_item=schema_list_next_item) {
			struct dsdb_extended_replicated_object object;

			cur = schema_list_item->obj;

			/*
			 * Save the next item, now we have saved out
			 * the current one, so we can DLIST_REMOVE it
			 * safely
			 */
			schema_list_next_item = schema_list_item->next;

			/*
			 * Convert the objects into LDB messages using the
			 * schema we have so far. It's ok if we fail to convert
			 * an object. We should convert more objects on next pass.
			 */
			werr = dsdb_convert_object_ex(ldb, working_schema,
						      pfm_remote,
						      cur, &empty_key,
						      ignore_attids,
						      0,
						      schema_list_item, &object);
			if (!W_ERROR_IS_OK(werr)) {
				DEBUG(4,("debug: Failed to convert schema "
					 "object %s into ldb msg, "
					 "will try during next loop\n",
					 cur->object.identifier->dn));

				failed_obj_count++;
			} else {
				/*
				 * Convert the schema from ldb_message format
				 * (OIDs as OID strings) into schema, using
				 * the remote prefixMap
				 *
				 * It's not likely, but possible to get the
				 * same object twice and we should keep
				 * the last instance.
				 */
				werr = dsdb_schema_set_el_from_ldb_msg_dups(ldb,
								resulting_schema,
								object.msg,
								true);
				if (!W_ERROR_IS_OK(werr)) {
					DEBUG(4,("debug: failed to convert "
						 "object %s into a schema element, "
						 "will try during next loop: %s\n",
						 ldb_dn_get_linearized(object.msg->dn),
						 win_errstr(werr)));
					failed_obj_count++;
				} else {
					DEBUG(8,("Converted object %s into a schema element\n",
						 ldb_dn_get_linearized(object.msg->dn)));
					DLIST_REMOVE(schema_list, schema_list_item);
					TALLOC_FREE(schema_list_item);
					converted_obj_count++;
				}
			}
		}

		DEBUG(4,("Schema load pass %d: converted %d, %d of %d objects left to be converted.\n",
			 pass_no, converted_obj_count, failed_obj_count, object_count));

		/* check if we converted any objects in this pass */
		if (converted_obj_count == 0) {
			DEBUG(0,("Can't continue Schema load: "
				 "didn't manage to convert any objects: "
				 "all %d remaining of %d objects "
				 "failed to convert\n",
				 failed_obj_count, object_count));
			return WERR_INTERNAL_ERROR;
		}

		/*
		 * Don't try to load the schema if there is missing object
		 * _and_ we are on the first pass as some critical objects
		 * might be missing.
		 */
		if (failed_obj_count == 0 || pass_no > cycle_before_switching) {
			/* prepare for another cycle */
			working_schema = resulting_schema;

			ret = dsdb_setup_sorted_accessors(ldb, working_schema);
			if (LDB_SUCCESS != ret) {
				DEBUG(0,("Failed to create schema-cache indexes!\n"));
				return WERR_INTERNAL_ERROR;
			}
		}
		pass_no++;
	}

	return WERR_OK;
}
예제 #17
0
/*
  remember an established session key for a netr server authentication
  use a simple ldb structure
*/
NTSTATUS schannel_store_session_key_ldb(struct ldb_context *ldb,
					TALLOC_CTX *mem_ctx,
					struct netlogon_creds_CredentialState *creds)
{
	struct ldb_message *msg;
	struct ldb_val val, seed, client_state, server_state;
	struct ldb_val *sid_val;
	char *f;
	char *sct;
	int ret;

	f = talloc_asprintf(mem_ctx, "%u", (unsigned int)creds->negotiate_flags);

	if (f == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	sct = talloc_asprintf(mem_ctx, "%u", (unsigned int)creds->secure_channel_type);

	if (sct == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	msg = ldb_msg_new(ldb);
	if (msg == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	msg->dn = ldb_dn_new_fmt(msg, ldb, "computerName=%s", creds->computer_name);
	if ( ! msg->dn) {
		return NT_STATUS_NO_MEMORY;
	}

	sid_val = schannel_dom_sid_ldb_val(msg, creds->sid);
	if (sid_val == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	val.data = creds->session_key;
	val.length = sizeof(creds->session_key);

	seed.data = creds->seed.data;
	seed.length = sizeof(creds->seed.data);

	client_state.data = creds->client.data;
	client_state.length = sizeof(creds->client.data);
	server_state.data = creds->server.data;
	server_state.length = sizeof(creds->server.data);

	ldb_msg_add_string(msg, "objectClass", "schannelState");
	ldb_msg_add_value(msg, "sessionKey", &val, NULL);
	ldb_msg_add_value(msg, "seed", &seed, NULL);
	ldb_msg_add_value(msg, "clientState", &client_state, NULL);
	ldb_msg_add_value(msg, "serverState", &server_state, NULL);
	ldb_msg_add_string(msg, "negotiateFlags", f);
	ldb_msg_add_string(msg, "secureChannelType", sct);
	ldb_msg_add_string(msg, "accountName", creds->account_name);
	ldb_msg_add_string(msg, "computerName", creds->computer_name);
	ldb_msg_add_value(msg, "objectSid", sid_val, NULL);

	ret = ldb_add(ldb, msg);
	if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
		int i;
		/* from samdb_replace() */
		/* mark all the message elements as LDB_FLAG_MOD_REPLACE */
		for (i=0;i<msg->num_elements;i++) {
			msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
		}

		ret = ldb_modify(ldb, msg);
	}

	/* We don't need a transaction here, as we either add or
	 * modify records, never delete them, so it must exist */

	if (ret != LDB_SUCCESS) {
		DEBUG(0,("Unable to add %s to session key db - %s\n",
			 ldb_dn_get_linearized(msg->dn), ldb_errstring(ldb)));
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}

	return NT_STATUS_OK;
}
예제 #18
0
WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
			      const struct dsdb_schema *schema,
			      const struct dsdb_schema_prefixmap *pfm_remote,
			      const struct drsuapi_DsReplicaObjectListItemEx *in,
			      const DATA_BLOB *gensec_skey,
			      const uint32_t *ignore_attids,
			      uint32_t dsdb_repl_flags,
			      TALLOC_CTX *mem_ctx,
			      struct dsdb_extended_replicated_object *out)
{
	NTSTATUS nt_status;
	WERROR status = WERR_OK;
	uint32_t i;
	struct ldb_message *msg;
	struct replPropertyMetaDataBlob *md;
	int instanceType;
	struct ldb_message_element *instanceType_e = NULL;
	struct ldb_val guid_value;
	struct ldb_val parent_guid_value;
	NTTIME whenChanged = 0;
	time_t whenChanged_t;
	const char *whenChanged_s;
	struct drsuapi_DsReplicaAttribute *name_a = NULL;
	struct drsuapi_DsReplicaMetaData *name_d = NULL;
	struct replPropertyMetaData1 *rdn_m = NULL;
	struct dom_sid *sid = NULL;
	uint32_t rid = 0;
	uint32_t attr_count;
	int ret;

	if (!in->object.identifier) {
		return WERR_FOOBAR;
	}

	if (!in->object.identifier->dn || !in->object.identifier->dn[0]) {
		return WERR_FOOBAR;
	}

	if (in->object.attribute_ctr.num_attributes != 0 && !in->meta_data_ctr) {
		return WERR_FOOBAR;
	}

	if (in->object.attribute_ctr.num_attributes != in->meta_data_ctr->count) {
		return WERR_FOOBAR;
	}

	sid = &in->object.identifier->sid;
	if (sid->num_auths > 0) {
		rid = sid->sub_auths[sid->num_auths - 1];
	}

	msg = ldb_msg_new(mem_ctx);
	W_ERROR_HAVE_NO_MEMORY(msg);

	msg->dn			= ldb_dn_new(msg, ldb, in->object.identifier->dn);
	W_ERROR_HAVE_NO_MEMORY(msg->dn);

	msg->num_elements	= in->object.attribute_ctr.num_attributes;
	msg->elements		= talloc_array(msg, struct ldb_message_element,
					       msg->num_elements + 1); /* +1 because of the RDN attribute */
	W_ERROR_HAVE_NO_MEMORY(msg->elements);

	md = talloc(mem_ctx, struct replPropertyMetaDataBlob);
	W_ERROR_HAVE_NO_MEMORY(md);

	md->version		= 1;
	md->reserved		= 0;
	md->ctr.ctr1.count	= in->meta_data_ctr->count;
	md->ctr.ctr1.reserved	= 0;
	md->ctr.ctr1.array	= talloc_array(mem_ctx,
					       struct replPropertyMetaData1,
					       md->ctr.ctr1.count + 1); /* +1 because of the RDN attribute */
	W_ERROR_HAVE_NO_MEMORY(md->ctr.ctr1.array);

	for (i=0, attr_count=0; i < in->meta_data_ctr->count; i++, attr_count++) {
		struct drsuapi_DsReplicaAttribute *a;
		struct drsuapi_DsReplicaMetaData *d;
		struct replPropertyMetaData1 *m;
		struct ldb_message_element *e;
		uint32_t j;

		a = &in->object.attribute_ctr.attributes[i];
		d = &in->meta_data_ctr->meta_data[i];
		m = &md->ctr.ctr1.array[attr_count];
		e = &msg->elements[attr_count];

		if (dsdb_attid_in_list(ignore_attids, a->attid)) {
			attr_count--;
			continue;
		}

		if (GUID_all_zero(&d->originating_invocation_id)) {
			status = WERR_DS_SRC_GUID_MISMATCH;
			DEBUG(0, ("Refusing replication of object containing invalid zero invocationID on attribute %d of %s: %s\n",
				  a->attid,
				  ldb_dn_get_linearized(msg->dn),
				  win_errstr(status)));
			return status;
		}

		if (a->attid == DRSUAPI_ATTID_instanceType) {
			if (instanceType_e != NULL) {
				return WERR_FOOBAR;
			}
			instanceType_e = e;
		}

		for (j=0; j<a->value_ctr.num_values; j++) {
			status = drsuapi_decrypt_attribute(a->value_ctr.values[j].blob,
							   gensec_skey, rid,
							   dsdb_repl_flags, a);
			if (!W_ERROR_IS_OK(status)) {
				break;
			}
		}
		if (W_ERROR_EQUAL(status, WERR_TOO_MANY_SECRETS)) {
			WERROR get_name_status = dsdb_attribute_drsuapi_to_ldb(ldb, schema, pfm_remote,
									       a, msg->elements, e);
			if (W_ERROR_IS_OK(get_name_status)) {
				DEBUG(0, ("Unxpectedly got secret value %s on %s from DRS server\n",
					  e->name, ldb_dn_get_linearized(msg->dn)));
			} else {
				DEBUG(0, ("Unxpectedly got secret value on %s from DRS server",
					  ldb_dn_get_linearized(msg->dn)));
			}
		} else if (!W_ERROR_IS_OK(status)) {
			return status;
		}

		status = dsdb_attribute_drsuapi_to_ldb(ldb, schema, pfm_remote,
						       a, msg->elements, e);
		W_ERROR_NOT_OK_RETURN(status);

		m->attid			= a->attid;
		m->version			= d->version;
		m->originating_change_time	= d->originating_change_time;
		m->originating_invocation_id	= d->originating_invocation_id;
		m->originating_usn		= d->originating_usn;
		m->local_usn			= 0;

		if (d->originating_change_time > whenChanged) {
			whenChanged = d->originating_change_time;
		}

		if (a->attid == DRSUAPI_ATTID_name) {
			name_a = a;
			name_d = d;
		}
	}

	msg->num_elements = attr_count;
	md->ctr.ctr1.count = attr_count;
	if (name_a) {
		rdn_m = &md->ctr.ctr1.array[md->ctr.ctr1.count];
	}

	if (rdn_m) {
		struct ldb_message_element *el;
		const char *rdn_name = NULL;
		const struct ldb_val *rdn_value = NULL;
		const struct dsdb_attribute *rdn_attr = NULL;
		uint32_t rdn_attid;

		/*
		 * We only need the schema calls for the RDN in this
		 * codepath, and by doing this we avoid needing to
		 * have the dsdb_attribute_by_lDAPDisplayName accessor
		 * working during the schema load.
		 */
		rdn_name	= ldb_dn_get_rdn_name(msg->dn);
		rdn_attr	= dsdb_attribute_by_lDAPDisplayName(schema, rdn_name);
		if (!rdn_attr) {
			return WERR_FOOBAR;
		}
		rdn_attid	= rdn_attr->attributeID_id;
		rdn_value	= ldb_dn_get_rdn_val(msg->dn);

		el = ldb_msg_find_element(msg, rdn_attr->lDAPDisplayName);
		if (!el) {
			ret = ldb_msg_add_value(msg, rdn_attr->lDAPDisplayName, rdn_value, NULL);
			if (ret != LDB_SUCCESS) {
				return WERR_FOOBAR;
			}
		} else {
			if (el->num_values != 1) {
				DEBUG(0,(__location__ ": Unexpected num_values=%u\n",
					 el->num_values));
				return WERR_FOOBAR;				
			}
			if (!ldb_val_equal_exact(&el->values[0], rdn_value)) {
				DEBUG(0,(__location__ ": RDN value changed? '%*.*s' '%*.*s'\n",
					 (int)el->values[0].length, (int)el->values[0].length, el->values[0].data,
					 (int)rdn_value->length, (int)rdn_value->length, rdn_value->data));
				return WERR_FOOBAR;				
			}
		}

		rdn_m->attid				= rdn_attid;
		rdn_m->version				= name_d->version;
		rdn_m->originating_change_time		= name_d->originating_change_time;
		rdn_m->originating_invocation_id	= name_d->originating_invocation_id;
		rdn_m->originating_usn			= name_d->originating_usn;
		rdn_m->local_usn			= 0;
		md->ctr.ctr1.count++;

	}

	if (instanceType_e == NULL) {
		return WERR_FOOBAR;
	}

	instanceType = ldb_msg_find_attr_as_int(msg, "instanceType", 0);
	if (dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
		/* the instanceType type for partial_replica
		   replication is sent via DRS with TYPE_WRITE set, but
		   must be used on the client with TYPE_WRITE removed
		*/
		if (instanceType & INSTANCE_TYPE_WRITE) {
			/*
			 * Make sure we do not change the order
			 * of msg->elements!
			 *
			 * That's why we use
			 * instanceType_e->num_values = 0
			 * instead of
			 * ldb_msg_remove_attr(msg, "instanceType");
			 */
			struct ldb_message_element *e;

			e = ldb_msg_find_element(msg, "instanceType");
			if (e != instanceType_e) {
				DEBUG(0,("instanceType_e[%p] changed to e[%p]\n",
					 instanceType_e, e));
				return WERR_FOOBAR;
			}

			instanceType_e->num_values = 0;

			instanceType &= ~INSTANCE_TYPE_WRITE;
			if (ldb_msg_add_fmt(msg, "instanceType", "%d", instanceType) != LDB_SUCCESS) {
				return WERR_INTERNAL_ERROR;
			}
		}
	} else {
		if (!(instanceType & INSTANCE_TYPE_WRITE)) {
			DEBUG(0, ("Refusing to replicate %s from a read-only repilca into a read-write replica!\n",
				  ldb_dn_get_linearized(msg->dn)));
			return WERR_DS_DRA_SOURCE_IS_PARTIAL_REPLICA;
		}
	}

	whenChanged_t = nt_time_to_unix(whenChanged);
	whenChanged_s = ldb_timestring(msg, whenChanged_t);
	W_ERROR_HAVE_NO_MEMORY(whenChanged_s);

	nt_status = GUID_to_ndr_blob(&in->object.identifier->guid, msg, &guid_value);
	if (!NT_STATUS_IS_OK(nt_status)) {
		return ntstatus_to_werror(nt_status);
	}

	if (in->parent_object_guid) {
		nt_status = GUID_to_ndr_blob(in->parent_object_guid, msg, &parent_guid_value);
		if (!NT_STATUS_IS_OK(nt_status)) {
			return ntstatus_to_werror(nt_status);
		}
	} else {
		parent_guid_value = data_blob_null;
	}

	out->msg		= msg;
	out->guid_value		= guid_value;
	out->parent_guid_value	= parent_guid_value;
	out->when_changed	= whenChanged_s;
	out->meta_data		= md;
	return WERR_OK;
}
예제 #19
0
/*
  samr_ChangePasswordUser3
*/
NTSTATUS dcesrv_samr_ChangePasswordUser3(struct dcesrv_call_state *dce_call,
					 TALLOC_CTX *mem_ctx,
					 struct samr_ChangePasswordUser3 *r)
{
	NTSTATUS status;
	DATA_BLOB new_password;
	struct ldb_context *sam_ctx = NULL;
	struct ldb_dn *user_dn;
	int ret;
	struct ldb_message **res;
	const char * const attrs[] = { "unicodePwd", "dBCSPwd", NULL };
	struct samr_Password *nt_pwd, *lm_pwd;
	DATA_BLOB nt_pwd_blob;
	struct samr_DomInfo1 *dominfo = NULL;
	struct userPwdChangeFailureInformation *reject = NULL;
	enum samPwdChangeReason reason = SAM_PWD_CHANGE_NO_ERROR;
	uint8_t new_nt_hash[16], new_lm_hash[16];
	struct samr_Password nt_verifier, lm_verifier;

	*r->out.dominfo = NULL;
	*r->out.reject = NULL;

	if (r->in.nt_password == NULL ||
	    r->in.nt_verifier == NULL) {
		return NT_STATUS_INVALID_PARAMETER;
	}

	/* Connect to a SAMDB with system privileges for fetching the old pw
	 * hashes. */
	sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
				dce_call->conn->dce_ctx->lp_ctx,
				system_session(dce_call->conn->dce_ctx->lp_ctx), 0);
	if (sam_ctx == NULL) {
		return NT_STATUS_INVALID_SYSTEM_SERVICE;
	}

	/* we need the users dn and the domain dn (derived from the
	   user SID). We also need the current lm and nt password hashes
	   in order to decrypt the incoming passwords */
	ret = gendb_search(sam_ctx,
			   mem_ctx, NULL, &res, attrs,
			   "(&(sAMAccountName=%s)(objectclass=user))",
			   r->in.account->string);
	if (ret != 1) {
		/* Don't give the game away:  (don't allow anonymous users to prove the existance of usernames) */
		status = NT_STATUS_WRONG_PASSWORD;
		goto failed;
	}

	user_dn = res[0]->dn;

	status = samdb_result_passwords(mem_ctx, dce_call->conn->dce_ctx->lp_ctx,
					res[0], &lm_pwd, &nt_pwd);
	if (!NT_STATUS_IS_OK(status) ) {
		goto failed;
	}

	if (!nt_pwd) {
		status = NT_STATUS_WRONG_PASSWORD;
		goto failed;
	}

	/* decrypt the password we have been given */
	nt_pwd_blob = data_blob(nt_pwd->hash, sizeof(nt_pwd->hash));
	arcfour_crypt_blob(r->in.nt_password->data, 516, &nt_pwd_blob);
	data_blob_free(&nt_pwd_blob);

	if (!extract_pw_from_buffer(mem_ctx, r->in.nt_password->data, &new_password)) {
		DEBUG(3,("samr: failed to decode password buffer\n"));
		status =  NT_STATUS_WRONG_PASSWORD;
		goto failed;
	}

	if (r->in.nt_verifier == NULL) {
		status = NT_STATUS_WRONG_PASSWORD;
		goto failed;
	}

	/* check NT verifier */
	mdfour(new_nt_hash, new_password.data, new_password.length);

	E_old_pw_hash(new_nt_hash, nt_pwd->hash, nt_verifier.hash);
	if (memcmp(nt_verifier.hash, r->in.nt_verifier->hash, 16) != 0) {
		status = NT_STATUS_WRONG_PASSWORD;
		goto failed;
	}

	/* check LM verifier (really not needed as we just checked the
	 * much stronger NT hash, but the RPC-SAMR test checks for
	 * this) */
	if (lm_pwd && r->in.lm_verifier != NULL) {
		char *new_pass;
		if (!convert_string_talloc_convenience(mem_ctx, lpcfg_iconv_convenience(dce_call->conn->dce_ctx->lp_ctx),
					  CH_UTF16, CH_UNIX,
					  (const char *)new_password.data,
					  new_password.length,
					  (void **)&new_pass, NULL, false)) {
			E_deshash(new_pass, new_lm_hash);
			E_old_pw_hash(new_nt_hash, lm_pwd->hash, lm_verifier.hash);
			if (memcmp(lm_verifier.hash, r->in.lm_verifier->hash, 16) != 0) {
				status = NT_STATUS_WRONG_PASSWORD;
				goto failed;
			}
		}
	}

	/* Connect to a SAMDB with user privileges for the password change */
	sam_ctx = samdb_connect(mem_ctx, dce_call->event_ctx,
				dce_call->conn->dce_ctx->lp_ctx,
				dce_call->conn->auth_state.session_info, 0);
	if (sam_ctx == NULL) {
		return NT_STATUS_INVALID_SYSTEM_SERVICE;
	}

	ret = ldb_transaction_start(sam_ctx);
	if (ret != LDB_SUCCESS) {
		DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(sam_ctx)));
		return NT_STATUS_TRANSACTION_ABORTED;
	}

	/* Performs the password modification. We pass the old hashes read out
	 * from the database since they were already checked against the user-
	 * provided ones. */
	status = samdb_set_password(sam_ctx, mem_ctx,
				    user_dn, NULL,
				    &new_password,
				    NULL, NULL,
				    lm_pwd, nt_pwd, /* this is a user password change */
				    &reason,
				    &dominfo);

	if (!NT_STATUS_IS_OK(status)) {
		ldb_transaction_cancel(sam_ctx);
		goto failed;
	}

	/* And this confirms it in a transaction commit */
	ret = ldb_transaction_commit(sam_ctx);
	if (ret != LDB_SUCCESS) {
		DEBUG(1,("Failed to commit transaction to change password on %s: %s\n",
			 ldb_dn_get_linearized(user_dn),
			 ldb_errstring(sam_ctx)));
		status = NT_STATUS_TRANSACTION_ABORTED;
		goto failed;
	}

	return NT_STATUS_OK;

failed:
	reject = talloc_zero(mem_ctx, struct userPwdChangeFailureInformation);
	if (reject != NULL) {
		reject->extendedFailureReason = reason;

		*r->out.reject = reject;
	}

	*r->out.dominfo = dominfo;

	return status;
}
예제 #20
0
/**
 * Commits a list of replicated objects.
 *
 * @param working_schema dsdb_schema to be used for resolving
 * 			 Classes/Attributes during Schema replication. If not NULL,
 * 			 it will be set on ldb and used while committing replicated objects
 */
WERROR dsdb_replicated_objects_commit(struct ldb_context *ldb,
				      struct dsdb_schema *working_schema,
				      struct dsdb_extended_replicated_objects *objects,
				      uint64_t *notify_uSN)
{
	WERROR werr;
	struct ldb_result *ext_res;
	struct dsdb_schema *cur_schema = NULL;
	struct dsdb_schema *new_schema = NULL;
	int ret;
	uint64_t seq_num1, seq_num2;
	bool used_global_schema = false;

	TALLOC_CTX *tmp_ctx = talloc_new(objects);
	if (!tmp_ctx) {
		DEBUG(0,("Failed to start talloc\n"));
		return WERR_NOMEM;
	}

	/* TODO: handle linked attributes */

	/* wrap the extended operation in a transaction 
	   See [MS-DRSR] 3.3.2 Transactions
	 */
	ret = ldb_transaction_start(ldb);
	if (ret != LDB_SUCCESS) {
		DEBUG(0,(__location__ " Failed to start transaction\n"));
		return WERR_FOOBAR;
	}

	ret = dsdb_load_partition_usn(ldb, objects->partition_dn, &seq_num1, NULL);
	if (ret != LDB_SUCCESS) {
		DEBUG(0,(__location__ " Failed to load partition uSN\n"));
		ldb_transaction_cancel(ldb);
		TALLOC_FREE(tmp_ctx);
		return WERR_FOOBAR;		
	}

	/*
	 * Set working_schema for ldb in case we are replicating from Schema NC.
	 * Schema won't be reloaded during Replicated Objects commit, as it is
	 * done in a transaction. So we need some way to search for newly
	 * added Classes and Attributes
	 */
	if (working_schema) {
		/* store current schema so we can fall back in case of failure */
		cur_schema = dsdb_get_schema(ldb, tmp_ctx);
		used_global_schema = dsdb_uses_global_schema(ldb);

		ret = dsdb_reference_schema(ldb, working_schema, false);
		if (ret != LDB_SUCCESS) {
			DEBUG(0,(__location__ "Failed to reference working schema - %s\n",
				 ldb_strerror(ret)));
			/* TODO: Map LDB Error to NTSTATUS? */
			ldb_transaction_cancel(ldb);
			TALLOC_FREE(tmp_ctx);
			return WERR_INTERNAL_ERROR;
		}
	}

	ret = ldb_extended(ldb, DSDB_EXTENDED_REPLICATED_OBJECTS_OID, objects, &ext_res);
	if (ret != LDB_SUCCESS) {
		/* restore previous schema */
		if (used_global_schema) { 
			dsdb_set_global_schema(ldb);
		} else if (cur_schema) {
			dsdb_reference_schema(ldb, cur_schema, false);
		}

		DEBUG(0,("Failed to apply records: %s: %s\n",
			 ldb_errstring(ldb), ldb_strerror(ret)));
		ldb_transaction_cancel(ldb);
		TALLOC_FREE(tmp_ctx);
		return WERR_FOOBAR;
	}
	talloc_free(ext_res);

	/* Save our updated prefixMap */
	if (working_schema) {
		werr = dsdb_write_prefixes_from_schema_to_ldb(working_schema,
							      ldb,
							      working_schema);
		if (!W_ERROR_IS_OK(werr)) {
			/* restore previous schema */
			if (used_global_schema) { 
				dsdb_set_global_schema(ldb);
			} else if (cur_schema ) {
				dsdb_reference_schema(ldb, cur_schema, false);
			}
			DEBUG(0,("Failed to save updated prefixMap: %s\n",
				 win_errstr(werr)));
			TALLOC_FREE(tmp_ctx);
			return werr;
		}
	}

	ret = ldb_transaction_prepare_commit(ldb);
	if (ret != LDB_SUCCESS) {
		/* restore previous schema */
		if (used_global_schema) { 
			dsdb_set_global_schema(ldb);
		} else if (cur_schema ) {
			dsdb_reference_schema(ldb, cur_schema, false);
		}
		DEBUG(0,(__location__ " Failed to prepare commit of transaction: %s\n",
			 ldb_errstring(ldb)));
		TALLOC_FREE(tmp_ctx);
		return WERR_FOOBAR;
	}

	ret = dsdb_load_partition_usn(ldb, objects->partition_dn, &seq_num2, NULL);
	if (ret != LDB_SUCCESS) {
		/* restore previous schema */
		if (used_global_schema) { 
			dsdb_set_global_schema(ldb);
		} else if (cur_schema ) {
			dsdb_reference_schema(ldb, cur_schema, false);
		}
		DEBUG(0,(__location__ " Failed to load partition uSN\n"));
		ldb_transaction_cancel(ldb);
		TALLOC_FREE(tmp_ctx);
		return WERR_FOOBAR;		
	}

	ret = ldb_transaction_commit(ldb);
	if (ret != LDB_SUCCESS) {
		/* restore previous schema */
		if (used_global_schema) { 
			dsdb_set_global_schema(ldb);
		} else if (cur_schema ) {
			dsdb_reference_schema(ldb, cur_schema, false);
		}
		DEBUG(0,(__location__ " Failed to commit transaction\n"));
		TALLOC_FREE(tmp_ctx);
		return WERR_FOOBAR;
	}

	/* if this replication partner didn't need to be notified
	   before this transaction then it still doesn't need to be
	   notified, as the changes came from this server */
	if (seq_num2 > seq_num1 && seq_num1 <= *notify_uSN) {
		*notify_uSN = seq_num2;
	}

	/*
	 * Reset the Schema used by ldb. This will lead to
	 * a schema cache being refreshed from database.
	 */
	if (working_schema) {
		struct ldb_message *msg;
		struct ldb_request *req;

		/* Force a reload */
		working_schema->last_refresh = 0;
		new_schema = dsdb_get_schema(ldb, tmp_ctx);
		/* TODO: 
		 * If dsdb_get_schema() fails, we just fall back
		 * to what we had.  However, the database is probably
		 * unable to operate for other users from this
		 * point... */
		if (new_schema && used_global_schema) {
			dsdb_make_schema_global(ldb, new_schema);
		} else if (used_global_schema) { 
			DEBUG(0,("Failed to re-load schema after commit of transaction\n"));
			dsdb_set_global_schema(ldb);
			TALLOC_FREE(tmp_ctx);
			return WERR_INTERNAL_ERROR;
		} else {
			DEBUG(0,("Failed to re-load schema after commit of transaction\n"));
			dsdb_reference_schema(ldb, cur_schema, false);
			TALLOC_FREE(tmp_ctx);
			return WERR_INTERNAL_ERROR;
		}
		msg = ldb_msg_new(tmp_ctx);
		if (msg == NULL) {
			TALLOC_FREE(tmp_ctx);
			return WERR_NOMEM;
		}
		msg->dn = ldb_dn_new(msg, ldb, "");
		if (msg->dn == NULL) {
			TALLOC_FREE(tmp_ctx);
			return WERR_NOMEM;
		}

		ret = ldb_msg_add_string(msg, "schemaUpdateNow", "1");
		if (ret != LDB_SUCCESS) {
			TALLOC_FREE(tmp_ctx);
			return WERR_INTERNAL_ERROR;
		}

		ret = ldb_build_mod_req(&req, ldb, objects,
				msg,
				NULL,
				NULL,
				ldb_op_default_callback,
				NULL);

		if (ret != LDB_SUCCESS) {
			TALLOC_FREE(tmp_ctx);
			return WERR_DS_DRA_INTERNAL_ERROR;
		}

		ret = ldb_transaction_start(ldb);
		if (ret != LDB_SUCCESS) {
			TALLOC_FREE(tmp_ctx);
			DEBUG(0, ("Autotransaction start failed\n"));
			return WERR_DS_DRA_INTERNAL_ERROR;
		}

		ret = ldb_request(ldb, req);
		if (ret == LDB_SUCCESS) {
			ret = ldb_wait(req->handle, LDB_WAIT_ALL);
		}

		if (ret == LDB_SUCCESS) {
			ret = ldb_transaction_commit(ldb);
		} else {
			DEBUG(0, ("Schema update now failed: %s\n",
				  ldb_errstring(ldb)));
			ldb_transaction_cancel(ldb);
		}

		if (ret != LDB_SUCCESS) {
			DEBUG(0, ("Commit failed: %s\n", ldb_errstring(ldb)));
			TALLOC_FREE(tmp_ctx);
			return WERR_DS_INTERNAL_FAILURE;
		}
	}

	DEBUG(2,("Replicated %u objects (%u linked attributes) for %s\n",
		 objects->num_objects, objects->linked_attributes_count,
		 ldb_dn_get_linearized(objects->partition_dn)));
		 
	TALLOC_FREE(tmp_ctx);
	return WERR_OK;
}
예제 #21
0
파일: ldb_tdb.c 프로젝트: GSam/samba
/*
  rename a record
*/
static int ltdb_rename(struct ltdb_context *ctx)
{
	struct ldb_module *module = ctx->module;
	void *data = ldb_module_get_private(module);
	struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
	struct ldb_request *req = ctx->req;
	struct ldb_message *msg;
	int ret = LDB_SUCCESS;
	TDB_DATA tdb_key, tdb_key_old;

	ldb_request_set_state(req, LDB_ASYNC_PENDING);

	if (ltdb_cache_load(ctx->module) != 0) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	msg = ldb_msg_new(ctx);
	if (msg == NULL) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	/* we need to fetch the old record to re-add under the new name */
	ret = ltdb_search_dn1(module, req->op.rename.olddn, msg);
	if (ret != LDB_SUCCESS) {
		/* not finding the old record is an error */
		return ret;
	}

	/* We need to, before changing the DB, check if the new DN
	 * exists, so we can return this error to the caller with an
	 * unmodified DB */
	tdb_key = ltdb_key(module, req->op.rename.newdn);
	if (!tdb_key.dptr) {
		talloc_free(msg);
		return LDB_ERR_OPERATIONS_ERROR;
	}

	tdb_key_old = ltdb_key(module, req->op.rename.olddn);
	if (!tdb_key_old.dptr) {
		talloc_free(msg);
		talloc_free(tdb_key.dptr);
		return LDB_ERR_OPERATIONS_ERROR;
	}

	/* Only declare a conflict if the new DN already exists, and it isn't a case change on the old DN */
	if (tdb_key_old.dsize != tdb_key.dsize || memcmp(tdb_key.dptr, tdb_key_old.dptr, tdb_key.dsize) != 0) {
		if (tdb_exists(ltdb->tdb, tdb_key)) {
			talloc_free(tdb_key_old.dptr);
			talloc_free(tdb_key.dptr);
			ldb_asprintf_errstring(ldb_module_get_ctx(module),
					       "Entry %s already exists",
					       ldb_dn_get_linearized(req->op.rename.newdn));
			/* finding the new record already in the DB is an error */
			talloc_free(msg);
			return LDB_ERR_ENTRY_ALREADY_EXISTS;
		}
	}
	talloc_free(tdb_key_old.dptr);
	talloc_free(tdb_key.dptr);

	/* Always delete first then add, to avoid conflicts with
	 * unique indexes. We rely on the transaction to make this
	 * atomic
	 */
	ret = ltdb_delete_internal(module, msg->dn);
	if (ret != LDB_SUCCESS) {
		talloc_free(msg);
		return ret;
	}

	msg->dn = ldb_dn_copy(msg, req->op.rename.newdn);
	if (msg->dn == NULL) {
		talloc_free(msg);
		return LDB_ERR_OPERATIONS_ERROR;
	}

	/* We don't check single value as we can have more than 1 with
	 * deleted attributes. We could go through all elements but that's
	 * maybe not the most efficient way
	 */
	ret = ltdb_add_internal(module, msg, false);

	talloc_free(msg);

	return ret;
}
예제 #22
0
파일: dsdb_dn.c 프로젝트: endisd/samba
char *dsdb_dn_get_linearized(TALLOC_CTX *mem_ctx, 
			      struct dsdb_dn *dsdb_dn)
{
	const char *postfix = ldb_dn_get_linearized(dsdb_dn->dn);
	return dsdb_dn_get_with_postfix(mem_ctx, dsdb_dn, postfix);
}
예제 #23
0
파일: ldb_tdb.c 프로젝트: GSam/samba
/*
  modify a record - internal interface

  yuck - this is O(n^2). Luckily n is usually small so we probably
  get away with it, but if we ever have really large attribute lists
  then we'll need to look at this again

  'req' is optional, and is used to specify controls if supplied
*/
int ltdb_modify_internal(struct ldb_module *module,
			 const struct ldb_message *msg,
			 struct ldb_request *req)
{
	struct ldb_context *ldb = ldb_module_get_ctx(module);
	void *data = ldb_module_get_private(module);
	struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
	TDB_DATA tdb_key, tdb_data;
	struct ldb_val ldb_data;
	struct ldb_message *msg2;
	unsigned int i, j, k;
	int ret = LDB_SUCCESS, idx;
	struct ldb_control *control_permissive = NULL;

	if (req) {
		control_permissive = ldb_request_get_control(req,
					LDB_CONTROL_PERMISSIVE_MODIFY_OID);
	}

	tdb_key = ltdb_key(module, msg->dn);
	if (!tdb_key.dptr) {
		return LDB_ERR_OTHER;
	}

	tdb_data = tdb_fetch(ltdb->tdb, tdb_key);
	if (!tdb_data.dptr) {
		talloc_free(tdb_key.dptr);
		return ltdb_err_map(tdb_error(ltdb->tdb));
	}

	msg2 = ldb_msg_new(tdb_key.dptr);
	if (msg2 == NULL) {
		free(tdb_data.dptr);
		ret = LDB_ERR_OTHER;
		goto done;
	}

	ldb_data.data = tdb_data.dptr;
	ldb_data.length = tdb_data.dsize;

	ret = ldb_unpack_data(ldb_module_get_ctx(module), &ldb_data, msg2);
	free(tdb_data.dptr);
	if (ret == -1) {
		ret = LDB_ERR_OTHER;
		goto done;
	}

	if (!msg2->dn) {
		msg2->dn = msg->dn;
	}

	for (i=0; i<msg->num_elements; i++) {
		struct ldb_message_element *el = &msg->elements[i], *el2;
		struct ldb_val *vals;
		const struct ldb_schema_attribute *a = ldb_schema_attribute_by_name(ldb, el->name);
		const char *dn;

		switch (msg->elements[i].flags & LDB_FLAG_MOD_MASK) {
		case LDB_FLAG_MOD_ADD:

			if (el->num_values == 0) {
				ldb_asprintf_errstring(ldb,
						       "attribute '%s': attribute on '%s' specified, but with 0 values (illegal)",
						       el->name, ldb_dn_get_linearized(msg2->dn));
				ret = LDB_ERR_CONSTRAINT_VIOLATION;
				goto done;
			}

			/* make a copy of the array so that a permissive
			 * control can remove duplicates without changing the
			 * original values, but do not copy data as we do not
			 * need to keep it around once the operation is
			 * finished */
			if (control_permissive) {
				el = talloc(msg2, struct ldb_message_element);
				if (!el) {
					ret = LDB_ERR_OTHER;
					goto done;
				}
				*el = msg->elements[i];
				el->values = talloc_array(el, struct ldb_val, el->num_values);
				if (el->values == NULL) {
					ret = LDB_ERR_OTHER;
					goto done;
				}
				for (j = 0; j < el->num_values; j++) {
					el->values[j] = msg->elements[i].values[j];
				}
			}

			if (el->num_values > 1 && ldb_tdb_single_valued(a, el)) {
				ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s specified more than once",
						       el->name, ldb_dn_get_linearized(msg2->dn));
				ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
				goto done;
			}

			/* Checks if element already exists */
			idx = find_element(msg2, el->name);
			if (idx == -1) {
				if (ltdb_msg_add_element(ldb, msg2, el) != 0) {
					ret = LDB_ERR_OTHER;
					goto done;
				}
				ret = ltdb_index_add_element(module, msg2->dn,
							     el);
				if (ret != LDB_SUCCESS) {
					goto done;
				}
			} else {
				j = (unsigned int) idx;
				el2 = &(msg2->elements[j]);

				/* We cannot add another value on a existing one
				   if the attribute is single-valued */
				if (ldb_tdb_single_valued(a, el)) {
					ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s specified more than once",
						               el->name, ldb_dn_get_linearized(msg2->dn));
					ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
					goto done;
				}

				/* Check that values don't exist yet on multi-
				   valued attributes or aren't provided twice */
				/* TODO: This is O(n^2) - replace with more efficient check */
				for (j = 0; j < el->num_values; j++) {
					if (ldb_msg_find_val(el2, &el->values[j]) != NULL) {
						if (control_permissive) {
							/* remove this one as if it was never added */
							el->num_values--;
							for (k = j; k < el->num_values; k++) {
								el->values[k] = el->values[k + 1];
							}
							j--; /* rewind */

							continue;
						}

						ldb_asprintf_errstring(ldb,
								       "attribute '%s': value #%u on '%s' already exists",
								       el->name, j, ldb_dn_get_linearized(msg2->dn));
						ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
						goto done;
					}
					if (ldb_msg_find_val(el, &el->values[j]) != &el->values[j]) {
						ldb_asprintf_errstring(ldb,
								       "attribute '%s': value #%u on '%s' provided more than once",
								       el->name, j, ldb_dn_get_linearized(msg2->dn));
						ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
						goto done;
					}
				}

				/* Now combine existing and new values to a new
				   attribute record */
				vals = talloc_realloc(msg2->elements,
						      el2->values, struct ldb_val,
						      el2->num_values + el->num_values);
				if (vals == NULL) {
					ldb_oom(ldb);
					ret = LDB_ERR_OTHER;
					goto done;
				}

				for (j=0; j<el->num_values; j++) {
					vals[el2->num_values + j] =
						ldb_val_dup(vals, &el->values[j]);
				}

				el2->values = vals;
				el2->num_values += el->num_values;

				ret = ltdb_index_add_element(module, msg2->dn, el);
				if (ret != LDB_SUCCESS) {
					goto done;
				}
			}

			break;

		case LDB_FLAG_MOD_REPLACE:

			if (el->num_values > 1 && ldb_tdb_single_valued(a, el)) {
				ldb_asprintf_errstring(ldb, "SINGLE-VALUE attribute %s on %s specified more than once",
						       el->name, ldb_dn_get_linearized(msg2->dn));
				ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
				goto done;
			}

			/*
			 * We don't need to check this if we have been
			 * pre-screened by the repl_meta_data module
			 * in Samba, or someone else who can claim to
			 * know what they are doing. 
			 */
			if (!(el->flags & LDB_FLAG_INTERNAL_DISABLE_SINGLE_VALUE_CHECK)) { 
				/* TODO: This is O(n^2) - replace with more efficient check */
				for (j=0; j<el->num_values; j++) {
					if (ldb_msg_find_val(el, &el->values[j]) != &el->values[j]) {
						ldb_asprintf_errstring(ldb,
								       "attribute '%s': value #%u on '%s' provided more than once",
								       el->name, j, ldb_dn_get_linearized(msg2->dn));
						ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
						goto done;
					}
				}
			}

			/* Checks if element already exists */
			idx = find_element(msg2, el->name);
			if (idx != -1) {
				j = (unsigned int) idx;
				el2 = &(msg2->elements[j]);

				/* we consider two elements to be
				 * equal only if the order
				 * matches. This allows dbcheck to
				 * fix the ordering on attributes
				 * where order matters, such as
				 * objectClass
				 */
				if (ldb_msg_element_equal_ordered(el, el2)) {
					continue;
				}

				/* Delete the attribute if it exists in the DB */
				if (msg_delete_attribute(module, ldb, msg2,
							 el->name) != 0) {
					ret = LDB_ERR_OTHER;
					goto done;
				}
			}

			/* Recreate it with the new values */
			if (ltdb_msg_add_element(ldb, msg2, el) != 0) {
				ret = LDB_ERR_OTHER;
				goto done;
			}

			ret = ltdb_index_add_element(module, msg2->dn, el);
			if (ret != LDB_SUCCESS) {
				goto done;
			}

			break;

		case LDB_FLAG_MOD_DELETE:
			dn = ldb_dn_get_linearized(msg2->dn);
			if (dn == NULL) {
				ret = LDB_ERR_OTHER;
				goto done;
			}

			if (msg->elements[i].num_values == 0) {
				/* Delete the whole attribute */
				ret = msg_delete_attribute(module, ldb, msg2,
							   msg->elements[i].name);
				if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE &&
				    control_permissive) {
					ret = LDB_SUCCESS;
				} else {
					ldb_asprintf_errstring(ldb,
							       "attribute '%s': no such attribute for delete on '%s'",
							       msg->elements[i].name, dn);
				}
				if (ret != LDB_SUCCESS) {
					goto done;
				}
			} else {
				/* Delete specified values from an attribute */
				for (j=0; j < msg->elements[i].num_values; j++) {
					ret = msg_delete_element(module,
							         msg2,
							         msg->elements[i].name,
							         &msg->elements[i].values[j]);
					if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE &&
					    control_permissive) {
						ret = LDB_SUCCESS;
					} else {
						ldb_asprintf_errstring(ldb,
								       "attribute '%s': no matching attribute value while deleting attribute on '%s'",
								       msg->elements[i].name, dn);
					}
					if (ret != LDB_SUCCESS) {
						goto done;
					}
				}
			}
			break;
		default:
			ldb_asprintf_errstring(ldb,
					       "attribute '%s': invalid modify flags on '%s': 0x%x",
					       msg->elements[i].name, ldb_dn_get_linearized(msg->dn),
					       msg->elements[i].flags & LDB_FLAG_MOD_MASK);
			ret = LDB_ERR_PROTOCOL_ERROR;
			goto done;
		}
	}

	ret = ltdb_store(module, msg2, TDB_MODIFY);
	if (ret != LDB_SUCCESS) {
		goto done;
	}

	ret = ltdb_modified(module, msg2->dn);
	if (ret != LDB_SUCCESS) {
		goto done;
	}

done:
	talloc_free(tdb_key.dptr);
	return ret;
}
예제 #24
0
/*
  search for attrs on one DN, in the modules below
 */
int dsdb_module_search_dn(struct ldb_module *module,
			  TALLOC_CTX *mem_ctx,
			  struct ldb_result **_res,
			  struct ldb_dn *basedn,
			  const char * const *attrs,
			  uint32_t dsdb_flags,
			  struct ldb_request *parent)
{
	int ret;
	struct ldb_request *req;
	TALLOC_CTX *tmp_ctx;
	struct ldb_result *res;

	tmp_ctx = talloc_new(mem_ctx);

	res = talloc_zero(tmp_ctx, struct ldb_result);
	if (!res) {
		talloc_free(tmp_ctx);
		return ldb_oom(ldb_module_get_ctx(module));
	}

	ret = ldb_build_search_req(&req, ldb_module_get_ctx(module), tmp_ctx,
				   basedn,
				   LDB_SCOPE_BASE,
				   NULL,
				   attrs,
				   NULL,
				   res,
				   ldb_search_default_callback,
				   parent);
	LDB_REQ_SET_LOCATION(req);
	if (ret != LDB_SUCCESS) {
		talloc_free(tmp_ctx);
		return ret;
	}

	ret = dsdb_request_add_controls(req, dsdb_flags);
	if (ret != LDB_SUCCESS) {
		talloc_free(tmp_ctx);
		return ret;
	}

	if (dsdb_flags & DSDB_FLAG_TRUSTED) {
		ldb_req_mark_trusted(req);
	}

	/* Run the new request */
	if (dsdb_flags & DSDB_FLAG_NEXT_MODULE) {
		ret = ldb_next_request(module, req);
	} else if (dsdb_flags & DSDB_FLAG_TOP_MODULE) {
		ret = ldb_request(ldb_module_get_ctx(module), req);
	} else {
		const struct ldb_module_ops *ops = ldb_module_get_ops(module);
		SMB_ASSERT(dsdb_flags & DSDB_FLAG_OWN_MODULE);
		ret = ops->search(module, req);
	}
	if (ret == LDB_SUCCESS) {
		ret = ldb_wait(req->handle, LDB_WAIT_ALL);
	}

	if (ret != LDB_SUCCESS) {
		talloc_free(tmp_ctx);
		return ret;
	}

	if (res->count != 1) {
		/* we may be reading a DB that does not have the 'check base on search' option... */
		ret = LDB_ERR_NO_SUCH_OBJECT;
		ldb_asprintf_errstring(ldb_module_get_ctx(module), 
				       "dsdb_module_search_dn: did not find base dn %s (%d results)", 
				       ldb_dn_get_linearized(basedn), res->count);
	} else {
		*_res = talloc_steal(mem_ctx, res);
	}
	talloc_free(tmp_ctx);
	return ret;
}
예제 #25
0
/*
  construct the parent GUID for an entry from a message
*/
static int construct_parent_guid(struct ldb_module *module,
				 struct ldb_message *msg, enum ldb_scope scope,
				 struct ldb_request *parent)
{
	struct ldb_result *res, *parent_res;
	const struct ldb_val *parent_guid;
	const char *attrs[] = { "instanceType", NULL };
	const char *attrs2[] = { "objectGUID", NULL };
	uint32_t instanceType;
	int ret;
	struct ldb_dn *parent_dn;
	struct ldb_val v;

	/* determine if the object is NC by instance type */
	ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs,
	                            DSDB_FLAG_NEXT_MODULE |
	                            DSDB_SEARCH_SHOW_RECYCLED, parent);
	if (ret != LDB_SUCCESS) {
		return ret;
	}

	instanceType = ldb_msg_find_attr_as_uint(res->msgs[0],
						 "instanceType", 0);
	talloc_free(res);
	if (instanceType & INSTANCE_TYPE_IS_NC_HEAD) {
		DEBUG(4,(__location__ ": Object %s is NC\n",
			 ldb_dn_get_linearized(msg->dn)));
		return LDB_SUCCESS;
	}
	parent_dn = ldb_dn_get_parent(msg, msg->dn);

	if (parent_dn == NULL) {
		DEBUG(4,(__location__ ": Failed to find parent for dn %s\n",
					 ldb_dn_get_linearized(msg->dn)));
		return LDB_SUCCESS;
	}
	ret = dsdb_module_search_dn(module, msg, &parent_res, parent_dn, attrs2,
	                            DSDB_FLAG_NEXT_MODULE |
	                            DSDB_SEARCH_SHOW_RECYCLED, parent);
	talloc_free(parent_dn);

	/* not NC, so the object should have a parent*/
	if (ret == LDB_ERR_NO_SUCH_OBJECT) {
		return ldb_error(ldb_module_get_ctx(module), LDB_ERR_OPERATIONS_ERROR, 
				 talloc_asprintf(msg, "Parent dn for %s does not exist", 
						 ldb_dn_get_linearized(msg->dn)));
	} else if (ret != LDB_SUCCESS) {
		return ret;
	}

	parent_guid = ldb_msg_find_ldb_val(parent_res->msgs[0], "objectGUID");
	if (!parent_guid) {
		talloc_free(parent_res);
		return LDB_SUCCESS;
	}

	v = data_blob_dup_talloc(parent_res, *parent_guid);
	if (!v.data) {
		talloc_free(parent_res);
		return ldb_oom(ldb_module_get_ctx(module));
	}
	ret = ldb_msg_add_steal_value(msg, "parentGUID", &v);
	talloc_free(parent_res);
	return ret;
}
예제 #26
0
/*
  fill in the cldap netlogon union for a given version
*/
NTSTATUS fill_netlogon_samlogon_response(struct ldb_context *sam_ctx,
					 TALLOC_CTX *mem_ctx,
					 const char *domain,
					 const char *netbios_domain,
					 struct dom_sid *domain_sid,
					 const char *domain_guid,
					 const char *user,
					 uint32_t acct_control,
					 const char *src_address,
					 uint32_t version,
					 struct loadparm_context *lp_ctx,
					 struct netlogon_samlogon_response *netlogon,
					 bool fill_on_blank_request)
{
	const char *dom_attrs[] = {"objectGUID", NULL};
	const char *none_attrs[] = {NULL};
	struct ldb_result *dom_res = NULL;
	int ret;
	const char **services = lpcfg_server_services(lp_ctx);
	uint32_t server_type;
	const char *pdc_name;
	struct GUID domain_uuid;
	const char *dns_domain;
	const char *forest_domain;
	const char *pdc_dns_name;
	const char *flatname;
	const char *server_site;
	const char *client_site;
	const char *pdc_ip;
	struct ldb_dn *domain_dn = NULL;
	struct interface *ifaces;
	bool user_known = false, am_rodc = false;
	uint32_t uac = 0;
	NTSTATUS status;

	/* the domain parameter could have an optional trailing "." */
	if (domain && domain[strlen(domain)-1] == '.') {
		domain = talloc_strndup(mem_ctx, domain, strlen(domain)-1);
		NT_STATUS_HAVE_NO_MEMORY(domain);
	}

	/* Lookup using long or short domainname */
	if (domain && (strcasecmp_m(domain, lpcfg_dnsdomain(lp_ctx)) == 0)) {
		domain_dn = ldb_get_default_basedn(sam_ctx);
	}
	if (netbios_domain && (strcasecmp_m(netbios_domain, lpcfg_sam_name(lp_ctx)) == 0)) {
		domain_dn = ldb_get_default_basedn(sam_ctx);
	}
	if (domain_dn) {
		const char *domain_identifier = domain != NULL ? domain
							: netbios_domain;
		ret = ldb_search(sam_ctx, mem_ctx, &dom_res,
				 domain_dn, LDB_SCOPE_BASE, dom_attrs,
				 "objectClass=domain");
		if (ret != LDB_SUCCESS) {
			DEBUG(2,("Error finding domain '%s'/'%s' in sam: %s\n",
				 domain_identifier,
				 ldb_dn_get_linearized(domain_dn),
				 ldb_errstring(sam_ctx)));
			return NT_STATUS_NO_SUCH_DOMAIN;
		}
		if (dom_res->count != 1) {
			DEBUG(2,("Error finding domain '%s'/'%s' in sam\n",
				 domain_identifier,
				 ldb_dn_get_linearized(domain_dn)));
			return NT_STATUS_NO_SUCH_DOMAIN;
		}
	}

	/* Lookup using GUID or SID */
	if ((dom_res == NULL) && (domain_guid || domain_sid)) {
		if (domain_guid) {
			struct GUID binary_guid;
			struct ldb_val guid_val;

			/* By this means, we ensure we don't have funny stuff in the GUID */

			status = GUID_from_string(domain_guid, &binary_guid);
			if (!NT_STATUS_IS_OK(status)) {
				return status;
			}

			/* And this gets the result into the binary format we want anyway */
			status = GUID_to_ndr_blob(&binary_guid, mem_ctx, &guid_val);
			if (!NT_STATUS_IS_OK(status)) {
				return status;
			}
			ret = ldb_search(sam_ctx, mem_ctx, &dom_res,
						 NULL, LDB_SCOPE_SUBTREE, 
						 dom_attrs, 
						 "(&(objectCategory=DomainDNS)(objectGUID=%s))", 
						 ldb_binary_encode(mem_ctx, guid_val));
		} else { /* domain_sid case */
			ret = ldb_search(sam_ctx, mem_ctx, &dom_res,
					 NULL, LDB_SCOPE_SUBTREE,
					 dom_attrs,
					 "(&(objectCategory=DomainDNS)(objectSid=%s))",
					 dom_sid_string(mem_ctx, domain_sid));
		}
		
		if (ret != LDB_SUCCESS) {
			DEBUG(2,("Unable to find a correct reference to GUID '%s' or SID '%s' in sam: %s\n",
				 domain_guid, dom_sid_string(mem_ctx, domain_sid),
				 ldb_errstring(sam_ctx)));
			return NT_STATUS_NO_SUCH_DOMAIN;
		} else if (dom_res->count == 1) {
			/* Ok, now just check it is our domain */
			if (ldb_dn_compare(ldb_get_default_basedn(sam_ctx),
					   dom_res->msgs[0]->dn) != 0) {
				DEBUG(2,("The GUID '%s' or SID '%s' doesn't identify our domain\n",
					 domain_guid,
					 dom_sid_string(mem_ctx, domain_sid)));
				return NT_STATUS_NO_SUCH_DOMAIN;
			}
		} else {
			DEBUG(2,("Unable to find a correct reference to GUID '%s' or SID '%s' in sam\n",
				 domain_guid, dom_sid_string(mem_ctx, domain_sid)));
			return NT_STATUS_NO_SUCH_DOMAIN;
		}
	}

	if (dom_res == NULL && fill_on_blank_request) {
		/* blank inputs gives our domain - tested against
		   w2k8r2. Without this ADUC on Win7 won't start */
		domain_dn = ldb_get_default_basedn(sam_ctx);
		ret = ldb_search(sam_ctx, mem_ctx, &dom_res,
				 domain_dn, LDB_SCOPE_BASE, dom_attrs,
				 "objectClass=domain");
		if (ret != LDB_SUCCESS) {
			DEBUG(2,("Error finding domain '%s'/'%s' in sam: %s\n",
				 lpcfg_dnsdomain(lp_ctx),
				 ldb_dn_get_linearized(domain_dn),
				 ldb_errstring(sam_ctx)));
			return NT_STATUS_NO_SUCH_DOMAIN;
		}
	}

        if (dom_res == NULL) {
		DEBUG(2,(__location__ ": Unable to get domain information with no inputs\n"));
		return NT_STATUS_NO_SUCH_DOMAIN;
	}

	/* work around different inputs for not-specified users */
	if (!user) {
		user = "";
	}

	/* Enquire about any valid username with just a CLDAP packet -
	 * if kerberos didn't also do this, the security folks would
	 * scream... */
	if (user[0]) {
		/* Only allow some bits to be enquired:  [MS-ATDS] 7.3.3.2 */
		if (acct_control == (uint32_t)-1) {
			acct_control = 0;
		}
		/*
		 * ACB_AUTOLOCK/UF_LOCKOUT seems to be a special
		 * hack for SEC_CHAN_DNS_DOMAIN.
		 *
		 * It's used together with user = "******"
		 */
		if (acct_control != ACB_AUTOLOCK) {
			acct_control &= (ACB_TEMPDUP | ACB_NORMAL | ACB_DOMTRUST | ACB_WSTRUST | ACB_SVRTRUST);
		}
		uac = ds_acb2uf(acct_control);
	}

	if (uac == UF_LOCKOUT) {
		struct ldb_message *tdo_msg = NULL;

		/*
		 * ACB_AUTOLOCK/UF_LOCKOUT seems to be a special
		 * hack for SEC_CHAN_DNS_DOMAIN.
		 *
		 * It's used together with user = "******"
		 */
		status = dsdb_trust_search_tdo_by_type(sam_ctx,
						       SEC_CHAN_DNS_DOMAIN,
						       user, none_attrs,
						       mem_ctx, &tdo_msg);
		if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
			user_known = false;
		} else if (NT_STATUS_IS_OK(status)) {
			TALLOC_FREE(tdo_msg);
			user_known = true;
		} else {
			DEBUG(2,("Unable to find reference to TDO '%s' - %s\n",
				 user, nt_errstr(status)));
			return status;
		}
	} else if (user[0]) {
		struct ldb_result *user_res = NULL;

		/* We must exclude disabled accounts, but otherwise do the bitwise match the client asked for */
		ret = ldb_search(sam_ctx, mem_ctx, &user_res,
					 dom_res->msgs[0]->dn, LDB_SCOPE_SUBTREE, 
					 none_attrs, 
					 "(&(objectClass=user)(samAccountName=%s)"
					 "(!(userAccountControl:" LDB_OID_COMPARATOR_AND ":=%u))"
					 "(userAccountControl:" LDB_OID_COMPARATOR_OR ":=%u))", 
					 ldb_binary_encode_string(mem_ctx, user),
					 UF_ACCOUNTDISABLE, uac);
		if (ret != LDB_SUCCESS) {
			DEBUG(2,("Unable to find reference to user '%s' with ACB 0x%8x under %s: %s\n",
				 user, acct_control, ldb_dn_get_linearized(dom_res->msgs[0]->dn),
				 ldb_errstring(sam_ctx)));
			return NT_STATUS_NO_SUCH_USER;
		} else if (user_res->count == 1) {
			user_known = true;
		} else {
			user_known = false;
		}
		TALLOC_FREE(user_res);
	} else {
		user_known = true;
	}

	server_type = DS_SERVER_DS;

	if (samdb_is_pdc(sam_ctx)) {
		server_type |= DS_SERVER_PDC;
	}

	if (samdb_is_gc(sam_ctx)) {
		server_type |= DS_SERVER_GC;
	}

	if (str_list_check(services, "ldap")) {
		server_type |= DS_SERVER_LDAP;
	}

	if (str_list_check(services, "kdc")) {
		server_type |= DS_SERVER_KDC;
	}

	if (str_list_check(services, "ntp_signd")) {
		server_type |= DS_SERVER_TIMESERV | DS_SERVER_GOOD_TIMESERV;
	}

	if (samdb_rodc(sam_ctx, &am_rodc) == LDB_SUCCESS && !am_rodc) {
		server_type |= DS_SERVER_WRITABLE;
	}

	if (dsdb_functional_level(sam_ctx) >= DS_DOMAIN_FUNCTION_2008) {
		if (server_type & DS_SERVER_WRITABLE) {
			server_type |= DS_SERVER_FULL_SECRET_DOMAIN_6;
		} else {
			server_type |= DS_SERVER_SELECT_SECRET_DOMAIN_6;
		}
	}

	if (version & (NETLOGON_NT_VERSION_5EX|NETLOGON_NT_VERSION_5EX_WITH_IP)) {
		pdc_name = lpcfg_netbios_name(lp_ctx);
	} else {
		pdc_name = talloc_asprintf(mem_ctx, "\\\\%s",
					   lpcfg_netbios_name(lp_ctx));
		NT_STATUS_HAVE_NO_MEMORY(pdc_name);
	}
	domain_uuid      = samdb_result_guid(dom_res->msgs[0], "objectGUID");
	dns_domain       = lpcfg_dnsdomain(lp_ctx);
	forest_domain    = samdb_forest_name(sam_ctx, mem_ctx);
	NT_STATUS_HAVE_NO_MEMORY(forest_domain);
	pdc_dns_name     = talloc_asprintf(mem_ctx, "%s.%s", 
					   strlower_talloc(mem_ctx, 
							   lpcfg_netbios_name(lp_ctx)),
					   dns_domain);
	NT_STATUS_HAVE_NO_MEMORY(pdc_dns_name);
	flatname         = lpcfg_workgroup(lp_ctx);

	server_site      = samdb_server_site_name(sam_ctx, mem_ctx);
	NT_STATUS_HAVE_NO_MEMORY(server_site);
	client_site      = samdb_client_site_name(sam_ctx, mem_ctx,
						  src_address, NULL);
	NT_STATUS_HAVE_NO_MEMORY(client_site);
	if (strcasecmp(server_site, client_site) == 0) {
		server_type |= DS_SERVER_CLOSEST;
	}

	load_interface_list(mem_ctx, lp_ctx, &ifaces);
	if (src_address) {
		pdc_ip = iface_list_best_ip(ifaces, src_address);
	} else {
		pdc_ip = iface_list_first_v4(ifaces);
	}
	if (pdc_ip == NULL || !is_ipaddress_v4(pdc_ip)) {
		/* this matches windows behaviour */
		pdc_ip = "127.0.0.1";
	}

	ZERO_STRUCTP(netlogon);

	/* check if either of these bits is present */
	if (version & (NETLOGON_NT_VERSION_5EX|NETLOGON_NT_VERSION_5EX_WITH_IP)) {
		uint32_t extra_flags = 0;
		netlogon->ntver = NETLOGON_NT_VERSION_5EX;

		/* could check if the user exists */
		if (user_known) {
			netlogon->data.nt5_ex.command      = LOGON_SAM_LOGON_RESPONSE_EX;
		} else {
			netlogon->data.nt5_ex.command      = LOGON_SAM_LOGON_USER_UNKNOWN_EX;
		}
		netlogon->data.nt5_ex.pdc_name     = pdc_name;
		netlogon->data.nt5_ex.user_name    = user;
		netlogon->data.nt5_ex.domain_name  = flatname;
		netlogon->data.nt5_ex.domain_uuid  = domain_uuid;
		netlogon->data.nt5_ex.forest       = forest_domain;
		netlogon->data.nt5_ex.dns_domain   = dns_domain;
		netlogon->data.nt5_ex.pdc_dns_name = pdc_dns_name;
		netlogon->data.nt5_ex.server_site  = server_site;
		netlogon->data.nt5_ex.client_site  = client_site;
		if (version & NETLOGON_NT_VERSION_5EX_WITH_IP) {
			/* note that this is always a IPV4 address */
			extra_flags = NETLOGON_NT_VERSION_5EX_WITH_IP;
			netlogon->data.nt5_ex.sockaddr.sockaddr_family    = 2;
			netlogon->data.nt5_ex.sockaddr.pdc_ip       = pdc_ip;
			netlogon->data.nt5_ex.sockaddr.remaining = data_blob_talloc_zero(mem_ctx, 8);
		}
		netlogon->data.nt5_ex.server_type  = server_type;
		netlogon->data.nt5_ex.nt_version   = NETLOGON_NT_VERSION_1|NETLOGON_NT_VERSION_5EX|extra_flags;
		netlogon->data.nt5_ex.lmnt_token   = 0xFFFF;
		netlogon->data.nt5_ex.lm20_token   = 0xFFFF;

	} else if (version & NETLOGON_NT_VERSION_5) {
		netlogon->ntver = NETLOGON_NT_VERSION_5;

		/* could check if the user exists */
		if (user_known) {
			netlogon->data.nt5.command      = LOGON_SAM_LOGON_RESPONSE;
		} else {
			netlogon->data.nt5.command      = LOGON_SAM_LOGON_USER_UNKNOWN;
		}
		netlogon->data.nt5.pdc_name     = pdc_name;
		netlogon->data.nt5.user_name    = user;
		netlogon->data.nt5.domain_name  = flatname;
		netlogon->data.nt5.domain_uuid  = domain_uuid;
		netlogon->data.nt5.forest       = forest_domain;
		netlogon->data.nt5.dns_domain   = dns_domain;
		netlogon->data.nt5.pdc_dns_name = pdc_dns_name;
		netlogon->data.nt5.pdc_ip       = pdc_ip;
		netlogon->data.nt5.server_type  = server_type;
		netlogon->data.nt5.nt_version   = NETLOGON_NT_VERSION_1|NETLOGON_NT_VERSION_5;
		netlogon->data.nt5.lmnt_token   = 0xFFFF;
		netlogon->data.nt5.lm20_token   = 0xFFFF;

	} else /* (version & NETLOGON_NT_VERSION_1) and all other cases */ {
		netlogon->ntver = NETLOGON_NT_VERSION_1;
		/* could check if the user exists */
		if (user_known) {
			netlogon->data.nt4.command      = LOGON_SAM_LOGON_RESPONSE;
		} else {
			netlogon->data.nt4.command      = LOGON_SAM_LOGON_USER_UNKNOWN;
		}
		netlogon->data.nt4.pdc_name    = pdc_name;
		netlogon->data.nt4.user_name   = user;
		netlogon->data.nt4.domain_name = flatname;
		netlogon->data.nt4.nt_version  = NETLOGON_NT_VERSION_1;
		netlogon->data.nt4.lmnt_token  = 0xFFFF;
		netlogon->data.nt4.lm20_token  = 0xFFFF;
	}

	return NT_STATUS_OK;
}
예제 #27
0
WERROR dsdb_origin_objects_commit(struct ldb_context *ldb,
				  TALLOC_CTX *mem_ctx,
				  const struct drsuapi_DsReplicaObjectListItem *first_object,
				  uint32_t *_num,
				  struct drsuapi_DsReplicaObjectIdentifier2 **_ids)
{
	WERROR status;
	const struct dsdb_schema *schema;
	const struct drsuapi_DsReplicaObjectListItem *cur;
	struct ldb_message **objects;
	struct drsuapi_DsReplicaObjectIdentifier2 *ids;
	uint32_t i;
	uint32_t num_objects = 0;
	const char * const attrs[] = {
		"objectGUID",
		"objectSid",
		NULL
	};
	struct ldb_result *res;
	int ret;

	schema = dsdb_get_schema(ldb);
	if (!schema) {
		return WERR_DS_SCHEMA_NOT_LOADED;
	}

	for (cur = first_object; cur; cur = cur->next_object) {
		num_objects++;
	}

	if (num_objects == 0) {
		return WERR_OK;
	}

	ret = ldb_transaction_start(ldb);
	if (ret != LDB_SUCCESS) {
		return WERR_DS_INTERNAL_FAILURE;
	}

	objects	= talloc_array(mem_ctx, struct ldb_message *,
			       num_objects);
	if (objects == NULL) {
		status = WERR_NOMEM;
		goto cancel;
	}

	for (i=0, cur = first_object; cur; cur = cur->next_object, i++) {
		status = dsdb_convert_object(ldb, schema,
					     cur, objects, &objects[i]);
		if (!W_ERROR_IS_OK(status)) {
			goto cancel;
		}
	}

	ids = talloc_array(mem_ctx,
			   struct drsuapi_DsReplicaObjectIdentifier2,
			   num_objects);
	if (ids == NULL) {
		status = WERR_NOMEM;
		goto cancel;
	}

	for (i=0; i < num_objects; i++) {
		struct dom_sid *sid = NULL;
		struct ldb_request *add_req;

		DEBUG(6,(__location__ ": adding %s\n", 
			 ldb_dn_get_linearized(objects[i]->dn)));

		ret = ldb_build_add_req(&add_req,
					ldb,
					objects,
					objects[i],
					NULL,
					NULL,
					ldb_op_default_callback,
					NULL);
		if (ret != LDB_SUCCESS) {
			status = WERR_DS_INTERNAL_FAILURE;
			goto cancel;
		}

		ret = ldb_request_add_control(add_req, LDB_CONTROL_RELAX_OID, true, NULL);
		if (ret != LDB_SUCCESS) {
			status = WERR_DS_INTERNAL_FAILURE;
			goto cancel;
		}
		
		ret = ldb_request(ldb, add_req);
		if (ret == LDB_SUCCESS) {
			ret = ldb_wait(add_req->handle, LDB_WAIT_ALL);
		}
		if (ret != LDB_SUCCESS) {
			DEBUG(0,(__location__ ": Failed add of %s - %s\n",
				 ldb_dn_get_linearized(objects[i]->dn), ldb_errstring(ldb)));
			status = WERR_DS_INTERNAL_FAILURE;
			goto cancel;
		}

		talloc_free(add_req);

		ret = ldb_search(ldb, objects, &res, objects[i]->dn,
				 LDB_SCOPE_BASE, attrs,
				 "(objectClass=*)");
		if (ret != LDB_SUCCESS) {
			status = WERR_DS_INTERNAL_FAILURE;
			goto cancel;
		}
		ids[i].guid = samdb_result_guid(res->msgs[0], "objectGUID");
		sid = samdb_result_dom_sid(objects, res->msgs[0], "objectSid");
		if (sid) {
			ids[i].sid = *sid;
		} else {
			ZERO_STRUCT(ids[i].sid);
		}
	}

	ret = ldb_transaction_commit(ldb);
	if (ret != LDB_SUCCESS) {
		return WERR_DS_INTERNAL_FAILURE;
	}

	talloc_free(objects);

	*_num = num_objects;
	*_ids = ids;
	return WERR_OK;

cancel:
	talloc_free(objects);
	ldb_transaction_cancel(ldb);
	return status;
}
예제 #28
0
파일: schema_init.c 프로젝트: endisd/samba
int dsdb_schema_from_ldb_results(TALLOC_CTX *mem_ctx, struct ldb_context *ldb,
				 struct smb_iconv_convenience *iconv_convenience, 
				 struct ldb_result *schema_res,
				 struct ldb_result *attrs_res, struct ldb_result *objectclass_res, 
				 struct dsdb_schema **schema_out,
				 char **error_string)
{
	WERROR status;
	uint32_t i;
	const struct ldb_val *prefix_val;
	const struct ldb_val *info_val;
	struct ldb_val info_val_default;
	struct dsdb_schema *schema;

	schema = dsdb_new_schema(mem_ctx, iconv_convenience);
	if (!schema) {
		dsdb_oom(error_string, mem_ctx);
		return LDB_ERR_OPERATIONS_ERROR;
	}

	prefix_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "prefixMap");
	if (!prefix_val) {
		*error_string = talloc_asprintf(mem_ctx, 
						"schema_fsmo_init: no prefixMap attribute found");
		DEBUG(0,(__location__ ": %s\n", *error_string));
		return LDB_ERR_CONSTRAINT_VIOLATION;
	}
	info_val = ldb_msg_find_ldb_val(schema_res->msgs[0], "schemaInfo");
	if (!info_val) {
		info_val_default = strhex_to_data_blob(mem_ctx, "FF0000000000000000000000000000000000000000");
		if (!info_val_default.data) {
			dsdb_oom(error_string, mem_ctx);
			return LDB_ERR_OPERATIONS_ERROR;
		}
		info_val = &info_val_default;
	}

	status = dsdb_load_oid_mappings_ldb(schema, prefix_val, info_val);
	if (!W_ERROR_IS_OK(status)) {
		*error_string = talloc_asprintf(mem_ctx, 
			      "schema_fsmo_init: failed to load oid mappings: %s",
			      win_errstr(status));
		DEBUG(0,(__location__ ": %s\n", *error_string));
		return LDB_ERR_CONSTRAINT_VIOLATION;
	}

	for (i=0; i < attrs_res->count; i++) {
		status = dsdb_attribute_from_ldb(ldb, schema, attrs_res->msgs[i]);
		if (!W_ERROR_IS_OK(status)) {
			*error_string = talloc_asprintf(mem_ctx, 
				      "schema_fsmo_init: failed to load attribute definition: %s:%s",
				      ldb_dn_get_linearized(attrs_res->msgs[i]->dn),
				      win_errstr(status));
			DEBUG(0,(__location__ ": %s\n", *error_string));
			return LDB_ERR_CONSTRAINT_VIOLATION;
		}
	}

	for (i=0; i < objectclass_res->count; i++) {
		status = dsdb_class_from_ldb(schema, objectclass_res->msgs[i]);
		if (!W_ERROR_IS_OK(status)) {
			*error_string = talloc_asprintf(mem_ctx, 
				      "schema_fsmo_init: failed to load class definition: %s:%s",
				      ldb_dn_get_linearized(objectclass_res->msgs[i]->dn),
				      win_errstr(status));
			DEBUG(0,(__location__ ": %s\n", *error_string));
			return LDB_ERR_CONSTRAINT_VIOLATION;
		}
	}

	schema->fsmo.master_dn = ldb_msg_find_attr_as_dn(ldb, schema, schema_res->msgs[0], "fSMORoleOwner");
	if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), schema->fsmo.master_dn) == 0) {
		schema->fsmo.we_are_master = true;
	} else {
		schema->fsmo.we_are_master = false;
	}

	DEBUG(5, ("schema_fsmo_init: we are master: %s\n",
		  (schema->fsmo.we_are_master?"yes":"no")));

	*schema_out = schema;
	return LDB_SUCCESS;
}
예제 #29
0
const char * ads_get_dn(ADS_STRUCT *ads, LDAPMessage *res)
{
	return ldb_dn_get_linearized(res->msgs[0]->dn);
}
예제 #30
0
WERROR dreplsrv_load_partitions(struct dreplsrv_service *s)
{
	WERROR status;
	static const char *attrs[] = { "hasMasterNCs", "hasPartialReplicaNCs", NULL };
	unsigned int i;
	int ret;
	TALLOC_CTX *tmp_ctx;
	struct ldb_result *res;
	struct ldb_message_element *el;
	struct ldb_dn *ntds_dn;

	tmp_ctx = talloc_new(s);
	W_ERROR_HAVE_NO_MEMORY(tmp_ctx);

	ntds_dn = samdb_ntds_settings_dn(s->samdb);
	if (!ntds_dn) {
		DEBUG(1,(__location__ ": Unable to find ntds_dn: %s\n", ldb_errstring(s->samdb)));
		talloc_free(tmp_ctx);
		return WERR_DS_DRA_INTERNAL_ERROR;
	}

	ret = dsdb_search_dn(s->samdb, tmp_ctx, &res, ntds_dn, attrs, DSDB_SEARCH_SHOW_EXTENDED_DN);
	if (ret != LDB_SUCCESS) {
		DEBUG(1,("Searching for hasMasterNCs in NTDS DN failed: %s\n", ldb_errstring(s->samdb)));
		talloc_free(tmp_ctx);
		return WERR_DS_DRA_INTERNAL_ERROR;
	}

	el = ldb_msg_find_element(res->msgs[0], "hasMasterNCs");
	if (!el) {
		DEBUG(1,("Finding hasMasterNCs element in root_res failed: %s\n",
			 ldb_errstring(s->samdb)));
		talloc_free(tmp_ctx);
		return WERR_DS_DRA_INTERNAL_ERROR;
	}

	for (i=0; i<el->num_values; i++) {
		struct ldb_dn *pdn;
		struct dreplsrv_partition *p;

		pdn = ldb_dn_from_ldb_val(tmp_ctx, s->samdb, &el->values[i]);
		if (pdn == NULL) {
			talloc_free(tmp_ctx);
			return WERR_DS_DRA_INTERNAL_ERROR;
		}
		if (!ldb_dn_validate(pdn)) {
			return WERR_DS_DRA_INTERNAL_ERROR;
		}

		p = talloc_zero(s, struct dreplsrv_partition);
		W_ERROR_HAVE_NO_MEMORY(p);

		p->dn = talloc_steal(p, pdn);
		p->service = s;

		DLIST_ADD(s->partitions, p);

		DEBUG(2, ("dreplsrv_partition[%s] loaded\n", ldb_dn_get_linearized(p->dn)));
	}

	el = ldb_msg_find_element(res->msgs[0], "hasPartialReplicaNCs");

	for (i=0; el && i<el->num_values; i++) {
		struct ldb_dn *pdn;
		struct dreplsrv_partition *p;

		pdn = ldb_dn_from_ldb_val(tmp_ctx, s->samdb, &el->values[i]);
		if (pdn == NULL) {
			talloc_free(tmp_ctx);
			return WERR_DS_DRA_INTERNAL_ERROR;
		}
		if (!ldb_dn_validate(pdn)) {
			return WERR_DS_DRA_INTERNAL_ERROR;
		}

		p = talloc_zero(s, struct dreplsrv_partition);
		W_ERROR_HAVE_NO_MEMORY(p);

		p->dn = talloc_steal(p, pdn);
		p->partial_replica = true;
		p->service = s;

		DLIST_ADD(s->partitions, p);

		DEBUG(2, ("dreplsrv_partition[%s] loaded (partial replica)\n", ldb_dn_get_linearized(p->dn)));
	}

	talloc_free(tmp_ctx);

	status = dreplsrv_refresh_partitions(s);
	W_ERROR_NOT_OK_RETURN(status);

	return WERR_OK;
}