LCOV - code coverage report
Current view: top level - source4/kdc - mit_samba.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 63 390 16.2 %
Date: 2024-06-13 04:01:37 Functions: 4 20 20.0 %

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

Generated by: LCOV version 1.13