155682Smarkm/* 2233294Sstas * Copyright (c) 1997 - 2008 Kungliga Tekniska H��gskolan 3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4233294Sstas * All rights reserved. 555682Smarkm * 6233294Sstas * Portions Copyright (c) 2009 Apple Inc. All rights reserved. 755682Smarkm * 8233294Sstas * Redistribution and use in source and binary forms, with or without 9233294Sstas * modification, are permitted provided that the following conditions 10233294Sstas * are met: 1155682Smarkm * 12233294Sstas * 1. Redistributions of source code must retain the above copyright 13233294Sstas * notice, this list of conditions and the following disclaimer. 1455682Smarkm * 15233294Sstas * 2. Redistributions in binary form must reproduce the above copyright 16233294Sstas * notice, this list of conditions and the following disclaimer in the 17233294Sstas * documentation and/or other materials provided with the distribution. 1855682Smarkm * 19233294Sstas * 3. Neither the name of the Institute nor the names of its contributors 20233294Sstas * may be used to endorse or promote products derived from this software 21233294Sstas * without specific prior written permission. 22233294Sstas * 23233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26233294Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33233294Sstas * SUCH DAMAGE. 3455682Smarkm */ 3555682Smarkm 3655682Smarkm#include "krb5_locl.h" 3755682Smarkm 38178825Sdfrtypedef struct krb5_get_init_creds_ctx { 39178825Sdfr KDCOptions flags; 40178825Sdfr krb5_creds cred; 41178825Sdfr krb5_addresses *addrs; 42178825Sdfr krb5_enctype *etypes; 43178825Sdfr krb5_preauthtype *pre_auth_types; 44233294Sstas char *in_tkt_service; 45178825Sdfr unsigned nonce; 46178825Sdfr unsigned pk_nonce; 47178825Sdfr 48178825Sdfr krb5_data req_buffer; 49178825Sdfr AS_REQ as_req; 50178825Sdfr int pa_counter; 51178825Sdfr 52233294Sstas /* password and keytab_data is freed on completion */ 53233294Sstas char *password; 54233294Sstas krb5_keytab_key_proc_args *keytab_data; 55178825Sdfr 56233294Sstas krb5_pointer *keyseed; 57233294Sstas krb5_s2k_proc keyproc; 58233294Sstas 59178825Sdfr krb5_get_init_creds_tristate req_pac; 60178825Sdfr 61178825Sdfr krb5_pk_init_ctx pk_init_ctx; 62178825Sdfr int ic_flags; 63233294Sstas 64233294Sstas int used_pa_types; 65233294Sstas#define USED_PKINIT 1 66233294Sstas#define USED_PKINIT_W2K 2 67233294Sstas#define USED_ENC_TS_GUESS 4 68233294Sstas#define USED_ENC_TS_INFO 8 69233294Sstas 70233294Sstas METHOD_DATA md; 71233294Sstas KRB_ERROR error; 72233294Sstas AS_REP as_rep; 73233294Sstas EncKDCRepPart enc_part; 74233294Sstas 75233294Sstas krb5_prompter_fct prompter; 76233294Sstas void *prompter_data; 77233294Sstas 78233294Sstas struct pa_info_data *ppaid; 79233294Sstas 80178825Sdfr} krb5_get_init_creds_ctx; 81178825Sdfr 82233294Sstas 83233294Sstasstruct pa_info_data { 84233294Sstas krb5_enctype etype; 85233294Sstas krb5_salt salt; 86233294Sstas krb5_data *s2kparams; 87233294Sstas}; 88233294Sstas 89233294Sstasstatic void 90233294Sstasfree_paid(krb5_context context, struct pa_info_data *ppaid) 91233294Sstas{ 92233294Sstas krb5_free_salt(context, ppaid->salt); 93233294Sstas if (ppaid->s2kparams) 94233294Sstas krb5_free_data(context, ppaid->s2kparams); 95233294Sstas} 96233294Sstas 97233294Sstasstatic krb5_error_code KRB5_CALLCONV 98233294Sstasdefault_s2k_func(krb5_context context, krb5_enctype type, 99178825Sdfr krb5_const_pointer keyseed, 100178825Sdfr krb5_salt salt, krb5_data *s2kparms, 101178825Sdfr krb5_keyblock **key) 102178825Sdfr{ 103178825Sdfr krb5_error_code ret; 104178825Sdfr krb5_data password; 105178825Sdfr krb5_data opaque; 106178825Sdfr 107233294Sstas _krb5_debug(context, 5, "krb5_get_init_creds: using default_s2k_func"); 108233294Sstas 109178825Sdfr password.data = rk_UNCONST(keyseed); 110178825Sdfr password.length = strlen(keyseed); 111178825Sdfr if (s2kparms) 112178825Sdfr opaque = *s2kparms; 113178825Sdfr else 114178825Sdfr krb5_data_zero(&opaque); 115233294Sstas 116178825Sdfr *key = malloc(sizeof(**key)); 117178825Sdfr if (*key == NULL) 118178825Sdfr return ENOMEM; 119178825Sdfr ret = krb5_string_to_key_data_salt_opaque(context, type, password, 120178825Sdfr salt, opaque, *key); 121178825Sdfr if (ret) { 122178825Sdfr free(*key); 123178825Sdfr *key = NULL; 124178825Sdfr } 125178825Sdfr return ret; 126178825Sdfr} 127178825Sdfr 128178825Sdfrstatic void 129233294Sstasfree_init_creds_ctx(krb5_context context, krb5_init_creds_context ctx) 130178825Sdfr{ 131178825Sdfr if (ctx->etypes) 132178825Sdfr free(ctx->etypes); 133178825Sdfr if (ctx->pre_auth_types) 134178825Sdfr free (ctx->pre_auth_types); 135233294Sstas if (ctx->in_tkt_service) 136233294Sstas free(ctx->in_tkt_service); 137233294Sstas if (ctx->keytab_data) 138233294Sstas free(ctx->keytab_data); 139233294Sstas if (ctx->password) { 140233294Sstas memset(ctx->password, 0, strlen(ctx->password)); 141233294Sstas free(ctx->password); 142233294Sstas } 143233294Sstas krb5_data_free(&ctx->req_buffer); 144233294Sstas krb5_free_cred_contents(context, &ctx->cred); 145233294Sstas free_METHOD_DATA(&ctx->md); 146233294Sstas free_AS_REP(&ctx->as_rep); 147233294Sstas free_EncKDCRepPart(&ctx->enc_part); 148233294Sstas free_KRB_ERROR(&ctx->error); 149178825Sdfr free_AS_REQ(&ctx->as_req); 150233294Sstas if (ctx->ppaid) { 151233294Sstas free_paid(context, ctx->ppaid); 152233294Sstas free(ctx->ppaid); 153233294Sstas } 154233294Sstas memset(ctx, 0, sizeof(*ctx)); 155178825Sdfr} 156178825Sdfr 15755682Smarkmstatic int 15855682Smarkmget_config_time (krb5_context context, 15990926Snectar const char *realm, 16090926Snectar const char *name, 16155682Smarkm int def) 16255682Smarkm{ 16355682Smarkm int ret; 16455682Smarkm 16555682Smarkm ret = krb5_config_get_time (context, NULL, 16655682Smarkm "realms", 16755682Smarkm realm, 16855682Smarkm name, 16955682Smarkm NULL); 17055682Smarkm if (ret >= 0) 17155682Smarkm return ret; 17255682Smarkm ret = krb5_config_get_time (context, NULL, 17355682Smarkm "libdefaults", 17455682Smarkm name, 17555682Smarkm NULL); 17655682Smarkm if (ret >= 0) 17755682Smarkm return ret; 17855682Smarkm return def; 17955682Smarkm} 18055682Smarkm 18155682Smarkmstatic krb5_error_code 18255682Smarkminit_cred (krb5_context context, 18355682Smarkm krb5_creds *cred, 18455682Smarkm krb5_principal client, 18555682Smarkm krb5_deltat start_time, 18655682Smarkm krb5_get_init_creds_opt *options) 18755682Smarkm{ 18855682Smarkm krb5_error_code ret; 18955682Smarkm int tmp; 19057416Smarkm krb5_timestamp now; 19155682Smarkm 19255682Smarkm krb5_timeofday (context, &now); 19355682Smarkm 19455682Smarkm memset (cred, 0, sizeof(*cred)); 195233294Sstas 19655682Smarkm if (client) 19755682Smarkm krb5_copy_principal(context, client, &cred->client); 19855682Smarkm else { 19955682Smarkm ret = krb5_get_default_principal (context, 20055682Smarkm &cred->client); 20155682Smarkm if (ret) 20255682Smarkm goto out; 20355682Smarkm } 20455682Smarkm 20555682Smarkm if (start_time) 20655682Smarkm cred->times.starttime = now + start_time; 20755682Smarkm 20855682Smarkm if (options->flags & KRB5_GET_INIT_CREDS_OPT_TKT_LIFE) 20955682Smarkm tmp = options->tkt_life; 21055682Smarkm else 21190926Snectar tmp = 10 * 60 * 60; 21255682Smarkm cred->times.endtime = now + tmp; 21355682Smarkm 21490926Snectar if ((options->flags & KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE) && 21590926Snectar options->renew_life > 0) { 21690926Snectar cred->times.renew_till = now + options->renew_life; 21790926Snectar } 21855682Smarkm 21955682Smarkm return 0; 22055682Smarkm 22155682Smarkmout: 222178825Sdfr krb5_free_cred_contents (context, cred); 22355682Smarkm return ret; 22455682Smarkm} 22555682Smarkm 22655682Smarkm/* 227102644Snectar * Print a message (str) to the user about the expiration in `lr' 228102644Snectar */ 229102644Snectar 230102644Snectarstatic void 231102644Snectarreport_expiration (krb5_context context, 232102644Snectar krb5_prompter_fct prompter, 233102644Snectar krb5_data *data, 234102644Snectar const char *str, 235178825Sdfr time_t now) 236102644Snectar{ 237233294Sstas char *p = NULL; 238233294Sstas 239233294Sstas if (asprintf(&p, "%s%s", str, ctime(&now)) < 0 || p == NULL) 240233294Sstas return; 241233294Sstas (*prompter)(context, data, NULL, p, 0, NULL); 242233294Sstas free(p); 243102644Snectar} 244102644Snectar 245102644Snectar/* 246233294Sstas * Check the context, and in the case there is a expiration warning, 247233294Sstas * use the prompter to print the warning. 248233294Sstas * 249233294Sstas * @param context A Kerberos 5 context. 250233294Sstas * @param options An GIC options structure 251233294Sstas * @param ctx The krb5_init_creds_context check for expiration. 25255682Smarkm */ 25355682Smarkm 254233294Sstasstatic krb5_error_code 255233294Sstasprocess_last_request(krb5_context context, 256233294Sstas krb5_get_init_creds_opt *options, 257233294Sstas krb5_init_creds_context ctx) 25855682Smarkm{ 259233294Sstas krb5_const_realm realm; 260233294Sstas LastReq *lr; 261233294Sstas krb5_boolean reported = FALSE; 26257416Smarkm krb5_timestamp sec; 26355682Smarkm time_t t; 264233294Sstas size_t i; 26555682Smarkm 266233294Sstas /* 267233294Sstas * First check if there is a API consumer. 268233294Sstas */ 269233294Sstas 270233294Sstas realm = krb5_principal_get_realm (context, ctx->cred.client); 271233294Sstas lr = &ctx->enc_part.last_req; 272233294Sstas 273233294Sstas if (options && options->opt_private && options->opt_private->lr.func) { 274233294Sstas krb5_last_req_entry **lre; 275233294Sstas 276233294Sstas lre = calloc(lr->len + 1, sizeof(**lre)); 277233294Sstas if (lre == NULL) { 278233294Sstas krb5_set_error_message(context, ENOMEM, 279233294Sstas N_("malloc: out of memory", "")); 280233294Sstas return ENOMEM; 281233294Sstas } 282233294Sstas for (i = 0; i < lr->len; i++) { 283233294Sstas lre[i] = calloc(1, sizeof(*lre[i])); 284233294Sstas if (lre[i] == NULL) 285233294Sstas break; 286233294Sstas lre[i]->lr_type = lr->val[i].lr_type; 287233294Sstas lre[i]->value = lr->val[i].lr_value; 288233294Sstas } 289233294Sstas 290233294Sstas (*options->opt_private->lr.func)(context, lre, 291233294Sstas options->opt_private->lr.ctx); 292233294Sstas 293233294Sstas for (i = 0; i < lr->len; i++) 294233294Sstas free(lre[i]); 295233294Sstas free(lre); 296233294Sstas } 297233294Sstas 298233294Sstas /* 299233294Sstas * Now check if we should prompt the user 300233294Sstas */ 301233294Sstas 302233294Sstas if (ctx->prompter == NULL) 303233294Sstas return 0; 304233294Sstas 30555682Smarkm krb5_timeofday (context, &sec); 30655682Smarkm 30755682Smarkm t = sec + get_config_time (context, 308178825Sdfr realm, 30955682Smarkm "warn_pwexpire", 31055682Smarkm 7 * 24 * 60 * 60); 31155682Smarkm 31255682Smarkm for (i = 0; i < lr->len; ++i) { 313102644Snectar if (lr->val[i].lr_value <= t) { 314102644Snectar switch (abs(lr->val[i].lr_type)) { 315102644Snectar case LR_PW_EXPTIME : 316233294Sstas report_expiration(context, ctx->prompter, 317233294Sstas ctx->prompter_data, 318102644Snectar "Your password will expire at ", 319102644Snectar lr->val[i].lr_value); 320102644Snectar reported = TRUE; 321102644Snectar break; 322102644Snectar case LR_ACCT_EXPTIME : 323233294Sstas report_expiration(context, ctx->prompter, 324233294Sstas ctx->prompter_data, 325102644Snectar "Your account will expire at ", 326102644Snectar lr->val[i].lr_value); 327102644Snectar reported = TRUE; 328102644Snectar break; 329102644Snectar } 33055682Smarkm } 33155682Smarkm } 33255682Smarkm 333102644Snectar if (!reported 334233294Sstas && ctx->enc_part.key_expiration 335233294Sstas && *ctx->enc_part.key_expiration <= t) { 336233294Sstas report_expiration(context, ctx->prompter, 337233294Sstas ctx->prompter_data, 338102644Snectar "Your password/account will expire at ", 339233294Sstas *ctx->enc_part.key_expiration); 34055682Smarkm } 341233294Sstas return 0; 34255682Smarkm} 34355682Smarkm 344178825Sdfrstatic krb5_addresses no_addrs = { 0, NULL }; 345178825Sdfr 34655682Smarkmstatic krb5_error_code 34755682Smarkmget_init_creds_common(krb5_context context, 34855682Smarkm krb5_principal client, 34955682Smarkm krb5_deltat start_time, 35055682Smarkm krb5_get_init_creds_opt *options, 351233294Sstas krb5_init_creds_context ctx) 35255682Smarkm{ 353233294Sstas krb5_get_init_creds_opt *default_opt = NULL; 35455682Smarkm krb5_error_code ret; 355178825Sdfr krb5_enctype *etypes; 356178825Sdfr krb5_preauthtype *pre_auth_types; 35755682Smarkm 358178825Sdfr memset(ctx, 0, sizeof(*ctx)); 359178825Sdfr 36078527Sassar if (options == NULL) { 361233294Sstas const char *realm = krb5_principal_get_realm(context, client); 362233294Sstas 363233294Sstas krb5_get_init_creds_opt_alloc (context, &default_opt); 364233294Sstas options = default_opt; 365233294Sstas krb5_get_init_creds_opt_set_default_flags(context, NULL, realm, options); 36678527Sassar } 36778527Sassar 368178825Sdfr if (options->opt_private) { 369233294Sstas if (options->opt_private->password) { 370233294Sstas ret = krb5_init_creds_set_password(context, ctx, 371233294Sstas options->opt_private->password); 372233294Sstas if (ret) 373233294Sstas goto out; 374233294Sstas } 375233294Sstas 376233294Sstas ctx->keyproc = options->opt_private->key_proc; 377178825Sdfr ctx->req_pac = options->opt_private->req_pac; 378178825Sdfr ctx->pk_init_ctx = options->opt_private->pk_init_ctx; 379178825Sdfr ctx->ic_flags = options->opt_private->flags; 380178825Sdfr } else 381178825Sdfr ctx->req_pac = KRB5_INIT_CREDS_TRISTATE_UNSET; 382178825Sdfr 383233294Sstas if (ctx->keyproc == NULL) 384233294Sstas ctx->keyproc = default_s2k_func; 385178825Sdfr 386233294Sstas /* Enterprise name implicitly turns on canonicalize */ 387233294Sstas if ((ctx->ic_flags & KRB5_INIT_CREDS_CANONICALIZE) || 388233294Sstas krb5_principal_get_type(context, client) == KRB5_NT_ENTERPRISE_PRINCIPAL) 389178825Sdfr ctx->flags.canonicalize = 1; 390178825Sdfr 391178825Sdfr ctx->pre_auth_types = NULL; 392178825Sdfr ctx->addrs = NULL; 393178825Sdfr ctx->etypes = NULL; 394178825Sdfr ctx->pre_auth_types = NULL; 395178825Sdfr 396233294Sstas ret = init_cred(context, &ctx->cred, client, start_time, options); 397233294Sstas if (ret) { 398233294Sstas if (default_opt) 399233294Sstas krb5_get_init_creds_opt_free(context, default_opt); 40055682Smarkm return ret; 401233294Sstas } 40255682Smarkm 403233294Sstas ret = krb5_init_creds_set_service(context, ctx, NULL); 404233294Sstas if (ret) 405233294Sstas goto out; 406233294Sstas 40755682Smarkm if (options->flags & KRB5_GET_INIT_CREDS_OPT_FORWARDABLE) 408178825Sdfr ctx->flags.forwardable = options->forwardable; 40955682Smarkm 41055682Smarkm if (options->flags & KRB5_GET_INIT_CREDS_OPT_PROXIABLE) 411178825Sdfr ctx->flags.proxiable = options->proxiable; 41255682Smarkm 41355682Smarkm if (start_time) 414178825Sdfr ctx->flags.postdated = 1; 415178825Sdfr if (ctx->cred.times.renew_till) 416178825Sdfr ctx->flags.renewable = 1; 417178825Sdfr if (options->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST) { 418178825Sdfr ctx->addrs = options->address_list; 419178825Sdfr } else if (options->opt_private) { 420178825Sdfr switch (options->opt_private->addressless) { 421178825Sdfr case KRB5_INIT_CREDS_TRISTATE_UNSET: 422178825Sdfr#if KRB5_ADDRESSLESS_DEFAULT == TRUE 423178825Sdfr ctx->addrs = &no_addrs; 424178825Sdfr#else 425178825Sdfr ctx->addrs = NULL; 426178825Sdfr#endif 427178825Sdfr break; 428178825Sdfr case KRB5_INIT_CREDS_TRISTATE_FALSE: 429178825Sdfr ctx->addrs = NULL; 430178825Sdfr break; 431178825Sdfr case KRB5_INIT_CREDS_TRISTATE_TRUE: 432178825Sdfr ctx->addrs = &no_addrs; 433178825Sdfr break; 434178825Sdfr } 435178825Sdfr } 43655682Smarkm if (options->flags & KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST) { 437233294Sstas if (ctx->etypes) 438233294Sstas free(ctx->etypes); 439233294Sstas 440178825Sdfr etypes = malloc((options->etype_list_length + 1) 44155682Smarkm * sizeof(krb5_enctype)); 442178825Sdfr if (etypes == NULL) { 443233294Sstas ret = ENOMEM; 444233294Sstas krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 445233294Sstas goto out; 44678527Sassar } 447178825Sdfr memcpy (etypes, options->etype_list, 44855682Smarkm options->etype_list_length * sizeof(krb5_enctype)); 449178825Sdfr etypes[options->etype_list_length] = ETYPE_NULL; 450178825Sdfr ctx->etypes = etypes; 45155682Smarkm } 45255682Smarkm if (options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST) { 453178825Sdfr pre_auth_types = malloc((options->preauth_list_length + 1) 454178825Sdfr * sizeof(krb5_preauthtype)); 455178825Sdfr if (pre_auth_types == NULL) { 456233294Sstas ret = ENOMEM; 457233294Sstas krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 458233294Sstas goto out; 45978527Sassar } 460178825Sdfr memcpy (pre_auth_types, options->preauth_list, 46155682Smarkm options->preauth_list_length * sizeof(krb5_preauthtype)); 462178825Sdfr pre_auth_types[options->preauth_list_length] = KRB5_PADATA_NONE; 463178825Sdfr ctx->pre_auth_types = pre_auth_types; 46455682Smarkm } 46572445Sassar if (options->flags & KRB5_GET_INIT_CREDS_OPT_ANONYMOUS) 466178825Sdfr ctx->flags.request_anonymous = options->anonymous; 467233294Sstas if (default_opt) 468233294Sstas krb5_get_init_creds_opt_free(context, default_opt); 46955682Smarkm return 0; 470233294Sstas out: 471233294Sstas if (default_opt) 472233294Sstas krb5_get_init_creds_opt_free(context, default_opt); 473233294Sstas return ret; 47455682Smarkm} 47555682Smarkm 47655682Smarkmstatic krb5_error_code 47755682Smarkmchange_password (krb5_context context, 47855682Smarkm krb5_principal client, 47955682Smarkm const char *password, 48055682Smarkm char *newpw, 48155682Smarkm size_t newpw_sz, 48255682Smarkm krb5_prompter_fct prompter, 48355682Smarkm void *data, 48455682Smarkm krb5_get_init_creds_opt *old_options) 48555682Smarkm{ 48678527Sassar krb5_prompt prompts[2]; 48755682Smarkm krb5_error_code ret; 48855682Smarkm krb5_creds cpw_cred; 48955682Smarkm char buf1[BUFSIZ], buf2[BUFSIZ]; 49090926Snectar krb5_data password_data[2]; 49155682Smarkm int result_code; 49255682Smarkm krb5_data result_code_string; 49355682Smarkm krb5_data result_string; 49455682Smarkm char *p; 495233294Sstas krb5_get_init_creds_opt *options; 49655682Smarkm 49755682Smarkm memset (&cpw_cred, 0, sizeof(cpw_cred)); 49855682Smarkm 499233294Sstas ret = krb5_get_init_creds_opt_alloc(context, &options); 500233294Sstas if (ret) 501233294Sstas return ret; 502233294Sstas krb5_get_init_creds_opt_set_tkt_life (options, 60); 503233294Sstas krb5_get_init_creds_opt_set_forwardable (options, FALSE); 504233294Sstas krb5_get_init_creds_opt_set_proxiable (options, FALSE); 505178825Sdfr if (old_options && old_options->flags & KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST) 506233294Sstas krb5_get_init_creds_opt_set_preauth_list (options, 50772445Sassar old_options->preauth_list, 508233294Sstas old_options->preauth_list_length); 50955682Smarkm 51055682Smarkm krb5_data_zero (&result_code_string); 51155682Smarkm krb5_data_zero (&result_string); 51255682Smarkm 51355682Smarkm ret = krb5_get_init_creds_password (context, 51455682Smarkm &cpw_cred, 51555682Smarkm client, 51655682Smarkm password, 51755682Smarkm prompter, 51855682Smarkm data, 51955682Smarkm 0, 52055682Smarkm "kadmin/changepw", 521233294Sstas options); 522233294Sstas krb5_get_init_creds_opt_free(context, options); 52355682Smarkm if (ret) 52455682Smarkm goto out; 52555682Smarkm 52655682Smarkm for(;;) { 52790926Snectar password_data[0].data = buf1; 52890926Snectar password_data[0].length = sizeof(buf1); 52955682Smarkm 53078527Sassar prompts[0].hidden = 1; 53178527Sassar prompts[0].prompt = "New password: "; 53290926Snectar prompts[0].reply = &password_data[0]; 53378527Sassar prompts[0].type = KRB5_PROMPT_TYPE_NEW_PASSWORD; 53455682Smarkm 53590926Snectar password_data[1].data = buf2; 53690926Snectar password_data[1].length = sizeof(buf2); 53755682Smarkm 53878527Sassar prompts[1].hidden = 1; 53978527Sassar prompts[1].prompt = "Repeat new password: "; 54090926Snectar prompts[1].reply = &password_data[1]; 54178527Sassar prompts[1].type = KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN; 54255682Smarkm 54378527Sassar ret = (*prompter) (context, data, NULL, "Changing password", 54478527Sassar 2, prompts); 54578527Sassar if (ret) { 54678527Sassar memset (buf1, 0, sizeof(buf1)); 54778527Sassar memset (buf2, 0, sizeof(buf2)); 54855682Smarkm goto out; 54978527Sassar } 55055682Smarkm 55155682Smarkm if (strcmp (buf1, buf2) == 0) 55255682Smarkm break; 55378527Sassar memset (buf1, 0, sizeof(buf1)); 55478527Sassar memset (buf2, 0, sizeof(buf2)); 55555682Smarkm } 556233294Sstas 557233294Sstas ret = krb5_set_password (context, 558233294Sstas &cpw_cred, 559233294Sstas buf1, 560233294Sstas client, 561233294Sstas &result_code, 562233294Sstas &result_code_string, 563233294Sstas &result_string); 56455682Smarkm if (ret) 56555682Smarkm goto out; 566233294Sstas if (asprintf(&p, "%s: %.*s\n", 567233294Sstas result_code ? "Error" : "Success", 568233294Sstas (int)result_string.length, 569233294Sstas result_string.length > 0 ? (char*)result_string.data : "") < 0) 570233294Sstas { 571233294Sstas ret = ENOMEM; 572233294Sstas goto out; 573233294Sstas } 57455682Smarkm 575233294Sstas /* return the result */ 576233294Sstas (*prompter) (context, data, NULL, p, 0, NULL); 577233294Sstas 57855682Smarkm free (p); 57955682Smarkm if (result_code == 0) { 58057416Smarkm strlcpy (newpw, buf1, newpw_sz); 58155682Smarkm ret = 0; 58278527Sassar } else { 58355682Smarkm ret = ENOTTY; 584233294Sstas krb5_set_error_message(context, ret, 585233294Sstas N_("failed changing password", "")); 58678527Sassar } 58755682Smarkm 58855682Smarkmout: 58955682Smarkm memset (buf1, 0, sizeof(buf1)); 59055682Smarkm memset (buf2, 0, sizeof(buf2)); 59155682Smarkm krb5_data_free (&result_string); 59255682Smarkm krb5_data_free (&result_code_string); 593178825Sdfr krb5_free_cred_contents (context, &cpw_cred); 59455682Smarkm return ret; 59555682Smarkm} 59655682Smarkm 597233294Sstas 598233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 599178825Sdfrkrb5_keyblock_key_proc (krb5_context context, 600178825Sdfr krb5_keytype type, 601178825Sdfr krb5_data *salt, 602178825Sdfr krb5_const_pointer keyseed, 603178825Sdfr krb5_keyblock **key) 60455682Smarkm{ 605178825Sdfr return krb5_copy_keyblock (context, keyseed, key); 606178825Sdfr} 607178825Sdfr 608178825Sdfr/* 609178825Sdfr * 610178825Sdfr */ 611178825Sdfr 612178825Sdfrstatic krb5_error_code 613233294Sstasinit_as_req (krb5_context context, 614233294Sstas KDCOptions opts, 615233294Sstas const krb5_creds *creds, 616233294Sstas const krb5_addresses *addrs, 617233294Sstas const krb5_enctype *etypes, 618233294Sstas AS_REQ *a) 619178825Sdfr{ 620178825Sdfr krb5_error_code ret; 621178825Sdfr 622178825Sdfr memset(a, 0, sizeof(*a)); 623178825Sdfr 624178825Sdfr a->pvno = 5; 625178825Sdfr a->msg_type = krb_as_req; 626178825Sdfr a->req_body.kdc_options = opts; 627178825Sdfr a->req_body.cname = malloc(sizeof(*a->req_body.cname)); 628178825Sdfr if (a->req_body.cname == NULL) { 629178825Sdfr ret = ENOMEM; 630233294Sstas krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 631178825Sdfr goto fail; 632178825Sdfr } 633178825Sdfr a->req_body.sname = malloc(sizeof(*a->req_body.sname)); 634178825Sdfr if (a->req_body.sname == NULL) { 635178825Sdfr ret = ENOMEM; 636233294Sstas krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 637178825Sdfr goto fail; 638178825Sdfr } 639178825Sdfr 640178825Sdfr ret = _krb5_principal2principalname (a->req_body.cname, creds->client); 641178825Sdfr if (ret) 642178825Sdfr goto fail; 643178825Sdfr ret = copy_Realm(&creds->client->realm, &a->req_body.realm); 644178825Sdfr if (ret) 645178825Sdfr goto fail; 646178825Sdfr 647178825Sdfr ret = _krb5_principal2principalname (a->req_body.sname, creds->server); 648178825Sdfr if (ret) 649178825Sdfr goto fail; 650178825Sdfr 651178825Sdfr if(creds->times.starttime) { 652178825Sdfr a->req_body.from = malloc(sizeof(*a->req_body.from)); 653178825Sdfr if (a->req_body.from == NULL) { 654178825Sdfr ret = ENOMEM; 655233294Sstas krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 656178825Sdfr goto fail; 657178825Sdfr } 658178825Sdfr *a->req_body.from = creds->times.starttime; 659178825Sdfr } 660178825Sdfr if(creds->times.endtime){ 661178825Sdfr ALLOC(a->req_body.till, 1); 662178825Sdfr *a->req_body.till = creds->times.endtime; 663178825Sdfr } 664178825Sdfr if(creds->times.renew_till){ 665178825Sdfr a->req_body.rtime = malloc(sizeof(*a->req_body.rtime)); 666178825Sdfr if (a->req_body.rtime == NULL) { 667178825Sdfr ret = ENOMEM; 668233294Sstas krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 669178825Sdfr goto fail; 670178825Sdfr } 671178825Sdfr *a->req_body.rtime = creds->times.renew_till; 672178825Sdfr } 673178825Sdfr a->req_body.nonce = 0; 674233294Sstas ret = _krb5_init_etype(context, 675233294Sstas KRB5_PDU_AS_REQUEST, 676178825Sdfr &a->req_body.etype.len, 677178825Sdfr &a->req_body.etype.val, 678178825Sdfr etypes); 679178825Sdfr if (ret) 680178825Sdfr goto fail; 681178825Sdfr 682178825Sdfr /* 683178825Sdfr * This means no addresses 684178825Sdfr */ 685178825Sdfr 686178825Sdfr if (addrs && addrs->len == 0) { 687178825Sdfr a->req_body.addresses = NULL; 688178825Sdfr } else { 689178825Sdfr a->req_body.addresses = malloc(sizeof(*a->req_body.addresses)); 690178825Sdfr if (a->req_body.addresses == NULL) { 691178825Sdfr ret = ENOMEM; 692233294Sstas krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 693178825Sdfr goto fail; 694178825Sdfr } 695178825Sdfr 696178825Sdfr if (addrs) 697178825Sdfr ret = krb5_copy_addresses(context, addrs, a->req_body.addresses); 698178825Sdfr else { 699178825Sdfr ret = krb5_get_all_client_addrs (context, a->req_body.addresses); 700178825Sdfr if(ret == 0 && a->req_body.addresses->len == 0) { 701178825Sdfr free(a->req_body.addresses); 702178825Sdfr a->req_body.addresses = NULL; 703178825Sdfr } 704178825Sdfr } 705178825Sdfr if (ret) 706178825Sdfr goto fail; 707178825Sdfr } 708178825Sdfr 709178825Sdfr a->req_body.enc_authorization_data = NULL; 710178825Sdfr a->req_body.additional_tickets = NULL; 711178825Sdfr 712178825Sdfr a->padata = NULL; 713178825Sdfr 714178825Sdfr return 0; 715178825Sdfr fail: 716178825Sdfr free_AS_REQ(a); 717178825Sdfr memset(a, 0, sizeof(*a)); 718178825Sdfr return ret; 719178825Sdfr} 720178825Sdfr 721178825Sdfr 722178825Sdfrstatic krb5_error_code 723178825Sdfrset_paid(struct pa_info_data *paid, krb5_context context, 724178825Sdfr krb5_enctype etype, 725178825Sdfr krb5_salttype salttype, void *salt_string, size_t salt_len, 726178825Sdfr krb5_data *s2kparams) 727178825Sdfr{ 728178825Sdfr paid->etype = etype; 729178825Sdfr paid->salt.salttype = salttype; 730178825Sdfr paid->salt.saltvalue.data = malloc(salt_len + 1); 731178825Sdfr if (paid->salt.saltvalue.data == NULL) { 732233294Sstas krb5_clear_error_message(context); 733178825Sdfr return ENOMEM; 734178825Sdfr } 735178825Sdfr memcpy(paid->salt.saltvalue.data, salt_string, salt_len); 736178825Sdfr ((char *)paid->salt.saltvalue.data)[salt_len] = '\0'; 737178825Sdfr paid->salt.saltvalue.length = salt_len; 738178825Sdfr if (s2kparams) { 739178825Sdfr krb5_error_code ret; 740178825Sdfr 741178825Sdfr ret = krb5_copy_data(context, s2kparams, &paid->s2kparams); 742178825Sdfr if (ret) { 743233294Sstas krb5_clear_error_message(context); 744178825Sdfr krb5_free_salt(context, paid->salt); 745178825Sdfr return ret; 746178825Sdfr } 747178825Sdfr } else 748178825Sdfr paid->s2kparams = NULL; 749178825Sdfr 750178825Sdfr return 0; 751178825Sdfr} 752178825Sdfr 753178825Sdfrstatic struct pa_info_data * 754178825Sdfrpa_etype_info2(krb5_context context, 755233294Sstas const krb5_principal client, 756178825Sdfr const AS_REQ *asreq, 757233294Sstas struct pa_info_data *paid, 758178825Sdfr heim_octet_string *data) 759178825Sdfr{ 760178825Sdfr krb5_error_code ret; 761178825Sdfr ETYPE_INFO2 e; 762178825Sdfr size_t sz; 763233294Sstas size_t i, j; 764178825Sdfr 765178825Sdfr memset(&e, 0, sizeof(e)); 766178825Sdfr ret = decode_ETYPE_INFO2(data->data, data->length, &e, &sz); 767178825Sdfr if (ret) 76855682Smarkm goto out; 769178825Sdfr if (e.len == 0) 770178825Sdfr goto out; 771178825Sdfr for (j = 0; j < asreq->req_body.etype.len; j++) { 772178825Sdfr for (i = 0; i < e.len; i++) { 773178825Sdfr if (asreq->req_body.etype.val[j] == e.val[i].etype) { 774178825Sdfr krb5_salt salt; 775178825Sdfr if (e.val[i].salt == NULL) 776178825Sdfr ret = krb5_get_pw_salt(context, client, &salt); 777178825Sdfr else { 778178825Sdfr salt.saltvalue.data = *e.val[i].salt; 779178825Sdfr salt.saltvalue.length = strlen(*e.val[i].salt); 780178825Sdfr ret = 0; 781178825Sdfr } 782178825Sdfr if (ret == 0) 783178825Sdfr ret = set_paid(paid, context, e.val[i].etype, 784178825Sdfr KRB5_PW_SALT, 785233294Sstas salt.saltvalue.data, 786178825Sdfr salt.saltvalue.length, 787178825Sdfr e.val[i].s2kparams); 788178825Sdfr if (e.val[i].salt == NULL) 789178825Sdfr krb5_free_salt(context, salt); 790178825Sdfr if (ret == 0) { 791178825Sdfr free_ETYPE_INFO2(&e); 792178825Sdfr return paid; 793178825Sdfr } 794178825Sdfr } 795178825Sdfr } 796178825Sdfr } 797178825Sdfr out: 798178825Sdfr free_ETYPE_INFO2(&e); 799178825Sdfr return NULL; 800178825Sdfr} 80155682Smarkm 802178825Sdfrstatic struct pa_info_data * 803178825Sdfrpa_etype_info(krb5_context context, 804233294Sstas const krb5_principal client, 805178825Sdfr const AS_REQ *asreq, 806178825Sdfr struct pa_info_data *paid, 807178825Sdfr heim_octet_string *data) 808178825Sdfr{ 809178825Sdfr krb5_error_code ret; 810178825Sdfr ETYPE_INFO e; 811178825Sdfr size_t sz; 812233294Sstas size_t i, j; 81355682Smarkm 814178825Sdfr memset(&e, 0, sizeof(e)); 815178825Sdfr ret = decode_ETYPE_INFO(data->data, data->length, &e, &sz); 816178825Sdfr if (ret) 817178825Sdfr goto out; 818178825Sdfr if (e.len == 0) 819178825Sdfr goto out; 820178825Sdfr for (j = 0; j < asreq->req_body.etype.len; j++) { 821178825Sdfr for (i = 0; i < e.len; i++) { 822178825Sdfr if (asreq->req_body.etype.val[j] == e.val[i].etype) { 823178825Sdfr krb5_salt salt; 824178825Sdfr salt.salttype = KRB5_PW_SALT; 825178825Sdfr if (e.val[i].salt == NULL) 826178825Sdfr ret = krb5_get_pw_salt(context, client, &salt); 827178825Sdfr else { 828178825Sdfr salt.saltvalue = *e.val[i].salt; 829178825Sdfr ret = 0; 830178825Sdfr } 831178825Sdfr if (e.val[i].salttype) 832178825Sdfr salt.salttype = *e.val[i].salttype; 833178825Sdfr if (ret == 0) { 834178825Sdfr ret = set_paid(paid, context, e.val[i].etype, 835178825Sdfr salt.salttype, 836233294Sstas salt.saltvalue.data, 837178825Sdfr salt.saltvalue.length, 838178825Sdfr NULL); 839178825Sdfr if (e.val[i].salt == NULL) 840178825Sdfr krb5_free_salt(context, salt); 841178825Sdfr } 842178825Sdfr if (ret == 0) { 843178825Sdfr free_ETYPE_INFO(&e); 844178825Sdfr return paid; 845178825Sdfr } 846178825Sdfr } 847178825Sdfr } 848178825Sdfr } 849178825Sdfr out: 850178825Sdfr free_ETYPE_INFO(&e); 851178825Sdfr return NULL; 852178825Sdfr} 85355682Smarkm 854178825Sdfrstatic struct pa_info_data * 855178825Sdfrpa_pw_or_afs3_salt(krb5_context context, 856233294Sstas const krb5_principal client, 857178825Sdfr const AS_REQ *asreq, 858178825Sdfr struct pa_info_data *paid, 859178825Sdfr heim_octet_string *data) 860178825Sdfr{ 861178825Sdfr krb5_error_code ret; 862178825Sdfr if (paid->etype == ENCTYPE_NULL) 863178825Sdfr return NULL; 864233294Sstas ret = set_paid(paid, context, 865178825Sdfr paid->etype, 866178825Sdfr paid->salt.salttype, 867233294Sstas data->data, 868178825Sdfr data->length, 869178825Sdfr NULL); 870178825Sdfr if (ret) 871178825Sdfr return NULL; 872178825Sdfr return paid; 873178825Sdfr} 874178825Sdfr 875178825Sdfr 876178825Sdfrstruct pa_info { 877178825Sdfr krb5_preauthtype type; 878178825Sdfr struct pa_info_data *(*salt_info)(krb5_context, 879233294Sstas const krb5_principal, 880178825Sdfr const AS_REQ *, 881233294Sstas struct pa_info_data *, 882178825Sdfr heim_octet_string *); 883178825Sdfr}; 884178825Sdfr 885178825Sdfrstatic struct pa_info pa_prefs[] = { 886178825Sdfr { KRB5_PADATA_ETYPE_INFO2, pa_etype_info2 }, 887178825Sdfr { KRB5_PADATA_ETYPE_INFO, pa_etype_info }, 888178825Sdfr { KRB5_PADATA_PW_SALT, pa_pw_or_afs3_salt }, 889178825Sdfr { KRB5_PADATA_AFS3_SALT, pa_pw_or_afs3_salt } 890178825Sdfr}; 891233294Sstas 892178825Sdfrstatic PA_DATA * 893233294Sstasfind_pa_data(const METHOD_DATA *md, unsigned type) 894178825Sdfr{ 895233294Sstas size_t i; 896178825Sdfr if (md == NULL) 897178825Sdfr return NULL; 898178825Sdfr for (i = 0; i < md->len; i++) 899178825Sdfr if (md->val[i].padata_type == type) 900178825Sdfr return &md->val[i]; 901178825Sdfr return NULL; 902178825Sdfr} 903178825Sdfr 904178825Sdfrstatic struct pa_info_data * 905233294Sstasprocess_pa_info(krb5_context context, 906233294Sstas const krb5_principal client, 907178825Sdfr const AS_REQ *asreq, 908178825Sdfr struct pa_info_data *paid, 909178825Sdfr METHOD_DATA *md) 910178825Sdfr{ 911178825Sdfr struct pa_info_data *p = NULL; 912233294Sstas size_t i; 913178825Sdfr 914178825Sdfr for (i = 0; p == NULL && i < sizeof(pa_prefs)/sizeof(pa_prefs[0]); i++) { 915178825Sdfr PA_DATA *pa = find_pa_data(md, pa_prefs[i].type); 916178825Sdfr if (pa == NULL) 917178825Sdfr continue; 918233294Sstas paid->salt.salttype = (krb5_salttype)pa_prefs[i].type; 919178825Sdfr p = (*pa_prefs[i].salt_info)(context, client, asreq, 920178825Sdfr paid, &pa->padata_value); 921178825Sdfr } 922178825Sdfr return p; 923178825Sdfr} 924178825Sdfr 925178825Sdfrstatic krb5_error_code 926233294Sstasmake_pa_enc_timestamp(krb5_context context, METHOD_DATA *md, 927178825Sdfr krb5_enctype etype, krb5_keyblock *key) 928178825Sdfr{ 929178825Sdfr PA_ENC_TS_ENC p; 930178825Sdfr unsigned char *buf; 931178825Sdfr size_t buf_size; 932233294Sstas size_t len = 0; 933178825Sdfr EncryptedData encdata; 934178825Sdfr krb5_error_code ret; 935178825Sdfr int32_t usec; 936178825Sdfr int usec2; 937178825Sdfr krb5_crypto crypto; 938233294Sstas 939178825Sdfr krb5_us_timeofday (context, &p.patimestamp, &usec); 940178825Sdfr usec2 = usec; 941178825Sdfr p.pausec = &usec2; 942178825Sdfr 943178825Sdfr ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC, buf, buf_size, &p, &len, ret); 944178825Sdfr if (ret) 945178825Sdfr return ret; 946178825Sdfr if(buf_size != len) 947178825Sdfr krb5_abortx(context, "internal error in ASN.1 encoder"); 948178825Sdfr 949178825Sdfr ret = krb5_crypto_init(context, key, 0, &crypto); 950178825Sdfr if (ret) { 951178825Sdfr free(buf); 952178825Sdfr return ret; 953178825Sdfr } 954233294Sstas ret = krb5_encrypt_EncryptedData(context, 955178825Sdfr crypto, 956178825Sdfr KRB5_KU_PA_ENC_TIMESTAMP, 957178825Sdfr buf, 958178825Sdfr len, 959178825Sdfr 0, 960178825Sdfr &encdata); 961178825Sdfr free(buf); 962178825Sdfr krb5_crypto_destroy(context, crypto); 963178825Sdfr if (ret) 964178825Sdfr return ret; 965233294Sstas 966178825Sdfr ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_size, &encdata, &len, ret); 967178825Sdfr free_EncryptedData(&encdata); 968178825Sdfr if (ret) 969178825Sdfr return ret; 970178825Sdfr if(buf_size != len) 971178825Sdfr krb5_abortx(context, "internal error in ASN.1 encoder"); 972178825Sdfr 973178825Sdfr ret = krb5_padata_add(context, md, KRB5_PADATA_ENC_TIMESTAMP, buf, len); 974178825Sdfr if (ret) 975178825Sdfr free(buf); 976178825Sdfr return ret; 977178825Sdfr} 978178825Sdfr 979178825Sdfrstatic krb5_error_code 980178825Sdfradd_enc_ts_padata(krb5_context context, 981233294Sstas METHOD_DATA *md, 982178825Sdfr krb5_principal client, 983233294Sstas krb5_s2k_proc keyproc, 984178825Sdfr krb5_const_pointer keyseed, 985178825Sdfr krb5_enctype *enctypes, 986178825Sdfr unsigned netypes, 987178825Sdfr krb5_salt *salt, 988178825Sdfr krb5_data *s2kparams) 989178825Sdfr{ 990178825Sdfr krb5_error_code ret; 991178825Sdfr krb5_salt salt2; 992178825Sdfr krb5_enctype *ep; 993233294Sstas size_t i; 994233294Sstas 995178825Sdfr if(salt == NULL) { 996178825Sdfr /* default to standard salt */ 997178825Sdfr ret = krb5_get_pw_salt (context, client, &salt2); 998233294Sstas if (ret) 999233294Sstas return ret; 1000178825Sdfr salt = &salt2; 1001178825Sdfr } 1002178825Sdfr if (!enctypes) { 1003178825Sdfr enctypes = context->etypes; 1004178825Sdfr netypes = 0; 1005178825Sdfr for (ep = enctypes; *ep != ETYPE_NULL; ep++) 1006178825Sdfr netypes++; 1007178825Sdfr } 1008178825Sdfr 1009178825Sdfr for (i = 0; i < netypes; ++i) { 1010178825Sdfr krb5_keyblock *key; 1011178825Sdfr 1012233294Sstas _krb5_debug(context, 5, "krb5_get_init_creds: using ENC-TS with enctype %d", enctypes[i]); 1013233294Sstas 1014233294Sstas ret = (*keyproc)(context, enctypes[i], keyseed, 1015233294Sstas *salt, s2kparams, &key); 1016178825Sdfr if (ret) 1017178825Sdfr continue; 1018178825Sdfr ret = make_pa_enc_timestamp (context, md, enctypes[i], key); 1019178825Sdfr krb5_free_keyblock (context, key); 1020178825Sdfr if (ret) 1021178825Sdfr return ret; 1022178825Sdfr } 1023178825Sdfr if(salt == &salt2) 1024178825Sdfr krb5_free_salt(context, salt2); 1025178825Sdfr return 0; 1026178825Sdfr} 1027178825Sdfr 1028178825Sdfrstatic krb5_error_code 1029178825Sdfrpa_data_to_md_ts_enc(krb5_context context, 1030178825Sdfr const AS_REQ *a, 1031178825Sdfr const krb5_principal client, 1032178825Sdfr krb5_get_init_creds_ctx *ctx, 1033178825Sdfr struct pa_info_data *ppaid, 1034178825Sdfr METHOD_DATA *md) 1035178825Sdfr{ 1036233294Sstas if (ctx->keyproc == NULL || ctx->keyseed == NULL) 1037178825Sdfr return 0; 1038178825Sdfr 1039178825Sdfr if (ppaid) { 1040233294Sstas add_enc_ts_padata(context, md, client, 1041233294Sstas ctx->keyproc, ctx->keyseed, 1042178825Sdfr &ppaid->etype, 1, 1043178825Sdfr &ppaid->salt, ppaid->s2kparams); 1044178825Sdfr } else { 1045178825Sdfr krb5_salt salt; 1046233294Sstas 1047233294Sstas _krb5_debug(context, 5, "krb5_get_init_creds: pa-info not found, guessing salt"); 1048233294Sstas 1049178825Sdfr /* make a v5 salted pa-data */ 1050233294Sstas add_enc_ts_padata(context, md, client, 1051233294Sstas ctx->keyproc, ctx->keyseed, 1052233294Sstas a->req_body.etype.val, a->req_body.etype.len, 1053178825Sdfr NULL, NULL); 1054233294Sstas 1055178825Sdfr /* make a v4 salted pa-data */ 1056178825Sdfr salt.salttype = KRB5_PW_SALT; 1057178825Sdfr krb5_data_zero(&salt.saltvalue); 1058233294Sstas add_enc_ts_padata(context, md, client, 1059233294Sstas ctx->keyproc, ctx->keyseed, 1060233294Sstas a->req_body.etype.val, a->req_body.etype.len, 1061178825Sdfr &salt, NULL); 1062178825Sdfr } 1063178825Sdfr return 0; 1064178825Sdfr} 1065178825Sdfr 1066178825Sdfrstatic krb5_error_code 1067178825Sdfrpa_data_to_key_plain(krb5_context context, 1068178825Sdfr const krb5_principal client, 1069178825Sdfr krb5_get_init_creds_ctx *ctx, 1070178825Sdfr krb5_salt salt, 1071178825Sdfr krb5_data *s2kparams, 1072178825Sdfr krb5_enctype etype, 1073178825Sdfr krb5_keyblock **key) 1074178825Sdfr{ 1075178825Sdfr krb5_error_code ret; 1076178825Sdfr 1077233294Sstas ret = (*ctx->keyproc)(context, etype, ctx->keyseed, 1078178825Sdfr salt, s2kparams, key); 1079178825Sdfr return ret; 1080178825Sdfr} 1081178825Sdfr 1082178825Sdfr 1083178825Sdfrstatic krb5_error_code 1084178825Sdfrpa_data_to_md_pkinit(krb5_context context, 1085178825Sdfr const AS_REQ *a, 1086178825Sdfr const krb5_principal client, 1087233294Sstas int win2k, 1088178825Sdfr krb5_get_init_creds_ctx *ctx, 1089178825Sdfr METHOD_DATA *md) 1090178825Sdfr{ 1091178825Sdfr if (ctx->pk_init_ctx == NULL) 1092178825Sdfr return 0; 1093178825Sdfr#ifdef PKINIT 1094178825Sdfr return _krb5_pk_mk_padata(context, 1095233294Sstas ctx->pk_init_ctx, 1096233294Sstas ctx->ic_flags, 1097233294Sstas win2k, 1098233294Sstas &a->req_body, 1099233294Sstas ctx->pk_nonce, 1100233294Sstas md); 1101178825Sdfr#else 1102233294Sstas krb5_set_error_message(context, EINVAL, 1103233294Sstas N_("no support for PKINIT compiled in", "")); 1104178825Sdfr return EINVAL; 1105178825Sdfr#endif 1106178825Sdfr} 1107178825Sdfr 1108178825Sdfrstatic krb5_error_code 1109178825Sdfrpa_data_add_pac_request(krb5_context context, 1110178825Sdfr krb5_get_init_creds_ctx *ctx, 1111178825Sdfr METHOD_DATA *md) 1112178825Sdfr{ 1113233294Sstas size_t len = 0, length; 1114178825Sdfr krb5_error_code ret; 1115178825Sdfr PA_PAC_REQUEST req; 1116178825Sdfr void *buf; 1117233294Sstas 1118178825Sdfr switch (ctx->req_pac) { 1119178825Sdfr case KRB5_INIT_CREDS_TRISTATE_UNSET: 1120178825Sdfr return 0; /* don't bother */ 1121178825Sdfr case KRB5_INIT_CREDS_TRISTATE_TRUE: 1122178825Sdfr req.include_pac = 1; 1123178825Sdfr break; 1124178825Sdfr case KRB5_INIT_CREDS_TRISTATE_FALSE: 1125178825Sdfr req.include_pac = 0; 1126233294Sstas } 1127178825Sdfr 1128233294Sstas ASN1_MALLOC_ENCODE(PA_PAC_REQUEST, buf, length, 1129178825Sdfr &req, &len, ret); 1130178825Sdfr if (ret) 1131178825Sdfr return ret; 1132178825Sdfr if(len != length) 1133178825Sdfr krb5_abortx(context, "internal error in ASN.1 encoder"); 1134178825Sdfr 1135178825Sdfr ret = krb5_padata_add(context, md, KRB5_PADATA_PA_PAC_REQUEST, buf, len); 1136178825Sdfr if (ret) 1137178825Sdfr free(buf); 1138178825Sdfr 1139178825Sdfr return 0; 1140178825Sdfr} 1141178825Sdfr 1142178825Sdfr/* 1143178825Sdfr * Assumes caller always will free `out_md', even on error. 1144178825Sdfr */ 1145178825Sdfr 1146178825Sdfrstatic krb5_error_code 1147178825Sdfrprocess_pa_data_to_md(krb5_context context, 1148178825Sdfr const krb5_creds *creds, 1149178825Sdfr const AS_REQ *a, 1150178825Sdfr krb5_get_init_creds_ctx *ctx, 1151178825Sdfr METHOD_DATA *in_md, 1152178825Sdfr METHOD_DATA **out_md, 1153178825Sdfr krb5_prompter_fct prompter, 1154178825Sdfr void *prompter_data) 1155178825Sdfr{ 1156178825Sdfr krb5_error_code ret; 1157178825Sdfr 1158178825Sdfr ALLOC(*out_md, 1); 1159178825Sdfr if (*out_md == NULL) { 1160233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 1161178825Sdfr return ENOMEM; 1162178825Sdfr } 1163178825Sdfr (*out_md)->len = 0; 1164178825Sdfr (*out_md)->val = NULL; 1165233294Sstas 1166233294Sstas if (_krb5_have_debug(context, 5)) { 1167233294Sstas unsigned i; 1168233294Sstas _krb5_debug(context, 5, "KDC send %d patypes", in_md->len); 1169233294Sstas for (i = 0; i < in_md->len; i++) 1170233294Sstas _krb5_debug(context, 5, "KDC send PA-DATA type: %d", in_md->val[i].padata_type); 1171233294Sstas } 1172233294Sstas 1173178825Sdfr /* 1174178825Sdfr * Make sure we don't sent both ENC-TS and PK-INIT pa data, no 1175178825Sdfr * need to expose our password protecting our PKCS12 key. 1176178825Sdfr */ 1177178825Sdfr 1178178825Sdfr if (ctx->pk_init_ctx) { 1179178825Sdfr 1180233294Sstas _krb5_debug(context, 5, "krb5_get_init_creds: " 1181233294Sstas "prepareing PKINIT padata (%s)", 1182233294Sstas (ctx->used_pa_types & USED_PKINIT_W2K) ? "win2k" : "ietf"); 1183233294Sstas 1184233294Sstas if (ctx->used_pa_types & USED_PKINIT_W2K) { 1185233294Sstas krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP, 1186233294Sstas "Already tried pkinit, looping"); 1187233294Sstas return KRB5_GET_IN_TKT_LOOP; 1188233294Sstas } 1189233294Sstas 1190233294Sstas ret = pa_data_to_md_pkinit(context, a, creds->client, 1191233294Sstas (ctx->used_pa_types & USED_PKINIT), 1192233294Sstas ctx, *out_md); 1193178825Sdfr if (ret) 1194178825Sdfr return ret; 1195178825Sdfr 1196233294Sstas if (ctx->used_pa_types & USED_PKINIT) 1197233294Sstas ctx->used_pa_types |= USED_PKINIT_W2K; 1198233294Sstas else 1199233294Sstas ctx->used_pa_types |= USED_PKINIT; 1200233294Sstas 1201178825Sdfr } else if (in_md->len != 0) { 1202233294Sstas struct pa_info_data *paid, *ppaid; 1203233294Sstas unsigned flag; 1204233294Sstas 1205233294Sstas paid = calloc(1, sizeof(*paid)); 1206233294Sstas 1207233294Sstas paid->etype = ENCTYPE_NULL; 1208233294Sstas ppaid = process_pa_info(context, creds->client, a, paid, in_md); 1209233294Sstas 1210233294Sstas if (ppaid) 1211233294Sstas flag = USED_ENC_TS_INFO; 1212233294Sstas else 1213233294Sstas flag = USED_ENC_TS_GUESS; 1214233294Sstas 1215233294Sstas if (ctx->used_pa_types & flag) { 1216233294Sstas if (ppaid) 1217233294Sstas free_paid(context, ppaid); 1218233294Sstas krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP, 1219233294Sstas "Already tried ENC-TS-%s, looping", 1220233294Sstas flag == USED_ENC_TS_INFO ? "info" : "guess"); 1221233294Sstas return KRB5_GET_IN_TKT_LOOP; 1222233294Sstas } 1223233294Sstas 1224178825Sdfr pa_data_to_md_ts_enc(context, a, creds->client, ctx, ppaid, *out_md); 1225233294Sstas 1226233294Sstas ctx->used_pa_types |= flag; 1227233294Sstas 1228233294Sstas if (ppaid) { 1229233294Sstas if (ctx->ppaid) { 1230233294Sstas free_paid(context, ctx->ppaid); 1231233294Sstas free(ctx->ppaid); 1232233294Sstas } 1233233294Sstas ctx->ppaid = ppaid; 1234233294Sstas } else 1235233294Sstas free(paid); 1236178825Sdfr } 1237178825Sdfr 1238178825Sdfr pa_data_add_pac_request(context, ctx, *out_md); 1239178825Sdfr 1240178825Sdfr if ((*out_md)->len == 0) { 1241178825Sdfr free(*out_md); 1242178825Sdfr *out_md = NULL; 1243178825Sdfr } 1244178825Sdfr 1245178825Sdfr return 0; 1246178825Sdfr} 1247178825Sdfr 1248178825Sdfrstatic krb5_error_code 1249178825Sdfrprocess_pa_data_to_key(krb5_context context, 1250178825Sdfr krb5_get_init_creds_ctx *ctx, 1251178825Sdfr krb5_creds *creds, 1252178825Sdfr AS_REQ *a, 1253233294Sstas AS_REP *rep, 1254178825Sdfr const krb5_krbhst_info *hi, 1255178825Sdfr krb5_keyblock **key) 1256178825Sdfr{ 1257178825Sdfr struct pa_info_data paid, *ppaid = NULL; 1258178825Sdfr krb5_error_code ret; 1259178825Sdfr krb5_enctype etype; 1260178825Sdfr PA_DATA *pa; 1261178825Sdfr 1262178825Sdfr memset(&paid, 0, sizeof(paid)); 1263178825Sdfr 1264233294Sstas etype = rep->enc_part.etype; 1265178825Sdfr 1266233294Sstas if (rep->padata) { 1267178825Sdfr paid.etype = etype; 1268233294Sstas ppaid = process_pa_info(context, creds->client, a, &paid, 1269233294Sstas rep->padata); 1270178825Sdfr } 1271233294Sstas if (ppaid == NULL) 1272233294Sstas ppaid = ctx->ppaid; 1273178825Sdfr if (ppaid == NULL) { 1274178825Sdfr ret = krb5_get_pw_salt (context, creds->client, &paid.salt); 1275178825Sdfr if (ret) 1276178825Sdfr return ret; 1277178825Sdfr paid.etype = etype; 1278178825Sdfr paid.s2kparams = NULL; 1279233294Sstas ppaid = &paid; 1280178825Sdfr } 1281178825Sdfr 1282178825Sdfr pa = NULL; 1283233294Sstas if (rep->padata) { 1284178825Sdfr int idx = 0; 1285233294Sstas pa = krb5_find_padata(rep->padata->val, 1286233294Sstas rep->padata->len, 1287178825Sdfr KRB5_PADATA_PK_AS_REP, 1288178825Sdfr &idx); 1289178825Sdfr if (pa == NULL) { 1290178825Sdfr idx = 0; 1291233294Sstas pa = krb5_find_padata(rep->padata->val, 1292233294Sstas rep->padata->len, 1293178825Sdfr KRB5_PADATA_PK_AS_REP_19, 1294178825Sdfr &idx); 1295178825Sdfr } 1296178825Sdfr } 1297178825Sdfr if (pa && ctx->pk_init_ctx) { 1298178825Sdfr#ifdef PKINIT 1299233294Sstas _krb5_debug(context, 5, "krb5_get_init_creds: using PKINIT"); 1300233294Sstas 1301178825Sdfr ret = _krb5_pk_rd_pa_reply(context, 1302178825Sdfr a->req_body.realm, 1303178825Sdfr ctx->pk_init_ctx, 1304178825Sdfr etype, 1305178825Sdfr hi, 1306178825Sdfr ctx->pk_nonce, 1307178825Sdfr &ctx->req_buffer, 1308178825Sdfr pa, 1309178825Sdfr key); 1310178825Sdfr#else 1311178825Sdfr ret = EINVAL; 1312233294Sstas krb5_set_error_message(context, ret, N_("no support for PKINIT compiled in", "")); 1313178825Sdfr#endif 1314233294Sstas } else if (ctx->keyseed) { 1315233294Sstas _krb5_debug(context, 5, "krb5_get_init_creds: using keyproc"); 1316233294Sstas ret = pa_data_to_key_plain(context, creds->client, ctx, 1317233294Sstas ppaid->salt, ppaid->s2kparams, etype, key); 1318233294Sstas } else { 1319178825Sdfr ret = EINVAL; 1320233294Sstas krb5_set_error_message(context, ret, N_("No usable pa data type", "")); 1321178825Sdfr } 1322178825Sdfr 1323178825Sdfr free_paid(context, &paid); 1324178825Sdfr return ret; 1325178825Sdfr} 1326178825Sdfr 1327233294Sstas/** 1328233294Sstas * Start a new context to get a new initial credential. 1329233294Sstas * 1330233294Sstas * @param context A Kerberos 5 context. 1331233294Sstas * @param client The Kerberos principal to get the credential for, if 1332233294Sstas * NULL is given, the default principal is used as determined by 1333233294Sstas * krb5_get_default_principal(). 1334233294Sstas * @param prompter 1335233294Sstas * @param prompter_data 1336233294Sstas * @param start_time the time the ticket should start to be valid or 0 for now. 1337233294Sstas * @param options a options structure, can be NULL for default options. 1338233294Sstas * @param rctx A new allocated free with krb5_init_creds_free(). 1339233294Sstas * 1340233294Sstas * @return 0 for success or an Kerberos 5 error code, see krb5_get_error_message(). 1341233294Sstas * 1342233294Sstas * @ingroup krb5_credential 1343233294Sstas */ 1344233294Sstas 1345233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1346233294Sstaskrb5_init_creds_init(krb5_context context, 1347233294Sstas krb5_principal client, 1348233294Sstas krb5_prompter_fct prompter, 1349233294Sstas void *prompter_data, 1350233294Sstas krb5_deltat start_time, 1351233294Sstas krb5_get_init_creds_opt *options, 1352233294Sstas krb5_init_creds_context *rctx) 1353178825Sdfr{ 1354233294Sstas krb5_init_creds_context ctx; 1355178825Sdfr krb5_error_code ret; 1356178825Sdfr 1357233294Sstas *rctx = NULL; 1358178825Sdfr 1359233294Sstas ctx = calloc(1, sizeof(*ctx)); 1360233294Sstas if (ctx == NULL) { 1361233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 1362233294Sstas return ENOMEM; 1363233294Sstas } 1364178825Sdfr 1365233294Sstas ret = get_init_creds_common(context, client, start_time, options, ctx); 1366233294Sstas if (ret) { 1367233294Sstas free(ctx); 1368178825Sdfr return ret; 1369233294Sstas } 1370178825Sdfr 1371178825Sdfr /* Set a new nonce. */ 1372178825Sdfr krb5_generate_random_block (&ctx->nonce, sizeof(ctx->nonce)); 1373233294Sstas ctx->nonce &= 0x7fffffff; 1374178825Sdfr /* XXX these just needs to be the same when using Windows PK-INIT */ 1375178825Sdfr ctx->pk_nonce = ctx->nonce; 1376178825Sdfr 1377233294Sstas ctx->prompter = prompter; 1378233294Sstas ctx->prompter_data = prompter_data; 1379233294Sstas 1380233294Sstas *rctx = ctx; 1381233294Sstas 1382233294Sstas return ret; 1383233294Sstas} 1384233294Sstas 1385233294Sstas/** 1386233294Sstas * Sets the service that the is requested. This call is only neede for 1387233294Sstas * special initial tickets, by default the a krbtgt is fetched in the default realm. 1388233294Sstas * 1389233294Sstas * @param context a Kerberos 5 context. 1390233294Sstas * @param ctx a krb5_init_creds_context context. 1391233294Sstas * @param service the service given as a string, for example 1392233294Sstas * "kadmind/admin". If NULL, the default krbtgt in the clients 1393233294Sstas * realm is set. 1394233294Sstas * 1395233294Sstas * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message(). 1396233294Sstas * @ingroup krb5_credential 1397233294Sstas */ 1398233294Sstas 1399233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1400233294Sstaskrb5_init_creds_set_service(krb5_context context, 1401233294Sstas krb5_init_creds_context ctx, 1402233294Sstas const char *service) 1403233294Sstas{ 1404233294Sstas krb5_const_realm client_realm; 1405233294Sstas krb5_principal principal; 1406233294Sstas krb5_error_code ret; 1407233294Sstas 1408233294Sstas client_realm = krb5_principal_get_realm (context, ctx->cred.client); 1409233294Sstas 1410233294Sstas if (service) { 1411233294Sstas ret = krb5_parse_name (context, service, &principal); 1412233294Sstas if (ret) 1413233294Sstas return ret; 1414233294Sstas krb5_principal_set_realm (context, principal, client_realm); 1415233294Sstas } else { 1416233294Sstas ret = krb5_make_principal(context, &principal, 1417233294Sstas client_realm, KRB5_TGS_NAME, client_realm, 1418233294Sstas NULL); 1419233294Sstas if (ret) 1420233294Sstas return ret; 1421233294Sstas } 1422233294Sstas 1423178825Sdfr /* 1424233294Sstas * This is for Windows RODC that are picky about what name type 1425233294Sstas * the server principal have, and the really strange part is that 1426233294Sstas * they are picky about the AS-REQ name type and not the TGS-REQ 1427233294Sstas * later. Oh well. 1428178825Sdfr */ 1429178825Sdfr 1430233294Sstas if (krb5_principal_is_krbtgt(context, principal)) 1431233294Sstas krb5_principal_set_type(context, principal, KRB5_NT_SRV_INST); 1432178825Sdfr 1433233294Sstas krb5_free_principal(context, ctx->cred.server); 1434233294Sstas ctx->cred.server = principal; 1435178825Sdfr 1436233294Sstas return 0; 1437233294Sstas} 1438233294Sstas 1439233294Sstas/** 1440233294Sstas * Sets the password that will use for the request. 1441233294Sstas * 1442233294Sstas * @param context a Kerberos 5 context. 1443233294Sstas * @param ctx ctx krb5_init_creds_context context. 1444233294Sstas * @param password the password to use. 1445233294Sstas * 1446233294Sstas * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message(). 1447233294Sstas * @ingroup krb5_credential 1448233294Sstas */ 1449233294Sstas 1450233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1451233294Sstaskrb5_init_creds_set_password(krb5_context context, 1452233294Sstas krb5_init_creds_context ctx, 1453233294Sstas const char *password) 1454233294Sstas{ 1455233294Sstas if (ctx->password) { 1456233294Sstas memset(ctx->password, 0, strlen(ctx->password)); 1457233294Sstas free(ctx->password); 1458233294Sstas } 1459233294Sstas if (password) { 1460233294Sstas ctx->password = strdup(password); 1461233294Sstas if (ctx->password == NULL) { 1462233294Sstas krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", "")); 1463233294Sstas return ENOMEM; 1464178825Sdfr } 1465233294Sstas ctx->keyseed = (void *) ctx->password; 1466233294Sstas } else { 1467233294Sstas ctx->keyseed = NULL; 1468233294Sstas ctx->password = NULL; 1469233294Sstas } 1470178825Sdfr 1471233294Sstas return 0; 1472233294Sstas} 1473178825Sdfr 1474233294Sstasstatic krb5_error_code KRB5_CALLCONV 1475233294Sstaskeytab_key_proc(krb5_context context, krb5_enctype enctype, 1476233294Sstas krb5_const_pointer keyseed, 1477233294Sstas krb5_salt salt, krb5_data *s2kparms, 1478233294Sstas krb5_keyblock **key) 1479233294Sstas{ 1480233294Sstas krb5_keytab_key_proc_args *args = rk_UNCONST(keyseed); 1481233294Sstas krb5_keytab keytab = args->keytab; 1482233294Sstas krb5_principal principal = args->principal; 1483233294Sstas krb5_error_code ret; 1484233294Sstas krb5_keytab real_keytab; 1485233294Sstas krb5_keytab_entry entry; 1486178825Sdfr 1487233294Sstas if(keytab == NULL) 1488233294Sstas krb5_kt_default(context, &real_keytab); 1489233294Sstas else 1490233294Sstas real_keytab = keytab; 1491178825Sdfr 1492233294Sstas ret = krb5_kt_get_entry (context, real_keytab, principal, 1493233294Sstas 0, enctype, &entry); 1494178825Sdfr 1495233294Sstas if (keytab == NULL) 1496233294Sstas krb5_kt_close (context, real_keytab); 1497178825Sdfr 1498233294Sstas if (ret) 1499233294Sstas return ret; 1500233294Sstas 1501233294Sstas ret = krb5_copy_keyblock (context, &entry.keyblock, key); 1502233294Sstas krb5_kt_free_entry(context, &entry); 1503233294Sstas return ret; 1504233294Sstas} 1505233294Sstas 1506233294Sstas 1507233294Sstas/** 1508233294Sstas * Set the keytab to use for authentication. 1509233294Sstas * 1510233294Sstas * @param context a Kerberos 5 context. 1511233294Sstas * @param ctx ctx krb5_init_creds_context context. 1512233294Sstas * @param keytab the keytab to read the key from. 1513233294Sstas * 1514233294Sstas * @return 0 for success, or an Kerberos 5 error code, see krb5_get_error_message(). 1515233294Sstas * @ingroup krb5_credential 1516233294Sstas */ 1517233294Sstas 1518233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1519233294Sstaskrb5_init_creds_set_keytab(krb5_context context, 1520233294Sstas krb5_init_creds_context ctx, 1521233294Sstas krb5_keytab keytab) 1522233294Sstas{ 1523233294Sstas krb5_keytab_key_proc_args *a; 1524233294Sstas krb5_keytab_entry entry; 1525233294Sstas krb5_kt_cursor cursor; 1526233294Sstas krb5_enctype *etypes = NULL; 1527233294Sstas krb5_error_code ret; 1528233294Sstas size_t netypes = 0; 1529233294Sstas int kvno = 0; 1530233294Sstas 1531233294Sstas a = malloc(sizeof(*a)); 1532233294Sstas if (a == NULL) { 1533233294Sstas krb5_set_error_message(context, ENOMEM, 1534233294Sstas N_("malloc: out of memory", "")); 1535233294Sstas return ENOMEM; 1536233294Sstas } 1537233294Sstas 1538233294Sstas a->principal = ctx->cred.client; 1539233294Sstas a->keytab = keytab; 1540233294Sstas 1541233294Sstas ctx->keytab_data = a; 1542233294Sstas ctx->keyseed = (void *)a; 1543233294Sstas ctx->keyproc = keytab_key_proc; 1544233294Sstas 1545233294Sstas /* 1546233294Sstas * We need to the KDC what enctypes we support for this keytab, 1547233294Sstas * esp if the keytab is really a password based entry, then the 1548233294Sstas * KDC might have more enctypes in the database then what we have 1549233294Sstas * in the keytab. 1550233294Sstas */ 1551233294Sstas 1552233294Sstas ret = krb5_kt_start_seq_get(context, keytab, &cursor); 1553233294Sstas if(ret) 1554233294Sstas goto out; 1555233294Sstas 1556233294Sstas while(krb5_kt_next_entry(context, keytab, &entry, &cursor) == 0){ 1557233294Sstas void *ptr; 1558233294Sstas 1559233294Sstas if (!krb5_principal_compare(context, entry.principal, ctx->cred.client)) 1560233294Sstas goto next; 1561233294Sstas 1562233294Sstas /* check if we ahve this kvno already */ 1563233294Sstas if (entry.vno > kvno) { 1564233294Sstas /* remove old list of etype */ 1565233294Sstas if (etypes) 1566233294Sstas free(etypes); 1567233294Sstas etypes = NULL; 1568233294Sstas netypes = 0; 1569233294Sstas kvno = entry.vno; 1570233294Sstas } else if (entry.vno != kvno) 1571233294Sstas goto next; 1572233294Sstas 1573233294Sstas /* check if enctype is supported */ 1574233294Sstas if (krb5_enctype_valid(context, entry.keyblock.keytype) != 0) 1575233294Sstas goto next; 1576233294Sstas 1577233294Sstas /* add enctype to supported list */ 1578233294Sstas ptr = realloc(etypes, sizeof(etypes[0]) * (netypes + 2)); 1579233294Sstas if (ptr == NULL) 1580233294Sstas goto next; 1581233294Sstas 1582233294Sstas etypes = ptr; 1583233294Sstas etypes[netypes] = entry.keyblock.keytype; 1584233294Sstas etypes[netypes + 1] = ETYPE_NULL; 1585233294Sstas netypes++; 1586233294Sstas next: 1587233294Sstas krb5_kt_free_entry(context, &entry); 1588233294Sstas } 1589233294Sstas krb5_kt_end_seq_get(context, keytab, &cursor); 1590233294Sstas 1591233294Sstas if (etypes) { 1592233294Sstas if (ctx->etypes) 1593233294Sstas free(ctx->etypes); 1594233294Sstas ctx->etypes = etypes; 1595233294Sstas } 1596233294Sstas 1597233294Sstas out: 1598233294Sstas return 0; 1599233294Sstas} 1600233294Sstas 1601233294Sstasstatic krb5_error_code KRB5_CALLCONV 1602233294Sstaskeyblock_key_proc(krb5_context context, krb5_enctype enctype, 1603233294Sstas krb5_const_pointer keyseed, 1604233294Sstas krb5_salt salt, krb5_data *s2kparms, 1605233294Sstas krb5_keyblock **key) 1606233294Sstas{ 1607233294Sstas return krb5_copy_keyblock (context, keyseed, key); 1608233294Sstas} 1609233294Sstas 1610233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1611233294Sstaskrb5_init_creds_set_keyblock(krb5_context context, 1612233294Sstas krb5_init_creds_context ctx, 1613233294Sstas krb5_keyblock *keyblock) 1614233294Sstas{ 1615233294Sstas ctx->keyseed = (void *)keyblock; 1616233294Sstas ctx->keyproc = keyblock_key_proc; 1617233294Sstas 1618233294Sstas return 0; 1619233294Sstas} 1620233294Sstas 1621233294Sstas/** 1622233294Sstas * The core loop if krb5_get_init_creds() function family. Create the 1623233294Sstas * packets and have the caller send them off to the KDC. 1624233294Sstas * 1625233294Sstas * If the caller want all work been done for them, use 1626233294Sstas * krb5_init_creds_get() instead. 1627233294Sstas * 1628233294Sstas * @param context a Kerberos 5 context. 1629233294Sstas * @param ctx ctx krb5_init_creds_context context. 1630233294Sstas * @param in input data from KDC, first round it should be reset by krb5_data_zer(). 1631233294Sstas * @param out reply to KDC. 1632233294Sstas * @param hostinfo KDC address info, first round it can be NULL. 1633233294Sstas * @param flags status of the round, if 1634233294Sstas * KRB5_INIT_CREDS_STEP_FLAG_CONTINUE is set, continue one more round. 1635233294Sstas * 1636233294Sstas * @return 0 for success, or an Kerberos 5 error code, see 1637233294Sstas * krb5_get_error_message(). 1638233294Sstas * 1639233294Sstas * @ingroup krb5_credential 1640233294Sstas */ 1641233294Sstas 1642233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1643233294Sstaskrb5_init_creds_step(krb5_context context, 1644233294Sstas krb5_init_creds_context ctx, 1645233294Sstas krb5_data *in, 1646233294Sstas krb5_data *out, 1647233294Sstas krb5_krbhst_info *hostinfo, 1648233294Sstas unsigned int *flags) 1649233294Sstas{ 1650233294Sstas krb5_error_code ret; 1651233294Sstas size_t len = 0; 1652233294Sstas size_t size; 1653233294Sstas 1654233294Sstas krb5_data_zero(out); 1655233294Sstas 1656233294Sstas if (ctx->as_req.req_body.cname == NULL) { 1657233294Sstas ret = init_as_req(context, ctx->flags, &ctx->cred, 1658233294Sstas ctx->addrs, ctx->etypes, &ctx->as_req); 1659233294Sstas if (ret) { 1660233294Sstas free_init_creds_ctx(context, ctx); 1661233294Sstas return ret; 1662233294Sstas } 1663233294Sstas } 1664233294Sstas 1665233294Sstas#define MAX_PA_COUNTER 10 1666233294Sstas if (ctx->pa_counter > MAX_PA_COUNTER) { 1667233294Sstas krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP, 1668233294Sstas N_("Looping %d times while getting " 1669233294Sstas "initial credentials", ""), 1670233294Sstas ctx->pa_counter); 1671233294Sstas return KRB5_GET_IN_TKT_LOOP; 1672233294Sstas } 1673233294Sstas ctx->pa_counter++; 1674233294Sstas 1675233294Sstas _krb5_debug(context, 5, "krb5_get_init_creds: loop %d", ctx->pa_counter); 1676233294Sstas 1677233294Sstas /* Lets process the input packet */ 1678233294Sstas if (in && in->length) { 1679233294Sstas krb5_kdc_rep rep; 1680233294Sstas 1681233294Sstas memset(&rep, 0, sizeof(rep)); 1682233294Sstas 1683233294Sstas _krb5_debug(context, 5, "krb5_get_init_creds: processing input"); 1684233294Sstas 1685233294Sstas ret = decode_AS_REP(in->data, in->length, &rep.kdc_rep, &size); 1686178825Sdfr if (ret == 0) { 1687233294Sstas krb5_keyblock *key = NULL; 1688233294Sstas unsigned eflags = EXTRACT_TICKET_AS_REQ | EXTRACT_TICKET_TIMESYNC; 1689233294Sstas 1690233294Sstas if (ctx->flags.canonicalize) { 1691233294Sstas eflags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH; 1692233294Sstas eflags |= EXTRACT_TICKET_MATCH_REALM; 1693233294Sstas } 1694233294Sstas if (ctx->ic_flags & KRB5_INIT_CREDS_NO_C_CANON_CHECK) 1695233294Sstas eflags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH; 1696233294Sstas 1697233294Sstas ret = process_pa_data_to_key(context, ctx, &ctx->cred, 1698233294Sstas &ctx->as_req, &rep.kdc_rep, hostinfo, &key); 1699233294Sstas if (ret) { 1700233294Sstas free_AS_REP(&rep.kdc_rep); 1701233294Sstas goto out; 1702233294Sstas } 1703233294Sstas 1704233294Sstas _krb5_debug(context, 5, "krb5_get_init_creds: extracting ticket"); 1705233294Sstas 1706233294Sstas ret = _krb5_extract_ticket(context, 1707233294Sstas &rep, 1708233294Sstas &ctx->cred, 1709233294Sstas key, 1710233294Sstas NULL, 1711233294Sstas KRB5_KU_AS_REP_ENC_PART, 1712233294Sstas NULL, 1713233294Sstas ctx->nonce, 1714233294Sstas eflags, 1715233294Sstas NULL, 1716233294Sstas NULL); 1717233294Sstas krb5_free_keyblock(context, key); 1718233294Sstas 1719233294Sstas *flags = 0; 1720233294Sstas 1721233294Sstas if (ret == 0) 1722233294Sstas ret = copy_EncKDCRepPart(&rep.enc_part, &ctx->enc_part); 1723233294Sstas 1724233294Sstas free_AS_REP(&rep.kdc_rep); 1725233294Sstas free_EncASRepPart(&rep.enc_part); 1726233294Sstas 1727233294Sstas return ret; 1728233294Sstas 1729178825Sdfr } else { 1730178825Sdfr /* let's try to parse it as a KRB-ERROR */ 1731178825Sdfr 1732233294Sstas _krb5_debug(context, 5, "krb5_get_init_creds: got an error"); 1733233294Sstas 1734233294Sstas free_KRB_ERROR(&ctx->error); 1735233294Sstas 1736233294Sstas ret = krb5_rd_error(context, in, &ctx->error); 1737233294Sstas if(ret && in->length && ((char*)in->data)[0] == 4) 1738178825Sdfr ret = KRB5KRB_AP_ERR_V4_REPLY; 1739233294Sstas if (ret) { 1740233294Sstas _krb5_debug(context, 5, "krb5_get_init_creds: failed to read error"); 1741178825Sdfr goto out; 1742233294Sstas } 1743178825Sdfr 1744233294Sstas ret = krb5_error_from_rd_error(context, &ctx->error, &ctx->cred); 1745178825Sdfr 1746233294Sstas _krb5_debug(context, 5, "krb5_get_init_creds: KRB-ERROR %d", ret); 1747233294Sstas 1748178825Sdfr /* 1749178825Sdfr * If no preauth was set and KDC requires it, give it one 1750178825Sdfr * more try. 1751178825Sdfr */ 1752178825Sdfr 1753178825Sdfr if (ret == KRB5KDC_ERR_PREAUTH_REQUIRED) { 1754178825Sdfr 1755233294Sstas free_METHOD_DATA(&ctx->md); 1756233294Sstas memset(&ctx->md, 0, sizeof(ctx->md)); 1757233294Sstas 1758233294Sstas if (ctx->error.e_data) { 1759233294Sstas ret = decode_METHOD_DATA(ctx->error.e_data->data, 1760233294Sstas ctx->error.e_data->length, 1761233294Sstas &ctx->md, 1762178825Sdfr NULL); 1763178825Sdfr if (ret) 1764233294Sstas krb5_set_error_message(context, ret, 1765233294Sstas N_("Failed to decode METHOD-DATA", "")); 1766178825Sdfr } else { 1767233294Sstas krb5_set_error_message(context, ret, 1768233294Sstas N_("Preauth required but no preauth " 1769233294Sstas "options send by KDC", "")); 1770178825Sdfr } 1771233294Sstas } else if (ret == KRB5KRB_AP_ERR_SKEW && context->kdc_sec_offset == 0) { 1772233294Sstas /* 1773233294Sstas * Try adapt to timeskrew when we are using pre-auth, and 1774233294Sstas * if there was a time skew, try again. 1775233294Sstas */ 1776233294Sstas krb5_set_real_time(context, ctx->error.stime, -1); 1777233294Sstas if (context->kdc_sec_offset) 1778233294Sstas ret = 0; 1779233294Sstas 1780233294Sstas _krb5_debug(context, 10, "init_creds: err skew updateing kdc offset to %d", 1781233294Sstas context->kdc_sec_offset); 1782233294Sstas 1783233294Sstas ctx->used_pa_types = 0; 1784233294Sstas 1785233294Sstas } else if (ret == KRB5_KDC_ERR_WRONG_REALM && ctx->flags.canonicalize) { 1786233294Sstas /* client referal to a new realm */ 1787233294Sstas 1788233294Sstas if (ctx->error.crealm == NULL) { 1789233294Sstas krb5_set_error_message(context, ret, 1790233294Sstas N_("Got a client referral, not but no realm", "")); 1791178825Sdfr goto out; 1792233294Sstas } 1793233294Sstas _krb5_debug(context, 5, 1794233294Sstas "krb5_get_init_creds: got referal to realm %s", 1795233294Sstas *ctx->error.crealm); 1796233294Sstas 1797233294Sstas ret = krb5_principal_set_realm(context, 1798233294Sstas ctx->cred.client, 1799233294Sstas *ctx->error.crealm); 1800233294Sstas 1801233294Sstas ctx->used_pa_types = 0; 1802233294Sstas } 1803233294Sstas if (ret) 1804178825Sdfr goto out; 1805178825Sdfr } 1806178825Sdfr } 1807178825Sdfr 1808233294Sstas if (ctx->as_req.padata) { 1809233294Sstas free_METHOD_DATA(ctx->as_req.padata); 1810233294Sstas free(ctx->as_req.padata); 1811233294Sstas ctx->as_req.padata = NULL; 1812233294Sstas } 1813178825Sdfr 1814233294Sstas /* Set a new nonce. */ 1815233294Sstas ctx->as_req.req_body.nonce = ctx->nonce; 1816178825Sdfr 1817233294Sstas /* fill_in_md_data */ 1818233294Sstas ret = process_pa_data_to_md(context, &ctx->cred, &ctx->as_req, ctx, 1819233294Sstas &ctx->md, &ctx->as_req.padata, 1820233294Sstas ctx->prompter, ctx->prompter_data); 1821233294Sstas if (ret) 1822233294Sstas goto out; 1823178825Sdfr 1824233294Sstas krb5_data_free(&ctx->req_buffer); 1825178825Sdfr 1826233294Sstas ASN1_MALLOC_ENCODE(AS_REQ, 1827233294Sstas ctx->req_buffer.data, ctx->req_buffer.length, 1828233294Sstas &ctx->as_req, &len, ret); 1829233294Sstas if (ret) 1830233294Sstas goto out; 1831233294Sstas if(len != ctx->req_buffer.length) 1832233294Sstas krb5_abortx(context, "internal error in ASN.1 encoder"); 1833178825Sdfr 1834233294Sstas out->data = ctx->req_buffer.data; 1835233294Sstas out->length = ctx->req_buffer.length; 1836178825Sdfr 1837233294Sstas *flags = KRB5_INIT_CREDS_STEP_FLAG_CONTINUE; 183855682Smarkm 1839233294Sstas return 0; 1840233294Sstas out: 1841178825Sdfr return ret; 1842178825Sdfr} 1843178825Sdfr 1844233294Sstas/** 1845233294Sstas * Extract the newly acquired credentials from krb5_init_creds_context 1846233294Sstas * context. 1847233294Sstas * 1848233294Sstas * @param context A Kerberos 5 context. 1849233294Sstas * @param ctx 1850233294Sstas * @param cred credentials, free with krb5_free_cred_contents(). 1851233294Sstas * 1852233294Sstas * @return 0 for sucess or An Kerberos error code, see krb5_get_error_message(). 1853233294Sstas */ 1854233294Sstas 1855233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1856233294Sstaskrb5_init_creds_get_creds(krb5_context context, 1857233294Sstas krb5_init_creds_context ctx, 1858233294Sstas krb5_creds *cred) 1859178825Sdfr{ 1860233294Sstas return krb5_copy_creds_contents(context, &ctx->cred, cred); 1861233294Sstas} 1862233294Sstas 1863233294Sstas/** 1864233294Sstas * Get the last error from the transaction. 1865233294Sstas * 1866233294Sstas * @return Returns 0 or an error code 1867233294Sstas * 1868233294Sstas * @ingroup krb5_credential 1869233294Sstas */ 1870233294Sstas 1871233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1872233294Sstaskrb5_init_creds_get_error(krb5_context context, 1873233294Sstas krb5_init_creds_context ctx, 1874233294Sstas KRB_ERROR *error) 1875233294Sstas{ 1876178825Sdfr krb5_error_code ret; 1877178825Sdfr 1878233294Sstas ret = copy_KRB_ERROR(&ctx->error, error); 1879178825Sdfr if (ret) 1880233294Sstas krb5_set_error_message(context, ret, N_("malloc: out of memory", "")); 1881178825Sdfr 1882233294Sstas return ret; 1883233294Sstas} 1884178825Sdfr 1885233294Sstas/** 1886233294Sstas * Free the krb5_init_creds_context allocated by krb5_init_creds_init(). 1887233294Sstas * 1888233294Sstas * @param context A Kerberos 5 context. 1889233294Sstas * @param ctx The krb5_init_creds_context to free. 1890233294Sstas * 1891233294Sstas * @ingroup krb5_credential 1892233294Sstas */ 189372445Sassar 1894233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL 1895233294Sstaskrb5_init_creds_free(krb5_context context, 1896233294Sstas krb5_init_creds_context ctx) 1897233294Sstas{ 1898233294Sstas free_init_creds_ctx(context, ctx); 1899233294Sstas free(ctx); 1900233294Sstas} 1901120945Snectar 1902233294Sstas/** 1903233294Sstas * Get new credentials as setup by the krb5_init_creds_context. 1904233294Sstas * 1905233294Sstas * @param context A Kerberos 5 context. 1906233294Sstas * @param ctx The krb5_init_creds_context to process. 1907233294Sstas * 1908233294Sstas * @ingroup krb5_credential 1909233294Sstas */ 191078527Sassar 1911233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1912233294Sstaskrb5_init_creds_get(krb5_context context, krb5_init_creds_context ctx) 1913233294Sstas{ 1914233294Sstas krb5_sendto_ctx stctx = NULL; 1915233294Sstas krb5_krbhst_info *hostinfo = NULL; 1916233294Sstas krb5_error_code ret; 1917233294Sstas krb5_data in, out; 1918233294Sstas unsigned int flags = 0; 191972445Sassar 1920233294Sstas krb5_data_zero(&in); 1921233294Sstas krb5_data_zero(&out); 1922233294Sstas 1923233294Sstas ret = krb5_sendto_ctx_alloc(context, &stctx); 1924233294Sstas if (ret) 1925233294Sstas goto out; 1926233294Sstas krb5_sendto_ctx_set_func(stctx, _krb5_kdc_retry, NULL); 1927233294Sstas 1928233294Sstas while (1) { 1929233294Sstas flags = 0; 1930233294Sstas ret = krb5_init_creds_step(context, ctx, &in, &out, hostinfo, &flags); 1931233294Sstas krb5_data_free(&in); 1932233294Sstas if (ret) 1933233294Sstas goto out; 1934233294Sstas 1935233294Sstas if ((flags & 1) == 0) 193655682Smarkm break; 1937233294Sstas 1938233294Sstas ret = krb5_sendto_context (context, stctx, &out, 1939233294Sstas ctx->cred.client->realm, &in); 1940233294Sstas if (ret) 194155682Smarkm goto out; 1942233294Sstas 194355682Smarkm } 194455682Smarkm 1945178825Sdfr out: 1946233294Sstas if (stctx) 1947233294Sstas krb5_sendto_ctx_free(context, stctx); 1948142403Snectar 194955682Smarkm return ret; 195055682Smarkm} 195155682Smarkm 1952233294Sstas/** 1953233294Sstas * Get new credentials using password. 1954233294Sstas * 1955233294Sstas * @ingroup krb5_credential 1956233294Sstas */ 1957233294Sstas 1958233294Sstas 1959233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 1960178825Sdfrkrb5_get_init_creds_password(krb5_context context, 1961178825Sdfr krb5_creds *creds, 1962178825Sdfr krb5_principal client, 1963178825Sdfr const char *password, 1964178825Sdfr krb5_prompter_fct prompter, 1965178825Sdfr void *data, 1966178825Sdfr krb5_deltat start_time, 1967178825Sdfr const char *in_tkt_service, 1968233294Sstas krb5_get_init_creds_opt *options) 196955682Smarkm{ 1970233294Sstas krb5_init_creds_context ctx; 1971178825Sdfr char buf[BUFSIZ]; 1972178825Sdfr krb5_error_code ret; 1973233294Sstas int chpw = 0; 1974178825Sdfr 1975233294Sstas again: 1976233294Sstas ret = krb5_init_creds_init(context, client, prompter, data, start_time, options, &ctx); 1977178825Sdfr if (ret) 1978233294Sstas goto out; 1979178825Sdfr 1980233294Sstas ret = krb5_init_creds_set_service(context, ctx, in_tkt_service); 1981233294Sstas if (ret) 1982233294Sstas goto out; 1983233294Sstas 1984233294Sstas if (prompter != NULL && ctx->password == NULL && password == NULL) { 1985178825Sdfr krb5_prompt prompt; 1986178825Sdfr krb5_data password_data; 1987178825Sdfr char *p, *q; 1988178825Sdfr 1989178825Sdfr krb5_unparse_name (context, client, &p); 1990178825Sdfr asprintf (&q, "%s's Password: ", p); 1991178825Sdfr free (p); 1992178825Sdfr prompt.prompt = q; 1993178825Sdfr password_data.data = buf; 1994178825Sdfr password_data.length = sizeof(buf); 1995178825Sdfr prompt.hidden = 1; 1996178825Sdfr prompt.reply = &password_data; 1997178825Sdfr prompt.type = KRB5_PROMPT_TYPE_PASSWORD; 1998178825Sdfr 1999178825Sdfr ret = (*prompter) (context, data, NULL, NULL, 1, &prompt); 2000178825Sdfr free (q); 2001178825Sdfr if (ret) { 2002178825Sdfr memset (buf, 0, sizeof(buf)); 2003178825Sdfr ret = KRB5_LIBOS_PWDINTR; 2004233294Sstas krb5_clear_error_message (context); 2005233294Sstas goto out; 2006178825Sdfr } 2007178825Sdfr password = password_data.data; 2008178825Sdfr } 2009178825Sdfr 2010233294Sstas if (password) { 2011233294Sstas ret = krb5_init_creds_set_password(context, ctx, password); 2012233294Sstas if (ret) 2013233294Sstas goto out; 2014178825Sdfr } 2015178825Sdfr 2016233294Sstas ret = krb5_init_creds_get(context, ctx); 2017233294Sstas 2018233294Sstas if (ret == 0) 2019233294Sstas process_last_request(context, options, ctx); 2020233294Sstas 2021233294Sstas 2022233294Sstas if (ret == KRB5KDC_ERR_KEY_EXPIRED && chpw == 0) { 2023233294Sstas char buf2[1024]; 2024233294Sstas 2025233294Sstas /* try to avoid recursion */ 2026233294Sstas if (in_tkt_service != NULL && strcmp(in_tkt_service, "kadmin/changepw") == 0) 2027233294Sstas goto out; 2028233294Sstas 2029233294Sstas /* don't try to change password where then where none */ 2030233294Sstas if (prompter == NULL) 2031233294Sstas goto out; 2032233294Sstas 2033233294Sstas ret = change_password (context, 2034233294Sstas client, 2035233294Sstas ctx->password, 2036233294Sstas buf2, 2037233294Sstas sizeof(buf), 2038233294Sstas prompter, 2039233294Sstas data, 2040233294Sstas options); 2041233294Sstas if (ret) 2042233294Sstas goto out; 2043233294Sstas chpw = 1; 2044233294Sstas krb5_init_creds_free(context, ctx); 2045233294Sstas goto again; 2046233294Sstas } 2047233294Sstas 2048233294Sstas out: 2049233294Sstas if (ret == 0) 2050233294Sstas krb5_init_creds_get_creds(context, ctx, creds); 2051233294Sstas 2052233294Sstas if (ctx) 2053233294Sstas krb5_init_creds_free(context, ctx); 2054233294Sstas 2055178825Sdfr memset(buf, 0, sizeof(buf)); 2056178825Sdfr return ret; 2057178825Sdfr} 2058178825Sdfr 2059233294Sstas/** 2060233294Sstas * Get new credentials using keyblock. 2061233294Sstas * 2062233294Sstas * @ingroup krb5_credential 2063233294Sstas */ 206455682Smarkm 2065233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2066178825Sdfrkrb5_get_init_creds_keyblock(krb5_context context, 2067178825Sdfr krb5_creds *creds, 2068178825Sdfr krb5_principal client, 2069178825Sdfr krb5_keyblock *keyblock, 2070178825Sdfr krb5_deltat start_time, 2071178825Sdfr const char *in_tkt_service, 2072178825Sdfr krb5_get_init_creds_opt *options) 207355682Smarkm{ 2074233294Sstas krb5_init_creds_context ctx; 207555682Smarkm krb5_error_code ret; 2076233294Sstas 2077233294Sstas memset(creds, 0, sizeof(*creds)); 2078233294Sstas 2079233294Sstas ret = krb5_init_creds_init(context, client, NULL, NULL, start_time, options, &ctx); 2080178825Sdfr if (ret) 208155682Smarkm goto out; 208255682Smarkm 2083233294Sstas ret = krb5_init_creds_set_service(context, ctx, in_tkt_service); 2084233294Sstas if (ret) 2085233294Sstas goto out; 208690926Snectar 2087233294Sstas ret = krb5_init_creds_set_keyblock(context, ctx, keyblock); 2088233294Sstas if (ret) 2089233294Sstas goto out; 209055682Smarkm 2091233294Sstas ret = krb5_init_creds_get(context, ctx); 2092233294Sstas 2093233294Sstas if (ret == 0) 2094233294Sstas process_last_request(context, options, ctx); 2095233294Sstas 2096178825Sdfr out: 2097233294Sstas if (ret == 0) 2098233294Sstas krb5_init_creds_get_creds(context, ctx, creds); 2099233294Sstas 2100233294Sstas if (ctx) 2101233294Sstas krb5_init_creds_free(context, ctx); 2102233294Sstas 210355682Smarkm return ret; 210455682Smarkm} 2105233294Sstas 2106233294Sstas/** 2107233294Sstas * Get new credentials using keytab. 2108233294Sstas * 2109233294Sstas * @ingroup krb5_credential 2110233294Sstas */ 2111233294Sstas 2112233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL 2113233294Sstaskrb5_get_init_creds_keytab(krb5_context context, 2114233294Sstas krb5_creds *creds, 2115233294Sstas krb5_principal client, 2116233294Sstas krb5_keytab keytab, 2117233294Sstas krb5_deltat start_time, 2118233294Sstas const char *in_tkt_service, 2119233294Sstas krb5_get_init_creds_opt *options) 2120233294Sstas{ 2121233294Sstas krb5_init_creds_context ctx; 2122233294Sstas krb5_error_code ret; 2123233294Sstas 2124233294Sstas memset(creds, 0, sizeof(*creds)); 2125233294Sstas 2126233294Sstas ret = krb5_init_creds_init(context, client, NULL, NULL, start_time, options, &ctx); 2127233294Sstas if (ret) 2128233294Sstas goto out; 2129233294Sstas 2130233294Sstas ret = krb5_init_creds_set_service(context, ctx, in_tkt_service); 2131233294Sstas if (ret) 2132233294Sstas goto out; 2133233294Sstas 2134233294Sstas ret = krb5_init_creds_set_keytab(context, ctx, keytab); 2135233294Sstas if (ret) 2136233294Sstas goto out; 2137233294Sstas 2138233294Sstas ret = krb5_init_creds_get(context, ctx); 2139233294Sstas if (ret == 0) 2140233294Sstas process_last_request(context, options, ctx); 2141233294Sstas 2142233294Sstas out: 2143233294Sstas if (ret == 0) 2144233294Sstas krb5_init_creds_get_creds(context, ctx, creds); 2145233294Sstas 2146233294Sstas if (ctx) 2147233294Sstas krb5_init_creds_free(context, ctx); 2148233294Sstas 2149233294Sstas return ret; 2150233294Sstas} 2151