LCOV - code coverage report
Current view: top level - third_party/heimdal/lib/krb5 - init_creds_pw.c (source / functions) Hit Total Coverage
Test: coverage report for support-claim-type-attributes 6b5c566e Lines: 1151 1902 60.5 %
Date: 2023-11-21 12:31:41 Functions: 65 88 73.9 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
       3             :  * (Royal Institute of Technology, Stockholm, Sweden).
       4             :  * All rights reserved.
       5             :  *
       6             :  * Portions Copyright (c) 2009 - 2010 Apple Inc. All rights reserved.
       7             :  * Portions Copyright (c) 2021, PADL Software Pty Ltd. All rights reserved.
       8             :  *
       9             :  * Redistribution and use in source and binary forms, with or without
      10             :  * modification, are permitted provided that the following conditions
      11             :  * are met:
      12             :  *
      13             :  * 1. Redistributions of source code must retain the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer.
      15             :  *
      16             :  * 2. Redistributions in binary form must reproduce the above copyright
      17             :  *    notice, this list of conditions and the following disclaimer in the
      18             :  *    documentation and/or other materials provided with the distribution.
      19             :  *
      20             :  * 3. Neither the name of the Institute nor the names of its contributors
      21             :  *    may be used to endorse or promote products derived from this software
      22             :  *    without specific prior written permission.
      23             :  *
      24             :  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
      25             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      26             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      27             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
      28             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      29             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      30             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      31             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      32             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      33             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      34             :  * SUCH DAMAGE.
      35             :  */
      36             : 
      37             : #include "krb5_locl.h"
      38             : 
      39             : #include <heimbasepriv.h>
      40             : 
      41             : struct pa_info_data {
      42             :     krb5_enctype etype;
      43             :     krb5_salt salt;
      44             :     krb5_data *s2kparams;
      45             : };
      46             : 
      47             : struct krb5_gss_init_ctx_data {
      48             :     krb5_gssic_step step;
      49             :     krb5_gssic_finish finish;
      50             :     krb5_gssic_release_cred release_cred;
      51             :     krb5_gssic_delete_sec_context delete_sec_context;
      52             : 
      53             :     const struct gss_OID_desc_struct *mech;
      54             :     struct gss_cred_id_t_desc_struct *cred;
      55             : 
      56             :     struct {
      57             :         unsigned int release_cred : 1;
      58             :     } flags;
      59             : };
      60             : 
      61             : struct krb5_get_init_creds_ctx {
      62             :     KDCOptions flags;
      63             :     krb5_creds cred;
      64             :     const krb5_addresses *addrs;
      65             :     krb5_enctype *etypes;
      66             :     krb5_preauthtype *pre_auth_types;
      67             :     char *in_tkt_service;
      68             :     unsigned nonce;
      69             :     unsigned pk_nonce;
      70             : 
      71             :     krb5_data req_buffer;
      72             :     AS_REQ as_req;
      73             :     int pa_counter;
      74             : 
      75             :     /* password and keytab_data is freed on completion */
      76             :     char *password;
      77             :     krb5_keytab_key_proc_args *keytab_data;
      78             : 
      79             :     krb5_pointer *keyseed;
      80             :     krb5_s2k_proc keyproc;
      81             : 
      82             :     krb5_get_init_creds_tristate req_pac;
      83             : 
      84             :     krb5_pk_init_ctx pk_init_ctx;
      85             :     krb5_gss_init_ctx gss_init_ctx;
      86             :     int ic_flags;
      87             : 
      88             :     char *kdc_hostname;
      89             :     char *sitename;
      90             : 
      91             :     struct {
      92             :         unsigned int change_password:1;
      93             :         unsigned int change_password_prompt:1;
      94             :         unsigned int allow_enc_pa_rep:1;
      95             :         unsigned int allow_save_as_reply_key:1;
      96             :     } runflags;
      97             : 
      98             :     struct pa_info_data paid;
      99             : 
     100             :     METHOD_DATA md;
     101             :     KRB_ERROR error;
     102             :     EncKDCRepPart enc_part;
     103             : 
     104             :     krb5_prompter_fct prompter;
     105             :     void *prompter_data;
     106             :     int warned_user;
     107             : 
     108             :     struct pa_info_data *ppaid;
     109             : 
     110             :     struct krb5_fast_state fast_state;
     111             :     krb5_enctype as_enctype;
     112             :     krb5_keyblock *as_reply_key;
     113             : 
     114             :     /* current and available pa mechansm in this exchange */
     115             :     struct pa_auth_mech *pa_mech;
     116             :     heim_array_t available_pa_mechs;
     117             :     const char *pa_used;
     118             : 
     119             :     struct {
     120             :         struct timeval run_time;
     121             :     } stats;
     122             : };
     123             : 
     124             : static void
     125       63394 : free_paid(krb5_context context, struct pa_info_data *ppaid)
     126             : {
     127       63394 :     krb5_free_salt(context, ppaid->salt);
     128       63394 :     if (ppaid->s2kparams)
     129       39369 :         krb5_free_data(context, ppaid->s2kparams);
     130       63394 :     memset(ppaid, 0, sizeof(*ppaid));
     131       63394 : }
     132             : 
     133             : static krb5_error_code KRB5_CALLCONV
     134       27496 : default_s2k_func(krb5_context context, krb5_enctype type,
     135             :                  krb5_const_pointer keyseed,
     136             :                  krb5_salt salt, krb5_data *s2kparms,
     137             :                  krb5_keyblock **key)
     138             : {
     139        1164 :     krb5_error_code ret;
     140        1164 :     krb5_data password;
     141        1164 :     krb5_data opaque;
     142             : 
     143       27496 :     if (_krb5_have_debug(context, 5)) {
     144           0 :         char *str = NULL;
     145           0 :         ret = krb5_enctype_to_string(context, type, &str);
     146           0 :         if (ret)
     147           0 :             return ret;
     148             : 
     149           0 :         _krb5_debug(context, 5, "krb5_get_init_creds: using default_s2k_func: %s (%d)", str, (int)type);
     150           0 :         free(str);
     151             :     }
     152             : 
     153       27496 :     password.data = rk_UNCONST(keyseed);
     154       27496 :     password.length = keyseed ? strlen(keyseed) : 0;
     155       27496 :     if (s2kparms)
     156       26314 :         opaque = *s2kparms;
     157             :     else
     158        1182 :         krb5_data_zero(&opaque);
     159             : 
     160       27496 :     *key = malloc(sizeof(**key));
     161       27496 :     if (*key == NULL)
     162           0 :         return krb5_enomem(context);
     163       27496 :     ret = krb5_string_to_key_data_salt_opaque(context, type, password,
     164             :                                               salt, opaque, *key);
     165       27496 :     if (ret) {
     166           0 :         free(*key);
     167           0 :         *key = NULL;
     168             :     }
     169       26332 :     return ret;
     170             : }
     171             : 
     172             : static void
     173       22216 : free_gss_init_ctx(krb5_context context, krb5_gss_init_ctx gssic)
     174             : {
     175       22216 :     if (gssic == NULL)
     176       21631 :         return;
     177             : 
     178           0 :     if (gssic->flags.release_cred)
     179           0 :         gssic->release_cred(context, gssic, gssic->cred);
     180           0 :     free(gssic);
     181             : }
     182             : 
     183             : static void
     184       22216 : free_init_creds_ctx(krb5_context context, krb5_init_creds_context ctx)
     185             : {
     186       22216 :     if (ctx->etypes)
     187          31 :         free(ctx->etypes);
     188       22216 :     if (ctx->pre_auth_types)
     189           0 :         free (ctx->pre_auth_types);
     190       22216 :     if (ctx->in_tkt_service)
     191           0 :         free(ctx->in_tkt_service);
     192       22216 :     if (ctx->keytab_data)
     193           7 :         free(ctx->keytab_data);
     194       22216 :     if (ctx->password) {
     195         582 :         size_t len;
     196       22073 :         len = strlen(ctx->password);
     197       22073 :         memset_s(ctx->password, len, 0, len);
     198       22073 :         free(ctx->password);
     199             :     }
     200       22216 :     free_gss_init_ctx(context, ctx->gss_init_ctx);
     201             :     /*
     202             :      * FAST state
     203             :      */
     204       22216 :     _krb5_fast_free(context, &ctx->fast_state);
     205       22216 :     if (ctx->as_reply_key)
     206          13 :         krb5_free_keyblock(context, ctx->as_reply_key);
     207             : 
     208       22216 :     krb5_data_free(&ctx->req_buffer);
     209       22216 :     krb5_free_cred_contents(context, &ctx->cred);
     210       22216 :     free_METHOD_DATA(&ctx->md);
     211       22216 :     free_EncKDCRepPart(&ctx->enc_part);
     212       22216 :     free_KRB_ERROR(&ctx->error);
     213       22216 :     free_AS_REQ(&ctx->as_req);
     214             : 
     215       22216 :     heim_release(ctx->available_pa_mechs);
     216       22216 :     heim_release(ctx->pa_mech);
     217       22216 :     ctx->pa_mech = NULL;
     218       22216 :     free(ctx->kdc_hostname);
     219       22216 :     free(ctx->sitename);
     220       22216 :     free_paid(context, &ctx->paid);
     221       22216 :     memset_s(ctx, sizeof(*ctx), 0, sizeof(*ctx));
     222       22216 : }
     223             : 
     224             : static krb5_deltat
     225        1734 : get_config_time (krb5_context context,
     226             :                  const char *realm,
     227             :                  const char *name,
     228             :                  int def)
     229             : {
     230           0 :     krb5_deltat ret;
     231             : 
     232        1734 :     ret = krb5_config_get_time (context, NULL,
     233             :                                 "realms",
     234             :                                 realm,
     235             :                                 name,
     236             :                                 NULL);
     237        1734 :     if (ret >= 0)
     238           0 :         return ret;
     239        1734 :     ret = krb5_config_get_time (context, NULL,
     240             :                                 "libdefaults",
     241             :                                 name,
     242             :                                 NULL);
     243        1734 :     if (ret >= 0)
     244           0 :         return ret;
     245        1734 :     return def;
     246             : }
     247             : 
     248             : static krb5_error_code
     249       22216 : init_cred (krb5_context context,
     250             :            krb5_creds *cred,
     251             :            krb5_principal client,
     252             :            krb5_deltat start_time,
     253             :            krb5_get_init_creds_opt *options)
     254             : {
     255         585 :     krb5_error_code ret;
     256         585 :     krb5_deltat tmp;
     257         585 :     krb5_timestamp now;
     258             : 
     259       22216 :     krb5_timeofday (context, &now);
     260             : 
     261       22216 :     memset (cred, 0, sizeof(*cred));
     262             : 
     263       22216 :     if (client)
     264       22216 :         ret = krb5_copy_principal(context, client, &cred->client);
     265             :     else
     266           0 :         ret = krb5_get_default_principal(context, &cred->client);
     267       22216 :     if (ret)
     268           0 :         goto out;
     269             : 
     270       22216 :     if (start_time)
     271           0 :         cred->times.starttime  = now + start_time;
     272             : 
     273       22216 :     if (options->flags & KRB5_GET_INIT_CREDS_OPT_TKT_LIFE)
     274       11543 :         tmp = options->tkt_life;
     275             :     else
     276       10673 :         tmp = KRB5_TKT_LIFETIME_DEFAULT;
     277       22216 :     cred->times.endtime = now + tmp;
     278             : 
     279       22216 :     if ((options->flags & KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE)) {
     280        8511 :         if (options->renew_life > 0)
     281          32 :             tmp = options->renew_life;
     282             :         else
     283        8479 :             tmp = KRB5_TKT_RENEW_LIFETIME_DEFAULT;
     284        8511 :         cred->times.renew_till = now + tmp;
     285             :     }
     286             : 
     287       21631 :     return 0;
     288             : 
     289           0 : out:
     290           0 :     krb5_free_cred_contents (context, cred);
     291           0 :     return ret;
     292             : }
     293             : 
     294             : /*
     295             :  * Print a message (str) to the user about the expiration in `lr'
     296             :  */
     297             : 
     298             : static void
     299           4 : report_expiration (krb5_context context,
     300             :                    krb5_prompter_fct prompter,
     301             :                    krb5_data *data,
     302             :                    const char *str,
     303             :                    time_t now)
     304             : {
     305           4 :     char *p = NULL;
     306             : 
     307           4 :     if (asprintf(&p, "%s%s", str, ctime(&now)) < 0 || p == NULL)
     308           0 :         return;
     309           4 :     (*prompter)(context, data, NULL, p, 0, NULL);
     310           4 :     free(p);
     311             : }
     312             : 
     313             : /*
     314             :  * Check the context, and in the case there is a expiration warning,
     315             :  * use the prompter to print the warning.
     316             :  *
     317             :  * @param context A Kerberos 5 context.
     318             :  * @param options An GIC options structure
     319             :  * @param ctx The krb5_init_creds_context check for expiration.
     320             :  */
     321             : 
     322             : krb5_error_code
     323       13632 : krb5_process_last_request(krb5_context context,
     324             :                           krb5_get_init_creds_opt *options,
     325             :                           krb5_init_creds_context ctx)
     326             : {
     327         585 :     LastReq *lr;
     328         585 :     size_t i;
     329             : 
     330             :     /*
     331             :      * First check if there is a API consumer.
     332             :      */
     333             : 
     334       13632 :     lr = &ctx->enc_part.last_req;
     335             : 
     336       13632 :     if (options && options->opt_private && options->opt_private->lr.func) {
     337           0 :         krb5_last_req_entry **lre;
     338             : 
     339           0 :         lre = calloc(lr->len + 1, sizeof(*lre));
     340           0 :         if (lre == NULL)
     341           0 :             return krb5_enomem(context);
     342             : 
     343           0 :         for (i = 0; i < lr->len; i++) {
     344           0 :             lre[i] = calloc(1, sizeof(*lre[i]));
     345           0 :             if (lre[i] == NULL)
     346           0 :                 break;
     347           0 :             lre[i]->lr_type = lr->val[i].lr_type;
     348           0 :             lre[i]->value = lr->val[i].lr_value;
     349             :         }
     350             : 
     351           0 :         (*options->opt_private->lr.func)(context, lre,
     352           0 :                                          options->opt_private->lr.ctx);
     353             : 
     354           0 :         for (i = 0; i < lr->len; i++)
     355           0 :             free(lre[i]);
     356           0 :         free(lre);
     357             :     }
     358             : 
     359       13632 :     return krb5_init_creds_warn_user(context, ctx);
     360             : }
     361             : 
     362             : /**
     363             :  * Warn the user using prompter in the krb5_init_creds_context about
     364             :  * possible password and account expiration.
     365             :  *
     366             :  * @param context a Kerberos 5 context.
     367             :  * @param ctx a krb5_init_creds_context context.
     368             :  *
     369             :  * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message().
     370             :  * @ingroup krb5_credential
     371             :  */
     372             : 
     373             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     374       13745 : krb5_init_creds_warn_user(krb5_context context,
     375             :                           krb5_init_creds_context ctx)
     376             : {
     377         585 :     krb5_timestamp sec;
     378         585 :     krb5_const_realm realm;
     379       13745 :     krb5_enctype weak_enctype = KRB5_ENCTYPE_NULL;
     380         585 :     LastReq *lr;
     381         585 :     unsigned i;
     382         585 :     time_t t;
     383             : 
     384       13745 :     if (ctx->prompter == NULL)
     385       11313 :         return 0;
     386             : 
     387        1847 :     if (ctx->warned_user)
     388         113 :         return 0;
     389             : 
     390        1734 :     ctx->warned_user = 1;
     391             : 
     392        1734 :     krb5_timeofday (context, &sec);
     393             : 
     394        1734 :     realm = krb5_principal_get_realm (context, ctx->cred.client);
     395        1734 :     lr = &ctx->enc_part.last_req;
     396             : 
     397        1734 :     t = sec + get_config_time (context,
     398             :                                realm,
     399             :                                "warn_pwexpire",
     400             :                                7 * 24 * 60 * 60);
     401             : 
     402        3468 :     for (i = 0; i < lr->len; ++i) {
     403        1734 :         if (lr->val[i].lr_value <= t) {
     404         274 :             switch (lr->val[i].lr_type) {
     405           4 :             case LR_PW_EXPTIME :
     406           4 :                 report_expiration(context, ctx->prompter,
     407           4 :                                   ctx->prompter_data,
     408             :                                   "Your password will expire at ",
     409           4 :                                   lr->val[i].lr_value);
     410           4 :                 break;
     411           0 :             case LR_ACCT_EXPTIME :
     412           0 :                 report_expiration(context, ctx->prompter,
     413           0 :                                   ctx->prompter_data,
     414             :                                   "Your account will expire at ",
     415           0 :                                   lr->val[i].lr_value);
     416           0 :                 break;
     417         270 :             default:
     418         270 :                 break;
     419             :             }
     420             :         }
     421             :     }
     422             : 
     423        1734 :     if (krb5_is_enctype_weak(context, ctx->as_enctype))
     424          42 :         weak_enctype = ctx->as_enctype;
     425        1692 :     else if (krb5_is_enctype_weak(context, ctx->cred.session.keytype))
     426           1 :         weak_enctype = ctx->cred.session.keytype;
     427             : 
     428        1734 :     if (ctx->prompter && weak_enctype != KRB5_ENCTYPE_NULL) {
     429          43 :         int suppress = krb5_config_get_bool_default(context, NULL, false,
     430             :                                                     "libdefaults",
     431             :                                                     "suppress_weak_enctype", NULL);
     432          43 :         if (!suppress) {
     433          43 :             char *str = NULL, *p = NULL;
     434           0 :             int aret;
     435             : 
     436          43 :             (void) krb5_enctype_to_string(context, weak_enctype, &str);
     437          43 :             aret = asprintf(&p, "Encryption type %s(%d) used for authentication is weak and will be deprecated",
     438          43 :                             str ? str : "unknown", weak_enctype);
     439          43 :             if (aret >= 0 && p) {
     440          43 :                 (*ctx->prompter)(context, ctx->prompter_data, NULL, p, 0, NULL);
     441          43 :                 free(p);
     442             :             }
     443          43 :             free(str);
     444             :         }
     445             :     }
     446             : 
     447        1734 :     return 0;
     448             : }
     449             : 
     450             : static const krb5_addresses no_addrs = { 0, NULL };
     451             : 
     452             : static krb5_error_code
     453       22216 : get_init_creds_common(krb5_context context,
     454             :                       krb5_principal client,
     455             :                       krb5_prompter_fct prompter,
     456             :                       void *prompter_data,
     457             :                       krb5_deltat start_time,
     458             :                       krb5_get_init_creds_opt *options,
     459             :                       krb5_init_creds_context ctx)
     460             : {
     461       22216 :     krb5_get_init_creds_opt *default_opt = NULL;
     462         585 :     krb5_error_code ret;
     463         585 :     krb5_enctype *etypes;
     464         585 :     krb5_preauthtype *pre_auth_types;
     465             : 
     466       22216 :     memset(ctx, 0, sizeof(*ctx));
     467             : 
     468       22216 :     if (options == NULL) {
     469          48 :         const char *realm = krb5_principal_get_realm(context, client);
     470             : 
     471          48 :         ret = krb5_get_init_creds_opt_alloc(context, &default_opt);
     472          48 :         if (ret)
     473           0 :             return ret;
     474          48 :         options = default_opt;
     475          48 :         krb5_get_init_creds_opt_set_default_flags(context, NULL, realm, options);
     476             :     }
     477             : 
     478       22216 :     if (options->opt_private) {
     479       22216 :         if (options->opt_private->password) {
     480           0 :             ret = krb5_init_creds_set_password(context, ctx,
     481           0 :                                                options->opt_private->password);
     482           0 :             if (ret)
     483           0 :                 goto out;
     484             :         }
     485             : 
     486       22216 :         ctx->keyproc = options->opt_private->key_proc;
     487       22216 :         ctx->req_pac = options->opt_private->req_pac;
     488       22216 :         ctx->pk_init_ctx = options->opt_private->pk_init_ctx;
     489       22216 :         ctx->ic_flags = options->opt_private->flags;
     490             :     } else
     491           0 :         ctx->req_pac = KRB5_INIT_CREDS_TRISTATE_UNSET;
     492             : 
     493       22216 :     if (ctx->keyproc == NULL)
     494       22216 :         ctx->keyproc = default_s2k_func;
     495             : 
     496       22216 :     if (ctx->ic_flags & KRB5_INIT_CREDS_CANONICALIZE)
     497       20853 :         ctx->flags.canonicalize = 1;
     498       22216 :     if (krb5_principal_get_type(context, client) == KRB5_NT_ENTERPRISE_PRINCIPAL)
     499         756 :         ctx->flags.canonicalize = 1;
     500             : 
     501       22216 :     ctx->pre_auth_types = NULL;
     502       22216 :     ctx->addrs = NULL;
     503       22216 :     ctx->etypes = NULL;
     504       22216 :     ctx->pre_auth_types = NULL;
     505             : 
     506       22216 :     ret = init_cred(context, &ctx->cred, client, start_time, options);
     507       22216 :     if (ret)
     508           0 :         goto out;
     509             : 
     510       22216 :     ret = krb5_init_creds_set_service(context, ctx, NULL);
     511       22216 :     if (ret)
     512           0 :         goto out;
     513             : 
     514       22216 :     if (options->flags & KRB5_GET_INIT_CREDS_OPT_FORWARDABLE)
     515       19915 :         ctx->flags.forwardable = options->forwardable;
     516             : 
     517       22216 :     if (options->flags & KRB5_GET_INIT_CREDS_OPT_PROXIABLE)
     518       11439 :         ctx->flags.proxiable = options->proxiable;
     519             : 
     520       22216 :     if (start_time)
     521           0 :         ctx->flags.postdated = 1;
     522       22216 :     if (ctx->cred.times.renew_till)
     523        8511 :         ctx->flags.renewable = 1;
     524       22216 :     if (options->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST) {
     525           3 :         ctx->addrs = options->address_list;
     526       22213 :     } else if (options->opt_private) {
     527       22213 :         switch (options->opt_private->addressless) {
     528       10787 :         case KRB5_INIT_CREDS_TRISTATE_UNSET:
     529             : #if KRB5_ADDRESSLESS_DEFAULT == TRUE
     530       10787 :             ctx->addrs = &no_addrs;
     531             : #else
     532             :             ctx->addrs = NULL;
     533             : #endif
     534       10787 :             break;
     535           0 :         case KRB5_INIT_CREDS_TRISTATE_FALSE:
     536           0 :             ctx->addrs = NULL;
     537           0 :             break;
     538       11426 :         case KRB5_INIT_CREDS_TRISTATE_TRUE:
     539       11426 :             ctx->addrs = &no_addrs;
     540       11426 :             break;
     541             :         }
     542             :     }
     543       22216 :     if (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST) {
     544          26 :         if (ctx->etypes)
     545           0 :             free(ctx->etypes);
     546             : 
     547          26 :         etypes = malloc((options->etype_list_length + 1)
     548             :                         * sizeof(krb5_enctype));
     549          26 :         if (etypes == NULL) {
     550           0 :             ret = krb5_enomem(context);
     551           0 :             goto out;
     552             :         }
     553          26 :         memcpy (etypes, options->etype_list,
     554          26 :                 options->etype_list_length * sizeof(krb5_enctype));
     555          26 :         etypes[options->etype_list_length] = ETYPE_NULL;
     556          26 :         ctx->etypes = etypes;
     557             :     }
     558       22216 :     if (options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST) {
     559           0 :         pre_auth_types = malloc((options->preauth_list_length + 1)
     560             :                                 * sizeof(krb5_preauthtype));
     561           0 :         if (pre_auth_types == NULL) {
     562           0 :             ret = krb5_enomem(context);
     563           0 :             goto out;
     564             :         }
     565           0 :         memcpy (pre_auth_types, options->preauth_list,
     566           0 :                 options->preauth_list_length * sizeof(krb5_preauthtype));
     567           0 :         pre_auth_types[options->preauth_list_length] = KRB5_PADATA_NONE;
     568           0 :         ctx->pre_auth_types = pre_auth_types;
     569             :     }
     570       22216 :     if (options->flags & KRB5_GET_INIT_CREDS_OPT_ANONYMOUS)
     571         104 :         ctx->flags.request_anonymous = options->anonymous;
     572             : 
     573       22216 :     ctx->prompter = prompter;
     574       22216 :     ctx->prompter_data = prompter_data;
     575             : 
     576       22216 :     if ((options->flags & KRB5_GET_INIT_CREDS_OPT_CHANGE_PASSWORD_PROMPT) &&
     577           0 :         !options->change_password_prompt)
     578           0 :         ctx->runflags.change_password_prompt = 0;
     579             :     else
     580       22216 :         ctx->runflags.change_password_prompt = ctx->prompter != NULL;
     581             : 
     582       22216 :  out:
     583       22216 :     if (default_opt)
     584          48 :         krb5_get_init_creds_opt_free(context, default_opt);
     585       21631 :     return ret;
     586             : }
     587             : 
     588             : static krb5_error_code
     589           4 : change_password (krb5_context context,
     590             :                  krb5_principal client,
     591             :                  const char *password,
     592             :                  char *newpw,
     593             :                  size_t newpw_sz,
     594             :                  krb5_prompter_fct prompter,
     595             :                  void *data,
     596             :                  krb5_get_init_creds_opt *old_options)
     597             : {
     598           0 :     krb5_prompt prompts[2];
     599           0 :     krb5_error_code ret;
     600           0 :     krb5_creds cpw_cred;
     601           0 :     char buf1[BUFSIZ], buf2[BUFSIZ];
     602           0 :     krb5_data password_data[2];
     603           0 :     int result_code;
     604           0 :     krb5_data result_code_string;
     605           0 :     krb5_data result_string;
     606           0 :     char *p;
     607           0 :     krb5_get_init_creds_opt *options;
     608             : 
     609           4 :     heim_assert(prompter != NULL, "unexpected NULL prompter");
     610             : 
     611           4 :     memset (&cpw_cred, 0, sizeof(cpw_cred));
     612             : 
     613           4 :     ret = krb5_get_init_creds_opt_alloc(context, &options);
     614           4 :     if (ret)
     615           0 :         return ret;
     616           4 :     krb5_get_init_creds_opt_set_tkt_life (options, 60);
     617           4 :     krb5_get_init_creds_opt_set_forwardable (options, FALSE);
     618           4 :     krb5_get_init_creds_opt_set_proxiable (options, FALSE);
     619           4 :     if (old_options &&
     620           0 :         (old_options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST))
     621           0 :         krb5_get_init_creds_opt_set_preauth_list(options,
     622             :                                                  old_options->preauth_list,
     623             :                                                  old_options->preauth_list_length);
     624           4 :     if (old_options &&
     625           0 :         (old_options->flags & KRB5_GET_INIT_CREDS_OPT_CHANGE_PASSWORD_PROMPT))
     626           0 :         krb5_get_init_creds_opt_set_change_password_prompt(options,
     627             :                                                            old_options->change_password_prompt);
     628             : 
     629           4 :     krb5_data_zero (&result_code_string);
     630           4 :     krb5_data_zero (&result_string);
     631             : 
     632           4 :     ret = krb5_get_init_creds_password (context,
     633             :                                         &cpw_cred,
     634             :                                         client,
     635             :                                         password,
     636             :                                         prompter,
     637             :                                         data,
     638             :                                         0,
     639             :                                         "kadmin/changepw",
     640             :                                         options);
     641           4 :     krb5_get_init_creds_opt_free(context, options);
     642           4 :     if (ret)
     643           0 :         goto out;
     644             : 
     645           0 :     for(;;) {
     646           4 :         password_data[0].data   = buf1;
     647           4 :         password_data[0].length = sizeof(buf1);
     648             : 
     649           4 :         prompts[0].hidden = 1;
     650           4 :         prompts[0].prompt = "New password: ";
     651           4 :         prompts[0].reply  = &password_data[0];
     652           4 :         prompts[0].type   = KRB5_PROMPT_TYPE_NEW_PASSWORD;
     653             : 
     654           4 :         password_data[1].data   = buf2;
     655           4 :         password_data[1].length = sizeof(buf2);
     656             : 
     657           4 :         prompts[1].hidden = 1;
     658           4 :         prompts[1].prompt = "Repeat new password: ";
     659           4 :         prompts[1].reply  = &password_data[1];
     660           4 :         prompts[1].type   = KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN;
     661             : 
     662           4 :         ret = (*prompter) (context, data, NULL, "Changing password",
     663             :                            2, prompts);
     664           4 :         if (ret) {
     665           0 :             memset (buf1, 0, sizeof(buf1));
     666           0 :             memset (buf2, 0, sizeof(buf2));
     667           0 :             goto out;
     668             :         }
     669             : 
     670           4 :         if (strcmp (buf1, buf2) == 0)
     671           4 :             break;
     672           0 :         memset (buf1, 0, sizeof(buf1));
     673           0 :         memset (buf2, 0, sizeof(buf2));
     674             :     }
     675             : 
     676           4 :     ret = krb5_set_password (context,
     677             :                              &cpw_cred,
     678             :                              buf1,
     679             :                              client,
     680             :                              &result_code,
     681             :                              &result_code_string,
     682             :                              &result_string);
     683           4 :     if (ret)
     684           0 :         goto out;
     685             : 
     686           8 :     if (asprintf(&p, "%s: %.*s\n",
     687           4 :                  result_code ? "Error" : "Success",
     688           4 :                  (int)result_string.length,
     689           4 :                  result_string.length > 0 ? (char*)result_string.data : "") < 0)
     690             :     {
     691           0 :         ret = krb5_enomem(context);
     692           0 :         goto out;
     693             :     }
     694             : 
     695             :     /* return the result */
     696           4 :     (*prompter) (context, data, NULL, p, 0, NULL);
     697             : 
     698           4 :     if (result_code == 0) {
     699           4 :         strlcpy (newpw, buf1, newpw_sz);
     700           4 :         ret = 0;
     701             :     } else {
     702           0 :         krb5_set_error_message(context, ret = KRB5_CHPW_FAIL,
     703           0 :                                N_("failed changing password: %s", ""), p);
     704             :     }
     705           4 :     free (p);
     706             : 
     707           4 : out:
     708           4 :     memset_s(buf1, sizeof(buf1), 0, sizeof(buf1));
     709           4 :     memset_s(buf2, sizeof(buf2), 0, sizeof(buf2));
     710           4 :     krb5_data_free (&result_string);
     711           4 :     krb5_data_free (&result_code_string);
     712           4 :     krb5_free_cred_contents (context, &cpw_cred);
     713           4 :     return ret;
     714             : }
     715             : 
     716             : 
     717             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     718           0 : krb5_keyblock_key_proc (krb5_context context,
     719             :                         krb5_keytype type,
     720             :                         krb5_data *salt,
     721             :                         krb5_const_pointer keyseed,
     722             :                         krb5_keyblock **key)
     723             : {
     724           0 :     return krb5_copy_keyblock (context, keyseed, key);
     725             : }
     726             : 
     727             : /*
     728             :  *
     729             :  */
     730             : 
     731             : static krb5_error_code
     732       22216 : init_as_req (krb5_context context,
     733             :              KDCOptions opts,
     734             :              const krb5_creds *creds,
     735             :              const krb5_addresses *addrs,
     736             :              const krb5_enctype *etypes,
     737             :              AS_REQ *a)
     738             : {
     739         585 :     krb5_error_code ret;
     740             : 
     741       22216 :     memset(a, 0, sizeof(*a));
     742             : 
     743       22216 :     a->pvno = 5;
     744       22216 :     a->msg_type = krb_as_req;
     745       22216 :     a->req_body.kdc_options = opts;
     746       22216 :     a->req_body.cname = calloc(1, sizeof(*a->req_body.cname));
     747       22216 :     if (a->req_body.cname == NULL) {
     748           0 :         ret = krb5_enomem(context);
     749           0 :         goto fail;
     750             :     }
     751       22216 :     a->req_body.sname = calloc(1, sizeof(*a->req_body.sname));
     752       22216 :     if (a->req_body.sname == NULL) {
     753           0 :         ret = krb5_enomem(context);
     754           0 :         goto fail;
     755             :     }
     756             : 
     757       22216 :     ret = _krb5_principal2principalname (a->req_body.cname, creds->client);
     758       22216 :     if (ret)
     759           0 :         goto fail;
     760       22216 :     ret = copy_Realm(&creds->client->realm, &a->req_body.realm);
     761       22216 :     if (ret)
     762           0 :         goto fail;
     763             : 
     764       22216 :     ret = _krb5_principal2principalname (a->req_body.sname, creds->server);
     765       22216 :     if (ret)
     766           0 :         goto fail;
     767             : 
     768       22216 :     if(creds->times.starttime) {
     769           0 :         a->req_body.from = malloc(sizeof(*a->req_body.from));
     770           0 :         if (a->req_body.from == NULL) {
     771           0 :             ret = krb5_enomem(context);
     772           0 :             goto fail;
     773             :         }
     774           0 :         *a->req_body.from = creds->times.starttime;
     775             :     }
     776       22216 :     if(creds->times.endtime){
     777       22216 :         if ((ALLOC(a->req_body.till, 1)) != NULL)
     778       22216 :             *a->req_body.till = creds->times.endtime;
     779             :         else {
     780           0 :             ret = krb5_enomem(context);
     781           0 :             goto fail;
     782             :         }
     783             :     }
     784       22216 :     if(creds->times.renew_till){
     785        8511 :         a->req_body.rtime = malloc(sizeof(*a->req_body.rtime));
     786        8511 :         if (a->req_body.rtime == NULL) {
     787           0 :             ret = krb5_enomem(context);
     788           0 :             goto fail;
     789             :         }
     790        8511 :         *a->req_body.rtime = creds->times.renew_till;
     791             :     }
     792       22216 :     a->req_body.nonce = 0;
     793       22801 :     ret = _krb5_init_etype(context,
     794             :                            KRB5_PDU_AS_REQUEST,
     795             :                            &a->req_body.etype.len,
     796       22216 :                            &a->req_body.etype.val,
     797             :                            etypes);
     798       22216 :     if (ret)
     799           0 :         goto fail;
     800             : 
     801             :     /*
     802             :      * This means no addresses
     803             :      */
     804             : 
     805       22216 :     if (addrs && addrs->len == 0) {
     806       22213 :         a->req_body.addresses = NULL;
     807             :     } else {
     808           3 :         a->req_body.addresses = malloc(sizeof(*a->req_body.addresses));
     809           3 :         if (a->req_body.addresses == NULL) {
     810           0 :             ret = krb5_enomem(context);
     811           0 :             goto fail;
     812             :         }
     813             : 
     814           3 :         if (addrs)
     815           3 :             ret = krb5_copy_addresses(context, addrs, a->req_body.addresses);
     816             :         else {
     817           0 :             ret = krb5_get_all_client_addrs (context, a->req_body.addresses);
     818           0 :             if(ret == 0 && a->req_body.addresses->len == 0) {
     819           0 :                 free(a->req_body.addresses);
     820           0 :                 a->req_body.addresses = NULL;
     821             :             }
     822             :         }
     823           3 :         if (ret)
     824           0 :             goto fail;
     825             :     }
     826             : 
     827       22216 :     a->req_body.enc_authorization_data = NULL;
     828       22216 :     a->req_body.additional_tickets = NULL;
     829             : 
     830       22216 :     a->padata = NULL;
     831             : 
     832       22216 :     return 0;
     833           0 :  fail:
     834           0 :     free_AS_REQ(a);
     835           0 :     memset_s(a, sizeof(*a), 0, sizeof(*a));
     836           0 :     return ret;
     837             : }
     838             : 
     839             : 
     840             : static krb5_error_code
     841       39961 : set_paid(struct pa_info_data *paid, krb5_context context,
     842             :          krb5_enctype etype,
     843             :          krb5_salttype salttype, void *salt_string, size_t salt_len,
     844             :          krb5_data *s2kparams)
     845             : {
     846       39961 :     paid->etype = etype;
     847       39961 :     paid->salt.salttype = salttype;
     848       39961 :     paid->salt.saltvalue.data = malloc(salt_len + 1);
     849       39961 :     if (paid->salt.saltvalue.data == NULL) {
     850           0 :         krb5_clear_error_message(context);
     851           0 :         return krb5_enomem(context);
     852             :     }
     853       39961 :     memcpy(paid->salt.saltvalue.data, salt_string, salt_len);
     854       39961 :     ((char *)paid->salt.saltvalue.data)[salt_len] = '\0';
     855       39961 :     paid->salt.saltvalue.length = salt_len;
     856       39961 :     if (s2kparams) {
     857        1740 :         krb5_error_code ret;
     858             : 
     859       39369 :         ret = krb5_copy_data(context, s2kparams, &paid->s2kparams);
     860       39369 :         if (ret) {
     861           0 :             krb5_clear_error_message(context);
     862           0 :             krb5_free_salt(context, paid->salt);
     863           0 :             return ret;
     864             :         }
     865             :     } else
     866         592 :         paid->s2kparams = NULL;
     867             : 
     868       38218 :     return 0;
     869             : }
     870             : 
     871             : static struct pa_info_data *
     872       39961 : pa_etype_info2(krb5_context context,
     873             :                const krb5_principal client,
     874             :                const AS_REQ *asreq,
     875             :                struct pa_info_data *paid,
     876             :                heim_octet_string *data)
     877             : {
     878        1743 :     krb5_error_code ret;
     879        1743 :     ETYPE_INFO2 e;
     880        1743 :     size_t sz;
     881        1743 :     size_t i, j;
     882             : 
     883       39961 :     memset(&e, 0, sizeof(e));
     884       39961 :     ret = decode_ETYPE_INFO2(data->data, data->length, &e, &sz);
     885       39961 :     if (ret)
     886           0 :         goto out;
     887       39961 :     if (e.len == 0)
     888           0 :         goto out;
     889       40910 :     for (j = 0; j < asreq->req_body.etype.len; j++) {
     890       41859 :         for (i = 0; i < e.len; i++) {
     891             : 
     892       40910 :             if (krb5_enctype_valid(context, e.val[i].etype) != 0)
     893           0 :                 continue;
     894             : 
     895       40910 :             if (asreq->req_body.etype.val[j] == e.val[i].etype) {
     896        1743 :                 krb5_salt salt;
     897       39961 :                 if (e.val[i].salt == NULL)
     898         598 :                     ret = krb5_get_pw_salt(context, client, &salt);
     899             :                 else {
     900       39363 :                     salt.saltvalue.data = *e.val[i].salt;
     901       39363 :                     salt.saltvalue.length = strlen(*e.val[i].salt);
     902       39363 :                     ret = 0;
     903             :                 }
     904       39961 :                 if (ret == 0)
     905       39961 :                     ret = set_paid(paid, context, e.val[i].etype,
     906             :                                    KRB5_PW_SALT,
     907             :                                    salt.saltvalue.data,
     908             :                                    salt.saltvalue.length,
     909       39961 :                                    e.val[i].s2kparams);
     910       39961 :                 if (e.val[i].salt == NULL)
     911         598 :                     krb5_free_salt(context, salt);
     912       39961 :                 if (ret == 0) {
     913       39961 :                     free_ETYPE_INFO2(&e);
     914       39961 :                     return paid;
     915             :                 }
     916             :             }
     917             :         }
     918             :     }
     919           0 :  out:
     920           0 :     free_ETYPE_INFO2(&e);
     921           0 :     return NULL;
     922             : }
     923             : 
     924             : static struct pa_info_data *
     925           0 : pa_etype_info(krb5_context context,
     926             :               const krb5_principal client,
     927             :               const AS_REQ *asreq,
     928             :               struct pa_info_data *paid,
     929             :               heim_octet_string *data)
     930             : {
     931           0 :     krb5_error_code ret;
     932           0 :     ETYPE_INFO e;
     933           0 :     size_t sz;
     934           0 :     size_t i, j;
     935             : 
     936           0 :     memset(&e, 0, sizeof(e));
     937           0 :     ret = decode_ETYPE_INFO(data->data, data->length, &e, &sz);
     938           0 :     if (ret)
     939           0 :         goto out;
     940           0 :     if (e.len == 0)
     941           0 :         goto out;
     942           0 :     for (j = 0; j < asreq->req_body.etype.len; j++) {
     943           0 :         for (i = 0; i < e.len; i++) {
     944             : 
     945           0 :             if (krb5_enctype_valid(context, e.val[i].etype) != 0)
     946           0 :                 continue;
     947             : 
     948           0 :             if (asreq->req_body.etype.val[j] == e.val[i].etype) {
     949           0 :                 krb5_salt salt;
     950           0 :                 salt.salttype = KRB5_PW_SALT;
     951           0 :                 if (e.val[i].salt == NULL)
     952           0 :                     ret = krb5_get_pw_salt(context, client, &salt);
     953             :                 else {
     954           0 :                     salt.saltvalue = *e.val[i].salt;
     955           0 :                     ret = 0;
     956             :                 }
     957           0 :                 if (e.val[i].salttype)
     958           0 :                     salt.salttype = *e.val[i].salttype;
     959           0 :                 if (ret == 0) {
     960           0 :                     ret = set_paid(paid, context, e.val[i].etype,
     961             :                                    salt.salttype,
     962             :                                    salt.saltvalue.data,
     963             :                                    salt.saltvalue.length,
     964             :                                    NULL);
     965           0 :                     if (e.val[i].salt == NULL)
     966           0 :                         krb5_free_salt(context, salt);
     967             :                 }
     968           0 :                 if (ret == 0) {
     969           0 :                     free_ETYPE_INFO(&e);
     970           0 :                     return paid;
     971             :                 }
     972             :             }
     973             :         }
     974             :     }
     975           0 :  out:
     976           0 :     free_ETYPE_INFO(&e);
     977           0 :     return NULL;
     978             : }
     979             : 
     980             : static struct pa_info_data *
     981           0 : pa_pw_or_afs3_salt(krb5_context context,
     982             :                    const krb5_principal client,
     983             :                    const AS_REQ *asreq,
     984             :                    struct pa_info_data *paid,
     985             :                    heim_octet_string *data)
     986             : {
     987           0 :     krb5_error_code ret;
     988           0 :     if (paid->etype == KRB5_ENCTYPE_NULL)
     989           0 :         return NULL;
     990           0 :     if (krb5_enctype_valid(context, paid->etype) != 0)
     991           0 :         return NULL;
     992             : 
     993           0 :     ret = set_paid(paid, context,
     994             :                    paid->etype,
     995             :                    paid->salt.salttype,
     996             :                    data->data,
     997             :                    data->length,
     998             :                    NULL);
     999           0 :     if (ret)
    1000           0 :         return NULL;
    1001           0 :     return paid;
    1002             : }
    1003             : 
    1004             : 
    1005             : static krb5_error_code
    1006       13903 : make_pa_enc_timestamp(krb5_context context, METHOD_DATA *md,
    1007             :                       krb5_enctype etype, krb5_keyblock *key)
    1008             : {
    1009         585 :     PA_ENC_TS_ENC p;
    1010         585 :     unsigned char *buf;
    1011         585 :     size_t buf_size;
    1012       13903 :     size_t len = 0;
    1013         585 :     EncryptedData encdata;
    1014         585 :     krb5_error_code ret;
    1015         585 :     int32_t usec;
    1016         585 :     int usec2;
    1017         585 :     krb5_crypto crypto;
    1018             : 
    1019       13903 :     krb5_us_timeofday (context, &p.patimestamp, &usec);
    1020       13903 :     usec2         = usec;
    1021       13903 :     p.pausec      = &usec2;
    1022             : 
    1023       13903 :     ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC, buf, buf_size, &p, &len, ret);
    1024       13903 :     if (ret)
    1025           0 :         return ret;
    1026       13903 :     if(buf_size != len)
    1027           0 :         krb5_abortx(context, "internal error in ASN.1 encoder");
    1028             : 
    1029       13903 :     ret = krb5_crypto_init(context, key, 0, &crypto);
    1030       13903 :     if (ret) {
    1031           0 :         free(buf);
    1032           0 :         return ret;
    1033             :     }
    1034       13903 :     ret = krb5_encrypt_EncryptedData(context,
    1035             :                                      crypto,
    1036             :                                      KRB5_KU_PA_ENC_TIMESTAMP,
    1037             :                                      buf,
    1038             :                                      len,
    1039             :                                      0,
    1040             :                                      &encdata);
    1041       13903 :     free(buf);
    1042       13903 :     krb5_crypto_destroy(context, crypto);
    1043       13903 :     if (ret)
    1044           0 :         return ret;
    1045             : 
    1046       13903 :     ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_size, &encdata, &len, ret);
    1047       13903 :     free_EncryptedData(&encdata);
    1048       13903 :     if (ret)
    1049           0 :         return ret;
    1050       13903 :     if(buf_size != len)
    1051           0 :         krb5_abortx(context, "internal error in ASN.1 encoder");
    1052             : 
    1053       13903 :     ret = krb5_padata_add(context, md, KRB5_PADATA_ENC_TIMESTAMP, buf, len);
    1054       13903 :     if (ret)
    1055           0 :         free(buf);
    1056       13318 :     return ret;
    1057             : }
    1058             : 
    1059             : static krb5_error_code
    1060       13903 : add_enc_ts_padata(krb5_context context,
    1061             :                   METHOD_DATA *md,
    1062             :                   krb5_principal client,
    1063             :                   krb5_s2k_proc keyproc,
    1064             :                   krb5_const_pointer keyseed,
    1065             :                   krb5_enctype *enctypes,
    1066             :                   unsigned netypes,
    1067             :                   krb5_salt *salt,
    1068             :                   krb5_data *s2kparams)
    1069             : {
    1070         585 :     krb5_error_code ret;
    1071         585 :     krb5_salt salt2;
    1072         585 :     krb5_enctype *ep;
    1073         585 :     size_t i;
    1074             : 
    1075       13903 :     memset(&salt2, 0, sizeof(salt2));
    1076             : 
    1077       13903 :     if(salt == NULL) {
    1078             :         /* default to standard salt */
    1079           0 :         ret = krb5_get_pw_salt (context, client, &salt2);
    1080           0 :         if (ret)
    1081           0 :             return ret;
    1082           0 :         salt = &salt2;
    1083             :     }
    1084       13903 :     if (!enctypes) {
    1085           0 :         enctypes = context->etypes;
    1086           0 :         netypes = 0;
    1087           0 :         for (ep = enctypes; *ep != ETYPE_NULL; ep++)
    1088           0 :             netypes++;
    1089             :     }
    1090             : 
    1091       27806 :     for (i = 0; i < netypes; ++i) {
    1092         585 :         krb5_keyblock *key;
    1093             : 
    1094       13903 :         _krb5_debug(context, 5, "krb5_get_init_creds: using ENC-TS with enctype %d", enctypes[i]);
    1095             : 
    1096       13903 :         ret = (*keyproc)(context, enctypes[i], keyseed,
    1097             :                          *salt, s2kparams, &key);
    1098       13903 :         if (ret)
    1099           0 :             continue;
    1100       13903 :         ret = make_pa_enc_timestamp (context, md, enctypes[i], key);
    1101       13903 :         krb5_free_keyblock (context, key);
    1102       13903 :         if (ret)
    1103           0 :             return ret;
    1104             :     }
    1105       13903 :     if(salt == &salt2)
    1106           0 :         krb5_free_salt(context, salt2);
    1107       13318 :     return 0;
    1108             : }
    1109             : 
    1110             : static krb5_error_code
    1111       13903 : pa_data_to_md_ts_enc(krb5_context context,
    1112             :                      const AS_REQ *a,
    1113             :                      const krb5_principal client,
    1114             :                      krb5_init_creds_context ctx,
    1115             :                      struct pa_info_data *ppaid,
    1116             :                      METHOD_DATA *md)
    1117             : {
    1118       13903 :     if (ctx->keyproc == NULL || ctx->keyseed == NULL)
    1119           0 :         return 0;
    1120             : 
    1121       13903 :     if (ppaid) {
    1122       13903 :         add_enc_ts_padata(context, md, client,
    1123       13318 :                           ctx->keyproc, ctx->keyseed,
    1124             :                           &ppaid->etype, 1,
    1125             :                           &ppaid->salt, ppaid->s2kparams);
    1126             :     } else {
    1127           0 :         krb5_salt salt;
    1128             : 
    1129           0 :         _krb5_debug(context, 5, "krb5_get_init_creds: pa-info not found, guessing salt");
    1130             : 
    1131             :         /* make a v5 salted pa-data */
    1132           0 :         add_enc_ts_padata(context, md, client,
    1133           0 :                           ctx->keyproc, ctx->keyseed,
    1134           0 :                           a->req_body.etype.val, a->req_body.etype.len,
    1135             :                           NULL, NULL);
    1136             : 
    1137             :         /* make a v4 salted pa-data */
    1138           0 :         salt.salttype = KRB5_PW_SALT;
    1139           0 :         krb5_data_zero(&salt.saltvalue);
    1140           0 :         add_enc_ts_padata(context, md, client,
    1141           0 :                           ctx->keyproc, ctx->keyseed,
    1142           0 :                           a->req_body.etype.val, a->req_body.etype.len,
    1143             :                           &salt, NULL);
    1144             :     }
    1145       13318 :     return 0;
    1146             : }
    1147             : 
    1148             : static krb5_error_code
    1149       13631 : pa_data_to_key_plain(krb5_context context,
    1150             :                      const krb5_principal client,
    1151             :                      krb5_init_creds_context ctx,
    1152             :                      krb5_salt salt,
    1153             :                      krb5_data *s2kparams,
    1154             :                      krb5_enctype etype,
    1155             :                      krb5_keyblock **key)
    1156             : {
    1157         585 :     krb5_error_code ret;
    1158             : 
    1159       14216 :     ret = (*ctx->keyproc)(context, etype, ctx->keyseed,
    1160             :                            salt, s2kparams, key);
    1161       13631 :     return ret;
    1162             : }
    1163             : 
    1164             : struct pkinit_context {
    1165             :     unsigned int win2k : 1;
    1166             :     unsigned int used_pkinit : 1;
    1167             : };
    1168             : 
    1169             : 
    1170             : static krb5_error_code
    1171         124 : pa_data_to_md_pkinit(krb5_context context,
    1172             :                      const AS_REQ *a,
    1173             :                      const krb5_principal client,
    1174             :                      int win2k,
    1175             :                      krb5_init_creds_context ctx,
    1176             :                      METHOD_DATA *md)
    1177             : {
    1178         124 :     if (ctx->pk_init_ctx == NULL)
    1179           0 :         return 0;
    1180             : #ifdef PKINIT
    1181         124 :     return _krb5_pk_mk_padata(context,
    1182         124 :                               ctx->pk_init_ctx,
    1183             :                               ctx->ic_flags,
    1184             :                               win2k,
    1185             :                               &a->req_body,
    1186             :                               ctx->pk_nonce,
    1187             :                               md);
    1188             : #else
    1189             :     krb5_set_error_message(context, EINVAL,
    1190             :                            N_("no support for PKINIT compiled in", ""));
    1191             :     return EINVAL;
    1192             : #endif
    1193             : }
    1194             : 
    1195             : static krb5_error_code
    1196         124 : pkinit_configure_ietf(krb5_context context, krb5_init_creds_context ctx, void *pa_ctx)
    1197             : {
    1198         124 :     struct pkinit_context *pkinit_ctx = pa_ctx;
    1199             : 
    1200         124 :     pkinit_ctx->win2k = 0;
    1201             : 
    1202         124 :     if (ctx->pk_init_ctx == NULL)
    1203           0 :         return HEIM_ERR_PA_CANT_CONTINUE;
    1204             : 
    1205         124 :     return 0;
    1206             : }
    1207             : 
    1208             : static krb5_error_code
    1209         124 : pkinit_configure_win(krb5_context context, krb5_init_creds_context ctx, void *pa_ctx)
    1210             : {
    1211         124 :     struct pkinit_context *pkinit_ctx = pa_ctx;
    1212             : 
    1213         124 :     pkinit_ctx->win2k = 1;
    1214         124 :     pkinit_ctx->used_pkinit = 0;
    1215             : 
    1216         124 :     if (ctx->pk_init_ctx == NULL)
    1217           0 :         return HEIM_ERR_PA_CANT_CONTINUE;
    1218             : 
    1219         124 :     return 0;
    1220             : }
    1221             : 
    1222             : static krb5_error_code
    1223         137 : pkinit_step(krb5_context context, krb5_init_creds_context ctx, void *pa_ctx, PA_DATA *pa, const AS_REQ *a,
    1224             :             const AS_REP *rep, METHOD_DATA *in_md, METHOD_DATA *out_md)
    1225             : {
    1226         137 :     krb5_error_code ret = HEIM_ERR_PA_CANT_CONTINUE;
    1227         137 :     struct pkinit_context *pkinit_ctx = pa_ctx;
    1228             : 
    1229         137 :     if (rep == NULL) {
    1230         124 :         if (pkinit_ctx->used_pkinit) {
    1231           0 :             krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP,
    1232             :                                    "Already tried PKINIT(%s), looping",
    1233           0 :                                    pkinit_ctx->win2k ? "win2k" : "ietf");
    1234             :         } else {
    1235         124 :             ret = pa_data_to_md_pkinit(context, a, ctx->cred.client,
    1236         124 :                                        (pkinit_ctx->win2k != 0),
    1237             :                                        ctx, out_md);
    1238         124 :             if (ret == 0)
    1239         124 :                 ret = HEIM_ERR_PA_CONTINUE_NEEDED;
    1240             : 
    1241         124 :             pkinit_ctx->used_pkinit = 1;
    1242             :         }
    1243          13 :     } else if (pa) {
    1244          13 :         ret = _krb5_pk_rd_pa_reply(context,
    1245          13 :                                    a->req_body.realm,
    1246          13 :                                    ctx->pk_init_ctx,
    1247          13 :                                    rep->enc_part.etype,
    1248             :                                    ctx->pk_nonce,
    1249          13 :                                    &ctx->req_buffer,
    1250             :                                    pa,
    1251             :                                    &ctx->fast_state.reply_key);
    1252          13 :         if (ret == 0)
    1253          13 :             ctx->runflags.allow_save_as_reply_key = 1;
    1254             :     }
    1255             : 
    1256         137 :     return ret;
    1257             : }
    1258             : 
    1259             : static void
    1260         248 : pkinit_release(void *pa_ctx)
    1261             : {
    1262         248 : }
    1263             : 
    1264             : /*
    1265             :  * GSS-API pre-authentication support
    1266             :  */
    1267             : 
    1268             : struct pa_gss_context {
    1269             :     struct gss_ctx_id_t_desc_struct *context_handle;
    1270             :     int open;
    1271             : };
    1272             : 
    1273             : static krb5_error_code
    1274           0 : pa_gss_configure(krb5_context context,
    1275             :                  krb5_init_creds_context ctx,
    1276             :                  void *pa_ctx)
    1277             : {
    1278           0 :     krb5_gss_init_ctx gssic = ctx->gss_init_ctx;
    1279           0 :     struct pa_gss_context *pa_gss_ctx = pa_ctx;
    1280             : 
    1281           0 :     if (gssic == NULL)
    1282           0 :         return HEIM_ERR_PA_CANT_CONTINUE;
    1283             : 
    1284           0 :     pa_gss_ctx->context_handle = NULL;
    1285           0 :     pa_gss_ctx->open = 0;
    1286             : 
    1287           0 :     return 0;
    1288             : }
    1289             : 
    1290             : static krb5_error_code
    1291           0 : pa_data_to_md_gss(krb5_context context,
    1292             :                   const AS_REQ *a,
    1293             :                   const krb5_creds *creds,
    1294             :                   krb5_init_creds_context ctx,
    1295             :                   struct pa_gss_context *pa_gss_ctx,
    1296             :                   PA_DATA *pa,
    1297             :                   METHOD_DATA *out_md)
    1298             : {
    1299           0 :     krb5_error_code ret;
    1300           0 :     krb5_gss_init_ctx gssic = ctx->gss_init_ctx;
    1301           0 :     krb5_data req_body;
    1302           0 :     krb5_data *input_token, output_token;
    1303           0 :     size_t len = 0;
    1304             : 
    1305           0 :     krb5_data_zero(&req_body);
    1306           0 :     krb5_data_zero(&output_token);
    1307             : 
    1308           0 :     input_token = pa ? &pa->padata_value : NULL;
    1309             : 
    1310           0 :     if ((input_token == NULL || input_token->length == 0) &&
    1311           0 :         pa_gss_ctx->context_handle) {
    1312           0 :         krb5_set_error_message(context, HEIM_ERR_PA_CANT_CONTINUE,
    1313             :                                "Missing GSS preauthentication data from KDC");
    1314           0 :         return HEIM_ERR_PA_CANT_CONTINUE;
    1315             :     }
    1316             : 
    1317           0 :     ASN1_MALLOC_ENCODE(KDC_REQ_BODY, req_body.data, req_body.length,
    1318             :                        &ctx->as_req.req_body, &len, ret);
    1319           0 :     if (ret)
    1320           0 :         goto out;
    1321           0 :     heim_assert(req_body.length == len, "ASN.1 internal error");
    1322             : 
    1323           0 :     ret = gssic->step(context, gssic, creds, &pa_gss_ctx->context_handle,
    1324             :                       ctx->flags, &req_body,
    1325             :                       input_token, &output_token);
    1326             : 
    1327             :     /*
    1328             :      * If FAST authenticated the KDC (which will be the case unless anonymous
    1329             :      * PKINIT was used without KDC certificate validation) then we can relax
    1330             :      * the mutual authentication requirement.
    1331             :      */
    1332           0 :     if (ret == KRB5_MUTUAL_FAILED &&
    1333           0 :         (ctx->fast_state.flags & KRB5_FAST_EXPECTED) &&
    1334           0 :         (ctx->fast_state.flags & KRB5_FAST_KDC_VERIFIED))
    1335           0 :         ret = 0;
    1336           0 :     if (ret == 0) {
    1337             :         /*
    1338             :          * Always require a strengthen key if FAST was used, to avoid a MITM
    1339             :          * attack that could result in unintended privilege escalation should
    1340             :          * the KDC add positive authorization data from the armor ticket.
    1341             :          */
    1342           0 :         if ((ctx->fast_state.flags & KRB5_FAST_EXPECTED) &&
    1343           0 :             ctx->fast_state.strengthen_key == NULL) {
    1344           0 :             krb5_set_error_message(context, HEIM_ERR_PA_CANT_CONTINUE,
    1345             :                                    "FAST GSS pre-authentication without strengthen key");
    1346           0 :             ret = KRB5_KDCREP_MODIFIED;
    1347           0 :             goto out;
    1348             :         }
    1349             : 
    1350           0 :         pa_gss_ctx->open = 1;
    1351             :     }
    1352             : 
    1353           0 :     if (output_token.length) {
    1354           0 :         ret = krb5_padata_add(context, out_md, KRB5_PADATA_GSS,
    1355             :                               output_token.data, output_token.length);
    1356           0 :         if (ret)
    1357           0 :             goto out;
    1358             : 
    1359           0 :         krb5_data_zero(&output_token);
    1360             :     }
    1361             : 
    1362           0 : out:
    1363           0 :     krb5_data_free(&output_token);
    1364           0 :     krb5_data_free(&req_body);
    1365             : 
    1366           0 :     return ret;
    1367             : }
    1368             : 
    1369             : static krb5_error_code
    1370           0 : pa_gss_step(krb5_context context,
    1371             :             krb5_init_creds_context ctx,
    1372             :             void *pa_ctx,
    1373             :             PA_DATA *pa,
    1374             :             const AS_REQ *a,
    1375             :             const AS_REP *rep,
    1376             :             METHOD_DATA *in_md,
    1377             :             METHOD_DATA *out_md)
    1378             : {
    1379           0 :     krb5_error_code ret;
    1380           0 :     krb5_principal cname;
    1381           0 :     krb5_gss_init_ctx gssic = ctx->gss_init_ctx;
    1382           0 :     struct pa_gss_context *pa_gss_ctx = pa_ctx;
    1383             : 
    1384           0 :     heim_assert(gssic != NULL, "invalid context passed to pa_gss_step");
    1385             : 
    1386           0 :     if (!pa_gss_ctx->open) {
    1387           0 :         ret = pa_data_to_md_gss(context, a, &ctx->cred, ctx,
    1388             :                                 pa_gss_ctx, pa, out_md);
    1389           0 :         if (ret == HEIM_ERR_PA_CONTINUE_NEEDED && rep) {
    1390           0 :             krb5_set_error_message(context, KRB5_PREAUTH_FAILED,
    1391             :                                    "KDC sent AS-REP before GSS "
    1392             :                                    "pre-authentication completed");
    1393           0 :             ret = KRB5_KDCREP_MODIFIED;
    1394           0 :         } else if (ret == 0 && rep == NULL) {
    1395           0 :             ret = HEIM_ERR_PA_CONTINUE_NEEDED; /* odd number of legs */
    1396             :         }
    1397           0 :         if (ret)
    1398           0 :             return ret;
    1399           0 :     } else if (pa && pa->padata_value.length) {
    1400           0 :         krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP,
    1401             :                                "Already completed GSS pre-authentication");
    1402           0 :         return KRB5_GET_IN_TKT_LOOP;
    1403           0 :     } else if (rep == NULL) {
    1404           0 :         krb5_set_error_message(context, KRB5_PREAUTH_FAILED,
    1405             :                                "Completed GSS pre-authentication before KDC");
    1406           0 :         return KRB5_PREAUTH_FAILED;
    1407             :     }
    1408             : 
    1409           0 :     heim_assert(pa_gss_ctx->open,
    1410             :                 "GSS pre-authentication incomplete");
    1411             : 
    1412           0 :     ret = gssic->finish(context, gssic, &ctx->cred,
    1413           0 :                         pa_gss_ctx->context_handle, ctx->nonce,
    1414           0 :                         rep->enc_part.etype, &cname,
    1415             :                         &ctx->fast_state.reply_key);
    1416           0 :     if (ret)
    1417           0 :         return ret;
    1418             : 
    1419             :     {
    1420           0 :         char *from = NULL;
    1421           0 :         char *to = NULL;
    1422             : 
    1423           0 :         if (krb5_unparse_name(context, ctx->cred.client, &from) == 0) {
    1424           0 :             if (krb5_unparse_name(context, cname, &to) == 0) {
    1425           0 :                 _krb5_debug(context, 1, "pa_gss_step: %s as %s",
    1426             :                             from, to);
    1427           0 :                 krb5_xfree(to);
    1428             :             }
    1429           0 :             krb5_xfree(from);
    1430             :         }
    1431             :     }
    1432             : 
    1433           0 :     if (krb5_principal_is_federated(context, ctx->cred.client)) {
    1434             :         /*
    1435             :          * The well-known federated name will be replaced with the cname
    1436             :          * in the AS-REP, but save the locally mapped initiator name in the
    1437             :          * cred for logging.
    1438             :          */
    1439           0 :         krb5_free_principal(context, ctx->cred.client);
    1440           0 :         ctx->cred.client = cname;
    1441             : 
    1442           0 :         ctx->ic_flags |= KRB5_INIT_CREDS_NO_C_CANON_CHECK;
    1443             :     } else {
    1444           0 :         krb5_free_principal(context, cname);
    1445             :     }
    1446             : 
    1447           0 :     ctx->runflags.allow_save_as_reply_key = 1;
    1448             : 
    1449           0 :     gssic->delete_sec_context(context, gssic, pa_gss_ctx->context_handle);
    1450           0 :     pa_gss_ctx->context_handle = NULL;
    1451           0 :     pa_gss_ctx->open = 0;
    1452             : 
    1453           0 :     return 0;
    1454             : }
    1455             : 
    1456             : static krb5_error_code
    1457           0 : pa_gss_restart(krb5_context context,
    1458             :                krb5_init_creds_context ctx,
    1459             :                void *pa_ctx)
    1460             : {
    1461           0 :     krb5_gss_init_ctx gssic = ctx->gss_init_ctx;
    1462           0 :     struct pa_gss_context *pa_gss_ctx = pa_ctx;
    1463             : 
    1464           0 :     if (gssic == NULL)
    1465           0 :         return HEIM_ERR_PA_CANT_CONTINUE;
    1466             : 
    1467           0 :     gssic->delete_sec_context(context, gssic, pa_gss_ctx->context_handle);
    1468           0 :     pa_gss_ctx->context_handle = NULL;
    1469           0 :     pa_gss_ctx->open = 0;
    1470             : 
    1471           0 :     return 0;
    1472             : }
    1473             : 
    1474             : static void
    1475           0 : pa_gss_release(void *pa_ctx)
    1476             : {
    1477           0 : }
    1478             : 
    1479             : krb5_error_code
    1480         151 : _krb5_make_pa_enc_challenge(krb5_context context,
    1481             :                             krb5_crypto crypto,
    1482             :                             krb5_key_usage usage,
    1483             :                             METHOD_DATA *md)
    1484             : {
    1485           0 :     PA_ENC_TS_ENC p;
    1486           0 :     unsigned char *buf;
    1487           0 :     size_t buf_size;
    1488         151 :     size_t len = 0;
    1489           0 :     EncryptedData encdata;
    1490           0 :     krb5_error_code ret;
    1491           0 :     int32_t usec;
    1492           0 :     int usec2;
    1493             : 
    1494         151 :     krb5_us_timeofday (context, &p.patimestamp, &usec);
    1495         151 :     usec2         = usec;
    1496         151 :     p.pausec      = &usec2;
    1497             : 
    1498         151 :     ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC, buf, buf_size, &p, &len, ret);
    1499         151 :     if (ret)
    1500           0 :         return ret;
    1501         151 :     if(buf_size != len)
    1502           0 :         krb5_abortx(context, "internal error in ASN.1 encoder");
    1503             : 
    1504         151 :     ret = krb5_encrypt_EncryptedData(context,
    1505             :                                      crypto,
    1506             :                                      usage,
    1507             :                                      buf,
    1508             :                                      len,
    1509             :                                      0,
    1510             :                                      &encdata);
    1511         151 :     free(buf);
    1512         151 :     if (ret)
    1513           0 :         return ret;
    1514             : 
    1515         151 :     ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_size, &encdata, &len, ret);
    1516         151 :     free_EncryptedData(&encdata);
    1517         151 :     if (ret)
    1518           0 :         return ret;
    1519         151 :     if(buf_size != len)
    1520           0 :         krb5_abortx(context, "internal error in ASN.1 encoder");
    1521             : 
    1522         151 :     ret = krb5_padata_add(context, md, KRB5_PADATA_ENCRYPTED_CHALLENGE, buf, len);
    1523         151 :     if (ret)
    1524           0 :         free(buf);
    1525         151 :     return ret;
    1526             : }
    1527             : 
    1528             : krb5_error_code
    1529         158 : _krb5_validate_pa_enc_challenge(krb5_context context,
    1530             :                                 krb5_crypto crypto,
    1531             :                                 krb5_key_usage usage,
    1532             :                                 EncryptedData *enc_data,
    1533             :                                 const char *peer_name)
    1534             : {
    1535           0 :     krb5_error_code ret;
    1536           0 :     krb5_data ts_data;
    1537           0 :     PA_ENC_TS_ENC p;
    1538           0 :     time_t timestamp;
    1539           0 :     int32_t usec;
    1540           0 :     size_t size;
    1541             : 
    1542         158 :     ret = krb5_decrypt_EncryptedData(context, crypto, usage, enc_data, &ts_data);
    1543         158 :     if (ret)
    1544           6 :         return ret;
    1545             : 
    1546         152 :     ret = decode_PA_ENC_TS_ENC(ts_data.data,
    1547             :                                ts_data.length,
    1548             :                                &p,
    1549             :                                &size);
    1550         152 :     krb5_data_free(&ts_data);
    1551         152 :     if(ret){
    1552           0 :         ret = KRB5KDC_ERR_PREAUTH_FAILED;
    1553           0 :         _krb5_debug(context, 5, "Failed to decode PA-ENC-TS_ENC -- %s", peer_name);
    1554           0 :         goto out;
    1555             :     }
    1556             : 
    1557         152 :     krb5_us_timeofday(context, &timestamp, &usec);
    1558             : 
    1559         152 :     if (krb5_time_abs(timestamp, p.patimestamp) > context->max_skew) {
    1560           0 :         char client_time[100];
    1561             : 
    1562           1 :         krb5_format_time(context, p.patimestamp,
    1563             :                          client_time, sizeof(client_time), TRUE);
    1564             : 
    1565           1 :         ret = KRB5KRB_AP_ERR_SKEW;
    1566           1 :         _krb5_debug(context, 0, "Too large time skew, "
    1567             :                     "client time %s is out by %u > %d seconds -- %s",
    1568             :                     client_time,
    1569           1 :                     (unsigned)krb5_time_abs(timestamp, p.patimestamp),
    1570           1 :                     (int)context->max_skew,
    1571             :                     peer_name);
    1572             :     } else {
    1573         151 :         ret = 0;
    1574             :     }
    1575             : 
    1576         152 :  out:
    1577         152 :     free_PA_ENC_TS_ENC(&p);
    1578             : 
    1579         152 :     return ret;
    1580             : }
    1581             : 
    1582             : 
    1583             : static struct pa_info_data *
    1584             : process_pa_info(krb5_context, const krb5_principal, const AS_REQ *, struct pa_info_data *, METHOD_DATA *);
    1585             : 
    1586             : 
    1587             : static krb5_error_code
    1588           0 : enc_chal_step(krb5_context context, krb5_init_creds_context ctx, void *pa_ctx, PA_DATA *pa, const AS_REQ *a,
    1589             :               const AS_REP *rep, METHOD_DATA *in_md, METHOD_DATA *out_md)
    1590             : {
    1591           0 :     struct pa_info_data paid, *ppaid;
    1592           0 :     krb5_keyblock challengekey;
    1593           0 :     krb5_data pepper1, pepper2;
    1594           0 :     krb5_crypto crypto = NULL;
    1595           0 :     krb5_enctype aenctype;
    1596           0 :     krb5_error_code ret;
    1597             : 
    1598           0 :     memset(&paid, 0, sizeof(paid));
    1599             : 
    1600           0 :     if (rep == NULL)
    1601           0 :         paid.etype = KRB5_ENCTYPE_NULL;
    1602             :     else
    1603           0 :         paid.etype = rep->enc_part.etype;
    1604           0 :     ppaid = process_pa_info(context, ctx->cred.client, a, &paid, in_md);
    1605             : 
    1606             :     /*
    1607             :      * If we don't have ppaid, ts because the KDC have not sent any
    1608             :      * salt info, lets to the first roundtrip so the KDC have a chance
    1609             :      * to send any.
    1610             :      */
    1611           0 :     if (ppaid == NULL) {
    1612           0 :         _krb5_debug(context, 5, "no ppaid found");
    1613           0 :         return HEIM_ERR_PA_CONTINUE_NEEDED;
    1614             :     }
    1615           0 :     if (ppaid->etype == KRB5_ENCTYPE_NULL) {
    1616           0 :         return HEIM_ERR_PA_CANT_CONTINUE;
    1617             :     }
    1618             : 
    1619           0 :     if (ctx->fast_state.reply_key)
    1620           0 :         krb5_free_keyblock(context, ctx->fast_state.reply_key);
    1621             : 
    1622           0 :     ret = pa_data_to_key_plain(context, ctx->cred.client, ctx,
    1623             :                                ppaid->salt, ppaid->s2kparams, ppaid->etype,
    1624             :                                &ctx->fast_state.reply_key);
    1625           0 :     free_paid(context, &paid);
    1626           0 :     if (ret) {
    1627           0 :         _krb5_debug(context, 5, "enc-chal: failed to build key");
    1628           0 :         return ret;
    1629             :     }
    1630             : 
    1631           0 :     ret = krb5_crypto_init(context, ctx->fast_state.reply_key, 0, &crypto);
    1632           0 :     if (ret)
    1633           0 :         return ret;
    1634             : 
    1635           0 :     krb5_crypto_getenctype(context, ctx->fast_state.armor_crypto, &aenctype);
    1636             : 
    1637           0 :     pepper1.data = rep ? "kdcchallengearmor" : "clientchallengearmor";
    1638           0 :     pepper1.length = strlen(pepper1.data);
    1639           0 :     pepper2.data = "challengelongterm";
    1640           0 :     pepper2.length = strlen(pepper2.data);
    1641             : 
    1642           0 :     ret = krb5_crypto_fx_cf2(context, ctx->fast_state.armor_crypto, crypto,
    1643             :                              &pepper1, &pepper2, aenctype,
    1644             :                              &challengekey);
    1645           0 :     krb5_crypto_destroy(context, crypto);
    1646           0 :     if (ret)
    1647           0 :         return ret;
    1648             : 
    1649           0 :     ret = krb5_crypto_init(context, &challengekey, 0, &crypto);
    1650           0 :     krb5_free_keyblock_contents(context, &challengekey);
    1651           0 :     if (ret)
    1652           0 :         return ret;
    1653             : 
    1654           0 :     if (rep) {
    1655           0 :         EncryptedData enc_data;
    1656           0 :         size_t size;
    1657             : 
    1658           0 :         _krb5_debug(context, 5, "ENC_CHAL rep key");
    1659             : 
    1660           0 :         if (ctx->fast_state.strengthen_key == NULL) {
    1661           0 :             krb5_crypto_destroy(context, crypto);
    1662           0 :             _krb5_debug(context, 5, "ENC_CHAL w/o strengthen_key");
    1663           0 :             return KRB5_KDCREP_MODIFIED;
    1664             :         }
    1665             : 
    1666           0 :         if (pa == NULL) {
    1667           0 :             krb5_crypto_destroy(context, crypto);
    1668           0 :             _krb5_debug(context, 0, "KDC response missing");
    1669           0 :             return HEIM_ERR_PA_CANT_CONTINUE;
    1670             :         }
    1671             : 
    1672           0 :         ret = decode_EncryptedData(pa->padata_value.data,
    1673             :                                    pa->padata_value.length,
    1674             :                                    &enc_data,
    1675             :                                    &size);
    1676           0 :         if (ret) {
    1677           0 :             ret = KRB5KRB_AP_ERR_BAD_INTEGRITY;
    1678           0 :             _krb5_debug(context, 5, "Failed to decode ENC_CHAL KDC reply");
    1679           0 :             return ret;
    1680             :         }
    1681             : 
    1682           0 :         ret = _krb5_validate_pa_enc_challenge(context, crypto,
    1683             :                                               KRB5_KU_ENC_CHALLENGE_KDC,
    1684             :                                               &enc_data,
    1685             :                                               "KDC");
    1686           0 :         free_EncryptedData(&enc_data);
    1687           0 :         krb5_crypto_destroy(context, crypto);
    1688             : 
    1689           0 :         return ret;
    1690             : 
    1691             :     } else {
    1692             : 
    1693           0 :         ret = _krb5_make_pa_enc_challenge(context, crypto,
    1694             :                                           KRB5_KU_ENC_CHALLENGE_CLIENT,
    1695             :                                           out_md);
    1696           0 :         krb5_crypto_destroy(context, crypto);
    1697           0 :         if (ret) {
    1698           0 :             _krb5_debug(context, 5, "enc-chal: failed build enc challenge");
    1699           0 :             return ret;
    1700             :         }
    1701             : 
    1702           0 :         return HEIM_ERR_PA_CONTINUE_NEEDED;
    1703             :     }
    1704             : }
    1705             : 
    1706             : struct enc_ts_context {
    1707             :     int used_pa_types;
    1708             : #define  USED_ENC_TS_GUESS      4
    1709             : #define  USED_ENC_TS_INFO       8
    1710             : #define  USED_ENC_TS_RENEG      16
    1711             :     krb5_principal user;
    1712             : };
    1713             : 
    1714             : static krb5_error_code
    1715         263 : enc_ts_restart(krb5_context context, krb5_init_creds_context ctx, void *pa_ctx)
    1716             : {
    1717         263 :     struct enc_ts_context *pactx = (struct enc_ts_context *)pa_ctx;
    1718         263 :     pactx->used_pa_types = 0;
    1719         263 :     krb5_free_principal(context, pactx->user);
    1720         263 :     pactx->user = NULL;
    1721         263 :     return 0;
    1722             : }
    1723             : 
    1724             : static krb5_error_code
    1725       49889 : enc_ts_step(krb5_context context, krb5_init_creds_context ctx, void *pa_ctx, PA_DATA *pa,
    1726             :             const AS_REQ *a,
    1727             :             const AS_REP *rep,
    1728             :             METHOD_DATA *in_md, METHOD_DATA *out_md)
    1729             : {
    1730       49889 :     struct enc_ts_context *pactx = (struct enc_ts_context *)pa_ctx;
    1731        1755 :     struct pa_info_data paid, *ppaid;
    1732        1755 :     krb5_error_code ret;
    1733        1755 :     const char *state;
    1734        1755 :     unsigned flag;
    1735             : 
    1736             :     /*
    1737             :      * Keep track of the user we used so that we can restart
    1738             :      * authentication when we get referrals.
    1739             :      */
    1740             : 
    1741       49889 :     if (pactx->user && !krb5_principal_compare(context, pactx->user, ctx->cred.client)) {
    1742           0 :         pactx->used_pa_types = 0;
    1743           0 :         krb5_free_principal(context, pactx->user);
    1744           0 :         pactx->user = NULL;
    1745             :     }
    1746             : 
    1747       49889 :     if (pactx->user == NULL) {
    1748       22355 :         ret = krb5_copy_principal(context, ctx->cred.client, &pactx->user);
    1749       22355 :         if (ret)
    1750           0 :             return ret;
    1751             :     }
    1752             : 
    1753       49889 :     memset(&paid, 0, sizeof(paid));
    1754             : 
    1755       49889 :     if (rep == NULL)
    1756       35088 :         paid.etype = KRB5_ENCTYPE_NULL;
    1757             :     else
    1758       13631 :         paid.etype = rep->enc_part.etype;
    1759             : 
    1760       49889 :     ppaid = process_pa_info(context, ctx->cred.client, a, &paid, in_md);
    1761             : 
    1762       49889 :     if (rep) {
    1763             :         /*
    1764             :          * Some KDC's don't send salt info in the reply when there is
    1765             :          * success pre-auth happned before, so use cached copy (or
    1766             :          * even better, if there is just one pre-auth, save reply-key).
    1767             :          */
    1768       13631 :         if (ppaid == NULL && ctx->paid.etype != KRB5_ENCTYPE_NULL) {
    1769         602 :             ppaid = &ctx->paid;
    1770             : 
    1771       13029 :         } else if (ppaid == NULL) {
    1772           0 :             _krb5_debug(context, 0, "no paid when building key, build a default salt structure ?");
    1773           0 :             return HEIM_ERR_PA_CANT_CONTINUE;
    1774             :         }
    1775             : 
    1776       14216 :         ret = pa_data_to_key_plain(context, ctx->cred.client, ctx,
    1777       13631 :                                    ppaid->salt, ppaid->s2kparams, rep->enc_part.etype,
    1778             :                                    &ctx->fast_state.reply_key);
    1779       13631 :         free_paid(context, &paid);
    1780       13631 :         return ret;
    1781             :     }
    1782             : 
    1783             :     /*
    1784             :      * If we don't have ppaid, ts because the KDC have not sent any
    1785             :      * salt info, lets to the first roundtrip so the KDC have a chance
    1786             :      * to send any.
    1787             :      *
    1788             :      * Don't bother guessing, it sounds like a good idea until you run
    1789             :      * into KDCs that are doing failed auth counting based on the
    1790             :      * ENC_TS tries.
    1791             :      *
    1792             :      * Stashing the salt for the next run is a diffrent issue and
    1793             :      * could be considered in the future.
    1794             :      */
    1795             : 
    1796       36258 :     if (ppaid == NULL) {
    1797       22355 :         _krb5_debug(context, 5,
    1798             :                      "TS-ENC: waiting for KDC to set pw-salt/etype_info{,2}");
    1799       22355 :         return HEIM_ERR_PA_CONTINUE_NEEDED;
    1800             :     }
    1801       13903 :     if (ppaid->etype == KRB5_ENCTYPE_NULL) {
    1802           0 :         free_paid(context, &paid);
    1803           0 :         _krb5_debug(context, 5,
    1804             :                      "TS-ENC: kdc proposes enctype NULL ?");
    1805           0 :         return HEIM_ERR_PA_CANT_CONTINUE;
    1806             :     }
    1807             : 
    1808             :     /*
    1809             :      * We have to allow the KDC to re-negotiate the PA-TS data
    1810             :      * once, this is since the in the case of a windows read only
    1811             :      * KDC that doesn't have the keys simply guesses what the
    1812             :      * master is supposed to support. In the case where this
    1813             :      * breaks in when the RO-KDC is a newer version the the RW-KDC
    1814             :      * and the RO-KDC announced a enctype that the older doesn't
    1815             :      * support.
    1816             :      */
    1817       13903 :     if (pactx->used_pa_types & USED_ENC_TS_INFO) {
    1818           0 :         flag = USED_ENC_TS_RENEG;
    1819           0 :         state = "reneg";
    1820             :     } else {
    1821       13903 :         flag = USED_ENC_TS_INFO;
    1822       13903 :         state = "info";
    1823             :     }
    1824             : 
    1825       13903 :     if (pactx->used_pa_types & flag) {
    1826           0 :         free_paid(context, &paid);
    1827           0 :         krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP,
    1828             :                                "Already tried ENC-TS-%s, looping", state);
    1829           0 :         return KRB5_GET_IN_TKT_LOOP;
    1830             :     }
    1831             : 
    1832       13903 :     pactx->used_pa_types |= flag;
    1833             : 
    1834       13903 :     free_paid(context, &ctx->paid);
    1835       13903 :     ctx->paid = *ppaid;
    1836             : 
    1837       13903 :     ret = pa_data_to_md_ts_enc(context, a, ctx->cred.client, ctx, ppaid, out_md);
    1838       13903 :     if (ret)
    1839           0 :         return ret;
    1840             : 
    1841       13318 :     return HEIM_ERR_PA_CONTINUE_NEEDED;
    1842             : }
    1843             : 
    1844             : static void
    1845       22092 : enc_ts_release(void *pa_ctx)
    1846             : {
    1847       22092 :     struct enc_ts_context *pactx = (struct enc_ts_context *)pa_ctx;
    1848             : 
    1849       22092 :     if (pactx->user)
    1850       22092 :         krb5_free_principal(NULL, pactx->user);
    1851       22092 : }
    1852             : 
    1853             : static krb5_error_code
    1854       36382 : pa_pac_step(krb5_context context, krb5_init_creds_context ctx, void *pa_ctx, PA_DATA *pa, const AS_REQ *a,
    1855             :             const AS_REP *rep, METHOD_DATA *in_md, METHOD_DATA *out_md)
    1856             : {
    1857       36382 :     size_t len = 0, length;
    1858        1170 :     krb5_error_code ret;
    1859        1170 :     PA_PAC_REQUEST req;
    1860        1170 :     void *buf;
    1861             : 
    1862       36382 :     switch (ctx->req_pac) {
    1863       34357 :     case KRB5_INIT_CREDS_TRISTATE_UNSET:
    1864       34357 :         return 0; /* don't bother */
    1865         855 :     case KRB5_INIT_CREDS_TRISTATE_TRUE:
    1866         855 :         req.include_pac = 1;
    1867         855 :         break;
    1868           0 :     case KRB5_INIT_CREDS_TRISTATE_FALSE:
    1869           0 :         req.include_pac = 0;
    1870             :     }
    1871             : 
    1872         855 :     ASN1_MALLOC_ENCODE(PA_PAC_REQUEST, buf, length,
    1873             :                        &req, &len, ret);
    1874         855 :     if (ret)
    1875           0 :         return ret;
    1876         855 :     heim_assert(len == length, "internal error in ASN.1 encoder");
    1877             : 
    1878         855 :     ret = krb5_padata_add(context, out_md, KRB5_PADATA_PA_PAC_REQUEST, buf, len);
    1879         855 :     if (ret)
    1880           0 :         free(buf);
    1881             : 
    1882         855 :     return 0;
    1883             : }
    1884             : 
    1885             : static krb5_error_code
    1886       36382 : pa_enc_pa_rep_step(krb5_context context, krb5_init_creds_context ctx, void *pa_ctx, PA_DATA *pa, const AS_REQ *a,
    1887             :                    const AS_REP *rep, METHOD_DATA *in_md, METHOD_DATA *out_md)
    1888             : {
    1889       36382 :     if (ctx->runflags.allow_enc_pa_rep)
    1890       36382 :         return krb5_padata_add(context, out_md, KRB5_PADATA_REQ_ENC_PA_REP, NULL, 0);
    1891             : 
    1892           0 :     return 0;
    1893             : }
    1894             : 
    1895             : static krb5_error_code
    1896       36382 : pa_fx_cookie_step(krb5_context context,
    1897             :                   krb5_init_creds_context ctx,
    1898             :                   void *pa_ctx,
    1899             :                   PA_DATA *pa,
    1900             :                   const AS_REQ *a,
    1901             :                   const AS_REP *rep,
    1902             :                   METHOD_DATA *in_md,
    1903             :                   METHOD_DATA *out_md)
    1904             : {
    1905        1170 :     krb5_error_code ret;
    1906        1170 :     void *cookie;
    1907        1170 :     PA_DATA *pad;
    1908       36382 :     int idx = 0;
    1909             : 
    1910       36382 :     pad = krb5_find_padata(in_md->val, in_md->len, KRB5_PADATA_FX_COOKIE, &idx);
    1911       36382 :     if (pad == NULL) {
    1912             :         /*
    1913             :          * RFC 6113 5.4.3: PA-FX-COOKIE MUST be included if the KDC
    1914             :          * expects at least one more message from the client.
    1915             :          */
    1916       36382 :         if (ctx->error.error_code == KRB5_KDC_ERR_MORE_PREAUTH_DATA_REQUIRED)
    1917           0 :             return KRB5_PREAUTH_FAILED;
    1918             :         else
    1919       36382 :             return 0;
    1920             :     }
    1921             : 
    1922           0 :     cookie = malloc(pad->padata_value.length);
    1923           0 :     if (cookie == NULL)
    1924           0 :         return krb5_enomem(context);
    1925             : 
    1926           0 :     memcpy(cookie, pad->padata_value.data, pad->padata_value.length);
    1927             : 
    1928           0 :     ret = krb5_padata_add(context, out_md, KRB5_PADATA_FX_COOKIE,
    1929             :                           cookie, pad->padata_value.length);
    1930           0 :     if (ret)
    1931           0 :         free(cookie);
    1932             :     else
    1933           0 :         _krb5_debug(context, 5, "Mirrored FX-COOKIE to KDC");
    1934             : 
    1935           0 :     return ret;
    1936             : }
    1937             : 
    1938             : typedef struct pa_info_data *(*pa_salt_info_f)(krb5_context, const krb5_principal, const AS_REQ *, struct pa_info_data *, heim_octet_string *);
    1939             : typedef krb5_error_code (*pa_configure_f)(krb5_context, krb5_init_creds_context, void *);
    1940             : typedef krb5_error_code (*pa_restart_f)(krb5_context, krb5_init_creds_context, void *);
    1941             : typedef krb5_error_code (*pa_step_f)(krb5_context, krb5_init_creds_context, void *, PA_DATA *, const AS_REQ *, const AS_REP *, METHOD_DATA *, METHOD_DATA *);
    1942             : typedef void            (*pa_release_f)(void *);
    1943             : 
    1944             : static const struct patype {
    1945             :     int type;
    1946             :     const char *name;
    1947             :     int flags;
    1948             : #define PA_F_ANNOUNCE           1
    1949             : #define PA_F_CONFIG             2
    1950             : #define PA_F_FAST               4 /* available inside FAST */
    1951             : #define PA_F_NOT_FAST           8 /* only available without FAST */
    1952             :     size_t pa_ctx_size;
    1953             :     pa_salt_info_f salt_info;
    1954             :     /**
    1955             :      * Return 0 if the PA-mechanism is available and optionally set pa_ctx pointer to non-NULL.
    1956             :      */
    1957             :     pa_configure_f configure;
    1958             :     /**
    1959             :      * Return 0 if the PA-mechanism can be restarted (time skew, referrals, etc)
    1960             :      */
    1961             :     pa_restart_f restart;
    1962             :     /**
    1963             :      * Return 0 if the when complete, HEIM_ERR_PA_CONTINUE_NEEDED if more steps are require
    1964             :      */
    1965             :     pa_step_f step;
    1966             :     pa_release_f release;
    1967             : } patypes[] = {
    1968             :     {
    1969             :         KRB5_PADATA_PK_AS_REP,
    1970             :         "PKINIT(IETF)",
    1971             :         PA_F_FAST | PA_F_NOT_FAST,
    1972             :         sizeof(struct pkinit_context),
    1973             :         NULL,
    1974             :         pkinit_configure_ietf,
    1975             :         NULL,
    1976             :         pkinit_step,
    1977             :         pkinit_release
    1978             :     },
    1979             :     {
    1980             :         KRB5_PADATA_PK_AS_REP_19,
    1981             :         "PKINIT(win)",
    1982             :         PA_F_FAST | PA_F_NOT_FAST,
    1983             :         sizeof(struct pkinit_context),
    1984             :         NULL,
    1985             :         pkinit_configure_win,
    1986             :         NULL,
    1987             :         pkinit_step,
    1988             :         pkinit_release
    1989             :     },
    1990             :     {
    1991             :         KRB5_PADATA_GSS,
    1992             :         "GSS",
    1993             :         PA_F_FAST | PA_F_NOT_FAST,
    1994             :         sizeof(struct pa_gss_context),
    1995             :         NULL,
    1996             :         pa_gss_configure,
    1997             :         pa_gss_restart,
    1998             :         pa_gss_step,
    1999             :         pa_gss_release
    2000             :     },
    2001             :     {
    2002             :         KRB5_PADATA_ENCRYPTED_CHALLENGE,
    2003             :         "ENCRYPTED_CHALLENGE",
    2004             :         PA_F_FAST,
    2005             :         0,
    2006             :         NULL,
    2007             :         NULL,
    2008             :         NULL,
    2009             :         enc_chal_step,
    2010             :         NULL
    2011             :     },
    2012             :     {
    2013             :         KRB5_PADATA_ENC_TIMESTAMP,
    2014             :         "ENCRYPTED_TIMESTAMP",
    2015             :         PA_F_NOT_FAST,
    2016             :         sizeof(struct enc_ts_context),
    2017             :         NULL,
    2018             :         NULL,
    2019             :         enc_ts_restart,
    2020             :         enc_ts_step,
    2021             :         enc_ts_release
    2022             :     },
    2023             :     {
    2024             :         KRB5_PADATA_PA_PAC_REQUEST,
    2025             :         "PA_PAC_REQUEST",
    2026             :         PA_F_CONFIG,
    2027             :         0,
    2028             :         NULL,
    2029             :         NULL,
    2030             :         NULL,
    2031             :         pa_pac_step,
    2032             :         NULL
    2033             :     },
    2034             :     {
    2035             :         KRB5_PADATA_REQ_ENC_PA_REP,
    2036             :         "REQ-ENC-PA-REP",
    2037             :         PA_F_CONFIG,
    2038             :         0,
    2039             :         NULL,
    2040             :         NULL,
    2041             :         NULL,
    2042             :         pa_enc_pa_rep_step,
    2043             :         NULL
    2044             :     },
    2045             :     {
    2046             :         KRB5_PADATA_FX_COOKIE,
    2047             :         "FX-COOKIE",
    2048             :         PA_F_CONFIG,
    2049             :         0,
    2050             :         NULL,
    2051             :         NULL,
    2052             :         NULL,
    2053             :         pa_fx_cookie_step,
    2054             :         NULL
    2055             :     },
    2056             : #define patype_salt(n, f) { KRB5_PADATA_##n, #n, 0, 0, f, NULL, NULL, NULL, NULL }
    2057             :     patype_salt(ETYPE_INFO2, pa_etype_info2),
    2058             :     patype_salt(ETYPE_INFO, pa_etype_info),
    2059             :     patype_salt(PW_SALT, pa_pw_or_afs3_salt),
    2060             :     patype_salt(AFS3_SALT, pa_pw_or_afs3_salt),
    2061             : #undef patype_salt
    2062             :     /* below are just for pretty printing */
    2063             : #define patype_info(n) { KRB5_PADATA_##n, #n, 0, 0, NULL, NULL, NULL, NULL, NULL }
    2064             :     patype_info(AUTHENTICATION_SET),
    2065             :     patype_info(AUTH_SET_SELECTED),
    2066             :     patype_info(FX_FAST),
    2067             :     patype_info(FX_ERROR),
    2068             :     patype_info(PKINIT_KX),
    2069             :     patype_info(PK_AS_REQ)
    2070             : #undef patype_info
    2071             : };
    2072             : 
    2073             : static const char *
    2074           6 : get_pa_type_name(int type)
    2075             : {
    2076           0 :     size_t n;
    2077          58 :     for (n = 0; n < sizeof(patypes)/sizeof(patypes[0]); n++)
    2078          58 :         if (type == patypes[n].type)
    2079           6 :             return patypes[n].name;
    2080           0 :     return "unknown";
    2081             : }
    2082             : 
    2083             : /*
    2084             :  *
    2085             :  */
    2086             : 
    2087             : struct pa_auth_mech {
    2088             :     const struct patype *patype;
    2089             :     struct pa_auth_mech *next; /* when doing authentication sets */
    2090             :     char pactx[1];
    2091             : };
    2092             : 
    2093             : /*
    2094             :  *
    2095             :  */
    2096             : 
    2097             : static struct pa_info_data *
    2098       62931 : process_pa_info(krb5_context context,
    2099             :                 const krb5_principal client,
    2100             :                 const AS_REQ *asreq,
    2101             :                 struct pa_info_data *paid,
    2102             :                 METHOD_DATA *md)
    2103             : {
    2104       62931 :     struct pa_info_data *p = NULL;
    2105        2334 :     PA_DATA *pa;
    2106        2334 :     size_t i;
    2107             : 
    2108       62931 :     if (md == NULL)
    2109         596 :         return NULL;
    2110             : 
    2111      824602 :     for (i = 0; p == NULL && i < sizeof(patypes)/sizeof(patypes[0]); i++) {
    2112      762273 :         int idx = 0;
    2113             : 
    2114      762273 :         if (patypes[i].salt_info == NULL)
    2115      722312 :             continue;
    2116             : 
    2117      129433 :         pa = krb5_find_padata(md->val, md->len, patypes[i].type, &idx);
    2118      129433 :         if (pa == NULL)
    2119       89472 :             continue;
    2120             : 
    2121       39961 :         paid->salt.salttype = (krb5_salttype)patypes[i].type;
    2122       39961 :         p = patypes[i].salt_info(context, client, asreq, paid, &pa->padata_value);
    2123             :     }
    2124       60001 :     return p;
    2125             : }
    2126             : 
    2127             : static krb5_error_code
    2128       36382 : pa_announce(krb5_context context,
    2129             :             int types,
    2130             :             krb5_init_creds_context ctx,
    2131             :             METHOD_DATA *in_md,
    2132             :             METHOD_DATA *out_md)
    2133             : {
    2134       36382 :     krb5_error_code ret = 0;
    2135        1170 :     size_t n;
    2136             : 
    2137      691258 :     for (n = 0; ret == 0 && n < sizeof(patypes)/sizeof(patypes[0]); n++) {
    2138      654876 :         if ((patypes[n].flags & types) == 0)
    2139      545730 :             continue;
    2140             : 
    2141      109146 :         if (patypes[n].step)
    2142      109146 :             patypes[n].step(context, ctx, NULL, NULL, NULL, NULL, in_md, out_md);
    2143             :         else
    2144           0 :             ret = krb5_padata_add(context, out_md, patypes[n].type, NULL, 0);
    2145             :     }
    2146       36382 :     return ret;
    2147             : }
    2148             : 
    2149             : 
    2150             : static void HEIM_CALLCONV
    2151       44432 : mech_dealloc(void *ctx)
    2152             : {
    2153       44432 :     struct pa_auth_mech *pa_mech = ctx;
    2154       44432 :     if (pa_mech->patype->release)
    2155       22340 :         pa_mech->patype->release((void *)&pa_mech->pactx[0]);
    2156       44432 : }
    2157             : 
    2158             : static const struct heim_type_data pa_auth_mech_object = {
    2159             :     HEIM_TID_PA_AUTH_MECH,
    2160             :     "heim-pa-mech-context",
    2161             :     NULL,
    2162             :     mech_dealloc,
    2163             :     NULL,
    2164             :     NULL,
    2165             :     NULL,
    2166             :     NULL
    2167             : };
    2168             : 
    2169             : static struct pa_auth_mech *
    2170       44432 : pa_mech_create(krb5_context context, krb5_init_creds_context ctx, int pa_type)
    2171             : {
    2172        1170 :     struct pa_auth_mech *pa_mech;
    2173       44432 :     const struct patype *patype = NULL;
    2174        1170 :     size_t n;
    2175             : 
    2176      243632 :     for (n = 0; patype == NULL && n < sizeof(patypes)/sizeof(patypes[0]); n++) {
    2177      199200 :         if (patypes[n].type == pa_type)
    2178       44432 :             patype = &patypes[n];
    2179             :     }
    2180       44432 :     if (patype == NULL)
    2181           0 :         return NULL;
    2182             : 
    2183       44432 :     pa_mech = _heim_alloc_object(&pa_auth_mech_object, sizeof(*pa_mech) - 1 + patype->pa_ctx_size);
    2184       44432 :     if (pa_mech == NULL)
    2185           0 :         return NULL;
    2186             : 
    2187       44432 :     pa_mech->patype = patype;
    2188             : 
    2189       44432 :     if (pa_mech->patype->configure) {
    2190           0 :         krb5_error_code ret;
    2191             : 
    2192         248 :         ret = pa_mech->patype->configure(context, ctx, &pa_mech->pactx[0]);
    2193         248 :         if (ret) {
    2194           0 :             heim_release(pa_mech);
    2195           0 :             return NULL;
    2196             :         }
    2197             :     }
    2198             : 
    2199       44432 :     _krb5_debug(context, 5, "Adding PA mech: %s", patype->name);
    2200             : 
    2201       44432 :     return pa_mech;
    2202             : }
    2203             : 
    2204             : static void
    2205       44432 : pa_mech_add(krb5_context context, krb5_init_creds_context ctx, int pa_type)
    2206             : {
    2207        1170 :     struct pa_auth_mech *mech;
    2208             : 
    2209       44432 :     mech = pa_mech_create(context, ctx, pa_type);
    2210       44432 :     if (mech) {
    2211       44432 :         heim_array_append_value(ctx->available_pa_mechs, mech);
    2212       44432 :         heim_release(mech);
    2213             :     }
    2214       44432 : }
    2215             : 
    2216             : static krb5_error_code
    2217       22216 : pa_configure(krb5_context context,
    2218             :              krb5_init_creds_context ctx,
    2219             :              METHOD_DATA *in_md)
    2220             : {
    2221       22216 :     ctx->available_pa_mechs = heim_array_create();
    2222             : 
    2223       22216 :     if (ctx->gss_init_ctx) {
    2224           0 :         pa_mech_add(context, ctx, KRB5_PADATA_GSS);
    2225       22216 :     } else if (ctx->pk_init_ctx) {
    2226         124 :         pa_mech_add(context, ctx, KRB5_PADATA_PK_AS_REP);
    2227         124 :         pa_mech_add(context, ctx, KRB5_PADATA_PK_AS_REP_19);
    2228       22092 :     } else if (ctx->keyproc || ctx->keyseed || ctx->prompter) {
    2229       22092 :         pa_mech_add(context, ctx, KRB5_PADATA_ENCRYPTED_CHALLENGE);
    2230       22092 :         pa_mech_add(context, ctx, KRB5_PADATA_ENC_TIMESTAMP);
    2231             :     }
    2232             :     /* XXX setup context based on KDC reply */
    2233             : 
    2234       22216 :     return 0;
    2235             : }
    2236             : 
    2237             : static krb5_error_code
    2238         263 : pa_restart(krb5_context context,
    2239             :            krb5_init_creds_context ctx)
    2240             : {
    2241         263 :     krb5_error_code ret = HEIM_ERR_PA_CANT_CONTINUE;
    2242             : 
    2243         263 :     if (ctx->pa_mech && ctx->pa_mech->patype->restart)
    2244         263 :         ret = ctx->pa_mech->patype->restart(context, ctx, (void *)&ctx->pa_mech->pactx[0]);
    2245             : 
    2246         263 :     return ret;
    2247             : }
    2248             : 
    2249             : 
    2250             : static krb5_error_code
    2251       50026 : pa_step(krb5_context context,
    2252             :         krb5_init_creds_context ctx,
    2253             :         const AS_REQ *a,
    2254             :         const AS_REP *rep,
    2255             :         METHOD_DATA *in_md,
    2256             :         METHOD_DATA *out_md)
    2257             : {
    2258        1755 :     krb5_error_code ret;
    2259       50026 :     PA_DATA *pa = NULL;
    2260        2340 :     int idx;
    2261             : 
    2262       48271 :  next:
    2263        2340 :     do {
    2264       72118 :         if (ctx->pa_mech == NULL) {
    2265       44308 :             size_t len = heim_array_get_length(ctx->available_pa_mechs);
    2266       44308 :             if (len == 0) {
    2267           0 :                 _krb5_debug(context, 0, "no more available_pa_mechs to try");
    2268           0 :                 return HEIM_ERR_NO_MORE_PA_MECHS;
    2269             :             }
    2270             : 
    2271       44308 :             ctx->pa_mech = heim_array_copy_value(ctx->available_pa_mechs, 0);
    2272       44308 :             heim_array_delete_value(ctx->available_pa_mechs, 0);
    2273             :         }
    2274             : 
    2275       72118 :         if (ctx->fast_state.armor_crypto) {
    2276           0 :             if ((ctx->pa_mech->patype->flags & PA_F_FAST) == 0) {
    2277           0 :                 _krb5_debug(context, 0, "pa-mech %s dropped under FAST (not supported)",
    2278           0 :                             ctx->pa_mech->patype->name);
    2279           0 :                 heim_release(ctx->pa_mech);
    2280           0 :                 ctx->pa_mech = NULL;
    2281           0 :                 continue;
    2282             :             }
    2283             :         } else {
    2284       72118 :             if ((ctx->pa_mech->patype->flags & PA_F_NOT_FAST) == 0) {
    2285       22092 :                 _krb5_debug(context, 0, "dropped pa-mech %s since not running under FAST",
    2286       22092 :                             ctx->pa_mech->patype->name);
    2287       22092 :                 heim_release(ctx->pa_mech);
    2288       22092 :                 ctx->pa_mech = NULL;
    2289       22092 :                 continue;
    2290             :             }
    2291             :         }
    2292             : 
    2293       50026 :         _krb5_debug(context, 0, "pa-mech trying: %s, searching for %d",
    2294       50026 :                     ctx->pa_mech->patype->name, ctx->pa_mech->patype->type);
    2295             : 
    2296       50026 :         idx = 0;
    2297       50026 :         if (in_md)
    2298       49424 :             pa = krb5_find_padata(in_md->val, in_md->len, ctx->pa_mech->patype->type, &idx);
    2299             :         else
    2300         596 :             pa = NULL;
    2301             : 
    2302       72118 :     } while (ctx->pa_mech == NULL);
    2303             : 
    2304       50026 :     _krb5_debug(context, 5, "Stepping pa-mech: %s", ctx->pa_mech->patype->name);
    2305             : 
    2306       50026 :     ret = ctx->pa_mech->patype->step(context, ctx, (void *)&ctx->pa_mech->pactx[0], pa, a, rep, in_md, out_md);
    2307       50026 :     _krb5_debug(context, 10, "PA type %s returned %d", ctx->pa_mech->patype->name, ret);
    2308       50026 :     if (ret == 0) {
    2309       13644 :         struct pa_auth_mech *next_pa = ctx->pa_mech->next;
    2310             : 
    2311       13644 :         if (next_pa) {
    2312           0 :             _krb5_debug(context, 5, "Next PA type in set is: %s",
    2313           0 :                          next_pa->patype->name);
    2314           0 :             ret = HEIM_ERR_PA_CONTINUE_NEEDED;
    2315       13644 :         } else if (rep == NULL) {
    2316           0 :             _krb5_debug(context, 5, "PA %s done, but no ticket in sight!!!",
    2317           0 :                          ctx->pa_mech->patype->name);
    2318           0 :             ret = HEIM_ERR_PA_CANT_CONTINUE;
    2319             :         } else {
    2320       13644 :             ctx->pa_used = ctx->pa_mech->patype->name;
    2321             :         }
    2322             : 
    2323       13644 :         heim_retain(next_pa);
    2324       13644 :         heim_release(ctx->pa_mech);
    2325       13644 :         ctx->pa_mech = next_pa;
    2326             :     }
    2327             : 
    2328       50026 :     if (ret == HEIM_ERR_PA_CANT_CONTINUE) {
    2329           0 :         if (ctx->pa_mech) {
    2330           0 :             _krb5_debug(context, 5, "Dropping PA type %s", ctx->pa_mech->patype->name);
    2331           0 :             heim_release(ctx->pa_mech);
    2332           0 :             ctx->pa_mech = NULL;
    2333             :         }
    2334           0 :         goto next;
    2335       50026 :     } else if (ret == HEIM_ERR_PA_CONTINUE_NEEDED) {
    2336       36382 :         _krb5_debug(context, 5, "Continue needed for %s", ctx->pa_mech->patype->name);
    2337       13644 :     } else if (ret != 0) {
    2338           0 :         _krb5_debug(context, 5, "Other error from mech %s: %d", ctx->pa_mech->patype->name, ret);
    2339           0 :         heim_release(ctx->pa_mech);
    2340           0 :         ctx->pa_mech = NULL;
    2341             :     }
    2342             : 
    2343       48271 :     return ret;
    2344             : }
    2345             : 
    2346             : static void
    2347       49424 : log_kdc_pa_types(krb5_context context, METHOD_DATA *in_md)
    2348             : {
    2349       49424 :     if (_krb5_have_debug(context, 5)) {
    2350           0 :         unsigned i;
    2351           4 :         _krb5_debug(context, 5, "KDC sent %d patypes", in_md->len);
    2352          10 :         for (i = 0; i < in_md->len; i++)
    2353          12 :             _krb5_debug(context, 5, "KDC sent PA-DATA type: %d (%s)",
    2354           6 :                          in_md->val[i].padata_type,
    2355           6 :                          get_pa_type_name(in_md->val[i].padata_type));
    2356             :     }
    2357       49424 : }
    2358             : 
    2359             : /*
    2360             :  * Assumes caller always will free `out_md', even on error.
    2361             :  */
    2362             : 
    2363             : static krb5_error_code
    2364       36382 : process_pa_data_to_md(krb5_context context,
    2365             :                       const krb5_creds *creds,
    2366             :                       const AS_REQ *a,
    2367             :                       krb5_init_creds_context ctx,
    2368             :                       METHOD_DATA *in_md,
    2369             :                       METHOD_DATA **out_md)
    2370             : {
    2371        1170 :     krb5_error_code ret;
    2372             : 
    2373       36382 :     ALLOC(*out_md, 1);
    2374       36382 :     if (*out_md == NULL) {
    2375           0 :         return krb5_enomem(context);
    2376             :     }
    2377       36382 :     (*out_md)->len = 0;
    2378       36382 :     (*out_md)->val = NULL;
    2379             : 
    2380       36382 :     log_kdc_pa_types(context, in_md);
    2381             : 
    2382       36382 :     ret = pa_step(context, ctx, a, NULL, in_md, *out_md);
    2383       36382 :     if (ret == HEIM_ERR_PA_CONTINUE_NEEDED) {
    2384       36382 :         _krb5_debug(context, 0, "pamech need more stepping");
    2385           0 :     } else if (ret == 0) {
    2386           0 :         _krb5_debug(context, 0, "pamech done step");
    2387             :     } else {
    2388           0 :         return ret;
    2389             :     }
    2390             : 
    2391             :     /*
    2392             :      * Send announcement (what we support) and configuration (user
    2393             :      * introduced behavior change)
    2394             :      */
    2395       36382 :     ret = pa_announce(context, PA_F_ANNOUNCE|PA_F_CONFIG, ctx, in_md, *out_md);
    2396             : 
    2397             :     /*
    2398             :      *
    2399             :      */
    2400             : 
    2401       36382 :     if ((*out_md)->len == 0) {
    2402           0 :         free(*out_md);
    2403           0 :         *out_md = NULL;
    2404             :     }
    2405             : 
    2406       35212 :     return ret;
    2407             : }
    2408             : 
    2409             : static krb5_error_code
    2410       13644 : process_pa_data_to_key(krb5_context context,
    2411             :                        krb5_init_creds_context ctx,
    2412             :                        krb5_creds *creds,
    2413             :                        AS_REQ *a,
    2414             :                        AS_REP *rep,
    2415             :                        krb5_keyblock **key)
    2416             : {
    2417       13644 :     struct pa_info_data paid, *ppaid = NULL;
    2418         585 :     krb5_error_code ret;
    2419       13644 :     krb5_enctype etype = rep->enc_part.etype;
    2420             : 
    2421       13644 :     memset(&paid, 0, sizeof(paid));
    2422             : 
    2423       13644 :     if (rep->padata)
    2424       13042 :         log_kdc_pa_types(context, rep->padata);
    2425             : 
    2426       13644 :     if (rep->padata) {
    2427       13042 :         paid.etype = etype;
    2428       13042 :         ppaid = process_pa_info(context, creds->client, a, &paid,
    2429             :                                 rep->padata);
    2430             :     }
    2431       13638 :     if (ppaid == NULL) {
    2432         615 :         if (ctx->paid.etype == KRB5_ENCTYPE_NULL) {
    2433          13 :             ctx->paid.etype = etype;
    2434          13 :             ctx->paid.s2kparams = NULL;
    2435          13 :             ret = krb5_get_pw_salt (context, creds->client, &ctx->paid.salt);
    2436          13 :             if (ret)
    2437           0 :                 return ret;
    2438             :         }
    2439             :     }
    2440             : 
    2441       13644 :     ret = pa_step(context, ctx, a, rep, rep->padata, NULL);
    2442       13644 :     if (ret == HEIM_ERR_PA_CONTINUE_NEEDED) {
    2443           0 :         _krb5_debug(context, 0, "In final stretch and pa require more stepping ?");
    2444           0 :         return ret;
    2445       13644 :     } else if (ret == 0) {
    2446       13644 :         _krb5_debug(context, 0, "final pamech done step");
    2447       13644 :         goto out;
    2448             :     } else {
    2449           0 :         return ret;
    2450             :     }
    2451       13644 :  out:
    2452       13644 :     free_paid(context, &paid);
    2453       13644 :     return ret;
    2454             : }
    2455             : 
    2456             : /*
    2457             :  *
    2458             :  */
    2459             : 
    2460             : static krb5_error_code
    2461       22216 : capture_lkdc_domain(krb5_context context,
    2462             :                     krb5_init_creds_context ctx)
    2463             : {
    2464         585 :     size_t len;
    2465             : 
    2466       22216 :     len = strlen(_krb5_wellknown_lkdc);
    2467             : 
    2468       22216 :     if (ctx->kdc_hostname != NULL ||
    2469       22216 :         strncmp(ctx->cred.client->realm, _krb5_wellknown_lkdc, len) != 0 ||
    2470           0 :         ctx->cred.client->realm[len] != ':')
    2471       21631 :         return 0;
    2472             : 
    2473           0 :     ctx->kdc_hostname = strdup(&ctx->cred.client->realm[len + 1]);
    2474             : 
    2475           0 :     _krb5_debug(context, 5, "krb5_get_init_creds: setting LKDC hostname to: %s",
    2476             :                 ctx->kdc_hostname);
    2477           0 :     return 0;
    2478             : }
    2479             : 
    2480             : /**
    2481             :  * Start a new context to get a new initial credential.
    2482             :  *
    2483             :  * @param context A Kerberos 5 context.
    2484             :  * @param client The Kerberos principal to get the credential for, if
    2485             :  *     NULL is given, the default principal is used as determined by
    2486             :  *     krb5_get_default_principal().
    2487             :  * @param prompter
    2488             :  * @param prompter_data
    2489             :  * @param start_time the time the ticket should start to be valid or 0 for now.
    2490             :  * @param options a options structure, can be NULL for default options.
    2491             :  * @param rctx A new allocated free with krb5_init_creds_free().
    2492             :  *
    2493             :  * @return 0 for success or an Kerberos 5 error code, see krb5_get_error_message().
    2494             :  *
    2495             :  * @ingroup krb5_credential
    2496             :  */
    2497             : 
    2498             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    2499       22216 : krb5_init_creds_init(krb5_context context,
    2500             :                      krb5_principal client,
    2501             :                      krb5_prompter_fct prompter,
    2502             :                      void *prompter_data,
    2503             :                      krb5_deltat start_time,
    2504             :                      krb5_get_init_creds_opt *options,
    2505             :                      krb5_init_creds_context *rctx)
    2506             : {
    2507         585 :     krb5_init_creds_context ctx;
    2508         585 :     krb5_error_code ret;
    2509             : 
    2510       22216 :     *rctx = NULL;
    2511             : 
    2512       22216 :     ctx = calloc(1, sizeof(*ctx));
    2513       22216 :     if (ctx == NULL)
    2514           0 :         return krb5_enomem(context);
    2515             : 
    2516       22216 :     ret = get_init_creds_common(context, client, prompter, prompter_data,
    2517             :                                  start_time, options, ctx);
    2518       22216 :     if (ret) {
    2519           0 :         free(ctx);
    2520           0 :         return ret;
    2521             :     }
    2522             : 
    2523             :     /* Set a new nonce. */
    2524             :     /* FIXME should generate a new nonce for each AS-REQ */
    2525       22216 :     krb5_generate_random_block (&ctx->nonce, sizeof(ctx->nonce));
    2526       22216 :     ctx->nonce &= 0x7fffffff;
    2527             :     /* XXX these just needs to be the same when using Windows PK-INIT */
    2528       22216 :     ctx->pk_nonce = ctx->nonce;
    2529             : 
    2530       22216 :     ctx->prompter = prompter;
    2531       22216 :     ctx->prompter_data = prompter_data;
    2532             : 
    2533             :     /* pick up hostname from LKDC realm name */
    2534       22216 :     ret = capture_lkdc_domain(context, ctx);
    2535       22216 :     if (ret) {
    2536           0 :         free_init_creds_ctx(context, ctx);
    2537           0 :         return ret;
    2538             :     }
    2539             : 
    2540       22216 :     ctx->runflags.allow_enc_pa_rep = 1;
    2541             : 
    2542       22216 :     ctx->fast_state.flags |= KRB5_FAST_AS_REQ;
    2543             : 
    2544       22216 :     *rctx = ctx;
    2545             : 
    2546       22216 :     return ret;
    2547             : }
    2548             : 
    2549             : /**
    2550             :  * Set the KDC hostname for the initial request, it will not be
    2551             :  * considered in referrals to another KDC.
    2552             :  *
    2553             :  * @param context a Kerberos 5 context.
    2554             :  * @param ctx a krb5_init_creds_context context.
    2555             :  * @param hostname the hostname for the KDC of realm
    2556             :  *
    2557             :  * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message().
    2558             :  * @ingroup krb5_credential
    2559             :  */
    2560             : 
    2561             : krb5_error_code KRB5_LIB_FUNCTION
    2562           0 : krb5_init_creds_set_kdc_hostname(krb5_context context,
    2563             :                                  krb5_init_creds_context ctx,
    2564             :                                  const char *hostname)
    2565             : {
    2566           0 :     if (ctx->kdc_hostname)
    2567           0 :         free(ctx->kdc_hostname);
    2568           0 :     ctx->kdc_hostname = strdup(hostname);
    2569           0 :     if (ctx->kdc_hostname == NULL)
    2570           0 :         return krb5_enomem(context);
    2571           0 :     return 0;
    2572             : }
    2573             : 
    2574             : /**
    2575             :  * Set the sitename for the request
    2576             :  *
    2577             :  */
    2578             : 
    2579             : krb5_error_code KRB5_LIB_FUNCTION
    2580           0 : krb5_init_creds_set_sitename(krb5_context context,
    2581             :                              krb5_init_creds_context ctx,
    2582             :                              const char *sitename)
    2583             : {
    2584           0 :     if (ctx->sitename)
    2585           0 :         free(ctx->sitename);
    2586           0 :     ctx->sitename = strdup(sitename);
    2587           0 :     if (ctx->sitename == NULL)
    2588           0 :         return krb5_enomem(context);
    2589           0 :     return 0;
    2590             : }
    2591             : 
    2592             : /**
    2593             :  * Sets the service that the is requested. This call is only neede for
    2594             :  * special initial tickets, by default the a krbtgt is fetched in the default realm.
    2595             :  *
    2596             :  * @param context a Kerberos 5 context.
    2597             :  * @param ctx a krb5_init_creds_context context.
    2598             :  * @param service the service given as a string, for example
    2599             :  *        "kadmind/admin". If NULL, the default krbtgt in the clients
    2600             :  *        realm is set.
    2601             :  *
    2602             :  * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message().
    2603             :  * @ingroup krb5_credential
    2604             :  */
    2605             : 
    2606             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    2607       44210 : krb5_init_creds_set_service(krb5_context context,
    2608             :                             krb5_init_creds_context ctx,
    2609             :                             const char *service)
    2610             : {
    2611        1170 :     krb5_const_realm client_realm;
    2612        1170 :     krb5_principal principal;
    2613        1170 :     krb5_error_code ret;
    2614             : 
    2615       44210 :     client_realm = krb5_principal_get_realm (context, ctx->cred.client);
    2616             : 
    2617       44210 :     if (service) {
    2618          19 :         ret = krb5_parse_name (context, service, &principal);
    2619          19 :         if (ret)
    2620           0 :             return ret;
    2621          19 :         ret = krb5_principal_set_realm (context, principal, client_realm);
    2622          19 :         if (ret) {
    2623           0 :             krb5_free_principal(context, principal);
    2624           0 :             return ret;
    2625             :         }
    2626             :     } else {
    2627       44191 :         ret = krb5_make_principal(context, &principal,
    2628             :                                   client_realm, KRB5_TGS_NAME, client_realm,
    2629             :                                   NULL);
    2630       44191 :         if (ret)
    2631           0 :             return ret;
    2632             :     }
    2633             : 
    2634             :     /*
    2635             :      * This is for Windows RODC that are picky about what name type
    2636             :      * the server principal have, and the really strange part is that
    2637             :      * they are picky about the AS-REQ name type and not the TGS-REQ
    2638             :      * later. Oh well.
    2639             :      */
    2640             : 
    2641       44210 :     if (krb5_principal_is_krbtgt(context, principal))
    2642       44194 :         krb5_principal_set_type(context, principal, KRB5_NT_SRV_INST);
    2643             : 
    2644       44210 :     krb5_free_principal(context, ctx->cred.server);
    2645       44210 :     ctx->cred.server = principal;
    2646             : 
    2647       44210 :     return 0;
    2648             : }
    2649             : 
    2650             : /**
    2651             :  * Sets the password that will use for the request.
    2652             :  *
    2653             :  * @param context a Kerberos 5 context.
    2654             :  * @param ctx ctx krb5_init_creds_context context.
    2655             :  * @param password the password to use.
    2656             :  *
    2657             :  * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message().
    2658             :  * @ingroup krb5_credential
    2659             :  */
    2660             : 
    2661             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    2662       22077 : krb5_init_creds_set_password(krb5_context context,
    2663             :                              krb5_init_creds_context ctx,
    2664             :                              const char *password)
    2665             : {
    2666       22077 :     if (ctx->password) {
    2667           0 :         size_t len;
    2668           4 :         len = strlen(ctx->password);
    2669           4 :         memset_s(ctx->password, len, 0, len);
    2670           4 :         free(ctx->password);
    2671             :     }
    2672       22077 :     if (password) {
    2673       22077 :         ctx->password = strdup(password);
    2674       22077 :         if (ctx->password == NULL)
    2675           0 :             return krb5_enomem(context);
    2676       22077 :         ctx->keyseed = (void *) ctx->password;
    2677             :     } else {
    2678           0 :         ctx->keyseed = NULL;
    2679           0 :         ctx->password = NULL;
    2680             :     }
    2681             : 
    2682       21495 :     return 0;
    2683             : }
    2684             : 
    2685             : static krb5_error_code KRB5_CALLCONV
    2686          14 : keytab_key_proc(krb5_context context, krb5_enctype enctype,
    2687             :                 krb5_const_pointer keyseed,
    2688             :                 krb5_salt salt, krb5_data *s2kparms,
    2689             :                 krb5_keyblock **key)
    2690             : {
    2691          14 :     krb5_keytab_key_proc_args *args  = rk_UNCONST(keyseed);
    2692          14 :     krb5_keytab keytab = args->keytab;
    2693          14 :     krb5_principal principal = args->principal;
    2694           0 :     krb5_error_code ret;
    2695          14 :     krb5_keytab real_keytab = NULL;
    2696           0 :     krb5_keytab_entry entry;
    2697             : 
    2698          14 :     if (keytab == NULL) {
    2699           0 :         ret = krb5_kt_default(context, &real_keytab);
    2700           0 :         if (ret)
    2701           0 :             return ret;
    2702           0 :         keytab = real_keytab;
    2703             :     }
    2704             : 
    2705          14 :     ret = krb5_kt_get_entry (context, keytab, principal, 0, enctype, &entry);
    2706          14 :     if (ret == 0) {
    2707          14 :         ret = krb5_copy_keyblock(context, &entry.keyblock, key);
    2708          14 :         krb5_kt_free_entry(context, &entry);
    2709             :     }
    2710             : 
    2711          14 :     krb5_kt_close(context, real_keytab);
    2712          14 :     return ret;
    2713             : }
    2714             : 
    2715             : 
    2716             : /**
    2717             :  * Set the keytab to use for authentication.
    2718             :  *
    2719             :  * @param context a Kerberos 5 context.
    2720             :  * @param ctx ctx krb5_init_creds_context context.
    2721             :  * @param keytab the keytab to read the key from.
    2722             :  *
    2723             :  * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message().
    2724             :  * @ingroup krb5_credential
    2725             :  */
    2726             : 
    2727             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    2728           7 : krb5_init_creds_set_keytab(krb5_context context,
    2729             :                            krb5_init_creds_context ctx,
    2730             :                            krb5_keytab keytab)
    2731             : {
    2732           0 :     krb5_keytab_key_proc_args *a;
    2733           0 :     krb5_keytab_entry entry;
    2734           0 :     krb5_kt_cursor cursor;
    2735           7 :     krb5_enctype *etypes = NULL;
    2736           0 :     krb5_error_code ret;
    2737           7 :     size_t netypes = 0;
    2738           7 :     int kvno = 0, found = 0;
    2739           0 :     unsigned n;
    2740             : 
    2741           7 :     a = malloc(sizeof(*a));
    2742           7 :     if (a == NULL)
    2743           0 :         return krb5_enomem(context);
    2744             : 
    2745           7 :     a->principal = ctx->cred.client;
    2746           7 :     a->keytab    = keytab;
    2747             : 
    2748           7 :     ctx->keytab_data = a;
    2749           7 :     ctx->keyseed = (void *)a;
    2750           7 :     ctx->keyproc = keytab_key_proc;
    2751             : 
    2752             :     /*
    2753             :      * We need to the KDC what enctypes we support for this keytab,
    2754             :      * esp if the keytab is really a password based entry, then the
    2755             :      * KDC might have more enctypes in the database then what we have
    2756             :      * in the keytab.
    2757             :      */
    2758             : 
    2759           7 :     ret = krb5_kt_start_seq_get(context, keytab, &cursor);
    2760           7 :     if(ret)
    2761           0 :         goto out;
    2762             : 
    2763         111 :     while(krb5_kt_next_entry(context, keytab, &entry, &cursor) == 0){
    2764           0 :         void *ptr;
    2765             : 
    2766         104 :         if (!krb5_principal_compare(context, entry.principal, ctx->cred.client))
    2767          80 :             goto next;
    2768             : 
    2769          24 :         found = 1;
    2770             : 
    2771             :         /* check if we ahve this kvno already */
    2772          24 :         if (entry.vno > kvno) {
    2773             :             /* remove old list of etype */
    2774           7 :             if (etypes)
    2775           0 :                 free(etypes);
    2776           7 :             etypes = NULL;
    2777           7 :             netypes = 0;
    2778           7 :             kvno = entry.vno;
    2779          17 :         } else if (entry.vno != kvno)
    2780           3 :             goto next;
    2781             : 
    2782             :         /* check if enctype is supported */
    2783          21 :         if (krb5_enctype_valid(context, entry.keyblock.keytype) != 0)
    2784           0 :             goto next;
    2785             : 
    2786             :         /*
    2787             :          * If user already provided a enctype list, use that as an
    2788             :          * additonal filter.
    2789             :          */
    2790          21 :         if (ctx->etypes) {
    2791          10 :             for (n = 0; ctx->etypes[n] != KRB5_ENCTYPE_NULL; n++) {
    2792           6 :                 if (ctx->etypes[n] == entry.keyblock.keytype)
    2793           2 :                     break;
    2794             :             }
    2795           6 :             if (ctx->etypes[n] == KRB5_ENCTYPE_NULL)
    2796           4 :                 goto next;
    2797             :         }
    2798             : 
    2799             :         /* add enctype to supported list */
    2800          17 :         ptr = realloc(etypes, sizeof(etypes[0]) * (netypes + 2));
    2801          17 :         if (ptr == NULL) {
    2802           0 :             free(etypes);
    2803           0 :             ret = krb5_enomem(context);
    2804           0 :             goto out;
    2805             :         }
    2806             : 
    2807          17 :         etypes = ptr;
    2808          17 :         etypes[netypes] = entry.keyblock.keytype;
    2809          17 :         etypes[netypes + 1] = ETYPE_NULL;
    2810          17 :         netypes++;
    2811         104 :     next:
    2812         104 :         krb5_kt_free_entry(context, &entry);
    2813             :     }
    2814           7 :     krb5_kt_end_seq_get(context, keytab, &cursor);
    2815             : 
    2816           7 :     if (etypes) {
    2817           7 :         if (ctx->etypes)
    2818           2 :             free(ctx->etypes);
    2819           7 :         ctx->etypes = etypes;
    2820             :     }
    2821             : 
    2822           0 :  out:
    2823           7 :     if (!found) {
    2824           0 :         if (ret == 0)
    2825           0 :             ret = KRB5_KT_NOTFOUND;
    2826           0 :         _krb5_kt_principal_not_found(context, ret, keytab, ctx->cred.client, 0, 0);
    2827             :     }
    2828             : 
    2829           7 :     return ret;
    2830             : }
    2831             : 
    2832             : static krb5_error_code KRB5_CALLCONV
    2833          24 : keyblock_key_proc(krb5_context context, krb5_enctype enctype,
    2834             :                   krb5_const_pointer keyseed,
    2835             :                   krb5_salt salt, krb5_data *s2kparms,
    2836             :                   krb5_keyblock **key)
    2837             : {
    2838          24 :     return krb5_copy_keyblock (context, keyseed, key);
    2839             : }
    2840             : 
    2841             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    2842          12 : krb5_init_creds_set_keyblock(krb5_context context,
    2843             :                              krb5_init_creds_context ctx,
    2844             :                              krb5_keyblock *keyblock)
    2845             : {
    2846          12 :     ctx->keyseed = (void *)keyblock;
    2847          12 :     ctx->keyproc = keyblock_key_proc;
    2848             : 
    2849          12 :     return 0;
    2850             : }
    2851             : 
    2852             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    2853           0 : krb5_init_creds_set_fast_ccache(krb5_context context,
    2854             :                                 krb5_init_creds_context ctx,
    2855             :                                 krb5_ccache fast_ccache)
    2856             : {
    2857           0 :     ctx->fast_state.armor_ccache = fast_ccache;
    2858           0 :     ctx->fast_state.flags |= KRB5_FAST_REQUIRED;
    2859           0 :     ctx->fast_state.flags |= KRB5_FAST_KDC_VERIFIED;
    2860           0 :     return 0;
    2861             : }
    2862             : 
    2863             : static krb5_error_code
    2864       13632 : validate_pkinit_fx(krb5_context context,
    2865             :                    krb5_init_creds_context ctx,
    2866             :                    AS_REP *rep,
    2867             :                    krb5_keyblock *ticket_sessionkey)
    2868             : {
    2869       13632 :     PA_DATA *pa = NULL;
    2870       13632 :     int idx = 0;
    2871             : 
    2872       13632 :     if (rep->padata)
    2873       13032 :         pa = krb5_find_padata(rep->padata->val, rep->padata->len, KRB5_PADATA_PKINIT_KX, &idx);
    2874             : 
    2875       13626 :     if (pa == NULL) {
    2876       13619 :         if (ctx->flags.request_anonymous && ctx->pk_init_ctx) {
    2877             :             /* XXX handle the case where pkinit is not used */
    2878           0 :             krb5_set_error_message(context, KRB5_KDCREP_MODIFIED,
    2879           0 :                                    N_("Requested anonymous with PKINIT and KDC didn't set PKINIT_KX", ""));
    2880           0 :             return KRB5_KDCREP_MODIFIED;
    2881             :         }
    2882             : 
    2883       13034 :         return 0;
    2884             :     }
    2885             : 
    2886          13 :     heim_assert(ctx->fast_state.reply_key != NULL, "must have a reply key at this stage");
    2887             : 
    2888          13 :     return _krb5_pk_kx_confirm(context,
    2889             :                                ctx->pk_init_ctx,
    2890             :                                ctx->fast_state.reply_key,
    2891             :                                ticket_sessionkey,
    2892             :                                pa);
    2893             : }
    2894             : 
    2895             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    2896           0 : krb5_init_creds_set_fast_ap_armor_service(krb5_context context,
    2897             :                                           krb5_init_creds_context ctx,
    2898             :                                           krb5_const_principal armor_service)
    2899             : {
    2900           0 :     krb5_error_code ret;
    2901             : 
    2902           0 :     if (ctx->fast_state.armor_service)
    2903           0 :         krb5_free_principal(context, ctx->fast_state.armor_service);
    2904           0 :     if (armor_service) {
    2905           0 :         ret = krb5_copy_principal(context, armor_service, &ctx->fast_state.armor_service);
    2906           0 :         if (ret)
    2907           0 :             return ret;
    2908             :     } else {
    2909           0 :         ctx->fast_state.armor_service = NULL;
    2910             :     }
    2911           0 :     ctx->fast_state.flags |= KRB5_FAST_AP_ARMOR_SERVICE;
    2912           0 :     return 0;
    2913             : }
    2914             : 
    2915             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    2916           0 : krb5_init_creds_set_fast_anon_pkinit(krb5_context context,
    2917             :                                      krb5_init_creds_context ctx)
    2918             : {
    2919           0 :     if (ctx->fast_state.armor_ccache)
    2920           0 :         return EINVAL;
    2921             : 
    2922           0 :     ctx->fast_state.flags |= KRB5_FAST_REQUIRED;
    2923           0 :     ctx->fast_state.flags |= KRB5_FAST_ANON_PKINIT_ARMOR;
    2924           0 :     return 0;
    2925             : }
    2926             : 
    2927             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    2928         104 : _krb5_init_creds_set_fast_anon_pkinit_optimistic(krb5_context context,
    2929             :                                                  krb5_init_creds_context ctx)
    2930             : {
    2931         104 :     if (ctx->fast_state.armor_ccache)
    2932           0 :         return EINVAL;
    2933             : 
    2934         104 :     ctx->fast_state.flags |= KRB5_FAST_REQUIRED;
    2935         104 :     ctx->fast_state.flags |= KRB5_FAST_ANON_PKINIT_ARMOR;
    2936         104 :     ctx->fast_state.flags |= KRB5_FAST_OPTIMISTIC;
    2937         104 :     return 0;
    2938             : }
    2939             : 
    2940             : static size_t
    2941       13319 : available_padata_count(METHOD_DATA *md)
    2942             : {
    2943       13319 :     size_t i, count = 0;
    2944             : 
    2945       83268 :     for (i = 0; i < md->len; i++) {
    2946       69364 :         PA_DATA *pa = &md->val[i];
    2947             : 
    2948       69364 :         if (pa->padata_type == KRB5_PADATA_FX_COOKIE ||
    2949       66439 :             pa->padata_type == KRB5_PADATA_FX_ERROR)
    2950           0 :             continue;
    2951             : 
    2952       69364 :         count++;
    2953             :     }
    2954             : 
    2955       13904 :     return count;
    2956             : }
    2957             : 
    2958             : static krb5_error_code
    2959       50757 : init_creds_step(krb5_context context,
    2960             :                 krb5_init_creds_context ctx,
    2961             :                 const krb5_data *in,
    2962             :                 krb5_data *out,
    2963             :                 krb5_realm *out_realm,
    2964             :                 unsigned int *flags)
    2965             : {
    2966        1755 :     struct timeval start_time, end_time;
    2967        1755 :     krb5_data checksum_data;
    2968        1755 :     krb5_error_code ret;
    2969       50757 :     size_t len = 0;
    2970        1755 :     size_t size;
    2971        1755 :     AS_REQ req2;
    2972             : 
    2973       50757 :     gettimeofday(&start_time, NULL);
    2974             : 
    2975       50757 :     krb5_data_zero(out);
    2976       50757 :     *out_realm = NULL;
    2977       50757 :     krb5_data_zero(&checksum_data);
    2978             : 
    2979       50757 :     if (ctx->as_req.req_body.cname == NULL) {
    2980       22801 :         ret = init_as_req(context, ctx->flags, &ctx->cred,
    2981       22216 :                           ctx->addrs, ctx->etypes, &ctx->as_req);
    2982       22216 :         if (ret)
    2983           0 :             return ret;
    2984       22216 :         if (ctx->fast_state.flags & KRB5_FAST_REQUIRED)
    2985             :             ;
    2986       22216 :         else if (ctx->fast_state.flags & KRB5_FAST_AP_ARMOR_SERVICE)
    2987             :             /* Check with armor service if there is FAST */;
    2988             :         else
    2989       22216 :             ctx->fast_state.flags |= KRB5_FAST_DISABLED;
    2990             : 
    2991             : 
    2992             :         /* XXX should happen after we get back reply from KDC */
    2993       22216 :         pa_configure(context, ctx, NULL);
    2994             :     }
    2995             : 
    2996             : #define MAX_PA_COUNTER 15
    2997       50757 :     if (ctx->pa_counter > MAX_PA_COUNTER) {
    2998           0 :         krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP,
    2999           0 :                                N_("Looping %d times while getting "
    3000             :                                   "initial credentials", ""),
    3001             :                                ctx->pa_counter);
    3002           0 :         return KRB5_GET_IN_TKT_LOOP;
    3003             :     }
    3004       50757 :     ctx->pa_counter++;
    3005             : 
    3006       50757 :     _krb5_debug(context, 5, "krb5_get_init_creds: loop %d", ctx->pa_counter);
    3007             : 
    3008             :     /* Lets process the input packet */
    3009       50757 :     if (in && in->length) {
    3010        1170 :         krb5_kdc_rep rep;
    3011             : 
    3012       28541 :         memset(&rep, 0, sizeof(rep));
    3013             : 
    3014       28541 :         _krb5_debug(context, 5, "krb5_get_init_creds: processing input");
    3015             : 
    3016       28541 :         ret = decode_AS_REP(in->data, in->length, &rep.kdc_rep, &size);
    3017       28541 :         if (ret == 0) {
    3018       13644 :             unsigned eflags = EXTRACT_TICKET_AS_REQ | EXTRACT_TICKET_TIMESYNC;
    3019         585 :             krb5_data data;
    3020             : 
    3021             :             /*
    3022             :              * Unwrap AS-REP
    3023             :              */
    3024       13644 :             ASN1_MALLOC_ENCODE(Ticket, data.data, data.length,
    3025             :                                &rep.kdc_rep.ticket, &size, ret);
    3026       13644 :             if (ret)
    3027           0 :                 goto out;
    3028       13644 :             heim_assert(data.length == size, "ASN.1 internal error");
    3029             : 
    3030       13644 :             ret = _krb5_fast_unwrap_kdc_rep(context, ctx->nonce, &data,
    3031             :                                             &ctx->fast_state, &rep.kdc_rep);
    3032       13644 :             krb5_data_free(&data);
    3033       13644 :             if (ret)
    3034           0 :                 goto out;
    3035             : 
    3036             :             /*
    3037             :              * Now check and extract the ticket
    3038             :              */
    3039             : 
    3040       13644 :             if (ctx->flags.canonicalize) {
    3041       12929 :                 eflags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH;
    3042       12929 :                 eflags |= EXTRACT_TICKET_MATCH_REALM;
    3043             :             }
    3044       13644 :             if (ctx->ic_flags & KRB5_INIT_CREDS_NO_C_CANON_CHECK)
    3045       12699 :                 eflags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH;
    3046       13644 :             if (ctx->flags.request_anonymous)
    3047           0 :                 eflags |= EXTRACT_TICKET_MATCH_ANON;
    3048             : 
    3049       13644 :             ret = process_pa_data_to_key(context, ctx, &ctx->cred,
    3050             :                                          &ctx->as_req, &rep.kdc_rep,
    3051             :                                          &ctx->fast_state.reply_key);
    3052       13644 :             if (ret) {
    3053           0 :                 free_AS_REP(&rep.kdc_rep);
    3054           0 :                 goto out;
    3055             :             }
    3056             : 
    3057       13644 :             if (ctx->fast_state.strengthen_key) {
    3058           0 :                 krb5_keyblock result;
    3059             : 
    3060           0 :                 _krb5_debug(context, 5, "krb5_get_init_creds: FAST strengthen_key");
    3061             : 
    3062           0 :                 ret = _krb5_fast_cf2(context,
    3063             :                                      ctx->fast_state.strengthen_key,
    3064             :                                      "strengthenkey",
    3065             :                                      ctx->fast_state.reply_key,
    3066             :                                      "replykey",
    3067             :                                      &result,
    3068             :                                      NULL);
    3069           0 :                 if (ret) {
    3070           0 :                     free_AS_REP(&rep.kdc_rep);
    3071           0 :                     goto out;
    3072             :                 }
    3073             : 
    3074           0 :                 ctx->runflags.allow_save_as_reply_key = 1;
    3075             : 
    3076           0 :                 krb5_free_keyblock_contents(context, ctx->fast_state.reply_key);
    3077           0 :                 *ctx->fast_state.reply_key = result;
    3078             :             }
    3079             : 
    3080       13644 :             _krb5_debug(context, 5, "krb5_get_init_creds: extracting ticket");
    3081             : 
    3082       13644 :             ret = _krb5_extract_ticket(context,
    3083             :                                        &rep,
    3084             :                                        &ctx->cred,
    3085             :                                        ctx->fast_state.reply_key,
    3086             :                                        NULL,
    3087             :                                        KRB5_KU_AS_REP_ENC_PART,
    3088             :                                        NULL,
    3089             :                                        ctx->nonce,
    3090             :                                        eflags,
    3091             :                                        &ctx->req_buffer,
    3092             :                                        NULL,
    3093             :                                        NULL);
    3094             : 
    3095       13644 :             if (ret == 0)
    3096       13632 :                 ret = copy_EncKDCRepPart(&rep.enc_part, &ctx->enc_part);
    3097       13644 :             if (ret == 0)
    3098       13632 :                 ret = validate_pkinit_fx(context, ctx, &rep.kdc_rep, &ctx->cred.session);
    3099             : 
    3100       13644 :             ctx->as_enctype = ctx->fast_state.reply_key->keytype;
    3101             : 
    3102       13644 :             if (ctx->runflags.allow_save_as_reply_key) {
    3103          13 :                 ctx->as_reply_key = ctx->fast_state.reply_key;
    3104          13 :                 ctx->fast_state.reply_key = NULL;
    3105             :             } else {
    3106       13631 :                 krb5_free_keyblock(context, ctx->fast_state.reply_key);
    3107       13631 :                 ctx->fast_state.reply_key = NULL;
    3108             :             }
    3109       13644 :             ctx->ic_flags |= KRB5_INIT_CREDS_DONE;
    3110       13644 :             *flags = 0;
    3111             : 
    3112       13644 :             free_AS_REP(&rep.kdc_rep);
    3113       13644 :             free_EncASRepPart(&rep.enc_part);
    3114             : 
    3115       13644 :             gettimeofday(&end_time, NULL);
    3116       13644 :             timevalsub(&end_time, &start_time);
    3117       13644 :             timevaladd(&ctx->stats.run_time, &end_time);
    3118             : 
    3119       13644 :             _krb5_debug(context, 1, "krb5_get_init_creds: wc: %lld.%06ld",
    3120       13644 :                         (long long)ctx->stats.run_time.tv_sec,
    3121       13644 :                         (long)ctx->stats.run_time.tv_usec);
    3122       13644 :             return ret;
    3123             : 
    3124             :         } else {
    3125             :             /* let's try to parse it as a KRB-ERROR */
    3126             : 
    3127       14897 :             _krb5_debug(context, 5, "krb5_get_init_creds: got an KRB-ERROR from KDC");
    3128             : 
    3129       14897 :             free_KRB_ERROR(&ctx->error);
    3130             : 
    3131       14897 :             ret = krb5_rd_error(context, in, &ctx->error);
    3132       14897 :             if(ret && in->length && ((char*)in->data)[0] == 4)
    3133           0 :                 ret = KRB5KRB_AP_ERR_V4_REPLY;
    3134       14897 :             if (ret) {
    3135           0 :                 _krb5_debug(context, 5, "krb5_get_init_creds: failed to read error");
    3136           0 :                 goto out;
    3137             :             }
    3138             : 
    3139             :             /*
    3140             :              * Unwrap method-data, if there is any,
    3141             :              * fast_unwrap_error() below might replace it with a
    3142             :              * wrapped version if we are using FAST.
    3143             :              */
    3144             : 
    3145       14897 :             free_METHOD_DATA(&ctx->md);
    3146       14897 :             memset(&ctx->md, 0, sizeof(ctx->md));
    3147             : 
    3148       14897 :             if (ctx->error.e_data) {
    3149         585 :                 KERB_ERROR_DATA kerb_error_data;
    3150         585 :                 krb5_error_code ret2;
    3151             : 
    3152       14204 :                 memset(&kerb_error_data, 0, sizeof(kerb_error_data));
    3153             : 
    3154             :                 /* First try to decode the e-data as KERB-ERROR-DATA. */
    3155       14204 :                 ret2 = decode_KERB_ERROR_DATA(ctx->error.e_data->data,
    3156       13619 :                                               ctx->error.e_data->length,
    3157             :                                               &kerb_error_data,
    3158             :                                               &len);
    3159       14204 :                 if (ret2) {
    3160             :                     /* That failed, so try to decode it as METHOD-DATA. */
    3161       14760 :                     ret2 = decode_METHOD_DATA(ctx->error.e_data->data,
    3162       14175 :                                               ctx->error.e_data->length,
    3163             :                                               &ctx->md,
    3164             :                                               NULL);
    3165       14175 :                     if (ret2) {
    3166             :                         /*
    3167             :                          * Just ignore any error, the error will be pushed
    3168             :                          * out from krb5_error_from_rd_error() if there
    3169             :                          * was one.
    3170             :                          */
    3171           0 :                         _krb5_debug(context, 5, N_("Failed to decode METHOD-DATA", ""));
    3172             :                     }
    3173          29 :                 } else if (len != ctx->error.e_data->length) {
    3174             :                     /* Trailing data — just ignore the error. */
    3175           0 :                     free_KERB_ERROR_DATA(&kerb_error_data);
    3176             :                 } else {
    3177             :                     /* OK. */
    3178          29 :                     free_KERB_ERROR_DATA(&kerb_error_data);
    3179             :                 }
    3180             :             }
    3181             : 
    3182             :             /*
    3183             :              * Unwrap KRB-ERROR, we are always calling this so that
    3184             :              * FAST can tell us if your peer KDC suddenly dropped FAST
    3185             :              * wrapping and its really an attacker's packet (or a bug
    3186             :              * in the KDC).
    3187             :              */
    3188       14897 :             ret = _krb5_fast_unwrap_error(context, ctx->nonce, &ctx->fast_state,
    3189             :                                           &ctx->md, &ctx->error);
    3190       14897 :             if (ret)
    3191           0 :                 goto out;
    3192             : 
    3193             :             /*
    3194             :              *
    3195             :              */
    3196             : 
    3197       14897 :             ret = krb5_error_from_rd_error(context, &ctx->error, &ctx->cred);
    3198             : 
    3199             :             /* log the failure */
    3200       14897 :             if (_krb5_have_debug(context, 5)) {
    3201           2 :                 const char *str = krb5_get_error_message(context, ret);
    3202           2 :                 _krb5_debug(context, 5, "krb5_get_init_creds: KRB-ERROR %d/%s", ret, str);
    3203           2 :                 krb5_free_error_message(context, str);
    3204             :             }
    3205             : 
    3206             :             /*
    3207             :              * Handle special error codes
    3208             :              */
    3209             : 
    3210       14897 :             if (ret == KRB5KDC_ERR_PREAUTH_REQUIRED
    3211        1579 :                 || ret == KRB5_KDC_ERR_MORE_PREAUTH_DATA_REQUIRED
    3212         994 :                 || ret == KRB5KDC_ERR_ETYPE_NOSUPP)
    3213             :             {
    3214             :                 /*
    3215             :                  * If no preauth was set and KDC requires it, give it one
    3216             :                  * more try.
    3217             :                  *
    3218             :                  * If the KDC returned KRB5KDC_ERR_ETYPE_NOSUPP, just loop
    3219             :                  * one more time since that might mean we are dealing with
    3220             :                  * a Windows KDC that is confused about what enctypes are
    3221             :                  * available.
    3222             :                  */
    3223             : 
    3224       13904 :                 if (available_padata_count(&ctx->md) == 0) {
    3225           1 :                     krb5_set_error_message(context, ret,
    3226           1 :                                            N_("Preauth required but no preauth "
    3227             :                                               "options sent by KDC", ""));
    3228           1 :                     goto out;
    3229             :                 }
    3230         993 :             } else if (ret == KRB5KRB_AP_ERR_SKEW && context->kdc_sec_offset == 0) {
    3231             :                 /*
    3232             :                  * Try adapt to timeskrew when we are using pre-auth, and
    3233             :                  * if there was a time skew, try again.
    3234             :                  */
    3235           0 :                 krb5_set_real_time(context, ctx->error.stime, -1);
    3236           0 :                 if (context->kdc_sec_offset)
    3237           0 :                     ret = 0;
    3238             : 
    3239           0 :                 _krb5_debug(context, 10, "init_creds: err skew updating kdc offset to %d",
    3240             :                             context->kdc_sec_offset);
    3241           0 :                 if (ret)
    3242           0 :                     goto out;
    3243             : 
    3244           0 :                 pa_restart(context, ctx);
    3245             : 
    3246        1252 :             } else if (ret == KRB5_KDC_ERR_WRONG_REALM && ctx->flags.canonicalize) {
    3247             :                 /* client referral to a new realm */
    3248           0 :                 char *ref_realm;
    3249             : 
    3250         259 :                 if (ctx->error.crealm == NULL) {
    3251           0 :                     krb5_set_error_message(context, ret,
    3252           0 :                                            N_("Got a client referral, not but no realm", ""));
    3253           0 :                     goto out;
    3254             :                 }
    3255         259 :                 ref_realm = *ctx->error.crealm;
    3256             : 
    3257         259 :                 _krb5_debug(context, 5, "krb5_get_init_creds: referral to realm %s",
    3258             :                             ref_realm);
    3259             : 
    3260             :                 /*
    3261             :                  * If its a krbtgt, lets updat the requested krbtgt too
    3262             :                  */
    3263         259 :                 if (krb5_principal_is_krbtgt(context, ctx->cred.server)) {
    3264             : 
    3265         259 :                     free(ctx->cred.server->name.name_string.val[1]);
    3266         259 :                     ctx->cred.server->name.name_string.val[1] = strdup(ref_realm);
    3267         259 :                     if (ctx->cred.server->name.name_string.val[1] == NULL) {
    3268           0 :                         ret = krb5_enomem(context);
    3269           0 :                         goto out;
    3270             :                     }
    3271             : 
    3272         259 :                     free_PrincipalName(ctx->as_req.req_body.sname);
    3273         259 :                     ret = _krb5_principal2principalname(ctx->as_req.req_body.sname, ctx->cred.server);
    3274         259 :                     if (ret)
    3275           0 :                         goto out;
    3276             :                 }
    3277             : 
    3278         259 :                 free(ctx->as_req.req_body.realm);
    3279         259 :                 ret = copy_Realm(&ref_realm, &ctx->as_req.req_body.realm);
    3280         259 :                 if (ret)
    3281           0 :                     goto out;
    3282             : 
    3283         259 :                 ret = krb5_principal_set_realm(context,
    3284             :                                                ctx->cred.client,
    3285         259 :                                                *ctx->error.crealm);
    3286         259 :                 if (ret)
    3287           0 :                     goto out;
    3288             : 
    3289         259 :                 ret = krb5_unparse_name(context, ctx->cred.client, &ref_realm);
    3290         259 :                 if (ret == 0) {
    3291         259 :                     _krb5_debug(context, 5, "krb5_get_init_creds: got referral to %s", ref_realm);
    3292         259 :                     krb5_xfree(ref_realm);
    3293             :                 }
    3294             : 
    3295         259 :                 pa_restart(context, ctx);
    3296             : 
    3297         734 :             } else if (ret == KRB5KDC_ERR_KEY_EXP && ctx->runflags.change_password == 0 &&
    3298           4 :                        ctx->runflags.change_password_prompt) {
    3299           0 :                 char buf2[1024];
    3300             : 
    3301           4 :                 ctx->runflags.change_password = 1;
    3302             : 
    3303           4 :                 ctx->prompter(context, ctx->prompter_data, NULL, N_("Password has expired", ""), 0, NULL);
    3304             : 
    3305             :                 /* try to avoid recursion */
    3306           4 :                 if (ctx->in_tkt_service != NULL && strcmp(ctx->in_tkt_service, "kadmin/changepw") == 0)
    3307           0 :                     goto out;
    3308             : 
    3309             :                 /* don't include prompter in runtime */
    3310           4 :                 gettimeofday(&end_time, NULL);
    3311           4 :                 timevalsub(&end_time, &start_time);
    3312           4 :                 timevaladd(&ctx->stats.run_time, &end_time);
    3313             : 
    3314           4 :                 ret = change_password(context,
    3315             :                                       ctx->cred.client,
    3316           4 :                                       ctx->password,
    3317             :                                       buf2,
    3318             :                                       sizeof(buf2),
    3319             :                                       ctx->prompter,
    3320             :                                       ctx->prompter_data,
    3321             :                                       NULL);
    3322           4 :                 if (ret)
    3323           0 :                     goto out;
    3324             : 
    3325           4 :                 gettimeofday(&start_time, NULL);
    3326             : 
    3327           4 :                 krb5_init_creds_set_password(context, ctx, buf2);
    3328             : 
    3329           4 :                 pa_restart(context, ctx);
    3330             : 
    3331         730 :             } else if (ret == KRB5KDC_ERR_PREAUTH_FAILED) {
    3332             : 
    3333             :                 /*
    3334             :                  * Old MIT KDC can't handle KRB5_PADATA_REQ_ENC_PA_REP,
    3335             :                  * so drop it and try again. But only try that for MIT
    3336             :                  * Kerberos servers by keying of no METHOD-DATA.
    3337             :                  */
    3338         262 :                 if (ctx->runflags.allow_enc_pa_rep) {
    3339         262 :                     if (ctx->md.len != 0) {
    3340         262 :                         _krb5_debug(context, 10, "Server sent PA data with KRB-ERROR, "
    3341             :                                     "so not a pre 1.7 MIT KDC and won't retry w/o ENC-PA-REQ");
    3342         262 :                         goto out;
    3343             :                     }
    3344           0 :                     _krb5_debug(context, 10, "Disabling allow_enc_pa_rep and trying again");
    3345           0 :                     ctx->runflags.allow_enc_pa_rep = 0;
    3346           0 :                     goto retry;
    3347             :                 }
    3348             : 
    3349           0 :                 if (ctx->fast_state.flags & KRB5_FAST_DISABLED) {
    3350           0 :                     _krb5_debug(context, 10, "FAST disabled and got preauth failed");
    3351           0 :                     goto out;
    3352             :                 }
    3353             : 
    3354           0 :             retry:
    3355           0 :                 pa_restart(context, ctx);
    3356             : 
    3357         468 :             } else if (ctx->fast_state.flags & KRB5_FAST_OPTIMISTIC) {
    3358           0 :                 _krb5_debug(context, 10,
    3359             :                             "Some other error %d failed with optimistic FAST, trying w/o FAST", ret);
    3360             : 
    3361           0 :                 ctx->fast_state.flags &= ~KRB5_FAST_OPTIMISTIC;
    3362           0 :                 ctx->fast_state.flags &= ~KRB5_FAST_REQUIRED;
    3363           0 :                 ctx->fast_state.flags &= ~KRB5_FAST_ANON_PKINIT_ARMOR;
    3364           0 :                 ctx->fast_state.flags |= KRB5_FAST_DISABLED;
    3365         585 :                 pa_restart(context, ctx);
    3366             :             } else {
    3367             :                 /* some other error code from the KDC, lets' return it to the user */
    3368         468 :                 goto out;
    3369             :             }
    3370             :         }
    3371             :     }
    3372             : 
    3373       36382 :     if (ctx->as_req.padata) {
    3374       14166 :         free_METHOD_DATA(ctx->as_req.padata);
    3375       14166 :         free(ctx->as_req.padata);
    3376       14166 :         ctx->as_req.padata = NULL;
    3377             :     }
    3378             : 
    3379       37552 :     ret = _krb5_fast_create_armor(context, &ctx->fast_state,
    3380       36382 :                                   ctx->cred.client->realm);
    3381       36382 :     if (ret)
    3382           0 :         goto out;
    3383             : 
    3384             :     /* Set a new nonce. */
    3385       36382 :     ctx->as_req.req_body.nonce = ctx->nonce;
    3386             : 
    3387             : 
    3388             :     /*
    3389             :      * Step and announce PA-DATA
    3390             :      */
    3391             : 
    3392       36382 :     ret = process_pa_data_to_md(context, &ctx->cred, &ctx->as_req, ctx,
    3393             :                                 &ctx->md, &ctx->as_req.padata);
    3394       36382 :     if (ret)
    3395           0 :         goto out;
    3396             : 
    3397             : 
    3398             :     /*
    3399             :      * Wrap with FAST
    3400             :      */
    3401       36382 :     ret = copy_AS_REQ(&ctx->as_req, &req2);
    3402       36382 :     if (ret)
    3403           0 :         goto out;
    3404             : 
    3405       36382 :     ret = _krb5_fast_wrap_req(context,
    3406             :                               &ctx->fast_state,
    3407             :                               &req2);
    3408             : 
    3409       36382 :     krb5_data_free(&checksum_data);
    3410       36382 :     if (ret) {
    3411           0 :         free_AS_REQ(&req2);
    3412           0 :         goto out;
    3413             :     }
    3414             : 
    3415       36382 :     krb5_data_free(&ctx->req_buffer);
    3416             : 
    3417       36382 :     ASN1_MALLOC_ENCODE(AS_REQ,
    3418             :                        ctx->req_buffer.data, ctx->req_buffer.length,
    3419             :                        &req2, &len, ret);
    3420       36382 :     free_AS_REQ(&req2);
    3421       36382 :     if (ret)
    3422           0 :         goto out;
    3423       36382 :     if(len != ctx->req_buffer.length)
    3424           0 :         krb5_abortx(context, "internal error in ASN.1 encoder");
    3425             : 
    3426       37552 :     ret = krb5_data_copy(out,
    3427       36382 :                          ctx->req_buffer.data,
    3428             :                          ctx->req_buffer.length);
    3429       36382 :     if (ret)
    3430           0 :         goto out;
    3431             : 
    3432       36382 :     *out_realm = strdup(ctx->cred.client->realm);
    3433       36382 :     if (*out_realm == NULL) {
    3434           0 :         krb5_data_free(out);
    3435           0 :         ret = ENOMEM;
    3436           0 :         goto out;
    3437             :     }
    3438             : 
    3439       36382 :     *flags = KRB5_INIT_CREDS_STEP_FLAG_CONTINUE;
    3440             : 
    3441       36382 :     gettimeofday(&end_time, NULL);
    3442       36382 :     timevalsub(&end_time, &start_time);
    3443       36382 :     timevaladd(&ctx->stats.run_time, &end_time);
    3444             : 
    3445       36382 :     return 0;
    3446         731 :  out:
    3447         731 :     return ret;
    3448             : }
    3449             : 
    3450             : /**
    3451             :  * The core loop if krb5_get_init_creds() function family. Create the
    3452             :  * packets and have the caller send them off to the KDC.
    3453             :  *
    3454             :  * If the caller want all work been done for them, use
    3455             :  * krb5_init_creds_get() instead.
    3456             :  *
    3457             :  * @param context a Kerberos 5 context.
    3458             :  * @param ctx ctx krb5_init_creds_context context.
    3459             :  * @param in input data from KDC, first round it should be reset by krb5_data_zero().
    3460             :  * @param out reply to KDC. The caller needs to call krb5_data_free()
    3461             :  * @param out_realm the destination realm for 'out', free with krb5_xfree()
    3462             :  * @param flags status of the round, if
    3463             :  *        KRB5_INIT_CREDS_STEP_FLAG_CONTINUE is set, continue one more round.
    3464             :  *
    3465             :  * @return 0 for success, or an Kerberos 5 error code, see
    3466             :  *     krb5_get_error_message().
    3467             :  *
    3468             :  * @ingroup krb5_credential
    3469             :  */
    3470             : 
    3471             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    3472       50861 : krb5_init_creds_step(krb5_context context,
    3473             :                      krb5_init_creds_context ctx,
    3474             :                      const krb5_data *in,
    3475             :                      krb5_data *out,
    3476             :                      krb5_realm *out_realm,
    3477             :                      unsigned int *flags)
    3478             : {
    3479        1755 :     krb5_error_code ret;
    3480        1755 :     krb5_data empty;
    3481             : 
    3482       50861 :     krb5_data_zero(&empty);
    3483       50861 :     krb5_data_zero(out);
    3484       50861 :     *out_realm = NULL;
    3485             : 
    3486       50861 :     if ((ctx->fast_state.flags & KRB5_FAST_ANON_PKINIT_ARMOR) &&
    3487         208 :         ctx->fast_state.armor_ccache == NULL) {
    3488         208 :         ret = _krb5_fast_anon_pkinit_step(context, ctx, &ctx->fast_state,
    3489             :                                           in, out, out_realm, flags);
    3490         208 :         if (ret && (ctx->fast_state.flags & KRB5_FAST_OPTIMISTIC)) {
    3491         104 :             _krb5_debug(context, 5, "Preauth failed with optimistic "
    3492             :                         "FAST, trying w/o FAST");
    3493         104 :             ctx->fast_state.flags &= ~KRB5_FAST_OPTIMISTIC;
    3494         104 :             ctx->fast_state.flags &= ~KRB5_FAST_REQUIRED;
    3495         104 :             ctx->fast_state.flags &= ~KRB5_FAST_ANON_PKINIT_ARMOR;
    3496         104 :         } else if (ret ||
    3497         104 :                    (*flags & KRB5_INIT_CREDS_STEP_FLAG_CONTINUE))
    3498         104 :             return ret;
    3499             : 
    3500         104 :         in = &empty;
    3501             :     }
    3502             : 
    3503       50757 :     return init_creds_step(context, ctx, in, out, out_realm, flags);
    3504             : }
    3505             : 
    3506             : /**
    3507             :  * Extract the newly acquired credentials from krb5_init_creds_context
    3508             :  * context.
    3509             :  *
    3510             :  * @param context A Kerberos 5 context.
    3511             :  * @param ctx
    3512             :  * @param cred credentials, free with krb5_free_cred_contents().
    3513             :  *
    3514             :  * @return 0 for sucess or An Kerberos error code, see krb5_get_error_message().
    3515             :  */
    3516             : 
    3517             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    3518       13632 : krb5_init_creds_get_creds(krb5_context context,
    3519             :                           krb5_init_creds_context ctx,
    3520             :                           krb5_creds *cred)
    3521             : {
    3522       13632 :     return krb5_copy_creds_contents(context, &ctx->cred, cred);
    3523             : }
    3524             : 
    3525             : /**
    3526             :  * Extract the as-reply key from the context.
    3527             :  *
    3528             :  * Only allowed when the as-reply-key is not directly derived from the
    3529             :  * password like PK-INIT, GSS, FAST hardened key, etc.
    3530             :  *
    3531             :  * @param context A Kerberos 5 context.
    3532             :  * @param ctx ctx krb5_init_creds_context context.
    3533             :  * @param as_reply_key keyblock, free with krb5_free_keyblock_contents().
    3534             :  *
    3535             :  * @return 0 for sucess or An Kerberos error code, see krb5_get_error_message().
    3536             :  */
    3537             : 
    3538             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    3539           0 : krb5_init_creds_get_as_reply_key(krb5_context context,
    3540             :                                  krb5_init_creds_context ctx,
    3541             :                                  krb5_keyblock *as_reply_key)
    3542             : {
    3543           0 :     if (ctx->as_reply_key == NULL)
    3544           0 :         return KRB5KDC_ERR_PREAUTH_REQUIRED;
    3545           0 :     return krb5_copy_keyblock_contents(context, ctx->as_reply_key, as_reply_key);
    3546             : }
    3547             : 
    3548             : KRB5_LIB_FUNCTION krb5_timestamp KRB5_LIB_CALL
    3549         104 : _krb5_init_creds_get_cred_starttime(krb5_context context, krb5_init_creds_context ctx)
    3550             : {
    3551         104 :     return ctx->cred.times.starttime;
    3552             : }
    3553             : 
    3554             : KRB5_LIB_FUNCTION krb5_timestamp KRB5_LIB_CALL
    3555           0 : _krb5_init_creds_get_cred_endtime(krb5_context context, krb5_init_creds_context ctx)
    3556             : {
    3557           0 :     return ctx->cred.times.endtime;
    3558             : }
    3559             : 
    3560             : KRB5_LIB_FUNCTION krb5_principal KRB5_LIB_CALL
    3561         208 : _krb5_init_creds_get_cred_client(krb5_context context, krb5_init_creds_context ctx)
    3562             : {
    3563         208 :     return ctx->cred.client;
    3564             : }
    3565             : 
    3566             : /**
    3567             :  * Get the last error from the transaction.
    3568             :  *
    3569             :  * @return Returns 0 or an error code
    3570             :  *
    3571             :  * @ingroup krb5_credential
    3572             :  */
    3573             : 
    3574             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    3575           0 : krb5_init_creds_get_error(krb5_context context,
    3576             :                           krb5_init_creds_context ctx,
    3577             :                           KRB_ERROR *error)
    3578             : {
    3579           0 :     krb5_error_code ret;
    3580             : 
    3581           0 :     ret = copy_KRB_ERROR(&ctx->error, error);
    3582           0 :     if (ret)
    3583           0 :         krb5_enomem(context);
    3584             : 
    3585           0 :     return ret;
    3586             : }
    3587             : 
    3588             : /**
    3589             :  * Store config
    3590             :  *
    3591             :  * @param context A Kerberos 5 context.
    3592             :  * @param ctx The krb5_init_creds_context to free.
    3593             :  * @param id store
    3594             :  *
    3595             :  * @return Returns 0 or an error code
    3596             :  *
    3597             :  * @ingroup krb5_credential
    3598             :  */
    3599             : 
    3600             : krb5_error_code KRB5_LIB_FUNCTION
    3601         113 : krb5_init_creds_store_config(krb5_context context,
    3602             :                              krb5_init_creds_context ctx,
    3603             :                              krb5_ccache id)
    3604             : {
    3605           0 :     krb5_error_code ret;
    3606             : 
    3607         113 :     if (ctx->kdc_hostname) {
    3608           0 :         krb5_data data;
    3609           0 :         data.length = strlen(ctx->kdc_hostname);
    3610           0 :         data.data = ctx->kdc_hostname;
    3611             : 
    3612           0 :         ret = krb5_cc_set_config(context, id, NULL, "lkdc-hostname", &data);
    3613           0 :         if (ret)
    3614           0 :             return ret;
    3615             :     }
    3616         113 :     if (ctx->sitename) {
    3617           0 :         krb5_data data;
    3618           0 :         data.length = strlen(ctx->sitename);
    3619           0 :         data.data = ctx->sitename;
    3620             : 
    3621           0 :         ret = krb5_cc_set_config(context, id, NULL, "sitename", &data);
    3622           0 :         if (ret)
    3623           0 :             return ret;
    3624             :     }
    3625             : 
    3626         113 :     return 0;
    3627             : }
    3628             : 
    3629             : /**
    3630             :  *
    3631             :  * @ingroup krb5_credential
    3632             :  */
    3633             : 
    3634             : krb5_error_code
    3635         113 : krb5_init_creds_store(krb5_context context,
    3636             :                       krb5_init_creds_context ctx,
    3637             :                       krb5_ccache id)
    3638             : {
    3639           0 :     krb5_error_code ret;
    3640             : 
    3641         113 :     if (ctx->cred.client == NULL) {
    3642           0 :         ret = KRB5KDC_ERR_PREAUTH_REQUIRED;
    3643           0 :         krb5_set_error_message(context, ret, "init creds not completed yet");
    3644           0 :         return ret;
    3645             :     }
    3646             : 
    3647         113 :     ret = krb5_cc_initialize(context, id, ctx->cred.client);
    3648         113 :     if (ret)
    3649           0 :         return ret;
    3650             : 
    3651         113 :     ret = krb5_cc_store_cred(context, id, &ctx->cred);
    3652         113 :     if (ret)
    3653           0 :         return ret;
    3654             : 
    3655         113 :     if (ctx->cred.flags.b.enc_pa_rep) {
    3656         113 :         krb5_data data = { 3, rk_UNCONST("yes") };
    3657         113 :         ret = krb5_cc_set_config(context, id, ctx->cred.server,
    3658             :                                  "fast_avail", &data);
    3659         113 :         if (ret && ret != KRB5_CC_NOSUPP)
    3660           0 :             return ret;
    3661             :     }
    3662             : 
    3663         113 :     return 0;
    3664             : }
    3665             : 
    3666             : /**
    3667             :  * Free the krb5_init_creds_context allocated by krb5_init_creds_init().
    3668             :  *
    3669             :  * @param context A Kerberos 5 context.
    3670             :  * @param ctx The krb5_init_creds_context to free.
    3671             :  *
    3672             :  * @ingroup krb5_credential
    3673             :  */
    3674             : 
    3675             : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
    3676       22216 : krb5_init_creds_free(krb5_context context,
    3677             :                      krb5_init_creds_context ctx)
    3678             : {
    3679       22216 :     free_init_creds_ctx(context, ctx);
    3680       22216 :     free(ctx);
    3681       22216 : }
    3682             : 
    3683             : /**
    3684             :  * Get new credentials as setup by the krb5_init_creds_context.
    3685             :  *
    3686             :  * @param context A Kerberos 5 context.
    3687             :  * @param ctx The krb5_init_creds_context to process.
    3688             :  *
    3689             :  * @ingroup krb5_credential
    3690             :  */
    3691             : 
    3692             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    3693       22112 : krb5_init_creds_get(krb5_context context, krb5_init_creds_context ctx)
    3694             : {
    3695       22112 :     krb5_sendto_ctx stctx = NULL;
    3696         585 :     krb5_error_code ret;
    3697         585 :     krb5_data in, out;
    3698       22112 :     unsigned int flags = 0;
    3699             : 
    3700       22112 :     krb5_data_zero(&in);
    3701       22112 :     krb5_data_zero(&out);
    3702             : 
    3703       22112 :     ret = krb5_sendto_ctx_alloc(context, &stctx);
    3704       22112 :     if (ret)
    3705           0 :         goto out;
    3706       22112 :     krb5_sendto_ctx_set_func(stctx, _krb5_kdc_retry, NULL);
    3707             : 
    3708       22112 :     if (ctx->kdc_hostname)
    3709           0 :         krb5_sendto_set_hostname(context, stctx, ctx->kdc_hostname);
    3710       22112 :     if (ctx->sitename)
    3711           0 :         krb5_sendto_set_sitename(context, stctx, ctx->sitename);
    3712             : 
    3713       28541 :     while (1) {
    3714        1755 :         struct timeval nstart, nend;
    3715       50653 :         krb5_realm realm = NULL;
    3716             : 
    3717       50653 :         flags = 0;
    3718       50653 :         ret = krb5_init_creds_step(context, ctx, &in, &out, &realm, &flags);
    3719       50653 :         krb5_data_free(&in);
    3720       50653 :         if (ret)
    3721        8480 :             goto out;
    3722             : 
    3723       50014 :         if ((flags & KRB5_INIT_CREDS_STEP_FLAG_CONTINUE) == 0)
    3724       13047 :             break;
    3725             : 
    3726       36382 :         gettimeofday(&nstart, NULL);
    3727             : 
    3728       36382 :         ret = krb5_sendto_context (context, stctx, &out, realm, &in);
    3729       36382 :         krb5_data_free(&out);
    3730       36382 :         free(realm);
    3731       36382 :         if (ret)
    3732        7841 :             goto out;
    3733             : 
    3734       28541 :         gettimeofday(&nend, NULL);
    3735       28541 :         timevalsub(&nend, &nstart);
    3736       28541 :         timevaladd(&ctx->stats.run_time, &nend);
    3737             :     }
    3738             : 
    3739       22112 :  out:
    3740       22112 :     if (stctx)
    3741       22112 :         krb5_sendto_ctx_free(context, stctx);
    3742             : 
    3743       22112 :     return ret;
    3744             : }
    3745             : 
    3746             : /**
    3747             :  * Get new credentials using password.
    3748             :  *
    3749             :  * @ingroup krb5_credential
    3750             :  */
    3751             : 
    3752             : 
    3753             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    3754       21976 : krb5_get_init_creds_password(krb5_context context,
    3755             :                              krb5_creds *creds,
    3756             :                              krb5_principal client,
    3757             :                              const char *password,
    3758             :                              krb5_prompter_fct prompter,
    3759             :                              void *data,
    3760             :                              krb5_deltat start_time,
    3761             :                              const char *in_tkt_service,
    3762             :                              krb5_get_init_creds_opt *options)
    3763             : {
    3764         582 :     krb5_init_creds_context ctx;
    3765         582 :     char buf[BUFSIZ], buf2[BUFSIZ];
    3766         582 :     krb5_error_code ret;
    3767       21976 :     int chpw = 0;
    3768             : 
    3769       21976 :  again:
    3770       21976 :     ret = krb5_init_creds_init(context, client, prompter, data, start_time, options, &ctx);
    3771       21976 :     if (ret)
    3772           0 :         goto out;
    3773             : 
    3774       21976 :     ret = krb5_init_creds_set_service(context, ctx, in_tkt_service);
    3775       21976 :     if (ret)
    3776           0 :         goto out;
    3777             : 
    3778       21976 :     if (prompter != NULL && ctx->password == NULL && password == NULL) {
    3779           0 :         krb5_prompt prompt;
    3780           0 :         krb5_data password_data;
    3781           6 :         char *p, *q = NULL;
    3782           0 :         int aret;
    3783             : 
    3784           6 :         ret = krb5_unparse_name(context, client, &p);
    3785           6 :         if (ret)
    3786           0 :             goto out;
    3787             : 
    3788           6 :         aret = asprintf(&q, "%s's Password: ", p);
    3789           6 :         free (p);
    3790           6 :         if (aret == -1 || q == NULL) {
    3791           0 :             ret = krb5_enomem(context);
    3792           0 :             goto out;
    3793             :         }
    3794           6 :         prompt.prompt = q;
    3795           6 :         password_data.data   = buf;
    3796           6 :         password_data.length = sizeof(buf);
    3797           6 :         prompt.hidden = 1;
    3798           6 :         prompt.reply  = &password_data;
    3799           6 :         prompt.type   = KRB5_PROMPT_TYPE_PASSWORD;
    3800             : 
    3801           6 :         ret = (*prompter) (context, data, NULL, NULL, 1, &prompt);
    3802           6 :         free (q);
    3803           6 :         if (ret) {
    3804           0 :             memset_s(buf, sizeof(buf), 0, sizeof(buf));
    3805           0 :             ret = KRB5_LIBOS_PWDINTR;
    3806           0 :             krb5_clear_error_message (context);
    3807           0 :             goto out;
    3808             :         }
    3809           6 :         password = password_data.data;
    3810             :     }
    3811             : 
    3812       21976 :     if (password) {
    3813       21976 :         ret = krb5_init_creds_set_password(context, ctx, password);
    3814       21976 :         if (ret)
    3815           0 :             goto out;
    3816             :     }
    3817             : 
    3818       21976 :     ret = krb5_init_creds_get(context, ctx);
    3819             : 
    3820       21976 :     if (ret == 0)
    3821       13507 :         krb5_process_last_request(context, options, ctx);
    3822             : 
    3823             : 
    3824       21976 :     if (ret == KRB5KDC_ERR_KEY_EXPIRED && chpw == 0) {
    3825             :         /* try to avoid recursion */
    3826           0 :         if (in_tkt_service != NULL && strcmp(in_tkt_service, "kadmin/changepw") == 0)
    3827           0 :            goto out;
    3828             : 
    3829             :         /* don't try to change password if no prompter or prompting disabled */
    3830           0 :         if (!ctx->runflags.change_password_prompt)
    3831           0 :             goto out;
    3832             : 
    3833           0 :         ret = change_password (context,
    3834             :                                client,
    3835           0 :                                ctx->password,
    3836             :                                buf2,
    3837             :                                sizeof(buf2),
    3838             :                                prompter,
    3839             :                                data,
    3840             :                                options);
    3841           0 :         if (ret)
    3842           0 :             goto out;
    3843           0 :         password = buf2;
    3844           0 :         chpw = 1;
    3845           0 :         krb5_init_creds_free(context, ctx);
    3846           0 :         goto again;
    3847             :     }
    3848             : 
    3849       21976 :  out:
    3850       21976 :     if (ret == 0)
    3851       13507 :         krb5_init_creds_get_creds(context, ctx, creds);
    3852             : 
    3853       21976 :     if (ctx)
    3854       21976 :         krb5_init_creds_free(context, ctx);
    3855             : 
    3856       21976 :     memset_s(buf, sizeof(buf), 0, sizeof(buf));
    3857       21976 :     memset_s(buf2, sizeof(buf), 0, sizeof(buf2));
    3858       21976 :     return ret;
    3859             : }
    3860             : 
    3861             : /**
    3862             :  * Get new credentials using keyblock.
    3863             :  *
    3864             :  * @ingroup krb5_credential
    3865             :  */
    3866             : 
    3867             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    3868          12 : krb5_get_init_creds_keyblock(krb5_context context,
    3869             :                              krb5_creds *creds,
    3870             :                              krb5_principal client,
    3871             :                              krb5_keyblock *keyblock,
    3872             :                              krb5_deltat start_time,
    3873             :                              const char *in_tkt_service,
    3874             :                              krb5_get_init_creds_opt *options)
    3875             : {
    3876           3 :     krb5_init_creds_context ctx;
    3877           3 :     krb5_error_code ret;
    3878             : 
    3879          12 :     memset(creds, 0, sizeof(*creds));
    3880             : 
    3881          12 :     ret = krb5_init_creds_init(context, client, NULL, NULL, start_time, options, &ctx);
    3882          12 :     if (ret)
    3883           0 :         goto out;
    3884             : 
    3885          12 :     ret = krb5_init_creds_set_service(context, ctx, in_tkt_service);
    3886          12 :     if (ret)
    3887           0 :         goto out;
    3888             : 
    3889          12 :     ret = krb5_init_creds_set_keyblock(context, ctx, keyblock);
    3890          12 :     if (ret)
    3891           0 :         goto out;
    3892             : 
    3893          12 :     ret = krb5_init_creds_get(context, ctx);
    3894             : 
    3895          12 :     if (ret == 0)
    3896          12 :         krb5_process_last_request(context, options, ctx);
    3897             : 
    3898           0 :  out:
    3899          12 :     if (ret == 0)
    3900          12 :         krb5_init_creds_get_creds(context, ctx, creds);
    3901             : 
    3902          12 :     if (ctx)
    3903          12 :         krb5_init_creds_free(context, ctx);
    3904             : 
    3905          12 :     return ret;
    3906             : }
    3907             : 
    3908             : /**
    3909             :  * Get new credentials using keytab.
    3910             :  *
    3911             :  * @ingroup krb5_credential
    3912             :  */
    3913             : 
    3914             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    3915           0 : krb5_get_init_creds_keytab(krb5_context context,
    3916             :                            krb5_creds *creds,
    3917             :                            krb5_principal client,
    3918             :                            krb5_keytab keytab,
    3919             :                            krb5_deltat start_time,
    3920             :                            const char *in_tkt_service,
    3921             :                            krb5_get_init_creds_opt *options)
    3922             : {
    3923           0 :     krb5_init_creds_context ctx;
    3924           0 :     krb5_keytab_entry ktent;
    3925           0 :     krb5_error_code ret;
    3926             : 
    3927           0 :     memset(&ktent, 0, sizeof(ktent));
    3928           0 :     memset(creds, 0, sizeof(*creds));
    3929             : 
    3930           0 :     if (strcmp(client->realm, "") == 0) {
    3931             :         /*
    3932             :          * Referral realm.  We have a keytab, so pick a realm by
    3933             :          * matching in the keytab.
    3934             :          */
    3935           0 :         ret = krb5_kt_get_entry(context, keytab, client, 0, 0, &ktent);
    3936           0 :         if (ret == 0)
    3937           0 :             client = ktent.principal;
    3938             :     }
    3939             : 
    3940           0 :     ret = krb5_init_creds_init(context, client, NULL, NULL, start_time, options, &ctx);
    3941           0 :     if (ret)
    3942           0 :         goto out;
    3943             : 
    3944           0 :     ret = krb5_init_creds_set_service(context, ctx, in_tkt_service);
    3945           0 :     if (ret)
    3946           0 :         goto out;
    3947             : 
    3948           0 :     ret = krb5_init_creds_set_keytab(context, ctx, keytab);
    3949           0 :     if (ret)
    3950           0 :         goto out;
    3951             : 
    3952           0 :     ret = krb5_init_creds_get(context, ctx);
    3953           0 :     if (ret == 0)
    3954           0 :         krb5_process_last_request(context, options, ctx);
    3955             : 
    3956           0 :  out:
    3957           0 :     krb5_kt_free_entry(context, &ktent);
    3958           0 :     if (ret == 0)
    3959           0 :         krb5_init_creds_get_creds(context, ctx, creds);
    3960             : 
    3961           0 :     if (ctx)
    3962           0 :         krb5_init_creds_free(context, ctx);
    3963             : 
    3964           0 :     return ret;
    3965             : }
    3966             : 
    3967             : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
    3968           0 : _krb5_init_creds_set_gss_mechanism(krb5_context context,
    3969             :                                    krb5_gss_init_ctx gssic,
    3970             :                                    const struct gss_OID_desc_struct *gss_mech)
    3971             : {
    3972           0 :     gssic->mech = gss_mech; /* OIDs are interned, so no copy required */
    3973           0 : }
    3974             : 
    3975             : KRB5_LIB_FUNCTION const struct gss_OID_desc_struct * KRB5_LIB_CALL
    3976           0 : _krb5_init_creds_get_gss_mechanism(krb5_context context,
    3977             :                                    krb5_gss_init_ctx gssic)
    3978             : {
    3979           0 :     return gssic->mech;
    3980             : }
    3981             : 
    3982             : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
    3983           0 : _krb5_init_creds_set_gss_cred(krb5_context context,
    3984             :                               krb5_gss_init_ctx gssic,
    3985             :                               struct gss_cred_id_t_desc_struct *gss_cred)
    3986             : {
    3987           0 :     if (gssic->cred != gss_cred && gssic->flags.release_cred)
    3988           0 :         gssic->release_cred(context, gssic, gssic->cred);
    3989             : 
    3990           0 :     gssic->cred = gss_cred;
    3991           0 :     gssic->flags.release_cred = 1;
    3992           0 : }
    3993             : 
    3994             : KRB5_LIB_FUNCTION const struct gss_cred_id_t_desc_struct * KRB5_LIB_CALL
    3995           0 : _krb5_init_creds_get_gss_cred(krb5_context context,
    3996             :                               krb5_gss_init_ctx gssic)
    3997             : {
    3998           0 :     return gssic->cred;
    3999             : }
    4000             : 
    4001             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    4002           0 : _krb5_init_creds_init_gss(krb5_context context,
    4003             :                           krb5_init_creds_context ctx,
    4004             :                           krb5_gssic_step step,
    4005             :                           krb5_gssic_finish finish,
    4006             :                           krb5_gssic_release_cred release_cred,
    4007             :                           krb5_gssic_delete_sec_context delete_sec_context,
    4008             :                           const struct gss_cred_id_t_desc_struct *gss_cred,
    4009             :                           const struct gss_OID_desc_struct *gss_mech,
    4010             :                           unsigned int flags)
    4011             : {
    4012           0 :     krb5_gss_init_ctx gssic;
    4013             : 
    4014           0 :     gssic = calloc(1, sizeof(*gssic));
    4015           0 :     if (gssic == NULL)
    4016           0 :         return krb5_enomem(context);
    4017             : 
    4018           0 :     if (ctx->gss_init_ctx)
    4019           0 :         free_gss_init_ctx(context, ctx->gss_init_ctx);
    4020           0 :     ctx->gss_init_ctx = gssic;
    4021             : 
    4022           0 :     gssic->cred = (struct gss_cred_id_t_desc_struct *)gss_cred;
    4023           0 :     gssic->mech = gss_mech;
    4024           0 :     if (flags & KRB5_GSS_IC_FLAG_RELEASE_CRED)
    4025           0 :         gssic->flags.release_cred = 1;
    4026             : 
    4027           0 :     gssic->step = step;
    4028           0 :     gssic->finish = finish;
    4029           0 :     gssic->release_cred = release_cred;
    4030           0 :     gssic->delete_sec_context = delete_sec_context;
    4031             : 
    4032           0 :     return 0;
    4033             : }

Generated by: LCOV version 1.14