1
0
mirror of https://github.com/samba-team/samba.git synced 2025-03-08 04:58:40 +03:00

s4:password_hash - Rework unique value checks

Windows Server performs the constraint checks in a different way than we do.
All testing has been done using "passwords.py".
This commit is contained in:
Matthias Dieter Wallnöfer 2009-10-23 12:51:47 +02:00 committed by Stefan Metzmacher
parent 3ce4a0c5f2
commit 12c4b09fd5

View File

@ -1748,23 +1748,6 @@ static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
return ldb_next_request(module, req);
}
if (userPasswordAttr && (userPasswordAttr->num_values != 1)) {
ldb_set_errstring(ldb, "'userPassword' must have exactly one value!");
return LDB_ERR_CONSTRAINT_VIOLATION;
}
if (clearTextPasswordAttr && (clearTextPasswordAttr->num_values != 1)) {
ldb_set_errstring(ldb, "'clearTextPassword' must have exactly one value!");
return LDB_ERR_CONSTRAINT_VIOLATION;
}
if (ntAttr && (ntAttr->num_values != 1)) {
ldb_set_errstring(ldb, "'unicodePwd' must have exactly one value!");
return LDB_ERR_CONSTRAINT_VIOLATION;
}
if (lmAttr && (lmAttr->num_values != 1)) {
ldb_set_errstring(ldb, "'dBCSPwd' must have exactly one value!");
return LDB_ERR_CONSTRAINT_VIOLATION;
}
/* Make sure we are performing the password set action on a (for us)
* valid object. Those are instances of either "user" and/or
* "inetOrgPerson". Otherwise continue with the submodules. */
@ -1890,8 +1873,10 @@ static int password_hash_modify(struct ldb_module *module, struct ldb_request *r
{
struct ldb_context *ldb;
struct ph_context *ac;
struct ldb_message_element *userPasswordAttr, *clearTextPasswordAttr,
*ntAttr, *lmAttr;
const char *passwordAttrs[] = { "userPassword", "clearTextPassword",
"unicodePwd", "dBCSPwd", NULL }, **l;
unsigned int attr_cnt, del_attr_cnt, add_attr_cnt, rep_attr_cnt;
struct ldb_message_element *passwordAttr;
struct ldb_message *msg;
struct ldb_request *down_req;
int ret;
@ -1925,33 +1910,16 @@ static int password_hash_modify(struct ldb_module *module, struct ldb_request *r
* OR 'unicodePwd' OR 'dBCSPwd' we don't need to make any changes.
* For password changes/set there should be a 'delete' or a 'modify'
* on these attributes. */
userPasswordAttr = ldb_msg_find_element(req->op.mod.message, "userPassword");
clearTextPasswordAttr = ldb_msg_find_element(req->op.mod.message, "clearTextPassword");
ntAttr = ldb_msg_find_element(req->op.mod.message, "unicodePwd");
lmAttr = ldb_msg_find_element(req->op.mod.message, "dBCSPwd");
if ((!userPasswordAttr) && (!clearTextPasswordAttr) && (!ntAttr) && (!lmAttr)) {
attr_cnt = 0;
for (l = passwordAttrs; *l != NULL; l++) {
if (ldb_msg_find_element(req->op.mod.message, *l) != NULL) {
++attr_cnt;
}
}
if (attr_cnt == 0) {
return ldb_next_request(module, req);
}
if (userPasswordAttr && (userPasswordAttr->num_values != 1)) {
ldb_set_errstring(ldb, "'userPassword' must have exactly one value!");
return LDB_ERR_CONSTRAINT_VIOLATION;
}
if (clearTextPasswordAttr && (clearTextPasswordAttr->num_values != 1)) {
ldb_set_errstring(ldb, "'clearTextPassword' must have exactly one value!");
return LDB_ERR_CONSTRAINT_VIOLATION;
}
if (ntAttr && (ntAttr->num_values != 1)) {
ldb_set_errstring(ldb, "'unicodePwd' must have exactly one value!");
return LDB_ERR_CONSTRAINT_VIOLATION;
}
if (lmAttr && (lmAttr->num_values != 1)) {
ldb_set_errstring(ldb, "'dBCSPwd' must have exactly one value!");
return LDB_ERR_CONSTRAINT_VIOLATION;
}
ac = ph_init_context(module, req);
if (!ac) {
DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
@ -1965,12 +1933,66 @@ static int password_hash_modify(struct ldb_module *module, struct ldb_request *r
return LDB_ERR_OPERATIONS_ERROR;
}
/* - remove any modification to the password from the first commit
* we will make the real modification later */
if (userPasswordAttr) ldb_msg_remove_attr(msg, "userPassword");
if (clearTextPasswordAttr) ldb_msg_remove_attr(msg, "clearTextPassword");
if (ntAttr) ldb_msg_remove_attr(msg, "unicodePwd");
if (lmAttr) ldb_msg_remove_attr(msg, "dBCSPwd");
/* - check for single-valued password attributes
* (if not return "CONSTRAINT_VIOLATION")
* - check that for a password change operation one add and one delete
* operation exists
* (if not return "CONSTRAINT_VIOLATION" or "UNWILLING_TO_PERFORM")
* - check that a password change and a password set operation cannot
* be mixed
* (if not return "UNWILLING_TO_PERFORM")
* - remove all password attributes modifications from the first change
* operation (anything without the passwords) - we will make the real
* modification later */
del_attr_cnt = 0;
add_attr_cnt = 0;
rep_attr_cnt = 0;
for (l = passwordAttrs; *l != NULL; l++) {
while ((passwordAttr = ldb_msg_find_element(msg, *l)) != NULL) {
if (passwordAttr->flags == LDB_FLAG_MOD_DELETE) {
++del_attr_cnt;
}
if (passwordAttr->flags == LDB_FLAG_MOD_ADD) {
++add_attr_cnt;
}
if (passwordAttr->flags == LDB_FLAG_MOD_REPLACE) {
++rep_attr_cnt;
}
if ((passwordAttr->num_values != 1) &&
(passwordAttr->flags != LDB_FLAG_MOD_REPLACE)) {
talloc_free(ac);
ldb_asprintf_errstring(ldb,
"'%s' attributes must have exactly one value!",
*l);
return LDB_ERR_CONSTRAINT_VIOLATION;
}
ldb_msg_remove_attr(msg, *l);
}
}
if ((del_attr_cnt > 0) && (add_attr_cnt == 0)) {
talloc_free(ac);
ldb_set_errstring(ldb,
"Only the delete action for a password change specified!");
return LDB_ERR_CONSTRAINT_VIOLATION;
}
if ((del_attr_cnt == 0) && (add_attr_cnt > 0)) {
talloc_free(ac);
ldb_set_errstring(ldb,
"Only the add action for a password change specified!");
return LDB_ERR_UNWILLING_TO_PERFORM;
}
if ((del_attr_cnt > 1) || (add_attr_cnt > 1)) {
talloc_free(ac);
ldb_set_errstring(ldb,
"Only one delete and one add action for a password change allowed!");
return LDB_ERR_UNWILLING_TO_PERFORM;
}
if ((rep_attr_cnt > 0) && ((del_attr_cnt > 0) || (add_attr_cnt > 0))) {
talloc_free(ac);
ldb_set_errstring(ldb,
"Either a password change or a password set operation is allowed!");
return LDB_ERR_UNWILLING_TO_PERFORM;
}
/* if there was nothing else to be modified skip to next step */
if (msg->num_elements == 0) {