LCOV - code coverage report
Current view: top level - auth/credentials - credentials_krb5.c (source / functions) Hit Total Coverage
Test: coverage report for fix-15632 9995c5c2 Lines: 493 750 65.7 %
Date: 2024-04-13 12:30:31 Functions: 33 37 89.2 %

          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       46402 : static int free_mccache(struct ccache_container *ccc)
      49             : {
      50       46402 :         if (ccc->ccache != NULL) {
      51       46402 :                 krb5_cc_destroy(ccc->smb_krb5_context->krb5_context,
      52             :                                 ccc->ccache);
      53       46402 :                 ccc->ccache = NULL;
      54             :         }
      55             : 
      56       46402 :         return 0;
      57             : }
      58             : 
      59             : /* Free a disk-based ccache */
      60       98229 : static int free_dccache(struct ccache_container *ccc)
      61             : {
      62       98229 :         if (ccc->ccache != NULL) {
      63       98229 :                 krb5_cc_close(ccc->smb_krb5_context->krb5_context,
      64             :                               ccc->ccache);
      65       98229 :                 ccc->ccache = NULL;
      66             :         }
      67             : 
      68       98229 :         return 0;
      69             : }
      70             : 
      71       30908 : 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        7605 :         krb5_context context = ccc->smb_krb5_context->krb5_context;
      77        7605 :         krb5_ccache dummy_ccache = NULL;
      78        7605 :         krb5_creds creds = {0};
      79        7605 :         krb5_cc_cursor cursor = NULL;
      80        7605 :         krb5_principal princ = NULL;
      81             :         krb5_error_code code;
      82             :         char *dummy_name;
      83        7605 :         uint32_t maj_stat = GSS_S_FAILURE;
      84             : 
      85        7605 :         dummy_name = talloc_asprintf(ccc,
      86             :                                      "MEMORY:gss_krb5_copy_ccache-%p",
      87             :                                      &ccc->ccache);
      88        7605 :         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        7605 :         code = krb5_cc_resolve(context, dummy_name, &dummy_ccache);
     100        7605 :         TALLOC_FREE(dummy_name);
     101        7605 :         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        7605 :         maj_stat = gss_krb5_copy_ccache(min_stat, cred, dummy_ccache);
     111        7605 :         if (maj_stat != 0) {
     112           0 :                 krb5_cc_close(context, dummy_ccache);
     113           0 :                 return maj_stat;
     114             :         }
     115             : 
     116        7605 :         code = krb5_cc_start_seq_get(context, dummy_ccache, &cursor);
     117        7605 :         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        7605 :         code = krb5_cc_next_cred(context,
     124             :                                  dummy_ccache,
     125             :                                  &cursor,
     126             :                                  &creds);
     127        7605 :         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        7605 :                 if (creds.ticket_flags & TKT_FLG_PRE_AUTH) {
     135             :                         krb5_data *tgs;
     136             : 
     137        7605 :                         tgs = krb5_princ_component(context,
     138             :                                                    creds.server,
     139             :                                                    0);
     140        7605 :                         if (tgs != NULL && tgs->length >= 1) {
     141             :                                 int cmp;
     142             : 
     143        7605 :                                 cmp = memcmp(tgs->data,
     144             :                                              KRB5_TGS_NAME,
     145        7605 :                                              tgs->length);
     146        7605 :                                 if (cmp == 0 && creds.client != NULL) {
     147        7605 :                                         princ = creds.client;
     148        7605 :                                         code = KRB5_CC_END;
     149        7605 :                                         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        7605 :         if (code == KRB5_CC_END) {
     163        7605 :                 krb5_cc_end_seq_get(context, dummy_ccache, &cursor);
     164        7605 :                 code = 0;
     165             :         }
     166        7605 :         krb5_cc_close(context, dummy_ccache);
     167             : 
     168        7605 :         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        7605 :         code = krb5_cc_initialize(context, ccc->ccache, princ);
     181        7605 :         if (code != 0) {
     182           0 :                 krb5_free_cred_contents(context, &creds);
     183           0 :                 *min_stat = EINVAL;
     184           0 :                 return GSS_S_FAILURE;
     185             :         }
     186        7605 :         krb5_free_cred_contents(context, &creds);
     187             : 
     188             : #endif /* SAMBA4_USES_HEIMDAL */
     189             : 
     190       30908 :         return gss_krb5_copy_ccache(min_stat,
     191             :                                     cred,
     192             :                                     ccc->ccache);
     193             : }
     194             : 
     195      261454 : _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      261454 :         if (cred->smb_krb5_context) {
     201       67623 :                 *smb_krb5_context = cred->smb_krb5_context;
     202       67623 :                 return 0;
     203             :         }
     204             : 
     205      193831 :         ret = smb_krb5_init_context(cred, lp_ctx,
     206             :                                     &cred->smb_krb5_context);
     207      193831 :         if (ret) {
     208           0 :                 cred->smb_krb5_context = NULL;
     209           0 :                 return ret;
     210             :         }
     211      193831 :         *smb_krb5_context = cred->smb_krb5_context;
     212      193831 :         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       51843 : 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       51843 :         if (cred->ccache_obtained > obtained) {
     246        5102 :                 return 0;
     247             :         }
     248             : 
     249       46741 :         ret = krb5_cc_get_principal(ccache->smb_krb5_context->krb5_context,
     250             :                                     ccache->ccache, &princ);
     251             : 
     252       46741 :         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       46741 :         ret = krb5_unparse_name(ccache->smb_krb5_context->krb5_context, princ, &name);
     260       46741 :         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       46741 :         ok = cli_credentials_set_principal(cred, name, obtained);
     269       46741 :         krb5_free_unparsed_name(ccache->smb_krb5_context->krb5_context, name);
     270       46741 :         if (!ok) {
     271          25 :                 krb5_free_principal(ccache->smb_krb5_context->krb5_context, princ);
     272          25 :                 return ENOMEM;
     273             :         }
     274             : 
     275       48182 :         realm = smb_krb5_principal_get_realm(
     276       46716 :                 cred, ccache->smb_krb5_context->krb5_context, princ);
     277       46716 :         krb5_free_principal(ccache->smb_krb5_context->krb5_context, princ);
     278       46716 :         if (realm == NULL) {
     279           0 :                 return ENOMEM;
     280             :         }
     281       46716 :         ok = cli_credentials_set_realm(cred, realm, obtained);
     282       46716 :         TALLOC_FREE(realm);
     283       46716 :         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       46690 :         cred->ccache_obtained = obtained;
     289             : 
     290       46690 :         return 0;
     291             : }
     292             : 
     293      100445 : _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      100445 :         if (cred->ccache_obtained > obtained) {
     303        2191 :                 return 0;
     304             :         }
     305             : 
     306       98254 :         ccc = talloc(cred, struct ccache_container);
     307       98254 :         if (!ccc) {
     308           0 :                 (*error_string) = error_message(ENOMEM);
     309           0 :                 return ENOMEM;
     310             :         }
     311             : 
     312       98254 :         ret = cli_credentials_get_krb5_context(cred, lp_ctx,
     313             :                                                &ccc->smb_krb5_context);
     314       98254 :         if (ret) {
     315           0 :                 (*error_string) = error_message(ret);
     316           0 :                 talloc_free(ccc);
     317           0 :                 return ret;
     318             :         }
     319       98254 :         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       98254 :         if (name) {
     326        2235 :                 ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, name, &ccc->ccache);
     327        2235 :                 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       96019 :                 ret = krb5_cc_default(ccc->smb_krb5_context->krb5_context, &ccc->ccache);
     337       96019 :                 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       98254 :         talloc_set_destructor(ccc, free_dccache);
     347             : 
     348       98254 :         ret = krb5_cc_get_principal(ccc->smb_krb5_context->krb5_context, ccc->ccache, &princ);
     349             : 
     350       98254 :         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       98203 :         cred->ccache = ccc;
     362       98203 :         cred->ccache_obtained = obtained;
     363             : 
     364       98203 :         cli_credentials_invalidate_client_gss_creds(
     365             :                 cred, cred->ccache_obtained);
     366             : 
     367       98203 :         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        1572 : _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        1572 :         if (principal == NULL) {
     527             :                 /* no way to delete if we don't know the principal */
     528           0 :                 return false;
     529             :         }
     530             : 
     531        1572 :         ccc = cred->ccache;
     532        1572 :         if (ccc == NULL) {
     533             :                 /* not a kerberos connection */
     534        1546 :                 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       45976 : 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       45976 :         bool must_free_cc_name = false;
     605        1466 :         krb5_error_code ret;
     606       45976 :         struct ccache_container *ccc = talloc(cred, struct ccache_container);
     607       45976 :         if (!ccc) {
     608           0 :                 return ENOMEM;
     609             :         }
     610             : 
     611       45976 :         ret = cli_credentials_get_krb5_context(cred, lp_ctx,
     612             :                                                &ccc->smb_krb5_context);
     613       45976 :         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       45976 :         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       45976 :         if (!ccache_name) {
     626       45952 :                 must_free_cc_name = true;
     627             : 
     628       45952 :                 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       45952 :                         ccache_name = talloc_asprintf(ccc, "MEMORY:%p",
     633             :                                                       ccc);
     634             :                 }
     635             : 
     636       45952 :                 if (!ccache_name) {
     637           0 :                         talloc_free(ccc);
     638           0 :                         (*error_string) = strerror(ENOMEM);
     639           0 :                         return ENOMEM;
     640             :                 }
     641             :         }
     642             : 
     643       45976 :         ret = krb5_cc_resolve(ccc->smb_krb5_context->krb5_context, ccache_name,
     644             :                               &ccc->ccache);
     645       45976 :         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       45976 :         if (strncasecmp(ccache_name, "MEMORY:", 7) == 0) {
     656       45953 :                 talloc_set_destructor(ccc, free_mccache);
     657             :         } else {
     658          23 :                 talloc_set_destructor(ccc, free_dccache);
     659             :         }
     660             : 
     661       45976 :         if (must_free_cc_name) {
     662       45952 :                 talloc_free(ccache_name);
     663             :         }
     664             : 
     665       45976 :         *_ccc = ccc;
     666             : 
     667       45976 :         return 0;
     668             : }
     669             : 
     670       19195 : _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       19195 :         if (cred->machine_account_pending) {
     681           0 :                 cli_credentials_set_machine_account(cred, lp_ctx);
     682             :         }
     683             : 
     684       19195 :         if (cred->ccache_obtained >= cred->ccache_threshold &&
     685        4127 :             cred->ccache_obtained > CRED_UNINITIALISED) {
     686           0 :                 time_t lifetime;
     687        4127 :                 bool expired = false;
     688        4127 :                 ret = smb_krb5_cc_get_lifetime(cred->ccache->smb_krb5_context->krb5_context,
     689        4127 :                                                cred->ccache->ccache, &lifetime);
     690        4127 :                 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        4124 :                 } else if (ret == 0) {
     695        4124 :                         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        4124 :                         } 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        4127 :                         return ret;
     709             :                 }
     710             : 
     711        4127 :                 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        4127 :                 if (!expired) {
     715        4127 :                         *ccc = cred->ccache;
     716        4127 :                         return 0;
     717             :                 }
     718             :         }
     719       15068 :         if (cli_credentials_is_anonymous(cred)) {
     720           0 :                 (*error_string) = "Cannot get anonymous kerberos credentials";
     721           0 :                 return EINVAL;
     722             :         }
     723             : 
     724       15068 :         ret = cli_credentials_new_ccache(cred, lp_ctx, ccache_name, ccc, error_string);
     725       15068 :         if (ret) {
     726           0 :                 return ret;
     727             :         }
     728             : 
     729       15653 :         ret = kinit_to_ccache(cred,
     730             :                               cred,
     731       14483 :                               (*ccc)->smb_krb5_context,
     732             :                               lp_ctx,
     733             :                               event_ctx,
     734       15068 :                               (*ccc)->ccache,
     735             :                               &obtained,
     736             :                               error_string);
     737       15068 :         if (ret) {
     738        1254 :                 return ret;
     739             :         }
     740             : 
     741       13814 :         ret = cli_credentials_set_from_ccache(cred, *ccc,
     742             :                                               obtained, error_string);
     743             : 
     744       13814 :         cred->ccache = *ccc;
     745       13814 :         cred->ccache_obtained = cred->principal_obtained;
     746       13814 :         if (ret) {
     747           0 :                 return ret;
     748             :         }
     749       13814 :         cli_credentials_invalidate_client_gss_creds(cred, cred->ccache_obtained);
     750       13814 :         return 0;
     751             : }
     752             : 
     753       17315 : _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       17315 :         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     1589480 : 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     1589480 :         if (obtained >= cred->client_gss_creds_obtained) {
     778     1589464 :                 if (cred->client_gss_creds_obtained > CRED_UNINITIALISED) {
     779        4959 :                         talloc_unlink(cred, cred->client_gss_creds);
     780        4959 :                         cred->client_gss_creds = NULL;
     781             :                 }
     782     1589464 :                 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     1589480 :         if (obtained > cred->client_gss_creds_threshold) {
     789      612613 :                 cred->client_gss_creds_threshold = obtained;
     790             :         }
     791     1589480 : }
     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     1477463 : _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     1477463 :         if (obtained >= cred->ccache_obtained) {
     811     1459911 :                 if (cred->ccache_obtained > CRED_UNINITIALISED) {
     812       72597 :                         talloc_unlink(cred, cred->ccache);
     813       72597 :                         cred->ccache = NULL;
     814             :                 }
     815     1459911 :                 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     1477463 :         if (obtained > cred->ccache_threshold) {
     822      543717 :                 cred->ccache_threshold  = obtained;
     823             :         }
     824             : 
     825     1477463 :         cli_credentials_invalidate_client_gss_creds(cred,
     826             :                                                     obtained);
     827     1477463 : }
     828             : 
     829       92671 : static int free_gssapi_creds(struct gssapi_creds_container *gcc)
     830             : {
     831        3617 :         OM_uint32 min_stat;
     832       92671 :         (void)gss_release_cred(&min_stat, &gcc->creds);
     833       92671 :         return 0;
     834             : }
     835             : 
     836       32516 : _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       32516 :         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       32516 :         gss_buffer_desc empty_buffer = GSS_C_EMPTY_BUFFER;
     848       32516 :         gss_OID oid = discard_const(GSS_KRB5_CRED_NO_CI_FLAGS_X);
     849             : #endif
     850       32516 :         krb5_enctype *etypes = NULL;
     851             : 
     852       32516 :         if (cred->client_gss_creds_obtained >= cred->client_gss_creds_threshold &&
     853       14965 :             cred->client_gss_creds_obtained > CRED_UNINITIALISED) {
     854       15415 :                 bool expired = false;
     855       15415 :                 OM_uint32 lifetime = 0;
     856       15415 :                 gss_cred_usage_t usage = 0;
     857       15415 :                 maj_stat = gss_inquire_cred(&min_stat, cred->client_gss_creds->creds,
     858             :                                             NULL, &lifetime, &usage, NULL);
     859       15415 :                 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       15415 :                 } 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       15415 :                 } 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       15415 :                         return EINVAL;
     869             :                 }
     870       15415 :                 if (expired) {
     871           0 :                         cli_credentials_unconditionally_invalidate_client_gss_creds(cred);
     872             :                 } else {
     873       15415 :                         DEBUG(5, ("GSSAPI credentials for %s will expire in %u secs\n",
     874             :                                   cli_credentials_get_principal(cred, cred), (unsigned int)lifetime));
     875             : 
     876       15415 :                         *_gcc = cred->client_gss_creds;
     877       15415 :                         return 0;
     878             :                 }
     879             :         }
     880             : 
     881       17101 :         ret = cli_credentials_get_ccache(cred, event_ctx, lp_ctx,
     882             :                                          &ccache, error_string);
     883       17101 :         if (ret) {
     884        1248 :                 if (cli_credentials_get_kerberos_state(cred) == CRED_USE_KERBEROS_REQUIRED) {
     885         175 :                         DEBUG(1, ("Failed to get kerberos credentials (kerberos required): %s\n", *error_string));
     886             :                 } else {
     887        1073 :                         DEBUG(4, ("Failed to get kerberos credentials: %s\n", *error_string));
     888             :                 }
     889        1248 :                 return ret;
     890             :         }
     891             : 
     892       15853 :         gcc = talloc(cred, struct gssapi_creds_container);
     893       15853 :         if (!gcc) {
     894           0 :                 (*error_string) = error_message(ENOMEM);
     895           0 :                 return ENOMEM;
     896             :         }
     897             : 
     898       16438 :         maj_stat = smb_gss_krb5_import_cred(&min_stat, ccache->smb_krb5_context->krb5_context,
     899       15853 :                                             ccache->ccache, NULL, NULL,
     900             :                                             &gcc->creds);
     901       15853 :         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       15853 :         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       15853 :         min_stat = smb_krb5_get_allowed_etypes(ccache->smb_krb5_context->krb5_context,
     947             :                                                &etypes);
     948       15853 :         if (min_stat == 0) {
     949             :                 OM_uint32 num_ktypes;
     950             : 
     951      112227 :                 for (num_ktypes = 0; etypes[num_ktypes]; num_ktypes++);
     952             : 
     953       15853 :                 maj_stat = gss_krb5_set_allowable_enctypes(&min_stat, gcc->creds,
     954             :                                                            num_ktypes,
     955             :                                                            (int32_t *) etypes);
     956       15853 :                 krb5_free_enctypes(ccache->smb_krb5_context->krb5_context,
     957             :                                    etypes);
     958       15853 :                 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       15853 :         maj_stat = gss_set_cred_option(&min_stat, &gcc->creds,
     981             :                                        oid,
     982             :                                        &empty_buffer);
     983       15853 :         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       15853 :         cred->client_gss_creds_obtained = cred->ccache_obtained;
     995       15853 :         talloc_set_destructor(gcc, free_gssapi_creds);
     996       15853 :         cred->client_gss_creds = gcc;
     997       15853 :         *_gcc = gcc;
     998       15853 :         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       30908 :  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       30908 :         struct ccache_container *ccc = NULL;
    1021       30908 :         struct gssapi_creds_container *gcc = NULL;
    1022       30908 :         if (cred->client_gss_creds_obtained > obtained) {
    1023           0 :                 return 0;
    1024             :         }
    1025             : 
    1026       30908 :         gcc = talloc(cred, struct gssapi_creds_container);
    1027       30908 :         if (!gcc) {
    1028           0 :                 (*error_string) = error_message(ENOMEM);
    1029           0 :                 return ENOMEM;
    1030             :         }
    1031             : 
    1032       30908 :         ret = cli_credentials_new_ccache(cred, lp_ctx, NULL, &ccc, error_string);
    1033       30908 :         if (ret != 0) {
    1034           0 :                 return ret;
    1035             :         }
    1036             : 
    1037       30908 :         maj_stat = smb_gss_krb5_copy_ccache(&min_stat,
    1038             :                                             gssapi_cred,
    1039             :                                             ccc);
    1040       30908 :         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       30908 :         if (ret == 0) {
    1052       30908 :                 ret = cli_credentials_set_from_ccache(cred, ccc, obtained, error_string);
    1053             :         }
    1054       30908 :         cred->ccache = ccc;
    1055       30908 :         cred->ccache_obtained = obtained;
    1056       30908 :         if (ret == 0) {
    1057       30908 :                 gcc->creds = gssapi_cred;
    1058       30908 :                 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       30908 :                 cred->client_gss_creds_obtained = obtained;
    1063       30908 :                 cred->client_gss_creds = gcc;
    1064             :         }
    1065       30027 :         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       47035 : _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       47035 :         const char *username = cli_credentials_get_username(cred);
    1177       47035 :         const char *upn = NULL;
    1178       47035 :         const char *realm = cli_credentials_get_realm(cred);
    1179       47035 :         char *salt_principal = NULL;
    1180       47035 :         uint32_t uac_flags = 0;
    1181             : 
    1182       47035 :         if (cred->keytab_obtained >= (MAX(cred->principal_obtained,
    1183             :                                           cred->username_obtained))) {
    1184       46938 :                 *_ktc = cred->keytab;
    1185       46938 :                 return 0;
    1186             :         }
    1187             : 
    1188          97 :         if (cli_credentials_is_anonymous(cred)) {
    1189           0 :                 return EINVAL;
    1190             :         }
    1191             : 
    1192          97 :         ret = cli_credentials_get_krb5_context(cred, lp_ctx,
    1193             :                                                &smb_krb5_context);
    1194          97 :         if (ret) {
    1195           0 :                 return ret;
    1196             :         }
    1197             : 
    1198          97 :         mem_ctx = talloc_new(cred);
    1199          97 :         if (!mem_ctx) {
    1200           0 :                 return ENOMEM;
    1201             :         }
    1202             : 
    1203          97 :         switch (cred->secure_channel_type) {
    1204          49 :         case SEC_CHAN_WKSTA:
    1205             :         case SEC_CHAN_RODC:
    1206          49 :                 uac_flags = UF_WORKSTATION_TRUST_ACCOUNT;
    1207          49 :                 break;
    1208          30 :         case SEC_CHAN_BDC:
    1209          30 :                 uac_flags = UF_SERVER_TRUST_ACCOUNT;
    1210          30 :                 break;
    1211           0 :         case SEC_CHAN_DOMAIN:
    1212             :         case SEC_CHAN_DNS_DOMAIN:
    1213           0 :                 uac_flags = UF_INTERDOMAIN_TRUST_ACCOUNT;
    1214           0 :                 break;
    1215          18 :         default:
    1216          18 :                 upn = cli_credentials_get_principal(cred, mem_ctx);
    1217          18 :                 if (upn == NULL) {
    1218           0 :                         TALLOC_FREE(mem_ctx);
    1219           0 :                         return ENOMEM;
    1220             :                 }
    1221          18 :                 uac_flags = UF_NORMAL_ACCOUNT;
    1222          18 :                 break;
    1223             :         }
    1224             : 
    1225          97 :         ret = smb_krb5_salt_principal_str(realm,
    1226             :                                           username, /* sAMAccountName */
    1227             :                                           upn, /* userPrincipalName */
    1228             :                                           uac_flags,
    1229             :                                           mem_ctx,
    1230             :                                           &salt_principal);
    1231          97 :         if (ret) {
    1232           0 :                 talloc_free(mem_ctx);
    1233           0 :                 return ret;
    1234             :         }
    1235             : 
    1236          97 :         ret = smb_krb5_create_memory_keytab(mem_ctx,
    1237          97 :                                             smb_krb5_context->krb5_context,
    1238             :                                             cli_credentials_get_password(cred),
    1239             :                                             username,
    1240             :                                             realm,
    1241             :                                             salt_principal,
    1242             :                                             cli_credentials_get_kvno(cred),
    1243             :                                             &keytab,
    1244             :                                             &keytab_name);
    1245          97 :         if (ret) {
    1246           0 :                 talloc_free(mem_ctx);
    1247           0 :                 return ret;
    1248             :         }
    1249             : 
    1250          97 :         ret = smb_krb5_get_keytab_container(mem_ctx, smb_krb5_context,
    1251             :                                             keytab, keytab_name, &ktc);
    1252          97 :         if (ret) {
    1253           0 :                 talloc_free(mem_ctx);
    1254           0 :                 return ret;
    1255             :         }
    1256             : 
    1257          97 :         cred->keytab_obtained = (MAX(cred->principal_obtained,
    1258             :                                      cred->username_obtained));
    1259             : 
    1260             :         /* We make this keytab up based on a password.  Therefore
    1261             :          * match-by-key is acceptable, we can't match on the wrong
    1262             :          * principal */
    1263          97 :         ktc->password_based = true;
    1264             : 
    1265          97 :         talloc_steal(cred, ktc);
    1266          97 :         cred->keytab = ktc;
    1267          97 :         *_ktc = cred->keytab;
    1268          97 :         talloc_free(mem_ctx);
    1269          97 :         return ret;
    1270             : }
    1271             : 
    1272             : /* Given the name of a keytab (presumably in the format
    1273             :  * FILE:/etc/krb5.keytab), open it and attach it */
    1274             : 
    1275       67005 : _PUBLIC_ int cli_credentials_set_keytab_name(struct cli_credentials *cred,
    1276             :                                              struct loadparm_context *lp_ctx,
    1277             :                                              const char *keytab_name,
    1278             :                                              enum credentials_obtained obtained)
    1279             : {
    1280        2655 :         krb5_error_code ret;
    1281        2655 :         struct keytab_container *ktc;
    1282        2655 :         struct smb_krb5_context *smb_krb5_context;
    1283        2655 :         TALLOC_CTX *mem_ctx;
    1284             : 
    1285       67005 :         if (cred->keytab_obtained >= obtained) {
    1286           0 :                 return 0;
    1287             :         }
    1288             : 
    1289       67005 :         ret = cli_credentials_get_krb5_context(cred, lp_ctx, &smb_krb5_context);
    1290       67005 :         if (ret) {
    1291           0 :                 return ret;
    1292             :         }
    1293             : 
    1294       67005 :         mem_ctx = talloc_new(cred);
    1295       67005 :         if (!mem_ctx) {
    1296           0 :                 return ENOMEM;
    1297             :         }
    1298             : 
    1299       67005 :         ret = smb_krb5_get_keytab_container(mem_ctx, smb_krb5_context,
    1300             :                                             NULL, keytab_name, &ktc);
    1301       67005 :         if (ret) {
    1302           0 :                 return ret;
    1303             :         }
    1304             : 
    1305       67005 :         cred->keytab_obtained = obtained;
    1306             : 
    1307       67005 :         talloc_steal(cred, ktc);
    1308       67005 :         cred->keytab = ktc;
    1309       67005 :         talloc_free(mem_ctx);
    1310             : 
    1311       67005 :         return ret;
    1312             : }
    1313             : 
    1314             : /* Get server gss credentials (in gsskrb5, this means the keytab) */
    1315             : 
    1316       48536 : _PUBLIC_ int cli_credentials_get_server_gss_creds(struct cli_credentials *cred,
    1317             :                                                   struct loadparm_context *lp_ctx,
    1318             :                                                   struct gssapi_creds_container **_gcc)
    1319             : {
    1320       48536 :         int ret = 0;
    1321        2157 :         OM_uint32 maj_stat, min_stat;
    1322        2157 :         struct gssapi_creds_container *gcc;
    1323        2157 :         struct keytab_container *ktc;
    1324        2157 :         struct smb_krb5_context *smb_krb5_context;
    1325        2157 :         TALLOC_CTX *mem_ctx;
    1326        2157 :         krb5_principal princ;
    1327        2157 :         const char *error_string;
    1328        2157 :         enum credentials_obtained obtained;
    1329             : 
    1330       48536 :         mem_ctx = talloc_new(cred);
    1331       48536 :         if (!mem_ctx) {
    1332           0 :                 return ENOMEM;
    1333             :         }
    1334             : 
    1335       48536 :         ret = cli_credentials_get_krb5_context(cred, lp_ctx, &smb_krb5_context);
    1336       48536 :         if (ret) {
    1337           0 :                 return ret;
    1338             :         }
    1339             : 
    1340       48536 :         ret = principal_from_credentials(mem_ctx, cred, smb_krb5_context, &princ, &obtained, &error_string);
    1341       48536 :         if (ret) {
    1342           0 :                 DEBUG(1,("cli_credentials_get_server_gss_creds: making krb5 principal failed (%s)\n",
    1343             :                          error_string));
    1344           0 :                 talloc_free(mem_ctx);
    1345           0 :                 return ret;
    1346             :         }
    1347             : 
    1348       48536 :         if (cred->server_gss_creds_obtained >= (MAX(cred->keytab_obtained, obtained))) {
    1349        2775 :                 talloc_free(mem_ctx);
    1350        2775 :                 *_gcc = cred->server_gss_creds;
    1351        2775 :                 return 0;
    1352             :         }
    1353             : 
    1354       45761 :         ret = cli_credentials_get_keytab(cred, lp_ctx, &ktc);
    1355       45761 :         if (ret) {
    1356           0 :                 DEBUG(1, ("Failed to get keytab for GSSAPI server: %s\n", error_message(ret)));
    1357           0 :                 return ret;
    1358             :         }
    1359             : 
    1360       45761 :         gcc = talloc(cred, struct gssapi_creds_container);
    1361       45761 :         if (!gcc) {
    1362           0 :                 talloc_free(mem_ctx);
    1363           0 :                 return ENOMEM;
    1364             :         }
    1365             : 
    1366       45761 :         if (ktc->password_based || obtained < CRED_SPECIFIED) {
    1367             :                 /*
    1368             :                  * This creates a GSSAPI cred_id_t for match-by-key with only
    1369             :                  * the keytab set
    1370             :                  */
    1371          97 :                 princ = NULL;
    1372             :         }
    1373       47918 :         maj_stat = smb_gss_krb5_import_cred(&min_stat,
    1374       45761 :                                             smb_krb5_context->krb5_context,
    1375             :                                             NULL, princ,
    1376       43604 :                                             ktc->keytab,
    1377             :                                             &gcc->creds);
    1378       45761 :         if (maj_stat) {
    1379           0 :                 if (min_stat) {
    1380           0 :                         ret = min_stat;
    1381             :                 } else {
    1382           0 :                         ret = EINVAL;
    1383             :                 }
    1384             :         }
    1385       45761 :         if (ret == 0) {
    1386       45761 :                 cred->server_gss_creds_obtained = cred->keytab_obtained;
    1387       45761 :                 talloc_set_destructor(gcc, free_gssapi_creds);
    1388       45761 :                 cred->server_gss_creds = gcc;
    1389       45761 :                 *_gcc = gcc;
    1390             :         }
    1391       45761 :         talloc_free(mem_ctx);
    1392       45761 :         return ret;
    1393             : }
    1394             : 
    1395             : /**
    1396             :  * Set Kerberos KVNO
    1397             :  */
    1398             : 
    1399       67555 : _PUBLIC_ void cli_credentials_set_kvno(struct cli_credentials *cred,
    1400             :                               int kvno)
    1401             : {
    1402       67555 :         cred->kvno = kvno;
    1403       67555 : }
    1404             : 
    1405             : /**
    1406             :  * Return Kerberos KVNO
    1407             :  */
    1408             : 
    1409         103 : _PUBLIC_ int cli_credentials_get_kvno(struct cli_credentials *cred)
    1410             : {
    1411         103 :         return cred->kvno;
    1412             : }
    1413             : 
    1414             : 
    1415           0 : const char *cli_credentials_get_salt_principal(struct cli_credentials *cred)
    1416             : {
    1417           0 :         return cred->salt_principal;
    1418             : }
    1419             : 
    1420       66883 : _PUBLIC_ void cli_credentials_set_salt_principal(struct cli_credentials *cred, const char *principal)
    1421             : {
    1422       66883 :         talloc_free(cred->salt_principal);
    1423       66883 :         cred->salt_principal = talloc_strdup(cred, principal);
    1424       66883 : }
    1425             : 
    1426             : /* The 'impersonate_principal' is used to allow one Kerberos principal
    1427             :  * (and it's associated keytab etc) to impersonate another.  The
    1428             :  * ability to do this is controlled by the KDC, but it is generally
    1429             :  * permitted to impersonate anyone to yourself.  This allows any
    1430             :  * member of the domain to get the groups of a user.  This is also
    1431             :  * known as S4U2Self */
    1432             : 
    1433       46375 : _PUBLIC_ const char *cli_credentials_get_impersonate_principal(struct cli_credentials *cred)
    1434             : {
    1435       46375 :         return cred->impersonate_principal;
    1436             : }
    1437             : 
    1438             : /*
    1439             :  * The 'self_service' is the service principal that
    1440             :  * represents the same object (by its objectSid)
    1441             :  * as the client principal (typically our machine account).
    1442             :  * When trying to impersonate 'impersonate_principal' with
    1443             :  * S4U2Self.
    1444             :  */
    1445       15066 : _PUBLIC_ const char *cli_credentials_get_self_service(struct cli_credentials *cred)
    1446             : {
    1447       15066 :         return cred->self_service;
    1448             : }
    1449             : 
    1450          55 : _PUBLIC_ void cli_credentials_set_impersonate_principal(struct cli_credentials *cred,
    1451             :                                                         const char *principal,
    1452             :                                                         const char *self_service)
    1453             : {
    1454          55 :         talloc_free(cred->impersonate_principal);
    1455          55 :         cred->impersonate_principal = talloc_strdup(cred, principal);
    1456          55 :         talloc_free(cred->self_service);
    1457          55 :         cred->self_service = talloc_strdup(cred, self_service);
    1458          55 :         cli_credentials_set_kerberos_state(cred,
    1459             :                                            CRED_USE_KERBEROS_REQUIRED,
    1460             :                                            CRED_SPECIFIED);
    1461          55 : }
    1462             : 
    1463             : /*
    1464             :  * when impersonating for S4U2proxy we need to set the target principal.
    1465             :  * Similarly, we may only be authorized to do general impersonation to
    1466             :  * some particular services.
    1467             :  *
    1468             :  * Likewise, password changes typically require a ticket to kpasswd/realm directly, not via a TGT
    1469             :  *
    1470             :  * NULL means that tickets will be obtained for the krbtgt service.
    1471             : */
    1472             : 
    1473       15066 : const char *cli_credentials_get_target_service(struct cli_credentials *cred)
    1474             : {
    1475       15066 :         return cred->target_service;
    1476             : }
    1477             : 
    1478          35 : _PUBLIC_ void cli_credentials_set_target_service(struct cli_credentials *cred, const char *target_service)
    1479             : {
    1480          35 :         talloc_free(cred->target_service);
    1481          35 :         cred->target_service = talloc_strdup(cred, target_service);
    1482          35 : }
    1483             : 
    1484         114 : _PUBLIC_ int cli_credentials_get_aes256_key(struct cli_credentials *cred,
    1485             :                                             TALLOC_CTX *mem_ctx,
    1486             :                                             struct loadparm_context *lp_ctx,
    1487             :                                             const char *salt,
    1488             :                                             DATA_BLOB *aes_256)
    1489             : {
    1490         114 :         struct smb_krb5_context *smb_krb5_context = NULL;
    1491           0 :         krb5_error_code krb5_ret;
    1492           0 :         int ret;
    1493         114 :         const char *password = NULL;
    1494           0 :         krb5_data cleartext_data;
    1495         114 :         krb5_data salt_data = {
    1496             :                 .length = 0,
    1497             :         };
    1498           0 :         krb5_keyblock key;
    1499             : 
    1500         114 :         if (cred->password_will_be_nt_hash) {
    1501           0 :                 DEBUG(1,("cli_credentials_get_aes256_key: cannot generate AES256 key using NT hash\n"));
    1502           0 :                 return EINVAL;
    1503             :         }
    1504             : 
    1505         114 :         password = cli_credentials_get_password(cred);
    1506         114 :         if (password == NULL) {
    1507           0 :                 return EINVAL;
    1508             :         }
    1509             : 
    1510         114 :         cleartext_data.data = discard_const_p(char, password);
    1511         114 :         cleartext_data.length = strlen(password);
    1512             : 
    1513         114 :         ret = cli_credentials_get_krb5_context(cred, lp_ctx,
    1514             :                                                &smb_krb5_context);
    1515         114 :         if (ret != 0) {
    1516           0 :                 return ret;
    1517             :         }
    1518             : 
    1519         114 :         salt_data.data = discard_const_p(char, salt);
    1520         114 :         salt_data.length = strlen(salt);
    1521             : 
    1522             :         /*
    1523             :          * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of
    1524             :          * the salt and the cleartext password
    1525             :          */
    1526         114 :         krb5_ret = smb_krb5_create_key_from_string(smb_krb5_context->krb5_context,
    1527             :                                                    NULL,
    1528             :                                                    &salt_data,
    1529             :                                                    &cleartext_data,
    1530             :                                                    ENCTYPE_AES256_CTS_HMAC_SHA1_96,
    1531             :                                                    &key);
    1532         114 :         if (krb5_ret != 0) {
    1533           0 :                 DEBUG(1,("cli_credentials_get_aes256_key: "
    1534             :                          "generation of a aes256-cts-hmac-sha1-96 key failed: %s\n",
    1535             :                          smb_get_krb5_error_message(smb_krb5_context->krb5_context,
    1536             :                                                     krb5_ret, mem_ctx)));
    1537           0 :                 return EINVAL;
    1538             :         }
    1539         114 :         *aes_256 = data_blob_talloc(mem_ctx,
    1540             :                                     KRB5_KEY_DATA(&key),
    1541             :                                     KRB5_KEY_LENGTH(&key));
    1542         114 :         krb5_free_keyblock_contents(smb_krb5_context->krb5_context, &key);
    1543         114 :         if (aes_256->data == NULL) {
    1544           0 :                 return ENOMEM;
    1545             :         }
    1546         114 :         talloc_keep_secret(aes_256->data);
    1547             : 
    1548         114 :         return 0;
    1549             : }
    1550             : 
    1551             : /* This take a reference to the armor credentials to ensure the lifetime is appropriate */
    1552             : 
    1553          13 : NTSTATUS cli_credentials_set_krb5_fast_armor_credentials(struct cli_credentials *creds,
    1554             :                                                          struct cli_credentials *armor_creds,
    1555             :                                                          bool require_fast_armor)
    1556             : {
    1557          13 :         talloc_unlink(creds, creds->krb5_fast_armor_credentials);
    1558          13 :         if (armor_creds == NULL) {
    1559           2 :                 creds->krb5_fast_armor_credentials = NULL;
    1560           2 :                 return NT_STATUS_OK;
    1561             :         }
    1562             : 
    1563          11 :         creds->krb5_fast_armor_credentials = talloc_reference(creds, armor_creds);
    1564          11 :         if (creds->krb5_fast_armor_credentials == NULL) {
    1565           0 :                 return NT_STATUS_NO_MEMORY;
    1566             :         }
    1567             : 
    1568          11 :         creds->krb5_require_fast_armor = require_fast_armor;
    1569             : 
    1570          11 :         return NT_STATUS_OK;
    1571             : }
    1572             : 
    1573       15066 : struct cli_credentials *cli_credentials_get_krb5_fast_armor_credentials(struct cli_credentials *creds)
    1574             : {
    1575       15066 :         return creds->krb5_fast_armor_credentials;
    1576             : }
    1577             : 
    1578       15066 : bool cli_credentials_get_krb5_require_fast_armor(struct cli_credentials *creds)
    1579             : {
    1580       15066 :         return creds->krb5_require_fast_armor;
    1581             : }

Generated by: LCOV version 1.14