diff options
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/samldb.c | 126 |
1 files changed, 96 insertions, 30 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/samldb.c b/source4/dsdb/samdb/ldb_modules/samldb.c index 7a5beda60b..0a7ab22c40 100644 --- a/source4/dsdb/samdb/ldb_modules/samldb.c +++ b/source4/dsdb/samdb/ldb_modules/samldb.c @@ -1510,15 +1510,16 @@ static int samldb_member_check(struct samldb_ctx *ac) } /* This trigger adapts the "servicePrincipalName" attributes if the - * "dNSHostName" attribute changes */ + * "dNSHostName" and/or "sAMAccountName" attribute change(s) */ static int samldb_service_principal_names_change(struct samldb_ctx *ac) { struct ldb_context *ldb = ldb_module_get_ctx(ac->module); - struct ldb_message_element *el = NULL; + struct ldb_message_element *el = NULL, *el2 = NULL; struct ldb_message *msg; const char *attrs[] = { "servicePrincipalName", NULL }; struct ldb_result *res; - const char *dns_hostname, *old_dns_hostname; + const char *dns_hostname = NULL, *old_dns_hostname = NULL, + *sam_accountname = NULL, *old_sam_accountname = NULL; unsigned int i; int ret; @@ -1530,40 +1531,98 @@ static int samldb_service_principal_names_change(struct samldb_ctx *ac) * write protected */ for (i = 0; i < ac->msg->num_elements; i++) { - if (ldb_attr_cmp(ac->msg->elements[i].name, - "dNSHostName") != 0) { - continue; - } - - if (LDB_FLAG_MOD_TYPE(ac->msg->elements[i].flags) - != LDB_FLAG_MOD_DELETE) { + if ((ldb_attr_cmp(ac->msg->elements[i].name, + "dNSHostName") == 0) && + (LDB_FLAG_MOD_TYPE(ac->msg->elements[i].flags) + != LDB_FLAG_MOD_DELETE)) { el = &ac->msg->elements[i]; } + if ((ldb_attr_cmp(ac->msg->elements[i].name, + "sAMAccountName") == 0) && + (LDB_FLAG_MOD_TYPE(ac->msg->elements[i].flags) + != LDB_FLAG_MOD_DELETE)) { + el2 = &ac->msg->elements[i]; + } } - if (el == NULL) { + if ((el == NULL) && (el2 == NULL)) { /* we are not affected */ return LDB_SUCCESS; } /* Create a temporary message for fetching the "dNSHostName" */ - msg = ldb_msg_new(ac->msg); - if (msg == NULL) { - return ldb_module_oom(ac->module); + if (el != NULL) { + msg = ldb_msg_new(ac->msg); + if (msg == NULL) { + return ldb_module_oom(ac->module); + } + ret = ldb_msg_add(msg, el, 0); + if (ret != LDB_SUCCESS) { + return ret; + } + dns_hostname = talloc_steal(ac, + ldb_msg_find_attr_as_string(msg, "dNSHostName", NULL)); + talloc_free(msg); + + old_dns_hostname = samdb_search_string(ldb, ac, ac->msg->dn, + "dNSHostName", NULL); } - ret = ldb_msg_add(msg, el, 0); - if (ret != LDB_SUCCESS) { - return ret; + + /* Create a temporary message for fetching the "sAMAccountName" */ + if (el2 != NULL) { + char *tempstr, *tempstr2; + + msg = ldb_msg_new(ac->msg); + if (msg == NULL) { + return ldb_module_oom(ac->module); + } + ret = ldb_msg_add(msg, el2, 0); + if (ret != LDB_SUCCESS) { + return ret; + } + tempstr = talloc_strdup(ac, + ldb_msg_find_attr_as_string(msg, "sAMAccountName", NULL)); + talloc_free(msg); + + tempstr2 = talloc_strdup(ac, + samdb_search_string(ldb, ac, ac->msg->dn, "sAMAccountName", NULL)); + + /* The "sAMAccountName" needs some additional trimming: we need + * to remove the trailing "$"s if they exist. */ + if ((tempstr != NULL) && (tempstr[0] != '\0') && + (tempstr[strlen(tempstr) - 1] == '$')) { + tempstr[strlen(tempstr) - 1] = '\0'; + } + if ((tempstr2 != NULL) && (tempstr2[0] != '\0') && + (tempstr2[strlen(tempstr2) - 1] == '$')) { + tempstr2[strlen(tempstr2) - 1] = '\0'; + } + sam_accountname = tempstr; + old_sam_accountname = tempstr2; + } + + if (old_dns_hostname == NULL) { + /* we cannot change when the old name is unknown */ + dns_hostname = NULL; + } + if ((old_dns_hostname != NULL) && (dns_hostname != NULL) && + (strcasecmp(old_dns_hostname, dns_hostname) == 0)) { + /* The "dNSHostName" didn't change */ + dns_hostname = NULL; + } + + if (old_sam_accountname == NULL) { + /* we cannot change when the old name is unknown */ + sam_accountname = NULL; + } + if ((old_sam_accountname != NULL) && (sam_accountname != NULL) && + (strcasecmp(old_sam_accountname, sam_accountname) == 0)) { + /* The "sAMAccountName" didn't change */ + sam_accountname = NULL; } - dns_hostname = ldb_msg_find_attr_as_string(msg, "dNSHostName", ""); - talloc_free(msg); - old_dns_hostname = samdb_search_string(ldb, ac, ac->msg->dn, - "dNSHostName", NULL); - if ((old_dns_hostname == NULL) || (strcasecmp(old_dns_hostname, - dns_hostname) == 0)) { - /* Well, if there's no old DNS hostname then we cannot do this. - * And if old and new DNS name do match we are also finished - * here. */ + if ((dns_hostname == NULL) && (sam_accountname == NULL)) { + /* Well, there are informations missing (old name(s)) or the + * names didn't change. We've nothing to do and can exit here */ return LDB_SUCCESS; } @@ -1610,7 +1669,8 @@ static int samldb_service_principal_names_change(struct samldb_ctx *ac) if (res->msgs[0]->num_elements == 1) { /* Yes, we do have "servicePrincipalName"s. First we update them * locally, that means we do always substitute the current - * "dNSHostName" with the new one and then we append this to the + * "dNSHostName" with the new one and/or "sAMAccountName" + * without "$" with the new one and then we append this to the * modification request (Windows behaviour). */ for (i = 0; i < res->msgs[0]->elements[0].num_values; i++) { @@ -1627,9 +1687,14 @@ static int samldb_service_principal_names_change(struct samldb_ctx *ac) } while ((tok = strtok_r(NULL, "/", &pos)) != NULL) { - if (strcasecmp(tok, old_dns_hostname) == 0) { + if ((dns_hostname != NULL) && + (strcasecmp(tok, old_dns_hostname) == 0)) { tok = dns_hostname; } + if ((sam_accountname != NULL) && + (strcasecmp(tok, old_sam_accountname) == 0)) { + tok = sam_accountname; + } new_str = talloc_asprintf(ac->msg, "%s/%s", new_str, tok); @@ -1756,7 +1821,7 @@ static int samldb_modify(struct ldb_module *module, struct ldb_request *req) { struct ldb_context *ldb; struct samldb_ctx *ac; - struct ldb_message_element *el; + struct ldb_message_element *el, *el2; bool modified = false; int ret; @@ -1857,7 +1922,8 @@ static int samldb_modify(struct ldb_module *module, struct ldb_request *req) } el = ldb_msg_find_element(ac->msg, "dNSHostName"); - if (el != NULL) { + el2 = ldb_msg_find_element(ac->msg, "sAMAccountName"); + if ((el != NULL) || (el2 != NULL)) { modified = true; ret = samldb_service_principal_names_change(ac); if (ret != LDB_SUCCESS) { |