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 fix-15632 9995c5c2 Lines: 1215 1909 63.6 %
Date: 2024-04-13 12:30:31 Functions: 66 88 75.0 %

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

Generated by: LCOV version 1.14