コード例 #1
0
/*
  get the DN of the nTDSDSA object from the configuration partition
  whose invocationId is 'invocation_id'
  put the value on 'dn_str'
*/
static WERROR get_dn_from_invocation_id(TALLOC_CTX *mem_ctx,
					struct ldb_context *samdb,
					struct GUID *invocation_id,
					const char **dn_str)
{
	char *invocation_id_str;
	const char *attrs_invocation[] = { NULL };
	struct ldb_message *msg;
	int ret;

	invocation_id_str = GUID_string(mem_ctx, invocation_id);
	W_ERROR_HAVE_NO_MEMORY(invocation_id_str);

	ret = dsdb_search_one(samdb, invocation_id_str, &msg, ldb_get_config_basedn(samdb), LDB_SCOPE_SUBTREE,
			      attrs_invocation, 0, "(&(objectClass=nTDSDSA)(invocationId=%s))", invocation_id_str);
	if (ret != LDB_SUCCESS) {
		DEBUG(0, (__location__ ": Failed search for the object DN under %s whose invocationId is %s",
			  invocation_id_str, ldb_dn_get_linearized(ldb_get_config_basedn(samdb))));
		talloc_free(invocation_id_str);
		return WERR_INTERNAL_ERROR;
	}

	*dn_str = ldb_dn_alloc_linearized(mem_ctx, msg->dn);
	talloc_free(invocation_id_str);
	return WERR_OK;
}
コード例 #2
0
ファイル: dlz_bind9.c プロジェクト: rchicoli/samba
static isc_result_t dlz_bind9_writeable_zone_hook(dns_view_t *view,
					   const char *zone_name)
{
	struct torture_context *tctx = talloc_get_type((void *)view, struct torture_context);
	struct ldb_context *samdb = samdb_connect_url(tctx, NULL, tctx->lp_ctx,
						      system_session(tctx->lp_ctx),
						      0, lpcfg_private_path(tctx, tctx->lp_ctx, "dns/sam.ldb"));
	struct ldb_message *msg;
	int ret;
	const char *attrs[] = {
		NULL
	};
	if (!samdb) {
		torture_fail(tctx, "Failed to connect to samdb");
		return ISC_R_FAILURE;
	}

	ret = dsdb_search_one(samdb, tctx, &msg, NULL,
			      LDB_SCOPE_SUBTREE, attrs, DSDB_SEARCH_SEARCH_ALL_PARTITIONS,
			      "(&(objectClass=dnsZone)(name=%s))", zone_name);
	if (ret != LDB_SUCCESS) {
		torture_fail(tctx, talloc_asprintf(tctx, "Failed to search for %s: %s", zone_name, ldb_errstring(samdb)));
		return ISC_R_FAILURE;
	}
	talloc_free(msg);

	return ISC_R_SUCCESS;
}
コード例 #3
0
ファイル: dns_utils.c プロジェクト: srimalik/samba
WERROR dns_lookup_records(struct dns_server *dns,
			  TALLOC_CTX *mem_ctx,
			  struct ldb_dn *dn,
			  struct dnsp_DnssrvRpcRecord **records,
			  uint16_t *rec_count)
{
	static const char * const attrs[] = { "dnsRecord", NULL};
	struct ldb_message_element *el;
	uint16_t ri;
	int ret;
	struct ldb_message *msg = NULL;
	struct dnsp_DnssrvRpcRecord *recs;

	ret = dsdb_search_one(dns->samdb, mem_ctx, &msg, dn,
			      LDB_SCOPE_BASE, attrs, 0, "%s", "(objectClass=dnsNode)");
	if (ret != LDB_SUCCESS) {
		/* TODO: we need to check if there's a glue record we need to
		 * create a referral to */
		return DNS_ERR(NAME_ERROR);
	}

	el = ldb_msg_find_element(msg, attrs[0]);
	if (el == NULL) {
		*records = NULL;
		*rec_count = 0;
		return WERR_OK;
	}

	recs = talloc_zero_array(mem_ctx, struct dnsp_DnssrvRpcRecord, el->num_values);
	W_ERROR_HAVE_NO_MEMORY(recs);
	for (ri = 0; ri < el->num_values; ri++) {
		struct ldb_val *v = &el->values[ri];
		enum ndr_err_code ndr_err;

		ndr_err = ndr_pull_struct_blob(v, recs, &recs[ri],
				(ndr_pull_flags_fn_t)ndr_pull_dnsp_DnssrvRpcRecord);
		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
			DEBUG(0, ("Failed to grab dnsp_DnssrvRpcRecord\n"));
			return DNS_ERR(SERVER_FAILURE);
		}
	}
	*records = recs;
	*rec_count = el->num_values;
	return WERR_OK;
}
コード例 #4
0
ファイル: auth_sam.c プロジェクト: Alexandr-Galko/samba
static NTSTATUS authsam_search_account(TALLOC_CTX *mem_ctx, struct ldb_context *sam_ctx,
				       const char *account_name,
				       struct ldb_dn *domain_dn,
				       struct ldb_message **ret_msg)
{
	int ret;

