LCOV - code coverage report
Current view: top level - auth/credentials - credentials_krb5.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 539 819 65.8 %
Date: 2024-05-31 13:13:24 Functions: 35 38 92.1 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    Handle user credentials (as regards krb5)
       5             : 
       6             :    Copyright (C) Jelmer Vernooij 2005
       7             :    Copyright (C) Tim Potter 2001
       8             :    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
       9             : 
      10             :    This program is free software; you can redistribute it and/or modify
      11             :    it under the terms of the GNU General Public License as published by
      12             :    the Free Software Foundation; either version 3 of the License, or
      13             :    (at your option) any later version.
      14             : 
      15             :    This program is distributed in the hope that it will be useful,
      16             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :    GNU General Public License for more details.
      19             : 
      20             :    You should have received a copy of the GNU General Public License
      21             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      22             : */
      23             : 
      24             : #include "includes.h"
      25             : #include "system/kerberos.h"
      26             : #include "system/gssapi.h"
      27             : #include "auth/kerberos/kerberos.h"
      28             : #include "auth/credentials/credentials.h"
      29             : #include "auth/credentials/credentials_internal.h"
      30             : #include "auth/credentials/credentials_krb5.h"
      31             : #include "auth/kerberos/kerberos_credentials.h"
      32             : #include "auth/kerberos/kerberos_srv_keytab.h"
      33             : #include "auth/kerberos/kerberos_util.h"
      34             : #include "auth/kerberos/pac_utils.h"
      35             : #include "param/param.h"
      36             : #include "../libds/common/flags.h"
      37             : 
      38             : #undef DBGC_CLASS
      39             : #define DBGC_CLASS DBGC_AUTH
      40             : 
      41             : #undef strncasecmp
      42             : 
      43             : static void cli_credentials_invalidate_client_gss_creds(
      44             :                                         struct cli_credentials *cred,
      45             :                                         enum credentials_obtained obtained);
      46             : 
      47             : /* Free a memory ccache */
      48       46834 : static int free_mccache(struct ccache_container *ccc)
      49             : {
      50       46834 :         if (ccc->ccache != NULL) {
      51       46834 :                 krb5_cc_destroy(ccc->smb_krb5_context->krb5_context,
      52             :                                 ccc->ccache);
      53       46834 :                 ccc->ccache = NULL;
      54             :         }
      55             : 
      56       46834 :         return 0;
      57             : }
      58             : 
      59             : /* Free a disk-based ccache */
      60      103142 : static int free_dccache(struct ccache_container *ccc)
      61             : {
      62      103142 :         if (ccc->ccache != NULL) {
      63      103142 :                 krb5_cc_close(ccc->smb_krb5_context->krb5_context,
      64             :                               ccc->ccache);
      65      103142 :                 ccc->ccache = NULL;
      66             :         }
      67             : 
      68      103142 :         return 0;
      69             : }
      70             : 
      71       30938 : static uint32_t smb_gss_krb5_copy_ccache(uint32_t *min_stat,
      72             :                                          gss_cred_id_t cred,
      73             :                                          struct ccache_container *ccc)
      74             : {
      75             : #ifndef SAMBA4_USES_HEIMDAL /* MIT 1.10 */
      76        7559 :         krb5_context context = ccc->smb_krb5_context->krb5_context;
      77        7559 :         krb5_ccache dummy_ccache = NULL;
      78        7559 :         krb5_creds creds = {0};
      79        7559 :         krb5_cc_cursor cursor = NULL;
      80        7559 :         krb5_principal princ = NULL;
      81             :         krb5_error_code code;
      82        7559 :         uint32_t maj_stat = GSS_S_FAILURE;
      83             : 
      84             :         /*
      85             :          * Create a dummy ccache, so we can iterate over the credentials
      86             :          * and find the default principal for the ccache we want to
      87             :          * copy. The new ccache needs to be initialized with this
      88             :          * principal.
      89             :          */
      90        7559 :         code = smb_krb5_cc_new_unique_memory(context, NULL, NULL, &dummy_ccache);
      91        7559 :         if (code != 0) {
      92           0 :                 *min_stat = code;
      93           0 :                 return GSS_S_FAILURE;
      94             :         }
      95             : 
      96             :         /*
      97             :          * We do not need set a default principal on the temporary dummy
      98             :          * ccache, as we do consume it at all in this function.
      99             :          */
     100        7559 :         maj_stat = gss_krb5_copy_ccache(min_stat, cred, dummy_ccache);
     101        7559 :         if (maj_stat != 0) {
     102           0 :                 krb5_cc_destroy(context, dummy_ccache);
     103           0 :                 return maj_stat;
     104             :         }
     105             : 
     106        7559 :         code = krb5_cc_start_seq_get(context, dummy_ccache, &cursor);
     107        7559 :         if (code != 0) {
     108           0 :                 krb5_cc_destroy(context, dummy_ccache);
     109           0 :                 *min_stat = EINVAL;
     110           0 :                 return GSS_S_FAILURE;
     111             :         }
     112             : 
     113        7559 :         code = krb5_cc_next_cred(context,
     114             :                                  dummy_ccache,
     115             :                                  &cursor,
     116             :                                  &creds);
     117        7559 :         if (code != 0) {
     118           0 :                 krb5_cc_destroy(context, dummy_ccache);
     119           0 :                 *min_stat = EINVAL;
     120           0 :                 return GSS_S_FAILURE;
     121             :         }
     122             : 
     123             :         do {
     124        7559 :                 if (creds.ticket_flags & TKT_FLG_PRE_AUTH) {
     125             :                         krb5_data *tgs;
     126             : 
     127        7559 :                         tgs = krb5_princ_component(context,
     128             :                                                    creds.server,
     129             :                                                    0);
     130        7559 :                         if (tgs != NULL && tgs->length >= 1) {
     131             :                                 int cmp;
     132             : 
     133        7559 :                                 cmp = memcmp(tgs->data,
     134             :                                              KRB5_TGS_NAME,
     135        7559 :                                              tgs->length);
     136        7559 :                                 if (cmp == 0 && creds.client != NULL) {
     137        7559 :                                         princ = creds.client;
     138        7559 :                                         code = KRB5_CC_END;
     139        7559 :                                         break;
     140             :                                 }
     141             :                         }
     142             :                 }
     143             : 
     144           0 :                 krb5_free_cred_contents(context, &creds);
     145             : 
     146           0 :                 code = krb5_cc_next_cred(context,
     147             :                                          dummy_ccache,
     148             :                                          &cursor,
     149             :                                          &creds);
     150           0 :         } while (code == 0);
     151             : 
     152        7559 :         if (code == KRB5_CC_END) {
     153        7559 :                 krb5_cc_end_seq_get(context, dummy_ccache, &cursor);
     154        7559 :                 code = 0;
     155             :         }
     156        7559 :         krb5_cc_destroy(context, dummy_ccache);
     157             : 
     158        7559 :         if (code != 0 || princ == NULL) {
     159           0 :                 krb5_free_cred_contents(context, &creds);
     160           0 :                 *min_stat = EINVAL;
     161           0 :                 return GSS_S_FAILURE;
     162             :         }
     163             : 
     164             :         /*
     165             :          * Set the default principal for the cache we copy
     166             :          * into. This is needed to be able that other calls
     167             :          * can read it with e.g. gss_acquire_cred() or
     168             :          * krb5_cc_get_principal().
     169             :          */
     170        7559 :         code = krb5_cc_initialize(context, ccc->ccache, princ);
     171        7559 :         if (code != 0) {
     172           0 :                 krb5_free_cred_contents(context, &creds);
     173           0 :                 *min_stat = EINVAL;
     174           0 :                 return GSS_S_FAILURE;
     175             :         }
     176        7559 :         krb5_free_cred_contents(context, &creds);
     177             : 
     178             : #endif /* SAMBA4_USES_HEIMDAL */
     179             : 
     180       30938 :         return gss_krb5_copy_ccache(min_stat,
     181             :                                     cred,
     182             :                                     ccc->ccache);
     183             : }
     184             : 
     185      266513 : _PUBLIC_ int cli_credentials_get_krb5_context(struct cli_credentials *cred,
     186             :                                      struct loadparm_context *lp_ctx,
     187             :                                      struct smb_krb5_context **smb_krb5_context)
     188             : {
     189        6797 :         int ret;
     190      266513 :         if (cred->smb_krb5_context) {
     191       69237 :                 *smb_krb5_context = cred->smb_krb5_context;
     192       69237 :                 return 0;
     193             :         }
     194             : 
     195      197276 :         ret = smb_krb5_init_context(cred, lp_ctx,
     196             :                                     &cred->smb_krb5_context);
     197      197276 :         if (ret) {
     198           0 :                 cred->smb_krb5_context = NULL;
     199           0 :                 return ret;
     200             :         }
     201      197276 :         *smb_krb5_context = cred->smb_krb5_context;
     202      197276 :         return 0;
     203             : }
     204             : 
     205             : /* For most predictable behaviour, this needs to be called directly after the cli_credentials_init(),
     206             :  * otherwise we may still have references to the old smb_krb5_context in a credential cache etc
     207             :  */
     208         122 : _PUBLIC_ NTSTATUS cli_credentials_set_krb5_context(struct cli_credentials *cred,
     209             :                                           struct smb_krb5_context *smb_krb5_context)
     210             : {
     211         122 :         if (smb_krb5_context == NULL) {
     212           0 :                 talloc_unlink(cred, cred->smb_krb5_context);
     213           0 :                 cred->smb_krb5_context = NULL;
     214           0 :                 return NT_STATUS_OK;
     215             :         }
     216             : 
     217         122 :         if (!talloc_reference(cred, smb_krb5_context)) {
     218           0 :                 return NT_STATUS_NO_MEMORY;
     219             :         }
     220         122 :         cred->smb_krb5_context = smb_krb5_context;
     221         122 :         return NT_STATUS_OK;
     222             : }
     223             : 
     224       49684 : static int cli_credentials_set_from_ccache(struct cli_credentials *cred,
     225             :                                            struct ccache_container *ccache,
     226             :                                            enum credentials_obtained obtained,
     227             :                                            const char **error_string)
     228             : {
     229        1480 :         bool ok;
     230        1480 :         char *realm;
     231        1480 :         krb5_principal princ;
     232        1480 :         krb5_error_code ret;
     233        1480 :         char *name;
     234             : 
     235       49684 :         if (cred->ccache_obtained > obtained) {
     236        5867 :                 return 0;
     237             :         }
     238             : 
     239       43817 :         ret = krb5_cc_get_principal(ccache->smb_krb5_context->krb5_context,
     240             :                                     ccache->ccache, &princ);
     241             : 
     242       43817 :         if (ret) {
     243           0 :                 (*error_string) = talloc_asprintf(cred, "failed to get principal from ccache: %s\n",
     244           0 :                                                   smb_get_krb5_error_message(ccache->smb_krb5_context->krb5_context,
     245             :                                                                              ret, cred));
     246           0 :                 return ret;
     247             :         }
     248             : 
     249       43817 :         ret = krb5_unparse_name(ccache->smb_krb5_context->krb5_context, princ, &name);
     250       43817 :         if (ret) {
     251           0 :                 (*error_string) = talloc_asprintf(cred, "failed to unparse principal from ccache: %s\n",
     252           0 :                                                   smb_get_krb5_error_message(ccache->smb_krb5_context->krb5_context,
     253             :                                                                              ret, cred));
     254           0 :                 krb5_free_principal(ccache->smb_krb5_context->krb5_context, princ);
     255           0 :                 return ret;
     256             :         }
     257             : 
     258       43817 :         ok = cli_credentials_set_principal(cred, name, obtained);
     259       43817 :         krb5_free_unparsed_name(ccache->smb_krb5_context->krb5_context, name);
     260       43817 :         if (!ok) {
     261          25 :                 krb5_free_principal(ccache->smb_krb5_context->krb5_context, princ);
     262          25 :                 return ENOMEM;
     263             :         }
     264             : 
     265       45272 :         realm = smb_krb5_principal_get_realm(
     266       43792 :                 cred, ccache->smb_krb5_context->krb5_context, princ);
     267       43792 :         krb5_free_principal(ccache->smb_krb5_context->krb5_context, princ);
     268       43792 :         if (realm == NULL) {
     269           0 :                 return ENOMEM;
     270             :         }
     271       43792 :         ok = cli_credentials_set_realm(cred, realm, obtained);
     272       43792 :         TALLOC_FREE(realm);
     273       43792 :         if (!ok) {
     274           6 :                 return ENOMEM;
     275             :         }
     276             : 
     277             :         /* set the ccache_obtained here, as it just got set to UNINITIALISED by the calls above */
     278       43786 :         cred->ccache_obtained = obtained;
     279             : 
     280       43786 :         return 0;
     281             : }
     282             : 
     283      105494 : _PUBLIC_ int cli_credentials_set_ccache(struct cli_credentials *cred,
     284             :                                         struct loadparm_context *lp_ctx,
     285             :                                         const char *name,
     286             :                                         enum credentials_obtained obtained,
     287             :                                         const char **error_string)
     288             : {
     289         434 :         krb5_error_code ret;
     290         434 :         krb5_principal princ;
     291         434 :         struct ccache_container *ccc;
     292      105494 :         if (cred->ccache_obtained > obtained) {
     293        2191 :                 return 0;
     294             :         }
     295             : 
     296      103303 :         ccc = talloc(cred, struct ccache_container);
     297      103303 :         if (!ccc) {
     298           0 :                 (*error_string) = error_message(ENOMEM);
     299           0 :                 return ENOMEM;
     300             :         }
     301             : 
     302      103303 :         ret = cli_credentials_get_krb5_context(cred, lp_ctx,
     303             :                                                &ccc->smb_krb5_context);
     304      103303 :         if (ret) {
     305           0 :                 (*error_string) = error_message(ret);
     306           0 :                 talloc_free(ccc);
     307           0 :                 return ret;
     308             :         }
     309      103303 :         if (!talloc_reference(ccc, ccc->smb_krb5_context)) {
     310           0 :                 talloc_free(ccc);
     311           0 :                 (*error_string) = error_message(ENOMEM);
     312           0 :                 return ENOMEM;
     313             :         }
     314             : 
     315      103303 :         if (name) {
     316        4289 :                 ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, name, &ccc->ccache);
     317        4289 :                 if (ret) {
     318           0 :                         (*error_string) = talloc_asprintf(cred, "failed to read krb5 ccache: %s: %s\n",
     319             :                                                           name,
     320           0 :                                                           smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context,
     321             :                                                                                      ret, ccc));
     322           0 :                         talloc_free(ccc);
     323           0 :                         return ret;
     324             :                 }
     325             :         } else {
     326             :                 /*
     327             :                  * This is where the caller really wants to use
     328             :                  * the default krb5 ccache.
     329             :                  */
     330       99014 :                 ret = smb_force_krb5_cc_default(ccc->smb_krb5_context->krb5_context, &ccc->ccache);
     331       99014 :                 if (ret) {
     332           0 :                         (*error_string) = talloc_asprintf(cred, "failed to read default krb5 ccache: %s\n",
     333           0 :                                                           smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context,
     334             :                                                                                      ret, ccc));
     335           0 :                         talloc_free(ccc);
     336           0 :                         return ret;
     337             :                 }
     338             :         }
     339             : 
     340      103303 :         talloc_set_destructor(ccc, free_dccache);
     341             : 
     342      103303 :         ret = krb5_cc_get_principal(ccc->smb_krb5_context->krb5_context, ccc->ccache, &princ);
     343             : 
     344      103303 :         if (ret == 0) {
     345        4673 :                 krb5_free_principal(ccc->smb_krb5_context->krb5_context, princ);
     346        4673 :                 ret = cli_credentials_set_from_ccache(cred, ccc, obtained, error_string);
     347             : 
     348        4673 :                 if (ret) {
     349          31 :                         (*error_string) = error_message(ret);
     350          31 :                         TALLOC_FREE(ccc);
     351          31 :                         return ret;
     352             :                 }
     353             :         }
     354             : 
     355      103272 :         cred->ccache = ccc;
     356      103272 :         cred->ccache_obtained = obtained;
     357             : 
     358      103272 :         cli_credentials_invalidate_client_gss_creds(
     359             :                 cred, cred->ccache_obtained);
     360             : 
     361      103272 :         return 0;
     362             : }
     363             : 
     364             : #ifndef SAMBA4_USES_HEIMDAL
     365             : /*
     366             :  * This function is a workaround for old MIT Kerberos versions which did not
     367             :  * implement the krb5_cc_remove_cred function. It creates a temporary
     368             :  * credentials cache to copy the credentials in the current cache
     369             :  * except the one we want to remove and then overwrites the contents of the
     370             :  * current cache with the temporary copy.
     371             :  */
     372           0 : static krb5_error_code krb5_cc_remove_cred_wrap(struct ccache_container *ccc,
     373             :                                                 krb5_creds *creds)
     374             : {
     375           0 :         krb5_ccache dummy_ccache = NULL;
     376           0 :         krb5_creds cached_creds = {0};
     377           0 :         krb5_cc_cursor cursor = NULL;
     378             :         krb5_error_code code;
     379             : 
     380           0 :         code = smb_krb5_cc_new_unique_memory(ccc->smb_krb5_context->krb5_context,
     381             :                                              NULL, NULL,
     382             :                                              &dummy_ccache);
     383           0 :         if (code != 0) {
     384           0 :                 DBG_ERR("krb5_cc_resolve failed: %s\n",
     385             :                         smb_get_krb5_error_message(
     386             :                                 ccc->smb_krb5_context->krb5_context,
     387             :                                 code, ccc));
     388           0 :                 return code;
     389             :         }
     390             : 
     391           0 :         code = krb5_cc_start_seq_get(ccc->smb_krb5_context->krb5_context,
     392             :                                      ccc->ccache,
     393             :                                      &cursor);
     394           0 :         if (code != 0) {
     395           0 :                 krb5_cc_destroy(ccc->smb_krb5_context->krb5_context,
     396             :                                 dummy_ccache);
     397             : 
     398           0 :                 DBG_ERR("krb5_cc_start_seq_get failed: %s\n",
     399             :                         smb_get_krb5_error_message(
     400             :                                 ccc->smb_krb5_context->krb5_context,
     401             :                                 code, ccc));
     402           0 :                 return code;
     403             :         }
     404             : 
     405           0 :         while ((code = krb5_cc_next_cred(ccc->smb_krb5_context->krb5_context,
     406             :                                          ccc->ccache,
     407             :                                          &cursor,
     408           0 :                                          &cached_creds)) == 0) {
     409             :                 /* If the principal matches skip it and do not copy to the
     410             :                  * temporary cache as this is the one we want to remove */
     411           0 :                 if (krb5_principal_compare_flags(
     412           0 :                                 ccc->smb_krb5_context->krb5_context,
     413           0 :                                 creds->server,
     414           0 :                                 cached_creds.server,
     415             :                                 0)) {
     416           0 :                         continue;
     417             :                 }
     418             : 
     419           0 :                 code = krb5_cc_store_cred(
     420           0 :                                 ccc->smb_krb5_context->krb5_context,
     421             :                                 dummy_ccache,
     422             :                                 &cached_creds);
     423           0 :                 if (code != 0) {
     424           0 :                         krb5_cc_destroy(ccc->smb_krb5_context->krb5_context,
     425             :                                         dummy_ccache);
     426           0 :                         DBG_ERR("krb5_cc_store_cred failed: %s\n",
     427             :                                 smb_get_krb5_error_message(
     428             :                                         ccc->smb_krb5_context->krb5_context,
     429             :                                         code, ccc));
     430           0 :                         return code;
     431             :                 }
     432             :         }
     433             : 
     434           0 :         if (code == KRB5_CC_END) {
     435           0 :                 krb5_cc_end_seq_get(ccc->smb_krb5_context->krb5_context,
     436             :                                     dummy_ccache,
     437             :                                     &cursor);
     438           0 :                 code = 0;
     439             :         }
     440             : 
     441           0 :         if (code != 0) {
     442           0 :                 krb5_cc_destroy(ccc->smb_krb5_context->krb5_context,
     443             :                                 dummy_ccache);
     444           0 :                 DBG_ERR("krb5_cc_next_cred failed: %s\n",
     445             :                         smb_get_krb5_error_message(
     446             :                                 ccc->smb_krb5_context->krb5_context,
     447             :                                 code, ccc));
     448           0 :                 return code;
     449             :         }
     450             : 
     451           0 :         code = krb5_cc_initialize(ccc->smb_krb5_context->krb5_context,
     452             :                                   ccc->ccache,
     453             :                                   creds->client);
     454           0 :         if (code != 0) {
     455           0 :                 krb5_cc_destroy(ccc->smb_krb5_context->krb5_context,
     456             :                                 dummy_ccache);
     457           0 :                 DBG_ERR("krb5_cc_initialize failed: %s\n",
     458             :                         smb_get_krb5_error_message(
     459             :                                 ccc->smb_krb5_context->krb5_context,
     460             :                                 code, ccc));
     461           0 :                 return code;
     462             :         }
     463             : 
     464           0 :         code = krb5_cc_copy_creds(ccc->smb_krb5_context->krb5_context,
     465             :                                   dummy_ccache,
     466             :                                   ccc->ccache);
     467           0 :         if (code != 0) {
     468           0 :                 krb5_cc_destroy(ccc->smb_krb5_context->krb5_context,
     469             :                                 dummy_ccache);
     470           0 :                 DBG_ERR("krb5_cc_copy_creds failed: %s\n",
     471             :                         smb_get_krb5_error_message(
     472             :                                 ccc->smb_krb5_context->krb5_context,
     473             :                                 code, ccc));
     474           0 :                 return code;
     475             :         }
     476             : 
     477           0 :         code = krb5_cc_destroy(ccc->smb_krb5_context->krb5_context,
     478             :                                dummy_ccache);
     479           0 :         if (code != 0) {
     480           0 :                 DBG_ERR("krb5_cc_destroy failed: %s\n",
     481             :                         smb_get_krb5_error_message(
     482             :                                 ccc->smb_krb5_context->krb5_context,
     483             :                                 code, ccc));
     484           0 :                 return code;
     485             :         }
     486             : 
     487           0 :         return code;
     488             : }
     489             : #endif
     490             : 
     491             : /*
     492             :  * Indicate that we failed to log in to this service/host with these
     493             :  * credentials.  The caller passes an unsigned int which they
     494             :  * initialise to the number of times they would like to retry.
     495             :  *
     496             :  * This method is used to support re-trying with freshly fetched
     497             :  * credentials in case a server is rebuilt while clients have
     498             :  * non-expired tickets. When the client code gets a logon failure they
     499             :  * throw away the existing credentials for the server and retry.
     500             :  */
     501        1605 : _PUBLIC_ bool cli_credentials_failed_kerberos_login(struct cli_credentials *cred,
     502             :                                                     const char *principal,
     503             :                                                     unsigned int *count)
     504             : {
     505           6 :         struct ccache_container *ccc;
     506           6 :         krb5_creds creds, creds2;
     507           6 :         int ret;
     508             : 
     509        1605 :         if (principal == NULL) {
     510             :                 /* no way to delete if we don't know the principal */
     511           0 :                 return false;
     512             :         }
     513             : 
     514        1605 :         ccc = cred->ccache;
     515        1605 :         if (ccc == NULL) {
     516             :                 /* not a kerberos connection */
     517        1515 :                 return false;
     518             :         }
     519             : 
     520          90 :         if (*count > 0) {
     521             :                 /* We have already tried discarding the credentials */
     522          32 :                 return false;
     523             :         }
     524          58 :         (*count)++;
     525             : 
     526          58 :         ZERO_STRUCT(creds);
     527          58 :         ret = krb5_parse_name(ccc->smb_krb5_context->krb5_context, principal, &creds.server);
     528          58 :         if (ret != 0) {
     529           0 :                 return false;
     530             :         }
     531             : 
     532             :         /* MIT kerberos requires creds.client to match against cached
     533             :          * credentials */
     534          58 :         ret = krb5_cc_get_principal(ccc->smb_krb5_context->krb5_context,
     535             :                                     ccc->ccache,
     536             :                                     &creds.client);
     537          58 :         if (ret != 0) {
     538           0 :                 krb5_free_cred_contents(ccc->smb_krb5_context->krb5_context,
     539             :                                         &creds);
     540           0 :                 DBG_ERR("krb5_cc_get_principal failed: %s\n",
     541             :                         smb_get_krb5_error_message(
     542             :                                 ccc->smb_krb5_context->krb5_context,
     543             :                                 ret, ccc));
     544           0 :                 return false;
     545             :         }
     546             : 
     547          58 :         ret = krb5_cc_retrieve_cred(ccc->smb_krb5_context->krb5_context, ccc->ccache, KRB5_TC_MATCH_SRV_NAMEONLY, &creds, &creds2);
     548          58 :         if (ret != 0) {
     549             :                 /* don't retry - we didn't find these credentials to remove */
     550          18 :                 krb5_free_cred_contents(ccc->smb_krb5_context->krb5_context, &creds);
     551          18 :                 return false;
     552             :         }
     553             : 
     554          40 :         ret = krb5_cc_remove_cred(ccc->smb_krb5_context->krb5_context, ccc->ccache, KRB5_TC_MATCH_SRV_NAMEONLY, &creds);
     555             : #ifndef SAMBA4_USES_HEIMDAL
     556          18 :         if (ret == KRB5_CC_NOSUPP) {
     557             :                 /* Old MIT kerberos versions did not implement
     558             :                  * krb5_cc_remove_cred */
     559           0 :                 ret = krb5_cc_remove_cred_wrap(ccc, &creds);
     560             :         }
     561             : #endif
     562          40 :         krb5_free_cred_contents(ccc->smb_krb5_context->krb5_context, &creds);
     563          40 :         krb5_free_cred_contents(ccc->smb_krb5_context->krb5_context, &creds2);
     564          40 :         if (ret != 0) {
     565             :                 /* don't retry - we didn't find these credentials to
     566             :                  * remove. Note that with the current backend this
     567             :                  * never happens, as it always returns 0 even if the
     568             :                  * creds don't exist, which is why we do a separate
     569             :                  * krb5_cc_retrieve_cred() above.
     570             :                  */
     571           0 :                 DBG_ERR("krb5_cc_remove_cred failed: %s\n",
     572             :                         smb_get_krb5_error_message(
     573             :                                 ccc->smb_krb5_context->krb5_context,
     574             :                                 ret, ccc));
     575           0 :                 return false;
     576             :         }
     577          40 :         return true;
     578             : }
     579             : 
     580             : 
     581       46424 : static int cli_credentials_new_ccache(struct cli_credentials *cred,
     582             :                                       struct loadparm_context *lp_ctx,
     583             :                                       char *given_ccache_name,
     584             :                                       struct ccache_container **_ccc,
     585             :                                       const char **error_string)
     586             : {
     587       46424 :         char *ccache_name = given_ccache_name;
     588       46424 :         bool must_free_cc_name = false;
     589        1480 :         krb5_error_code ret;
     590       46424 :         struct ccache_container *ccc = talloc(cred, struct ccache_container);
     591       46424 :         if (!ccc) {
     592           0 :                 return ENOMEM;
     593             :         }
     594             : 
     595       46424 :         ret = cli_credentials_get_krb5_context(cred, lp_ctx,
     596             :                                                &ccc->smb_krb5_context);
     597       46424 :         if (ret) {
     598           0 :                 talloc_free(ccc);
     599           0 :                 (*error_string) = talloc_asprintf(cred, "Failed to get krb5_context: %s",
     600             :                                                   error_message(ret));
     601           0 :                 return ret;
     602             :         }
     603       46424 :         if (!talloc_reference(ccc, ccc->smb_krb5_context)) {
     604           0 :                 talloc_free(ccc);
     605           0 :                 (*error_string) = strerror(ENOMEM);
     606           0 :                 return ENOMEM;
     607             :         }
     608             : 
     609       46424 :         if (!ccache_name) {
     610       46402 :                 if (lpcfg_parm_bool(lp_ctx, NULL, "credentials", "krb5_cc_file", false)) {
     611           0 :                         ccache_name = talloc_asprintf(ccc, "FILE:/tmp/krb5_cc_samba_%u_%p",
     612           0 :                                                       (unsigned int)getpid(), ccc);
     613           0 :                         if (ccache_name == NULL) {
     614           0 :                                 talloc_free(ccc);
     615           0 :                                 (*error_string) = strerror(ENOMEM);
     616           0 :                                 return ENOMEM;
     617             :                         }
     618           0 :                         must_free_cc_name = true;
     619             :                 }
     620             :         }
     621             : 
     622       46424 :         if (ccache_name != NULL) {
     623          22 :                 ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, ccache_name,
     624             :                                       &ccc->ccache);
     625             :         } else {
     626       46402 :                 ret = smb_krb5_cc_new_unique_memory(ccc->smb_krb5_context->krb5_context,
     627             :                                                     ccc, &ccache_name,
     628             :                                                     &ccc->ccache);
     629       46402 :                 must_free_cc_name = true;
     630             :         }
     631       46424 :         if (ret) {
     632           0 :                 (*error_string) = talloc_asprintf(cred, "failed to resolve a krb5 ccache (%s): %s\n",
     633             :                                                   ccache_name,
     634           0 :                                                   smb_get_krb5_error_message(ccc->smb_krb5_context->krb5_context,
     635             :                                                                              ret, ccc));
     636           0 :                 talloc_free(ccc);
     637           0 :                 return ret;
     638             :         }
     639             : 
     640       46424 :         if (strncasecmp(ccache_name, "MEMORY:", 7) == 0) {
     641       46403 :                 talloc_set_destructor(ccc, free_mccache);
     642             :         } else {
     643          21 :                 talloc_set_destructor(ccc, free_dccache);
     644             :         }
     645             : 
     646       46424 :         if (must_free_cc_name) {
     647       46402 :                 talloc_free(ccache_name);
     648             :         }
     649             : 
     650       46424 :         *_ccc = ccc;
     651             : 
     652       46424 :         return 0;
     653             : }
     654             : 
     655       19727 : _PUBLIC_ int cli_credentials_get_named_ccache(struct cli_credentials *cred,
     656             :                                               struct tevent_context *event_ctx,
     657             :                                               struct loadparm_context *lp_ctx,
     658             :                                               char *ccache_name,
     659             :                                               struct ccache_container **ccc,
     660             :                                               const char **error_string)
     661             : {
     662         592 :         krb5_error_code ret;
     663         592 :         enum credentials_obtained obtained;
     664             : 
     665       19727 :         if (cred->machine_account_pending) {
     666           0 :                 cli_credentials_set_machine_account(cred, lp_ctx);
     667             :         }
     668             : 
     669       19727 :         if (cred->ccache_obtained >= cred->ccache_threshold &&
     670        4241 :             cred->ccache_obtained > CRED_UNINITIALISED) {
     671           0 :                 time_t lifetime;
     672        4241 :                 bool expired = false;
     673        4241 :                 ret = smb_krb5_cc_get_lifetime(cred->ccache->smb_krb5_context->krb5_context,
     674        4241 :                                                cred->ccache->ccache, &lifetime);
     675        4241 :                 if (ret == KRB5_CC_END || ret == ENOENT) {
     676             :                         /* If we have a particular ccache set, without
     677             :                          * an initial ticket, then assume there is a
     678             :                          * good reason */
     679        4241 :                 } else if (ret == 0) {
     680        4241 :                         if (lifetime == 0) {
     681           0 :                                 DEBUG(3, ("Ticket in credentials cache for %s expired, will refresh\n",
     682             :                                           cli_credentials_get_principal(cred, cred)));
     683           0 :                                 expired = true;
     684        4241 :                         } else if (lifetime < 300) {
     685           0 :                                 DEBUG(3, ("Ticket in credentials cache for %s will shortly expire (%u secs), will refresh\n",
     686             :                                           cli_credentials_get_principal(cred, cred), (unsigned int)lifetime));
     687           0 :                                 expired = true;
     688             :                         }
     689             :                 } else {
     690           0 :                         (*error_string) = talloc_asprintf(cred, "failed to get ccache lifetime: %s\n",
     691           0 :                                                           smb_get_krb5_error_message(cred->ccache->smb_krb5_context->krb5_context,
     692             :                                                                                      ret, cred));
     693        4241 :                         return ret;
     694             :                 }
     695             : 
     696        4241 :                 DEBUG(5, ("Ticket in credentials cache for %s will expire in %u secs\n",
     697             :                           cli_credentials_get_principal(cred, cred), (unsigned int)lifetime));
     698             : 
     699        4241 :                 if (!expired) {
     700        4241 :                         *ccc = cred->ccache;
     701        4241 :                         return 0;
     702             :                 }
     703             :         }
     704       15486 :         if (cli_credentials_is_anonymous(cred)) {
     705           0 :                 (*error_string) = "Cannot get anonymous kerberos credentials";
     706           0 :                 return EINVAL;
     707             :         }
     708             : 
     709       15486 :         ret = cli_credentials_new_ccache(cred, lp_ctx, ccache_name, ccc, error_string);
     710       15486 :         if (ret) {
     711           0 :                 return ret;
     712             :         }
     713             : 
     714       16078 :         ret = kinit_to_ccache(cred,
     715             :                               cred,
     716       14894 :                               (*ccc)->smb_krb5_context,
     717             :                               lp_ctx,
     718             :                               event_ctx,
     719       15486 :                               (*ccc)->ccache,
     720             :                               &obtained,
     721             :                               error_string);
     722       15486 :         if (ret) {
     723        1413 :                 return ret;
     724             :         }
     725             : 
     726       14073 :         ret = cli_credentials_set_from_ccache(cred, *ccc,
     727             :                                               obtained, error_string);
     728             : 
     729       14073 :         cred->ccache = *ccc;
     730       14073 :         cred->ccache_obtained = cred->principal_obtained;
     731       14073 :         if (ret) {
     732           0 :                 return ret;
     733             :         }
     734       14073 :         cli_credentials_invalidate_client_gss_creds(cred, cred->ccache_obtained);
     735       14073 :         return 0;
     736             : }
     737             : 
     738       17849 : _PUBLIC_ int cli_credentials_get_ccache(struct cli_credentials *cred,
     739             :                                         struct tevent_context *event_ctx,
     740             :                                         struct loadparm_context *lp_ctx,
     741             :                                         struct ccache_container **ccc,
     742             :                                         const char **error_string)
     743             : {
     744       17849 :         return cli_credentials_get_named_ccache(cred, event_ctx, lp_ctx, NULL, ccc, error_string);
     745             : }
     746             : 
     747             : /**
     748             :  * @brief Check if a valid Kerberos credential cache is attached.
     749             :  *
     750             :  * This will not ask for a password nor do a kinit.
     751             :  *
     752             :  * @param cred The credentials context.
     753             :  *
     754             :  * @param mem_ctx A memory context to allocate the ccache_name.
     755             :  *
     756             :  * @param ccache_name A pointer to a string to store the ccache name.
     757             :  *
     758             :  * @param obtained A pointer to store the information how the ccache was
     759             :  *                 obtained.
     760             :  *
     761             :  * @return True if a credential cache is attached, false if not or an error
     762             :  *         occurred.
     763             :  */
     764        4218 : _PUBLIC_ bool cli_credentials_get_ccache_name_obtained(
     765             :         struct cli_credentials *cred,
     766             :         TALLOC_CTX *mem_ctx,
     767             :         char **ccache_name,
     768             :         enum credentials_obtained *obtained)
     769             : {
     770        4218 :         if (ccache_name != NULL) {
     771        3219 :                 *ccache_name = NULL;
     772             :         }
     773             : 
     774        4218 :         if (obtained != NULL) {
     775        4214 :                 *obtained = CRED_UNINITIALISED;
     776             :         }
     777             : 
     778        4218 :         if (cred->machine_account_pending) {
     779           0 :                 return false;
     780             :         }
     781             : 
     782        4218 :         if (cred->ccache_obtained == CRED_UNINITIALISED) {
     783        2853 :                 return false;
     784             :         }
     785             : 
     786        1362 :         if (cred->ccache_obtained >= cred->ccache_threshold) {
     787        1013 :                 krb5_context k5ctx = cred->ccache->smb_krb5_context->krb5_context;
     788        1013 :                 krb5_ccache k5ccache = cred->ccache->ccache;
     789           0 :                 krb5_error_code ret;
     790        1013 :                 time_t lifetime = 0;
     791             : 
     792        1013 :                 ret = smb_krb5_cc_get_lifetime(k5ctx, k5ccache, &lifetime);
     793        1013 :                 if (ret == KRB5_CC_END || ret == ENOENT) {
     794           0 :                         return false;
     795             :                 }
     796        1013 :                 if (ret != 0) {
     797           0 :                         return false;
     798             :                 }
     799        1013 :                 if (lifetime == 0) {
     800           0 :                         return false;
     801        1013 :                 } else if (lifetime < 300) {
     802           6 :                         if (cred->password_obtained >= cred->ccache_obtained) {
     803             :                                 /*
     804             :                                  * we have a password to re-kinit
     805             :                                  * so let the caller try that.
     806             :                                  */
     807           0 :                                 return false;
     808             :                         }
     809             :                 }
     810             : 
     811        1013 :                 if (ccache_name != NULL) {
     812         730 :                         char *name = NULL;
     813             : 
     814         730 :                         ret = krb5_cc_get_full_name(k5ctx, k5ccache, &name);
     815         730 :                         if (ret != 0) {
     816           0 :                                 return false;
     817             :                         }
     818             : 
     819         730 :                         *ccache_name = talloc_strdup(mem_ctx, name);
     820         730 :                         SAFE_FREE(name);
     821         730 :                         if (*ccache_name == NULL) {
     822           0 :                                 return false;
     823             :                         }
     824             :                 }
     825             : 
     826        1013 :                 if (obtained != NULL) {
     827        1009 :                         *obtained = cred->ccache_obtained;
     828             :                 }
     829             : 
     830        1013 :                 return true;
     831             :         }
     832             : 
     833         349 :         return false;
     834             : }
     835             : 
     836             : /* We have good reason to think the ccache in these credentials is invalid - blow it away */
     837           0 : static void cli_credentials_unconditionally_invalidate_client_gss_creds(struct cli_credentials *cred)
     838             : {
     839           0 :         if (cred->client_gss_creds_obtained > CRED_UNINITIALISED) {
     840           0 :                 talloc_unlink(cred, cred->client_gss_creds);
     841           0 :                 cred->client_gss_creds = NULL;
     842             :         }
     843           0 :         cred->client_gss_creds_obtained = CRED_UNINITIALISED;
     844           0 : }
     845             : 
     846     1598418 : void cli_credentials_invalidate_client_gss_creds(struct cli_credentials *cred,
     847             :                                                  enum credentials_obtained obtained)
     848             : {
     849             :         /* If the caller just changed the username/password etc, then
     850             :          * any cached credentials are now invalid */
     851     1598418 :         if (obtained >= cred->client_gss_creds_obtained) {
     852     1598402 :                 if (cred->client_gss_creds_obtained > CRED_UNINITIALISED) {
     853        4194 :                         talloc_unlink(cred, cred->client_gss_creds);
     854        4194 :                         cred->client_gss_creds = NULL;
     855             :                 }
     856     1598402 :                 cred->client_gss_creds_obtained = CRED_UNINITIALISED;
     857             :         }
     858             :         /* Now that we know that the data is 'this specified', then
     859             :          * don't allow something less 'known' to be returned as a
     860             :          * ccache.  Ie, if the username is on the command line, we
     861             :          * don't want to later guess to use a file-based ccache */
     862     1598418 :         if (obtained > cred->client_gss_creds_threshold) {
     863      620825 :                 cred->client_gss_creds_threshold = obtained;
     864             :         }
     865     1598418 : }
     866             : 
     867             : /* We have good reason to think this CCACHE is invalid.  Blow it away */
     868           0 : static void cli_credentials_unconditionally_invalidate_ccache(struct cli_credentials *cred)
     869             : {
     870           0 :         if (cred->ccache_obtained > CRED_UNINITIALISED) {
     871           0 :                 talloc_unlink(cred, cred->ccache);
     872           0 :                 cred->ccache = NULL;
     873             :         }
     874           0 :         cred->ccache_obtained = CRED_UNINITIALISED;
     875             : 
     876           0 :         cli_credentials_unconditionally_invalidate_client_gss_creds(cred);
     877           0 : }
     878             : 
     879     1481073 : _PUBLIC_ void cli_credentials_invalidate_ccache(struct cli_credentials *cred,
     880             :                                        enum credentials_obtained obtained)
     881             : {
     882             :         /* If the caller just changed the username/password etc, then
     883             :          * any cached credentials are now invalid */
     884     1481073 :         if (obtained >= cred->ccache_obtained) {
     885     1465410 :                 if (cred->ccache_obtained > CRED_UNINITIALISED) {
     886       72872 :                         talloc_unlink(cred, cred->ccache);
     887       72872 :                         cred->ccache = NULL;
     888             :                 }
     889     1465410 :                 cred->ccache_obtained = CRED_UNINITIALISED;
     890             :         }
     891             :         /* Now that we know that the data is 'this specified', then
     892             :          * don't allow something less 'known' to be returned as a
     893             :          * ccache.  i.e, if the username is on the command line, we
     894             :          * don't want to later guess to use a file-based ccache */
     895     1481073 :         if (obtained > cred->ccache_threshold) {
     896      546307 :                 cred->ccache_threshold  = obtained;
     897             :         }
     898             : 
     899     1481073 :         cli_credentials_invalidate_client_gss_creds(cred,
     900             :                                                     obtained);
     901     1481073 : }
     902             : 
     903       92913 : static int free_gssapi_creds(struct gssapi_creds_container *gcc)
     904             : {
     905        3658 :         OM_uint32 min_stat;
     906       92913 :         (void)gss_release_cred(&min_stat, &gcc->creds);
     907       92913 :         return 0;
     908             : }
     909             : 
     910       32564 : _PUBLIC_ int cli_credentials_get_client_gss_creds(struct cli_credentials *cred,
     911             :                                                   struct tevent_context *event_ctx,
     912             :                                                   struct loadparm_context *lp_ctx,
     913             :                                                   struct gssapi_creds_container **_gcc,
     914             :                                                   const char **error_string)
     915             : {
     916       32564 :         int ret = 0;
     917        1042 :         OM_uint32 maj_stat, min_stat;
     918        1042 :         struct gssapi_creds_container *gcc;
     919        1042 :         struct ccache_container *ccache;
     920             : #ifdef HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X
     921       32564 :         gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER;
     922       32564 :         gss_OID oid = discard_const(GSS_KRB5_CRED_NO_CI_FLAGS_X);
     923             : #endif
     924       32564 :         krb5_enctype *etypes = NULL;
     925             : 
     926       32564 :         if (cred->client_gss_creds_obtained >= cred->client_gss_creds_threshold &&
     927       14415 :             cred->client_gss_creds_obtained > CRED_UNINITIALISED) {
     928       14865 :                 bool expired = false;
     929       14865 :                 OM_uint32 lifetime = 0;
     930       14865 :                 gss_cred_usage_t usage = 0;
     931       14865 :                 maj_stat = gss_inquire_cred(&min_stat, cred->client_gss_creds->creds,
     932             :                                             NULL, &lifetime, &usage, NULL);
     933       14865 :                 if (maj_stat == GSS_S_CREDENTIALS_EXPIRED) {
     934           0 :                         DEBUG(3, ("Credentials for %s expired, must refresh credentials cache\n", cli_credentials_get_principal(cred, cred)));
     935           0 :                         expired = true;
     936       14865 :                 } else if (maj_stat == GSS_S_COMPLETE && lifetime < 300) {
     937           0 :                         DEBUG(3, ("Credentials for %s will expire shortly (%u sec), must refresh credentials cache\n", cli_credentials_get_principal(cred, cred), lifetime));
     938           0 :                         expired = true;
     939       14865 :                 } else if (maj_stat != GSS_S_COMPLETE) {
     940           0 :                         *error_string = talloc_asprintf(cred, "inquiry of credential lifetime via GSSAPI gss_inquire_cred failed: %s\n",
     941             :                                                         gssapi_error_string(cred, maj_stat, min_stat, NULL));
     942       14865 :                         return EINVAL;
     943             :                 }
     944       14865 :                 if (expired) {
     945           0 :                         cli_credentials_unconditionally_invalidate_client_gss_creds(cred);
     946             :                 } else {
     947       14865 :                         DEBUG(5, ("GSSAPI credentials for %s will expire in %u secs\n",
     948             :                                   cli_credentials_get_principal(cred, cred), (unsigned int)lifetime));
     949             : 
     950       14865 :                         *_gcc = cred->client_gss_creds;
     951       14865 :                         return 0;
     952             :                 }
     953             :         }
     954             : 
     955       17699 :         ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx,
     956             :                                          &ccache, error_string);
     957       17699 :         if (ret) {
     958        1413 :                 if (cli_credentials_get_kerberos_state(cred) == CRED_USE_KERBEROS_REQUIRED) {
     959         184 :                         DEBUG(1, ("Failed to get kerberos credentials (kerberos required): %s\n", *error_string));
     960             :                 } else {
     961        1229 :                         DEBUG(4, ("Failed to get kerberos credentials: %s\n", *error_string));
     962             :                 }
     963        1413 :                 return ret;
     964             :         }
     965             : 
     966       16286 :         gcc = talloc(cred, struct gssapi_creds_container);
     967       16286 :         if (!gcc) {
     968           0 :                 (*error_string) = error_message(ENOMEM);
     969           0 :                 return ENOMEM;
     970             :         }
     971             : 
     972       16878 :         maj_stat = smb_gss_krb5_import_cred(&min_stat, ccache->smb_krb5_context->krb5_context,
     973       16286 :                                             ccache->ccache, NULL, NULL,
     974             :                                             &gcc->creds);
     975       16286 :         if ((maj_stat == GSS_S_FAILURE) &&
     976           0 :             (min_stat == (OM_uint32)KRB5_CC_END ||
     977           0 :              min_stat == (OM_uint32)KRB5_CC_NOTFOUND ||
     978           0 :              min_stat == (OM_uint32)KRB5_FCC_NOFILE))
     979             :         {
     980             :                 /* This CCACHE is no good.  Ensure we don't use it again */
     981           0 :                 cli_credentials_unconditionally_invalidate_ccache(cred);
     982             : 
     983             :                 /* Now try again to get a ccache */
     984           0 :                 ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx,
     985             :                                                  &ccache, error_string);
     986           0 :                 if (ret) {
     987           0 :                         DEBUG(1, ("Failed to re-get CCACHE for GSSAPI client: %s\n", error_message(ret)));
     988           0 :                         return ret;
     989             :                 }
     990             : 
     991           0 :                 maj_stat = smb_gss_krb5_import_cred(&min_stat, ccache->smb_krb5_context->krb5_context,
     992           0 :                                                     ccache->ccache, NULL, NULL,
     993             :                                                     &gcc->creds);
     994             : 
     995             :         }
     996             : 
     997       16286 :         if (maj_stat) {
     998           0 :                 talloc_free(gcc);
     999           0 :                 if (min_stat) {
    1000           0 :                         ret = min_stat;
    1001             :                 } else {
    1002           0 :                         ret = EINVAL;
    1003             :                 }
    1004           0 :                 (*error_string) = talloc_asprintf(cred, "smb_gss_krb5_import_cred failed: %s", error_message(ret));
    1005           0 :                 return ret;
    1006             :         }
    1007             : 
    1008             : 
    1009             :         /*
    1010             :          * transfer the enctypes from the smb_krb5_context to the gssapi layer
    1011             :          *
    1012             :          * We use 'our' smb_krb5_context to do the AS-REQ and it is possible
    1013             :          * to configure the enctypes via the krb5.conf.
    1014             :          *
    1015             :          * And the gss_init_sec_context() creates it's own krb5_context and
    1016             :          * the TGS-REQ had all enctypes in it and only the ones configured
    1017             :          * and used for the AS-REQ, so it wasn't possible to disable the usage
    1018             :          * of AES keys.
    1019             :          */
    1020       16286 :         min_stat = smb_krb5_get_allowed_etypes(ccache->smb_krb5_context->krb5_context,
    1021             :                                                &etypes);
    1022       16286 :         if (min_stat == 0) {
    1023             :                 OM_uint32 num_ktypes;
    1024             : 
    1025      115369 :                 for (num_ktypes = 0; etypes[num_ktypes]; num_ktypes++);
    1026             : 
    1027       16286 :                 maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, gcc->creds,
    1028             :                                                            num_ktypes,
    1029             :                                                            (int32_t *) etypes);
    1030       16286 :                 krb5_free_enctypes(ccache->smb_krb5_context->krb5_context,
    1031             :                                    etypes);
    1032       16286 :                 if (maj_stat) {
    1033           0 :                         talloc_free(gcc);
    1034           0 :                         if (min_stat) {
    1035           0 :                                 ret = min_stat;
    1036             :                         } else {
    1037           0 :                                 ret = EINVAL;
    1038             :                         }
    1039           0 :                         (*error_string) = talloc_asprintf(cred, "gss_krb5_set_allowable_enctypes failed: %s", error_message(ret));
    1040           0 :                         return ret;
    1041             :                 }
    1042             :         }
    1043             : 
    1044             : #ifdef HAVE_GSS_KRB5_CRED_NO_CI_FLAGS_X
    1045             :         /*
    1046             :          * Don't force GSS_C_CONF_FLAG and GSS_C_INTEG_FLAG.
    1047             :          *
    1048             :          * This allows us to disable SIGN and SEAL on a TLS connection with
    1049             :          * GSS-SPNENO. For example ldaps:// connections.
    1050             :          *
    1051             :          * https://groups.yahoo.com/neo/groups/cat-ietf/conversations/topics/575
    1052             :          * http://krbdev.mit.edu/rt/Ticket/Display.html?id=6938
    1053             :          */
    1054       16286 :         maj_stat = gss_set_cred_option(&min_stat, &gcc->creds,
    1055             :                                        oid,
    1056             :                                        &empty_buffer);
    1057       16286 :         if (maj_stat) {
    1058           0 :                 talloc_free(gcc);
    1059           0 :                 if (min_stat) {
    1060           0 :                         ret = min_stat;
    1061             :                 } else {
    1062           0 :                         ret = EINVAL;
    1063             :                 }
    1064           0 :                 (*error_string) = talloc_asprintf(cred, "gss_set_cred_option failed: %s", error_message(ret));
    1065           0 :                 return ret;
    1066             :         }
    1067             : #endif
    1068       16286 :         cred->client_gss_creds_obtained = cred->ccache_obtained;
    1069       16286 :         talloc_set_destructor(gcc, free_gssapi_creds);
    1070       16286 :         cred->client_gss_creds = gcc;
    1071       16286 :         *_gcc = gcc;
    1072       16286 :         return 0;
    1073             : }
    1074             : 
    1075             : /**
    1076             :    Set a gssapi cred_id_t into the credentials system. (Client case)
    1077             : 
    1078             :    This grabs the credentials both 'intact' and getting the krb5
    1079             :    ccache out of it.  This routine can be generalised in future for
    1080             :    the case where we deal with GSSAPI mechs other than krb5.
    1081             : 
    1082             :    On success, the caller must not free gssapi_cred, as it now belongs
    1083             :    to the credentials system.
    1084             : */
    1085             : 
    1086       30938 :  int cli_credentials_set_client_gss_creds(struct cli_credentials *cred,
    1087             :                                           struct loadparm_context *lp_ctx,
    1088             :                                           gss_cred_id_t gssapi_cred,
    1089             :                                           enum credentials_obtained obtained,
    1090             :                                           const char **error_string)
    1091             : {
    1092         888 :         int ret;
    1093         888 :         OM_uint32 maj_stat, min_stat;
    1094       30938 :         struct ccache_container *ccc = NULL;
    1095       30938 :         struct gssapi_creds_container *gcc = NULL;
    1096       30938 :         if (cred->client_gss_creds_obtained > obtained) {
    1097           0 :                 return 0;
    1098             :         }
    1099             : 
    1100       30938 :         gcc = talloc(cred, struct gssapi_creds_container);
    1101       30938 :         if (!gcc) {
    1102           0 :                 (*error_string) = error_message(ENOMEM);
    1103           0 :                 return ENOMEM;
    1104             :         }
    1105             : 
    1106       30938 :         ret = cli_credentials_new_ccache(cred, lp_ctx, NULL, &ccc, error_string);
    1107       30938 :         if (ret != 0) {
    1108           0 :                 return ret;
    1109             :         }
    1110             : 
    1111       30938 :         maj_stat = smb_gss_krb5_copy_ccache(&min_stat,
    1112             :                                             gssapi_cred,
    1113             :                                             ccc);
    1114       30938 :         if (maj_stat) {
    1115           0 :                 if (min_stat) {
    1116           0 :                         ret = min_stat;
    1117             :                 } else {
    1118           0 :                         ret = EINVAL;
    1119             :                 }
    1120           0 :                 if (ret) {
    1121           0 :                         (*error_string) = error_message(ENOMEM);
    1122             :                 }
    1123             :         }
    1124             : 
    1125       30938 :         if (ret == 0) {
    1126       30938 :                 ret = cli_credentials_set_from_ccache(cred, ccc, obtained, error_string);
    1127             :         }
    1128       30938 :         cred->ccache = ccc;
    1129       30938 :         cred->ccache_obtained = obtained;
    1130       30938 :         if (ret == 0) {
    1131       30938 :                 gcc->creds = gssapi_cred;
    1132       30938 :                 talloc_set_destructor(gcc, free_gssapi_creds);
    1133             : 
    1134             :                 /* set the client_gss_creds_obtained here, as it just
    1135             :                    got set to UNINITIALISED by the calls above */
    1136       30938 :                 cred->client_gss_creds_obtained = obtained;
    1137       30938 :                 cred->client_gss_creds = gcc;
    1138             :         }
    1139       30050 :         return ret;
    1140             : }
    1141             : 
    1142         610 : static int cli_credentials_shallow_ccache(struct cli_credentials *cred)
    1143             : {
    1144          81 :         krb5_error_code ret;
    1145         610 :         const struct ccache_container *old_ccc = NULL;
    1146          81 :         enum credentials_obtained old_obtained;
    1147         610 :         struct ccache_container *ccc = NULL;
    1148          81 :         krb5_principal princ;
    1149             : 
    1150         610 :         old_obtained = cred->ccache_obtained;
    1151         610 :         old_ccc = cred->ccache;
    1152         610 :         if (old_ccc == NULL) {
    1153         247 :                 return 0;
    1154             :         }
    1155             : 
    1156         320 :         cred->ccache = NULL;
    1157         320 :         cred->ccache_obtained = CRED_UNINITIALISED;
    1158         320 :         cred->client_gss_creds = NULL;
    1159         320 :         cred->client_gss_creds_obtained = CRED_UNINITIALISED;
    1160             : 
    1161         358 :         ret = krb5_cc_get_principal(
    1162         320 :                 old_ccc->smb_krb5_context->krb5_context,
    1163         320 :                 old_ccc->ccache,
    1164             :                 &princ);
    1165         320 :         if (ret != 0) {
    1166             :                 /*
    1167             :                  * This is an empty ccache. No point in copying anything.
    1168             :                  */
    1169           0 :                 return 0;
    1170             :         }
    1171         320 :         krb5_free_principal(old_ccc->smb_krb5_context->krb5_context, princ);
    1172             : 
    1173         320 :         ccc = talloc(cred, struct ccache_container);
    1174         320 :         if (ccc == NULL) {
    1175           0 :                 return ENOMEM;
    1176             :         }
    1177         320 :         *ccc = *old_ccc;
    1178         320 :         ccc->ccache = NULL;
    1179             : 
    1180         320 :         ret = smb_krb5_cc_new_unique_memory(ccc->smb_krb5_context->krb5_context,
    1181             :                                             NULL,
    1182             :                                             NULL,
    1183             :                                             &ccc->ccache);
    1184         320 :         if (ret != 0) {
    1185           0 :                 TALLOC_FREE(ccc);
    1186           0 :                 return ret;
    1187             :         }
    1188             : 
    1189         320 :         talloc_set_destructor(ccc, free_mccache);
    1190             : 
    1191         358 :         ret = smb_krb5_cc_copy_creds(ccc->smb_krb5_context->krb5_context,
    1192         320 :                                      old_ccc->ccache, ccc->ccache);
    1193         320 :         if (ret != 0) {
    1194           0 :                 TALLOC_FREE(ccc);
    1195           0 :                 return ret;
    1196             :         }
    1197             : 
    1198         320 :         cred->ccache = ccc;
    1199         320 :         cred->ccache_obtained = old_obtained;
    1200         320 :         return ret;
    1201             : }
    1202             : 
    1203         610 : _PUBLIC_ struct cli_credentials *cli_credentials_shallow_copy(TALLOC_CTX *mem_ctx,
    1204             :                                                 struct cli_credentials *src)
    1205             : {
    1206          81 :         struct cli_credentials *dst, *armor_credentials;
    1207          81 :         int ret;
    1208             : 
    1209         610 :         dst = talloc(mem_ctx, struct cli_credentials);
    1210         610 :         if (dst == NULL) {
    1211           0 :                 return NULL;
    1212             :         }
    1213             : 
    1214         610 :         *dst = *src;
    1215             : 
    1216         610 :         if (dst->krb5_fast_armor_credentials != NULL) {
    1217           0 :                 armor_credentials = talloc_reference(dst, dst->krb5_fast_armor_credentials);
    1218           0 :                 if (armor_credentials == NULL) {
    1219           0 :                         TALLOC_FREE(dst);
    1220           0 :                         return NULL;
    1221             :                 }
    1222             :         }
    1223             : 
    1224         610 :         ret = cli_credentials_shallow_ccache(dst);
    1225         610 :         if (ret != 0) {
    1226           0 :                 TALLOC_FREE(dst);
    1227           0 :                 return NULL;
    1228             :         }
    1229             : 
    1230         529 :         return dst;
    1231             : }
    1232             : 
    1233             : /* Get the keytab (actually, a container containing the krb5_keytab)
    1234             :  * attached to this context.  If this hasn't been done or set before,
    1235             :  * it will be generated from the password.
    1236             :  */
    1237       46844 : _PUBLIC_ int cli_credentials_get_keytab(struct cli_credentials *cred,
    1238             :                                         struct loadparm_context *lp_ctx,
    1239             :                                         struct keytab_container **_ktc)
    1240             : {
    1241        2184 :         krb5_error_code ret;
    1242        2184 :         struct keytab_container *ktc;
    1243        2184 :         struct smb_krb5_context *smb_krb5_context;
    1244        2184 :         const char *keytab_name;
    1245        2184 :         krb5_keytab keytab;
    1246        2184 :         TALLOC_CTX *mem_ctx;
    1247       46844 :         const char *username = cli_credentials_get_username(cred);
    1248       46844 :         const char *realm = cli_credentials_get_realm(cred);
    1249       46844 :         char *salt_principal = NULL;
    1250             : 
    1251       46844 :         if (cred->keytab_obtained >= (MAX(cred->principal_obtained,
    1252             :                                           cred->username_obtained))) {
    1253       46747 :                 *_ktc = cred->keytab;
    1254       46747 :                 return 0;
    1255             :         }
    1256             : 
    1257          97 :         if (cli_credentials_is_anonymous(cred)) {
    1258           0 :                 return EINVAL;
    1259             :         }
    1260             : 
    1261          97 :         ret = cli_credentials_get_krb5_context(cred, lp_ctx,
    1262             :                                                &smb_krb5_context);
    1263          97 :         if (ret) {
    1264           0 :                 return ret;
    1265             :         }
    1266             : 
    1267          97 :         mem_ctx = talloc_new(cred);
    1268          97 :         if (!mem_ctx) {
    1269           0 :                 return ENOMEM;
    1270             :         }
    1271             : 
    1272          97 :         salt_principal = cli_credentials_get_salt_principal(cred, mem_ctx);
    1273          97 :         if (salt_principal == NULL) {
    1274           0 :                 talloc_free(mem_ctx);
    1275           0 :                 return ENOMEM;
    1276             :         }
    1277             : 
    1278          97 :         ret = smb_krb5_create_memory_keytab(mem_ctx,
    1279          97 :                                             smb_krb5_context->krb5_context,
    1280             :                                             cli_credentials_get_password(cred),
    1281             :                                             username,
    1282             :                                             realm,
    1283             :                                             salt_principal,
    1284             :                                             cli_credentials_get_kvno(cred),
    1285             :                                             &keytab,
    1286             :                                             &keytab_name);
    1287          97 :         if (ret) {
    1288           0 :                 talloc_free(mem_ctx);
    1289           0 :                 return ret;
    1290             :         }
    1291             : 
    1292          97 :         ret = smb_krb5_get_keytab_container(mem_ctx, smb_krb5_context,
    1293             :                                             keytab, keytab_name, &ktc);
    1294          97 :         if (ret) {
    1295           0 :                 talloc_free(mem_ctx);
    1296           0 :                 return ret;
    1297             :         }
    1298             : 
    1299          97 :         cred->keytab_obtained = (MAX(cred->principal_obtained,
    1300             :                                      cred->username_obtained));
    1301             : 
    1302             :         /* We make this keytab up based on a password.  Therefore
    1303             :          * match-by-key is acceptable, we can't match on the wrong
    1304             :          * principal */
    1305          97 :         ktc->password_based = true;
    1306             : 
    1307          97 :         talloc_steal(cred, ktc);
    1308          97 :         cred->keytab = ktc;
    1309          97 :         *_ktc = cred->keytab;
    1310          97 :         talloc_free(mem_ctx);
    1311          97 :         return ret;
    1312             : }
    1313             : 
    1314             : /* Given the name of a keytab (presumably in the format
    1315             :  * FILE:/etc/krb5.keytab), open it and attach it */
    1316             : 
    1317       67150 : _PUBLIC_ int cli_credentials_set_keytab_name(struct cli_credentials *cred,
    1318             :                                              struct loadparm_context *lp_ctx,
    1319             :                                              const char *keytab_name,
    1320             :                                              enum credentials_obtained obtained)
    1321             : {
    1322        2699 :         krb5_error_code ret;
    1323        2699 :         struct keytab_container *ktc;
    1324        2699 :         struct smb_krb5_context *smb_krb5_context;
    1325        2699 :         TALLOC_CTX *mem_ctx;
    1326             : 
    1327       67150 :         if (cred->keytab_obtained >= obtained) {
    1328           0 :                 return 0;
    1329             :         }
    1330             : 
    1331       67150 :         ret = cli_credentials_get_krb5_context(cred, lp_ctx, &smb_krb5_context);
    1332       67150 :         if (ret) {
    1333           0 :                 return ret;
    1334             :         }
    1335             : 
    1336       67150 :         mem_ctx = talloc_new(cred);
    1337       67150 :         if (!mem_ctx) {
    1338           0 :                 return ENOMEM;
    1339             :         }
    1340             : 
    1341       67150 :         ret = smb_krb5_get_keytab_container(mem_ctx, smb_krb5_context,
    1342             :                                             NULL, keytab_name, &ktc);
    1343       67150 :         if (ret) {
    1344           0 :                 return ret;
    1345             :         }
    1346             : 
    1347       67150 :         cred->keytab_obtained = obtained;
    1348             : 
    1349       67150 :         talloc_steal(cred, ktc);
    1350       67150 :         cred->keytab = ktc;
    1351       67150 :         talloc_free(mem_ctx);
    1352             : 
    1353       67150 :         return ret;
    1354             : }
    1355             : 
    1356             : /* Get server gss credentials (in gsskrb5, this means the keytab) */
    1357             : 
    1358       48017 : _PUBLIC_ int cli_credentials_get_server_gss_creds(struct cli_credentials *cred,
    1359             :                                                   struct loadparm_context *lp_ctx,
    1360             :                                                   struct gssapi_creds_container **_gcc)
    1361             : {
    1362       48017 :         int ret = 0;
    1363        2184 :         OM_uint32 maj_stat, min_stat;
    1364        2184 :         struct gssapi_creds_container *gcc;
    1365        2184 :         struct keytab_container *ktc;
    1366        2184 :         struct smb_krb5_context *smb_krb5_context;
    1367        2184 :         TALLOC_CTX *mem_ctx;
    1368        2184 :         krb5_principal princ;
    1369        2184 :         const char *error_string;
    1370        2184 :         enum credentials_obtained obtained;
    1371             : 
    1372       48017 :         mem_ctx = talloc_new(cred);
    1373       48017 :         if (!mem_ctx) {
    1374           0 :                 return ENOMEM;
    1375             :         }
    1376             : 
    1377       48017 :         ret = cli_credentials_get_krb5_context(cred, lp_ctx, &smb_krb5_context);
    1378       48017 :         if (ret) {
    1379           0 :                 return ret;
    1380             :         }
    1381             : 
    1382       48017 :         ret = principal_from_credentials(mem_ctx, cred, smb_krb5_context, &princ, &obtained, &error_string);
    1383       48017 :         if (ret) {
    1384           0 :                 DEBUG(1,("cli_credentials_get_server_gss_creds: making krb5 principal failed (%s)\n",
    1385             :                          error_string));
    1386           0 :                 talloc_free(mem_ctx);
    1387           0 :                 return ret;
    1388             :         }
    1389             : 
    1390       48017 :         if (cred->server_gss_creds_obtained >= (MAX(cred->keytab_obtained, obtained))) {
    1391        2447 :                 talloc_free(mem_ctx);
    1392        2447 :                 *_gcc = cred->server_gss_creds;
    1393        2447 :                 return 0;
    1394             :         }
    1395             : 
    1396       45570 :         ret = cli_credentials_get_keytab(cred, lp_ctx, &ktc);
    1397       45570 :         if (ret) {
    1398           0 :                 DEBUG(1, ("Failed to get keytab for GSSAPI server: %s\n", error_message(ret)));
    1399           0 :                 return ret;
    1400             :         }
    1401             : 
    1402       45570 :         gcc = talloc(cred, struct gssapi_creds_container);
    1403       45570 :         if (!gcc) {
    1404           0 :                 talloc_free(mem_ctx);
    1405           0 :                 return ENOMEM;
    1406             :         }
    1407             : 
    1408       45570 :         if (ktc->password_based || obtained < CRED_SPECIFIED) {
    1409             :                 /*
    1410             :                  * This creates a GSSAPI cred_id_t for match-by-key with only
    1411             :                  * the keytab set
    1412             :                  */
    1413          97 :                 princ = NULL;
    1414             :         }
    1415       47754 :         maj_stat = smb_gss_krb5_import_cred(&min_stat,
    1416       45570 :                                             smb_krb5_context->krb5_context,
    1417             :                                             NULL, princ,
    1418       43386 :                                             ktc->keytab,
    1419             :                                             &gcc->creds);
    1420       45570 :         if (maj_stat) {
    1421           0 :                 if (min_stat) {
    1422           0 :                         ret = min_stat;
    1423             :                 } else {
    1424           0 :                         ret = EINVAL;
    1425             :                 }
    1426             :         }
    1427       45570 :         if (ret == 0) {
    1428       45570 :                 cred->server_gss_creds_obtained = cred->keytab_obtained;
    1429       45570 :                 talloc_set_destructor(gcc, free_gssapi_creds);
    1430       45570 :                 cred->server_gss_creds = gcc;
    1431       45570 :                 *_gcc = gcc;
    1432             :         }
    1433       45570 :         talloc_free(mem_ctx);
    1434       45570 :         return ret;
    1435             : }
    1436             : 
    1437             : /**
    1438             :  * Set Kerberos KVNO
    1439             :  */
    1440             : 
    1441       67828 : _PUBLIC_ void cli_credentials_set_kvno(struct cli_credentials *cred,
    1442             :                               int kvno)
    1443             : {
    1444       67828 :         cred->kvno = kvno;
    1445       67828 : }
    1446             : 
    1447             : /**
    1448             :  * Return Kerberos KVNO
    1449             :  */
    1450             : 
    1451         103 : _PUBLIC_ int cli_credentials_get_kvno(struct cli_credentials *cred)
    1452             : {
    1453         103 :         return cred->kvno;
    1454             : }
    1455             : 
    1456             : 
    1457         213 : char *cli_credentials_get_salt_principal(struct cli_credentials *cred, TALLOC_CTX *mem_ctx)
    1458             : {
    1459         213 :         TALLOC_CTX *frame = NULL;
    1460         213 :         const char *realm = NULL;
    1461         213 :         const char *username = NULL;
    1462         213 :         uint32_t uac_flags = 0;
    1463         213 :         char *salt_principal = NULL;
    1464         213 :         const char *upn = NULL;
    1465           0 :         int ret;
    1466             : 
    1467             :         /* If specified, use the specified value */
    1468         213 :         if (cred->salt_principal != NULL) {
    1469         114 :                 return talloc_strdup(mem_ctx, cred->salt_principal);
    1470             :         }
    1471             : 
    1472          99 :         frame = talloc_stackframe();
    1473             : 
    1474          99 :         switch (cred->secure_channel_type) {
    1475          51 :         case SEC_CHAN_WKSTA:
    1476             :         case SEC_CHAN_RODC:
    1477          51 :                 uac_flags = UF_WORKSTATION_TRUST_ACCOUNT;
    1478          51 :                 break;
    1479          30 :         case SEC_CHAN_BDC:
    1480          30 :                 uac_flags = UF_SERVER_TRUST_ACCOUNT;
    1481          30 :                 break;
    1482           0 :         case SEC_CHAN_DOMAIN:
    1483             :         case SEC_CHAN_DNS_DOMAIN:
    1484           0 :                 uac_flags = UF_INTERDOMAIN_TRUST_ACCOUNT;
    1485           0 :                 break;
    1486          18 :         default:
    1487          18 :                 upn = cli_credentials_get_principal(cred, frame);
    1488          18 :                 if (upn == NULL) {
    1489           0 :                         TALLOC_FREE(frame);
    1490           0 :                         return NULL;
    1491             :                 }
    1492          18 :                 uac_flags = UF_NORMAL_ACCOUNT;
    1493          18 :                 break;
    1494             :         }
    1495             : 
    1496          99 :         realm = cli_credentials_get_realm(cred);
    1497          99 :         username = cli_credentials_get_username(cred);
    1498             : 
    1499          99 :         ret = smb_krb5_salt_principal_str(realm,
    1500             :                                           username, /* sAMAccountName */
    1501             :                                           upn, /* userPrincipalName */
    1502             :                                           uac_flags,
    1503             :                                           mem_ctx,
    1504             :                                           &salt_principal);
    1505          99 :         if (ret) {
    1506           0 :                 TALLOC_FREE(frame);
    1507           0 :                 return NULL;
    1508             :         }
    1509             : 
    1510          99 :         TALLOC_FREE(frame);
    1511          99 :         return salt_principal;
    1512             : }
    1513             : 
    1514       67142 : _PUBLIC_ void cli_credentials_set_salt_principal(struct cli_credentials *cred, const char *principal)
    1515             : {
    1516       67142 :         talloc_free(cred->salt_principal);
    1517       67142 :         cred->salt_principal = talloc_strdup(cred, principal);
    1518       67142 : }
    1519             : 
    1520             : /* The 'impersonate_principal' is used to allow one Kerberos principal
    1521             :  * (and it's associated keytab etc) to impersonate another.  The
    1522             :  * ability to do this is controlled by the KDC, but it is generally
    1523             :  * permitted to impersonate anyone to yourself.  This allows any
    1524             :  * member of the domain to get the groups of a user.  This is also
    1525             :  * known as S4U2Self */
    1526             : 
    1527       46889 : _PUBLIC_ const char *cli_credentials_get_impersonate_principal(struct cli_credentials *cred)
    1528             : {
    1529       46889 :         return cred->impersonate_principal;
    1530             : }
    1531             : 
    1532             : /*
    1533             :  * The 'self_service' is the service principal that
    1534             :  * represents the same object (by its objectSid)
    1535             :  * as the client principal (typically our machine account).
    1536             :  * When trying to impersonate 'impersonate_principal' with
    1537             :  * S4U2Self.
    1538             :  */
    1539       15486 : _PUBLIC_ const char *cli_credentials_get_self_service(struct cli_credentials *cred)
    1540             : {
    1541       15486 :         return cred->self_service;
    1542             : }
    1543             : 
    1544          55 : _PUBLIC_ void cli_credentials_set_impersonate_principal(struct cli_credentials *cred,
    1545             :                                                         const char *principal,
    1546             :                                                         const char *self_service)
    1547             : {
    1548          55 :         talloc_free(cred->impersonate_principal);
    1549          55 :         cred->impersonate_principal = talloc_strdup(cred, principal);
    1550          55 :         talloc_free(cred->self_service);
    1551          55 :         cred->self_service = talloc_strdup(cred, self_service);
    1552          55 :         cli_credentials_set_kerberos_state(cred,
    1553             :                                            CRED_USE_KERBEROS_REQUIRED,
    1554             :                                            CRED_SPECIFIED);
    1555          55 : }
    1556             : 
    1557             : /*
    1558             :  * when impersonating for S4U2proxy we need to set the target principal.
    1559             :  * Similarly, we may only be authorized to do general impersonation to
    1560             :  * some particular services.
    1561             :  *
    1562             :  * Likewise, password changes typically require a ticket to kpasswd/realm directly, not via a TGT
    1563             :  *
    1564             :  * NULL means that tickets will be obtained for the krbtgt service.
    1565             : */
    1566             : 
    1567       15486 : const char *cli_credentials_get_target_service(struct cli_credentials *cred)
    1568             : {
    1569       15486 :         return cred->target_service;
    1570             : }
    1571             : 
    1572          35 : _PUBLIC_ void cli_credentials_set_target_service(struct cli_credentials *cred, const char *target_service)
    1573             : {
    1574          35 :         talloc_free(cred->target_service);
    1575          35 :         cred->target_service = talloc_strdup(cred, target_service);
    1576          35 : }
    1577             : 
    1578         114 : _PUBLIC_ int cli_credentials_get_kerberos_key(struct cli_credentials *cred,
    1579             :                                               TALLOC_CTX *mem_ctx,
    1580             :                                               struct loadparm_context *lp_ctx,
    1581             :                                               krb5_enctype enctype,
    1582             :                                               bool previous,
    1583             :                                               DATA_BLOB *key_blob)
    1584             : {
    1585         114 :         struct smb_krb5_context *smb_krb5_context = NULL;
    1586           0 :         krb5_error_code krb5_ret;
    1587           0 :         int ret;
    1588         114 :         const char *password = NULL;
    1589         114 :         const char *salt = NULL;
    1590           0 :         krb5_data cleartext_data;
    1591         114 :         krb5_data salt_data = {
    1592             :                 .length = 0,
    1593             :         };
    1594           0 :         krb5_keyblock key;
    1595             : 
    1596         114 :         TALLOC_CTX *frame = talloc_stackframe();
    1597             : 
    1598         114 :         if ((int)enctype == (int)ENCTYPE_ARCFOUR_HMAC) {
    1599           0 :                 struct samr_Password *nt_hash;
    1600             : 
    1601           0 :                 if (previous) {
    1602           0 :                         nt_hash = cli_credentials_get_old_nt_hash(cred, frame);
    1603             :                 } else {
    1604           0 :                         nt_hash = cli_credentials_get_nt_hash(cred, frame);
    1605             :                 }
    1606             : 
    1607           0 :                 if (nt_hash == NULL) {
    1608           0 :                         TALLOC_FREE(frame);
    1609           0 :                         return EINVAL;
    1610             :                 }
    1611           0 :                 *key_blob = data_blob_talloc(mem_ctx,
    1612             :                                              nt_hash->hash,
    1613             :                                              sizeof(nt_hash->hash));
    1614           0 :                 if (key_blob->data == NULL) {
    1615           0 :                         TALLOC_FREE(frame);
    1616           0 :                         return ENOMEM;
    1617             :                 }
    1618           0 :                 TALLOC_FREE(frame);
    1619           0 :                 return 0;
    1620             :         }
    1621             : 
    1622         114 :         if (cred->password_will_be_nt_hash) {
    1623           0 :                 DEBUG(1,("cli_credentials_get_kerberos_key: cannot generate Kerberos key using NT hash\n"));
    1624           0 :                 TALLOC_FREE(frame);
    1625           0 :                 return EINVAL;
    1626             :         }
    1627             : 
    1628         114 :         salt = cli_credentials_get_salt_principal(cred, frame);
    1629         114 :         if (salt == NULL) {
    1630           0 :                 TALLOC_FREE(frame);
    1631           0 :                 return EINVAL;
    1632             :         }
    1633             : 
    1634         114 :         if (previous) {
    1635           0 :                 password = cli_credentials_get_old_password(cred);
    1636             :         } else {
    1637         114 :                 password = cli_credentials_get_password(cred);
    1638             :         }
    1639         114 :         if (password == NULL) {
    1640           0 :                 TALLOC_FREE(frame);
    1641           0 :                 return EINVAL;
    1642             :         }
    1643             : 
    1644         114 :         cleartext_data.data = discard_const_p(char, password);
    1645         114 :         cleartext_data.length = strlen(password);
    1646             : 
    1647         114 :         ret = cli_credentials_get_krb5_context(cred, lp_ctx,
    1648             :                                                &smb_krb5_context);
    1649         114 :         if (ret != 0) {
    1650           0 :                 TALLOC_FREE(frame);
    1651           0 :                 return ret;
    1652             :         }
    1653             : 
    1654         114 :         salt_data.data = discard_const_p(char, salt);
    1655         114 :         salt_data.length = strlen(salt);
    1656             : 
    1657             :         /*
    1658             :          * create Kerberos key out of
    1659             :          * the salt and the cleartext password
    1660             :          */
    1661         114 :         krb5_ret = smb_krb5_create_key_from_string(smb_krb5_context->krb5_context,
    1662             :                                                    NULL,
    1663             :                                                    &salt_data,
    1664             :                                                    &cleartext_data,
    1665             :                                                    enctype,
    1666             :                                                    &key);
    1667         114 :         if (krb5_ret != 0) {
    1668           0 :                 DEBUG(1,("cli_credentials_get_aes256_key: "
    1669             :                          "generation of a aes256-cts-hmac-sha1-96 key failed: %s\n",
    1670             :                          smb_get_krb5_error_message(smb_krb5_context->krb5_context,
    1671             :                                                     krb5_ret, mem_ctx)));
    1672           0 :                 TALLOC_FREE(frame);
    1673           0 :                 return EINVAL;
    1674             :         }
    1675         114 :         *key_blob = data_blob_talloc(mem_ctx,
    1676             :                                     KRB5_KEY_DATA(&key),
    1677             :                                     KRB5_KEY_LENGTH(&key));
    1678         114 :         krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &key);
    1679         114 :         if (key_blob->data == NULL) {
    1680           0 :                 TALLOC_FREE(frame);
    1681           0 :                 return ENOMEM;
    1682             :         }
    1683         114 :         talloc_keep_secret(key_blob->data);
    1684             : 
    1685         114 :         TALLOC_FREE(frame);
    1686         114 :         return 0;
    1687             : }
    1688             : 
    1689             : /* This take a reference to the armor credentials to ensure the lifetime is appropriate */
    1690             : 
    1691          13 : NTSTATUS cli_credentials_set_krb5_fast_armor_credentials(struct cli_credentials *creds,
    1692             :                                                          struct cli_credentials *armor_creds,
    1693             :                                                          bool require_fast_armor)
    1694             : {
    1695          13 :         talloc_unlink(creds, creds->krb5_fast_armor_credentials);
    1696          13 :         if (armor_creds == NULL) {
    1697           2 :                 creds->krb5_fast_armor_credentials = NULL;
    1698           2 :                 return NT_STATUS_OK;
    1699             :         }
    1700             : 
    1701          11 :         creds->krb5_fast_armor_credentials = talloc_reference(creds, armor_creds);
    1702          11 :         if (creds->krb5_fast_armor_credentials == NULL) {
    1703           0 :                 return NT_STATUS_NO_MEMORY;
    1704             :         }
    1705             : 
    1706          11 :         creds->krb5_require_fast_armor = require_fast_armor;
    1707             : 
    1708          11 :         return NT_STATUS_OK;
    1709             : }
    1710             : 
    1711       15486 : struct cli_credentials *cli_credentials_get_krb5_fast_armor_credentials(struct cli_credentials *creds)
    1712             : {
    1713       15486 :         return creds->krb5_fast_armor_credentials;
    1714             : }
    1715             : 
    1716       15486 : bool cli_credentials_get_krb5_require_fast_armor(struct cli_credentials *creds)
    1717             : {
    1718       15486 :         return creds->krb5_require_fast_armor;
    1719             : }

Generated by: LCOV version 1.14