LCOV - code coverage report
Current view: top level - source4/kdc - mit_samba.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 65 461 14.1 %
Date: 2024-04-21 15:09:00 Functions: 4 19 21.1 %

          Line data    Source code
       1             : /*
       2             :    MIT-Samba4 library
       3             : 
       4             :    Copyright (c) 2010, Simo Sorce <idra@samba.org>
       5             :    Copyright (c) 2014-2015 Guenther Deschner <gd@samba.org>
       6             :    Copyright (c) 2014-2016 Andreas Schneider <asn@samba.org>
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             :  */
      21             : 
      22             : #define TEVENT_DEPRECATED 1
      23             : 
      24             : #include "includes.h"
      25             : #include "param/param.h"
      26             : #include "dsdb/samdb/samdb.h"
      27             : #include "system/kerberos.h"
      28             : #include "lib/replace/system/filesys.h"
      29             : #include <com_err.h>
      30             : #include <kdb.h>
      31             : #include <kadm5/kadm_err.h>
      32             : #include "kdc/sdb.h"
      33             : #include "kdc/sdb_kdb.h"
      34             : #include "auth/kerberos/kerberos.h"
      35             : #include "auth/kerberos/pac_utils.h"
      36             : #include "kdc/samba_kdc.h"
      37             : #include "kdc/pac-glue.h"
      38             : #include "kdc/db-glue.h"
      39             : #include "auth/auth.h"
      40             : #include "kdc/kpasswd_glue.h"
      41             : #include "auth/auth_sam.h"
      42             : 
      43             : #include "mit_samba.h"
      44             : 
      45             : #undef DBGC_CLASS
      46             : #define DBGC_CLASS DBGC_KERBEROS
      47             : 
      48          17 : void mit_samba_context_free(struct mit_samba_context *ctx)
      49             : {
      50             :         /* free MIT's krb5_context */
      51          17 :         if (ctx->context) {
      52          17 :                 krb5_free_context(ctx->context);
      53             :         }
      54             : 
      55             :         /* then free everything else */
      56          17 :         talloc_free(ctx);
      57          17 : }
      58             : 
      59             : /*
      60             :  * Implement a callback to log to the MIT KDC log facility
      61             :  *
      62             :  * http://web.mit.edu/kerberos/krb5-devel/doc/plugindev/general.html#logging-from-kdc-and-kadmind-plugin-modules
      63             :  */
      64         128 : static void mit_samba_debug(void *private_ptr, int msg_level, const char *msg)
      65             : {
      66         128 :         int is_error = errno;
      67             : 
      68         128 :         if (msg_level > 0) {
      69          48 :                 is_error = 0;
      70             :         }
      71             : 
      72         128 :         com_err("mitkdc", is_error, "%s", msg);
      73         128 : }
      74             : 
      75          17 : krb5_error_code mit_samba_context_init(struct mit_samba_context **_ctx)
      76             : {
      77             :         NTSTATUS status;
      78             :         struct mit_samba_context *ctx;
      79             :         const char *s4_conf_file;
      80             :         krb5_error_code ret;
      81          17 :         struct samba_kdc_base_context base_ctx = {};
      82             : 
      83          17 :         ctx = talloc_zero(NULL, struct mit_samba_context);
      84          17 :         if (!ctx) {
      85           0 :                 ret = ENOMEM;
      86           0 :                 goto done;
      87             :         }
      88             : 
      89          17 :         base_ctx.ev_ctx = tevent_context_init(ctx);
      90          17 :         if (!base_ctx.ev_ctx) {
      91           0 :                 ret = ENOMEM;
      92           0 :                 goto done;
      93             :         }
      94          17 :         tevent_loop_allow_nesting(base_ctx.ev_ctx);
      95          17 :         base_ctx.lp_ctx = loadparm_init_global(false);
      96          17 :         if (!base_ctx.lp_ctx) {
      97           0 :                 ret = ENOMEM;
      98           0 :                 goto done;
      99             :         }
     100             : 
     101          17 :         debug_set_callback(NULL, mit_samba_debug);
     102             : 
     103             :         /* init s4 configuration */
     104          17 :         s4_conf_file = lpcfg_configfile(base_ctx.lp_ctx);
     105          17 :         if (s4_conf_file != NULL) {
     106          17 :                 char *p = talloc_strdup(ctx, s4_conf_file);
     107          17 :                 if (p == NULL) {
     108           0 :                         ret = ENOMEM;
     109           0 :                         goto done;
     110             :                 }
     111          17 :                 lpcfg_load(base_ctx.lp_ctx, p);
     112          17 :                 TALLOC_FREE(p);
     113             :         } else {
     114           0 :                 lpcfg_load_default(base_ctx.lp_ctx);
     115             :         }
     116             : 
     117          17 :         status = samba_kdc_setup_db_ctx(ctx, &base_ctx, &ctx->db_ctx);
     118          17 :         if (!NT_STATUS_IS_OK(status)) {
     119           0 :                 ret = EINVAL;
     120           0 :                 goto done;
     121             :         }
     122             : 
     123             :         /* init MIT's krb_context and log facilities */
     124          17 :         ret = smb_krb5_init_context_basic(ctx,
     125          17 :                                           ctx->db_ctx->lp_ctx,
     126             :                                           &ctx->context);
     127          17 :         if (ret) {
     128           0 :                 goto done;
     129             :         }
     130             : 
     131          17 :         ret = 0;
     132             : 
     133          17 : done:
     134          17 :         if (ret) {
     135           0 :                 mit_samba_context_free(ctx);
     136             :         } else {
     137          17 :                 *_ctx = ctx;
     138             :         }
     139          17 :         return ret;
     140             : }
     141             : 
     142           0 : int mit_samba_generate_salt(krb5_data *salt)
     143             : {
     144           0 :         if (salt == NULL) {
     145           0 :                 return EINVAL;
     146             :         }
     147             : 
     148           0 :         salt->length = 16;
     149           0 :         salt->data = malloc(salt->length);
     150           0 :         if (salt->data == NULL) {
     151           0 :                 return ENOMEM;
     152             :         }
     153             : 
     154           0 :         generate_random_buffer((uint8_t *)salt->data, salt->length);
     155             : 
     156           0 :         return 0;
     157             : }
     158             : 
     159           0 : int mit_samba_generate_random_password(krb5_data *pwd)
     160             : {
     161             :         TALLOC_CTX *tmp_ctx;
     162             :         char *password;
     163           0 :         char *data = NULL;
     164           0 :         const unsigned length = 24;
     165             : 
     166           0 :         if (pwd == NULL) {
     167           0 :                 return EINVAL;
     168             :         }
     169             : 
     170           0 :         tmp_ctx = talloc_named(NULL,
     171             :                                0,
     172             :                                "mit_samba_generate_random_password context");
     173           0 :         if (tmp_ctx == NULL) {
     174           0 :                 return ENOMEM;
     175             :         }
     176             : 
     177           0 :         password = generate_random_password(tmp_ctx, length, length);
     178           0 :         if (password == NULL) {
     179           0 :                 talloc_free(tmp_ctx);
     180           0 :                 return ENOMEM;
     181             :         }
     182             : 
     183           0 :         data = strdup(password);
     184           0 :         talloc_free(tmp_ctx);
     185           0 :         if (data == NULL) {
     186           0 :                 return ENOMEM;
     187             :         }
     188             : 
     189           0 :         *pwd = smb_krb5_make_data(data, length);
     190             : 
     191           0 :         return 0;
     192             : }
     193             : 
     194          92 : krb5_error_code mit_samba_get_principal(struct mit_samba_context *ctx,
     195             :                                         krb5_const_principal principal,
     196             :                                         unsigned int kflags,
     197             :                                         krb5_db_entry **_kentry)
     198             : {
     199          92 :         struct sdb_entry sentry = {};
     200             :         krb5_db_entry *kentry;
     201             :         krb5_error_code ret;
     202          92 :         uint32_t sflags = 0;
     203          92 :         krb5_principal referral_principal = NULL;
     204             : 
     205          92 :         kentry = calloc(1, sizeof(krb5_db_entry));
     206          92 :         if (kentry == NULL) {
     207           0 :                 return ENOMEM;
     208             :         }
     209             : 
     210             :         /*
     211             :          * The MIT KDC code that wants the canonical name in all lookups, and
     212             :          * takes care to canonicalize only when appropriate.
     213             :          */
     214          92 :         sflags |= SDB_F_FORCE_CANON;
     215             : 
     216          92 :         if (kflags & KRB5_KDB_FLAG_REFERRAL_OK) {
     217           0 :                 sflags |= SDB_F_CANON;
     218             :         }
     219             : 
     220          92 :         if (kflags & KRB5_KDB_FLAG_CLIENT) {
     221           0 :                 sflags |= SDB_F_GET_CLIENT;
     222           0 :                 sflags |= SDB_F_FOR_AS_REQ;
     223             :         } else {
     224          92 :                 int equal = smb_krb5_principal_is_tgs(ctx->context, principal);
     225          92 :                 if (equal == -1) {
     226           0 :                         return ENOMEM;
     227             :                 }
     228             : 
     229          92 :                 if (equal) {
     230           0 :                         sflags |= SDB_F_GET_KRBTGT;
     231             :                 } else {
     232          92 :                         sflags |= SDB_F_GET_SERVER;
     233          92 :                         sflags |= SDB_F_FOR_TGS_REQ;
     234             :                 }
     235             :         }
     236             : 
     237             :         /* always set this or the created_by data will not be populated by samba's
     238             :          * backend and we will fail to parse the entry later */
     239          92 :         sflags |= SDB_F_ADMIN_DATA;
     240             : 
     241             : 
     242          92 : fetch_referral_principal:
     243          92 :         ret = samba_kdc_fetch(ctx->context, ctx->db_ctx,
     244             :                               principal, sflags, 0, &sentry);
     245          92 :         switch (ret) {
     246          92 :         case 0:
     247          92 :                 break;
     248           0 :         case SDB_ERR_NOENTRY:
     249           0 :                 ret = KRB5_KDB_NOENTRY;
     250           0 :                 goto done;
     251           0 :         case SDB_ERR_WRONG_REALM: {
     252           0 :                 char *dest_realm = NULL;
     253           0 :                 const char *our_realm = lpcfg_realm(ctx->db_ctx->lp_ctx);
     254             : 
     255           0 :                 if (sflags & SDB_F_FOR_AS_REQ) {
     256             :                         /*
     257             :                          * If this is a request for a TGT, we are done. The KDC
     258             :                          * will return the correct error to the client.
     259             :                          */
     260           0 :                         ret = 0;
     261           0 :                         break;
     262             :                 }
     263             : 
     264           0 :                 if (referral_principal != NULL) {
     265           0 :                         sdb_entry_free(&sentry);
     266           0 :                         ret = KRB5_KDB_NOENTRY;
     267           0 :                         goto done;
     268             :                 }
     269             : 
     270             :                 /*
     271             :                  * We get a TGS request
     272             :                  *
     273             :                  *     cifs/dc7.SAMBA2008R2.EXAMPLE.COM@ADDOM.SAMBA.EXAMPLE.COM
     274             :                  *
     275             :                  * to our DC for the realm
     276             :                  *
     277             :                  *     ADDOM.SAMBA.EXAMPLE.COM
     278             :                  *
     279             :                  * We look up if we have an entry in the database and get an
     280             :                  * entry with the principal:
     281             :                  *
     282             :                  *     cifs/dc7.SAMBA2008R2.EXAMPLE.COM@SAMBA2008R2.EXAMPLE.COM
     283             :                  *
     284             :                  * and the error: SDB_ERR_WRONG_REALM.
     285             :                  *
     286             :                  * In the case of a TGS-REQ we need to return a referral ticket
     287             :                  * for the next trust hop to the client. This ticket will have
     288             :                  * the following principal:
     289             :                  *
     290             :                  *     krbtgt/SAMBA2008R2.EXAMPLE.COM@ADDOM.SAMBA.EXAMPLE.COM
     291             :                  *
     292             :                  * We just redo the lookup in the database with the referral
     293             :                  * principal and return success.
     294             :                  */
     295           0 :                 dest_realm = smb_krb5_principal_get_realm(
     296           0 :                         ctx, ctx->context, sentry.principal);
     297           0 :                 sdb_entry_free(&sentry);
     298           0 :                 if (dest_realm == NULL) {
     299           0 :                         ret = KRB5_KDB_NOENTRY;
     300           0 :                         goto done;
     301             :                 }
     302             : 
     303           0 :                 ret = smb_krb5_make_principal(ctx->context,
     304             :                                               &referral_principal,
     305             :                                               our_realm,
     306             :                                               KRB5_TGS_NAME,
     307             :                                               dest_realm,
     308             :                                               NULL);
     309           0 :                 TALLOC_FREE(dest_realm);
     310           0 :                 if (ret != 0) {
     311           0 :                         goto done;
     312             :                 }
     313             : 
     314           0 :                 principal = referral_principal;
     315           0 :                 goto fetch_referral_principal;
     316             :         }
     317           0 :         case SDB_ERR_NOT_FOUND_HERE:
     318             :                 /* FIXME: RODC support */
     319             :         default:
     320           0 :                 goto done;
     321             :         }
     322             : 
     323          92 :         ret = sdb_entry_to_krb5_db_entry(ctx->context, &sentry, kentry);
     324             : 
     325          92 :         sdb_entry_free(&sentry);
     326             : 
     327          92 : done:
     328          92 :         krb5_free_principal(ctx->context, referral_principal);
     329          92 :         referral_principal = NULL;
     330             : 
     331          92 :         if (ret) {
     332           0 :                 free(kentry);
     333             :         } else {
     334          92 :                 *_kentry = kentry;
     335             :         }
     336          92 :         return ret;
     337             : }
     338             : 
     339           0 : krb5_error_code mit_samba_get_firstkey(struct mit_samba_context *ctx,
     340             :                                        krb5_db_entry **_kentry)
     341             : {
     342           0 :         struct sdb_entry sentry = {};
     343             :         krb5_db_entry *kentry;
     344             :         krb5_error_code ret;
     345             : 
     346           0 :         kentry = malloc(sizeof(krb5_db_entry));
     347           0 :         if (kentry == NULL) {
     348           0 :                 return ENOMEM;
     349             :         }
     350             : 
     351           0 :         ret = samba_kdc_firstkey(ctx->context, ctx->db_ctx, &sentry);
     352           0 :         switch (ret) {
     353           0 :         case 0:
     354           0 :                 break;
     355           0 :         case SDB_ERR_NOENTRY:
     356           0 :                 free(kentry);
     357           0 :                 return KRB5_KDB_NOENTRY;
     358           0 :         case SDB_ERR_NOT_FOUND_HERE:
     359             :                 /* FIXME: RODC support */
     360             :         default:
     361           0 :                 free(kentry);
     362           0 :                 return ret;
     363             :         }
     364             : 
     365           0 :         ret = sdb_entry_to_krb5_db_entry(ctx->context, &sentry, kentry);
     366             : 
     367           0 :         sdb_entry_free(&sentry);
     368             : 
     369           0 :         if (ret) {
     370           0 :                 free(kentry);
     371             :         } else {
     372           0 :                 *_kentry = kentry;
     373             :         }
     374           0 :         return ret;
     375             : }
     376             : 
     377           0 : krb5_error_code mit_samba_get_nextkey(struct mit_samba_context *ctx,
     378             :                                       krb5_db_entry **_kentry)
     379             : {
     380           0 :         struct sdb_entry sentry = {};
     381             :         krb5_db_entry *kentry;
     382             :         krb5_error_code ret;
     383             : 
     384           0 :         kentry = malloc(sizeof(krb5_db_entry));
     385           0 :         if (kentry == NULL) {
     386           0 :                 return ENOMEM;
     387             :         }
     388             : 
     389           0 :         ret = samba_kdc_nextkey(ctx->context, ctx->db_ctx, &sentry);
     390           0 :         switch (ret) {
     391           0 :         case 0:
     392           0 :                 break;
     393           0 :         case SDB_ERR_NOENTRY:
     394           0 :                 free(kentry);
     395           0 :                 return KRB5_KDB_NOENTRY;
     396           0 :         case SDB_ERR_NOT_FOUND_HERE:
     397             :                 /* FIXME: RODC support */
     398             :         default:
     399           0 :                 free(kentry);
     400           0 :                 return ret;
     401             :         }
     402             : 
     403           0 :         ret = sdb_entry_to_krb5_db_entry(ctx->context, &sentry, kentry);
     404             : 
     405           0 :         sdb_entry_free(&sentry);
     406             : 
     407           0 :         if (ret) {
     408           0 :                 free(kentry);
     409             :         } else {
     410           0 :                 *_kentry = kentry;
     411             :         }
     412           0 :         return ret;
     413             : }
     414             : 
     415           0 : krb5_error_code mit_samba_get_pac(struct mit_samba_context *smb_ctx,
     416             :                                   krb5_context context,
     417             :                                   uint32_t flags,
     418             :                                   krb5_db_entry *client,
     419             :                                   krb5_db_entry *server,
     420             :                                   krb5_keyblock *replaced_reply_key,
     421             :                                   krb5_pac *pac)
     422             : {
     423             :         TALLOC_CTX *tmp_ctx;
     424           0 :         const struct auth_user_info_dc *user_info_dc = NULL;
     425           0 :         struct auth_user_info_dc *user_info_dc_shallow_copy = NULL;
     426           0 :         DATA_BLOB *logon_info_blob = NULL;
     427           0 :         DATA_BLOB *upn_dns_info_blob = NULL;
     428           0 :         DATA_BLOB *cred_ndr = NULL;
     429           0 :         DATA_BLOB **cred_ndr_ptr = NULL;
     430           0 :         DATA_BLOB cred_blob = data_blob_null;
     431           0 :         DATA_BLOB *pcred_blob = NULL;
     432           0 :         DATA_BLOB *pac_attrs_blob = NULL;
     433           0 :         DATA_BLOB *requester_sid_blob = NULL;
     434           0 :         const DATA_BLOB *client_claims_blob = NULL;
     435             :         NTSTATUS nt_status;
     436             :         krb5_error_code code;
     437             :         struct samba_kdc_entry *skdc_entry;
     438           0 :         struct samba_kdc_entry *server_entry = NULL;
     439             :         bool is_krbtgt;
     440             :         /* Only include resource groups in a service ticket. */
     441             :         enum auth_group_inclusion group_inclusion;
     442           0 :         enum samba_asserted_identity asserted_identity =
     443           0 :                 (flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION) ?
     444           0 :                         SAMBA_ASSERTED_IDENTITY_SERVICE :
     445             :                         SAMBA_ASSERTED_IDENTITY_AUTHENTICATION_AUTHORITY;
     446             : 
     447           0 :         if (client == NULL) {
     448           0 :                 return EINVAL;
     449             :         }
     450           0 :         skdc_entry = talloc_get_type_abort(client->e_data,
     451             :                                            struct samba_kdc_entry);
     452             : 
     453           0 :         if (server == NULL) {
     454           0 :                 return EINVAL;
     455             :         }
     456             :         {
     457           0 :                 int result = smb_krb5_principal_is_tgs(smb_ctx->context, server->princ);
     458           0 :                 if (result == -1) {
     459           0 :                         return ENOMEM;
     460             :                 }
     461             : 
     462           0 :                 is_krbtgt = result;
     463             :         }
     464           0 :         server_entry = talloc_get_type_abort(server->e_data,
     465             :                                              struct samba_kdc_entry);
     466             : 
     467             :         /* Only include resource groups in a service ticket. */
     468           0 :         if (is_krbtgt) {
     469           0 :                 group_inclusion = AUTH_EXCLUDE_RESOURCE_GROUPS;
     470           0 :         } else if (server_entry->supported_enctypes & KERB_ENCTYPE_RESOURCE_SID_COMPRESSION_DISABLED) {
     471           0 :                 group_inclusion = AUTH_INCLUDE_RESOURCE_GROUPS;
     472             :         } else {
     473           0 :                 group_inclusion = AUTH_INCLUDE_RESOURCE_GROUPS_COMPRESSED;
     474             :         }
     475             : 
     476           0 :         tmp_ctx = talloc_named(smb_ctx,
     477             :                                0,
     478             :                                "mit_samba_get_pac context");
     479           0 :         if (tmp_ctx == NULL) {
     480           0 :                 return ENOMEM;
     481             :         }
     482             : 
     483             :         /* Check if we have a PREAUTH key */
     484           0 :         if (replaced_reply_key != NULL) {
     485           0 :                 cred_ndr_ptr = &cred_ndr;
     486             :         }
     487             : 
     488           0 :         code = samba_kdc_get_user_info_from_db(tmp_ctx,
     489           0 :                                                server_entry->kdc_db_ctx->samdb,
     490             :                                                skdc_entry,
     491           0 :                                                skdc_entry->msg,
     492             :                                                &user_info_dc);
     493           0 :         if (code) {
     494           0 :                 talloc_free(tmp_ctx);
     495           0 :                 return code;
     496             :         }
     497             : 
     498             :         /* Make a shallow copy of the user_info_dc structure. */
     499           0 :         nt_status = authsam_shallow_copy_user_info_dc(tmp_ctx,
     500             :                                                       user_info_dc,
     501             :                                                       &user_info_dc_shallow_copy);
     502           0 :         user_info_dc = NULL;
     503             : 
     504           0 :         if (!NT_STATUS_IS_OK(nt_status)) {
     505           0 :                 DBG_ERR("Failed to allocate shallow copy of user_info_dc: %s\n",
     506             :                         nt_errstr(nt_status));
     507           0 :                 talloc_free(tmp_ctx);
     508           0 :                 return map_errno_from_nt_status(nt_status);
     509             :         }
     510             : 
     511             : 
     512           0 :         nt_status = samba_kdc_add_asserted_identity(asserted_identity,
     513             :                                                     user_info_dc_shallow_copy);
     514           0 :         if (!NT_STATUS_IS_OK(nt_status)) {
     515           0 :                 DBG_ERR("Failed to add asserted identity: %s\n",
     516             :                         nt_errstr(nt_status));
     517           0 :                 talloc_free(tmp_ctx);
     518           0 :                 return EINVAL;
     519             :         }
     520             : 
     521           0 :         nt_status = samba_kdc_add_claims_valid(user_info_dc_shallow_copy);
     522           0 :         if (!NT_STATUS_IS_OK(nt_status)) {
     523           0 :                 DBG_ERR("Failed to add Claims Valid: %s\n",
     524             :                         nt_errstr(nt_status));
     525           0 :                 talloc_free(tmp_ctx);
     526           0 :                 return EINVAL;
     527             :         }
     528             : 
     529             :         /* We no longer need to modify this, so assign to const variable */
     530           0 :         user_info_dc = user_info_dc_shallow_copy;
     531             : 
     532           0 :         nt_status = samba_kdc_get_logon_info_blob(tmp_ctx,
     533             :                                                   user_info_dc,
     534             :                                                   group_inclusion,
     535             :                                                   &logon_info_blob);
     536           0 :         if (!NT_STATUS_IS_OK(nt_status)) {
     537           0 :                 talloc_free(tmp_ctx);
     538           0 :                 return EINVAL;
     539             :         }
     540             : 
     541           0 :         if (cred_ndr_ptr != NULL) {
     542           0 :                 nt_status = samba_kdc_get_cred_ndr_blob(tmp_ctx,
     543             :                                                         skdc_entry,
     544             :                                                         cred_ndr_ptr);
     545           0 :                 if (!NT_STATUS_IS_OK(nt_status)) {
     546           0 :                         talloc_free(tmp_ctx);
     547           0 :                         return EINVAL;
     548             :                 }
     549             :         }
     550             : 
     551           0 :         nt_status = samba_kdc_get_upn_info_blob(tmp_ctx,
     552             :                                                 user_info_dc,
     553             :                                                 &upn_dns_info_blob);
     554           0 :         if (!NT_STATUS_IS_OK(nt_status)) {
     555           0 :                 talloc_free(tmp_ctx);
     556           0 :                 return EINVAL;
     557             :         }
     558             : 
     559           0 :         if (is_krbtgt) {
     560           0 :                 nt_status = samba_kdc_get_pac_attrs_blob(tmp_ctx,
     561             :                                                          PAC_ATTRIBUTE_FLAG_PAC_WAS_GIVEN_IMPLICITLY,
     562             :                                                          &pac_attrs_blob);
     563           0 :                 if (!NT_STATUS_IS_OK(nt_status)) {
     564           0 :                         talloc_free(tmp_ctx);
     565           0 :                         return EINVAL;
     566             :                 }
     567             : 
     568           0 :                 nt_status = samba_kdc_get_requester_sid_blob(tmp_ctx,
     569             :                                                              user_info_dc,
     570             :                                                              &requester_sid_blob);
     571           0 :                 if (!NT_STATUS_IS_OK(nt_status)) {
     572           0 :                         talloc_free(tmp_ctx);
     573           0 :                         return EINVAL;
     574             :                 }
     575             :         }
     576             : 
     577           0 :         nt_status = samba_kdc_get_claims_blob(tmp_ctx,
     578             :                                               skdc_entry,
     579             :                                               &client_claims_blob);
     580           0 :         if (!NT_STATUS_IS_OK(nt_status)) {
     581           0 :                 talloc_free(tmp_ctx);
     582           0 :                 return EINVAL;
     583             :         }
     584             : 
     585           0 :         if (replaced_reply_key != NULL && cred_ndr != NULL) {
     586           0 :                 code = samba_kdc_encrypt_pac_credentials(context,
     587             :                                                          replaced_reply_key,
     588             :                                                          cred_ndr,
     589             :                                                          tmp_ctx,
     590             :                                                          &cred_blob);
     591           0 :                 if (code != 0) {
     592           0 :                         talloc_free(tmp_ctx);
     593           0 :                         return code;
     594             :                 }
     595           0 :                 pcred_blob = &cred_blob;
     596             :         }
     597             : 
     598           0 :         code = samba_make_krb5_pac(context,
     599             :                                    logon_info_blob,
     600             :                                    pcred_blob,
     601             :                                    upn_dns_info_blob,
     602             :                                    pac_attrs_blob,
     603             :                                    requester_sid_blob,
     604             :                                    NULL /* deleg_blob */,
     605             :                                    client_claims_blob,
     606             :                                    NULL /* device_info_blob */,
     607             :                                    NULL /* device_claims_blob */,
     608             :                                    *pac);
     609             : 
     610           0 :         talloc_free(tmp_ctx);
     611           0 :         return code;
     612             : }
     613             : 
     614           0 : krb5_error_code mit_samba_update_pac(struct mit_samba_context *ctx,
     615             :                                     krb5_context context,
     616             :                                     int kdc_flags,
     617             :                                     krb5_db_entry *client,
     618             :                                     krb5_db_entry *server,
     619             :                                     krb5_db_entry *krbtgt,
     620             :                                     krb5_pac old_pac,
     621             :                                     krb5_pac new_pac)
     622             : {
     623           0 :         TALLOC_CTX *tmp_ctx = NULL;
     624             :         krb5_error_code code;
     625           0 :         struct samba_kdc_entry *client_skdc_entry = NULL;
     626           0 :         struct samba_kdc_entry *server_skdc_entry = NULL;
     627           0 :         struct samba_kdc_entry *krbtgt_skdc_entry = NULL;
     628           0 :         struct samba_kdc_entry_pac client_pac_entry = {};
     629           0 :         bool is_in_db = false;
     630           0 :         bool is_trusted = false;
     631           0 :         uint32_t flags = 0;
     632             : 
     633             :         /* Create a memory context early so code can use talloc_stackframe() */
     634           0 :         tmp_ctx = talloc_named(ctx, 0, "mit_samba_update_pac context");
     635           0 :         if (tmp_ctx == NULL) {
     636           0 :                 return ENOMEM;
     637             :         }
     638             : 
     639           0 :         if (client != NULL) {
     640             :                 client_skdc_entry =
     641           0 :                         talloc_get_type_abort(client->e_data,
     642             :                                               struct samba_kdc_entry);
     643             :         }
     644             : 
     645           0 :         if (krbtgt == NULL) {
     646           0 :                 code = EINVAL;
     647           0 :                 goto done;
     648             :         }
     649             :         krbtgt_skdc_entry =
     650           0 :                 talloc_get_type_abort(krbtgt->e_data,
     651             :                                       struct samba_kdc_entry);
     652             : 
     653           0 :         if (server == NULL) {
     654           0 :                 code = EINVAL;
     655           0 :                 goto done;
     656             :         }
     657             :         server_skdc_entry =
     658           0 :                 talloc_get_type_abort(server->e_data,
     659             :                                       struct samba_kdc_entry);
     660             : 
     661             :         /*
     662             :          * If the krbtgt was generated by an RODC, and we are not that
     663             :          * RODC, then we need to regenerate the PAC - we can't trust
     664             :          * it, and confirm that the RODC was permitted to print this ticket
     665             :          *
     666             :          * Because of the samba_kdc_validate_pac_blob() step we can be
     667             :          * sure that the record in 'client' or 'server' matches the SID in the
     668             :          * original PAC.
     669             :          */
     670           0 :         code = samba_krbtgt_is_in_db(krbtgt_skdc_entry,
     671             :                                      &is_in_db,
     672             :                                      &is_trusted);
     673           0 :         if (code != 0) {
     674           0 :                 goto done;
     675             :         }
     676             : 
     677           0 :         if (kdc_flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION) {
     678           0 :                 flags |= SAMBA_KDC_FLAG_PROTOCOL_TRANSITION;
     679             :         }
     680             : 
     681           0 :         if (kdc_flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION) {
     682           0 :                 flags |= SAMBA_KDC_FLAG_CONSTRAINED_DELEGATION;
     683             :         }
     684             : 
     685           0 :         client_pac_entry = samba_kdc_entry_pac_from_trusted(old_pac,
     686             :                                                             client_skdc_entry,
     687           0 :                                                             samba_kdc_entry_is_trust(krbtgt_skdc_entry),
     688             :                                                             is_trusted);
     689             : 
     690           0 :         code = samba_kdc_verify_pac(tmp_ctx,
     691             :                                     context,
     692           0 :                                     krbtgt_skdc_entry->kdc_db_ctx->samdb,
     693             :                                     flags,
     694             :                                     client_pac_entry,
     695             :                                     krbtgt_skdc_entry);
     696           0 :         if (code != 0) {
     697           0 :                 goto done;
     698             :         }
     699             : 
     700           0 :         code = samba_kdc_update_pac(tmp_ctx,
     701             :                                     context,
     702           0 :                                     krbtgt_skdc_entry->kdc_db_ctx->samdb,
     703           0 :                                     krbtgt_skdc_entry->kdc_db_ctx->lp_ctx,
     704             :                                     flags,
     705             :                                     client_pac_entry,
     706           0 :                                     server->princ,
     707             :                                     server_skdc_entry,
     708             :                                     NULL /* delegated_proxy_principal */,
     709           0 :                                     (struct samba_kdc_entry_pac) {} /* delegated_proxy */,
     710           0 :                                     (struct samba_kdc_entry_pac) {} /* device */,
     711             :                                     new_pac,
     712             :                                     NULL /* server_audit_info_out */,
     713             :                                     NULL /* status_out */);
     714           0 :         if (code != 0) {
     715           0 :                 if (code == ENOATTR) {
     716             :                         /*
     717             :                          * We can't tell the KDC to not issue a PAC. It will
     718             :                          * just return the newly allocated empty PAC.
     719             :                          */
     720           0 :                         code = 0;
     721             :                 }
     722             :         }
     723             : 
     724           0 : done:
     725           0 :         talloc_free(tmp_ctx);
     726           0 :         return code;
     727             : }
     728             : 
     729             : /* provide header, function is exported but there are no public headers */
     730             : 
     731             : krb5_error_code encode_krb5_padata_sequence(krb5_pa_data *const *rep, krb5_data **code);
     732             : 
     733             : /* this function allocates 'data' using malloc.
     734             :  * The caller is responsible for freeing it */
     735           0 : static void samba_kdc_build_edata_reply(NTSTATUS nt_status, DATA_BLOB *e_data)
     736             : {
     737           0 :         krb5_error_code ret = 0;
     738             :         krb5_pa_data pa, *ppa[2];
     739           0 :         krb5_data *d = NULL;
     740             : 
     741           0 :         if (!e_data)
     742           0 :                 return;
     743             : 
     744           0 :         e_data->data   = NULL;
     745           0 :         e_data->length = 0;
     746             : 
     747           0 :         pa.magic                = KV5M_PA_DATA;
     748           0 :         pa.pa_type              = KRB5_PADATA_PW_SALT /* KERB_ERR_TYPE_EXTENDED */;
     749           0 :         pa.length               = 12;
     750           0 :         pa.contents             = malloc(pa.length);
     751           0 :         if (!pa.contents) {
     752           0 :                 return;
     753             :         }
     754             : 
     755           0 :         SIVAL(pa.contents, 0, NT_STATUS_V(nt_status));
     756           0 :         SIVAL(pa.contents, 4, 0);
     757           0 :         SIVAL(pa.contents, 8, 1);
     758             : 
     759           0 :         ppa[0] = &pa;
     760           0 :         ppa[1] = NULL;
     761             : 
     762           0 :         ret = encode_krb5_padata_sequence(ppa, &d);
     763           0 :         free(pa.contents);
     764           0 :         if (ret) {
     765           0 :                 return;
     766             :         }
     767             : 
     768           0 :         e_data->data   = (uint8_t *)d->data;
     769           0 :         e_data->length = d->length;
     770             : 
     771             :         /* free d, not d->data - gd */
     772           0 :         free(d);
     773             : 
     774           0 :         return;
     775             : }
     776             : 
     777           0 : krb5_error_code mit_samba_check_client_access(struct mit_samba_context *ctx,
     778             :                                               krb5_db_entry *client,
     779             :                                               const char *client_name,
     780             :                                               krb5_db_entry *server,
     781             :                                               const char *server_name,
     782             :                                               const char *netbios_name,
     783             :                                               bool password_change,
     784             :                                               DATA_BLOB *e_data)
     785             : {
     786             :         struct samba_kdc_entry *skdc_entry;
     787             :         NTSTATUS nt_status;
     788             : 
     789           0 :         skdc_entry = talloc_get_type(client->e_data, struct samba_kdc_entry);
     790             : 
     791           0 :         nt_status = samba_kdc_check_client_access(skdc_entry,
     792             :                                                   client_name,
     793             :                                                   netbios_name,
     794             :                                                   password_change);
     795             : 
     796           0 :         if (!NT_STATUS_IS_OK(nt_status)) {
     797           0 :                 if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_MEMORY)) {
     798           0 :                         return ENOMEM;
     799             :                 }
     800             : 
     801           0 :                 samba_kdc_build_edata_reply(nt_status, e_data);
     802             : 
     803           0 :                 return samba_kdc_map_policy_err(nt_status);
     804             :         }
     805             : 
     806           0 :         return 0;
     807             : }
     808             : 
     809           0 : krb5_error_code mit_samba_check_s4u2proxy(struct mit_samba_context *ctx,
     810             :                                           const krb5_db_entry *server,
     811             :                                           krb5_const_principal target_principal)
     812             : {
     813             :         struct samba_kdc_entry *server_skdc_entry =
     814           0 :                 talloc_get_type_abort(server->e_data, struct samba_kdc_entry);
     815             :         krb5_error_code code;
     816             : 
     817           0 :         code = samba_kdc_check_s4u2proxy(ctx->context,
     818             :                                          ctx->db_ctx,
     819             :                                          server_skdc_entry,
     820             :                                          target_principal);
     821             : 
     822           0 :         return code;
     823             : }
     824             : 
     825           0 : krb5_error_code mit_samba_check_allowed_to_delegate_from(
     826             :                 struct mit_samba_context *ctx,
     827             :                 krb5_const_principal client_principal,
     828             :                 krb5_const_principal server_principal,
     829             :                 krb5_pac header_pac,
     830             :                 const krb5_db_entry *proxy)
     831             : {
     832             :         struct samba_kdc_entry *proxy_skdc_entry =
     833           0 :                 talloc_get_type_abort(proxy->e_data, struct samba_kdc_entry);
     834           0 :         struct auth_user_info_dc *user_info_dc = NULL;
     835           0 :         TALLOC_CTX *mem_ctx = NULL;
     836             :         krb5_error_code code;
     837             : 
     838           0 :         mem_ctx = talloc_new(NULL);
     839           0 :         if (mem_ctx == NULL) {
     840           0 :                 return ENOMEM;
     841             :         }
     842             : 
     843             :         /*
     844             :          * FIXME: If ever we support RODCs, we must check that the PAC has not
     845             :          * been issued by an RODC (other than ourselves) — otherwise the PAC
     846             :          * cannot be trusted. Because the plugin interface does not give us the
     847             :          * client entry, we cannot look up its groups in the database.
     848             :          */
     849           0 :         code = kerberos_pac_to_user_info_dc(mem_ctx,
     850             :                                             header_pac,
     851             :                                             ctx->context,
     852             :                                             &user_info_dc,
     853             :                                             AUTH_INCLUDE_RESOURCE_GROUPS,
     854             :                                             NULL,
     855             :                                             NULL,
     856             :                                             NULL);
     857           0 :         if (code != 0) {
     858           0 :                 goto out;
     859             :         }
     860             : 
     861           0 :         code = samba_kdc_check_s4u2proxy_rbcd(ctx->context,
     862             :                                               ctx->db_ctx,
     863             :                                               client_principal,
     864             :                                               server_principal,
     865             :                                               user_info_dc,
     866             :                                               NULL /* device_info_dc */,
     867           0 :                                               (struct auth_claims) {},
     868             :                                               proxy_skdc_entry);
     869           0 : out:
     870           0 :         talloc_free(mem_ctx);
     871           0 :         return code;
     872             : }
     873             : 
     874           0 : static krb5_error_code mit_samba_change_pwd_error(krb5_context context,
     875             :                                                   NTSTATUS result,
     876             :                                                   enum samPwdChangeReason reject_reason,
     877             :                                                   struct samr_DomInfo1 *dominfo)
     878             : {
     879           0 :         krb5_error_code code = KADM5_PASS_Q_GENERIC;
     880             : 
     881           0 :         if (NT_STATUS_EQUAL(result, NT_STATUS_NO_SUCH_USER)) {
     882           0 :                 code = KADM5_BAD_PRINCIPAL;
     883           0 :                 krb5_set_error_message(context,
     884             :                                        code,
     885             :                                        "No such user when changing password");
     886             :         }
     887           0 :         if (NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED)) {
     888           0 :                 code = KADM5_PASS_Q_GENERIC;
     889           0 :                 krb5_set_error_message(context,
     890             :                                        code,
     891             :                                        "Not permitted to change password");
     892             :         }
     893           0 :         if (NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_RESTRICTION) &&
     894             :             dominfo != NULL) {
     895           0 :                 switch (reject_reason) {
     896           0 :                 case SAM_PWD_CHANGE_PASSWORD_TOO_SHORT:
     897           0 :                         code = KADM5_PASS_Q_TOOSHORT;
     898           0 :                         krb5_set_error_message(context,
     899             :                                                code,
     900             :                                                "Password too short, password "
     901             :                                                "must be at least %d characters "
     902             :                                                "long.",
     903           0 :                                                dominfo->min_password_length);
     904           0 :                         break;
     905           0 :                 case SAM_PWD_CHANGE_NOT_COMPLEX:
     906           0 :                         code = KADM5_PASS_Q_DICT;
     907           0 :                         krb5_set_error_message(context,
     908             :                                                code,
     909             :                                                "Password does not meet "
     910             :                                                "complexity requirements");
     911           0 :                         break;
     912           0 :                 case SAM_PWD_CHANGE_PWD_IN_HISTORY:
     913           0 :                         code = KADM5_PASS_TOOSOON;
     914           0 :                         krb5_set_error_message(context,
     915             :                                                code,
     916             :                                                "Password is already in password "
     917             :                                                "history. New password must not "
     918             :                                                "match any of your %d previous "
     919             :                                                "passwords.",
     920           0 :                                                dominfo->password_history_length);
     921           0 :                         break;
     922           0 :                 default:
     923           0 :                         code = KADM5_PASS_Q_GENERIC;
     924           0 :                         krb5_set_error_message(context,
     925             :                                                code,
     926             :                                                "Password change rejected, "
     927             :                                                "password changes may not be "
     928             :                                                "permitted on this account, or "
     929             :                                                "the minimum password age may "
     930             :                                                "not have elapsed.");
     931           0 :                         break;
     932             :                 }
     933             :         }
     934             : 
     935           0 :         return code;
     936             : }
     937             : 
     938           0 : krb5_error_code mit_samba_kpasswd_change_password(struct mit_samba_context *ctx,
     939             :                                                   char *pwd,
     940             :                                                   krb5_db_entry *db_entry)
     941             : {
     942             :         NTSTATUS status;
     943           0 :         NTSTATUS result = NT_STATUS_UNSUCCESSFUL;
     944             :         TALLOC_CTX *tmp_ctx;
     945             :         DATA_BLOB password;
     946             :         enum samPwdChangeReason reject_reason;
     947             :         struct samr_DomInfo1 *dominfo;
     948           0 :         const char *error_string = NULL;
     949           0 :         const struct auth_user_info_dc *user_info_dc = NULL;
     950             :         struct samba_kdc_entry *p =
     951           0 :                 talloc_get_type_abort(db_entry->e_data, struct samba_kdc_entry);
     952           0 :         krb5_error_code code = 0;
     953             : 
     954             : #ifdef DEBUG_PASSWORD
     955           0 :         DBG_WARNING("mit_samba_kpasswd_change_password called with: %s\n", pwd);
     956             : #endif
     957             : 
     958           0 :         tmp_ctx = talloc_named(ctx, 0, "mit_samba_kpasswd_change_password");
     959           0 :         if (tmp_ctx == NULL) {
     960           0 :                 return ENOMEM;
     961             :         }
     962             : 
     963           0 :         code = samba_kdc_get_user_info_from_db(tmp_ctx,
     964           0 :                                                ctx->db_ctx->samdb,
     965             :                                                p,
     966           0 :                                                p->msg,
     967             :                                                &user_info_dc);
     968           0 :         if (code) {
     969           0 :                 const char *krb5err = krb5_get_error_message(ctx->context, code);
     970           0 :                 DBG_WARNING("samba_kdc_get_user_info_from_db failed: %s\n",
     971             :                         krb5err != NULL ? krb5err : "<unknown>");
     972           0 :                 krb5_free_error_message(ctx->context, krb5err);
     973             : 
     974           0 :                 goto out;
     975             :         }
     976             : 
     977           0 :         status = auth_generate_session_info(tmp_ctx,
     978           0 :                                             ctx->db_ctx->lp_ctx,
     979           0 :                                             ctx->db_ctx->samdb,
     980             :                                             user_info_dc,
     981             :                                             0, /* session_info_flags */
     982             :                                             &ctx->session_info);
     983             : 
     984           0 :         if (!NT_STATUS_IS_OK(status)) {
     985           0 :                 DBG_WARNING("auth_generate_session_info failed: %s\n",
     986             :                             nt_errstr(status));
     987           0 :                 code = EINVAL;
     988           0 :                 goto out;
     989             :         }
     990             : 
     991             :         /* password is expected as UTF16 */
     992             : 
     993           0 :         if (!convert_string_talloc(tmp_ctx, CH_UTF8, CH_UTF16,
     994             :                                    pwd, strlen(pwd),
     995             :                                    &password.data, &password.length)) {
     996           0 :                 DBG_WARNING("convert_string_talloc failed\n");
     997           0 :                 code = EINVAL;
     998           0 :                 goto out;
     999             :         }
    1000             : 
    1001           0 :         status = samdb_kpasswd_change_password(tmp_ctx,
    1002           0 :                                                ctx->db_ctx->lp_ctx,
    1003           0 :                                                ctx->db_ctx->ev_ctx,
    1004             :                                                ctx->session_info,
    1005             :                                                &password,
    1006             :                                                &reject_reason,
    1007             :                                                &dominfo,
    1008             :                                                &error_string,
    1009             :                                                &result);
    1010           0 :         if (!NT_STATUS_IS_OK(status)) {
    1011           0 :                 DBG_WARNING("samdb_kpasswd_change_password failed: %s\n",
    1012             :                             nt_errstr(status));
    1013           0 :                 code = KADM5_PASS_Q_GENERIC;
    1014           0 :                 krb5_set_error_message(ctx->context, code, "%s", error_string);
    1015           0 :                 goto out;
    1016             :         }
    1017             : 
    1018           0 :         if (!NT_STATUS_IS_OK(result)) {
    1019           0 :                 code = mit_samba_change_pwd_error(ctx->context,
    1020             :                                                   result,
    1021             :                                                   reject_reason,
    1022             :                                                   dominfo);
    1023             :         }
    1024             : 
    1025           0 : out:
    1026           0 :         talloc_free(tmp_ctx);
    1027             : 
    1028           0 :         return code;
    1029             : }
    1030             : 
    1031           0 : void mit_samba_zero_bad_password_count(krb5_db_entry *db_entry)
    1032             : {
    1033             :         /* struct netr_SendToSamBase *send_to_sam = NULL; */
    1034             :         struct samba_kdc_entry *p =
    1035           0 :                 talloc_get_type_abort(db_entry->e_data, struct samba_kdc_entry);
    1036             :         struct ldb_dn *domain_dn;
    1037             : 
    1038           0 :         domain_dn = ldb_get_default_basedn(p->kdc_db_ctx->samdb);
    1039             : 
    1040           0 :         authsam_logon_success_accounting(p->kdc_db_ctx->samdb,
    1041           0 :                                          p->msg,
    1042             :                                          domain_dn,
    1043             :                                          true,
    1044             :                                          NULL, NULL);
    1045             :         /* TODO: RODC support */
    1046           0 : }
    1047             : 
    1048             : 
    1049           0 : void mit_samba_update_bad_password_count(krb5_db_entry *db_entry)
    1050             : {
    1051             :         struct samba_kdc_entry *p =
    1052           0 :                 talloc_get_type_abort(db_entry->e_data, struct samba_kdc_entry);
    1053             : 
    1054           0 :         authsam_update_bad_pwd_count(p->kdc_db_ctx->samdb,
    1055             :                                      p->msg,
    1056           0 :                                      ldb_get_default_basedn(p->kdc_db_ctx->samdb));
    1057           0 : }
    1058             : 
    1059           0 : bool mit_samba_princ_needs_pac(krb5_db_entry *db_entry)
    1060             : {
    1061             :         struct samba_kdc_entry *skdc_entry =
    1062           0 :                 talloc_get_type_abort(db_entry->e_data, struct samba_kdc_entry);
    1063             : 
    1064           0 :         return samba_princ_needs_pac(skdc_entry);
    1065             : }

Generated by: LCOV version 1.14