From: Stefan Metzmacher Date: Wed, 1 Jun 2016 09:13:47 +0000 (+0200) Subject: s4:dsdb/samldb: pwdLastSet = -1 requires Unexpire-Password right X-Git-Tag: tdb-1.3.10~658 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f77c82d950688ff73f7454da9098fdc384179270;p=thirdparty%2Fsamba.git s4:dsdb/samldb: pwdLastSet = -1 requires Unexpire-Password right BUG: https://bugzilla.samba.org/show_bug.cgi?id=9654 Signed-off-by: Stefan Metzmacher Reviewed-by: Andrew Bartlett --- diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c index 5dc62897ea3..047b6ee2a93 100644 --- a/source4/dsdb/samdb/ldb_modules/samldb.c +++ b/source4/dsdb/samdb/ldb_modules/samldb.c @@ -2149,6 +2149,142 @@ static int samldb_user_account_control_change(struct samldb_ctx *ac) return LDB_SUCCESS; } +static int samldb_check_pwd_last_set_acl(struct samldb_ctx *ac, + struct dom_sid *sid) +{ + struct ldb_context *ldb = ldb_module_get_ctx(ac->module); + int ret = 0; + struct ldb_result *res = NULL; + const char * const sd_attrs[] = {"ntSecurityDescriptor", NULL}; + struct security_token *user_token = NULL; + struct security_descriptor *domain_sd = NULL; + struct ldb_dn *domain_dn = ldb_get_default_basedn(ldb_module_get_ctx(ac->module)); + const char *operation = ""; + + if (dsdb_module_am_system(ac->module)) { + return LDB_SUCCESS; + } + + switch (ac->req->operation) { + case LDB_ADD: + operation = "add"; + break; + case LDB_MODIFY: + operation = "modify"; + break; + default: + return ldb_module_operr(ac->module); + } + + user_token = acl_user_token(ac->module); + if (user_token == NULL) { + return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS; + } + + ret = dsdb_module_search_dn(ac->module, ac, &res, + domain_dn, + sd_attrs, + DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED, + ac->req); + if (ret != LDB_SUCCESS) { + return ret; + } + if (res->count != 1) { + return ldb_module_operr(ac->module); + } + + ret = dsdb_get_sd_from_ldb_message(ldb, ac, res->msgs[0], &domain_sd); + if (ret != LDB_SUCCESS) { + return ret; + } + + ret = acl_check_extended_right(ac, domain_sd, + user_token, + GUID_DRS_UNEXPIRE_PASSWORD, + SEC_ADS_CONTROL_ACCESS, + sid); + if (ret != LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) { + return ret; + } + + ldb_debug_set(ldb, LDB_DEBUG_WARNING, + "Failed to %s %s: " + "Setting pwdLastSet to -1 requires the " + "Unexpire-Password right that was not given " + "on the Domain object", + operation, + ldb_dn_get_linearized(ac->msg->dn)); + dsdb_acl_debug(domain_sd, user_token, + domain_dn, true, 10); + + return ret; +} + +/** + * This function is called on LDB modify operations. It performs some additions/ + * replaces on the current LDB message when "pwdLastSet" changes. + */ +static int samldb_pwd_last_set_change(struct samldb_ctx *ac) +{ + struct ldb_context *ldb = ldb_module_get_ctx(ac->module); + NTTIME last_set = 0; + struct ldb_message_element *el = NULL; + struct ldb_message *tmp_msg = NULL; + struct dom_sid *self_sid = NULL; + int ret; + struct ldb_result *res = NULL; + const char * const attrs[] = { + "objectSid", + NULL + }; + + el = dsdb_get_single_valued_attr(ac->msg, "pwdLastSet", + ac->req->operation); + if (el == NULL || el->num_values == 0) { + ldb_asprintf_errstring(ldb, + "%08X: samldb: 'pwdLastSet' can't be deleted!", + W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION)); + return LDB_ERR_UNWILLING_TO_PERFORM; + } + + /* Create a temporary message for fetching the "userAccountControl" */ + tmp_msg = ldb_msg_new(ac->msg); + if (tmp_msg == NULL) { + return ldb_module_oom(ac->module); + } + ret = ldb_msg_add(tmp_msg, el, 0); + if (ret != LDB_SUCCESS) { + return ret; + } + last_set = samdb_result_nttime(tmp_msg, "pwdLastSet", 0); + talloc_free(tmp_msg); + + /* + * Setting -1 (0xFFFFFFFFFFFFFFFF) requires the Unexpire-Password right + */ + if (last_set != UINT64_MAX) { + return LDB_SUCCESS; + } + + /* Fetch the "objectSid" */ + ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, attrs, + DSDB_FLAG_NEXT_MODULE, ac->req); + if (ret != LDB_SUCCESS) { + return ret; + } + self_sid = samdb_result_dom_sid(res, res->msgs[0], "objectSid"); + if (self_sid == NULL) { + return ldb_module_operr(ac->module); + } + + ret = samldb_check_pwd_last_set_acl(ac, self_sid); + if (ret != LDB_SUCCESS) { + return ret; + } + + return LDB_SUCCESS; +} + static int samldb_lockout_time(struct samldb_ctx *ac) { struct ldb_context *ldb = ldb_module_get_ctx(ac->module); @@ -3245,6 +3381,15 @@ static int samldb_modify(struct ldb_module *module, struct ldb_request *req) } } + el = ldb_msg_find_element(ac->msg, "pwdLastSet"); + if (el != NULL) { + modified = true; + ret = samldb_pwd_last_set_change(ac); + if (ret != LDB_SUCCESS) { + return ret; + } + } + el = ldb_msg_find_element(ac->msg, "lockoutTime"); if (el != NULL) { modified = true;