LCOV - code coverage report
Current view: top level - auth/credentials - credentials_krb5.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 514 793 64.8 %
Date: 2024-04-21 15:09:00 Functions: 34 37 91.9 %

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

Generated by: LCOV version 1.14