ctdb/docs: Include ceph rados namespace support in man page
[samba.git] / source4 / kdc / mit_samba.c
index e316c57ee31b944bb9fbbeb58b07e554bcd6e7d8..4af02fa00d0530edd09921ccc187f67f0ad651d8 100644 (file)
@@ -25,6 +25,7 @@
 #include "param/param.h"
 #include "dsdb/samdb/samdb.h"
 #include "system/kerberos.h"
+#include "lib/replace/system/filesys.h"
 #include <com_err.h>
 #include <kdb.h>
 #include <kadm5/kadm_err.h>
@@ -46,7 +47,7 @@
 
 void mit_samba_context_free(struct mit_samba_context *ctx)
 {
-       /* free heimdal's krb5_context */
+       /* free MIT's krb5_context */
        if (ctx->context) {
                krb5_free_context(ctx->context);
        }
@@ -56,7 +57,7 @@ void mit_samba_context_free(struct mit_samba_context *ctx)
 }
 
 /*
- * Implemant a callback to log to the MIT KDC log facility
+ * Implement a callback to log to the MIT KDC log facility
  *
  * http://web.mit.edu/kerberos/krb5-devel/doc/plugindev/general.html#logging-from-kdc-and-kadmind-plugin-modules
  */
@@ -68,16 +69,16 @@ static void mit_samba_debug(void *private_ptr, int msg_level, const char *msg)
                is_error = 0;
        }
 
-       com_err("", is_error, "%s", msg);
+       com_err("mitkdc", is_error, "%s", msg);
 }
 
-int mit_samba_context_init(struct mit_samba_context **_ctx)
+krb5_error_code mit_samba_context_init(struct mit_samba_context **_ctx)
 {
        NTSTATUS status;
        struct mit_samba_context *ctx;
        const char *s4_conf_file;
-       int ret;
-       struct samba_kdc_base_context base_ctx;
+       krb5_error_code ret;
+       struct samba_kdc_base_context base_ctx = {};
 
        ctx = talloc_zero(NULL, struct mit_samba_context);
        if (!ctx) {
@@ -113,13 +114,19 @@ int mit_samba_context_init(struct mit_samba_context **_ctx)
                lpcfg_load_default(base_ctx.lp_ctx);
        }
 
+       base_ctx.current_nttime_ull = talloc_zero(ctx, unsigned long long);
+       if (base_ctx.current_nttime_ull == NULL) {
+               ret = ENOMEM;
+               goto done;
+       }
+
        status = samba_kdc_setup_db_ctx(ctx, &base_ctx, &ctx->db_ctx);
        if (!NT_STATUS_IS_OK(status)) {
                ret = EINVAL;
                goto done;
        }
 
-       /* init heimdal's krb_context and log facilities */
+       /* init MIT's krb_context and log facilities */
        ret = smb_krb5_init_context_basic(ctx,
                                          ctx->db_ctx->lp_ctx,
                                          &ctx->context);
@@ -138,22 +145,6 @@ done:
        return ret;
 }
 
