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

Generated by: LCOV version 1.13