	/* pull the user attributes */
	ret = dsdb_search_one(sam_ctx, mem_ctx, ret_msg, domain_dn, LDB_SCOPE_SUBTREE,
			      user_attrs,
			      DSDB_SEARCH_SHOW_EXTENDED_DN,
			      "(&(sAMAccountName=%s)(objectclass=user))",
			      ldb_binary_encode_string(mem_ctx, account_name));
	if (ret == LDB_ERR_NO_SUCH_OBJECT) {
		DEBUG(3,("sam_search_user: Couldn't find user [%s] in samdb, under %s\n", 
			 account_name, ldb_dn_get_linearized(domain_dn)));
		return NT_STATUS_NO_SUCH_USER;		
	}
	if (ret != LDB_SUCCESS) {
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}
	
	return NT_STATUS_OK;
}
コード例 #5
0
ファイル: secrets.c プロジェクト: Arkhont/samba
/**
 * Retrieve the domain SID from the secrets database.
 * @return pointer to a SID object if the SID could be obtained, NULL otherwise
 */
struct dom_sid *secrets_get_domain_sid(TALLOC_CTX *mem_ctx,
				       struct loadparm_context *lp_ctx,
				       const char *domain,
				       enum netr_SchannelType *sec_channel_type,
				       char **errstring)
{
	struct ldb_context *ldb;
	struct ldb_message *msg;
	int ldb_ret;
	const char *attrs[] = { "objectSid", "secureChannelType", NULL };
	struct dom_sid *result = NULL;
	const struct ldb_val *v;
	enum ndr_err_code ndr_err;

	*errstring = NULL;

	ldb = secrets_db_connect(mem_ctx, lp_ctx);
	if (ldb == NULL) {
		DEBUG(5, ("secrets_db_connect failed\n"));
		return NULL;
	}

	ldb_ret = dsdb_search_one(ldb, ldb, &msg,
			      ldb_dn_new(mem_ctx, ldb, SECRETS_PRIMARY_DOMAIN_DN),
			      LDB_SCOPE_ONELEVEL,
			      attrs, 0, SECRETS_PRIMARY_DOMAIN_FILTER, domain);

	if (ldb_ret != LDB_SUCCESS) {
		*errstring = talloc_asprintf(mem_ctx, "Failed to find record for %s in %s: %s: %s", 
					     domain, (char *) ldb_get_opaque(ldb, "ldb_url"),
					     ldb_strerror(ldb_ret), ldb_errstring(ldb));
		return NULL;
	}
	v = ldb_msg_find_ldb_val(msg, "objectSid");
	if (v == NULL) {
		*errstring = talloc_asprintf(mem_ctx, "Failed to find a SID on record for %s in %s", 
					     domain, (char *) ldb_get_opaque(ldb, "ldb_url"));
		return NULL;
	}

	if (sec_channel_type) {
		int t;
		t = ldb_msg_find_attr_as_int(msg, "secureChannelType", -1);
		if (t == -1) {
			*errstring = talloc_asprintf(mem_ctx, "Failed to find secureChannelType for %s in %s",
						     domain, (char *) ldb_get_opaque(ldb, "ldb_url"));
			return NULL;
		}
		*sec_channel_type = t;
	}

	result = talloc(mem_ctx, struct dom_sid);
	if (result == NULL) {
		talloc_free(ldb);
		return NULL;
	}

	ndr_err = ndr_pull_struct_blob(v, result, result,
				       (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
		*errstring = talloc_asprintf(mem_ctx, "Failed to parse SID on record for %s in %s", 
					     domain, (char *) ldb_get_opaque(ldb, "ldb_url"));
		talloc_free(result);
		talloc_free(ldb);
		return NULL;
	}

	return result;
}
コード例 #6
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;
}
コード例 #7
0
ファイル: kpasswd_glue.c プロジェクト: DanilKorotenko/samba
/*
   A user password change

   Return true if there is a valid error packet (or success) formed in
   the error_blob
*/
NTSTATUS samdb_kpasswd_change_password(TALLOC_CTX *mem_ctx,
				       struct loadparm_context *lp_ctx,
				       struct tevent_context *event_ctx,
				       struct ldb_context *samdb,
				       struct auth_session_info *session_info,
				       const DATA_BLOB *password,
				       enum samPwdChangeReason *reject_reason,
				       struct samr_DomInfo1 **dominfo,
				       const char **error_string,
				       NTSTATUS *result)
{
	struct samr_Password *oldLmHash, *oldNtHash;
	const char * const attrs[] = { "dBCSPwd", "unicodePwd", NULL };
	struct ldb_message *msg;
	NTSTATUS status;
	int ret;

	/* Fetch the old hashes to get the old password in order to perform
	 * the password change operation. Naturally it would be much better to
	 * have a password hash from an authentication around but this doesn't
	 * seem to be the case here. */
	ret = dsdb_search_one(samdb, mem_ctx, &msg, ldb_get_default_basedn(samdb),
			      LDB_SCOPE_SUBTREE,
			      attrs,
			      DSDB_SEARCH_NO_GLOBAL_CATALOG,
			      "(&(objectClass=user)(sAMAccountName=%s))",
			      session_info->info->account_name);
	if (ret != LDB_SUCCESS) {
		*error_string = "No such user when changing password";
		return NT_STATUS_NO_SUCH_USER;
	}

	/*
	 * No need to check for password lockout here, the KDC will
	 * have done that when issuing the ticket, which is not based
	 * on the user's password
	 */
	status = samdb_result_passwords_no_lockout(mem_ctx, lp_ctx, msg,
						   &oldLmHash, &oldNtHash);
	if (!NT_STATUS_IS_OK(status)) {
		*error_string = "Not permitted to change password";
		return NT_STATUS_ACCESS_DENIED;
	}

	/* Start a SAM with user privileges for the password change */
	samdb = samdb_connect(mem_ctx, event_ctx, lp_ctx,
			      session_info, 0);
	if (!samdb) {
		*error_string = "Failed to open samdb";
		return NT_STATUS_ACCESS_DENIED;
	}

	DEBUG(3, ("Changing password of %s\\%s (%s)\n",
		  session_info->info->domain_name,
		  session_info->info->account_name,
		  dom_sid_string(mem_ctx, &session_info->security_token->sids[PRIMARY_USER_SID_INDEX])));

	/* Performs the password change */
	status = samdb_set_password_sid(samdb,
					mem_ctx,
					&session_info->security_token->sids[PRIMARY_USER_SID_INDEX],
					NULL,
					password,
					NULL,
					NULL,
					oldLmHash,
					oldNtHash, /* this is a user password change */
					reject_reason,
					dominfo);
	if (!NT_STATUS_IS_OK(status)) {
		*error_string = nt_errstr(status);
	}
	*result = status;

	return NT_STATUS_OK;
}
コード例 #8
0
ファイル: util_samr.c プロジェクト: Arkhont/samba
NTSTATUS dsdb_lookup_rids(struct ldb_context *ldb,
			  TALLOC_CTX *mem_ctx,
			  const struct dom_sid *domain_sid,
			  unsigned int num_rids,
			  uint32_t *rids,
			  const char **names,
			  enum lsa_SidType *lsa_attrs)
{
	const char *attrs[] = { "sAMAccountType", "sAMAccountName", NULL };
	unsigned int i, num_mapped;

	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
	NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);

	num_mapped = 0;

	for (i=0; i<num_rids; i++) {
		struct ldb_message *msg;
		struct ldb_dn *dn;
		uint32_t attr;
		int rc;

		lsa_attrs[i] = SID_NAME_UNKNOWN;

		dn = ldb_dn_new_fmt(tmp_ctx, ldb, "<SID=%s>",
				    dom_sid_string(tmp_ctx,
						   dom_sid_add_rid(tmp_ctx, domain_sid,
								   rids[i])));
		if (dn == NULL) {
			talloc_free(tmp_ctx);
			return NT_STATUS_NO_MEMORY;
		}
		rc = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE, attrs, 0, "samAccountName=*");
		if (rc == LDB_ERR_NO_SUCH_OBJECT) {
			continue;
		} else if (rc != LDB_SUCCESS) {
			talloc_free(tmp_ctx);
			return NT_STATUS_INTERNAL_DB_CORRUPTION;
		}

		names[i] = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL);
		if (names[i] == NULL) {
			DEBUG(10, ("no samAccountName\n"));
			continue;
		}
		talloc_steal(names, names[i]);
		attr = ldb_msg_find_attr_as_uint(msg, "samAccountType", 0);
		lsa_attrs[i] = ds_atype_map(attr);
		if (lsa_attrs[i] == SID_NAME_UNKNOWN) {
			continue;
		}
		num_mapped += 1;
	}
	talloc_free(tmp_ctx);

	if (num_mapped == 0) {
		return NT_STATUS_NONE_MAPPED;
	}
	if (num_mapped < num_rids) {
		return STATUS_SOME_UNMAPPED;
	}
	return NT_STATUS_OK;
}
コード例 #9
0
ファイル: util_samr.c プロジェクト: Arkhont/samba
/* Return the members of this group (which may be a domain group or an alias) */
NTSTATUS dsdb_enum_group_mem(struct ldb_context *ldb,
			     TALLOC_CTX *mem_ctx,
			     struct ldb_dn *dn,
			     struct dom_sid **members_out,
			     unsigned int *pnum_members)
{
	struct ldb_message *msg;
	unsigned int i, j;
	int ret;
	struct dom_sid *members;
	struct ldb_message_element *member_el;
	const char *attrs[] = { "member", NULL };
	NTSTATUS status;
	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
	NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);

	ret = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE, attrs,
			      DSDB_SEARCH_SHOW_EXTENDED_DN, NULL);
	if (ret == LDB_ERR_NO_SUCH_OBJECT) {
		talloc_free(tmp_ctx);
		return NT_STATUS_OBJECT_NAME_NOT_FOUND;
	}
	if (ret != LDB_SUCCESS) {
		DEBUG(1, ("dsdb_enum_group_mem: dsdb_search for %s failed: %s\n",
			  ldb_dn_get_linearized(dn), ldb_errstring(ldb)));
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}

	member_el = ldb_msg_find_element(msg, "member");
	if (!member_el) {
		*members_out = NULL;
		*pnum_members = 0;
		talloc_free(tmp_ctx);
		return NT_STATUS_OK;
	}

	members = talloc_array(mem_ctx, struct dom_sid, member_el->num_values);
	if (members == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	j = 0;
	for (i=0; i <member_el->num_values; i++) {
		struct ldb_dn *member_dn = ldb_dn_from_ldb_val(tmp_ctx, ldb,
							       &member_el->values[i]);
		if (!member_dn || !ldb_dn_validate(member_dn)) {
			DEBUG(1, ("Could not parse %*.*s as a DN\n",
				  (int)member_el->values[i].length,
				  (int)member_el->values[i].length,
				  (const char *)member_el->values[i].data));
			talloc_free(tmp_ctx);
			return NT_STATUS_INTERNAL_DB_CORRUPTION;
		}

		status = dsdb_get_extended_dn_sid(member_dn, &members[j],
						  "SID");
		if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
			/* If we fail finding a SID then this is no error since
			 * it could be a non SAM object - e.g. a contact */
			continue;
		} else if (!NT_STATUS_IS_OK(status)) {
			DEBUG(1, ("When parsing DN '%s' we failed to parse it's SID component, so we cannot fetch the membership: %s\n",
				  ldb_dn_get_extended_linearized(tmp_ctx, member_dn, 1),
				  nt_errstr(status)));
			talloc_free(tmp_ctx);
			return status;
		}

		++j;
	}

	*members_out = talloc_steal(mem_ctx, members);
	*pnum_members = j;
	talloc_free(tmp_ctx);
	return NT_STATUS_OK;
}
コード例 #10
0
ファイル: util_samr.c プロジェクト: Arkhont/samba
/* Add a user, SAMR style, including the correct transaction
 * semantics.  Used by the SAMR server and by pdb_samba4 */
