summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source4/dsdb/samdb/ldb_modules/password_hash.c172
1 files changed, 106 insertions, 66 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/password_hash.c b/source4/dsdb/samdb/ldb_modules/password_hash.c
index 2466aac423..a4816f13db 100644
--- a/source4/dsdb/samdb/ldb_modules/password_hash.c
+++ b/source4/dsdb/samdb/ldb_modules/password_hash.c
@@ -82,6 +82,8 @@ struct ph_async_context {
struct ldb_async_result *search_res;
struct ldb_request *mod_req;
+
+ struct dom_sid *domain_sid;
};
struct domain_data {
@@ -474,8 +476,7 @@ static int get_domain_data_callback(struct ldb_context *ldb, void *context, stru
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_async_context *ac)
{
/* attrs[] is returned from this function in
ac->dom_req->op.search.attrs, so it must be static, as
@@ -492,8 +493,8 @@ static int build_domain_data_request(struct ph_async_context *ac,
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))",
- ldap_encode_ndr_dom_sid(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);
@@ -516,18 +517,21 @@ static int build_domain_data_request(struct ph_async_context *ac,
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_async_result *res)
{
struct domain_data *data;
const char *tmp;
+ struct ph_async_context *ac;
- data = talloc_zero(mem_ctx, struct domain_data);
+ ac = talloc_get_type(ctx, struct ph_async_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!\n");
+ 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;
}
@@ -542,7 +546,7 @@ static struct domain_data *get_domain_data(struct ldb_module *module, void *mem_
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;
@@ -556,8 +560,9 @@ 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_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");
@@ -572,10 +577,14 @@ static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
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);
}
@@ -588,16 +597,31 @@ static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
/* check sambaPassword is single valued here */
/* TODO: remove this when sambaPassword will be single valued in schema */
- if (attribute->num_values > 1) {
+ if (sambaAttr->num_values > 1) {
ldb_set_errstring(module->ldb,
talloc_asprintf(req,
"mupltiple values for sambaPassword not allowed!\n"));
return LDB_ERR_CONSTRAINT_VIOLATION;
}
+ if (ntAttr && (ntAttr->num_values > 1)) {
+ ldb_set_errstring(module->ldb,
+ talloc_asprintf(req,
+ "mupltiple values for lmPwdHash not allowed!\n"));
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+ if (lmAttr && (lmAttr->num_values > 1)) {
+ ldb_set_errstring(module->ldb,
+ talloc_asprintf(req,
+ "mupltiple values for lmPwdHash not allowed!\n"));
+ return LDB_ERR_CONSTRAINT_VIOLATION;
+ }
+
+ ac = talloc_get_type(h->private_data, struct ph_async_context);
+
/* get user domain data */
- domain_sid = samdb_result_sid_prefix(req, req->op.add.message, "objectSid");
- if (domain_sid == NULL) {
+ 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;
}
@@ -606,9 +630,7 @@ static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
if (!h) {
return LDB_ERR_OPERATIONS_ERROR;
}
- ac = talloc_get_type(h->private_data, struct ph_async_context);
-
- ret = build_domain_data_request(ac, domain_sid);
+ ret = build_domain_data_request(ac);
if (ret != LDB_SUCCESS) {
return ret;
}
@@ -625,7 +647,9 @@ static int password_hash_add_do_add(struct ldb_async_handle *h) {
struct ph_async_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);
@@ -650,30 +674,36 @@ static int password_hash_add_do_add(struct ldb_async_handle *h) {
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 */
@@ -871,20 +901,19 @@ static int password_hash_mod_search_self(struct ldb_async_handle *h) {
static int password_hash_mod_search_dom(struct ldb_async_handle *h) {
struct ph_async_context *ac;
- struct dom_sid *domain_sid;
int ret;
ac = talloc_get_type(h->private_data, struct ph_async_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;
}
@@ -902,6 +931,8 @@ static int password_hash_mod_do_mod(struct ldb_async_handle *h) {
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);
@@ -936,7 +967,7 @@ static int password_hash_mod_do_mod(struct ldb_async_handle *h) {
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) {
@@ -944,21 +975,26 @@ static int password_hash_mod_do_mod(struct ldb_async_handle *h) {
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
@@ -971,8 +1007,8 @@ static int password_hash_mod_do_mod(struct ldb_async_handle *h) {
}
}
- /* 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");
@@ -997,10 +1033,14 @@ static int password_hash_mod_do_mod(struct ldb_async_handle *h) {
}
/* 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) {