-static krb5_error_code ks_is_tgs_principal(struct mit_samba_context *ctx,
-                                          krb5_const_principal principal)
-{
-       char *p;
-       int eq = -1;
-
-       p = smb_krb5_principal_get_comp_string(ctx, ctx->context, principal, 0);
-
-       eq = krb5_princ_size(ctx->context, principal) == 2 &&
-            (strcmp(p, KRB5_TGS_NAME) == 0);
-
-       talloc_free(p);
-
-       return eq;
-}
-
 int mit_samba_generate_salt(krb5_data *salt)
 {
        if (salt == NULL) {
@@ -175,59 +166,68 @@ int mit_samba_generate_random_password(krb5_data *pwd)
 {
        TALLOC_CTX *tmp_ctx;
        char *password;
+       char *data = NULL;
+       const unsigned length = 24;
 
        if (pwd == NULL) {
                return EINVAL;
        }
-       pwd->length = 24;
 
        tmp_ctx = talloc_named(NULL,
                               0,
-                              "mit_samba_create_principal_password context");
+                              "mit_samba_generate_random_password context");
        if (tmp_ctx == NULL) {
                return ENOMEM;
        }
 
-       password = generate_random_password(tmp_ctx, pwd->length, pwd->length);
+       password = generate_random_password(tmp_ctx, length, length);
        if (password == NULL) {
                talloc_free(tmp_ctx);
                return ENOMEM;
        }
 
-       pwd->data = strdup(password);
+       data = strdup(password);
        talloc_free(tmp_ctx);
-       if (pwd->data == NULL) {
+       if (data == NULL) {
                return ENOMEM;
        }
 
+       *pwd = smb_krb5_make_data(data, length);
+
        return 0;
 }
 
-int mit_samba_get_principal(struct mit_samba_context *ctx,
-                           krb5_const_principal principal,
-                           unsigned int kflags,
-                           krb5_db_entry **_kentry)
+krb5_error_code mit_samba_get_principal(struct mit_samba_context *ctx,
+                                       krb5_const_principal principal,
+                                       unsigned int kflags,
+                                       krb5_db_entry **_kentry)
 {
        struct sdb_entry sentry = {};
        krb5_db_entry *kentry;
-       int ret;
+       krb5_error_code ret;
        uint32_t sflags = 0;
        krb5_principal referral_principal = NULL;
+       NTTIME now;
+       bool time_ok;
+
+       time_ok = gmsa_current_time(&now);
+       if (!time_ok) {
+               return EINVAL;
+       }
+
+       *ctx->db_ctx->current_nttime_ull = now;
 
        kentry = calloc(1, sizeof(krb5_db_entry));
        if (kentry == NULL) {
                return ENOMEM;
        }
 
-#if KRB5_KDB_API_VERSION >= 10
        /*
         * The MIT KDC code that wants the canonical name in all lookups, and
         * takes care to canonicalize only when appropriate.
         */
        sflags |= SDB_F_FORCE_CANON;
-#endif
 
-#if KRB5_KDB_DAL_MAJOR_VERSION >= 9
        if (kflags & KRB5_KDB_FLAG_REFERRAL_OK) {
                sflags |= SDB_F_CANON;
        }
@@ -248,33 +248,6 @@ int mit_samba_get_principal(struct mit_samba_context *ctx,
                        sflags |= SDB_F_FOR_TGS_REQ;
                }
        }
-#else /* KRB5_KDB_DAL_MAJOR_VERSION < 9 */
-       if (kflags & KRB5_KDB_FLAG_CANONICALIZE) {
-               sflags |= SDB_F_CANON;
-       }
-       if (kflags & (KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY |
-                     KRB5_KDB_FLAG_INCLUDE_PAC)) {
-               /*
-                * KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY is equal to
-                * SDB_F_FOR_AS_REQ
-                *
-                * We use ANY to also allow AS_REQ for service principal names
-                * This is supported by Windows.
-                */
-               sflags |= SDB_F_GET_ANY|SDB_F_FOR_AS_REQ;
-       } else {
-               int equal = smb_krb5_principal_is_tgs(ctx->context, principal);
-               if (equal == -1) {
-                       return ENOMEM;
-               }
-
-               if (equal) {
-                       sflags |= SDB_F_GET_KRBTGT;
-               } else {
-                       sflags |= SDB_F_GET_SERVER|SDB_F_FOR_TGS_REQ;
-               }
-       }
-#endif /* KRB5_KDB_DAL_MAJOR_VERSION */
 
        /* always set this or the created_by data will not be populated by samba's
         * backend and we will fail to parse the entry later */
@@ -318,15 +291,15 @@ fetch_referral_principal:
                 *
                 *     ADDOM.SAMBA.EXAMPLE.COM
                 *
-                * We look up if we have and entry in the database and get an
-                * entry with the pricipal:
+                * We look up if we have an entry in the database and get an
+                * entry with the principal:
                 *
                 *     cifs/dc7.SAMBA2008R2.EXAMPLE.COM@SAMBA2008R2.EXAMPLE.COM
                 *
                 * and the error: SDB_ERR_WRONG_REALM.
                 *
                 * In the case of a TGS-REQ we need to return a referral ticket
-                * fo the next trust hop to the client. This ticket will have
+                * for the next trust hop to the client. This ticket will have
                 * the following principal:
                 *
                 *     krbtgt/SAMBA2008R2.EXAMPLE.COM@ADDOM.SAMBA.EXAMPLE.COM
@@ -378,19 +351,29 @@ done:
        return ret;
 }
 
-int mit_samba_get_firstkey(struct mit_samba_context *ctx,
-                          krb5_db_entry **_kentry)
+krb5_error_code mit_samba_get_firstkey(struct mit_samba_context *ctx,
+                                      krb5_db_entry **_kentry)
 {
        struct sdb_entry sentry = {};
        krb5_db_entry *kentry;
-       int ret;
+       krb5_error_code ret;
+
+       NTTIME now;
+       bool time_ok;
+
+       time_ok = gmsa_current_time(&now);
+       if (!time_ok) {
+               return EINVAL;
+       }
+
+       *ctx->db_ctx->current_nttime_ull = now;
 
        kentry = malloc(sizeof(krb5_db_entry));
        if (kentry == NULL) {
                return ENOMEM;
        }
 
-       ret = samba_kdc_firstkey(ctx->context, ctx->db_ctx, &sentry);
+       ret = samba_kdc_firstkey(ctx->context, ctx->db_ctx, SDB_F_ADMIN_DATA, &sentry);
        switch (ret) {
        case 0:
                break;
@@ -416,19 +399,21 @@ int mit_samba_get_firstkey(struct mit_samba_context *ctx,
        return ret;
 }
 
-int mit_samba_get_nextkey(struct mit_samba_context *ctx,
-                         krb5_db_entry **_kentry)
+krb5_error_code mit_samba_get_nextkey(struct mit_samba_context *ctx,
+                                     krb5_db_entry **_kentry)
 {
        struct sdb_entry sentry = {};
        krb5_db_entry *kentry;
-       int ret;
+       krb5_error_code ret;
+
+       /* Not updating time, keep the same for the whole operation */
 
        kentry = malloc(sizeof(krb5_db_entry));
        if (kentry == NULL) {
                return ENOMEM;
        }
 
-       ret = samba_kdc_nextkey(ctx->context, ctx->db_ctx, &sentry);
+       ret = samba_kdc_nextkey(ctx->context, ctx->db_ctx, SDB_F_ADMIN_DATA, &sentry);
        switch (ret) {
        case 0:
                break;
@@ -454,15 +439,17 @@ int mit_samba_get_nextkey(struct mit_samba_context *ctx,
        return ret;
 }
 
-int mit_samba_get_pac(struct mit_samba_context *smb_ctx,
-                     krb5_context context,
-                     uint32_t flags,
-                     krb5_db_entry *client,
-                     krb5_db_entry *server,
-                     krb5_keyblock *replaced_reply_key,
-                     krb5_pac *pac)
+krb5_error_code mit_samba_get_pac(struct mit_samba_context *smb_ctx,
+                                 krb5_context context,
+                                 uint32_t flags,
+                                 krb5_db_entry *client,
+                                 krb5_db_entry *server,
+                                 krb5_keyblock *replaced_reply_key,
+                                 krb5_pac *pac)
 {
        TALLOC_CTX *tmp_ctx;
+       const struct auth_user_info_dc *user_info_dc = NULL;
+       struct auth_user_info_dc *user_info_dc_shallow_copy = NULL;
        DATA_BLOB *logon_info_blob = NULL;
        DATA_BLOB *upn_dns_info_blob = NULL;
        DATA_BLOB *cred_ndr = NULL;
@@ -471,21 +458,54 @@ int mit_samba_get_pac(struct mit_samba_context *smb_ctx,
        DATA_BLOB *pcred_blob = NULL;
        DATA_BLOB *pac_attrs_blob = NULL;
        DATA_BLOB *requester_sid_blob = NULL;
+       const DATA_BLOB *client_claims_blob = NULL;
        NTSTATUS nt_status;
        krb5_error_code code;
        struct samba_kdc_entry *skdc_entry;
+       struct samba_kdc_entry *server_entry = NULL;
        bool is_krbtgt;
+       /* Only include resource groups in a service ticket. */
+       enum auth_group_inclusion group_inclusion;
        enum samba_asserted_identity asserted_identity =
                (flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION) ?
                        SAMBA_ASSERTED_IDENTITY_SERVICE :
                        SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY;
 
+       if (client == NULL) {
+               return EINVAL;
+       }
        skdc_entry = talloc_get_type_abort(client->e_data,
                                           struct samba_kdc_entry);
 
+       /* This sets the time into the DSDB opaque */
+       *smb_ctx->db_ctx->current_nttime_ull = skdc_entry->current_nttime;
+
+       if (server == NULL) {
+               return EINVAL;
+       }
+       {
+               int result = smb_krb5_principal_is_tgs(smb_ctx->context, server->princ);
+               if (result == -1) {
+                       return ENOMEM;
+               }
+
+               is_krbtgt = result;
+       }
+       server_entry = talloc_get_type_abort(server->e_data,
+                                            struct samba_kdc_entry);
+
+       /* Only include resource groups in a service ticket. */
+       if (is_krbtgt) {
+               group_inclusion = AUTH_EXCLUDE_RESOURCE_GROUPS;
+       } else if (server_entry->supported_enctypes & KERB_ENCTYPE_RESOURCE_SID_COMPRESSION_DISABLED) {
+               group_inclusion = AUTH_INCLUDE_RESOURCE_GROUPS;
+       } else {
+               group_inclusion = AUTH_INCLUDE_RESOURCE_GROUPS_COMPRESSED;
+       }
+
        tmp_ctx = talloc_named(smb_ctx,
                               0,
-                              "mit_samba_get_pac_data_blobs context");
+                              "mit_samba_get_pac context");
        if (tmp_ctx == NULL) {
                return ENOMEM;
        }
@@ -495,23 +515,100 @@ int mit_samba_get_pac(struct mit_samba_context *smb_ctx,
                cred_ndr_ptr = &cred_ndr;
        }
 
-       is_krbtgt = ks_is_tgs_principal(smb_ctx, server->princ);
+       code = samba_kdc_get_user_info_from_db(tmp_ctx,
+                                              server_entry->kdc_db_ctx->samdb,
+                                              skdc_entry,
+                                              skdc_entry->msg,
+                                              &user_info_dc);
+       if (code) {
+               talloc_free(tmp_ctx);
+               return code;
+       }
+
+       /* Make a shallow copy of the user_info_dc structure. */
+       nt_status = authsam_shallow_copy_user_info_dc(tmp_ctx,
+                                                     user_info_dc,
+                                                     &user_info_dc_shallow_copy);
+       user_info_dc = NULL;
 
-       nt_status = samba_kdc_get_pac_blobs(tmp_ctx,
-                                           skdc_entry,
-                                           asserted_identity,
-                                           &logon_info_blob,
-                                           cred_ndr_ptr,
-                                           &upn_dns_info_blob,
-                                           is_krbtgt ? &pac_attrs_blob : NULL,
-                                           PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY,
-                                           is_krbtgt ? &requester_sid_blob : NULL);
        if (!NT_STATUS_IS_OK(nt_status)) {
+               DBG_ERR("Failed to allocate shallow copy of user_info_dc: %s\n",
+                       nt_errstr(nt_status));
                talloc_free(tmp_ctx);
-               if (NT_STATUS_EQUAL(nt_status,
-                                   NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
-                       return ENOENT;
+               return map_errno_from_nt_status(nt_status);
+       }
+
+
+       nt_status = samba_kdc_add_asserted_identity(asserted_identity,
+                                                   user_info_dc_shallow_copy);
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               DBG_ERR("Failed to add asserted identity: %s\n",
+                       nt_errstr(nt_status));
+               talloc_free(tmp_ctx);
+               return EINVAL;
+       }
+
+       nt_status = samba_kdc_add_claims_valid(user_info_dc_shallow_copy);
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               DBG_ERR("Failed to add Claims Valid: %s\n",
+                       nt_errstr(nt_status));
+               talloc_free(tmp_ctx);
+               return EINVAL;
+       }
+
+       /* We no longer need to modify this, so assign to const variable */
+       user_info_dc = user_info_dc_shallow_copy;
+
+       nt_status = samba_kdc_get_logon_info_blob(tmp_ctx,
+                                                 user_info_dc,
+                                                 group_inclusion,
+                                                 &logon_info_blob);
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               talloc_free(tmp_ctx);
+               return EINVAL;
+       }
+
+       if (cred_ndr_ptr != NULL) {
+               nt_status = samba_kdc_get_cred_ndr_blob(tmp_ctx,
+                                                       skdc_entry,
+                                                       cred_ndr_ptr);
+               if (!NT_STATUS_IS_OK(nt_status)) {
+                       talloc_free(tmp_ctx);
+                       return EINVAL;
                }
+       }
+
+       nt_status = samba_kdc_get_upn_info_blob(tmp_ctx,
+                                               user_info_dc,
+                                               &upn_dns_info_blob);
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               talloc_free(tmp_ctx);
+               return EINVAL;
+       }
+
+       if (is_krbtgt) {
+               nt_status = samba_kdc_get_pac_attrs_blob(tmp_ctx,
+                                                        PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY,
+                                                        &pac_attrs_blob);
+               if (!NT_STATUS_IS_OK(nt_status)) {
+                       talloc_free(tmp_ctx);
+                       return EINVAL;
+               }
+
+               nt_status = samba_kdc_get_requester_sid_blob(tmp_ctx,
+                                                            user_info_dc,
+                                                            &requester_sid_blob);
+               if (!NT_STATUS_IS_OK(nt_status)) {
+                       talloc_free(tmp_ctx);
+                       return EINVAL;
+               }
+       }
+
+       nt_status = samba_kdc_get_claims_blob(tmp_ctx,
+                                             skdc_entry,
+                                             &client_claims_blob);
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               talloc_free(tmp_ctx);
                return EINVAL;
        }
 
@@ -534,125 +631,16 @@ int mit_samba_get_pac(struct mit_samba_context *smb_ctx,
                                   upn_dns_info_blob,
                                   pac_attrs_blob,
                                   requester_sid_blob,
-                                  NULL,
+                                  NULL /* deleg_blob */,
+                                  client_claims_blob,
+                                  NULL /* device_info_blob */,
+                                  NULL /* device_claims_blob */,
                                   *pac);
 
        talloc_free(tmp_ctx);
        return code;
 }
 
-#if KRB5_KDB_DAL_MAJOR_VERSION < 9
-krb5_error_code mit_samba_reget_pac(struct mit_samba_context *ctx,
-                                   krb5_context context,
-                                   int kdc_flags,
-                                   krb5_const_principal client_principal,
-                                   krb5_db_entry *client,
-                                   krb5_db_entry *server,
-                                   krb5_db_entry *krbtgt,
-                                   krb5_keyblock *krbtgt_keyblock,
-                                   krb5_pac *pac)
-{
-       TALLOC_CTX *tmp_ctx;
-       krb5_error_code code;
-       struct samba_kdc_entry *client_skdc_entry = NULL;
-       struct samba_kdc_entry *krbtgt_skdc_entry = NULL;
-       struct samba_kdc_entry *server_skdc_entry = NULL;
-       krb5_principal delegated_proxy_principal = NULL;
-       krb5_pac new_pac = NULL;
-       bool is_in_db = false;
-       bool is_untrusted = false;
-       uint32_t flags = SAMBA_KDC_FLAG_SKIP_PAC_BUFFER;
-
-       /* Create a memory context early so code can use talloc_stackframe() */
-       tmp_ctx = talloc_named(ctx, 0, "mit_samba_reget_pac context");
-       if (tmp_ctx == NULL) {
-               return ENOMEM;
-       }
-
-       if (client != NULL) {
-               client_skdc_entry =
-                       talloc_get_type_abort(client->e_data,
-                                             struct samba_kdc_entry);
-       }
-
-       if (server == NULL) {
-               code = EINVAL;
-               goto done;
-       }
-
-       server_skdc_entry =
-               talloc_get_type_abort(server->e_data,
-                                     struct samba_kdc_entry);
-
-       if (krbtgt == NULL) {
-               code = EINVAL;
-               goto done;
-       }
-       krbtgt_skdc_entry =
-               talloc_get_type_abort(krbtgt->e_data,
-                                     struct samba_kdc_entry);
-
-       code = samba_krbtgt_is_in_db(krbtgt_skdc_entry,
-                                    &is_in_db,
-                                    &is_untrusted);
-       if (code != 0) {
-               goto done;
-       }
-
-       if (is_untrusted) {
-               flags |=  SAMBA_KDC_FLAG_KRBTGT_IS_UNTRUSTED;
-       }
-
-       if (is_in_db) {
-               flags |= SAMBA_KDC_FLAG_KRBTGT_IN_DB;
-
-       }
-
-       if (kdc_flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION) {
-               flags |= SAMBA_KDC_FLAG_PROTOCOL_TRANSITION;
-       }
-
-       if (kdc_flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) {
-               flags |= SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION;
-               delegated_proxy_principal = discard_const(client_principal);
-       }
-
-       /* Build an updated PAC */
-       code = krb5_pac_init(context, &new_pac);
-       if (code != 0) {
-               goto done;
-       }
-
-       code = samba_kdc_update_pac(tmp_ctx,
-                                   context,
-                                   krbtgt_skdc_entry->kdc_db_ctx->samdb,
-                                   flags,
-                                   client_skdc_entry,
-                                   server->princ,
-                                   server_skdc_entry,
-                                   krbtgt_skdc_entry,
-                                   delegated_proxy_principal,
-                                   *pac,
-                                   new_pac);
-       if (code != 0) {
-               krb5_pac_free(context, new_pac);
-               if (code == ENODATA) {
-                       krb5_pac_free(context, *pac);
-                       *pac = NULL;
-                       code = 0;
-               }
-               goto done;
-       }
-
-       /* We now replace the pac */
-       krb5_pac_free(context, *pac);
-       *pac = new_pac;
-
-done:
-       talloc_free(tmp_ctx);
-       return code;
-}
-#else
 krb5_error_code mit_samba_update_pac(struct mit_samba_context *ctx,
                                    krb5_context context,
                                    int kdc_flags,
@@ -667,9 +655,10 @@ krb5_error_code mit_samba_update_pac(struct mit_samba_context *ctx,
        struct samba_kdc_entry *client_skdc_entry = NULL;
        struct samba_kdc_entry *server_skdc_entry = NULL;
        struct samba_kdc_entry *krbtgt_skdc_entry = NULL;
+       struct samba_kdc_entry_pac client_pac_entry = {};
        bool is_in_db = false;
-       bool is_untrusted = false;
-       uint32_t flags = SAMBA_KDC_FLAG_SKIP_PAC_BUFFER;
+       bool is_trusted = false;
+       uint32_t flags = 0;
 
        /* Create a memory context early so code can use talloc_stackframe() */
        tmp_ctx = talloc_named(ctx, 0, "mit_samba_update_pac context");
@@ -691,6 +680,13 @@ krb5_error_code mit_samba_update_pac(struct mit_samba_context *ctx,
                talloc_get_type_abort(krbtgt->e_data,
                                      struct samba_kdc_entry);
 
+       /* This sets the time into the DSDB opaque */
+       *ctx->db_ctx->current_nttime_ull = krbtgt_skdc_entry->current_nttime;
+
+       if (server == NULL) {
+               code = EINVAL;
+               goto done;
+       }
        server_skdc_entry =
                talloc_get_type_abort(server->e_data,
                                      struct samba_kdc_entry);
@@ -706,37 +702,50 @@ krb5_error_code mit_samba_update_pac(struct mit_samba_context *ctx,
         */
        code = samba_krbtgt_is_in_db(krbtgt_skdc_entry,
                                     &is_in_db,
-                                    &is_untrusted);
+                                    &is_trusted);
        if (code != 0) {
                goto done;
        }
 
-       if (is_untrusted) {
-               flags |=  SAMBA_KDC_FLAG_KRBTGT_IS_UNTRUSTED;
-       }
-
-       if (is_in_db) {
-               flags |= SAMBA_KDC_FLAG_KRBTGT_IN_DB;
-
+       if (kdc_flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION) {
+               flags |= SAMBA_KDC_FLAG_PROTOCOL_TRANSITION;
        }
 
        if (kdc_flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) {
                flags |= SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION;
        }
 
+       client_pac_entry = samba_kdc_entry_pac_from_trusted(old_pac,
+                                                           client_skdc_entry,
+                                                           samba_kdc_entry_is_trust(krbtgt_skdc_entry),
+                                                           is_trusted);
+
+       code = samba_kdc_verify_pac(tmp_ctx,
+                                   context,
+                                   krbtgt_skdc_entry->kdc_db_ctx->samdb,
+                                   flags,
+                                   client_pac_entry,
+                                   krbtgt_skdc_entry);
+       if (code != 0) {
+               goto done;
+       }
+
        code = samba_kdc_update_pac(tmp_ctx,
                                    context,
                                    krbtgt_skdc_entry->kdc_db_ctx->samdb,
+                                   krbtgt_skdc_entry->kdc_db_ctx->lp_ctx,
                                    flags,
-                                   client_skdc_entry,
+                                   client_pac_entry,
                                    server->princ,
                                    server_skdc_entry,
-                                   krbtgt_skdc_entry,
-                                   NULL,
-                                   old_pac,
-                                   new_pac);
+                                   NULL /* delegated_proxy_principal */,
+                                   (struct samba_kdc_entry_pac) {} /* delegated_proxy */,
+                                   (struct samba_kdc_entry_pac) {} /* device */,
+                                   new_pac,
+                                   NULL /* server_audit_info_out */,
+                                   NULL /* status_out */);
        if (code != 0) {
-               if (code == ENODATA) {
+               if (code == ENOATTR) {
                        /*
                         * We can't tell the KDC to not issue a PAC. It will
                         * just return the newly allocated empty PAC.
@@ -749,7 +758,6 @@ done:
        talloc_free(tmp_ctx);
        return code;
 }
-#endif
 
 /* provide header, function is exported but there are no public headers */
 
@@ -770,7 +778,7 @@ static void samba_kdc_build_edata_reply(NTSTATUS nt_status, DATA_BLOB *e_data)
        e_data->length = 0;
 
        pa.magic                = KV5M_PA_DATA;
-       pa.pa_type              = KRB5_PADATA_PW_SALT;
+       pa.pa_type              = KRB5_PADATA_PW_SALT /* KERB_ERR_TYPE_EXTENDED */;
        pa.length               = 12;
        pa.contents             = malloc(pa.length);
        if (!pa.contents) {
@@ -799,20 +807,23 @@ static void samba_kdc_build_edata_reply(NTSTATUS nt_status, DATA_BLOB *e_data)
        return;
 }
 
-int mit_samba_check_client_access(struct mit_samba_context *ctx,
-                                 krb5_db_entry *client,
-                                 const char *client_name,
-                                 krb5_db_entry *server,
-                                 const char *server_name,
-                                 const char *netbios_name,
-                                 bool password_change,
-                                 DATA_BLOB *e_data)
+krb5_error_code mit_samba_check_client_access(struct mit_samba_context *ctx,
+                                             krb5_db_entry *client,
+                                             const char *client_name,
+                                             krb5_db_entry *server,
+                                             const char *server_name,
+                                             const char *netbios_name,
+                                             bool password_change,
+                                             DATA_BLOB *e_data)
 {
        struct samba_kdc_entry *skdc_entry;
        NTSTATUS nt_status;
 
        skdc_entry = talloc_get_type(client->e_data, struct samba_kdc_entry);
 
+       /* This sets the time into the DSDB opaque */
+       *ctx->db_ctx->current_nttime_ull = skdc_entry->current_nttime;
+
        nt_status = samba_kdc_check_client_access(skdc_entry,
                                                  client_name,
                                                  netbios_name,
@@ -831,24 +842,23 @@ int mit_samba_check_client_access(struct mit_samba_context *ctx,
        return 0;
 }
 
-int mit_samba_check_s4u2proxy(struct mit_samba_context *ctx,
-                             const krb5_db_entry *server,
-                             krb5_const_principal target_principal)
+krb5_error_code mit_samba_check_s4u2proxy(struct mit_samba_context *ctx,
+                                         const krb5_db_entry *server,
+                                         krb5_const_principal target_principal)
 {
-#if KRB5_KDB_DAL_MAJOR_VERSION < 9
-       return KRB5KDC_ERR_BADOPTION;
-#else
        struct samba_kdc_entry *server_skdc_entry =
                talloc_get_type_abort(server->e_data, struct samba_kdc_entry);
        krb5_error_code code;
 
+       /* This sets the time into the DSDB opaque */
+       *ctx->db_ctx->current_nttime_ull = server_skdc_entry->current_nttime;
+
        code = samba_kdc_check_s4u2proxy(ctx->context,
                                         ctx->db_ctx,
                                         server_skdc_entry,
                                         target_principal);
 
        return code;
-#endif
 }
 
 krb5_error_code mit_samba_check_allowed_to_delegate_from(
@@ -858,22 +868,49 @@ krb5_error_code mit_samba_check_allowed_to_delegate_from(
                krb5_pac header_pac,
                const krb5_db_entry *proxy)
 {
-#if KRB5_KDB_DAL_MAJOR_VERSION < 8
-       return KRB5KDC_ERR_POLICY;
-#else
        struct samba_kdc_entry *proxy_skdc_entry =
                talloc_get_type_abort(proxy->e_data, struct samba_kdc_entry);
+       struct auth_user_info_dc *user_info_dc = NULL;
+       TALLOC_CTX *mem_ctx = NULL;
        krb5_error_code code;
 
+       /* This sets the time into the DSDB opaque */
+       *ctx->db_ctx->current_nttime_ull = proxy_skdc_entry->current_nttime;
+
+       mem_ctx = talloc_new(NULL);
+       if (mem_ctx == NULL) {
+               return ENOMEM;
+       }
+
+       /*
+        * FIXME: If ever we support RODCs, we must check that the PAC has not
+        * been issued by an RODC (other than ourselves) — otherwise the PAC
+        * cannot be trusted. Because the plugin interface does not give us the
+        * client entry, we cannot look up its groups in the database.
+        */
+       code = kerberos_pac_to_user_info_dc(mem_ctx,
+                                           header_pac,
+                                           ctx->context,
+                                           &user_info_dc,
+                                           AUTH_INCLUDE_RESOURCE_GROUPS,
+                                           NULL,
+                                           NULL,
+                                           NULL);
+       if (code != 0) {
+               goto out;
+       }
+
        code = samba_kdc_check_s4u2proxy_rbcd(ctx->context,
                                              ctx->db_ctx,
                                              client_principal,
                                              server_principal,
-                                             header_pac,
+                                             user_info_dc,
+                                             NULL /* device_info_dc */,
+                                             (struct auth_claims) {},
                                              proxy_skdc_entry);
-
+out:
+       talloc_free(mem_ctx);
        return code;
-#endif
 }
 
 static krb5_error_code mit_samba_change_pwd_error(krb5_context context,
@@ -940,9 +977,9 @@ static krb5_error_code mit_samba_change_pwd_error(krb5_context context,
        return code;
 }
 
-int mit_samba_kpasswd_change_password(struct mit_samba_context *ctx,
-                                     char *pwd,
-                                     krb5_db_entry *db_entry)
+krb5_error_code mit_samba_kpasswd_change_password(struct mit_samba_context *ctx,
+                                                 char *pwd,
+                                                 krb5_db_entry *db_entry)
 {
        NTSTATUS status;
        NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
@@ -951,13 +988,16 @@ int mit_samba_kpasswd_change_password(struct mit_samba_context *ctx,
        enum samPwdChangeReason reject_reason;
        struct samr_DomInfo1 *dominfo;
        const char *error_string = NULL;
-       struct auth_user_info_dc *user_info_dc;
+       const struct auth_user_info_dc *user_info_dc = NULL;
        struct samba_kdc_entry *p =
                talloc_get_type_abort(db_entry->e_data, struct samba_kdc_entry);
        krb5_error_code code = 0;
 
+       /* This sets the time into the DSDB opaque */
+       *ctx->db_ctx->current_nttime_ull = p->current_nttime;
+
 #ifdef DEBUG_PASSWORD
-       DEBUG(1,("mit_samba_kpasswd_change_password called with: %s\n", pwd));
+       DBG_WARNING("mit_samba_kpasswd_change_password called with: %s\n", pwd);
 #endif
 
        tmp_ctx = talloc_named(ctx, 0, "mit_samba_kpasswd_change_password");
@@ -965,14 +1005,18 @@ int mit_samba_kpasswd_change_password(struct mit_samba_context *ctx,
                return ENOMEM;
        }
 
-       status = samba_kdc_get_user_info_from_db(p,
-                                                p->msg,
-                                                &user_info_dc);
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(1,("samba_kdc_get_user_info_from_db failed: %s\n",
-                       nt_errstr(status)));
-               talloc_free(tmp_ctx);
-               return EINVAL;
+       code = samba_kdc_get_user_info_from_db(tmp_ctx,
+                                              ctx->db_ctx->samdb,
+                                              p,
+                                              p->msg,
+                                              &user_info_dc);
+       if (code) {
+               const char *krb5err = krb5_get_error_message(ctx->context, code);
+               DBG_WARNING("samba_kdc_get_user_info_from_db failed: %s\n",
+                       krb5err != NULL ? krb5err : "<unknown>");
+               krb5_free_error_message(ctx->context, krb5err);
+
+               goto out;
        }
 
        status = auth_generate_session_info(tmp_ctx,
@@ -983,10 +1027,10 @@ int mit_samba_kpasswd_change_password(struct mit_samba_context *ctx,
                                            &ctx->session_info);
 
        if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(1,("auth_generate_session_info failed: %s\n",
-                       nt_errstr(status)));
-               talloc_free(tmp_ctx);
-               return EINVAL;
+               DBG_WARNING("auth_generate_session_info failed: %s\n",
+                           nt_errstr(status));
+               code = EINVAL;
+               goto out;
        }
 
        /* password is expected as UTF16 */
@@ -994,9 +1038,9 @@ int mit_samba_kpasswd_change_password(struct mit_samba_context *ctx,
        if (!convert_string_talloc(tmp_ctx, CH_UTF8, CH_UTF16,
                                   pwd, strlen(pwd),
                                   &password.data, &password.length)) {
-               DEBUG(1,("convert_string_talloc failed\n"));
-               talloc_free(tmp_ctx);
-               return EINVAL;
+               DBG_WARNING("convert_string_talloc failed\n");
+               code = EINVAL;
+               goto out;
        }
 
        status = samdb_kpasswd_change_password(tmp_ctx,
@@ -1009,8 +1053,8 @@ int mit_samba_kpasswd_change_password(struct mit_samba_context *ctx,
                                               &error_string,
                                               &result);
        if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(1,("samdb_kpasswd_change_password failed: %s\n",
-                       nt_errstr(status)));
+               DBG_WARNING("samdb_kpasswd_change_password failed: %s\n",
+                           nt_errstr(status));
                code = KADM5_PASS_Q_GENERIC;
                krb5_set_error_message(ctx->context, code, "%s", error_string);
                goto out;
@@ -1031,18 +1075,21 @@ out:
 
 void mit_samba_zero_bad_password_count(krb5_db_entry *db_entry)
 {
-       struct netr_SendToSamBase *send_to_sam = NULL;
+       /* struct netr_SendToSamBase *send_to_sam = NULL; */
        struct samba_kdc_entry *p =
                talloc_get_type_abort(db_entry->e_data, struct samba_kdc_entry);
        struct ldb_dn *domain_dn;
 
+       /* This sets the time into the DSDB opaque */
+       *p->kdc_db_ctx->current_nttime_ull = p->current_nttime;
+
        domain_dn = ldb_get_default_basedn(p->kdc_db_ctx->samdb);
 
        authsam_logon_success_accounting(p->kdc_db_ctx->samdb,
                                         p->msg,
                                         domain_dn,
                                         true,
-                                        &send_to_sam);
+                                        NULL, NULL);
        /* TODO: RODC support */
 }
 
@@ -1052,6 +1099,9 @@ void mit_samba_update_bad_password_count(krb5_db_entry *db_entry)
        struct samba_kdc_entry *p =
                talloc_get_type_abort(db_entry->e_data, struct samba_kdc_entry);
 
+       /* This sets the time into the DSDB opaque */
+       *p->kdc_db_ctx->current_nttime_ull = p->current_nttime;
+
        authsam_update_bad_pwd_count(p->kdc_db_ctx->samdb,
                                     p->msg,
                                     ldb_get_default_basedn(p->kdc_db_ctx->samdb));
@@ -1062,5 +1112,8 @@ bool mit_samba_princ_needs_pac(krb5_db_entry *db_entry)
        struct samba_kdc_entry *skdc_entry =
                talloc_get_type_abort(db_entry->e_data, struct samba_kdc_entry);
 
+       /* This sets the time into the DSDB opaque */
+       *skdc_entry->kdc_db_ctx->current_nttime_ull = skdc_entry->current_nttime;
+
        return samba_princ_needs_pac(skdc_entry);
 }