s4:dsdb: Set up passwords and password IDs of new gMSAs
authorJo Sutton <josutton@catalyst.net.nz>
Fri, 5 Apr 2024 00:23:18 +0000 (13:23 +1300)
committerAndrew Bartlett <abartlet@samba.org>
Tue, 16 Apr 2024 03:55:48 +0000 (15:55 +1200)
Signed-off-by: Jo Sutton <josutton@catalyst.net.nz>
Reviewed-by: Andrew Bartlett <abartlet@samba.org>
selftest/knownfail.d/gmsa
selftest/knownfail.d/samba-tool-user-get-kerberos-ticket
source4/dsdb/samdb/ldb_modules/samldb.c

index 0eabead5a16c907ad7aa4226194a6b249dc8a782..31b0c869db784e23efb55681eb5d2c1f3421049a 100644 (file)
@@ -1,14 +1,7 @@
 ^samba.tests.dckeytab.samba.tests.dckeytab.DCKeytabTests.test_export_keytab_gmsa
 ^samba.tests.blackbox.gmsa.samba.tests.blackbox.gmsa.GMSABlackboxTest.test_gmsa_password_access
-^samba.tests.krb5.gmsa_tests.samba.tests.krb5.gmsa_tests.GmsaTests.test_gmsa_can_authenticate_to_ldap_with_kerberos\(ad_dc:local\)$
-^samba.tests.krb5.gmsa_tests.samba.tests.krb5.gmsa_tests.GmsaTests.test_gmsa_can_authenticate_to_ldap_without_kerberos\(ad_dc:local\)$
-^samba.tests.krb5.gmsa_tests.samba.tests.krb5.gmsa_tests.GmsaTests.test_gmsa_can_perform_as_req_with_aes256\(ad_dc:local\)$
-^samba.tests.krb5.gmsa_tests.samba.tests.krb5.gmsa_tests.GmsaTests.test_gmsa_can_perform_as_req_with_rc4\(ad_dc:local\)$
-^samba.tests.krb5.gmsa_tests.samba.tests.krb5.gmsa_tests.GmsaTests.test_gmsa_can_perform_gensec_logon\(ad_dc:local\)$
-^samba.tests.krb5.gmsa_tests.samba.tests.krb5.gmsa_tests.GmsaTests.test_gmsa_can_perform_netlogon\(ad_dc:local\)$
 ^samba.tests.krb5.gmsa_tests.samba.tests.krb5.gmsa_tests.GmsaTests.test_retrieved_password\(ad_dc:local\)$
 ^samba.tests.krb5.gmsa_tests.samba.tests.krb5.gmsa_tests.GmsaTests.test_retrieved_password_allowed\(ad_dc:local\)$
-^samba.tests.krb5.gmsa_tests.samba.tests.krb5.gmsa_tests.GmsaTests.test_retrieved_password_denied\(ad_dc:local\)$
 ^samba.tests.krb5.gmsa_tests.samba.tests.krb5.gmsa_tests.GmsaTests.test_retrieved_password_during_clock_skew_window_when_current_key_is_expired\(ad_dc:local\)$
 ^samba.tests.krb5.gmsa_tests.samba.tests.krb5.gmsa_tests.GmsaTests.test_retrieved_password_during_clock_skew_window_when_current_key_is_valid\(ad_dc:local\)$
 ^samba.tests.krb5.gmsa_tests.samba.tests.krb5.gmsa_tests.GmsaTests.test_retrieved_password_during_clock_skew_window_when_next_key_is_expired\(ad_dc:local\)$
index 1be23ead50bc7043e19ea45cfe548b689fa9068c..9005d1782fda616a494641ca64fba443b0200329 100644 (file)
@@ -1,5 +1,2 @@
-# These tests will pass once gMSA support appears
-^samba.tests.samba_tool.user_get_kerberos_ticket.samba.tests.samba_tool.user_get_kerberos_ticket.GetKerberosTicketTest.test_gmsa_ticket.ad_dc:local
-^samba.tests.samba_tool.user_get_kerberos_ticket.samba.tests.samba_tool.user_get_kerberos_ticket.GetKerberosTicketTest.test_gmsa_ticket.ad_dc_no_ntlm:local
 # This test could be fixed by reading the AES keys in supplementalCredentials, not just the unicodePwd
 ^samba.tests.samba_tool.user_get_kerberos_ticket.samba.tests.samba_tool.user_get_kerberos_ticket.GetKerberosTicketTest.test_user_ticket.ad_dc_no_ntlm:local
index 4288cfff4465ace1dd7199a93a01e9ce69eb4820..30f4fddc098cefa795655da9a0b414a05c1a641c 100644 (file)
  */
 
 #include "includes.h"
