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