📄 password_hash.c
字号:
static int password_hash_modify(struct ldb_module *module, struct ldb_request *req){ 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"); if (ldb_dn_is_special(req->op.mod.message->dn)) { /* do not manipulate our control entries */ return ldb_next_request(module, req); } /* If the caller is manipulating the local passwords directly, let them pass */ if (ldb_dn_compare_base(ldb_dn_new(req, module->ldb, 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.add.message, "ntPwdHistory")) { return LDB_ERR_UNWILLING_TO_PERFORM; } if (ldb_msg_find_element(req->op.add.message, "lmPwdHistory")) { return LDB_ERR_UNWILLING_TO_PERFORM; } if (ldb_msg_find_element(req->op.add.message, "supplementalCredentials")) { return LDB_ERR_UNWILLING_TO_PERFORM; } sambaAttr = ldb_msg_find_element(req->op.mod.message, "sambaPassword"); ntAttr = ldb_msg_find_element(req->op.mod.message, "unicodePwd"); lmAttr = ldb_msg_find_element(req->op.mod.message, "dBCSPwd"); /* If no part of this touches the sambaPassword OR unicodePwd and/or dBCSPwd, 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 ((!sambaAttr) && (!ntAttr) && (!lmAttr)) { return ldb_next_request(module, req); } /* check passwords are single valued here */ /* TODO: remove this when passwords will be single valued in schema */ if (sambaAttr && (sambaAttr->num_values > 1)) { return LDB_ERR_CONSTRAINT_VIOLATION; } if (ntAttr && (ntAttr->num_values > 1)) { return LDB_ERR_CONSTRAINT_VIOLATION; } if (lmAttr && (lmAttr->num_values > 1)) { return LDB_ERR_CONSTRAINT_VIOLATION; } h = ph_init_handle(req, module, PH_MOD); if (!h) { return LDB_ERR_OPERATIONS_ERROR; } ac = talloc_get_type(h->private_data, struct ph_context); /* return or own handle to deal with this call */ 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, "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 = 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(msg, "sambaPassword"); if (ntAttr) ldb_msg_remove_attr(msg, "unicodePwd"); if (lmAttr) ldb_msg_remove_attr(msg, "dBCSPwd"); /* if there was nothing else to be modify skip to next step */ if (msg->num_elements == 0) { talloc_free(ac->down_req); ac->down_req = NULL; return password_hash_mod_search_self(h); } 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_reply *ares){ struct ph_context *ac; 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, "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, "Object class violation"); talloc_free(ares); return LDB_ERR_OBJECT_CLASS_VIOLATION; } ac->search_res = talloc_steal(ac, ares); } else { talloc_free(ares); } return LDB_SUCCESS;}static int password_hash_mod_search_self(struct ldb_handle *h) { struct ph_context *ac; static const char * const attrs[] = { "userAccountControl", "lmPwdHistory", "ntPwdHistory", "objectSid", "msDS-KeyVersionNumber", "objectClass", "userPrincipalName", "sAMAccountName", "dBCSPwd", "unicodePwd", "supplementalCredentials", NULL }; ac = talloc_get_type(h->private_data, struct ph_context); /* prepare the search operation */ ac->search_req = talloc_zero(ac, struct ldb_request); if (ac->search_req == NULL) { ldb_debug(ac->module->ldb, LDB_DEBUG_ERROR, "Out of Memory!\n"); return LDB_ERR_OPERATIONS_ERROR; } ac->search_req->operation = LDB_SEARCH; ac->search_req->op.search.base = ac->orig_req->op.mod.message->dn; ac->search_req->op.search.scope = LDB_SCOPE_BASE; ac->search_req->op.search.tree = ldb_parse_tree(ac->search_req, NULL); if (ac->search_req->op.search.tree == NULL) { ldb_set_errstring(ac->module->ldb, "Invalid search filter"); return LDB_ERR_OPERATIONS_ERROR; } ac->search_req->op.search.attrs = attrs; ac->search_req->controls = NULL; 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_handle *h) { struct ph_context *ac; int ret; ac = talloc_get_type(h->private_data, struct ph_context); /* get object domain sid */ 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); if (ret != LDB_SUCCESS) { return ret; } ac->step = PH_MOD_SEARCH_DOM; return ldb_next_request(ac->module, ac->dom_req);}static int password_hash_mod_do_mod(struct ldb_handle *h) { struct ph_context *ac; struct domain_data *domain; struct smb_krb5_context *smb_krb5_context; struct ldb_message *msg; struct ldb_message *orig_msg; struct ldb_message *searched_msg; struct setup_password_fields_io io; int ret; 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; } ac->mod_req = talloc(ac, struct ldb_request); if (ac->mod_req == NULL) { return LDB_ERR_OPERATIONS_ERROR; } *(ac->mod_req) = *(ac->orig_req); /* use a new message structure so that we can modify it */ ac->mod_req->op.mod.message = msg = ldb_msg_new(ac->mod_req); if (msg == NULL) { return LDB_ERR_OPERATIONS_ERROR; } /* modify dn */ msg->dn = ac->orig_req->op.mod.message->dn; /* Some operations below require kerberos contexts */ if (smb_krb5_init_context(ac->mod_req, ldb_get_opaque(h->module->ldb, "EventContext"), (struct loadparm_context *)ldb_get_opaque(h->module->ldb, "loadparm"), &smb_krb5_context) != 0) { return LDB_ERR_OPERATIONS_ERROR; } orig_msg = discard_const(ac->orig_req->op.mod.message); searched_msg = ac->search_res->message; ZERO_STRUCT(io); io.ac = ac; io.domain = domain; io.smb_krb5_context = smb_krb5_context; io.u.user_account_control = samdb_result_uint(searched_msg, "userAccountControl", 0); io.u.sAMAccountName = samdb_result_string(searched_msg, "samAccountName", NULL); io.u.user_principal_name = samdb_result_string(searched_msg, "userPrincipalName", NULL); io.u.is_computer = ldb_msg_check_string_attribute(searched_msg, "objectClass", "computer"); io.n.cleartext = samdb_result_string(orig_msg, "sambaPassword", NULL); io.n.nt_hash = samdb_result_hash(io.ac, orig_msg, "unicodePwd"); io.n.lm_hash = samdb_result_hash(io.ac, orig_msg, "dBCSPwd"); io.o.kvno = samdb_result_uint(searched_msg, "msDs-KeyVersionNumber", 0); io.o.nt_history_len = samdb_result_hashes(io.ac, searched_msg, "ntPwdHistory", &io.o.nt_history); io.o.lm_history_len = samdb_result_hashes(io.ac, searched_msg, "lmPwdHistory", &io.o.lm_history); io.o.supplemental = ldb_msg_find_ldb_val(searched_msg, "supplementalCredentials"); ret = setup_password_fields(&io); if (ret != LDB_SUCCESS) { return ret; } /* make sure we replace all the old attributes */ ret = ldb_msg_add_empty(msg, "unicodePwd", LDB_FLAG_MOD_REPLACE, NULL); ret = ldb_msg_add_empty(msg, "dBCSPwd", LDB_FLAG_MOD_REPLACE, NULL); ret = ldb_msg_add_empty(msg, "ntPwdHistory", LDB_FLAG_MOD_REPLACE, NULL); ret = ldb_msg_add_empty(msg, "lmPwdHistory", LDB_FLAG_MOD_REPLACE, NULL); ret = ldb_msg_add_empty(msg, "supplementalCredentials", LDB_FLAG_MOD_REPLACE, NULL); ret = ldb_msg_add_empty(msg, "pwdLastSet", LDB_FLAG_MOD_REPLACE, NULL); ret = ldb_msg_add_empty(msg, "msDs-KeyVersionNumber", LDB_FLAG_MOD_REPLACE, NULL); if (io.g.nt_hash) { ret = samdb_msg_add_hash(ac->module->ldb, ac, msg, "unicodePwd", io.g.nt_hash); if (ret != LDB_SUCCESS) { return ret; } } if (io.g.lm_hash) { ret = samdb_msg_add_hash(ac->module->ldb, ac, msg, "dBCSPwd", io.g.lm_hash); if (ret != LDB_SUCCESS) { return ret; } } if (io.g.nt_history_len > 0) { ret = samdb_msg_add_hashes(ac, msg, "ntPwdHistory", io.g.nt_history, io.g.nt_history_len); if (ret != LDB_SUCCESS) { return ret; } } if (io.g.lm_history_len > 0) { ret = samdb_msg_add_hashes(ac, msg, "lmPwdHistory", io.g.lm_history, io.g.lm_history_len); if (ret != LDB_SUCCESS) { return ret; } } if (io.g.supplemental.length > 0) { ret = ldb_msg_add_value(msg, "supplementalCredentials", &io.g.supplemental, NULL); if (ret != LDB_SUCCESS) { return ret; } } ret = samdb_msg_add_uint64(ac->module->ldb, ac, msg, "pwdLastSet", io.g.last_set); if (ret != LDB_SUCCESS) { return ret; } ret = samdb_msg_add_uint(ac->module->ldb, ac, msg, "msDs-KeyVersionNumber", io.g.kvno); if (ret != LDB_SUCCESS) { return ret; } h->state = LDB_ASYNC_INIT; h->status = LDB_SUCCESS; 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_wait(struct ldb_handle *handle) { struct ph_context *ac; int ret; if (!handle || !handle->private_data) { return LDB_ERR_OPERATIONS_ERROR; } if (handle->state == LDB_ASYNC_DONE) { return handle->status; } handle->state = LDB_ASYNC_PENDING; handle->status = LDB_SUCCESS; ac = talloc_get_type(handle->private_data, struct ph_context); switch (ac->step) { case PH_ADD_SEARCH_DOM: ret = ldb_wait(ac->dom_req->handle, LDB_WAIT_NONE); if (ret != LDB_SUCCESS) { handle->status = ret; goto done; } if (ac->dom_req->handle->status != LDB_SUCCESS) { handle->status = ac->dom_req->handle->status; goto done; } if (ac->dom_req->handle->state != LDB_ASYNC_DONE) { return LDB_SUCCESS; } /* domain search done, go on */ return password_hash_add_do_add(handle); case PH_ADD_DO_ADD: ret = ldb_wait(ac->down_req->handle, LDB_WAIT_NONE); if (ret != LDB_SUCCESS) { handle->status = ret; goto done; } if (ac->down_req->handle->status != LDB_SUCCESS) { handle->status = ac->down_req->handle->status; goto done; } if (ac->down_req->handle->state != LDB_ASYNC_DONE) { return LDB_SUCCESS; } break; case PH_MOD_DO_REQ: ret = ldb_wait(ac->down_req->handle, LDB_WAIT_NONE); if (ret != LDB_SUCCESS) { handle->status = ret; goto done; } if (ac->down_req->handle->status != LDB_SUCCESS) { handle->status = ac->down_req->handle->status; goto done; } if (ac->down_req->handle->state != LDB_ASYNC_DONE) { return LDB_SUCCESS; } /* non-password mods done, go on */ return password_hash_mod_search_self(handle); case PH_MOD_SEARCH_SELF: ret = ldb_wait(ac->search_req->handle, LDB_WAIT_NONE); if (ret != LDB_SUCCESS) { handle->status = ret; goto done; } if (ac->search_req->handle->status != LDB_SUCCESS) { handle->status = ac->search_req->handle->status; goto done; } if (ac->search_req->handle->state != LDB_ASYNC_DONE) { return LDB_SUCCESS; } if (ac->search_res == NULL) { return LDB_ERR_NO_SUCH_OBJECT; } /* self search done, go on */ return password_hash_mod_search_dom(handle); case PH_MOD_SEARCH_DOM: ret = ldb_wait(ac->dom_req->handle, LDB_WAIT_NONE); if (ret != LDB_SUCCESS) { handle->status = ret; goto done; } if (ac->dom_req->handle->status != LDB_SUCCESS) { handle->status = ac->dom_req->handle->status; goto done; } if (ac->dom_req->handle->state != LDB_ASYNC_DONE) { return LDB_SUCCESS; } /* domain search done, go on */ return password_hash_mod_do_mod(handle); case PH_MOD_DO_MOD: ret = ldb_wait(ac->mod_req->handle, LDB_WAIT_NONE); if (ret != LDB_SUCCESS) { handle->status = ret; goto done; } if (ac->mod_req->handle->status != LDB_SUCCESS) { handle->status = ac->mod_req->handle->status; goto done; } if (ac->mod_req->handle->state != LDB_ASYNC_DONE) { return LDB_SUCCESS; } break; default: ret = LDB_ERR_OPERATIONS_ERROR; goto done; } ret = LDB_SUCCESS;done: handle->state = LDB_ASYNC_DONE; return ret;}static int ph_wait_all(struct ldb_handle *handle) { int ret; while (handle->state != LDB_ASYNC_DONE) { ret = ph_wait(handle); if (ret != LDB_SUCCESS) { return ret; } } return handle->status;}static int password_hash_wait(struct ldb_handle *handle, enum ldb_wait_type type){ if (type == LDB_WAIT_ALL) { return ph_wait_all(handle); } else { return ph_wait(handle); }}_PUBLIC_ const struct ldb_module_ops ldb_password_hash_module_ops = { .name = "password_hash", .add = password_hash_add, .modify = password_hash_modify, .wait = password_hash_wait};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -