LCOV - code coverage report
Current view: top level - source4/kdc/mit-kdb - kdb_samba_principals.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 21 168 12.5 %
Date: 2024-02-28 12:06:22 Functions: 3 11 27.3 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Samba KDB plugin for MIT Kerberos
       5             : 
       6             :    Copyright (c) 2010      Simo Sorce <idra@samba.org>.
       7             :    Copyright (c) 2014      Andreas Schneider <asn@samba.org>
       8             : 
       9             :    This program is free software; you can redistribute it and/or modify
      10             :    it under the terms of the GNU General Public License as published by
      11             :    the Free Software Foundation; either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    This program is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU General Public License
      20             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      21             : */
      22             : 
      23             : #include "includes.h"
      24             : 
      25             : #include "system/kerberos.h"
      26             : 
      27             : #include <profile.h>
      28             : #include <kdb.h>
      29             : 
      30             : #include "kdc/samba_kdc.h"
      31             : #include "kdc/mit_samba.h"
      32             : #include "kdb_samba.h"
      33             : 
      34             : #undef DBGC_CLASS
      35             : #define DBGC_CLASS DBGC_KERBEROS
      36             : 
      37             : #define ADMIN_LIFETIME 60*60*3 /* 3 hours */
      38             : 
      39          92 : krb5_error_code ks_get_principal(krb5_context context,
      40             :                                  krb5_const_principal principal,
      41             :                                  unsigned int kflags,
      42             :                                  krb5_db_entry **kentry)
      43             : {
      44             :         struct mit_samba_context *mit_ctx;
      45             :         krb5_error_code code;
      46             : 
      47          92 :         mit_ctx = ks_get_context(context);
      48          92 :         if (mit_ctx == NULL) {
      49           0 :                 return KRB5_KDB_DBNOTINITED;
      50             :         }
      51             : 
      52          92 :         code = mit_samba_get_principal(mit_ctx,
      53             :                                        principal,
      54             :                                        kflags,
      55             :                                        kentry);
      56          92 :         if (code != 0) {
      57           0 :                 goto cleanup;
      58             :         }
      59             : 
      60          92 : cleanup:
      61             : 
      62          92 :         return code;
      63             : }
      64             : 
      65           0 : static void ks_free_principal_e_data(krb5_context context, krb5_octet *e_data)
      66             : {
      67             :         struct samba_kdc_entry *skdc_entry;
      68             : 
      69           0 :         skdc_entry = talloc_get_type_abort(e_data,
      70             :                                            struct samba_kdc_entry);
      71           0 :         skdc_entry->kdc_entry = NULL;
      72           0 :         TALLOC_FREE(skdc_entry);
      73           0 : }
      74             : 
      75           0 : void ks_free_principal(krb5_context context, krb5_db_entry *entry)
      76             : {
      77           0 :         krb5_tl_data *tl_data_next = NULL;
      78           0 :         krb5_tl_data *tl_data = NULL;
      79             :         size_t i, j;
      80             : 
      81           0 :         if (entry != NULL) {
      82           0 :                 krb5_free_principal(context, entry->princ);
      83             : 
      84           0 :                 for (tl_data = entry->tl_data; tl_data; tl_data = tl_data_next) {
      85           0 :                         tl_data_next = tl_data->tl_data_next;
      86           0 :                         if (tl_data->tl_data_contents != NULL) {
      87           0 :                                 free(tl_data->tl_data_contents);
      88             :                         }
      89           0 :                         free(tl_data);
      90             :                 }
      91             : 
      92           0 :                 if (entry->key_data != NULL) {
      93           0 :                         for (i = 0; i < entry->n_key_data; i++) {
      94           0 :                                 for (j = 0; j < entry->key_data[i].key_data_ver; j++) {
      95           0 :                                         if (entry->key_data[i].key_data_length[j] != 0) {
      96           0 :                                                 if (entry->key_data[i].key_data_contents[j] != NULL) {
      97           0 :                                                         memset(entry->key_data[i].key_data_contents[j], 0, entry->key_data[i].key_data_length[j]);
      98           0 :                                                         free(entry->key_data[i].key_data_contents[j]);
      99             :                                                 }
     100             :                                         }
     101           0 :                                         entry->key_data[i].key_data_contents[j] = NULL;
     102           0 :                                          entry->key_data[i].key_data_length[j] = 0;
     103           0 :                                          entry->key_data[i].key_data_type[j] = 0;
     104             :                                 }
     105             :                         }
     106           0 :                         free(entry->key_data);
     107             :                 }
     108             : 
     109           0 :                 if (entry->e_data) {
     110           0 :                         ks_free_principal_e_data(context, entry->e_data);
     111             :                 }
     112             : 
     113           0 :                 free(entry);
     114             :         }
     115           0 : }
     116             : 
     117          92 : static krb5_boolean ks_is_master_key_principal(krb5_context context,
     118             :                                                krb5_const_principal princ)
     119             : {
     120          92 :         return krb5_princ_size(context, princ) == 2 &&
     121         184 :                ks_data_eq_string(princ->data[0], "K") &&
     122           0 :                ks_data_eq_string(princ->data[1], "M");
     123             : }
     124             : 
     125           0 : static krb5_error_code ks_get_master_key_principal(krb5_context context,
     126             :                                                    krb5_const_principal princ,
     127             :                                                    krb5_db_entry **kentry_ptr)
     128             : {
     129             :         krb5_error_code code;
     130             :         krb5_key_data *key_data;
     131             :         krb5_timestamp now;
     132             :         krb5_db_entry *kentry;
     133             : 
     134           0 :         *kentry_ptr = NULL;
     135             : 
     136           0 :         kentry = calloc(1, sizeof(krb5_db_entry));
     137           0 :         if (kentry == NULL) {
     138           0 :                 return ENOMEM;
     139             :         }
     140             : 
     141           0 :         kentry->magic = KRB5_KDB_MAGIC_NUMBER;
     142           0 :         kentry->len = KRB5_KDB_V1_BASE_LENGTH;
     143           0 :         kentry->attributes = KRB5_KDB_DISALLOW_ALL_TIX;
     144             : 
     145           0 :         if (princ == NULL) {
     146           0 :                 code = krb5_parse_name(context, KRB5_KDB_M_NAME, &kentry->princ);
     147             :         } else {
     148           0 :                 code = krb5_copy_principal(context, princ, &kentry->princ);
     149             :         }
     150           0 :         if (code != 0) {
     151           0 :                 krb5_db_free_principal(context, kentry);
     152           0 :                 return code;
     153             :         }
     154             : 
     155           0 :         now = time(NULL);
     156             : 
     157           0 :         code = krb5_dbe_update_mod_princ_data(context, kentry, now, kentry->princ);
     158           0 :         if (code != 0) {
     159           0 :                 krb5_db_free_principal(context, kentry);
     160           0 :                 return code;
     161             :         }
     162             : 
     163             :         /* Return a dummy key */
     164           0 :         kentry->n_key_data = 1;
     165           0 :         kentry->key_data = calloc(1, sizeof(krb5_key_data));
     166           0 :         if (code != 0) {
     167           0 :                 krb5_db_free_principal(context, kentry);
     168           0 :                 return code;
     169             :         }
     170             : 
     171           0 :         key_data = &kentry->key_data[0];
     172             : 
     173           0 :         key_data->key_data_ver          = KRB5_KDB_V1_KEY_DATA_ARRAY;
     174           0 :         key_data->key_data_kvno         = 1;
     175           0 :         key_data->key_data_type[0]      = ENCTYPE_UNKNOWN;
     176           0 :         if (code != 0) {
     177           0 :                 krb5_db_free_principal(context, kentry);
     178           0 :                 return code;
     179             :         }
     180             : 
     181           0 :         *kentry_ptr = kentry;
     182             : 
     183           0 :         return 0;
     184             : }
     185             : 
     186           0 : static krb5_error_code ks_create_principal(krb5_context context,
     187             :                                            krb5_const_principal princ,
     188             :                                            int attributes,
     189             :                                            int max_life,
     190             :                                            const char *password,
     191             :                                            krb5_db_entry **kentry_ptr)
     192             : {
     193             :         krb5_error_code code;
     194             :         krb5_key_data *key_data;
     195             :         krb5_timestamp now;
     196             :         krb5_db_entry *kentry;
     197             :         krb5_keyblock key;
     198             :         krb5_data salt;
     199             :         krb5_data pwd;
     200           0 :         int enctype = ENCTYPE_AES256_CTS_HMAC_SHA1_96;
     201           0 :         int sts = KRB5_KDB_SALTTYPE_SPECIAL;
     202             : 
     203           0 :         if (princ == NULL) {
     204           0 :                 return KRB5_KDB_NOENTRY;
     205             :         }
     206             : 
     207           0 :         *kentry_ptr = NULL;
     208             : 
     209           0 :         kentry = calloc(1, sizeof(krb5_db_entry));
     210           0 :         if (kentry == NULL) {
     211           0 :                 return ENOMEM;
     212             :         }
     213             : 
     214           0 :         kentry->magic = KRB5_KDB_MAGIC_NUMBER;
     215           0 :         kentry->len = KRB5_KDB_V1_BASE_LENGTH;
     216             : 
     217           0 :         if (attributes > 0) {
     218           0 :                 kentry->attributes = attributes;
     219             :         }
     220             : 
     221           0 :         if (max_life > 0) {
     222           0 :                 kentry->max_life = max_life;
     223             :         }
     224             : 
     225           0 :         code = krb5_copy_principal(context, princ, &kentry->princ);
     226           0 :         if (code != 0) {
     227           0 :                 krb5_db_free_principal(context, kentry);
     228           0 :                 return code;
     229             :         }
     230             : 
     231           0 :         now = time(NULL);
     232             : 
     233           0 :         code = krb5_dbe_update_mod_princ_data(context, kentry, now, kentry->princ);
     234           0 :         if (code != 0) {
     235           0 :                 krb5_db_free_principal(context, kentry);
     236           0 :                 return code;
     237             :         }
     238             : 
     239           0 :         code = mit_samba_generate_salt(&salt);
     240           0 :         if (code != 0) {
     241           0 :                 krb5_db_free_principal(context, kentry);
     242           0 :                 return code;
     243             :         }
     244             : 
     245           0 :         if (password != NULL) {
     246           0 :                 pwd.data = strdup(password);
     247           0 :                 pwd.length = strlen(password);
     248             :         } else {
     249             :                 /* create a random password */
     250           0 :                 code = mit_samba_generate_random_password(&pwd);
     251           0 :                 if (code != 0) {
     252           0 :                         krb5_db_free_principal(context, kentry);
     253           0 :                         return code;
     254             :                 }
     255             :         }
     256             : 
     257           0 :         code = krb5_c_string_to_key(context, enctype, &pwd, &salt, &key);
     258           0 :         SAFE_FREE(pwd.data);
     259           0 :         if (code != 0) {
     260           0 :                 krb5_db_free_principal(context, kentry);
     261           0 :                 return code;
     262             :         }
     263             : 
     264           0 :         kentry->n_key_data = 1;
     265           0 :         kentry->key_data = calloc(1, sizeof(krb5_key_data));
     266           0 :         if (code != 0) {
     267           0 :                 krb5_db_free_principal(context, kentry);
     268           0 :                 return code;
     269             :         }
     270             : 
     271           0 :         key_data = &kentry->key_data[0];
     272             : 
     273           0 :         key_data->key_data_ver          = KRB5_KDB_V1_KEY_DATA_ARRAY;
     274           0 :         key_data->key_data_kvno         = 1;
     275           0 :         key_data->key_data_type[0]      = key.enctype;
     276           0 :         key_data->key_data_length[0]    = key.length;
     277           0 :         key_data->key_data_contents[0]  = key.contents;
     278           0 :         key_data->key_data_type[1]      = sts;
     279           0 :         key_data->key_data_length[1]    = salt.length;
     280           0 :         key_data->key_data_contents[1]  = (krb5_octet*)salt.data;
     281             : 
     282           0 :         *kentry_ptr = kentry;
     283             : 
     284           0 :         return 0;
     285             : }
     286             : 
     287           0 : static krb5_error_code ks_get_admin_principal(krb5_context context,
     288             :                                               krb5_const_principal princ,
     289             :                                               krb5_db_entry **kentry_ptr)
     290             : {
     291           0 :         krb5_error_code code = EINVAL;
     292             : 
     293           0 :         code = ks_create_principal(context,
     294             :                                    princ,
     295             :                                    KRB5_KDB_DISALLOW_TGT_BASED,
     296             :                                    ADMIN_LIFETIME,
     297             :                                    NULL,
     298             :                                    kentry_ptr);
     299             : 
     300           0 :         return code;
     301             : }
     302             : 
     303          92 : krb5_error_code kdb_samba_db_get_principal(krb5_context context,
     304             :                                            krb5_const_principal princ,
     305             :                                            unsigned int kflags,
     306             :                                            krb5_db_entry **kentry)
     307             : {
     308             :         struct mit_samba_context *mit_ctx;
     309             :         krb5_error_code code;
     310             : 
     311          92 :         mit_ctx = ks_get_context(context);
     312          92 :         if (mit_ctx == NULL) {
     313           0 :                 return KRB5_KDB_DBNOTINITED;
     314             :         }
     315             : 
     316          92 :         if (ks_is_master_key_principal(context, princ)) {
     317           0 :                 return ks_get_master_key_principal(context, princ, kentry);
     318             :         }
     319             : 
     320             :         /*
     321             :          * Fake a kadmin/admin and kadmin/history principal so that kadmindd can
     322             :          * start
     323             :          */
     324         184 :         if (ks_is_kadmin_admin(context, princ) ||
     325          92 :             ks_is_kadmin_history(context, princ)) {
     326           0 :                 return ks_get_admin_principal(context, princ, kentry);
     327             :         }
     328             : 
     329          92 :         code = ks_get_principal(context, princ, kflags, kentry);
     330             : 
     331             :         /*
     332             :          * This restricts the changepw account so it isn't able to request a
     333             :          * service ticket. It also marks the principal as the changepw service.
     334             :          */
     335          92 :         if (ks_is_kadmin_changepw(context, princ)) {
     336             :                 /* FIXME: shouldn't we also set KRB5_KDB_DISALLOW_TGT_BASED ?
     337             :                  * testing showed that setpw kpasswd command fails then on the
     338             :                  * server though... */
     339          92 :                 (*kentry)->attributes |= KRB5_KDB_PWCHANGE_SERVICE;
     340          92 :                 (*kentry)->max_life = CHANGEPW_LIFETIME;
     341             :         }
     342             : 
     343          92 :         return code;
     344             : }
     345             : 
     346           0 : krb5_error_code kdb_samba_db_put_principal(krb5_context context,
     347             :                                            krb5_db_entry *entry,
     348             :                                            char **db_args)
     349             : {
     350             : 
     351             :         /* NOTE: deferred, samba does not allow the KDC to store
     352             :          * principals for now. We should not return KRB5_KDB_DB_INUSE as this
     353             :          * would result in confusing error messages after password changes. */
     354           0 :         return 0;
     355             : }
     356             : 
     357           0 : krb5_error_code kdb_samba_db_delete_principal(krb5_context context,
     358             :                                               krb5_const_principal princ)
     359             : {
     360             : 
     361             :         /* NOTE: deferred, samba does not allow the KDC to delete
     362             :          * principals for now */
     363           0 :         return KRB5_KDB_DB_INUSE;
     364             : }
     365             : 
     366           0 : krb5_error_code kdb_samba_db_iterate(krb5_context context,
     367             :                                      char *match_entry,
     368             :                                      int (*func)(krb5_pointer, krb5_db_entry *),
     369             :                                      krb5_pointer func_arg,
     370             :                                      krb5_flags iterflags)
     371             : {
     372             :         struct mit_samba_context *mit_ctx;
     373           0 :         krb5_db_entry *kentry = NULL;
     374             :         krb5_error_code code;
     375             : 
     376             : 
     377           0 :         mit_ctx = ks_get_context(context);
     378           0 :         if (mit_ctx == NULL) {
     379           0 :                 return KRB5_KDB_DBNOTINITED;
     380             :         }
     381             : 
     382           0 :         code = mit_samba_get_firstkey(mit_ctx, &kentry);
     383           0 :         while (code == 0) {
     384           0 :                 code = (*func)(func_arg, kentry);
     385           0 :                 if (code != 0) {
     386           0 :                         break;
     387             :                 }
     388             : 
     389           0 :                 code = mit_samba_get_nextkey(mit_ctx, &kentry);
     390             :         }
     391             : 
     392           0 :         if (code == KRB5_KDB_NOENTRY) {
     393           0 :                 code = 0;
     394             :         }
     395             : 
     396           0 :         return code;
     397             : }

Generated by: LCOV version 1.14