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