LCOV - code coverage report
Current view: top level - source4/heimdal/lib/krb5 - init_creds_pw.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 692 978 70.8 %
Date: 2021-09-23 10:06:22 Functions: 42 45 93.3 %

          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 Apple Inc. All rights reserved.
       7             :  *
       8             :  * Redistribution and use in source and binary forms, with or without
       9             :  * modification, are permitted provided that the following conditions
      10             :  * are met:
      11             :  *
      12             :  * 1. Redistributions of source code must retain the above copyright
      13             :  *    notice, this list of conditions and the following disclaimer.
      14             :  *
      15             :  * 2. Redistributions in binary form must reproduce the above copyright
      16             :  *    notice, this list of conditions and the following disclaimer in the
      17             :  *    documentation and/or other materials provided with the distribution.
      18             :  *
      19             :  * 3. Neither the name of the Institute nor the names of its contributors
      20             :  *    may be used to endorse or promote products derived from this software
      21             :  *    without specific prior written permission.
      22             :  *
      23             :  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
      24             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      25             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      26             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
      27             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      28             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      29             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      30             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      31             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      32             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      33             :  * SUCH DAMAGE.
      34             :  */
      35             : 
      36             : #include "krb5_locl.h"
      37             : 
      38             : typedef struct krb5_get_init_creds_ctx {
      39             :     KDCOptions flags;
      40             :     krb5_creds cred;
      41             :     krb5_addresses *addrs;
      42             :     krb5_enctype *etypes;
      43             :     krb5_preauthtype *pre_auth_types;
      44             :     char *in_tkt_service;
      45             :     unsigned nonce;
      46             :     unsigned pk_nonce;
      47             : 
      48             :     krb5_data req_buffer;
      49             :     AS_REQ as_req;
      50             :     int pa_counter;
      51             : 
      52             :     /* password and keytab_data is freed on completion */
      53             :     char *password;
      54             :     krb5_keytab_key_proc_args *keytab_data;
      55             : 
      56             :     krb5_pointer *keyseed;
      57             :     krb5_s2k_proc keyproc;
      58             : 
      59             :     krb5_get_init_creds_tristate req_pac;
      60             : 
      61             :     krb5_pk_init_ctx pk_init_ctx;
      62             :     int ic_flags;
      63             : 
      64             :     int used_pa_types;
      65             : #define  USED_PKINIT    1
      66             : #define  USED_PKINIT_W2K        2
      67             : #define  USED_ENC_TS_GUESS      4
      68             : #define  USED_ENC_TS_INFO       8
      69             : 
      70             :     METHOD_DATA md;
      71             :     KRB_ERROR error;
      72             :     AS_REP as_rep;
      73             :     EncKDCRepPart enc_part;
      74             : 
      75             :     krb5_prompter_fct prompter;
      76             :     void *prompter_data;
      77             : 
      78             :     struct pa_info_data *ppaid;
      79             : 
      80             : } krb5_get_init_creds_ctx;
      81             : 
      82             : 
      83             : struct pa_info_data {
      84             :     krb5_enctype etype;
      85             :     krb5_salt salt;
      86             :     krb5_data *s2kparams;
      87             : };
      88             : 
      89             : static void
      90       28223 : free_paid(krb5_context context, struct pa_info_data *ppaid)
      91             : {
      92       28223 :     krb5_free_salt(context, ppaid->salt);
      93       28223 :     if (ppaid->s2kparams)
      94        9342 :         krb5_free_data(context, ppaid->s2kparams);
      95       28223 : }
      96             : 
      97             : static krb5_error_code KRB5_CALLCONV
      98       28159 : default_s2k_func(krb5_context context, krb5_enctype type,
      99             :                  krb5_const_pointer keyseed,
     100             :                  krb5_salt salt, krb5_data *s2kparms,
     101             :                  krb5_keyblock **key)
     102             : {
     103             :     krb5_error_code ret;
     104             :     krb5_data password;
     105             :     krb5_data opaque;
     106             : 
     107       28159 :     _krb5_debug(context, 5, "krb5_get_init_creds: using default_s2k_func");
     108             : 
     109       28159 :     password.data = rk_UNCONST(keyseed);
     110       28159 :     password.length = strlen(keyseed);
     111       28159 :     if (s2kparms)
     112        9339 :         opaque = *s2kparms;
     113             :     else
     114       18820 :         krb5_data_zero(&opaque);
     115             : 
     116       28159 :     *key = malloc(sizeof(**key));
     117       28159 :     if (*key == NULL)
     118           0 :         return ENOMEM;
     119       28159 :     ret = krb5_string_to_key_data_salt_opaque(context, type, password,
     120             :                                               salt, opaque, *key);
     121       28159 :     if (ret) {
     122           0 :         free(*key);
     123           0 :         *key = NULL;
     124             :     }
     125       27575 :     return ret;
     126             : }
     127             : 
     128             : static void
     129       22093 : free_init_creds_ctx(krb5_context context, krb5_init_creds_context ctx)
     130             : {
     131       22093 :     if (ctx->etypes)
     132         139 :         free(ctx->etypes);
     133       22093 :     if (ctx->pre_auth_types)
     134           0 :         free (ctx->pre_auth_types);
     135       22093 :     if (ctx->in_tkt_service)
     136           0 :         free(ctx->in_tkt_service);
     137       22093 :     if (ctx->keytab_data)
     138           7 :         free(ctx->keytab_data);
     139       22093 :     if (ctx->password) {
     140       22366 :         memset(ctx->password, 0, strlen(ctx->password));
     141       22074 :         free(ctx->password);
     142             :     }
     143       22093 :     krb5_data_free(&ctx->req_buffer);
     144       22093 :     krb5_free_cred_contents(context, &ctx->cred);
     145       22093 :     free_METHOD_DATA(&ctx->md);
     146       22093 :     free_AS_REP(&ctx->as_rep);
     147       22093 :     free_EncKDCRepPart(&ctx->enc_part);
     148       22093 :     free_KRB_ERROR(&ctx->error);
     149       22093 :     free_AS_REQ(&ctx->as_req);
     150       22093 :     if (ctx->ppaid) {
     151       14238 :         free_paid(context, ctx->ppaid);
     152       14238 :         free(ctx->ppaid);
     153             :     }
     154       22093 :     memset(ctx, 0, sizeof(*ctx));
     155       22093 : }
     156             : 
     157             : static int
     158        2007 : get_config_time (krb5_context context,
     159             :                  const char *realm,
     160             :                  const char *name,
     161             :                  int def)
     162             : {
     163             :     int ret;
     164             : 
     165        2007 :     ret = krb5_config_get_time (context, NULL,
     166             :                                 "realms",
     167             :                                 realm,
     168             :                                 name,
     169             :                                 NULL);
     170        2007 :     if (ret >= 0)
     171           0 :         return ret;
     172        2007 :     ret = krb5_config_get_time (context, NULL,
     173             :                                 "libdefaults",
     174             :                                 name,
     175             :                                 NULL);
     176        2007 :     if (ret >= 0)
     177           0 :         return ret;
     178        2007 :     return def;
     179             : }
     180             : 
     181             : static krb5_error_code
     182       22093 : init_cred (krb5_context context,
     183             :            krb5_creds *cred,
     184             :            krb5_principal client,
     185             :            krb5_deltat start_time,
     186             :            krb5_get_init_creds_opt *options)
     187             : {
     188             :     krb5_error_code ret;
     189             :     int tmp;
     190             :     krb5_timestamp now;
     191             : 
     192       22093 :     krb5_timeofday (context, &now);
     193             : 
     194       22093 :     memset (cred, 0, sizeof(*cred));
     195             : 
     196       22093 :     if (client)
     197       22093 :         krb5_copy_principal(context, client, &cred->client);
     198             :     else {
     199           0 :         ret = krb5_get_default_principal (context,
     200             :                                           &cred->client);
     201           0 :         if (ret)
     202           0 :             goto out;
     203             :     }
     204             : 
     205       22093 :     if (start_time)
     206           0 :         cred->times.starttime  = now + start_time;
     207             : 
     208       22093 :     if (options->flags & KRB5_GET_INIT_CREDS_OPT_TKT_LIFE)
     209        9862 :         tmp = options->tkt_life;
     210             :     else
     211       12231 :         tmp = 10 * 60 * 60;
     212       22093 :     cred->times.endtime = now + tmp;
     213             : 
     214       29971 :     if ((options->flags & KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE) &&
     215        7878 :         options->renew_life > 0) {
     216          49 :         cred->times.renew_till = now + options->renew_life;
     217             :     }
     218             : 
     219       21798 :     return 0;
     220             : 
     221           0 : out:
     222           0 :     krb5_free_cred_contents (context, cred);
     223           0 :     return ret;
     224             : }
     225             : 
     226             : /*
     227             :  * Print a message (str) to the user about the expiration in `lr'
     228             :  */
     229             : 
     230             : static void
     231           4 : report_expiration (krb5_context context,
     232             :                    krb5_prompter_fct prompter,
     233             :                    krb5_data *data,
     234             :                    const char *str,
     235             :                    time_t now)
     236             : {
     237           4 :     char *p = NULL;
     238             : 
     239           4 :     if (asprintf(&p, "%s%s", str, ctime(&now)) < 0 || p == NULL)
     240           0 :         return;
     241           4 :     (*prompter)(context, data, NULL, p, 0, NULL);
     242           4 :     free(p);
     243             : }
     244             : 
     245             : /*
     246             :  * Check the context, and in the case there is a expiration warning,
     247             :  * use the prompter to print the warning.
     248             :  *
     249             :  * @param context A Kerberos 5 context.
     250             :  * @param options An GIC options structure
     251             :  * @param ctx The krb5_init_creds_context check for expiration.
     252             :  */
     253             : 
     254             : static krb5_error_code
     255       13985 : process_last_request(krb5_context context,
     256             :                      krb5_get_init_creds_opt *options,
     257             :                      krb5_init_creds_context ctx)
     258             : {
     259             :     krb5_const_realm realm;
     260             :     LastReq *lr;
     261       13985 :     krb5_boolean reported = FALSE;
     262             :     krb5_timestamp sec;
     263             :     time_t t;
     264             :     size_t i;
     265             : 
     266             :     /*
     267             :      * First check if there is a API consumer.
     268             :      */
     269             : 
     270       13985 :     realm = krb5_principal_get_realm (context, ctx->cred.client);
     271       13985 :     lr = &ctx->enc_part.last_req;
     272             : 
     273       13985 :     if (options && options->opt_private && options->opt_private->lr.func) {
     274             :         krb5_last_req_entry **lre;
     275             : 
     276           0 :         lre = calloc(lr->len + 1, sizeof(**lre));
     277           0 :         if (lre == NULL) {
     278           0 :             krb5_set_error_message(context, ENOMEM,
     279           0 :                                    N_("malloc: out of memory", ""));
     280           0 :             return ENOMEM;
     281             :         }
     282           0 :         for (i = 0; i < lr->len; i++) {
     283           0 :             lre[i] = calloc(1, sizeof(*lre[i]));
     284           0 :             if (lre[i] == NULL)
     285           0 :                 break;
     286           0 :             lre[i]->lr_type = lr->val[i].lr_type;
     287           0 :             lre[i]->value = lr->val[i].lr_value;
     288             :         }
     289             : 
     290           0 :         (*options->opt_private->lr.func)(context, lre,
     291           0 :                                          options->opt_private->lr.ctx);
     292             : 
     293           0 :         for (i = 0; i < lr->len; i++)
     294           0 :             free(lre[i]);
     295           0 :         free(lre);
     296             :     }
     297             : 
     298             :     /*
     299             :      * Now check if we should prompt the user
     300             :      */
     301             : 
     302       13985 :     if (ctx->prompter == NULL)
     303       11683 :         return 0;
     304             : 
     305        2007 :     krb5_timeofday (context, &sec);
     306             : 
     307        2007 :     t = sec + get_config_time (context,
     308             :                                realm,
     309             :                                "warn_pwexpire",
     310             :                                7 * 24 * 60 * 60);
     311             : 
     312        4014 :     for (i = 0; i < lr->len; ++i) {
     313        2007 :         if (lr->val[i].lr_value <= t) {
     314         855 :             switch (abs(lr->val[i].lr_type)) {
     315           4 :             case LR_PW_EXPTIME :
     316           8 :                 report_expiration(context, ctx->prompter,
     317           4 :                                   ctx->prompter_data,
     318             :                                   "Your password will expire at ",
     319           4 :                                   lr->val[i].lr_value);
     320           4 :                 reported = TRUE;
     321           4 :                 break;
     322           0 :             case LR_ACCT_EXPTIME :
     323           0 :                 report_expiration(context, ctx->prompter,
     324           0 :                                   ctx->prompter_data,
     325             :                                   "Your account will expire at ",
     326           0 :                                   lr->val[i].lr_value);
     327           0 :                 reported = TRUE;
     328           0 :                 break;
     329             :             }
     330             :         }
     331             :     }
     332             : 
     333        2007 :     if (!reported
     334        2003 :         && ctx->enc_part.key_expiration
     335        1152 :         && *ctx->enc_part.key_expiration <= t) {
     336           0 :         report_expiration(context, ctx->prompter,
     337           0 :                           ctx->prompter_data,
     338             :                           "Your password/account will expire at ",
     339           0 :                           *ctx->enc_part.key_expiration);
     340             :     }
     341        2007 :     return 0;
     342             : }
     343             : 
     344             : static krb5_addresses no_addrs = { 0, NULL };
     345             : 
     346             : static krb5_error_code
     347       22093 : get_init_creds_common(krb5_context context,
     348             :                       krb5_principal client,
     349             :                       krb5_deltat start_time,
     350             :                       krb5_get_init_creds_opt *options,
     351             :                       krb5_init_creds_context ctx)
     352             : {
     353       22093 :     krb5_get_init_creds_opt *default_opt = NULL;
     354             :     krb5_error_code ret;
     355             :     krb5_enctype *etypes;
     356             :     krb5_preauthtype *pre_auth_types;
     357             : 
     358       22093 :     memset(ctx, 0, sizeof(*ctx));
     359             : 
     360       22093 :     if (options == NULL) {
     361          48 :         const char *realm = krb5_principal_get_realm(context, client);
     362             : 
     363          48 :         krb5_get_init_creds_opt_alloc (context, &default_opt);
     364          48 :         options = default_opt;
     365          48 :         krb5_get_init_creds_opt_set_default_flags(context, NULL, realm, options);
     366             :     }
     367             : 
     368       22093 :     if (options->opt_private) {
     369       22093 :         if (options->opt_private->password) {
     370           0 :             ret = krb5_init_creds_set_password(context, ctx,
     371           0 :                                                options->opt_private->password);
     372           0 :             if (ret)
     373           0 :                 goto out;
     374             :         }
     375             : 
     376       22093 :         ctx->keyproc = options->opt_private->key_proc;
     377       22093 :         ctx->req_pac = options->opt_private->req_pac;
     378       22093 :         ctx->pk_init_ctx = options->opt_private->pk_init_ctx;
     379       22093 :         ctx->ic_flags = options->opt_private->flags;
     380             :     } else
     381           0 :         ctx->req_pac = KRB5_INIT_CREDS_TRISTATE_UNSET;
     382             : 
     383       22093 :     if (ctx->keyproc == NULL)
     384       22093 :         ctx->keyproc = default_s2k_func;
     385             : 
     386             :     /* Enterprise name implicitly turns on canonicalize */
     387       24709 :     if ((ctx->ic_flags & KRB5_INIT_CREDS_CANONICALIZE) ||
     388        2616 :         krb5_principal_get_type(context, client) == KRB5_NT_ENTERPRISE_PRINCIPAL)
     389       20678 :         ctx->flags.canonicalize = 1;
     390             : 
     391       22093 :     ctx->pre_auth_types = NULL;
     392       22093 :     ctx->addrs = NULL;
     393       22093 :     ctx->etypes = NULL;
     394       21798 :     ctx->pre_auth_types = NULL;
     395             : 
     396       22093 :     ret = init_cred(context, &ctx->cred, client, start_time, options);
     397       22093 :     if (ret) {
     398           0 :         if (default_opt)
     399           0 :             krb5_get_init_creds_opt_free(context, default_opt);
     400           0 :         return ret;
     401             :     }
     402             : 
     403       22093 :     ret = krb5_init_creds_set_service(context, ctx, NULL);
     404       22093 :     if (ret)
     405           0 :         goto out;
     406             : 
     407       22093 :     if (options->flags & KRB5_GET_INIT_CREDS_OPT_FORWARDABLE)
     408       17688 :         ctx->flags.forwardable = options->forwardable;
     409             : 
     410       22093 :     if (options->flags & KRB5_GET_INIT_CREDS_OPT_PROXIABLE)
     411        9862 :         ctx->flags.proxiable = options->proxiable;
     412             : 
     413       22093 :     if (start_time)
     414           0 :         ctx->flags.postdated = 1;
     415       22093 :     if (ctx->cred.times.renew_till)
     416          49 :         ctx->flags.renewable = 1;
     417       22093 :     if (options->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST) {
     418           3 :         ctx->addrs = options->address_list;
     419       22090 :     } else if (options->opt_private) {
     420       22090 :         switch (options->opt_private->addressless) {
     421       12241 :         case KRB5_INIT_CREDS_TRISTATE_UNSET:
     422             : #if KRB5_ADDRESSLESS_DEFAULT == TRUE
     423       12241 :             ctx->addrs = &no_addrs;
     424             : #else
     425             :             ctx->addrs = NULL;
     426             : #endif
     427       12241 :             break;
     428           0 :         case KRB5_INIT_CREDS_TRISTATE_FALSE:
     429           0 :             ctx->addrs = NULL;
     430           0 :             break;
     431        9849 :         case KRB5_INIT_CREDS_TRISTATE_TRUE:
     432        9849 :             ctx->addrs = &no_addrs;
     433        9849 :             break;
     434             :         }
     435             :     }
     436       22093 :     if (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST) {
     437         134 :         if (ctx->etypes)
     438           0 :             free(ctx->etypes);
     439             : 
     440         134 :         etypes = malloc((options->etype_list_length + 1)
     441             :                         * sizeof(krb5_enctype));
     442         134 :         if (etypes == NULL) {
     443           0 :             ret = ENOMEM;
     444           0 :             krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
     445           0 :             goto out;
     446             :         }
     447         134 :         memcpy (etypes, options->etype_list,
     448         134 :                 options->etype_list_length * sizeof(krb5_enctype));
     449         134 :         etypes[options->etype_list_length] = ETYPE_NULL;
     450         134 :         ctx->etypes = etypes;
     451             :     }
     452       22093 :     if (options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST) {
     453           0 :         pre_auth_types = malloc((options->preauth_list_length + 1)
     454             :                                 * sizeof(krb5_preauthtype));
     455           0 :         if (pre_auth_types == NULL) {
     456           0 :             ret = ENOMEM;
     457           0 :             krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
     458           0 :             goto out;
     459             :         }
     460           0 :         memcpy (pre_auth_types, options->preauth_list,
     461           0 :                 options->preauth_list_length * sizeof(krb5_preauthtype));
     462           0 :         pre_auth_types[options->preauth_list_length] = KRB5_PADATA_NONE;
     463           0 :         ctx->pre_auth_types = pre_auth_types;
     464             :     }
     465       22093 :     if (options->flags & KRB5_GET_INIT_CREDS_OPT_ANONYMOUS)
     466           0 :         ctx->flags.request_anonymous = options->anonymous;
     467       22093 :     if (default_opt)
     468          48 :         krb5_get_init_creds_opt_free(context, default_opt);
     469       21798 :     return 0;
     470           0 :  out:
     471           0 :     if (default_opt)
     472           0 :         krb5_get_init_creds_opt_free(context, default_opt);
     473           0 :     return ret;
     474             : }
     475             : 
     476             : static krb5_error_code
     477           4 : change_password (krb5_context context,
     478             :                  krb5_principal client,
     479             :                  const char *password,
     480             :                  char *newpw,
     481             :                  size_t newpw_sz,
     482             :                  krb5_prompter_fct prompter,
     483             :                  void *data,
     484             :                  krb5_get_init_creds_opt *old_options)
     485             : {
     486             :     krb5_prompt prompts[2];
     487             :     krb5_error_code ret;
     488             :     krb5_creds cpw_cred;
     489             :     char buf1[BUFSIZ], buf2[BUFSIZ];
     490             :     krb5_data password_data[2];
     491             :     int result_code;
     492             :     krb5_data result_code_string;
     493             :     krb5_data result_string;
     494             :     char *p;
     495             :     krb5_get_init_creds_opt *options;
     496             : 
     497           4 :     memset (&cpw_cred, 0, sizeof(cpw_cred));
     498             : 
     499           4 :     ret = krb5_get_init_creds_opt_alloc(context, &options);
     500           4 :     if (ret)
     501           0 :         return ret;
     502           4 :     krb5_get_init_creds_opt_set_tkt_life (options, 60);
     503           4 :     krb5_get_init_creds_opt_set_forwardable (options, FALSE);
     504           4 :     krb5_get_init_creds_opt_set_proxiable (options, FALSE);
     505           4 :     if (old_options && old_options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST)
     506           0 :         krb5_get_init_creds_opt_set_preauth_list (options,
     507             :                                                   old_options->preauth_list,
     508             :                                                   old_options->preauth_list_length);
     509             : 
     510           4 :     krb5_data_zero (&result_code_string);
     511           4 :     krb5_data_zero (&result_string);
     512             : 
     513           4 :     ret = krb5_get_init_creds_password (context,
     514             :                                         &cpw_cred,
     515             :                                         client,
     516             :                                         password,
     517             :                                         prompter,
     518             :                                         data,
     519             :                                         0,
     520             :                                         "kadmin/changepw",
     521             :                                         options);
     522           4 :     krb5_get_init_creds_opt_free(context, options);
     523           4 :     if (ret)
     524           0 :         goto out;
     525             : 
     526             :     for(;;) {
     527           4 :         password_data[0].data   = buf1;
     528           4 :         password_data[0].length = sizeof(buf1);
     529             : 
     530           4 :         prompts[0].hidden = 1;
     531           4 :         prompts[0].prompt = "New password: ";
     532           4 :         prompts[0].reply  = &password_data[0];
     533           4 :         prompts[0].type   = KRB5_PROMPT_TYPE_NEW_PASSWORD;
     534             : 
     535           4 :         password_data[1].data   = buf2;
     536           4 :         password_data[1].length = sizeof(buf2);
     537             : 
     538           4 :         prompts[1].hidden = 1;
     539           4 :         prompts[1].prompt = "Repeat new password: ";
     540           4 :         prompts[1].reply  = &password_data[1];
     541           4 :         prompts[1].type   = KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN;
     542             : 
     543           4 :         ret = (*prompter) (context, data, NULL, "Changing password",
     544             :                            2, prompts);
     545           4 :         if (ret) {
     546           0 :             memset (buf1, 0, sizeof(buf1));
     547           0 :             memset (buf2, 0, sizeof(buf2));
     548           0 :             goto out;
     549             :         }
     550             : 
     551           4 :         if (strcmp (buf1, buf2) == 0)
     552           4 :             break;
     553           0 :         memset (buf1, 0, sizeof(buf1));
     554           0 :         memset (buf2, 0, sizeof(buf2));
     555             :     }
     556             : 
     557           4 :     ret = krb5_set_password (context,
     558             :                              &cpw_cred,
     559             :                              buf1,
     560             :                              client,
     561             :                              &result_code,
     562             :                              &result_code_string,
     563             :                              &result_string);
     564           4 :     if (ret)
     565           0 :         goto out;
     566          12 :     if (asprintf(&p, "%s: %.*s\n",
     567           4 :                  result_code ? "Error" : "Success",
     568           4 :                  (int)result_string.length,
     569           4 :                  result_string.length > 0 ? (char*)result_string.data : "") < 0)
     570             :     {
     571           0 :         ret = ENOMEM;
     572           0 :         goto out;
     573             :     }
     574             : 
     575             :     /* return the result */
     576           4 :     (*prompter) (context, data, NULL, p, 0, NULL);
     577             : 
     578           4 :     free (p);
     579           4 :     if (result_code == 0) {
     580           4 :         strlcpy (newpw, buf1, newpw_sz);
     581           4 :         ret = 0;
     582             :     } else {
     583           0 :         ret = ENOTTY;
     584           0 :         krb5_set_error_message(context, ret,
     585           0 :                                N_("failed changing password", ""));
     586             :     }
     587             : 
     588           4 : out:
     589           4 :     memset (buf1, 0, sizeof(buf1));
     590           4 :     memset (buf2, 0, sizeof(buf2));
     591           4 :     krb5_data_free (&result_string);
     592           4 :     krb5_data_free (&result_code_string);
     593           4 :     krb5_free_cred_contents (context, &cpw_cred);
     594           4 :     return ret;
     595             : }
     596             : 
     597             : 
     598             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
     599           0 : krb5_keyblock_key_proc (krb5_context context,
     600             :                         krb5_keytype type,
     601             :                         krb5_data *salt,
     602             :                         krb5_const_pointer keyseed,
     603             :                         krb5_keyblock **key)
     604             : {
     605           0 :     return krb5_copy_keyblock (context, keyseed, key);
     606             : }
     607             : 
     608             : /*
     609             :  *
     610             :  */
     611             : 
     612             : static krb5_error_code
     613       22349 : init_as_req (krb5_context context,
     614             :              KDCOptions opts,
     615             :              const krb5_creds *creds,
     616             :              const krb5_addresses *addrs,
     617             :              const krb5_enctype *etypes,
     618             :              AS_REQ *a)
     619             : {
     620             :     krb5_error_code ret;
     621             : 
     622       22349 :     memset(a, 0, sizeof(*a));
     623             : 
     624       22349 :     a->pvno = 5;
     625       22349 :     a->msg_type = krb_as_req;
     626       22349 :     a->req_body.kdc_options = opts;
     627       22349 :     a->req_body.cname = malloc(sizeof(*a->req_body.cname));
     628       22349 :     if (a->req_body.cname == NULL) {
     629           0 :         ret = ENOMEM;
     630           0 :         krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
     631           0 :         goto fail;
     632             :     }
     633       22349 :     a->req_body.sname = malloc(sizeof(*a->req_body.sname));
     634       22349 :     if (a->req_body.sname == NULL) {
     635           0 :         ret = ENOMEM;
     636           0 :         krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
     637           0 :         goto fail;
     638             :     }
     639             : 
     640       22349 :     ret = _krb5_principal2principalname (a->req_body.cname, creds->client);
     641       22349 :     if (ret)
     642           0 :         goto fail;
     643       22349 :     ret = copy_Realm(&creds->client->realm, &a->req_body.realm);
     644       22349 :     if (ret)
     645           0 :         goto fail;
     646             : 
     647       22349 :     ret = _krb5_principal2principalname (a->req_body.sname, creds->server);
     648       22349 :     if (ret)
     649           0 :         goto fail;
     650             : 
     651       22349 :     if(creds->times.starttime) {
     652           0 :         a->req_body.from = malloc(sizeof(*a->req_body.from));
     653           0 :         if (a->req_body.from == NULL) {
     654           0 :             ret = ENOMEM;
     655           0 :             krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
     656           0 :             goto fail;
     657             :         }
     658           0 :         *a->req_body.from = creds->times.starttime;
     659             :     }
     660       22349 :     if(creds->times.endtime){
     661       22349 :         ALLOC(a->req_body.till, 1);
     662       22349 :         *a->req_body.till = creds->times.endtime;
     663             :     }
     664       22349 :     if(creds->times.renew_till){
     665          49 :         a->req_body.rtime = malloc(sizeof(*a->req_body.rtime));
     666          49 :         if (a->req_body.rtime == NULL) {
     667           0 :             ret = ENOMEM;
     668           0 :             krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
     669           0 :             goto fail;
     670             :         }
     671          49 :         *a->req_body.rtime = creds->times.renew_till;
     672             :     }
     673       22349 :     a->req_body.nonce = 0;
     674       22349 :     ret = _krb5_init_etype(context,
     675             :                            KRB5_PDU_AS_REQUEST,
     676             :                            &a->req_body.etype.len,
     677       22349 :                            &a->req_body.etype.val,
     678             :                            etypes);
     679       22349 :     if (ret)
     680           0 :         goto fail;
     681             : 
     682             :     /*
     683             :      * This means no addresses
     684             :      */
     685             : 
     686       22349 :     if (addrs && addrs->len == 0) {
     687       22346 :         a->req_body.addresses = NULL;
     688             :     } else {
     689           3 :         a->req_body.addresses = malloc(sizeof(*a->req_body.addresses));
     690           3 :         if (a->req_body.addresses == NULL) {
     691           0 :             ret = ENOMEM;
     692           0 :             krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
     693           0 :             goto fail;
     694             :         }
     695             : 
     696           3 :         if (addrs)
     697           3 :             ret = krb5_copy_addresses(context, addrs, a->req_body.addresses);
     698             :         else {
     699           0 :             ret = krb5_get_all_client_addrs (context, a->req_body.addresses);
     700           0 :             if(ret == 0 && a->req_body.addresses->len == 0) {
     701           0 :                 free(a->req_body.addresses);
     702           0 :                 a->req_body.addresses = NULL;
     703             :             }
     704             :         }
     705           3 :         if (ret)
     706           0 :             goto fail;
     707             :     }
     708             : 
     709       22349 :     a->req_body.enc_authorization_data = NULL;
     710       22349 :     a->req_body.additional_tickets = NULL;
     711             : 
     712       22349 :     a->padata = NULL;
     713             : 
     714       22349 :     return 0;
     715           0 :  fail:
     716           0 :     free_AS_REQ(a);
     717           0 :     memset(a, 0, sizeof(*a));
     718           0 :     return ret;
     719             : }
     720             : 
     721             : 
     722             : static krb5_error_code
     723       23396 : set_paid(struct pa_info_data *paid, krb5_context context,
     724             :          krb5_enctype etype,
     725             :          krb5_salttype salttype, void *salt_string, size_t salt_len,
     726             :          krb5_data *s2kparams)
     727             : {
     728       23396 :     paid->etype = etype;
     729       23396 :     paid->salt.salttype = salttype;
     730       23396 :     paid->salt.saltvalue.data = malloc(salt_len + 1);
     731       23396 :     if (paid->salt.saltvalue.data == NULL) {
     732           0 :         krb5_clear_error_message(context);
     733           0 :         return ENOMEM;
     734             :     }
     735       23904 :     memcpy(paid->salt.saltvalue.data, salt_string, salt_len);
     736       23396 :     ((char *)paid->salt.saltvalue.data)[salt_len] = '\0';
     737       23396 :     paid->salt.saltvalue.length = salt_len;
     738       23396 :     if (s2kparams) {
     739             :         krb5_error_code ret;
     740             : 
     741        9342 :         ret = krb5_copy_data(context, s2kparams, &paid->s2kparams);
     742        9342 :         if (ret) {
     743           0 :             krb5_clear_error_message(context);
     744           0 :             krb5_free_salt(context, paid->salt);
     745           0 :             return ret;
     746             :         }
     747             :     } else
     748       14054 :         paid->s2kparams = NULL;
     749             : 
     750       22888 :     return 0;
     751             : }
     752             : 
     753             : static struct pa_info_data *
     754       14238 : pa_etype_info2(krb5_context context,
     755             :                const krb5_principal client,
     756             :                const AS_REQ *asreq,
     757             :                struct pa_info_data *paid,
     758             :                heim_octet_string *data)
     759             : {
     760             :     krb5_error_code ret;
     761             :     ETYPE_INFO2 e;
     762             :     size_t sz;
     763             :     size_t i, j;
     764             : 
     765       14238 :     memset(&e, 0, sizeof(e));
     766       14238 :     ret = decode_ETYPE_INFO2(data->data, data->length, &e, &sz);
     767       14238 :     if (ret)
     768           0 :         goto out;
     769       14238 :     if (e.len == 0)
     770           0 :         goto out;
     771       30454 :     for (j = 0; j < asreq->req_body.etype.len; j++) {
     772       46637 :         for (i = 0; i < e.len; i++) {
     773       30749 :             if (asreq->req_body.etype.val[j] == e.val[i].etype) {
     774             :                 krb5_salt salt;
     775       14238 :                 if (e.val[i].salt == NULL)
     776        4912 :                     ret = krb5_get_pw_salt(context, client, &salt);
     777             :                 else {
     778        9326 :                     salt.saltvalue.data = *e.val[i].salt;
     779        9326 :                     salt.saltvalue.length = strlen(*e.val[i].salt);
     780        9326 :                     ret = 0;
     781             :                 }
     782       14025 :                 if (ret == 0)
     783       14238 :                     ret = set_paid(paid, context, e.val[i].etype,
     784             :                                    KRB5_PW_SALT,
     785             :                                    salt.saltvalue.data,
     786             :                                    salt.saltvalue.length,
     787       14238 :                                    e.val[i].s2kparams);
     788       14238 :                 if (e.val[i].salt == NULL)
     789        4912 :                     krb5_free_salt(context, salt);
     790       14238 :                 if (ret == 0) {
     791       14238 :                     free_ETYPE_INFO2(&e);
     792       14238 :                     return paid;
     793             :                 }
     794             :             }
     795             :         }
     796             :     }
     797           0 :  out:
     798           0 :     free_ETYPE_INFO2(&e);
     799           0 :     return NULL;
     800             : }
     801             : 
     802             : static struct pa_info_data *
     803           0 : pa_etype_info(krb5_context context,
     804             :               const krb5_principal client,
     805             :               const AS_REQ *asreq,
     806             :               struct pa_info_data *paid,
     807             :               heim_octet_string *data)
     808             : {
     809             :     krb5_error_code ret;
     810             :     ETYPE_INFO e;
     811             :     size_t sz;
     812             :     size_t i, j;
     813             : 
     814           0 :     memset(&e, 0, sizeof(e));
     815           0 :     ret = decode_ETYPE_INFO(data->data, data->length, &e, &sz);
     816           0 :     if (ret)
     817           0 :         goto out;
     818           0 :     if (e.len == 0)
     819           0 :         goto out;
     820           0 :     for (j = 0; j < asreq->req_body.etype.len; j++) {
     821           0 :         for (i = 0; i < e.len; i++) {
     822           0 :             if (asreq->req_body.etype.val[j] == e.val[i].etype) {
     823             :                 krb5_salt salt;
     824           0 :                 salt.salttype = KRB5_PW_SALT;
     825           0 :                 if (e.val[i].salt == NULL)
     826           0 :                     ret = krb5_get_pw_salt(context, client, &salt);
     827             :                 else {
     828           0 :                     salt.saltvalue = *e.val[i].salt;
     829           0 :                     ret = 0;
     830             :                 }
     831           0 :                 if (e.val[i].salttype)
     832           0 :                     salt.salttype = *e.val[i].salttype;
     833           0 :                 if (ret == 0) {
     834           0 :                     ret = set_paid(paid, context, e.val[i].etype,
     835             :                                    salt.salttype,
     836             :                                    salt.saltvalue.data,
     837             :                                    salt.saltvalue.length,
     838             :                                    NULL);
     839           0 :                     if (e.val[i].salt == NULL)
     840           0 :                         krb5_free_salt(context, salt);
     841             :                 }
     842           0 :                 if (ret == 0) {
     843           0 :                     free_ETYPE_INFO(&e);
     844           0 :                     return paid;
     845             :                 }
     846             :             }
     847             :         }
     848             :     }
     849           0 :  out:
     850           0 :     free_ETYPE_INFO(&e);
     851           0 :     return NULL;
     852             : }
     853             : 
     854             : static struct pa_info_data *
     855        9158 : pa_pw_or_afs3_salt(krb5_context context,
     856             :                    const krb5_principal client,
     857             :                    const AS_REQ *asreq,
     858             :                    struct pa_info_data *paid,
     859             :                    heim_octet_string *data)
     860             : {
     861             :     krb5_error_code ret;
     862        9158 :     if (paid->etype == KRB5_ENCTYPE_NULL)
     863           0 :         return NULL;
     864        9158 :     ret = set_paid(paid, context,
     865             :                    paid->etype,
     866             :                    paid->salt.salttype,
     867             :                    data->data,
     868             :                    data->length,
     869             :                    NULL);
     870        9158 :     if (ret)
     871           0 :         return NULL;
     872        9158 :     return paid;
     873             : }
     874             : 
     875             : 
     876             : struct pa_info {
     877             :     krb5_preauthtype type;
     878             :     struct pa_info_data *(*salt_info)(krb5_context,
     879             :                                       const krb5_principal,
     880             :                                       const AS_REQ *,
     881             :                                       struct pa_info_data *,
     882             :                                       heim_octet_string *);
     883             : };
     884             : 
     885             : static struct pa_info pa_prefs[] = {
     886             :     { KRB5_PADATA_ETYPE_INFO2, pa_etype_info2 },
     887             :     { KRB5_PADATA_ETYPE_INFO, pa_etype_info },
     888             :     { KRB5_PADATA_PW_SALT, pa_pw_or_afs3_salt },
     889             :     { KRB5_PADATA_AFS3_SALT, pa_pw_or_afs3_salt }
     890             : };
     891             : 
     892             : static PA_DATA *
     893       40882 : find_pa_data(const METHOD_DATA *md, unsigned type)
     894             : {
     895             :     size_t i;
     896       41816 :     if (md == NULL)
     897           0 :         return NULL;
     898      106912 :     for (i = 0; i < md->len; i++)
     899       89426 :         if (md->val[i].padata_type == type)
     900       22888 :             return &md->val[i];
     901       17994 :     return NULL;
     902             : }
     903             : 
     904             : static struct pa_info_data *
     905       23422 : process_pa_info(krb5_context context,
     906             :                 const krb5_principal client,
     907             :                 const AS_REQ *asreq,
     908             :                 struct pa_info_data *paid,
     909             :                 METHOD_DATA *md)
     910             : {
     911       23422 :     struct pa_info_data *p = NULL;
     912             :     size_t i;
     913             : 
     914       65238 :     for (i = 0; p == NULL && i < sizeof(pa_prefs)/sizeof(pa_prefs[0]); i++) {
     915       42750 :         PA_DATA *pa = find_pa_data(md, pa_prefs[i].type);
     916       41816 :         if (pa == NULL)
     917       18420 :             continue;
     918       23396 :         paid->salt.salttype = (krb5_salttype)pa_prefs[i].type;
     919       23396 :         p = (*pa_prefs[i].salt_info)(context, client, asreq,
     920             :                                      paid, &pa->padata_value);
     921             :     }
     922       23422 :     return p;
     923             : }
     924             : 
     925             : static krb5_error_code
     926       14238 : make_pa_enc_timestamp(krb5_context context, METHOD_DATA *md,
     927             :                       krb5_enctype etype, krb5_keyblock *key)
     928             : {
     929             :     PA_ENC_TS_ENC p;
     930             :     unsigned char *buf;
     931             :     size_t buf_size;
     932       14238 :     size_t len = 0;
     933             :     EncryptedData encdata;
     934             :     krb5_error_code ret;
     935             :     int32_t usec;
     936             :     int usec2;
     937             :     krb5_crypto crypto;
     938             : 
     939       14238 :     krb5_us_timeofday (context, &p.patimestamp, &usec);
     940       14238 :     usec2         = usec;
     941       14238 :     p.pausec      = &usec2;
     942             : 
     943       14238 :     ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC, buf, buf_size, &p, &len, ret);
     944       14238 :     if (ret)
     945           0 :         return ret;
     946       14238 :     if(buf_size != len)
     947           0 :         krb5_abortx(context, "internal error in ASN.1 encoder");
     948             : 
     949       14238 :     ret = krb5_crypto_init(context, key, 0, &crypto);
     950       14238 :     if (ret) {
     951           0 :         free(buf);
     952           0 :         return ret;
     953             :     }
     954       14238 :     ret = krb5_encrypt_EncryptedData(context,
     955             :                                      crypto,
     956             :                                      KRB5_KU_PA_ENC_TIMESTAMP,
     957             :                                      buf,
     958             :                                      len,
     959             :                                      0,
     960             :                                      &encdata);
     961       14238 :     free(buf);
     962       14238 :     krb5_crypto_destroy(context, crypto);
     963       14238 :     if (ret)
     964           0 :         return ret;
     965             : 
     966       14238 :     ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_size, &encdata, &len, ret);
     967       14238 :     free_EncryptedData(&encdata);
     968       14238 :     if (ret)
     969           0 :         return ret;
     970       14238 :     if(buf_size != len)
     971           0 :         krb5_abortx(context, "internal error in ASN.1 encoder");
     972             : 
     973       14238 :     ret = krb5_padata_add(context, md, KRB5_PADATA_ENC_TIMESTAMP, buf, len);
     974       14238 :     if (ret)
     975           0 :         free(buf);
     976       13943 :     return ret;
     977             : }
     978             : 
     979             : static krb5_error_code
     980       14238 : add_enc_ts_padata(krb5_context context,
     981             :                   METHOD_DATA *md,
     982             :                   krb5_principal client,
     983             :                   krb5_s2k_proc keyproc,
     984             :                   krb5_const_pointer keyseed,
     985             :                   krb5_enctype *enctypes,
     986             :                   unsigned netypes,
     987             :                   krb5_salt *salt,
     988             :                   krb5_data *s2kparams)
     989             : {
     990             :     krb5_error_code ret;
     991             :     krb5_salt salt2;
     992             :     krb5_enctype *ep;
     993             :     size_t i;
     994             : 
     995       14238 :     if(salt == NULL) {
     996             :         /* default to standard salt */
     997           0 :         ret = krb5_get_pw_salt (context, client, &salt2);
     998           0 :         if (ret)
     999           0 :             return ret;
    1000           0 :         salt = &salt2;
    1001             :     }
    1002       14238 :     if (!enctypes) {
    1003           0 :         enctypes = context->etypes;
    1004           0 :         netypes = 0;
    1005           0 :         for (ep = enctypes; *ep != ETYPE_NULL; ep++)
    1006           0 :             netypes++;
    1007             :     }
    1008             : 
    1009       28476 :     for (i = 0; i < netypes; ++i) {
    1010             :         krb5_keyblock *key;
    1011             : 
    1012       14238 :         _krb5_debug(context, 5, "krb5_get_init_creds: using ENC-TS with enctype %d", enctypes[i]);
    1013             : 
    1014       14238 :         ret = (*keyproc)(context, enctypes[i], keyseed,
    1015             :                          *salt, s2kparams, &key);
    1016       14238 :         if (ret)
    1017           0 :             continue;
    1018       14238 :         ret = make_pa_enc_timestamp (context, md, enctypes[i], key);
    1019       14238 :         krb5_free_keyblock (context, key);
    1020       14238 :         if (ret)
    1021           0 :             return ret;
    1022             :     }
    1023       14238 :     if(salt == &salt2)
    1024           0 :         krb5_free_salt(context, salt2);
    1025       13943 :     return 0;
    1026             : }
    1027             : 
    1028             : static krb5_error_code
    1029       14238 : pa_data_to_md_ts_enc(krb5_context context,
    1030             :                      const AS_REQ *a,
    1031             :                      const krb5_principal client,
    1032             :                      krb5_get_init_creds_ctx *ctx,
    1033             :                      struct pa_info_data *ppaid,
    1034             :                      METHOD_DATA *md)
    1035             : {
    1036       14238 :     if (ctx->keyproc == NULL || ctx->keyseed == NULL)
    1037           0 :         return 0;
    1038             : 
    1039       14238 :     if (ppaid) {
    1040       28181 :         add_enc_ts_padata(context, md, client,
    1041       13943 :                           ctx->keyproc, ctx->keyseed,
    1042             :                           &ppaid->etype, 1,
    1043             :                           &ppaid->salt, ppaid->s2kparams);
    1044             :     } else {
    1045             :         krb5_salt salt;
    1046             : 
    1047           0 :         _krb5_debug(context, 5, "krb5_get_init_creds: pa-info not found, guessing salt");
    1048             : 
    1049             :         /* make a v5 salted pa-data */
    1050           0 :         add_enc_ts_padata(context, md, client,
    1051           0 :                           ctx->keyproc, ctx->keyseed,
    1052           0 :                           a->req_body.etype.val, a->req_body.etype.len,
    1053             :                           NULL, NULL);
    1054             : 
    1055             :         /* make a v4 salted pa-data */
    1056           0 :         salt.salttype = KRB5_PW_SALT;
    1057           0 :         krb5_data_zero(&salt.saltvalue);
    1058           0 :         add_enc_ts_padata(context, md, client,
    1059           0 :                           ctx->keyproc, ctx->keyseed,
    1060           0 :                           a->req_body.etype.val, a->req_body.etype.len,
    1061             :                           &salt, NULL);
    1062             :     }
    1063       13943 :     return 0;
    1064             : }
    1065             : 
    1066             : static krb5_error_code
    1067       13664 : pa_data_to_key_plain(krb5_context context,
    1068             :                      const krb5_principal client,
    1069             :                      krb5_get_init_creds_ctx *ctx,
    1070             :                      krb5_salt salt,
    1071             :                      krb5_data *s2kparams,
    1072             :                      krb5_enctype etype,
    1073             :                      krb5_keyblock **key)
    1074             : {
    1075             :     krb5_error_code ret;
    1076             : 
    1077       13959 :     ret = (*ctx->keyproc)(context, etype, ctx->keyseed,
    1078             :                            salt, s2kparams, key);
    1079       13664 :     return ret;
    1080             : }
    1081             : 
    1082             : 
    1083             : static krb5_error_code
    1084          40 : pa_data_to_md_pkinit(krb5_context context,
    1085             :                      const AS_REQ *a,
    1086             :                      const krb5_principal client,
    1087             :                      int win2k,
    1088             :                      krb5_get_init_creds_ctx *ctx,
    1089             :                      METHOD_DATA *md)
    1090             : {
    1091          40 :     if (ctx->pk_init_ctx == NULL)
    1092           0 :         return 0;
    1093             : #ifdef PKINIT
    1094          80 :     return _krb5_pk_mk_padata(context,
    1095          40 :                               ctx->pk_init_ctx,
    1096             :                               ctx->ic_flags,
    1097             :                               win2k,
    1098             :                               &a->req_body,
    1099             :                               ctx->pk_nonce,
    1100             :                               md);
    1101             : #else
    1102             :     krb5_set_error_message(context, EINVAL,
    1103             :                            N_("no support for PKINIT compiled in", ""));
    1104             :     return EINVAL;
    1105             : #endif
    1106             : }
    1107             : 
    1108             : static krb5_error_code
    1109       36587 : pa_data_add_pac_request(krb5_context context,
    1110             :                         krb5_get_init_creds_ctx *ctx,
    1111             :                         METHOD_DATA *md)
    1112             : {
    1113       36587 :     size_t len = 0, length;
    1114             :     krb5_error_code ret;
    1115             :     PA_PAC_REQUEST req;
    1116             :     void *buf;
    1117             : 
    1118       36587 :     switch (ctx->req_pac) {
    1119       34985 :     case KRB5_INIT_CREDS_TRISTATE_UNSET:
    1120       34985 :         return 0; /* don't bother */
    1121        1012 :     case KRB5_INIT_CREDS_TRISTATE_TRUE:
    1122        1012 :         req.include_pac = 1;
    1123        1012 :         break;
    1124           0 :     case KRB5_INIT_CREDS_TRISTATE_FALSE:
    1125           0 :         req.include_pac = 0;
    1126             :     }
    1127             : 
    1128        1012 :     ASN1_MALLOC_ENCODE(PA_PAC_REQUEST, buf, length,
    1129             :                        &req, &len, ret);
    1130        1012 :     if (ret)
    1131           0 :         return ret;
    1132        1012 :     if(len != length)
    1133           0 :         krb5_abortx(context, "internal error in ASN.1 encoder");
    1134             : 
    1135        1012 :     ret = krb5_padata_add(context, md, KRB5_PADATA_PA_PAC_REQUEST, buf, len);
    1136        1012 :     if (ret)
    1137           0 :         free(buf);
    1138             : 
    1139        1012 :     return 0;
    1140             : }
    1141             : 
    1142             : /*
    1143             :  * Assumes caller always will free `out_md', even on error.
    1144             :  */
    1145             : 
    1146             : static krb5_error_code
    1147       36587 : process_pa_data_to_md(krb5_context context,
    1148             :                       const krb5_creds *creds,
    1149             :                       const AS_REQ *a,
    1150             :                       krb5_get_init_creds_ctx *ctx,
    1151             :                       METHOD_DATA *in_md,
    1152             :                       METHOD_DATA **out_md,
    1153             :                       krb5_prompter_fct prompter,
    1154             :                       void *prompter_data)
    1155             : {
    1156             :     krb5_error_code ret;
    1157             : 
    1158       36587 :     ALLOC(*out_md, 1);
    1159       36587 :     if (*out_md == NULL) {
    1160           0 :         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
    1161           0 :         return ENOMEM;
    1162             :     }
    1163       36587 :     (*out_md)->len = 0;
    1164       36587 :     (*out_md)->val = NULL;
    1165             : 
    1166       36587 :     if (_krb5_have_debug(context, 5)) {
    1167             :         unsigned i;
    1168           0 :         _krb5_debug(context, 5, "KDC send %d patypes", in_md->len);
    1169           0 :         for (i = 0; i < in_md->len; i++)
    1170           0 :             _krb5_debug(context, 5, "KDC send PA-DATA type: %d", in_md->val[i].padata_type);
    1171             :     }
    1172             : 
    1173             :     /*
    1174             :      * Make sure we don't sent both ENC-TS and PK-INIT pa data, no
    1175             :      * need to expose our password protecting our PKCS12 key.
    1176             :      */
    1177             : 
    1178       36587 :     if (ctx->pk_init_ctx) {
    1179             : 
    1180          40 :         _krb5_debug(context, 5, "krb5_get_init_creds: "
    1181             :                     "prepareing PKINIT padata (%s)",
    1182          40 :                     (ctx->used_pa_types & USED_PKINIT_W2K) ? "win2k" : "ietf");
    1183             : 
    1184          40 :         if (ctx->used_pa_types & USED_PKINIT_W2K) {
    1185           0 :             krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP,
    1186             :                                    "Already tried pkinit, looping");
    1187           0 :             return KRB5_GET_IN_TKT_LOOP;
    1188             :         }
    1189             : 
    1190          80 :         ret = pa_data_to_md_pkinit(context, a, creds->client,
    1191          40 :                                    (ctx->used_pa_types & USED_PKINIT),
    1192             :                                    ctx, *out_md);
    1193          40 :         if (ret)
    1194           0 :             return ret;
    1195             : 
    1196          40 :         if (ctx->used_pa_types & USED_PKINIT)
    1197           0 :             ctx->used_pa_types |= USED_PKINIT_W2K;
    1198             :         else
    1199          40 :             ctx->used_pa_types |= USED_PKINIT;
    1200             : 
    1201       36547 :     } else if (in_md->len != 0) {
    1202             :         struct pa_info_data *paid, *ppaid;
    1203             :         unsigned flag;
    1204             : 
    1205       14238 :         paid = calloc(1, sizeof(*paid));
    1206             : 
    1207       14238 :         paid->etype = KRB5_ENCTYPE_NULL;
    1208       14238 :         ppaid = process_pa_info(context, creds->client, a, paid, in_md);
    1209             : 
    1210       14238 :         if (ppaid)
    1211       13943 :             flag = USED_ENC_TS_INFO;
    1212             :         else
    1213           0 :             flag = USED_ENC_TS_GUESS;
    1214             : 
    1215       14238 :         if (ctx->used_pa_types & flag) {
    1216           0 :             if (ppaid)
    1217           0 :                 free_paid(context, ppaid);
    1218           0 :             krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP,
    1219             :                                    "Already tried ENC-TS-%s, looping",
    1220             :                                    flag == USED_ENC_TS_INFO ? "info" : "guess");
    1221           0 :             return KRB5_GET_IN_TKT_LOOP;
    1222             :         }
    1223             : 
    1224       14238 :         pa_data_to_md_ts_enc(context, a, creds->client, ctx, ppaid, *out_md);
    1225             : 
    1226       14238 :         ctx->used_pa_types |= flag;
    1227             : 
    1228       14238 :         if (ppaid) {
    1229       14238 :             if (ctx->ppaid) {
    1230           0 :                 free_paid(context, ctx->ppaid);
    1231           0 :                 free(ctx->ppaid);
    1232             :             }
    1233       14238 :             ctx->ppaid = ppaid;
    1234             :         } else
    1235           0 :             free(paid);
    1236             :     }
    1237             : 
    1238       36587 :     pa_data_add_pac_request(context, ctx, *out_md);
    1239             : 
    1240       36587 :     if ((*out_md)->len == 0) {
    1241       21569 :         free(*out_md);
    1242       21569 :         *out_md = NULL;
    1243             :     }
    1244             : 
    1245       35997 :     return 0;
    1246             : }
    1247             : 
    1248             : static krb5_error_code
    1249       13985 : process_pa_data_to_key(krb5_context context,
    1250             :                        krb5_get_init_creds_ctx *ctx,
    1251             :                        krb5_creds *creds,
    1252             :                        AS_REQ *a,
    1253             :                        AS_REP *rep,
    1254             :                        const krb5_krbhst_info *hi,
    1255             :                        krb5_keyblock **key)
    1256             : {
    1257       13985 :     struct pa_info_data paid, *ppaid = NULL;
    1258             :     krb5_error_code ret;
    1259             :     krb5_enctype etype;
    1260             :     PA_DATA *pa;
    1261             : 
    1262       13985 :     memset(&paid, 0, sizeof(paid));
    1263             : 
    1264       13985 :     etype = rep->enc_part.etype;
    1265             : 
    1266       13985 :     if (rep->padata) {
    1267        9184 :         paid.etype = etype;
    1268        9184 :         ppaid = process_pa_info(context, creds->client, a, &paid,
    1269             :                                 rep->padata);
    1270             :     }
    1271       13903 :     if (ppaid == NULL)
    1272        4827 :         ppaid = ctx->ppaid;
    1273       13985 :     if (ppaid == NULL) {
    1274          26 :         ret = krb5_get_pw_salt (context, creds->client, &paid.salt);
    1275          26 :         if (ret)
    1276           0 :             return ret;
    1277          26 :         paid.etype = etype;
    1278          26 :         paid.s2kparams = NULL;
    1279          26 :         ppaid = &paid;
    1280             :     }
    1281             : 
    1282       13985 :     pa = NULL;
    1283       13985 :     if (rep->padata) {
    1284        9184 :         int idx = 0;
    1285        9184 :         pa = krb5_find_padata(rep->padata->val,
    1286        8971 :                               rep->padata->len,
    1287             :                               KRB5_PADATA_PK_AS_REP,
    1288             :                               &idx);
    1289        9184 :         if (pa == NULL) {
    1290        9158 :             idx = 0;
    1291        9158 :             pa = krb5_find_padata(rep->padata->val,
    1292        9158 :                                   rep->padata->len,
    1293             :                                   KRB5_PADATA_PK_AS_REP_19,
    1294             :                                   &idx);
    1295             :         }
    1296             :     }
    1297       13903 :     if (pa && ctx->pk_init_ctx) {
    1298             : #ifdef PKINIT
    1299          26 :         _krb5_debug(context, 5, "krb5_get_init_creds: using PKINIT");
    1300             : 
    1301          52 :         ret = _krb5_pk_rd_pa_reply(context,
    1302          26 :                                    a->req_body.realm,
    1303          26 :                                    ctx->pk_init_ctx,
    1304             :                                    etype,
    1305             :                                    hi,
    1306             :                                    ctx->pk_nonce,
    1307          26 :                                    &ctx->req_buffer,
    1308             :                                    pa,
    1309             :                                    key);
    1310             : #else
    1311             :         ret = EINVAL;
    1312             :         krb5_set_error_message(context, ret, N_("no support for PKINIT compiled in", ""));
    1313             : #endif
    1314       13959 :     } else if (ctx->keyseed) {
    1315       13959 :         _krb5_debug(context, 5, "krb5_get_init_creds: using keyproc");
    1316       14254 :         ret = pa_data_to_key_plain(context, creds->client, ctx,
    1317             :                                    ppaid->salt, ppaid->s2kparams, etype, key);
    1318             :     } else {
    1319           0 :         ret = EINVAL;
    1320           0 :         krb5_set_error_message(context, ret, N_("No usable pa data type", ""));
    1321             :     }
    1322             : 
    1323       13985 :     free_paid(context, &paid);
    1324       13690 :     return ret;
    1325             : }
    1326             : 
    1327             : /**
    1328             :  * Start a new context to get a new initial credential.
    1329             :  *
    1330             :  * @param context A Kerberos 5 context.
    1331             :  * @param client The Kerberos principal to get the credential for, if
    1332             :  *     NULL is given, the default principal is used as determined by
    1333             :  *     krb5_get_default_principal().
    1334             :  * @param prompter
    1335             :  * @param prompter_data
    1336             :  * @param start_time the time the ticket should start to be valid or 0 for now.
    1337             :  * @param options a options structure, can be NULL for default options.
    1338             :  * @param rctx A new allocated free with krb5_init_creds_free().
    1339             :  *
    1340             :  * @return 0 for success or an Kerberos 5 error code, see krb5_get_error_message().
    1341             :  *
    1342             :  * @ingroup krb5_credential
    1343             :  */
    1344             : 
    1345             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1346       22093 : krb5_init_creds_init(krb5_context context,
    1347             :                      krb5_principal client,
    1348             :                      krb5_prompter_fct prompter,
    1349             :                      void *prompter_data,
    1350             :                      krb5_deltat start_time,
    1351             :                      krb5_get_init_creds_opt *options,
    1352             :                      krb5_init_creds_context *rctx)
    1353             : {
    1354             :     krb5_init_creds_context ctx;
    1355             :     krb5_error_code ret;
    1356             : 
    1357       22093 :     *rctx = NULL;
    1358             : 
    1359       22093 :     ctx = calloc(1, sizeof(*ctx));
    1360       22093 :     if (ctx == NULL) {
    1361           0 :         krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
    1362           0 :         return ENOMEM;
    1363             :     }
    1364             : 
    1365       22093 :     ret = get_init_creds_common(context, client, start_time, options, ctx);
    1366       22093 :     if (ret) {
    1367           0 :         free(ctx);
    1368           0 :         return ret;
    1369             :     }
    1370             : 
    1371             :     /* Set a new nonce. */
    1372       22093 :     krb5_generate_random_block (&ctx->nonce, sizeof(ctx->nonce));
    1373       22093 :     ctx->nonce &= 0x7fffffff;
    1374             :     /* XXX these just needs to be the same when using Windows PK-INIT */
    1375       22093 :     ctx->pk_nonce = ctx->nonce;
    1376             : 
    1377       22093 :     ctx->prompter = prompter;
    1378       22093 :     ctx->prompter_data = prompter_data;
    1379             : 
    1380       22093 :     *rctx = ctx;
    1381             : 
    1382       22093 :     return ret;
    1383             : }
    1384             : 
    1385             : /**
    1386             :  * Sets the service that the is requested. This call is only neede for
    1387             :  * special initial tickets, by default the a krbtgt is fetched in the default realm.
    1388             :  *
    1389             :  * @param context a Kerberos 5 context.
    1390             :  * @param ctx a krb5_init_creds_context context.
    1391             :  * @param service the service given as a string, for example
    1392             :  *        "kadmind/admin". If NULL, the default krbtgt in the clients
    1393             :  *        realm is set.
    1394             :  *
    1395             :  * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message().
    1396             :  * @ingroup krb5_credential
    1397             :  */
    1398             : 
    1399             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1400       44442 : krb5_init_creds_set_service(krb5_context context,
    1401             :                             krb5_init_creds_context ctx,
    1402             :                             const char *service)
    1403             : {
    1404             :     krb5_const_realm client_realm;
    1405             :     krb5_principal principal;
    1406             :     krb5_error_code ret;
    1407             : 
    1408       44442 :     client_realm = krb5_principal_get_realm (context, ctx->cred.client);
    1409             : 
    1410       44442 :     if (service) {
    1411        1741 :         ret = krb5_parse_name (context, service, &principal);
    1412        1741 :         if (ret)
    1413           0 :             return ret;
    1414        1741 :         krb5_principal_set_realm (context, principal, client_realm);
    1415             :     } else {
    1416       42701 :         ret = krb5_make_principal(context, &principal,
    1417             :                                   client_realm, KRB5_TGS_NAME, client_realm,
    1418             :                                   NULL);
    1419       42701 :         if (ret)
    1420           0 :             return ret;
    1421             :     }
    1422             : 
    1423             :     /*
    1424             :      * This is for Windows RODC that are picky about what name type
    1425             :      * the server principal have, and the really strange part is that
    1426             :      * they are picky about the AS-REQ name type and not the TGS-REQ
    1427             :      * later. Oh well.
    1428             :      */
    1429             : 
    1430       44442 :     if (krb5_principal_is_krbtgt(context, principal))
    1431       42701 :         krb5_principal_set_type(context, principal, KRB5_NT_SRV_INST);
    1432             : 
    1433       44442 :     krb5_free_principal(context, ctx->cred.server);
    1434       44442 :     ctx->cred.server = principal;
    1435             : 
    1436       44442 :     return 0;
    1437             : }
    1438             : 
    1439             : /**
    1440             :  * Sets the password that will use for the request.
    1441             :  *
    1442             :  * @param context a Kerberos 5 context.
    1443             :  * @param ctx ctx krb5_init_creds_context context.
    1444             :  * @param password the password to use.
    1445             :  *
    1446             :  * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message().
    1447             :  * @ingroup krb5_credential
    1448             :  */
    1449             : 
    1450             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1451       22074 : krb5_init_creds_set_password(krb5_context context,
    1452             :                              krb5_init_creds_context ctx,
    1453             :                              const char *password)
    1454             : {
    1455       22074 :     if (ctx->password) {
    1456           0 :         memset(ctx->password, 0, strlen(ctx->password));
    1457           0 :         free(ctx->password);
    1458             :     }
    1459       22074 :     if (password) {
    1460       22074 :         ctx->password = strdup(password);
    1461       22074 :         if (ctx->password == NULL) {
    1462           0 :             krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
    1463           0 :             return ENOMEM;
    1464             :         }
    1465       22074 :         ctx->keyseed = (void *) ctx->password;
    1466             :     } else {
    1467           0 :         ctx->keyseed = NULL;
    1468           0 :         ctx->password = NULL;
    1469             :     }
    1470             : 
    1471       21782 :     return 0;
    1472             : }
    1473             : 
    1474             : static krb5_error_code KRB5_CALLCONV
    1475          14 : keytab_key_proc(krb5_context context, krb5_enctype enctype,
    1476             :                 krb5_const_pointer keyseed,
    1477             :                 krb5_salt salt, krb5_data *s2kparms,
    1478             :                 krb5_keyblock **key)
    1479             : {
    1480          14 :     krb5_keytab_key_proc_args *args  = rk_UNCONST(keyseed);
    1481          14 :     krb5_keytab keytab = args->keytab;
    1482          14 :     krb5_principal principal = args->principal;
    1483             :     krb5_error_code ret;
    1484             :     krb5_keytab real_keytab;
    1485             :     krb5_keytab_entry entry;
    1486             : 
    1487          14 :     if(keytab == NULL)
    1488           0 :         krb5_kt_default(context, &real_keytab);
    1489             :     else
    1490          14 :         real_keytab = keytab;
    1491             : 
    1492          14 :     ret = krb5_kt_get_entry (context, real_keytab, principal,
    1493             :                              0, enctype, &entry);
    1494             : 
    1495          14 :     if (keytab == NULL)
    1496           0 :         krb5_kt_close (context, real_keytab);
    1497             : 
    1498          14 :     if (ret)
    1499           0 :         return ret;
    1500             : 
    1501          14 :     ret = krb5_copy_keyblock (context, &entry.keyblock, key);
    1502          14 :     krb5_kt_free_entry(context, &entry);
    1503          14 :     return ret;
    1504             : }
    1505             : 
    1506             : 
    1507             : /**
    1508             :  * Set the keytab to use for authentication.
    1509             :  *
    1510             :  * @param context a Kerberos 5 context.
    1511             :  * @param ctx ctx krb5_init_creds_context context.
    1512             :  * @param keytab the keytab to read the key from.
    1513             :  *
    1514             :  * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message().
    1515             :  * @ingroup krb5_credential
    1516             :  */
    1517             : 
    1518             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1519           7 : krb5_init_creds_set_keytab(krb5_context context,
    1520             :                            krb5_init_creds_context ctx,
    1521             :                            krb5_keytab keytab)
    1522             : {
    1523             :     krb5_keytab_key_proc_args *a;
    1524             :     krb5_keytab_entry entry;
    1525             :     krb5_kt_cursor cursor;
    1526           7 :     krb5_enctype *etypes = NULL;
    1527             :     krb5_error_code ret;
    1528           7 :     size_t netypes = 0;
    1529           7 :     int kvno = 0;
    1530             : 
    1531           7 :     a = malloc(sizeof(*a));
    1532           7 :     if (a == NULL) {
    1533           0 :         krb5_set_error_message(context, ENOMEM,
    1534           0 :                                N_("malloc: out of memory", ""));
    1535           0 :         return ENOMEM;
    1536             :     }
    1537             : 
    1538           7 :     a->principal = ctx->cred.client;
    1539           7 :     a->keytab    = keytab;
    1540             : 
    1541           7 :     ctx->keytab_data = a;
    1542           7 :     ctx->keyseed = (void *)a;
    1543           7 :     ctx->keyproc = keytab_key_proc;
    1544             : 
    1545             :     /*
    1546             :      * We need to the KDC what enctypes we support for this keytab,
    1547             :      * esp if the keytab is really a password based entry, then the
    1548             :      * KDC might have more enctypes in the database then what we have
    1549             :      * in the keytab.
    1550             :      */
    1551             : 
    1552           7 :     ret = krb5_kt_start_seq_get(context, keytab, &cursor);
    1553           7 :     if(ret)
    1554           0 :         goto out;
    1555             : 
    1556         122 :     while(krb5_kt_next_entry(context, keytab, &entry, &cursor) == 0){
    1557             :         void *ptr;
    1558             : 
    1559         108 :         if (!krb5_principal_compare(context, entry.principal, ctx->cred.client))
    1560          84 :             goto next;
    1561             : 
    1562             :         /* check if we ahve this kvno already */
    1563          24 :         if (entry.vno > kvno) {
    1564             :             /* remove old list of etype */
    1565           7 :             if (etypes)
    1566           0 :                 free(etypes);
    1567           7 :             etypes = NULL;
    1568           7 :             netypes = 0;
    1569           7 :             kvno = entry.vno;
    1570          17 :         } else if (entry.vno != kvno)
    1571           3 :             goto next;
    1572             : 
    1573             :         /* check if enctype is supported */
    1574          21 :         if (krb5_enctype_valid(context, entry.keyblock.keytype) != 0)
    1575           0 :             goto next;
    1576             : 
    1577             :         /* add enctype to supported list */
    1578          21 :         ptr = realloc(etypes, sizeof(etypes[0]) * (netypes + 2));
    1579          21 :         if (ptr == NULL)
    1580           0 :             goto next;
    1581             : 
    1582          21 :         etypes = ptr;
    1583          21 :         etypes[netypes] = entry.keyblock.keytype;
    1584          21 :         etypes[netypes + 1] = ETYPE_NULL;
    1585          21 :         netypes++;
    1586         108 :     next:
    1587         108 :         krb5_kt_free_entry(context, &entry);
    1588             :     }
    1589           7 :     krb5_kt_end_seq_get(context, keytab, &cursor);
    1590             : 
    1591           7 :     if (etypes) {
    1592           7 :         if (ctx->etypes)
    1593           2 :             free(ctx->etypes);
    1594           7 :         ctx->etypes = etypes;
    1595             :     }
    1596             : 
    1597           7 :  out:
    1598           7 :     return 0;
    1599             : }
    1600             : 
    1601             : static krb5_error_code KRB5_CALLCONV
    1602          24 : keyblock_key_proc(krb5_context context, krb5_enctype enctype,
    1603             :                   krb5_const_pointer keyseed,
    1604             :                   krb5_salt salt, krb5_data *s2kparms,
    1605             :                   krb5_keyblock **key)
    1606             : {
    1607          24 :     return krb5_copy_keyblock (context, keyseed, key);
    1608             : }
    1609             : 
    1610             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1611          12 : krb5_init_creds_set_keyblock(krb5_context context,
    1612             :                              krb5_init_creds_context ctx,
    1613             :                              krb5_keyblock *keyblock)
    1614             : {
    1615          12 :     ctx->keyseed = (void *)keyblock;
    1616          12 :     ctx->keyproc = keyblock_key_proc;
    1617             : 
    1618          12 :     return 0;
    1619             : }
    1620             : 
    1621             : /**
    1622             :  * The core loop if krb5_get_init_creds() function family. Create the
    1623             :  * packets and have the caller send them off to the KDC.
    1624             :  *
    1625             :  * If the caller want all work been done for them, use
    1626             :  * krb5_init_creds_get() instead.
    1627             :  *
    1628             :  * @param context a Kerberos 5 context.
    1629             :  * @param ctx ctx krb5_init_creds_context context.
    1630             :  * @param in input data from KDC, first round it should be reset by krb5_data_zer().
    1631             :  * @param out reply to KDC.
    1632             :  * @param hostinfo KDC address info, first round it can be NULL.
    1633             :  * @param flags status of the round, if
    1634             :  *        KRB5_INIT_CREDS_STEP_FLAG_CONTINUE is set, continue one more round.
    1635             :  *
    1636             :  * @return 0 for success, or an Kerberos 5 error code, see
    1637             :  *     krb5_get_error_message().
    1638             :  *
    1639             :  * @ingroup krb5_credential
    1640             :  */
    1641             : 
    1642             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1643       51768 : krb5_init_creds_step(krb5_context context,
    1644             :                      krb5_init_creds_context ctx,
    1645             :                      krb5_data *in,
    1646             :                      krb5_data *out,
    1647             :                      krb5_krbhst_info *hostinfo,
    1648             :                      unsigned int *flags)
    1649             : {
    1650             :     krb5_error_code ret;
    1651       51768 :     size_t len = 0;
    1652             :     size_t size;
    1653             : 
    1654       51768 :     krb5_data_zero(out);
    1655             : 
    1656       51768 :     if (ctx->as_req.req_body.cname == NULL) {
    1657       44186 :         ret = init_as_req(context, ctx->flags, &ctx->cred,
    1658       22093 :                           ctx->addrs, ctx->etypes, &ctx->as_req);
    1659       22093 :         if (ret) {
    1660           0 :             free_init_creds_ctx(context, ctx);
    1661           0 :             return ret;
    1662             :         }
    1663             :     }
    1664             : 
    1665             : #define MAX_PA_COUNTER 10
    1666       51768 :     if (ctx->pa_counter > MAX_PA_COUNTER) {
    1667           0 :         krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP,
    1668           0 :                                N_("Looping %d times while getting "
    1669             :                                   "initial credentials", ""),
    1670             :                                ctx->pa_counter);
    1671           0 :         return KRB5_GET_IN_TKT_LOOP;
    1672             :     }
    1673       51768 :     ctx->pa_counter++;
    1674             : 
    1675       51768 :     _krb5_debug(context, 5, "krb5_get_init_creds: loop %d", ctx->pa_counter);
    1676             : 
    1677             :     /* Lets process the input packet */
    1678       51768 :     if (in && in->length) {
    1679             :         krb5_kdc_rep rep;
    1680             : 
    1681       29675 :         memset(&rep, 0, sizeof(rep));
    1682             : 
    1683       29675 :         _krb5_debug(context, 5, "krb5_get_init_creds: processing input");
    1684             : 
    1685       29675 :         ret = decode_AS_REP(in->data, in->length, &rep.kdc_rep, &size);
    1686       29675 :         if (ret == 0) {
    1687       13985 :             krb5_keyblock *key = NULL;
    1688       13985 :             unsigned eflags = EXTRACT_TICKET_AS_REQ | EXTRACT_TICKET_TIMESYNC;
    1689             : 
    1690       13985 :             if (ctx->flags.canonicalize) {
    1691       12977 :                 eflags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH;
    1692       12977 :                 eflags |= EXTRACT_TICKET_MATCH_REALM;
    1693             :             }
    1694       13985 :             if (ctx->ic_flags & KRB5_INIT_CREDS_NO_C_CANON_CHECK)
    1695       12234 :                 eflags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH;
    1696             : 
    1697       13985 :             ret = process_pa_data_to_key(context, ctx, &ctx->cred,
    1698             :                                          &ctx->as_req, &rep.kdc_rep, hostinfo, &key);
    1699       13985 :             if (ret) {
    1700           0 :                 free_AS_REP(&rep.kdc_rep);
    1701           0 :                 goto out;
    1702             :             }
    1703             : 
    1704       13985 :             _krb5_debug(context, 5, "krb5_get_init_creds: extracting ticket");
    1705             : 
    1706       13985 :             ret = _krb5_extract_ticket(context,
    1707             :                                        &rep,
    1708             :                                        &ctx->cred,
    1709             :                                        key,
    1710             :                                        NULL,
    1711             :                                        KRB5_KU_AS_REP_ENC_PART,
    1712             :                                        NULL,
    1713             :                                        ctx->nonce,
    1714             :                                        eflags,
    1715             :                                        NULL,
    1716             :                                        NULL);
    1717       13985 :             krb5_free_keyblock(context, key);
    1718             : 
    1719       13985 :             *flags = 0;
    1720             : 
    1721       13985 :             if (ret == 0)
    1722       13985 :                 ret = copy_EncKDCRepPart(&rep.enc_part, &ctx->enc_part);
    1723             : 
    1724       13985 :             free_AS_REP(&rep.kdc_rep);
    1725       13985 :             free_EncASRepPart(&rep.enc_part);
    1726             : 
    1727       13985 :             return ret;
    1728             : 
    1729             :         } else {
    1730             :             /* let's try to parse it as a KRB-ERROR */
    1731             : 
    1732       15690 :             _krb5_debug(context, 5, "krb5_get_init_creds: got an error");
    1733             : 
    1734       15690 :             free_KRB_ERROR(&ctx->error);
    1735             : 
    1736       15690 :             ret = krb5_rd_error(context, in, &ctx->error);
    1737       15690 :             if(ret && in->length && ((char*)in->data)[0] == 4)
    1738           0 :                 ret = KRB5KRB_AP_ERR_V4_REPLY;
    1739       15690 :             if (ret) {
    1740           0 :                 _krb5_debug(context, 5, "krb5_get_init_creds: failed to read error");
    1741           0 :                 goto out;
    1742             :             }
    1743             : 
    1744       15690 :             ret = krb5_error_from_rd_error(context, &ctx->error, &ctx->cred);
    1745             : 
    1746       15690 :             _krb5_debug(context, 5, "krb5_get_init_creds: KRB-ERROR %d", ret);
    1747             : 
    1748             :             /*
    1749             :              * If no preauth was set and KDC requires it, give it one
    1750             :              * more try.
    1751             :              */
    1752             : 
    1753       15690 :             if (ret == KRB5KDC_ERR_PREAUTH_REQUIRED) {
    1754             : 
    1755       14238 :                 free_METHOD_DATA(&ctx->md);
    1756       14533 :                 memset(&ctx->md, 0, sizeof(ctx->md));
    1757             : 
    1758       14238 :                 if (ctx->error.e_data) {
    1759       28181 :                     ret = decode_METHOD_DATA(ctx->error.e_data->data,
    1760       13943 :                                              ctx->error.e_data->length,
    1761             :                                              &ctx->md,
    1762             :                                              NULL);
    1763       14238 :                     if (ret)
    1764           0 :                         krb5_set_error_message(context, ret,
    1765           0 :                                                N_("Failed to decode METHOD-DATA", ""));
    1766             :                 } else {
    1767           0 :                     krb5_set_error_message(context, ret,
    1768           0 :                                            N_("Preauth required but no preauth "
    1769             :                                               "options send by KDC", ""));
    1770             :                 }
    1771        1452 :             } else if (ret == KRB5KRB_AP_ERR_SKEW && context->kdc_sec_offset == 0) {
    1772             :                 /*
    1773             :                  * Try adapt to timeskrew when we are using pre-auth, and
    1774             :                  * if there was a time skew, try again.
    1775             :                  */
    1776           0 :                 krb5_set_real_time(context, ctx->error.stime, -1);
    1777           0 :                 if (context->kdc_sec_offset)
    1778           0 :                     ret = 0;
    1779             : 
    1780           0 :                 _krb5_debug(context, 10, "init_creds: err skew updating kdc offset to %d",
    1781             :                             context->kdc_sec_offset);
    1782             : 
    1783           0 :                 ctx->used_pa_types = 0;
    1784             : 
    1785        1452 :             } else if (ret == KRB5_KDC_ERR_WRONG_REALM && ctx->flags.canonicalize) {
    1786             :                 /* client referal to a new realm */
    1787             : 
    1788         256 :                 if (ctx->error.crealm == NULL) {
    1789           0 :                     krb5_set_error_message(context, ret,
    1790           0 :                                            N_("Got a client referral, not but no realm", ""));
    1791           0 :                     goto out;
    1792             :                 }
    1793         256 :                 _krb5_debug(context, 5,
    1794             :                             "krb5_get_init_creds: got referal to realm %s",
    1795         256 :                             *ctx->error.crealm);
    1796             : 
    1797         256 :                 ret = krb5_principal_set_realm(context,
    1798             :                                                ctx->cred.client,
    1799         256 :                                                *ctx->error.crealm);
    1800             : 
    1801         256 :                 if (ret)
    1802           0 :                     goto out;
    1803             : 
    1804         256 :                 if (krb5_principal_is_krbtgt(context, ctx->cred.server)) {
    1805         256 :                     ret = krb5_init_creds_set_service(context, ctx, NULL);
    1806         256 :                     if (ret)
    1807           0 :                         goto out;
    1808             :                 }
    1809             : 
    1810         256 :                 free_AS_REQ(&ctx->as_req);
    1811         256 :                 memset(&ctx->as_req, 0, sizeof(ctx->as_req));
    1812             : 
    1813         256 :                 ctx->used_pa_types = 0;
    1814             :             }
    1815       15690 :             if (ret)
    1816        1196 :                 goto out;
    1817             :         }
    1818             :     }
    1819             : 
    1820       36587 :     if (ctx->as_req.req_body.cname == NULL) {
    1821         512 :         ret = init_as_req(context, ctx->flags, &ctx->cred,
    1822         256 :                           ctx->addrs, ctx->etypes, &ctx->as_req);
    1823         256 :         if (ret) {
    1824           0 :             free_init_creds_ctx(context, ctx);
    1825           0 :             return ret;
    1826             :         }
    1827             :     }
    1828             : 
    1829       36587 :     if (ctx->as_req.padata) {
    1830         232 :         free_METHOD_DATA(ctx->as_req.padata);
    1831         232 :         free(ctx->as_req.padata);
    1832         232 :         ctx->as_req.padata = NULL;
    1833             :     }
    1834             : 
    1835             :     /* Set a new nonce. */
    1836       36587 :     ctx->as_req.req_body.nonce = ctx->nonce;
    1837             : 
    1838             :     /* fill_in_md_data */
    1839       36587 :     ret = process_pa_data_to_md(context, &ctx->cred, &ctx->as_req, ctx,
    1840             :                                 &ctx->md, &ctx->as_req.padata,
    1841             :                                 ctx->prompter, ctx->prompter_data);
    1842       36587 :     if (ret)
    1843           0 :         goto out;
    1844             : 
    1845       36587 :     krb5_data_free(&ctx->req_buffer);
    1846             : 
    1847       36587 :     ASN1_MALLOC_ENCODE(AS_REQ,
    1848             :                        ctx->req_buffer.data, ctx->req_buffer.length,
    1849             :                        &ctx->as_req, &len, ret);
    1850       36587 :     if (ret)
    1851           0 :         goto out;
    1852       36587 :     if(len != ctx->req_buffer.length)
    1853           0 :         krb5_abortx(context, "internal error in ASN.1 encoder");
    1854             : 
    1855       36587 :     out->data = ctx->req_buffer.data;
    1856       36587 :     out->length = ctx->req_buffer.length;
    1857             : 
    1858       36587 :     *flags = KRB5_INIT_CREDS_STEP_FLAG_CONTINUE;
    1859             : 
    1860       36587 :     return 0;
    1861        1196 :  out:
    1862        1196 :     return ret;
    1863             : }
    1864             : 
    1865             : /**
    1866             :  * Extract the newly acquired credentials from krb5_init_creds_context
    1867             :  * context.
    1868             :  *
    1869             :  * @param context A Kerberos 5 context.
    1870             :  * @param ctx
    1871             :  * @param cred credentials, free with krb5_free_cred_contents().
    1872             :  *
    1873             :  * @return 0 for sucess or An Kerberos error code, see krb5_get_error_message().
    1874             :  */
    1875             : 
    1876             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1877       13985 : krb5_init_creds_get_creds(krb5_context context,
    1878             :                           krb5_init_creds_context ctx,
    1879             :                           krb5_creds *cred)
    1880             : {
    1881       13985 :     return krb5_copy_creds_contents(context, &ctx->cred, cred);
    1882             : }
    1883             : 
    1884             : /**
    1885             :  * Get the last error from the transaction.
    1886             :  *
    1887             :  * @return Returns 0 or an error code
    1888             :  *
    1889             :  * @ingroup krb5_credential
    1890             :  */
    1891             : 
    1892             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1893           0 : krb5_init_creds_get_error(krb5_context context,
    1894             :                           krb5_init_creds_context ctx,
    1895             :                           KRB_ERROR *error)
    1896             : {
    1897             :     krb5_error_code ret;
    1898             : 
    1899           0 :     ret = copy_KRB_ERROR(&ctx->error, error);
    1900           0 :     if (ret)
    1901           0 :         krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
    1902             : 
    1903           0 :     return ret;
    1904             : }
    1905             : 
    1906             : /**
    1907             :  * Free the krb5_init_creds_context allocated by krb5_init_creds_init().
    1908             :  *
    1909             :  * @param context A Kerberos 5 context.
    1910             :  * @param ctx The krb5_init_creds_context to free.
    1911             :  *
    1912             :  * @ingroup krb5_credential
    1913             :  */
    1914             : 
    1915             : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
    1916       22093 : krb5_init_creds_free(krb5_context context,
    1917             :                      krb5_init_creds_context ctx)
    1918             : {
    1919       22093 :     free_init_creds_ctx(context, ctx);
    1920       22093 :     free(ctx);
    1921       22093 : }
    1922             : 
    1923             : /**
    1924             :  * Get new credentials as setup by the krb5_init_creds_context.
    1925             :  *
    1926             :  * @param context A Kerberos 5 context.
    1927             :  * @param ctx The krb5_init_creds_context to process.
    1928             :  *
    1929             :  * @ingroup krb5_credential
    1930             :  */
    1931             : 
    1932             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1933       22093 : krb5_init_creds_get(krb5_context context, krb5_init_creds_context ctx)
    1934             : {
    1935       22093 :     krb5_sendto_ctx stctx = NULL;
    1936       22093 :     krb5_krbhst_info *hostinfo = NULL;
    1937             :     krb5_error_code ret;
    1938             :     krb5_data in, out;
    1939       22093 :     unsigned int flags = 0;
    1940             : 
    1941       22093 :     krb5_data_zero(&in);
    1942       22093 :     krb5_data_zero(&out);
    1943             : 
    1944       22093 :     ret = krb5_sendto_ctx_alloc(context, &stctx);
    1945       22093 :     if (ret)
    1946           0 :         goto out;
    1947       22093 :     krb5_sendto_ctx_set_func(stctx, _krb5_kdc_retry, NULL);
    1948             : 
    1949             :     while (1) {
    1950       80853 :         flags = 0;
    1951       51768 :         ret = krb5_init_creds_step(context, ctx, &in, &out, hostinfo, &flags);
    1952       51768 :         krb5_data_free(&in);
    1953       51768 :         if (ret)
    1954        1196 :             goto out;
    1955             : 
    1956       50572 :         if ((flags & 1) == 0)
    1957       13690 :             break;
    1958             : 
    1959       36587 :         ret = krb5_sendto_context (context, stctx, &out,
    1960       36587 :                                    ctx->cred.client->realm, &in);
    1961       36587 :         if (ret)
    1962        6912 :             goto out;
    1963             : 
    1964             :     }
    1965             : 
    1966       22093 :  out:
    1967       22093 :     if (stctx)
    1968       22093 :         krb5_sendto_ctx_free(context, stctx);
    1969             : 
    1970       22093 :     return ret;
    1971             : }
    1972             : 
    1973             : /**
    1974             :  * Get new credentials using password.
    1975             :  *
    1976             :  * @ingroup krb5_credential
    1977             :  */
    1978             : 
    1979             : 
    1980             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    1981       22070 : krb5_get_init_creds_password(krb5_context context,
    1982             :                              krb5_creds *creds,
    1983             :                              krb5_principal client,
    1984             :                              const char *password,
    1985             :                              krb5_prompter_fct prompter,
    1986             :                              void *data,
    1987             :                              krb5_deltat start_time,
    1988             :                              const char *in_tkt_service,
    1989             :                              krb5_get_init_creds_opt *options)
    1990             : {
    1991             :     krb5_init_creds_context ctx;
    1992             :     char buf[BUFSIZ];
    1993             :     char buf2[BUFSIZ];
    1994             :     krb5_error_code ret;
    1995       22070 :     int chpw = 0;
    1996             : 
    1997       22074 :  again:
    1998       22074 :     ret = krb5_init_creds_init(context, client, prompter, data, start_time, options, &ctx);
    1999       22074 :     if (ret)
    2000           0 :         goto out;
    2001             : 
    2002       22074 :     ret = krb5_init_creds_set_service(context, ctx, in_tkt_service);
    2003       22074 :     if (ret)
    2004           0 :         goto out;
    2005             : 
    2006       22074 :     if (prompter != NULL && ctx->password == NULL && password == NULL) {
    2007             :         krb5_prompt prompt;
    2008             :         krb5_data password_data;
    2009             :         char *p, *q;
    2010             : 
    2011           6 :         krb5_unparse_name (context, client, &p);
    2012           6 :         asprintf (&q, "%s's Password: ", p);
    2013           6 :         free (p);
    2014           6 :         prompt.prompt = q;
    2015           6 :         password_data.data   = buf;
    2016           6 :         password_data.length = sizeof(buf);
    2017           6 :         prompt.hidden = 1;
    2018           6 :         prompt.reply  = &password_data;
    2019           6 :         prompt.type   = KRB5_PROMPT_TYPE_PASSWORD;
    2020             : 
    2021           6 :         ret = (*prompter) (context, data, NULL, NULL, 1, &prompt);
    2022           6 :         free (q);
    2023           6 :         if (ret) {
    2024           0 :             memset (buf, 0, sizeof(buf));
    2025           0 :             ret = KRB5_LIBOS_PWDINTR;
    2026           0 :             krb5_clear_error_message (context);
    2027           0 :             goto out;
    2028             :         }
    2029           6 :         password = password_data.data;
    2030             :     }
    2031             : 
    2032       22074 :     if (password) {
    2033       22074 :         ret = krb5_init_creds_set_password(context, ctx, password);
    2034       22074 :         if (ret)
    2035           0 :             goto out;
    2036             :     }
    2037             : 
    2038       22074 :     ret = krb5_init_creds_get(context, ctx);
    2039             : 
    2040       22074 :     if (ret == 0)
    2041       13966 :         process_last_request(context, options, ctx);
    2042             : 
    2043             : 
    2044       22074 :     if (ret == KRB5KDC_ERR_KEY_EXPIRED && chpw == 0) {
    2045             :         /* try to avoid recursion */
    2046           4 :         if (in_tkt_service != NULL && strcmp(in_tkt_service, "kadmin/changepw") == 0)
    2047           0 :            goto out;
    2048             : 
    2049             :         /* don't try to change password where then where none */
    2050           4 :         if (prompter == NULL)
    2051           0 :             goto out;
    2052             : 
    2053           4 :         ret = change_password (context,
    2054             :                                client,
    2055           4 :                                ctx->password,
    2056             :                                buf2,
    2057             :                                sizeof(buf2),
    2058             :                                prompter,
    2059             :                                data,
    2060             :                                options);
    2061           4 :         if (ret)
    2062           0 :             goto out;
    2063           4 :         chpw = 1;
    2064           4 :         password = buf2;
    2065           4 :         krb5_init_creds_free(context, ctx);
    2066           4 :         goto again;
    2067             :     }
    2068             : 
    2069       22070 :  out:
    2070       22070 :     if (ret == 0)
    2071       13966 :         krb5_init_creds_get_creds(context, ctx, creds);
    2072             : 
    2073       22070 :     if (ctx)
    2074       22070 :         krb5_init_creds_free(context, ctx);
    2075             : 
    2076       22070 :     memset(buf, 0, sizeof(buf));
    2077       22070 :     memset(buf2, 0, sizeof(buf2));
    2078       22070 :     return ret;
    2079             : }
    2080             : 
    2081             : /**
    2082             :  * Get new credentials using keyblock.
    2083             :  *
    2084             :  * @ingroup krb5_credential
    2085             :  */
    2086             : 
    2087             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    2088          12 : krb5_get_init_creds_keyblock(krb5_context context,
    2089             :                              krb5_creds *creds,
    2090             :                              krb5_principal client,
    2091             :                              krb5_keyblock *keyblock,
    2092             :                              krb5_deltat start_time,
    2093             :                              const char *in_tkt_service,
    2094             :                              krb5_get_init_creds_opt *options)
    2095             : {
    2096             :     krb5_init_creds_context ctx;
    2097             :     krb5_error_code ret;
    2098             : 
    2099          12 :     memset(creds, 0, sizeof(*creds));
    2100             : 
    2101          12 :     ret = krb5_init_creds_init(context, client, NULL, NULL, start_time, options, &ctx);
    2102          12 :     if (ret)
    2103           0 :         goto out;
    2104             : 
    2105          12 :     ret = krb5_init_creds_set_service(context, ctx, in_tkt_service);
    2106          12 :     if (ret)
    2107           0 :         goto out;
    2108             : 
    2109          12 :     ret = krb5_init_creds_set_keyblock(context, ctx, keyblock);
    2110          12 :     if (ret)
    2111           0 :         goto out;
    2112             : 
    2113          12 :     ret = krb5_init_creds_get(context, ctx);
    2114             : 
    2115          12 :     if (ret == 0)
    2116          12 :         process_last_request(context, options, ctx);
    2117             : 
    2118          12 :  out:
    2119          12 :     if (ret == 0)
    2120          12 :         krb5_init_creds_get_creds(context, ctx, creds);
    2121             : 
    2122          12 :     if (ctx)
    2123          12 :         krb5_init_creds_free(context, ctx);
    2124             : 
    2125          12 :     return ret;
    2126             : }
    2127             : 
    2128             : /**
    2129             :  * Get new credentials using keytab.
    2130             :  *
    2131             :  * @ingroup krb5_credential
    2132             :  */
    2133             : 
    2134             : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
    2135           7 : krb5_get_init_creds_keytab(krb5_context context,
    2136             :                            krb5_creds *creds,
    2137             :                            krb5_principal client,
    2138             :                            krb5_keytab keytab,
    2139             :                            krb5_deltat start_time,
    2140             :                            const char *in_tkt_service,
    2141             :                            krb5_get_init_creds_opt *options)
    2142             : {
    2143             :     krb5_init_creds_context ctx;
    2144             :     krb5_error_code ret;
    2145             : 
    2146           7 :     memset(creds, 0, sizeof(*creds));
    2147             : 
    2148           7 :     ret = krb5_init_creds_init(context, client, NULL, NULL, start_time, options, &ctx);
    2149           7 :     if (ret)
    2150           0 :         goto out;
    2151             : 
    2152           7 :     ret = krb5_init_creds_set_service(context, ctx, in_tkt_service);
    2153           7 :     if (ret)
    2154           0 :         goto out;
    2155             : 
    2156           7 :     ret = krb5_init_creds_set_keytab(context, ctx, keytab);
    2157           7 :     if (ret)
    2158           0 :         goto out;
    2159             : 
    2160           7 :     ret = krb5_init_creds_get(context, ctx);
    2161           7 :     if (ret == 0)
    2162           7 :         process_last_request(context, options, ctx);
    2163             : 
    2164           7 :  out:
    2165           7 :     if (ret == 0)
    2166           7 :         krb5_init_creds_get_creds(context, ctx, creds);
    2167             : 
    2168           7 :     if (ctx)
    2169           7 :         krb5_init_creds_free(context, ctx);
    2170             : 
    2171           7 :     return ret;
    2172             : }

Generated by: LCOV version 1.13