NTSTATUS dsdb_add_user(struct ldb_context *ldb,
		       TALLOC_CTX *mem_ctx,
		       const char *account_name,
		       uint32_t acct_flags,
		       struct dom_sid **sid,
		       struct ldb_dn **dn)
{
	const char *name;
	struct ldb_message *msg;
	int ret;
	const char *container, *obj_class=NULL;
	char *cn_name;
	size_t cn_name_len;

	const char *attrs[] = {
		"objectSid",
		"userAccountControl",
		NULL
	};

	uint32_t user_account_control;
	struct ldb_dn *account_dn;
	struct dom_sid *account_sid;

	TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
	NT_STATUS_HAVE_NO_MEMORY(tmp_ctx);

	/*
	 * Start a transaction, so we can query and do a subsequent atomic
	 * modify
	 */

	ret = ldb_transaction_start(ldb);
	if (ret != LDB_SUCCESS) {
		DEBUG(0,("Failed to start a transaction for user creation: %s\n",
			 ldb_errstring(ldb)));
		talloc_free(tmp_ctx);
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}

	/* check if the user already exists */
	name = samdb_search_string(ldb, tmp_ctx, NULL,
				   "sAMAccountName",
				   "(&(sAMAccountName=%s)(objectclass=user))",
				   ldb_binary_encode_string(tmp_ctx, account_name));
	if (name != NULL) {
		ldb_transaction_cancel(ldb);
		talloc_free(tmp_ctx);
		return NT_STATUS_USER_EXISTS;
	}