+#include "ldb.h"
+#include "ldb_errors.h"
 #include "libcli/ldap/ldap_ndr.h"
 #include "ldb_module.h"
 #include "auth/auth.h"
+#include "dsdb/gmsa/util.h"
 #include "dsdb/samdb/samdb.h"
 #include "dsdb/samdb/ldb_modules/util.h"
 #include "dsdb/samdb/ldb_modules/ridalloc.h"
 #include "libcli/security/security.h"
+#include "librpc/gen_ndr/security.h"
 #include "librpc/gen_ndr/ndr_security.h"
 #include "ldb_wrap.h"
 #include "param/param.h"
 #include "libds/common/flag_mapping.h"
 #include "system/network.h"
 #include "librpc/gen_ndr/irpc.h"
+#include "lib/crypto/gmsa.h"
+#include "lib/util/data_blob.h"
 #include "lib/util/smb_strtox.h"
+#include "lib/util/time.h"
 
 #undef strcasecmp
 
@@ -84,6 +91,9 @@ struct samldb_ctx {
        /* used in "samldb_find_for_defaultObjectCategory" */
        struct ldb_dn *dn, *res_dn;
 
+       /* the SID to be assigned to the resulting account */
+       const struct dom_sid *sid;
+
        /* all the async steps necessary to complete the operation */
        struct samldb_step *steps;
        struct samldb_step *curstep;
@@ -1041,6 +1051,8 @@ static int samldb_allocate_sid(struct samldb_ctx *ac)
                return ldb_operr(ldb);
        }
 
+       ac->sid = sid;
+
        return samldb_next_step(ac);
 }
 
@@ -1137,6 +1149,85 @@ found:
        return samldb_next_step(ac);
 }
 
+static int samldb_gmsa_add(struct samldb_ctx *ac)
+{
+       struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
+       int ret = LDB_SUCCESS;
+       NTTIME current_time = 0;
+       const bool userPassword = dsdb_user_password_support(ac->module,
+                                                            ac->msg,
+                                                            ac->req);
+       bool ok;
+
+       ok = dsdb_gmsa_current_time(ldb, &current_time);
+       if (!ok) {
+               ret = ldb_operr(ldb);
+               goto out;
+       }
+
+       /* Remove any user‐specified passwords. */
+       dsdb_remove_password_related_attrs(ac->msg, userPassword);
+
+       /* Remove any user‐specified password IDs. */
+       ldb_msg_remove_attr(ac->msg, "msDS-ManagedPasswordId");
+       ldb_msg_remove_attr(ac->msg, "msDS-ManagedPasswordPreviousId");
+
+       {
+               DATA_BLOB pwd_id_blob = {};
+               DATA_BLOB password_blob = {};
+               struct gmsa_null_terminated_password *password = NULL;
+
+               /*
+                * The account must have a SID allocated for us to be able to
+                * derive its password.
+                */
+               if (ac->sid == NULL) {
+                       ret = ldb_operr(ldb);
+                       goto out;
+               }
+
+               /* Calculate the password and ID blobs. */
+               ret = gmsa_generate_blobs(ldb,
+                                         ac->msg,
+                                         current_time,
+                                         ac->sid,
+                                         &pwd_id_blob,
+                                         &password);
+               if (ret) {
+                       goto out;
+               }
+
+               password_blob = (DATA_BLOB){.data = password->buf,
+                                           .length = GMSA_PASSWORD_LEN};
+
+               /* Add the new password blob. */
+               ret = ldb_msg_append_steal_value(ac->msg,
+                                                "clearTextPassword",
+                                                &password_blob,
+                                                0);
+               if (ret) {
+                       goto out;
+               }
+
+               /* Add the new password ID blob. */
+               ret = ldb_msg_append_steal_value(ac->msg,
+                                                "msDS-ManagedPasswordId",
+                                                &pwd_id_blob,
+                                                0);
+               if (ret) {
+                       goto out;
+               }
+       }
+
+       ret = samldb_next_step(ac);
+       if (ret) {
+               goto out;
+       }
+
+out:
+       return ret;
+}
+
 static int samldb_find_for_defaultObjectCategory(struct samldb_ctx *ac)
 {
        struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
@@ -1418,6 +1509,13 @@ static int samldb_fill_object(struct samldb_ctx *ac)
                        if (ret != LDB_SUCCESS) return ret;
                }
 
+               if (dsdb_account_is_gmsa(ldb, ac->msg)) {
+                       ret = samldb_add_step(ac, samldb_gmsa_add);
+                       if (ret != LDB_SUCCESS) {
+                               return ret;
+                       }
+               }
+
                /* check if we have a valid sAMAccountName */
                ret = samldb_add_step(ac, samldb_check_sAMAccountName);
                if (ret != LDB_SUCCESS) return ret;