LCOV - code coverage report
Current view: top level - source4/kdc/mit-kdb - kdb_samba_policies.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 0 127 0.0 %
Date: 2024-04-21 15:09:00 Functions: 0 9 0.0 %

          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-2021 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 "lib/replace/replace.h"
      24             : #include "lib/replace/system/kerberos.h"
      25             : #include "lib/util/data_blob.h"
      26             : #include "lib/util/debug.h"
      27             : #include "lib/util/fault.h"
      28             : #include "lib/util/memory.h"
      29             : #include "libcli/util/ntstatus.h"
      30             : #include "lib/krb5_wrap/krb5_samba.h"
      31             : 
      32             : #include <profile.h>
      33             : #include <kdb.h>
      34             : 
      35             : #include "kdc/mit_samba.h"
      36             : #include "kdb_samba.h"
      37             : 
      38             : #undef DBGC_CLASS
      39             : #define DBGC_CLASS DBGC_KERBEROS
      40             : 
      41             : /* FIXME: This is a krb5 function which is exported, but in no header */
      42             : extern krb5_error_code decode_krb5_padata_sequence(const krb5_data *output,
      43             :                                                    krb5_pa_data ***rep);
      44             : 
      45           0 : static krb5_error_code ks_get_netbios_name(krb5_address **addrs, char **name)
      46             : {
      47           0 :         char *nb_name = NULL;
      48             :         int len, i;
      49             : 
      50           0 :         for (i = 0; addrs[i]; i++) {
      51           0 :                 if (addrs[i]->addrtype != ADDRTYPE_NETBIOS) {
      52           0 :                         continue;
      53             :                 }
      54           0 :                 len = MIN(addrs[i]->length, 15);
      55           0 :                 nb_name = strndup((const char *)addrs[i]->contents, len);
      56           0 :                 if (!nb_name) {
      57           0 :                         return ENOMEM;
      58             :                 }
      59           0 :                 break;
      60             :         }
      61             : 
      62           0 :         if (nb_name) {
      63             :                 /* Strip space padding */
      64           0 :                 i = strlen(nb_name) - 1;
      65           0 :                 for (i = strlen(nb_name) - 1;
      66           0 :                      i > 0 && nb_name[i] == ' ';
      67           0 :                      i--) {
      68           0 :                         nb_name[i] = '\0';
      69             :                 }
      70             :         }
      71             : 
      72           0 :         *name = nb_name;
      73             : 
      74           0 :         return 0;
      75             : }
      76             : 
      77           0 : krb5_error_code kdb_samba_db_check_policy_as(krb5_context context,
      78             :                                              krb5_kdc_req *kdcreq,
      79             :                                              krb5_db_entry *client,
      80             :                                              krb5_db_entry *server,
      81             :                                              krb5_timestamp kdc_time,
      82             :                                              const char **status,
      83             :                                              krb5_pa_data ***e_data_out)
      84             : {
      85             :         struct mit_samba_context *mit_ctx;
      86             :         krb5_error_code code;
      87           0 :         char *client_name = NULL;
      88           0 :         char *server_name = NULL;
      89           0 :         char *netbios_name = NULL;
      90           0 :         char *realm = NULL;
      91           0 :         bool password_change = false;
      92             :         krb5_const_principal client_princ;
      93           0 :         DATA_BLOB int_data = { NULL, 0 };
      94             :         krb5_data d;
      95             :         krb5_pa_data **e_data;
      96             : 
      97           0 :         mit_ctx = ks_get_context(context);
      98           0 :         if (mit_ctx == NULL) {
      99           0 :                 return KRB5_KDB_DBNOTINITED;
     100             :         }
     101             : 
     102             :         /* Prefer canonicalised name from client entry */
     103           0 :         client_princ = client ? client->princ : kdcreq->client;
     104             : 
     105           0 :         if (client_princ == NULL || ks_is_kadmin(context, client_princ)) {
     106           0 :                 return KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN;
     107             :         }
     108             : 
     109           0 :         if (krb5_princ_size(context, kdcreq->server) == 2 &&
     110           0 :             ks_is_kadmin_changepw(context, kdcreq->server)) {
     111           0 :                 code = krb5_get_default_realm(context, &realm);
     112           0 :                 if (code) {
     113           0 :                         goto done;
     114             :                 }
     115             : 
     116           0 :                 if (ks_data_eq_string(kdcreq->server->realm, realm)) {
     117           0 :                         password_change = true;
     118             :                 }
     119             :         }
     120             : 
     121           0 :         code = krb5_unparse_name(context, kdcreq->server, &server_name);
     122           0 :         if (code) {
     123           0 :                 goto done;
     124             :         }
     125             : 
     126           0 :         code = krb5_unparse_name(context, client_princ, &client_name);
     127           0 :         if (code) {
     128           0 :                 goto done;
     129             :         }
     130             : 
     131           0 :         if (kdcreq->addresses) {
     132           0 :                 code = ks_get_netbios_name(kdcreq->addresses, &netbios_name);
     133           0 :                 if (code) {
     134           0 :                         goto done;
     135             :                 }
     136             :         }
     137             : 
     138           0 :         code = mit_samba_check_client_access(mit_ctx,
     139             :                                              client,
     140             :                                              client_name,
     141             :                                              server,
     142             :                                              server_name,
     143             :                                              netbios_name,
     144             :                                              password_change,
     145             :                                              &int_data);
     146             : 
     147           0 :         if (int_data.length && int_data.data) {
     148             : 
     149             :                 /* make sure the mapped return code is returned - gd */
     150             :                 int code_tmp;
     151             : 
     152           0 :                 d = smb_krb5_data_from_blob(int_data);
     153             : 
     154           0 :                 code_tmp = decode_krb5_padata_sequence(&d, &e_data);
     155           0 :                 if (code_tmp == 0) {
     156           0 :                         *e_data_out = e_data;
     157             :                 }
     158             :         }
     159           0 : done:
     160           0 :         free(realm);
     161           0 :         free(server_name);
     162           0 :         free(client_name);
     163           0 :         free(netbios_name);
     164             : 
     165           0 :         return code;
     166             : }
     167             : 
     168           0 : static krb5_error_code ks_get_pac(krb5_context context,
     169             :                                   uint32_t flags,
     170             :                                   krb5_db_entry *client,
     171             :                                   krb5_db_entry *server,
     172             :                                   krb5_keyblock *client_key,
     173             :                                   krb5_pac *pac)
     174             : {
     175             :         struct mit_samba_context *mit_ctx;
     176             :         krb5_error_code code;
     177             : 
     178           0 :         mit_ctx = ks_get_context(context);
     179           0 :         if (mit_ctx == NULL) {
     180           0 :                 return KRB5_KDB_DBNOTINITED;
     181             :         }
     182             : 
     183           0 :         code = mit_samba_get_pac(mit_ctx,
     184             :                                  context,
     185             :                                  flags,
     186             :                                  client,
     187             :                                  server,
     188             :                                  client_key,
     189             :                                  pac);
     190           0 :         if (code != 0) {
     191           0 :                 return code;
     192             :         }
     193             : 
     194           0 :         return code;
     195             : }
     196             : 
     197           0 : static krb5_error_code ks_update_pac(krb5_context context,
     198             :                                      int flags,
     199             :                                      krb5_db_entry *client,
     200             :                                      krb5_db_entry *server,
     201             :                                      krb5_db_entry *signing_krbtgt,
     202             :                                      krb5_pac old_pac,
     203             :                                      krb5_pac new_pac)
     204             : {
     205           0 :         struct mit_samba_context *mit_ctx = NULL;
     206             :         krb5_error_code code;
     207             : 
     208           0 :         mit_ctx = ks_get_context(context);
     209           0 :         if (mit_ctx == NULL) {
     210           0 :                 return KRB5_KDB_DBNOTINITED;
     211             :         }
     212             : 
     213           0 :         code = mit_samba_update_pac(mit_ctx,
     214             :                                     context,
     215             :                                     flags,
     216             :                                     client,
     217             :                                     server,
     218             :                                     signing_krbtgt,
     219             :                                     old_pac,
     220             :                                     new_pac);
     221           0 :         if (code != 0) {
     222           0 :                 return code;
     223             :         }
     224             : 
     225           0 :         return code;
     226             : }
     227             : 
     228           0 : krb5_error_code kdb_samba_db_issue_pac(krb5_context context,
     229             :                                        unsigned int flags,
     230             :                                        krb5_db_entry *client,
     231             :                                        krb5_keyblock *replaced_reply_key,
     232             :                                        krb5_db_entry *server,
     233             :                                        krb5_db_entry *signing_krbtgt,
     234             :                                        krb5_timestamp authtime,
     235             :                                        krb5_pac old_pac,
     236             :                                        krb5_pac new_pac,
     237             :                                        krb5_data ***auth_indicators)
     238             : {
     239           0 :         char *client_name = NULL;
     240           0 :         char *server_name = NULL;
     241           0 :         krb5_error_code code = EINVAL;
     242             : 
     243             :         /* The KDC handles both signing and verification for us. */
     244             : 
     245           0 :         if (client != NULL) {
     246           0 :                 code = krb5_unparse_name(context,
     247           0 :                                          client->princ,
     248             :                                          &client_name);
     249           0 :                 if (code != 0) {
     250           0 :                         return code;
     251             :                 }
     252             :         }
     253             : 
     254           0 :         if (server != NULL) {
     255           0 :                 code = krb5_unparse_name(context,
     256           0 :                                          server->princ,
     257             :                                          &server_name);
     258           0 :                 if (code != 0) {
     259           0 :                         SAFE_FREE(client_name);
     260           0 :                         return code;
     261             :                 }
     262             :         }
     263             : 
     264             :         /*
     265             :          * Get a new PAC for AS-REQ or S4U2Self for our realm.
     266             :          *
     267             :          * For a simple cross-realm S4U2Proxy there will be the following TGS
     268             :          * requests after the client realm is identified:
     269             :          *
     270             :          * 1. server@SREALM to SREALM for krbtgt/CREALM@SREALM -- a regular TGS
     271             :          *    request with server's normal TGT and no S4U2Self padata.
     272             :          * 2. server@SREALM to CREALM for server@SREALM (expressed as an
     273             :          *    enterprise principal), with the TGT from #1 as header ticket and
     274             :          *    S4U2Self padata identifying the client.
     275             :          * 3. server@SREALM to SREALM for server@SREALM with S4U2Self padata,
     276             :          *    with the referral TGT from #2 as header ticket
     277             :          *
     278             :          * In request 2 the PROTOCOL_TRANSITION and CROSS_REALM flags are set,
     279             :          * and the request is for a local client (so client != NULL) and we
     280             :          * want to make a new PAC.
     281             :          *
     282             :          * In request 3 the PROTOCOL_TRANSITION and CROSS_REALM flags are also
     283             :          * set, but the request is for a non-local client (so client == NULL)
     284             :          * and we want to copy the subject PAC contained in the referral TGT.
     285             :          */
     286           0 :         if (old_pac == NULL ||
     287           0 :             (client != NULL && (flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION))) {
     288           0 :                 DBG_NOTICE("Generate PAC for AS-REQ [client=%s, flags=%#08x]\n",
     289             :                            client_name != NULL ? client_name : "<unknown>",
     290             :                            flags);
     291             : 
     292           0 :                 code = ks_get_pac(context,
     293             :                                   flags,
     294             :                                   client,
     295             :                                   server,
     296             :                                   replaced_reply_key,
     297             :                                   &new_pac);
     298             :         } else {
     299           0 :                 DBG_NOTICE("Update PAC for TGS-REQ [client=%s, server=%s, "
     300             :                            "flags=%#08x]\n",
     301             :                            client_name != NULL ? client_name : "<unknown>",
     302             :                            server_name != NULL ? server_name : "<unknown>",
     303             :                            flags);
     304             : 
     305           0 :                 code = ks_update_pac(context,
     306             :                                 flags,
     307             :                                 client,
     308             :                                 server,
     309             :                                 signing_krbtgt,
     310             :                                 old_pac,
     311             :                                 new_pac);
     312             :         }
     313           0 :         SAFE_FREE(client_name);
     314           0 :         SAFE_FREE(server_name);
     315             : 
     316           0 :         return code;
     317             : }
     318             : 
     319           0 : krb5_error_code kdb_samba_db_check_allowed_to_delegate(krb5_context context,
     320             :                                                        krb5_const_principal client,
     321             :                                                        const krb5_db_entry *server,
     322             :                                                        krb5_const_principal proxy)
     323             : {
     324           0 :         struct mit_samba_context *mit_ctx = NULL;
     325             : 
     326           0 :         mit_ctx = ks_get_context(context);
     327           0 :         if (mit_ctx == NULL) {
     328           0 :                 return KRB5_KDB_DBNOTINITED;
     329             :         }
     330             : 
     331           0 :         return mit_samba_check_s4u2proxy(mit_ctx,
     332             :                                          server,
     333             :                                          proxy);
     334             : 
     335             : }
     336             : 
     337             : 
     338           0 : krb5_error_code kdb_samba_db_allowed_to_delegate_from(
     339             :                 krb5_context context,
     340             :                 krb5_const_principal client_principal,
     341             :                 krb5_const_principal server_principal,
     342             :                 krb5_pac header_pac,
     343             :                 const krb5_db_entry *proxy)
     344             : {
     345           0 :         struct mit_samba_context *mit_ctx = NULL;
     346             :         krb5_error_code code;
     347             : 
     348           0 :         mit_ctx = ks_get_context(context);
     349           0 :         if (mit_ctx == NULL) {
     350           0 :                 return KRB5_KDB_DBNOTINITED;
     351             :         }
     352             : 
     353           0 :         code = mit_samba_check_allowed_to_delegate_from(mit_ctx,
     354             :                                                         client_principal,
     355             :                                                         server_principal,
     356             :                                                         header_pac,
     357             :                                                         proxy);
     358             : 
     359           0 :         return code;
     360             : }
     361             : 
     362             : 
     363           0 : static void samba_bad_password_count(krb5_db_entry *client,
     364             :                                      krb5_error_code error_code)
     365             : {
     366           0 :         switch (error_code) {
     367           0 :         case 0:
     368           0 :                 mit_samba_zero_bad_password_count(client);
     369           0 :                 break;
     370           0 :         case KRB5KDC_ERR_PREAUTH_FAILED:
     371             :         case KRB5KRB_AP_ERR_BAD_INTEGRITY:
     372           0 :                 mit_samba_update_bad_password_count(client);
     373           0 :                 break;
     374             :         }
     375           0 : }
     376             : 
     377           0 : void kdb_samba_db_audit_as_req(krb5_context context,
     378             :                                krb5_kdc_req *request,
     379             :                                const krb5_address *local_addr,
     380             :                                const krb5_address *remote_addr,
     381             :                                krb5_db_entry *client,
     382             :                                krb5_db_entry *server,
     383             :                                krb5_timestamp authtime,
     384             :                                krb5_error_code error_code)
     385             : {
     386             :         /*
     387             :          * FIXME: This segfaulted with a FAST test
     388             :          * FIND_FAST: <unknown client> for <unknown server>, Unknown FAST armor type 0
     389             :          */
     390           0 :         if (client == NULL) {
     391           0 :                 return;
     392             :         }
     393             : 
     394           0 :         samba_bad_password_count(client, error_code);
     395             : 
     396             :         /* TODO: perform proper audit logging for addresses */
     397             : }

Generated by: LCOV version 1.14