	cn_name = talloc_strdup(tmp_ctx, account_name);
	if (!cn_name) {
		ldb_transaction_cancel(ldb);
		talloc_free(tmp_ctx);
		return NT_STATUS_NO_MEMORY;
	}

	cn_name_len = strlen(cn_name);
	if (cn_name_len < 1) {
		ldb_transaction_cancel(ldb);
		talloc_free(tmp_ctx);
		return NT_STATUS_INVALID_PARAMETER;
	}

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

	/* This must be one of these values *only* */
	if (acct_flags == ACB_NORMAL) {
		container = "CN=Users";
		obj_class = "user";

	} else if (acct_flags == ACB_WSTRUST) {
		if (cn_name[cn_name_len - 1] != '$') {
			ldb_transaction_cancel(ldb);
			return NT_STATUS_FOOBAR;
		}
		cn_name[cn_name_len - 1] = '\0';
		container = "CN=Computers";
		obj_class = "computer";

	} else if (acct_flags == ACB_SVRTRUST) {
		if (cn_name[cn_name_len - 1] != '$') {
			ldb_transaction_cancel(ldb);
			return NT_STATUS_FOOBAR;
		}
		cn_name[cn_name_len - 1] = '\0';
		container = "OU=Domain Controllers";
		obj_class = "computer";
	} else {
		ldb_transaction_cancel(ldb);
		talloc_free(tmp_ctx);
		return NT_STATUS_INVALID_PARAMETER;
	}

