/*
ldb database module
- Copyright (C) Simo Sorce 2004
- Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
+ Copyright (C) Simo Sorce 2004-2006
+ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2006
Copyright (C) Andrew Tridgell 2004
This program is free software; you can redistribute it and/or modify
#include "dsdb/samdb/samdb.h"
#include "ads.h"
#include "hdb.h"
+#include "dsdb/samdb/ldb_modules/password_modules.h"
/* If we have decided there is reason to work on this request, then
* setup all the password hash types correctly.
*
*/
-struct ph_async_context {
+struct ph_context {
enum ph_type {PH_ADD, PH_MOD} type;
enum ph_step {PH_ADD_SEARCH_DOM, PH_ADD_DO_ADD, PH_MOD_DO_REQ, PH_MOD_SEARCH_SELF, PH_MOD_SEARCH_DOM, PH_MOD_DO_MOD} step;
struct ldb_request *orig_req;
struct ldb_request *dom_req;
- struct ldb_async_result *dom_res;
+ struct ldb_reply *dom_res;
struct ldb_request *down_req;
struct ldb_request *search_req;
- struct ldb_async_result *search_res;
+ struct ldb_reply *search_res;
struct ldb_request *mod_req;
+
+ struct dom_sid *domain_sid;
};
struct domain_data {
char *name = talloc_strdup(msg, samAccountName);
char *saltbody;
if (name == NULL) {
- ldb_set_errstring(module->ldb,
- talloc_asprintf(msg, "password_hash_handle: "
- "generation of new kerberos keys failed: %s is a computer without a samAccountName",
- ldb_dn_linearize(msg, msg->dn)));
+ ldb_asprintf_errstring(module->ldb,
+ "password_hash_handle: "
+ "generation of new kerberos keys failed: %s is a computer without a samAccountName",
+ ldb_dn_linearize(msg, msg->dn));
return LDB_ERR_OPERATIONS_ERROR;
}
if (name[strlen(name)-1] == '$') {
}
} else {
if (!samAccountName) {
- ldb_set_errstring(module->ldb,
- talloc_asprintf(msg, "password_hash_handle: "
- "generation of new kerberos keys failed: %s has no samAccountName",
- ldb_dn_linearize(msg, msg->dn)));
+ ldb_asprintf_errstring(module->ldb,
+ "password_hash_handle: "
+ "generation of new kerberos keys failed: %s has no samAccountName",
+ ldb_dn_linearize(msg, msg->dn));
return LDB_ERR_OPERATIONS_ERROR;
}
krb5_ret = krb5_make_principal(smb_krb5_context->krb5_context,
}
if (krb5_ret) {
- ldb_set_errstring(module->ldb,
- talloc_asprintf(msg, "password_hash_handle: "
- "generation of a saltking principal failed: %s",
- smb_get_krb5_error_message(smb_krb5_context->krb5_context,
- krb5_ret, msg)));
+ ldb_asprintf_errstring(module->ldb,
+ "password_hash_handle: "
+ "generation of a saltking principal failed: %s",
+ smb_get_krb5_error_message(smb_krb5_context->krb5_context, krb5_ret, msg));
return LDB_ERR_OPERATIONS_ERROR;
}
krb5_free_principal(smb_krb5_context->krb5_context, salt_principal);
if (krb5_ret) {
- ldb_set_errstring(module->ldb,
- talloc_asprintf(msg, "password_hash_handle: "
- "generation of new kerberos keys failed: %s",
- smb_get_krb5_error_message(smb_krb5_context->krb5_context,
- krb5_ret, msg)));
+ ldb_asprintf_errstring(module->ldb,
+ "password_hash_handle: "
+ "generation of new kerberos keys failed: %s",
+ smb_get_krb5_error_message(smb_krb5_context->krb5_context, krb5_ret, msg));
return LDB_ERR_OPERATIONS_ERROR;
}
struct ldb_val val;
int ret;
- if (keys[i].key.keytype == ENCTYPE_ARCFOUR_HMAC) {
+ if (keys[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5) {
/* We might end up doing this below:
* This ensures we get the unicode
* conversion right. This should also
}
krb5_ret = krb5_keyblock_init(smb_krb5_context->krb5_context,
- ENCTYPE_ARCFOUR_HMAC,
- ntPwdHash->hash, sizeof(ntPwdHash->hash),
- &key.key);
+ ETYPE_ARCFOUR_HMAC_MD5,
+ ntPwdHash->hash, sizeof(ntPwdHash->hash),
+ &key.key);
if (krb5_ret) {
return LDB_ERR_OPERATIONS_ERROR;
}
return LDB_SUCCESS;
}
-static struct ldb_async_handle *ph_init_handle(struct ldb_request *req, struct ldb_module *module, enum ph_type type)
+static struct ldb_handle *ph_init_handle(struct ldb_request *req, struct ldb_module *module, enum ph_type type)
{
- struct ph_async_context *ac;
- struct ldb_async_handle *h;
+ struct ph_context *ac;
+ struct ldb_handle *h;
- h = talloc_zero(req, struct ldb_async_handle);
+ h = talloc_zero(req, struct ldb_handle);
if (h == NULL) {
- ldb_set_errstring(module->ldb, talloc_asprintf(module, "Out of Memory"));
+ ldb_set_errstring(module->ldb, "Out of Memory");
return NULL;
}
h->module = module;
- ac = talloc_zero(h, struct ph_async_context);
+ ac = talloc_zero(h, struct ph_context);
if (ac == NULL) {
- ldb_set_errstring(module->ldb, talloc_asprintf(module, "Out of Memory"));
+ ldb_set_errstring(module->ldb, "Out of Memory");
talloc_free(h);
return NULL;
}
return h;
}
-static int get_domain_data_callback(struct ldb_context *ldb, void *context, struct ldb_async_result *ares)
+static int get_domain_data_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
{
- struct ph_async_context *ac;
+ struct ph_context *ac;
if (!context || !ares) {
- ldb_set_errstring(ldb, talloc_asprintf(ldb, "NULL Context or Result in callback"));
+ ldb_set_errstring(ldb, "NULL Context or Result in callback");
return LDB_ERR_OPERATIONS_ERROR;
}
- ac = talloc_get_type(context, struct ph_async_context);
+ ac = talloc_get_type(context, struct ph_context);
/* we are interested only in the single reply (base search) we receive here */
if (ares->type == LDB_REPLY_ENTRY) {
if (ac->dom_res != NULL) {
- ldb_set_errstring(ldb, talloc_asprintf(ldb, "Too many results"));
+ ldb_set_errstring(ldb, "Too many results");
talloc_free(ares);
return LDB_ERR_OPERATIONS_ERROR;
}
return LDB_SUCCESS;
}
-static int build_domain_data_request(struct ph_async_context *ac,
- struct dom_sid *sid)
+static int build_domain_data_request(struct ph_context *ac)
{
/* attrs[] is returned from this function in
ac->dom_req->op.search.attrs, so it must be static, as
return LDB_ERR_OPERATIONS_ERROR;
}
ac->dom_req->operation = LDB_SEARCH;
- ac->dom_req->op.search.base = NULL;
+ ac->dom_req->op.search.base = samdb_base_dn(ac);
ac->dom_req->op.search.scope = LDB_SCOPE_SUBTREE;
- filter = talloc_asprintf(ac->dom_req, "(&(objectSid=%s)(objectClass=domain))", dom_sid_string(ac->dom_req, sid));
+ filter = talloc_asprintf(ac->dom_req, "(&(objectSid=%s)(|(objectClass=domain)(objectClass=builtinDomain)))",
+ ldap_encode_ndr_dom_sid(ac->dom_req, ac->domain_sid));
if (filter == NULL) {
ldb_debug(ac->module->ldb, LDB_DEBUG_ERROR, "Out of Memory!\n");
talloc_free(ac->dom_req);
ac->dom_req->op.search.tree = ldb_parse_tree(ac->module->ldb, filter);
if (ac->dom_req->op.search.tree == NULL) {
- ldb_set_errstring(ac->module->ldb, talloc_asprintf(ac, "Invalid search filter"));
+ ldb_set_errstring(ac->module->ldb, "Invalid search filter");
talloc_free(ac->dom_req);
return LDB_ERR_OPERATIONS_ERROR;
}
ac->dom_req->op.search.attrs = attrs;
ac->dom_req->controls = NULL;
- ac->dom_req->async.context = ac;
- ac->dom_req->async.callback = get_domain_data_callback;
- ac->dom_req->async.timeout = ac->orig_req->async.timeout;
+ ac->dom_req->context = ac;
+ ac->dom_req->callback = get_domain_data_callback;
+ ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->dom_req);
return LDB_SUCCESS;
}
-static struct domain_data *get_domain_data(struct ldb_module *module, void *mem_ctx, struct ldb_async_result *res)
+static struct domain_data *get_domain_data(struct ldb_module *module, void *ctx, struct ldb_reply *res)
{
struct domain_data *data;
const char *tmp;
+ struct ph_context *ac;
- data = talloc_zero(mem_ctx, struct domain_data);
+ ac = talloc_get_type(ctx, struct ph_context);
+
+ data = talloc_zero(ac, struct domain_data);
if (data == NULL) {
return NULL;
}
+ if (res == NULL) {
+ ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Could not find this user's domain: %s!\n", dom_sid_string(data, ac->domain_sid));
+ talloc_free(data);
+ return NULL;
+ }
+
data->pwdProperties = samdb_result_uint(res->message, "pwdProperties", 0);
data->pwdHistoryLength = samdb_result_uint(res->message, "pwdHistoryLength", 0);
tmp = ldb_msg_find_string(res->message, "dnsDomain", NULL);
ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Out of memory!\n");
return NULL;
}
- data->realm = strupper_talloc(mem_ctx, tmp);
+ data->realm = strupper_talloc(data, tmp);
if (data->realm == NULL) {
ldb_debug(module->ldb, LDB_DEBUG_ERROR, "Out of memory!\n");
return NULL;
static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
{
- struct ldb_async_handle *h;
- struct ph_async_context *ac;
- struct ldb_message_element *attribute;
- struct dom_sid *domain_sid;
+ struct ldb_handle *h;
+ struct ph_context *ac;
+ struct ldb_message_element *sambaAttr;
+ struct ldb_message_element *ntAttr;
+ struct ldb_message_element *lmAttr;
int ret;
ldb_debug(module->ldb, LDB_DEBUG_TRACE, "password_hash_add\n");
return ldb_next_request(module, req);
}
+ /* If the caller is manipulating the local passwords directly, let them pass */
+ if (ldb_dn_compare_base(module->ldb,
+ ldb_dn_explode(req, LOCAL_BASE),
+ req->op.add.message->dn) == 0) {
+ return ldb_next_request(module, req);
+ }
+
/* nobody must touch password Histories */
if (ldb_msg_find_element(req->op.add.message, "sambaNTPwdHistory") ||
ldb_msg_find_element(req->op.add.message, "sambaLMPwdHistory")) {
return LDB_ERR_UNWILLING_TO_PERFORM;
}
- /* If no part of this touches the sambaPassword, then we don't
- * need to make any changes. For password changes/set there should
- * be a 'delete' or a 'modify' on this attribute. */
- if ((attribute = ldb_msg_find_element(req->op.add.message, "sambaPassword")) == NULL ) {
+ /* If no part of this ADD touches the sambaPassword, or the NT
+ * or LM hashes, then we don't need to make any changes. */
+
+ sambaAttr = ldb_msg_find_element(req->op.mod.message, "sambaPassword");
+ ntAttr = ldb_msg_find_element(req->op.mod.message, "ntPwdHash");
+ lmAttr = ldb_msg_find_element(req->op.mod.message, "lmPwdHash");
+
+ if ((!sambaAttr) && (!ntAttr) && (!lmAttr)) {
return ldb_next_request(module, req);
}
/* if it is not an entry of type person its an error */
/* TODO: remove this when sambaPassword will be in schema */
if (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "person")) {
+ ldb_set_errstring(module->ldb, "Cannot set a password on entry that does not have objectClass 'person'");
return LDB_ERR_OBJECT_CLASS_VIOLATION;
}
/* check sambaPassword is single valued here */
/* TODO: remove this when sambaPassword will be single valued in schema */
- if (attribute->num_values > 1) {
- ldb_set_errstring(module->ldb, talloc_asprintf(req,
- "mupltiple values for sambaPassword not allowed!\n"));
+ if (sambaAttr && sambaAttr->num_values > 1) {
+ ldb_set_errstring(module->ldb, "mupltiple values for sambaPassword not allowed!\n");
return LDB_ERR_CONSTRAINT_VIOLATION;
}
- /* get user domain data */
- domain_sid = samdb_result_sid_prefix(req, req->op.add.message, "objectSid");
- if (domain_sid == NULL) {
- ldb_debug(module->ldb, LDB_DEBUG_ERROR, "can't handle entry with missing objectSid!\n");
- return LDB_ERR_OPERATIONS_ERROR;
+ if (ntAttr && (ntAttr->num_values > 1)) {
+ ldb_set_errstring(module->ldb, "mupltiple values for lmPwdHash not allowed!\n");
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+ if (lmAttr && (lmAttr->num_values > 1)) {
+ ldb_set_errstring(module->ldb, "mupltiple values for lmPwdHash not allowed!\n");
+ return LDB_ERR_CONSTRAINT_VIOLATION;
}
h = ph_init_handle(req, module, PH_ADD);
if (!h) {
return LDB_ERR_OPERATIONS_ERROR;
}
- ac = talloc_get_type(h->private_data, struct ph_async_context);
+ ac = talloc_get_type(h->private_data, struct ph_context);
- ret = build_domain_data_request(ac, domain_sid);
+ /* get user domain data */
+ ac->domain_sid = samdb_result_sid_prefix(ac, req->op.add.message, "objectSid");
+ if (ac->domain_sid == NULL) {
+ ldb_debug(module->ldb, LDB_DEBUG_ERROR, "can't handle entry with missing objectSid!\n");
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
+
+ ret = build_domain_data_request(ac);
if (ret != LDB_SUCCESS) {
return ret;
}
ac->step = PH_ADD_SEARCH_DOM;
- req->async.handle = h;
+ req->handle = h;
return ldb_next_request(module, ac->dom_req);
}
-static int password_hash_add_do_add(struct ldb_async_handle *h) {
+static int password_hash_add_do_add(struct ldb_handle *h) {
- struct ph_async_context *ac;
+ struct ph_context *ac;
struct domain_data *domain;
struct smb_krb5_context *smb_krb5_context;
+ struct ldb_message_element *sambaAttr;
struct ldb_message *msg;
+ int ret;
- ac = talloc_get_type(h->private_data, struct ph_async_context);
+ ac = talloc_get_type(h->private_data, struct ph_context);
domain = get_domain_data(ac->module, ac, ac->dom_res);
if (domain == NULL) {
if (ac->down_req->op.add.message == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
-
+
/* Some operations below require kerberos contexts */
if (smb_krb5_init_context(ac->down_req, &smb_krb5_context) != 0) {
return LDB_ERR_OPERATIONS_ERROR;
}
- /* we can compute new password hashes from the unicode password */
- if (add_password_hashes(ac->module, msg, 0) != LDB_SUCCESS) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- /* now add krb5 keys based on unicode password */
- if (add_krb5_keys_from_password(ac->module, msg, smb_krb5_context, domain,
- ldb_msg_find_string(msg, "samAccountName", NULL),
- ldb_msg_find_string(msg, "userPrincipalName", NULL),
- ldb_msg_check_string_attribute(msg, "objectClass", "computer")
- ) != LDB_SUCCESS) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- /* add also kr5 keys based on NT the hash */
- if (add_krb5_keys_from_NThash(ac->module, msg, smb_krb5_context) != LDB_SUCCESS) {
- return LDB_ERR_OPERATIONS_ERROR;
- }
-
- /* if both the domain properties and the user account controls do not permit
- * clear text passwords then wipe out the sambaPassword */
- if ((!(domain->pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT)) ||
- (!(ldb_msg_find_uint(msg, "userAccountControl", 0) & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED))) {
- ldb_msg_remove_attr(msg, "sambaPassword");
+ /* if we have sambaPassword in the original message add the operatio on it here */
+ sambaAttr = ldb_msg_find_element(msg, "sambaPassword");
+ if (sambaAttr) {
+ ret = add_password_hashes(ac->module, msg, 0);
+ /* we can compute new password hashes from the unicode password */
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ /* now add krb5 keys based on unicode password */
+ ret = add_krb5_keys_from_password(ac->module, msg, smb_krb5_context, domain,
+ ldb_msg_find_string(msg, "samAccountName", NULL),
+ ldb_msg_find_string(msg, "userPrincipalName", NULL),
+ ldb_msg_check_string_attribute(msg, "objectClass", "computer"));
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ /* add also kr5 keys based on NT the hash */
+ ret = add_krb5_keys_from_NThash(ac->module, msg, smb_krb5_context);
+ if (ret != LDB_SUCCESS) {
+ return ret;
+ }
+
+ /* if both the domain properties and the user account controls do not permit
+ * clear text passwords then wipe out the sambaPassword */
+ if ((!(domain->pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT)) ||
+ (!(ldb_msg_find_uint(msg, "userAccountControl", 0) & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED))) {
+ ldb_msg_remove_attr(msg, "sambaPassword");
+ }
}
/* don't touch it if a value is set. It could be an incoming samsync */
ac->step = PH_ADD_DO_ADD;
+ ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->down_req);
+
/* perform the operation */
return ldb_next_request(ac->module, ac->down_req);
}
-static int password_hash_mod_search_self(struct ldb_async_handle *h);
+static int password_hash_mod_search_self(struct ldb_handle *h);
static int password_hash_modify(struct ldb_module *module, struct ldb_request *req)
{
- struct ldb_async_handle *h;
- struct ph_async_context *ac;
+ struct ldb_handle *h;
+ struct ph_context *ac;
struct ldb_message_element *sambaAttr;
struct ldb_message_element *ntAttr;
struct ldb_message_element *lmAttr;
+ struct ldb_message *msg;
ldb_debug(module->ldb, LDB_DEBUG_TRACE, "password_hash_modify\n");
return ldb_next_request(module, req);
}
+ /* If the caller is manipulating the local passwords directly, let them pass */
+ if (ldb_dn_compare_base(module->ldb,
+ ldb_dn_explode(req, LOCAL_BASE),
+ req->op.mod.message->dn) == 0) {
+ return ldb_next_request(module, req);
+ }
+
/* nobody must touch password Histories */
if (ldb_msg_find_element(req->op.mod.message, "sambaNTPwdHistory") ||
ldb_msg_find_element(req->op.mod.message, "sambaLMPwdHistory")) {
if (!h) {
return LDB_ERR_OPERATIONS_ERROR;
}
- ac = talloc_get_type(h->private_data, struct ph_async_context);
+ ac = talloc_get_type(h->private_data, struct ph_context);
/* return or own handle to deal with this call */
- req->async.handle = h;
+ req->handle = h;
/* prepare the first operation */
ac->down_req = talloc_zero(ac, struct ldb_request);
if (ac->down_req == NULL) {
- ldb_set_errstring(module->ldb, talloc_asprintf(module->ldb, "Out of memory!"));
+ ldb_set_errstring(module->ldb, "Out of memory!");
return LDB_ERR_OPERATIONS_ERROR;
}
*(ac->down_req) = *req; /* copy the request */
/* use a new message structure so that we can modify it */
- ac->down_req->op.mod.message = ldb_msg_copy_shallow(ac->down_req, req->op.mod.message);
+ ac->down_req->op.mod.message = msg = ldb_msg_copy_shallow(ac->down_req, req->op.mod.message);
/* - remove any imodification to the password from the first commit
* we will make the real modification later */
- if (sambaAttr) ldb_msg_remove_attr(ac->down_req->op.mod.message, "sambaPassword");
- if (ntAttr) ldb_msg_remove_attr(ac->down_req->op.mod.message, "ntPwdHash");
- if (lmAttr) ldb_msg_remove_attr(ac->down_req->op.mod.message, "lmPwdHash");
+ if (sambaAttr) ldb_msg_remove_attr(msg, "sambaPassword");
+ if (ntAttr) ldb_msg_remove_attr(msg, "ntPwdHash");
+ if (lmAttr) ldb_msg_remove_attr(msg, "lmPwdHash");
/* if there was nothing else to be modify skip to next step */
- if (ac->down_req->op.mod.message->num_elements == 0) {
+ if (msg->num_elements == 0) {
talloc_free(ac->down_req);
ac->down_req = NULL;
return password_hash_mod_search_self(h);
}
- ac->down_req->async.context = NULL;
- ac->down_req->async.callback = NULL;
+ ac->down_req->context = NULL;
+ ac->down_req->callback = NULL;
ac->step = PH_MOD_DO_REQ;
+ ldb_set_timeout_from_prev_req(module->ldb, req, ac->down_req);
+
return ldb_next_request(module, ac->down_req);
}
-static int get_self_callback(struct ldb_context *ldb, void *context, struct ldb_async_result *ares)
+static int get_self_callback(struct ldb_context *ldb, void *context, struct ldb_reply *ares)
{
- struct ph_async_context *ac;
+ struct ph_context *ac;
if (!context || !ares) {
- ldb_set_errstring(ldb, talloc_asprintf(ldb, "NULL Context or Result in callback"));
+ ldb_set_errstring(ldb, "NULL Context or Result in callback");
return LDB_ERR_OPERATIONS_ERROR;
}
- ac = talloc_get_type(context, struct ph_async_context);
+ ac = talloc_get_type(context, struct ph_context);
/* we are interested only in the single reply (base search) we receive here */
if (ares->type == LDB_REPLY_ENTRY) {
if (ac->search_res != NULL) {
- ldb_set_errstring(ldb, talloc_asprintf(ldb, "Too many results"));
+ ldb_set_errstring(ldb, "Too many results");
talloc_free(ares);
return LDB_ERR_OPERATIONS_ERROR;
}
/* if it is not an entry of type person this is an error */
/* TODO: remove this when sambaPassword will be in schema */
if (!ldb_msg_check_string_attribute(ares->message, "objectClass", "person")) {
- ldb_set_errstring(ldb, talloc_asprintf(ldb, "Object class violation"));
+ ldb_set_errstring(ldb, "Object class violation");
talloc_free(ares);
return LDB_ERR_OBJECT_CLASS_VIOLATION;
}
return LDB_SUCCESS;
}
-static int password_hash_mod_search_self(struct ldb_async_handle *h) {
+static int password_hash_mod_search_self(struct ldb_handle *h) {
- struct ph_async_context *ac;
+ struct ph_context *ac;
+ static const char * const attrs[] = { "userAccountControl", "sambaLMPwdHistory",
+ "sambaNTPwdHistory",
+ "objectSid", "msDS-KeyVersionNumber",
+ "objectClass", "userPrincipalName",
+ "samAccountName",
+ "lmPwdHash", "ntPwdHash",
+ NULL };
- ac = talloc_get_type(h->private_data, struct ph_async_context);
+ ac = talloc_get_type(h->private_data, struct ph_context);
/* prepare the search operation */
ac->search_req = talloc_zero(ac, struct ldb_request);
ac->search_req->op.search.scope = LDB_SCOPE_BASE;
ac->search_req->op.search.tree = ldb_parse_tree(ac->module->ldb, NULL);
if (ac->search_req->op.search.tree == NULL) {
- ldb_set_errstring(ac->module->ldb, talloc_asprintf(ac, "Invalid search filter"));
+ ldb_set_errstring(ac->module->ldb, "Invalid search filter");
return LDB_ERR_OPERATIONS_ERROR;
}
- ac->search_req->op.search.attrs = NULL;
+ ac->search_req->op.search.attrs = attrs;
ac->search_req->controls = NULL;
- ac->search_req->async.context = ac;
- ac->search_req->async.callback = get_self_callback;
- ac->search_req->async.timeout = ac->orig_req->async.timeout;
+ ac->search_req->context = ac;
+ ac->search_req->callback = get_self_callback;
+ ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->search_req);
ac->step = PH_MOD_SEARCH_SELF;
return ldb_next_request(ac->module, ac->search_req);
}
-static int password_hash_mod_search_dom(struct ldb_async_handle *h) {
+static int password_hash_mod_search_dom(struct ldb_handle *h) {
- struct ph_async_context *ac;
- struct dom_sid *domain_sid;
+ struct ph_context *ac;
int ret;
- ac = talloc_get_type(h->private_data, struct ph_async_context);
+ ac = talloc_get_type(h->private_data, struct ph_context);
/* get object domain sid */
- domain_sid = samdb_result_sid_prefix(ac, ac->search_res->message, "objectSid");
- if (domain_sid == NULL) {
+ ac->domain_sid = samdb_result_sid_prefix(ac, ac->search_res->message, "objectSid");
+ if (ac->domain_sid == NULL) {
ldb_debug(ac->module->ldb, LDB_DEBUG_ERROR, "can't handle entry with missing objectSid!\n");
return LDB_ERR_OPERATIONS_ERROR;
}
/* get user domain data */
- ret = build_domain_data_request(ac, domain_sid);
+ ret = build_domain_data_request(ac);
if (ret != LDB_SUCCESS) {
return ret;
}
return ldb_next_request(ac->module, ac->dom_req);
}
-static int password_hash_mod_do_mod(struct ldb_async_handle *h) {
+static int password_hash_mod_do_mod(struct ldb_handle *h) {
- struct ph_async_context *ac;
+ struct ph_context *ac;
struct domain_data *domain;
struct smb_krb5_context *smb_krb5_context;
struct ldb_message_element *sambaAttr;
struct ldb_message *msg;
int phlen;
+ int ret;
+ BOOL added_hashes = False;
- ac = talloc_get_type(h->private_data, struct ph_async_context);
+ ac = talloc_get_type(h->private_data, struct ph_context);
domain = get_domain_data(ac->module, ac, ac->dom_res);
if (domain == NULL) {
return LDB_ERR_OPERATIONS_ERROR;
}
- /* if we have sambaPassword in the original message add the operatio on it here */
+ /* if we have sambaPassword in the original message add the operation on it here */
sambaAttr = ldb_msg_find_element(ac->orig_req->op.mod.message, "sambaPassword");
if (sambaAttr) {
return LDB_ERR_OPERATIONS_ERROR;
}
- /* we are not deleteing it add password hashes */
- if ((sambaAttr->flags & LDB_FLAG_MOD_MASK) != LDB_FLAG_MOD_DELETE) {
-
+ /* if we are actually settting a new unicode password,
+ * use it to generate the password hashes */
+ if (((sambaAttr->flags & LDB_FLAG_MOD_MASK) != LDB_FLAG_MOD_DELETE)
+ && (sambaAttr->num_values == 1)) {
/* we can compute new password hashes from the unicode password */
- if (add_password_hashes(ac->module, msg, 1) != LDB_SUCCESS) {
- return LDB_ERR_OPERATIONS_ERROR;
+ ret = add_password_hashes(ac->module, msg, 1);
+ if (ret != LDB_SUCCESS) {
+ return ret;
}
+ added_hashes = True;
+
/* now add krb5 keys based on unicode password */
- if (add_krb5_keys_from_password(ac->module, msg, smb_krb5_context, domain,
- ldb_msg_find_string(ac->search_res->message, "samAccountName", NULL),
- ldb_msg_find_string(ac->search_res->message, "userPrincipalName", NULL),
- ldb_msg_check_string_attribute(ac->search_res->message, "objectClass", "computer")
- ) != LDB_SUCCESS) {
- return LDB_ERR_OPERATIONS_ERROR;
+ ret = add_krb5_keys_from_password(ac->module, msg, smb_krb5_context, domain,
+ ldb_msg_find_string(ac->search_res->message, "samAccountName", NULL),
+ ldb_msg_find_string(ac->search_res->message, "userPrincipalName", NULL),
+ ldb_msg_check_string_attribute(ac->search_res->message, "objectClass", "computer"));
+
+ if (ret != LDB_SUCCESS) {
+ return ret;
}
/* if the domain properties or the user account controls do not permit
}
}
- /* if we don't have sambaPassword or we are trying to delete it try with nt or lm hasehs */
- if ((!sambaAttr) || ((sambaAttr->flags & LDB_FLAG_MOD_MASK) == LDB_FLAG_MOD_DELETE)) {
+ /* if we didn't create the hashes above, try using values supplied directly */
+ if (!added_hashes) {
struct ldb_message_element *el;
el = ldb_msg_find_element(ac->orig_req->op.mod.message, "ntPwdHash");
}
}
- /* add also kr5 keys based on NT the hash */
+ /* add also krb5 keys based on NT the hash */
if (add_krb5_keys_from_NThash(ac->module, msg, smb_krb5_context) != LDB_SUCCESS) {
return LDB_ERR_OPERATIONS_ERROR;
}
}
/* don't touch it if a value is set. It could be an incoming samsync */
- if (add_keyVersionNumber(ac->module, msg,
- ldb_msg_find_uint(msg, "msDS-KeyVersionNumber", 0)
- ) != LDB_SUCCESS) {
- return LDB_ERR_OPERATIONS_ERROR;
+ if (!ldb_msg_find_element(ac->orig_req->op.mod.message,
+ "msDS-KeyVersionNumber")) {
+ if (add_keyVersionNumber(ac->module, msg,
+ ldb_msg_find_uint(ac->search_res->message,
+ "msDS-KeyVersionNumber", 0)
+ ) != LDB_SUCCESS) {
+ return LDB_ERR_OPERATIONS_ERROR;
+ }
}
if ((phlen = samdb_result_uint(ac->dom_res->message, "pwdHistoryLength", 0)) > 0) {
ac->step = PH_MOD_DO_MOD;
+ ldb_set_timeout_from_prev_req(ac->module->ldb, ac->orig_req, ac->mod_req);
+
/* perform the search */
return ldb_next_request(ac->module, ac->mod_req);
}
-static int ph_async_wait(struct ldb_async_handle *handle) {
- struct ph_async_context *ac;
+static int ph_wait(struct ldb_handle *handle) {
+ struct ph_context *ac;
int ret;
if (!handle || !handle->private_data) {
handle->state = LDB_ASYNC_PENDING;
handle->status = LDB_SUCCESS;
- ac = talloc_get_type(handle->private_data, struct ph_async_context);
+ ac = talloc_get_type(handle->private_data, struct ph_context);
switch (ac->step) {
case PH_ADD_SEARCH_DOM:
- ret = ldb_async_wait(ac->dom_req->async.handle, LDB_WAIT_NONE);
+ ret = ldb_wait(ac->dom_req->handle, LDB_WAIT_NONE);
if (ret != LDB_SUCCESS) {
handle->status = ret;
goto done;
}
- if (ac->dom_req->async.handle->status != LDB_SUCCESS) {
- handle->status = ac->dom_req->async.handle->status;
+ if (ac->dom_req->handle->status != LDB_SUCCESS) {
+ handle->status = ac->dom_req->handle->status;
goto done;
}
- if (ac->dom_req->async.handle->state != LDB_ASYNC_DONE) {
+ if (ac->dom_req->handle->state != LDB_ASYNC_DONE) {
return LDB_SUCCESS;
}
return password_hash_add_do_add(handle);
case PH_ADD_DO_ADD:
- ret = ldb_async_wait(ac->down_req->async.handle, LDB_WAIT_NONE);
+ ret = ldb_wait(ac->down_req->handle, LDB_WAIT_NONE);
if (ret != LDB_SUCCESS) {
handle->status = ret;
goto done;
}
- if (ac->down_req->async.handle->status != LDB_SUCCESS) {
- handle->status = ac->down_req->async.handle->status;
+ if (ac->down_req->handle->status != LDB_SUCCESS) {
+ handle->status = ac->down_req->handle->status;
goto done;
}
- if (ac->down_req->async.handle->state != LDB_ASYNC_DONE) {
+ if (ac->down_req->handle->state != LDB_ASYNC_DONE) {
return LDB_SUCCESS;
}
break;
case PH_MOD_DO_REQ:
- ret = ldb_async_wait(ac->down_req->async.handle, LDB_WAIT_NONE);
+ ret = ldb_wait(ac->down_req->handle, LDB_WAIT_NONE);
if (ret != LDB_SUCCESS) {
handle->status = ret;
goto done;
}
- if (ac->down_req->async.handle->status != LDB_SUCCESS) {
- handle->status = ac->down_req->async.handle->status;
+ if (ac->down_req->handle->status != LDB_SUCCESS) {
+ handle->status = ac->down_req->handle->status;
goto done;
}
- if (ac->down_req->async.handle->state != LDB_ASYNC_DONE) {
+ if (ac->down_req->handle->state != LDB_ASYNC_DONE) {
return LDB_SUCCESS;
}
return password_hash_mod_search_self(handle);
case PH_MOD_SEARCH_SELF:
- ret = ldb_async_wait(ac->search_req->async.handle, LDB_WAIT_NONE);
+ ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE);
if (ret != LDB_SUCCESS) {
handle->status = ret;
goto done;
}
- if (ac->search_req->async.handle->status != LDB_SUCCESS) {
- handle->status = ac->search_req->async.handle->status;
+ if (ac->search_req->handle->status != LDB_SUCCESS) {
+ handle->status = ac->search_req->handle->status;
goto done;
}
- if (ac->search_req->async.handle->state != LDB_ASYNC_DONE) {
+ if (ac->search_req->handle->state != LDB_ASYNC_DONE) {
return LDB_SUCCESS;
}
return password_hash_mod_search_dom(handle);
case PH_MOD_SEARCH_DOM:
- ret = ldb_async_wait(ac->dom_req->async.handle, LDB_WAIT_NONE);
+ ret = ldb_wait(ac->dom_req->handle, LDB_WAIT_NONE);
if (ret != LDB_SUCCESS) {
handle->status = ret;
goto done;
}
- if (ac->dom_req->async.handle->status != LDB_SUCCESS) {
- handle->status = ac->dom_req->async.handle->status;
+ if (ac->dom_req->handle->status != LDB_SUCCESS) {
+ handle->status = ac->dom_req->handle->status;
goto done;
}
- if (ac->dom_req->async.handle->state != LDB_ASYNC_DONE) {
+ if (ac->dom_req->handle->state != LDB_ASYNC_DONE) {
return LDB_SUCCESS;
}
return password_hash_mod_do_mod(handle);
case PH_MOD_DO_MOD:
- ret = ldb_async_wait(ac->mod_req->async.handle, LDB_WAIT_NONE);
+ ret = ldb_wait(ac->mod_req->handle, LDB_WAIT_NONE);
if (ret != LDB_SUCCESS) {
handle->status = ret;
goto done;
}
- if (ac->mod_req->async.handle->status != LDB_SUCCESS) {
- handle->status = ac->mod_req->async.handle->status;
+ if (ac->mod_req->handle->status != LDB_SUCCESS) {
+ handle->status = ac->mod_req->handle->status;
goto done;
}
- if (ac->mod_req->async.handle->state != LDB_ASYNC_DONE) {
+ if (ac->mod_req->handle->state != LDB_ASYNC_DONE) {
return LDB_SUCCESS;
}
return ret;
}
-static int ph_async_wait_all(struct ldb_async_handle *handle) {
+static int ph_wait_all(struct ldb_handle *handle) {
int ret;
while (handle->state != LDB_ASYNC_DONE) {
- ret = ph_async_wait(handle);
+ ret = ph_wait(handle);
if (ret != LDB_SUCCESS) {
return ret;
}
return handle->status;
}
-static int password_hash_async_wait(struct ldb_async_handle *handle, enum ldb_async_wait_type type)
+static int password_hash_wait(struct ldb_handle *handle, enum ldb_wait_type type)
{
if (type == LDB_WAIT_ALL) {
- return ph_async_wait_all(handle);
+ return ph_wait_all(handle);
} else {
- return ph_async_wait(handle);
+ return ph_wait(handle);
}
}
.name = "password_hash",
.add = password_hash_add,
.modify = password_hash_modify,
- .async_wait = password_hash_async_wait
+ .wait = password_hash_wait
};