	/* add core elements to the ldb_message for the user */
	msg->dn = ldb_dn_copy(msg, ldb_get_default_basedn(ldb));
	if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s,%s", cn_name, container)) {
		ldb_transaction_cancel(ldb);
		talloc_free(tmp_ctx);
		return NT_STATUS_FOOBAR;
	}

	ldb_msg_add_string(msg, "sAMAccountName", account_name);
	ldb_msg_add_string(msg, "objectClass", obj_class);

	/* create the user */
	ret = ldb_add(ldb, msg);
	switch (ret) {
	case LDB_SUCCESS:
		break;
	case LDB_ERR_ENTRY_ALREADY_EXISTS:
		ldb_transaction_cancel(ldb);
		DEBUG(0,("Failed to create user record %s: %s\n",
			 ldb_dn_get_linearized(msg->dn),
			 ldb_errstring(ldb)));
		talloc_free(tmp_ctx);
		return NT_STATUS_USER_EXISTS;
	case LDB_ERR_UNWILLING_TO_PERFORM:
	case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
		ldb_transaction_cancel(ldb);
		DEBUG(0,("Failed to create user record %s: %s\n",
			 ldb_dn_get_linearized(msg->dn),
			 ldb_errstring(ldb)));
		talloc_free(tmp_ctx);
		return NT_STATUS_ACCESS_DENIED;
	default:
		ldb_transaction_cancel(ldb);
		DEBUG(0,("Failed to create user record %s: %s\n",
			 ldb_dn_get_linearized(msg->dn),
			 ldb_errstring(ldb)));
		talloc_free(tmp_ctx);
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}

	account_dn = msg->dn;

	/* retrieve the sid and account control bits for the user just created */
	ret = dsdb_search_one(ldb, tmp_ctx, &msg,
			      account_dn, LDB_SCOPE_BASE, attrs, 0, NULL);

	if (ret != LDB_SUCCESS) {
		ldb_transaction_cancel(ldb);
		DEBUG(0,("Can't locate the account we just created %s: %s\n",
			 ldb_dn_get_linearized(account_dn), ldb_errstring(ldb)));
		talloc_free(tmp_ctx);
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}
	account_sid = samdb_result_dom_sid(tmp_ctx, msg, "objectSid");
	if (account_sid == NULL) {
		ldb_transaction_cancel(ldb);
		DEBUG(0,("Apparently we failed to get the objectSid of the just created account record %s\n",
			 ldb_dn_get_linearized(msg->dn)));
		talloc_free(tmp_ctx);
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}

	/* Change the account control to be the correct account type.
	 * The default is for a workstation account */
	user_account_control = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
	user_account_control = (user_account_control &
				~(UF_NORMAL_ACCOUNT |
				  UF_INTERDOMAIN_TRUST_ACCOUNT |
				  UF_WORKSTATION_TRUST_ACCOUNT |
				  UF_SERVER_TRUST_ACCOUNT));
	user_account_control |= ds_acb2uf(acct_flags);

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

	msg->dn = account_dn;

	if (samdb_msg_add_uint(ldb, tmp_ctx, msg,
			       "userAccountControl",
			       user_account_control) != LDB_SUCCESS) {
		ldb_transaction_cancel(ldb);
		talloc_free(tmp_ctx);
		return NT_STATUS_NO_MEMORY;
	}

	/* modify the samdb record */
	ret = dsdb_replace(ldb, msg, 0);
	if (ret != LDB_SUCCESS) {
		DEBUG(0,("Failed to modify account record %s to set userAccountControl: %s\n",
			 ldb_dn_get_linearized(msg->dn),
			 ldb_errstring(ldb)));
		ldb_transaction_cancel(ldb);
		talloc_free(tmp_ctx);

		/* we really need samdb.c to return NTSTATUS */
		return NT_STATUS_UNSUCCESSFUL;
	}

	ret = ldb_transaction_commit(ldb);
	if (ret != LDB_SUCCESS) {
		DEBUG(0,("Failed to commit transaction to add and modify account record %s: %s\n",
			 ldb_dn_get_linearized(msg->dn),
			 ldb_errstring(ldb)));
		talloc_free(tmp_ctx);
		return NT_STATUS_INTERNAL_DB_CORRUPTION;
	}
	*dn = talloc_steal(mem_ctx, account_dn);
	*sid = talloc_steal(mem_ctx, account_sid);
	talloc_free(tmp_ctx);
	return NT_STATUS_OK;
}
コード例 #11
0
ファイル: auth_sam.c プロジェクト: DavidMulder/samba
static NTSTATUS authsam_password_check_and_record(struct auth4_context *auth_context,
						  TALLOC_CTX *mem_ctx,
						  struct ldb_dn *domain_dn,
						  struct ldb_message *msg,
						  uint16_t acct_flags,
						  const struct auth_usersupplied_info *user_info,
						  DATA_BLOB *user_sess_key,
						  DATA_BLOB *lm_sess_key,
						  bool *authoritative)
{
	NTSTATUS nt_status;
	NTSTATUS auth_status;
	TALLOC_CTX *tmp_ctx;
	int i, ret;
	int history_len = 0;
	struct ldb_context *sam_ctx = auth_context->sam_ctx;
	const char * const attrs[] = { "pwdHistoryLength", NULL };
	struct ldb_message *dom_msg;
	struct samr_Password *lm_pwd;
	struct samr_Password *nt_pwd;
	bool am_rodc;

	tmp_ctx = talloc_new(mem_ctx);
	if (tmp_ctx == NULL) {
		return NT_STATUS_NO_MEMORY;
	}

	/*
	 * This call does more than what it appears to do, it also
	 * checks for the account lockout.
	 *
	 * It is done here so that all parts of Samba that read the
	 * password refuse to even operate on it if the account is
	 * locked out, to avoid mistakes like CVE-2013-4496.
	 */
	nt_status = samdb_result_passwords(tmp_ctx, auth_context->lp_ctx,
					   msg, &lm_pwd, &nt_pwd);
	if (!NT_STATUS_IS_OK(nt_status)) {
		TALLOC_FREE(tmp_ctx);
		return nt_status;
	}

	if (lm_pwd == NULL && nt_pwd == NULL) {
		if (samdb_rodc(auth_context->sam_ctx, &am_rodc) == LDB_SUCCESS && am_rodc) {
			/*
			 * we don't have passwords for this
			 * account. We are an RODC, and this account
			 * may be one for which we either are denied
			 * REPL_SECRET replication or we haven't yet
			 * done the replication. We return
			 * NT_STATUS_NOT_IMPLEMENTED which tells the
			 * auth code to try the next authentication
			 * mechanism. We also send a message to our
			 * drepl server to tell it to try and
			 * replicate the secrets for this account.
			 *
			 * TODO: Should we only trigger this is detected
			 * there's a chance that the password might be
			 * replicated, we should be able to detect this
			 * based on msDS-NeverRevealGroup.
			 */
			auth_sam_trigger_repl_secret(auth_context,
						     auth_context->msg_ctx,
						     auth_context->event_ctx,
						     msg->dn);
			TALLOC_FREE(tmp_ctx);
			return NT_STATUS_NOT_IMPLEMENTED;
		}
	}

	auth_status = authsam_password_ok(auth_context, tmp_ctx,
					  acct_flags,
					  lm_pwd, nt_pwd,
					  user_info,
					  user_sess_key, lm_sess_key);
	if (NT_STATUS_IS_OK(auth_status)) {
		if (user_sess_key->data) {
			talloc_steal(mem_ctx, user_sess_key->data);
		}
		if (lm_sess_key->data) {
			talloc_steal(mem_ctx, lm_sess_key->data);
		}
		TALLOC_FREE(tmp_ctx);
		return NT_STATUS_OK;
	}
	*user_sess_key = data_blob_null;
	*lm_sess_key = data_blob_null;

	if (!NT_STATUS_EQUAL(auth_status, NT_STATUS_WRONG_PASSWORD)) {
		TALLOC_FREE(tmp_ctx);
		return auth_status;
	}

	/*
	 * We only continue if this was a wrong password
	 * and we'll always return NT_STATUS_WRONG_PASSWORD
	 * no matter what error happens.
	 */

	/* pull the domain password property attributes */
	ret = dsdb_search_one(sam_ctx, tmp_ctx, &dom_msg, domain_dn, LDB_SCOPE_BASE,
			      attrs, 0, "objectClass=domain");
	if (ret == LDB_SUCCESS) {
		history_len = ldb_msg_find_attr_as_uint(dom_msg, "pwdHistoryLength", 0);
	} else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
		DEBUG(3,("Couldn't find domain %s: %s!\n",
			 ldb_dn_get_linearized(domain_dn),
			 ldb_errstring(sam_ctx)));
	} else {
		DEBUG(3,("error finding domain %s: %s!\n",
			 ldb_dn_get_linearized(domain_dn),
			 ldb_errstring(sam_ctx)));
	}

	for (i = 1; i < MIN(history_len, 3); i++) {
		struct samr_Password zero_string_hash;
		struct samr_Password zero_string_des_hash;
		struct samr_Password *nt_history_pwd = NULL;
		struct samr_Password *lm_history_pwd = NULL;
		NTTIME pwdLastSet;
		struct timeval tv_now;
		NTTIME now;
		int allowed_period_mins;
		NTTIME allowed_period;

		nt_status = samdb_result_passwords_from_history(tmp_ctx,
							auth_context->lp_ctx,
							msg, i,
							&lm_history_pwd,
							&nt_history_pwd);
		if (!NT_STATUS_IS_OK(nt_status)) {
			/*
			 * If we don't find element 'i' we won't find
			 * 'i+1' ...
			 */
			break;
		}

		/*
		 * We choose to avoid any issues
		 * around different LM and NT history
		 * lengths by only checking the NT
		 * history
		 */
		if (nt_history_pwd == NULL) {
			/*
			 * If we don't find element 'i' we won't find
			 * 'i+1' ...
			 */
			break;
		}

		/* Skip over all-zero hashes in the history */
		if (all_zero(nt_history_pwd->hash,
			     sizeof(nt_history_pwd->hash))) {
			continue;
		}

		/*
		 * This looks odd, but the password_hash module writes this in if
		 * (somehow) we didn't have an old NT hash
		 */

		E_md4hash("", zero_string_hash.hash);
		if (memcmp(nt_history_pwd->hash, zero_string_hash.hash, 16) == 0) {
			continue;
		}

		E_deshash("", zero_string_des_hash.hash);
		if (!lm_history_pwd || memcmp(lm_history_pwd->hash, zero_string_des_hash.hash, 16) == 0) {
			lm_history_pwd = NULL;
		}

		auth_status = authsam_password_ok(auth_context, tmp_ctx,
						  acct_flags,
						  lm_history_pwd,
						  nt_history_pwd,
						  user_info,
						  user_sess_key,
						  lm_sess_key);
		if (!NT_STATUS_IS_OK(auth_status)) {
			/*
			 * If this was not a correct password, try the next
			 * one from the history
			 */
			*user_sess_key = data_blob_null;
			*lm_sess_key = data_blob_null;
			continue;
		}

		if (i != 1) {
			/*
			 * The authentication was OK, but not against
			 * the previous password, which is stored at index 1.
			 *
			 * We just return the original wrong password.
			 * This skips the update of the bad pwd count,
			 * because this is almost certainly user error
			 * (or automatic login on a computer using a cached
			 * password from before the password change),
			 * not an attack.
			 */
			TALLOC_FREE(tmp_ctx);
			return NT_STATUS_WRONG_PASSWORD;
		}

		if (user_info->password_state != AUTH_PASSWORD_RESPONSE) {
			/*
			 * The authentication was OK against the previous password,
			 * but it's not a NTLM network authentication.
			 *
			 * We just return the original wrong password.
			 * This skips the update of the bad pwd count,
			 * because this is almost certainly user error
			 * (or automatic login on a computer using a cached
			 * password from before the password change),
			 * not an attack.
			 */
			TALLOC_FREE(tmp_ctx);
			return NT_STATUS_WRONG_PASSWORD;
		}

		/*
		 * If the password was OK, it's a NTLM network authentication
		 * and it was the previous password.
		 *
		 * Now we see if it is within the grace period,
		 * so that we don't break cached sessions on other computers
		 * before the user can lock and unlock their other screens
		 * (resetting their cached password).
		 *
		 * See http://support.microsoft.com/kb/906305
		 * OldPasswordAllowedPeriod ("old password allowed period")
		 * is specified in minutes. The default is 60.
		 */
		allowed_period_mins = lpcfg_old_password_allowed_period(auth_context->lp_ctx);
		/*
		 * NTTIME uses 100ns units
		 */
		allowed_period = allowed_period_mins * 60 * 1000*1000*10;
		pwdLastSet = samdb_result_nttime(msg, "pwdLastSet", 0);
		tv_now = timeval_current();
		now = timeval_to_nttime(&tv_now);

		if (now < pwdLastSet) {
			/*
			 * time jump?
			 *
			 * We just return the original wrong password.
			 * This skips the update of the bad pwd count,
			 * because this is almost certainly user error
			 * (or automatic login on a computer using a cached
			 * password from before the password change),
			 * not an attack.
			 */
			TALLOC_FREE(tmp_ctx);
			return NT_STATUS_WRONG_PASSWORD;
		}

		if ((now - pwdLastSet) >= allowed_period) {
			/*
			 * The allowed period is over.
			 *
			 * We just return the original wrong password.
			 * This skips the update of the bad pwd count,
			 * because this is almost certainly user error
			 * (or automatic login on a computer using a cached
			 * password from before the password change),
			 * not an attack.
			 */
			TALLOC_FREE(tmp_ctx);
			return NT_STATUS_WRONG_PASSWORD;
		}

		/*
		 * We finally allow the authentication with the
		 * previous password within the allowed period.
		 */
		if (user_sess_key->data) {
			talloc_steal(mem_ctx, user_sess_key->data);
		}
		if (lm_sess_key->data) {
			talloc_steal(mem_ctx, lm_sess_key->data);
		}

		TALLOC_FREE(tmp_ctx);
		return auth_status;
	}

	/*
	 * If we are not in the allowed period or match an old password,
	 * we didn't return early. Now update the badPwdCount et al.
	 */
	nt_status = authsam_update_bad_pwd_count(auth_context->sam_ctx,
						 msg, domain_dn);
	if (!NT_STATUS_IS_OK(nt_status)) {
		/*
		 * We need to return the original
		 * NT_STATUS_WRONG_PASSWORD error, so there isn't
		 * anything more we can do than write something into
		 * the log
		 */
		DEBUG(0, ("Failed to note bad password for user [%s]: %s\n",
			  user_info->mapped.account_name,
			  nt_errstr(nt_status)));
	}

	if (samdb_rodc(auth_context->sam_ctx, &am_rodc) == LDB_SUCCESS && am_rodc) {
		*authoritative = false;
	}

	TALLOC_FREE(tmp_ctx);
	return NT_STATUS_WRONG_PASSWORD;
}