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 62463 : free_paid(krb5_context context, struct pa_info_data *ppaid)
126 : {
127 62463 : krb5_free_salt(context, ppaid->salt);
128 62463 : if (ppaid->s2kparams)
129 38856 : krb5_free_data(context, ppaid->s2kparams);
130 62463 : memset(ppaid, 0, sizeof(*ppaid));
131 62463 : }
132 :
133 : static krb5_error_code KRB5_CALLCONV
134 27154 : 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 27154 : 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 27154 : password.data = rk_UNCONST(keyseed);
154 27154 : password.length = keyseed ? strlen(keyseed) : 0;
155 27154 : if (s2kparms)
156 25972 : opaque = *s2kparms;
157 : else
158 1182 : krb5_data_zero(&opaque);
159 :
160 27154 : *key = malloc(sizeof(**key));
161 27154 : if (*key == NULL)
162 0 : return krb5_enomem(context);
163 27154 : ret = krb5_string_to_key_data_salt_opaque(context, type, password,
164 : salt, opaque, *key);
165 27154 : if (ret) {
166 0 : free(*key);
167 0 : *key = NULL;
168 : }
169 25990 : return ret;
170 : }
171 :
172 : static void
173 21798 : free_gss_init_ctx(krb5_context context, krb5_gss_init_ctx gssic)
174 : {
175 21798 : if (gssic == NULL)
176 21213 : 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 21798 : free_init_creds_ctx(krb5_context context, krb5_init_creds_context ctx)
185 : {
186 21798 : if (ctx->etypes)
187 31 : free(ctx->etypes);
188 21798 : if (ctx->pre_auth_types)
189 0 : free (ctx->pre_auth_types);
190 21798 : if (ctx->in_tkt_service)
191 0 : free(ctx->in_tkt_service);
192 21798 : if (ctx->keytab_data)
193 7 : free(ctx->keytab_data);
194 21798 : if (ctx->password) {
195 582 : size_t len;
196 21655 : len = strlen(ctx->password);
197 21655 : memset_s(ctx->password, len, 0, len);
198 21655 : free(ctx->password);
199 : }
200 21798 : free_gss_init_ctx(context, ctx->gss_init_ctx);
201 : /*
202 : * FAST state
203 : */
204 21798 : _krb5_fast_free(context, &ctx->fast_state);
205 21798 : if (ctx->as_reply_key)
206 13 : krb5_free_keyblock(context, ctx->as_reply_key);
207 :
208 21798 : krb5_data_free(&ctx->req_buffer);
209 21798 : krb5_free_cred_contents(context, &ctx->cred);
210 21798 : free_METHOD_DATA(&ctx->md);
211 21798 : free_EncKDCRepPart(&ctx->enc_part);
212 21798 : free_KRB_ERROR(&ctx->error);
213 21798 : free_AS_REQ(&ctx->as_req);
214 :
215 21798 : heim_release(ctx->available_pa_mechs);
216 21798 : heim_release(ctx->pa_mech);
217 21798 : ctx->pa_mech = NULL;
218 21798 : free(ctx->kdc_hostname);
219 21798 : free(ctx->sitename);
220 21798 : free_paid(context, &ctx->paid);
221 21798 : memset_s(ctx, sizeof(*ctx), 0, sizeof(*ctx));
222 21798 : }
223 :
224 : static krb5_deltat
225 1634 : 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 1634 : ret = krb5_config_get_time (context, NULL,
233 : "realms",
234 : realm,
235 : name,
236 : NULL);
237 1634 : if (ret >= 0)
238 0 : return ret;
239 1634 : ret = krb5_config_get_time (context, NULL,
240 : "libdefaults",
241 : name,
242 : NULL);
243 1634 : if (ret >= 0)
244 0 : return ret;
245 1634 : return def;
246 : }
247 :
248 : static krb5_error_code
249 21798 : 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 21798 : krb5_timeofday (context, &now);
260 :
261 21798 : memset (cred, 0, sizeof(*cred));
262 :
263 21798 : if (client)
264 21798 : ret = krb5_copy_principal(context, client, &cred->client);
265 : else
266 0 : ret = krb5_get_default_principal(context, &cred->client);
267 21798 : if (ret)
268 0 : goto out;
269 :
270 21798 : if (start_time)
271 0 : cred->times.starttime = now + start_time;
272 :
273 21798 : if (options->flags & KRB5_GET_INIT_CREDS_OPT_TKT_LIFE)
274 11325 : tmp = options->tkt_life;
275 : else
276 10473 : tmp = KRB5_TKT_LIFETIME_DEFAULT;
277 21798 : cred->times.endtime = now + tmp;
278 :
279 21798 : if ((options->flags & KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE)) {
280 8311 : if (options->renew_life > 0)
281 32 : tmp = options->renew_life;
282 : else
283 8279 : tmp = KRB5_TKT_RENEW_LIFETIME_DEFAULT;
284 8311 : cred->times.renew_till = now + tmp;
285 : }
286 :
287 21213 : 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 13461 : 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 13461 : lr = &ctx->enc_part.last_req;
335 :
336 13461 : 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 13461 : 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 13574 : 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 13574 : krb5_enctype weak_enctype = KRB5_ENCTYPE_NULL;
380 585 : LastReq *lr;
381 585 : unsigned i;
382 585 : time_t t;
383 :
384 13574 : if (ctx->prompter == NULL)
385 11242 : return 0;
386 :
387 1747 : if (ctx->warned_user)
388 113 : return 0;
389 :
390 1634 : ctx->warned_user = 1;
391 :
392 1634 : krb5_timeofday (context, &sec);
393 :
394 1634 : realm = krb5_principal_get_realm (context, ctx->cred.client);
395 1634 : lr = &ctx->enc_part.last_req;
396 :
397 1634 : t = sec + get_config_time (context,
398 : realm,
399 : "warn_pwexpire",
400 : 7 * 24 * 60 * 60);
401 :
402 3268 : for (i = 0; i < lr->len; ++i) {
403 1634 : 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 1634 : if (krb5_is_enctype_weak(context, ctx->as_enctype))
424 42 : weak_enctype = ctx->as_enctype;
425 1592 : else if (krb5_is_enctype_weak(context, ctx->cred.session.keytype))
426 1 : weak_enctype = ctx->cred.session.keytype;
427 :
428 1634 : 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 1634 : return 0;
448 : }
449 :
450 : static const krb5_addresses no_addrs = { 0, NULL };
451 :
452 : static krb5_error_code
453 21798 : 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 21798 : 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 21798 : memset(ctx, 0, sizeof(*ctx));
467 :
468 21798 : 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 21798 : if (options->opt_private) {
479 21798 : 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 21798 : ctx->keyproc = options->opt_private->key_proc;
487 21798 : ctx->req_pac = options->opt_private->req_pac;
488 21798 : ctx->pk_init_ctx = options->opt_private->pk_init_ctx;
489 21798 : ctx->ic_flags = options->opt_private->flags;
490 : } else
491 0 : ctx->req_pac = KRB5_INIT_CREDS_TRISTATE_UNSET;
492 :
493 21798 : if (ctx->keyproc == NULL)
494 21798 : ctx->keyproc = default_s2k_func;
495 :
496 21798 : if (ctx->ic_flags & KRB5_INIT_CREDS_CANONICALIZE)
497 20435 : ctx->flags.canonicalize = 1;
498 21798 : if (krb5_principal_get_type(context, client) == KRB5_NT_ENTERPRISE_PRINCIPAL)
499 756 : ctx->flags.canonicalize = 1;
500 :
501 21798 : ctx->pre_auth_types = NULL;
502 21798 : ctx->addrs = NULL;
503 21798 : ctx->etypes = NULL;
504 21798 : ctx->pre_auth_types = NULL;
505 :
506 21798 : ret = init_cred(context, &ctx->cred, client, start_time, options);
507 21798 : if (ret)
508 0 : goto out;
509 :
510 21798 : ret = krb5_init_creds_set_service(context, ctx, NULL);
511 21798 : if (ret)
512 0 : goto out;
513 :
514 21798 : if (options->flags & KRB5_GET_INIT_CREDS_OPT_FORWARDABLE)
515 19497 : ctx->flags.forwardable = options->forwardable;
516 :
517 21798 : if (options->flags & KRB5_GET_INIT_CREDS_OPT_PROXIABLE)
518 11221 : ctx->flags.proxiable = options->proxiable;
519 :
520 21798 : if (start_time)
521 0 : ctx->flags.postdated = 1;
522 21798 : if (ctx->cred.times.renew_till)
523 8311 : ctx->flags.renewable = 1;
524 21798 : if (options->flags & KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST) {
525 3 : ctx->addrs = options->address_list;
526 21795 : } else if (options->opt_private) {
527 21795 : switch (options->opt_private->addressless) {
528 10587 : case KRB5_INIT_CREDS_TRISTATE_UNSET:
529 : #if KRB5_ADDRESSLESS_DEFAULT == TRUE
530 10587 : ctx->addrs = &no_addrs;
531 : #else
532 : ctx->addrs = NULL;
533 : #endif
534 10587 : break;
535 0 : case KRB5_INIT_CREDS_TRISTATE_FALSE:
536 0 : ctx->addrs = NULL;
537 0 : break;
538 11208 : case KRB5_INIT_CREDS_TRISTATE_TRUE:
539 11208 : ctx->addrs = &no_addrs;
540 11208 : break;
541 : }
542 : }
543 21798 : 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 21798 : 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 21798 : if (options->flags & KRB5_GET_INIT_CREDS_OPT_ANONYMOUS)
571 104 : ctx->flags.request_anonymous = options->anonymous;
572 :
573 21798 : ctx->prompter = prompter;
574 21798 : ctx->prompter_data = prompter_data;
575 :
576 21798 : 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 21798 : ctx->runflags.change_password_prompt = ctx->prompter != NULL;
581 :
582 21798 : out:
583 21798 : if (default_opt)
584 48 : krb5_get_init_creds_opt_free(context, default_opt);
585 21213 : 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 21798 : 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 21798 : memset(a, 0, sizeof(*a));
742 :
743 21798 : a->pvno = 5;
744 21798 : a->msg_type = krb_as_req;
745 21798 : a->req_body.kdc_options = opts;
746 21798 : a->req_body.cname = calloc(1, sizeof(*a->req_body.cname));
747 21798 : if (a->req_body.cname == NULL) {
748 0 : ret = krb5_enomem(context);
749 0 : goto fail;
750 : }
751 21798 : a->req_body.sname = calloc(1, sizeof(*a->req_body.sname));
752 21798 : if (a->req_body.sname == NULL) {
753 0 : ret = krb5_enomem(context);
754 0 : goto fail;
755 : }
756 :
757 21798 : ret = _krb5_principal2principalname (a->req_body.cname, creds->client);
758 21798 : if (ret)
759 0 : goto fail;
760 21798 : ret = copy_Realm(&creds->client->realm, &a->req_body.realm);
761 21798 : if (ret)
762 0 : goto fail;
763 :
764 21798 : ret = _krb5_principal2principalname (a->req_body.sname, creds->server);
765 21798 : if (ret)
766 0 : goto fail;
767 :
768 21798 : 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 21798 : if(creds->times.endtime){
777 21798 : if ((ALLOC(a->req_body.till, 1)) != NULL)
778 21798 : *a->req_body.till = creds->times.endtime;
779 : else {
780 0 : ret = krb5_enomem(context);
781 0 : goto fail;
782 : }
783 : }
784 21798 : if(creds->times.renew_till){
785 8311 : a->req_body.rtime = malloc(sizeof(*a->req_body.rtime));
786 8311 : if (a->req_body.rtime == NULL) {
787 0 : ret = krb5_enomem(context);
788 0 : goto fail;
789 : }
790 8311 : *a->req_body.rtime = creds->times.renew_till;
791 : }
792 21798 : a->req_body.nonce = 0;
793 22383 : ret = _krb5_init_etype(context,
794 : KRB5_PDU_AS_REQUEST,
795 : &a->req_body.etype.len,
796 21798 : &a->req_body.etype.val,
797 : etypes);
798 21798 : if (ret)
799 0 : goto fail;
800 :
801 : /*
802 : * This means no addresses
803 : */
804 :
805 21798 : if (addrs && addrs->len == 0) {
806 21795 : 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 21798 : a->req_body.enc_authorization_data = NULL;
828 21798 : a->req_body.additional_tickets = NULL;
829 :
830 21798 : a->padata = NULL;
831 :
832 21798 : 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 39448 : 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 39448 : paid->etype = etype;
847 39448 : paid->salt.salttype = salttype;
848 39448 : paid->salt.saltvalue.data = malloc(salt_len + 1);
849 39448 : if (paid->salt.saltvalue.data == NULL) {
850 0 : krb5_clear_error_message(context);
851 0 : return krb5_enomem(context);
852 : }
853 39448 : memcpy(paid->salt.saltvalue.data, salt_string, salt_len);
854 39448 : ((char *)paid->salt.saltvalue.data)[salt_len] = '\0';
855 39448 : paid->salt.saltvalue.length = salt_len;
856 39448 : if (s2kparams) {
857 1740 : krb5_error_code ret;
858 :
859 38856 : ret = krb5_copy_data(context, s2kparams, &paid->s2kparams);
860 38856 : 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 37705 : return 0;
869 : }
870 :
871 : static struct pa_info_data *
872 39448 : 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 39448 : memset(&e, 0, sizeof(e));
884 39448 : ret = decode_ETYPE_INFO2(data->data, data->length, &e, &sz);
885 39448 : if (ret)
886 0 : goto out;
887 39448 : if (e.len == 0)
888 0 : goto out;
889 40397 : for (j = 0; j < asreq->req_body.etype.len; j++) {
890 41346 : for (i = 0; i < e.len; i++) {
891 :
892 40397 : if (krb5_enctype_valid(context, e.val[i].etype) != 0)
893 0 : continue;
894 :
895 40397 : if (asreq->req_body.etype.val[j] == e.val[i].etype) {
896 1743 : krb5_salt salt;
897 39448 : if (e.val[i].salt == NULL)
898 598 : ret = krb5_get_pw_salt(context, client, &salt);
899 : else {
900 38850 : salt.saltvalue.data = *e.val[i].salt;
901 38850 : salt.saltvalue.length = strlen(*e.val[i].salt);
902 38850 : ret = 0;
903 : }
904 39448 : if (ret == 0)
905 39448 : ret = set_paid(paid, context, e.val[i].etype,
906 : KRB5_PW_SALT,
907 : salt.saltvalue.data,
908 : salt.saltvalue.length,
909 39448 : e.val[i].s2kparams);
910 39448 : if (e.val[i].salt == NULL)
911 598 : krb5_free_salt(context, salt);
912 39448 : if (ret == 0) {
913 39448 : free_ETYPE_INFO2(&e);
914 39448 : 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 13732 : 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 13732 : 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 13732 : krb5_us_timeofday (context, &p.patimestamp, &usec);
1020 13732 : usec2 = usec;
1021 13732 : p.pausec = &usec2;
1022 :
1023 13732 : ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC, buf, buf_size, &p, &len, ret);
1024 13732 : if (ret)
1025 0 : return ret;
1026 13732 : if(buf_size != len)
1027 0 : krb5_abortx(context, "internal error in ASN.1 encoder");
1028 :
1029 13732 : ret = krb5_crypto_init(context, key, 0, &crypto);
1030 13732 : if (ret) {
1031 0 : free(buf);
1032 0 : return ret;
1033 : }
1034 13732 : ret = krb5_encrypt_EncryptedData(context,
1035 : crypto,
1036 : KRB5_KU_PA_ENC_TIMESTAMP,
1037 : buf,
1038 : len,
1039 : 0,
1040 : &encdata);
1041 13732 : free(buf);
1042 13732 : krb5_crypto_destroy(context, crypto);
1043 13732 : if (ret)
1044 0 : return ret;
1045 :
1046 13732 : ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_size, &encdata, &len, ret);
1047 13732 : free_EncryptedData(&encdata);
1048 13732 : if (ret)
1049 0 : return ret;
1050 13732 : if(buf_size != len)
1051 0 : krb5_abortx(context, "internal error in ASN.1 encoder");
1052 :
1053 13732 : ret = krb5_padata_add(context, md, KRB5_PADATA_ENC_TIMESTAMP, buf, len);
1054 13732 : if (ret)
1055 0 : free(buf);
1056 13147 : return ret;
1057 : }
1058 :
1059 : static krb5_error_code
1060 13732 : 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 13732 : memset(&salt2, 0, sizeof(salt2));
1076 :
1077 13732 : 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 13732 : 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 27464 : for (i = 0; i < netypes; ++i) {
1092 585 : krb5_keyblock *key;
1093 :
1094 13732 : _krb5_debug(context, 5, "krb5_get_init_creds: using ENC-TS with enctype %d", enctypes[i]);
1095 :
1096 13732 : ret = (*keyproc)(context, enctypes[i], keyseed,
1097 : *salt, s2kparams, &key);
1098 13732 : if (ret)
1099 0 : continue;
1100 13732 : ret = make_pa_enc_timestamp (context, md, enctypes[i], key);
1101 13732 : krb5_free_keyblock (context, key);
1102 13732 : if (ret)
1103 0 : return ret;
1104 : }
1105 13732 : if(salt == &salt2)
1106 0 : krb5_free_salt(context, salt2);
1107 13147 : return 0;
1108 : }
1109 :
1110 : static krb5_error_code
1111 13732 : 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 13732 : if (ctx->keyproc == NULL || ctx->keyseed == NULL)
1119 0 : return 0;
1120 :
1121 13732 : if (ppaid) {
1122 13732 : add_enc_ts_padata(context, md, client,
1123 13147 : 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 13147 : return 0;
1146 : }
1147 :
1148 : static krb5_error_code
1149 13460 : 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 14045 : ret = (*ctx->keyproc)(context, etype, ctx->keyseed,
1160 : salt, s2kparams, key);
1161 13460 : 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 149 : _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 149 : 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 149 : krb5_us_timeofday (context, &p.patimestamp, &usec);
1495 149 : usec2 = usec;
1496 149 : p.pausec = &usec2;
1497 :
1498 149 : ASN1_MALLOC_ENCODE(PA_ENC_TS_ENC, buf, buf_size, &p, &len, ret);
1499 149 : if (ret)
1500 0 : return ret;
1501 149 : if(buf_size != len)
1502 0 : krb5_abortx(context, "internal error in ASN.1 encoder");
1503 :
1504 149 : ret = krb5_encrypt_EncryptedData(context,
1505 : crypto,
1506 : usage,
1507 : buf,
1508 : len,
1509 : 0,
1510 : &encdata);
1511 149 : free(buf);
1512 149 : if (ret)
1513 0 : return ret;
1514 :
1515 149 : ASN1_MALLOC_ENCODE(EncryptedData, buf, buf_size, &encdata, &len, ret);
1516 149 : free_EncryptedData(&encdata);
1517 149 : if (ret)
1518 0 : return ret;
1519 149 : if(buf_size != len)
1520 0 : krb5_abortx(context, "internal error in ASN.1 encoder");
1521 :
1522 149 : ret = krb5_padata_add(context, md, KRB5_PADATA_ENCRYPTED_CHALLENGE, buf, len);
1523 149 : if (ret)
1524 0 : free(buf);
1525 149 : return ret;
1526 : }
1527 :
1528 : krb5_error_code
1529 156 : _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 156 : ret = krb5_decrypt_EncryptedData(context, crypto, usage, enc_data, &ts_data);
1543 156 : if (ret)
1544 6 : return ret;
1545 :
1546 150 : ret = decode_PA_ENC_TS_ENC(ts_data.data,
1547 : ts_data.length,
1548 : &p,
1549 : &size);
1550 150 : krb5_data_free(&ts_data);
1551 150 : 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 150 : krb5_us_timeofday(context, ×tamp, &usec);
1558 :
1559 150 : 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 149 : ret = 0;
1574 : }
1575 :
1576 150 : out:
1577 150 : free_PA_ENC_TS_ENC(&p);
1578 :
1579 150 : 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 49129 : 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 49129 : 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 49129 : 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 49129 : if (pactx->user == NULL) {
1748 21937 : ret = krb5_copy_principal(context, ctx->cred.client, &pactx->user);
1749 21937 : if (ret)
1750 0 : return ret;
1751 : }
1752 :
1753 49129 : memset(&paid, 0, sizeof(paid));
1754 :
1755 49129 : if (rep == NULL)
1756 34499 : paid.etype = KRB5_ENCTYPE_NULL;
1757 : else
1758 13460 : paid.etype = rep->enc_part.etype;
1759 :
1760 49129 : ppaid = process_pa_info(context, ctx->cred.client, a, &paid, in_md);
1761 :
1762 49129 : 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 13460 : if (ppaid == NULL && ctx->paid.etype != KRB5_ENCTYPE_NULL) {
1769 602 : ppaid = &ctx->paid;
1770 :
1771 12858 : } 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 14045 : ret = pa_data_to_key_plain(context, ctx->cred.client, ctx,
1777 13460 : ppaid->salt, ppaid->s2kparams, rep->enc_part.etype,
1778 : &ctx->fast_state.reply_key);
1779 13460 : free_paid(context, &paid);
1780 13460 : 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 35669 : if (ppaid == NULL) {
1797 21937 : _krb5_debug(context, 5,
1798 : "TS-ENC: waiting for KDC to set pw-salt/etype_info{,2}");
1799 21937 : return HEIM_ERR_PA_CONTINUE_NEEDED;
1800 : }
1801 13732 : 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 13732 : if (pactx->used_pa_types & USED_ENC_TS_INFO) {
1818 0 : flag = USED_ENC_TS_RENEG;
1819 0 : state = "reneg";
1820 : } else {
1821 13732 : flag = USED_ENC_TS_INFO;
1822 13732 : state = "info";
1823 : }
1824 :
1825 13732 : 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 13732 : pactx->used_pa_types |= flag;
1833 :
1834 13732 : free_paid(context, &ctx->paid);
1835 13732 : ctx->paid = *ppaid;
1836 :
1837 13732 : ret = pa_data_to_md_ts_enc(context, a, ctx->cred.client, ctx, ppaid, out_md);
1838 13732 : if (ret)
1839 0 : return ret;
1840 :
1841 13147 : return HEIM_ERR_PA_CONTINUE_NEEDED;
1842 : }
1843 :
1844 : static void
1845 21674 : enc_ts_release(void *pa_ctx)
1846 : {
1847 21674 : struct enc_ts_context *pactx = (struct enc_ts_context *)pa_ctx;
1848 :
1849 21674 : if (pactx->user)
1850 21674 : krb5_free_principal(NULL, pactx->user);
1851 21674 : }
1852 :
1853 : static krb5_error_code
1854 35793 : 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 35793 : size_t len = 0, length;
1858 1170 : krb5_error_code ret;
1859 1170 : PA_PAC_REQUEST req;
1860 1170 : void *buf;
1861 :
1862 35793 : switch (ctx->req_pac) {
1863 33768 : case KRB5_INIT_CREDS_TRISTATE_UNSET:
1864 33768 : 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 35793 : 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 35793 : if (ctx->runflags.allow_enc_pa_rep)
1890 35793 : 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 35793 : 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 35793 : int idx = 0;
1909 :
1910 35793 : pad = krb5_find_padata(in_md->val, in_md->len, KRB5_PADATA_FX_COOKIE, &idx);
1911 35793 : 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 35793 : if (ctx->error.error_code == KRB5_KDC_ERR_MORE_PREAUTH_DATA_REQUIRED)
1917 0 : return KRB5_PREAUTH_FAILED;
1918 : else
1919 35793 : 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 62000 : 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 62000 : struct pa_info_data *p = NULL;
2105 2334 : PA_DATA *pa;
2106 2334 : size_t i;
2107 :
2108 62000 : if (md == NULL)
2109 596 : return NULL;
2110 :
2111 811530 : for (i = 0; p == NULL && i < sizeof(patypes)/sizeof(patypes[0]); i++) {
2112 750132 : int idx = 0;
2113 :
2114 750132 : if (patypes[i].salt_info == NULL)
2115 710684 : continue;
2116 :
2117 127248 : pa = krb5_find_padata(md->val, md->len, patypes[i].type, &idx);
2118 127248 : if (pa == NULL)
2119 87800 : continue;
2120 :
2121 39448 : paid->salt.salttype = (krb5_salttype)patypes[i].type;
2122 39448 : p = patypes[i].salt_info(context, client, asreq, paid, &pa->padata_value);
2123 : }
2124 59070 : return p;
2125 : }
2126 :
2127 : static krb5_error_code
2128 35793 : 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 35793 : krb5_error_code ret = 0;
2135 1170 : size_t n;
2136 :
2137 680067 : for (n = 0; ret == 0 && n < sizeof(patypes)/sizeof(patypes[0]); n++) {
2138 644274 : if ((patypes[n].flags & types) == 0)
2139 536895 : continue;
2140 :
2141 107379 : if (patypes[n].step)
2142 107379 : 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 35793 : return ret;
2147 : }
2148 :
2149 :
2150 : static void HEIM_CALLCONV
2151 43596 : mech_dealloc(void *ctx)
2152 : {
2153 43596 : struct pa_auth_mech *pa_mech = ctx;
2154 43596 : if (pa_mech->patype->release)
2155 21922 : pa_mech->patype->release((void *)&pa_mech->pactx[0]);
2156 43596 : }
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 43596 : pa_mech_create(krb5_context context, krb5_init_creds_context ctx, int pa_type)
2171 : {
2172 1170 : struct pa_auth_mech *pa_mech;
2173 43596 : const struct patype *patype = NULL;
2174 1170 : size_t n;
2175 :
2176 239034 : for (n = 0; patype == NULL && n < sizeof(patypes)/sizeof(patypes[0]); n++) {
2177 195438 : if (patypes[n].type == pa_type)
2178 43596 : patype = &patypes[n];
2179 : }
2180 43596 : if (patype == NULL)
2181 0 : return NULL;
2182 :
2183 43596 : pa_mech = _heim_alloc_object(&pa_auth_mech_object, sizeof(*pa_mech) - 1 + patype->pa_ctx_size);
2184 43596 : if (pa_mech == NULL)
2185 0 : return NULL;
2186 :
2187 43596 : pa_mech->patype = patype;
2188 :
2189 43596 : 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 43596 : _krb5_debug(context, 5, "Adding PA mech: %s", patype->name);
2200 :
2201 43596 : return pa_mech;
2202 : }
2203 :
2204 : static void
2205 43596 : pa_mech_add(krb5_context context, krb5_init_creds_context ctx, int pa_type)
2206 : {
2207 1170 : struct pa_auth_mech *mech;
2208 :
2209 43596 : mech = pa_mech_create(context, ctx, pa_type);
2210 43596 : if (mech) {
2211 43596 : heim_array_append_value(ctx->available_pa_mechs, mech);
2212 43596 : heim_release(mech);
2213 : }
2214 43596 : }
2215 :
2216 : static krb5_error_code
2217 21798 : pa_configure(krb5_context context,
2218 : krb5_init_creds_context ctx,
2219 : METHOD_DATA *in_md)
2220 : {
2221 21798 : ctx->available_pa_mechs = heim_array_create();
2222 :
2223 21798 : if (ctx->gss_init_ctx) {
2224 0 : pa_mech_add(context, ctx, KRB5_PADATA_GSS);
2225 21798 : } 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 21674 : } else if (ctx->keyproc || ctx->keyseed || ctx->prompter) {
2229 21674 : pa_mech_add(context, ctx, KRB5_PADATA_ENCRYPTED_CHALLENGE);
2230 21674 : pa_mech_add(context, ctx, KRB5_PADATA_ENC_TIMESTAMP);
2231 : }
2232 : /* XXX setup context based on KDC reply */
2233 :
2234 21798 : 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 49266 : 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 49266 : PA_DATA *pa = NULL;
2260 2340 : int idx;
2261 :
2262 47511 : next:
2263 2340 : do {
2264 70940 : if (ctx->pa_mech == NULL) {
2265 43472 : size_t len = heim_array_get_length(ctx->available_pa_mechs);
2266 43472 : 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 43472 : ctx->pa_mech = heim_array_copy_value(ctx->available_pa_mechs, 0);
2272 43472 : heim_array_delete_value(ctx->available_pa_mechs, 0);
2273 : }
2274 :
2275 70940 : 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 70940 : if ((ctx->pa_mech->patype->flags & PA_F_NOT_FAST) == 0) {
2285 21674 : _krb5_debug(context, 0, "dropped pa-mech %s since not running under FAST",
2286 21674 : ctx->pa_mech->patype->name);
2287 21674 : heim_release(ctx->pa_mech);
2288 21674 : ctx->pa_mech = NULL;
2289 21674 : continue;
2290 : }
2291 : }
2292 :
2293 49266 : _krb5_debug(context, 0, "pa-mech trying: %s, searching for %d",
2294 49266 : ctx->pa_mech->patype->name, ctx->pa_mech->patype->type);
2295 :
2296 49266 : idx = 0;
2297 49266 : if (in_md)
2298 48664 : pa = krb5_find_padata(in_md->val, in_md->len, ctx->pa_mech->patype->type, &idx);
2299 : else
2300 596 : pa = NULL;
2301 :
2302 70940 : } while (ctx->pa_mech == NULL);
2303 :
2304 49266 : _krb5_debug(context, 5, "Stepping pa-mech: %s", ctx->pa_mech->patype->name);
2305 :
2306 49266 : ret = ctx->pa_mech->patype->step(context, ctx, (void *)&ctx->pa_mech->pactx[0], pa, a, rep, in_md, out_md);
2307 49266 : _krb5_debug(context, 10, "PA type %s returned %d", ctx->pa_mech->patype->name, ret);
2308 49266 : if (ret == 0) {
2309 13473 : struct pa_auth_mech *next_pa = ctx->pa_mech->next;
2310 :
2311 13473 : 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 13473 : } 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 13473 : ctx->pa_used = ctx->pa_mech->patype->name;
2321 : }
2322 :
2323 13473 : heim_retain(next_pa);
2324 13473 : heim_release(ctx->pa_mech);
2325 13473 : ctx->pa_mech = next_pa;
2326 : }
2327 :
2328 49266 : 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 49266 : } else if (ret == HEIM_ERR_PA_CONTINUE_NEEDED) {
2336 35793 : _krb5_debug(context, 5, "Continue needed for %s", ctx->pa_mech->patype->name);
2337 13473 : } 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 47511 : return ret;
2344 : }
2345 :
2346 : static void
2347 48664 : log_kdc_pa_types(krb5_context context, METHOD_DATA *in_md)
2348 : {
2349 48664 : 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 48664 : }
2358 :
2359 : /*
2360 : * Assumes caller always will free `out_md', even on error.
2361 : */
2362 :
2363 : static krb5_error_code
2364 35793 : 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 35793 : ALLOC(*out_md, 1);
2374 35793 : if (*out_md == NULL) {
2375 0 : return krb5_enomem(context);
2376 : }
2377 35793 : (*out_md)->len = 0;
2378 35793 : (*out_md)->val = NULL;
2379 :
2380 35793 : log_kdc_pa_types(context, in_md);
2381 :
2382 35793 : ret = pa_step(context, ctx, a, NULL, in_md, *out_md);
2383 35793 : if (ret == HEIM_ERR_PA_CONTINUE_NEEDED) {
2384 35793 : _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 35793 : ret = pa_announce(context, PA_F_ANNOUNCE|PA_F_CONFIG, ctx, in_md, *out_md);
2396 :
2397 : /*
2398 : *
2399 : */
2400 :
2401 35793 : if ((*out_md)->len == 0) {
2402 0 : free(*out_md);
2403 0 : *out_md = NULL;
2404 : }
2405 :
2406 34623 : return ret;
2407 : }
2408 :
2409 : static krb5_error_code
2410 13473 : 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 13473 : struct pa_info_data paid, *ppaid = NULL;
2418 585 : krb5_error_code ret;
2419 13473 : krb5_enctype etype = rep->enc_part.etype;
2420 :
2421 13473 : memset(&paid, 0, sizeof(paid));
2422 :
2423 13473 : if (rep->padata)
2424 12871 : log_kdc_pa_types(context, rep->padata);
2425 :
2426 13473 : if (rep->padata) {
2427 12871 : paid.etype = etype;
2428 12871 : ppaid = process_pa_info(context, creds->client, a, &paid,
2429 : rep->padata);
2430 : }
2431 13467 : 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 13473 : ret = pa_step(context, ctx, a, rep, rep->padata, NULL);
2442 13473 : 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 13473 : } else if (ret == 0) {
2446 13473 : _krb5_debug(context, 0, "final pamech done step");
2447 13473 : goto out;
2448 : } else {
2449 0 : return ret;
2450 : }
2451 13473 : out:
2452 13473 : free_paid(context, &paid);
2453 13473 : return ret;
2454 : }
2455 :
2456 : /*
2457 : *
2458 : */
2459 :
2460 : static krb5_error_code
2461 21798 : capture_lkdc_domain(krb5_context context,
2462 : krb5_init_creds_context ctx)
2463 : {
2464 585 : size_t len;
2465 :
2466 21798 : len = strlen(_krb5_wellknown_lkdc);
2467 :
2468 21798 : if (ctx->kdc_hostname != NULL ||
2469 21798 : strncmp(ctx->cred.client->realm, _krb5_wellknown_lkdc, len) != 0 ||
2470 0 : ctx->cred.client->realm[len] != ':')
2471 21213 : 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 21798 : 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 21798 : *rctx = NULL;
2511 :
2512 21798 : ctx = calloc(1, sizeof(*ctx));
2513 21798 : if (ctx == NULL)
2514 0 : return krb5_enomem(context);
2515 :
2516 21798 : ret = get_init_creds_common(context, client, prompter, prompter_data,
2517 : start_time, options, ctx);
2518 21798 : 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 21798 : krb5_generate_random_block (&ctx->nonce, sizeof(ctx->nonce));
2526 21798 : ctx->nonce &= 0x7fffffff;
2527 : /* XXX these just needs to be the same when using Windows PK-INIT */
2528 21798 : ctx->pk_nonce = ctx->nonce;
2529 :
2530 21798 : ctx->prompter = prompter;
2531 21798 : ctx->prompter_data = prompter_data;
2532 :
2533 : /* pick up hostname from LKDC realm name */
2534 21798 : ret = capture_lkdc_domain(context, ctx);
2535 21798 : if (ret) {
2536 0 : free_init_creds_ctx(context, ctx);
2537 0 : return ret;
2538 : }
2539 :
2540 21798 : ctx->runflags.allow_enc_pa_rep = 1;
2541 :
2542 21798 : ctx->fast_state.flags |= KRB5_FAST_AS_REQ;
2543 :
2544 21798 : *rctx = ctx;
2545 :
2546 21798 : 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 43374 : 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 43374 : client_realm = krb5_principal_get_realm (context, ctx->cred.client);
2616 :
2617 43374 : 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 43355 : ret = krb5_make_principal(context, &principal,
2628 : client_realm, KRB5_TGS_NAME, client_realm,
2629 : NULL);
2630 43355 : 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 43374 : if (krb5_principal_is_krbtgt(context, principal))
2642 43358 : krb5_principal_set_type(context, principal, KRB5_NT_SRV_INST);
2643 :
2644 43374 : krb5_free_principal(context, ctx->cred.server);
2645 43374 : ctx->cred.server = principal;
2646 :
2647 43374 : 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 21659 : krb5_init_creds_set_password(krb5_context context,
2663 : krb5_init_creds_context ctx,
2664 : const char *password)
2665 : {
2666 21659 : 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 21659 : if (password) {
2673 21659 : ctx->password = strdup(password);
2674 21659 : if (ctx->password == NULL)
2675 0 : return krb5_enomem(context);
2676 21659 : ctx->keyseed = (void *) ctx->password;
2677 : } else {
2678 0 : ctx->keyseed = NULL;
2679 0 : ctx->password = NULL;
2680 : }
2681 :
2682 21077 : 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 117 : while(krb5_kt_next_entry(context, keytab, &entry, &cursor) == 0){
2764 0 : void *ptr;
2765 :
2766 110 : if (!krb5_principal_compare(context, entry.principal, ctx->cred.client))
2767 86 : 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 110 : next:
2812 110 : 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 13461 : validate_pkinit_fx(krb5_context context,
2865 : krb5_init_creds_context ctx,
2866 : AS_REP *rep,
2867 : krb5_keyblock *ticket_sessionkey)
2868 : {
2869 13461 : PA_DATA *pa = NULL;
2870 13461 : int idx = 0;
2871 :
2872 13461 : if (rep->padata)
2873 12861 : pa = krb5_find_padata(rep->padata->val, rep->padata->len, KRB5_PADATA_PKINIT_KX, &idx);
2874 :
2875 13455 : if (pa == NULL) {
2876 13448 : 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 12863 : 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 13148 : available_padata_count(METHOD_DATA *md)
2942 : {
2943 13148 : size_t i, count = 0;
2944 :
2945 82242 : for (i = 0; i < md->len; i++) {
2946 68509 : PA_DATA *pa = &md->val[i];
2947 :
2948 68509 : if (pa->padata_type == KRB5_PADATA_FX_COOKIE ||
2949 65584 : pa->padata_type == KRB5_PADATA_FX_ERROR)
2950 0 : continue;
2951 :
2952 68509 : count++;
2953 : }
2954 :
2955 13733 : return count;
2956 : }
2957 :
2958 : static krb5_error_code
2959 49997 : 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 49997 : size_t len = 0;
2970 1755 : size_t size;
2971 1755 : AS_REQ req2;
2972 :
2973 49997 : gettimeofday(&start_time, NULL);
2974 :
2975 49997 : krb5_data_zero(out);
2976 49997 : *out_realm = NULL;
2977 49997 : krb5_data_zero(&checksum_data);
2978 :
2979 49997 : if (ctx->as_req.req_body.cname == NULL) {
2980 22383 : ret = init_as_req(context, ctx->flags, &ctx->cred,
2981 21798 : ctx->addrs, ctx->etypes, &ctx->as_req);
2982 21798 : if (ret)
2983 0 : return ret;
2984 21798 : if (ctx->fast_state.flags & KRB5_FAST_REQUIRED)
2985 : ;
2986 21798 : else if (ctx->fast_state.flags & KRB5_FAST_AP_ARMOR_SERVICE)
2987 : /* Check with armor service if there is FAST */;
2988 : else
2989 21798 : ctx->fast_state.flags |= KRB5_FAST_DISABLED;
2990 :
2991 :
2992 : /* XXX should happen after we get back reply from KDC */
2993 21798 : pa_configure(context, ctx, NULL);
2994 : }
2995 :
2996 : #define MAX_PA_COUNTER 15
2997 49997 : 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 49997 : ctx->pa_counter++;
3005 :
3006 49997 : _krb5_debug(context, 5, "krb5_get_init_creds: loop %d", ctx->pa_counter);
3007 :
3008 : /* Lets process the input packet */
3009 49997 : if (in && in->length) {
3010 1170 : krb5_kdc_rep rep;
3011 :
3012 28199 : memset(&rep, 0, sizeof(rep));
3013 :
3014 28199 : _krb5_debug(context, 5, "krb5_get_init_creds: processing input");
3015 :
3016 28199 : ret = decode_AS_REP(in->data, in->length, &rep.kdc_rep, &size);
3017 28199 : if (ret == 0) {
3018 13473 : unsigned eflags = EXTRACT_TICKET_AS_REQ | EXTRACT_TICKET_TIMESYNC;
3019 585 : krb5_data data;
3020 :
3021 : /*
3022 : * Unwrap AS-REP
3023 : */
3024 13473 : ASN1_MALLOC_ENCODE(Ticket, data.data, data.length,
3025 : &rep.kdc_rep.ticket, &size, ret);
3026 13473 : if (ret)
3027 0 : goto out;
3028 13473 : heim_assert(data.length == size, "ASN.1 internal error");
3029 :
3030 13473 : ret = _krb5_fast_unwrap_kdc_rep(context, ctx->nonce, &data,
3031 : &ctx->fast_state, &rep.kdc_rep);
3032 13473 : krb5_data_free(&data);
3033 13473 : if (ret)
3034 0 : goto out;
3035 :
3036 : /*
3037 : * Now check and extract the ticket
3038 : */
3039 :
3040 13473 : if (ctx->flags.canonicalize) {
3041 12758 : eflags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH;
3042 12758 : eflags |= EXTRACT_TICKET_MATCH_REALM;
3043 : }
3044 13473 : if (ctx->ic_flags & KRB5_INIT_CREDS_NO_C_CANON_CHECK)
3045 12528 : eflags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH;
3046 13473 : if (ctx->flags.request_anonymous)
3047 0 : eflags |= EXTRACT_TICKET_MATCH_ANON;
3048 :
3049 13473 : ret = process_pa_data_to_key(context, ctx, &ctx->cred,
3050 : &ctx->as_req, &rep.kdc_rep,
3051 : &ctx->fast_state.reply_key);
3052 13473 : if (ret) {
3053 0 : free_AS_REP(&rep.kdc_rep);
3054 0 : goto out;
3055 : }
3056 :
3057 13473 : 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 13473 : _krb5_debug(context, 5, "krb5_get_init_creds: extracting ticket");
3081 :
3082 13473 : 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 13473 : if (ret == 0)
3096 13461 : ret = copy_EncKDCRepPart(&rep.enc_part, &ctx->enc_part);
3097 13473 : if (ret == 0)
3098 13461 : ret = validate_pkinit_fx(context, ctx, &rep.kdc_rep, &ctx->cred.session);
3099 :
3100 13473 : ctx->as_enctype = ctx->fast_state.reply_key->keytype;
3101 :
3102 13473 : 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 13460 : krb5_free_keyblock(context, ctx->fast_state.reply_key);
3107 13460 : ctx->fast_state.reply_key = NULL;
3108 : }
3109 13473 : ctx->ic_flags |= KRB5_INIT_CREDS_DONE;
3110 13473 : *flags = 0;
3111 :
3112 13473 : free_AS_REP(&rep.kdc_rep);
3113 13473 : free_EncASRepPart(&rep.enc_part);
3114 :
3115 13473 : gettimeofday(&end_time, NULL);
3116 13473 : timevalsub(&end_time, &start_time);
3117 13473 : timevaladd(&ctx->stats.run_time, &end_time);
3118 :
3119 13473 : _krb5_debug(context, 1, "krb5_get_init_creds: wc: %lld.%06ld",
3120 13473 : (long long)ctx->stats.run_time.tv_sec,
3121 13473 : (long)ctx->stats.run_time.tv_usec);
3122 13473 : return ret;
3123 :
3124 : } else {
3125 : /* let's try to parse it as a KRB-ERROR */
3126 :
3127 14726 : _krb5_debug(context, 5, "krb5_get_init_creds: got an KRB-ERROR from KDC");
3128 :
3129 14726 : free_KRB_ERROR(&ctx->error);
3130 :
3131 14726 : ret = krb5_rd_error(context, in, &ctx->error);
3132 14726 : if(ret && in->length && ((char*)in->data)[0] == 4)
3133 0 : ret = KRB5KRB_AP_ERR_V4_REPLY;
3134 14726 : 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 14726 : free_METHOD_DATA(&ctx->md);
3146 14726 : memset(&ctx->md, 0, sizeof(ctx->md));
3147 :
3148 14726 : if (ctx->error.e_data) {
3149 585 : krb5_error_code ret2;
3150 :
3151 14033 : ret2 = decode_METHOD_DATA(ctx->error.e_data->data,
3152 13448 : ctx->error.e_data->length,
3153 : &ctx->md,
3154 : NULL);
3155 14033 : if (ret2) {
3156 : /*
3157 : * Just ignore any error, the error will be pushed
3158 : * out from krb5_error_from_rd_error() if there
3159 : * was one.
3160 : */
3161 29 : _krb5_debug(context, 5, N_("Failed to decode METHOD-DATA", ""));
3162 : }
3163 : }
3164 :
3165 : /*
3166 : * Unwrap KRB-ERROR, we are always calling this so that
3167 : * FAST can tell us if your peer KDC suddenly dropped FAST
3168 : * wrapping and its really an attacker's packet (or a bug
3169 : * in the KDC).
3170 : */
3171 14726 : ret = _krb5_fast_unwrap_error(context, ctx->nonce, &ctx->fast_state,
3172 : &ctx->md, &ctx->error);
3173 14726 : if (ret)
3174 0 : goto out;
3175 :
3176 : /*
3177 : *
3178 : */
3179 :
3180 14726 : ret = krb5_error_from_rd_error(context, &ctx->error, &ctx->cred);
3181 :
3182 : /* log the failure */
3183 14726 : if (_krb5_have_debug(context, 5)) {
3184 2 : const char *str = krb5_get_error_message(context, ret);
3185 2 : _krb5_debug(context, 5, "krb5_get_init_creds: KRB-ERROR %d/%s", ret, str);
3186 2 : krb5_free_error_message(context, str);
3187 : }
3188 :
3189 : /*
3190 : * Handle special error codes
3191 : */
3192 :
3193 14726 : if (ret == KRB5KDC_ERR_PREAUTH_REQUIRED
3194 1579 : || ret == KRB5_KDC_ERR_MORE_PREAUTH_DATA_REQUIRED
3195 994 : || ret == KRB5KDC_ERR_ETYPE_NOSUPP)
3196 : {
3197 : /*
3198 : * If no preauth was set and KDC requires it, give it one
3199 : * more try.
3200 : *
3201 : * If the KDC returned KRB5KDC_ERR_ETYPE_NOSUPP, just loop
3202 : * one more time since that might mean we are dealing with
3203 : * a Windows KDC that is confused about what enctypes are
3204 : * available.
3205 : */
3206 :
3207 13733 : if (available_padata_count(&ctx->md) == 0) {
3208 1 : krb5_set_error_message(context, ret,
3209 1 : N_("Preauth required but no preauth "
3210 : "options sent by KDC", ""));
3211 1 : goto out;
3212 : }
3213 993 : } else if (ret == KRB5KRB_AP_ERR_SKEW && context->kdc_sec_offset == 0) {
3214 : /*
3215 : * Try adapt to timeskrew when we are using pre-auth, and
3216 : * if there was a time skew, try again.
3217 : */
3218 0 : krb5_set_real_time(context, ctx->error.stime, -1);
3219 0 : if (context->kdc_sec_offset)
3220 0 : ret = 0;
3221 :
3222 0 : _krb5_debug(context, 10, "init_creds: err skew updating kdc offset to %d",
3223 : context->kdc_sec_offset);
3224 0 : if (ret)
3225 0 : goto out;
3226 :
3227 0 : pa_restart(context, ctx);
3228 :
3229 1252 : } else if (ret == KRB5_KDC_ERR_WRONG_REALM && ctx->flags.canonicalize) {
3230 : /* client referral to a new realm */
3231 0 : char *ref_realm;
3232 :
3233 259 : if (ctx->error.crealm == NULL) {
3234 0 : krb5_set_error_message(context, ret,
3235 0 : N_("Got a client referral, not but no realm", ""));
3236 0 : goto out;
3237 : }
3238 259 : ref_realm = *ctx->error.crealm;
3239 :
3240 259 : _krb5_debug(context, 5, "krb5_get_init_creds: referral to realm %s",
3241 : ref_realm);
3242 :
3243 : /*
3244 : * If its a krbtgt, lets updat the requested krbtgt too
3245 : */
3246 259 : if (krb5_principal_is_krbtgt(context, ctx->cred.server)) {
3247 :
3248 259 : free(ctx->cred.server->name.name_string.val[1]);
3249 259 : ctx->cred.server->name.name_string.val[1] = strdup(ref_realm);
3250 259 : if (ctx->cred.server->name.name_string.val[1] == NULL) {
3251 0 : ret = krb5_enomem(context);
3252 0 : goto out;
3253 : }
3254 :
3255 259 : free_PrincipalName(ctx->as_req.req_body.sname);
3256 259 : ret = _krb5_principal2principalname(ctx->as_req.req_body.sname, ctx->cred.server);
3257 259 : if (ret)
3258 0 : goto out;
3259 : }
3260 :
3261 259 : free(ctx->as_req.req_body.realm);
3262 259 : ret = copy_Realm(&ref_realm, &ctx->as_req.req_body.realm);
3263 259 : if (ret)
3264 0 : goto out;
3265 :
3266 259 : ret = krb5_principal_set_realm(context,
3267 : ctx->cred.client,
3268 259 : *ctx->error.crealm);
3269 259 : if (ret)
3270 0 : goto out;
3271 :
3272 259 : ret = krb5_unparse_name(context, ctx->cred.client, &ref_realm);
3273 259 : if (ret == 0) {
3274 259 : _krb5_debug(context, 5, "krb5_get_init_creds: got referral to %s", ref_realm);
3275 259 : krb5_xfree(ref_realm);
3276 : }
3277 :
3278 259 : pa_restart(context, ctx);
3279 :
3280 734 : } else if (ret == KRB5KDC_ERR_KEY_EXP && ctx->runflags.change_password == 0 &&
3281 4 : ctx->runflags.change_password_prompt) {
3282 0 : char buf2[1024];
3283 :
3284 4 : ctx->runflags.change_password = 1;
3285 :
3286 4 : ctx->prompter(context, ctx->prompter_data, NULL, N_("Password has expired", ""), 0, NULL);
3287 :
3288 : /* try to avoid recursion */
3289 4 : if (ctx->in_tkt_service != NULL && strcmp(ctx->in_tkt_service, "kadmin/changepw") == 0)
3290 0 : goto out;
3291 :
3292 : /* don't include prompter in runtime */
3293 4 : gettimeofday(&end_time, NULL);
3294 4 : timevalsub(&end_time, &start_time);
3295 4 : timevaladd(&ctx->stats.run_time, &end_time);
3296 :
3297 4 : ret = change_password(context,
3298 : ctx->cred.client,
3299 4 : ctx->password,
3300 : buf2,
3301 : sizeof(buf2),
3302 : ctx->prompter,
3303 : ctx->prompter_data,
3304 : NULL);
3305 4 : if (ret)
3306 0 : goto out;
3307 :
3308 4 : gettimeofday(&start_time, NULL);
3309 :
3310 4 : krb5_init_creds_set_password(context, ctx, buf2);
3311 :
3312 4 : pa_restart(context, ctx);
3313 :
3314 730 : } else if (ret == KRB5KDC_ERR_PREAUTH_FAILED) {
3315 :
3316 : /*
3317 : * Old MIT KDC can't handle KRB5_PADATA_REQ_ENC_PA_REP,
3318 : * so drop it and try again. But only try that for MIT
3319 : * Kerberos servers by keying of no METHOD-DATA.
3320 : */
3321 262 : if (ctx->runflags.allow_enc_pa_rep) {
3322 262 : if (ctx->md.len != 0) {
3323 262 : _krb5_debug(context, 10, "Server sent PA data with KRB-ERROR, "
3324 : "so not a pre 1.7 MIT KDC and won't retry w/o ENC-PA-REQ");
3325 262 : goto out;
3326 : }
3327 0 : _krb5_debug(context, 10, "Disabling allow_enc_pa_rep and trying again");
3328 0 : ctx->runflags.allow_enc_pa_rep = 0;
3329 0 : goto retry;
3330 : }
3331 :
3332 0 : if (ctx->fast_state.flags & KRB5_FAST_DISABLED) {
3333 0 : _krb5_debug(context, 10, "FAST disabled and got preauth failed");
3334 0 : goto out;
3335 : }
3336 :
3337 0 : retry:
3338 0 : pa_restart(context, ctx);
3339 :
3340 468 : } else if (ctx->fast_state.flags & KRB5_FAST_OPTIMISTIC) {
3341 0 : _krb5_debug(context, 10,
3342 : "Some other error %d failed with optimistic FAST, trying w/o FAST", ret);
3343 :
3344 0 : ctx->fast_state.flags &= ~KRB5_FAST_OPTIMISTIC;
3345 0 : ctx->fast_state.flags &= ~KRB5_FAST_REQUIRED;
3346 0 : ctx->fast_state.flags &= ~KRB5_FAST_ANON_PKINIT_ARMOR;
3347 0 : ctx->fast_state.flags |= KRB5_FAST_DISABLED;
3348 585 : pa_restart(context, ctx);
3349 : } else {
3350 : /* some other error code from the KDC, lets' return it to the user */
3351 468 : goto out;
3352 : }
3353 : }
3354 : }
3355 :
3356 35793 : if (ctx->as_req.padata) {
3357 13995 : free_METHOD_DATA(ctx->as_req.padata);
3358 13995 : free(ctx->as_req.padata);
3359 13995 : ctx->as_req.padata = NULL;
3360 : }
3361 :
3362 36963 : ret = _krb5_fast_create_armor(context, &ctx->fast_state,
3363 35793 : ctx->cred.client->realm);
3364 35793 : if (ret)
3365 0 : goto out;
3366 :
3367 : /* Set a new nonce. */
3368 35793 : ctx->as_req.req_body.nonce = ctx->nonce;
3369 :
3370 :
3371 : /*
3372 : * Step and announce PA-DATA
3373 : */
3374 :
3375 35793 : ret = process_pa_data_to_md(context, &ctx->cred, &ctx->as_req, ctx,
3376 : &ctx->md, &ctx->as_req.padata);
3377 35793 : if (ret)
3378 0 : goto out;
3379 :
3380 :
3381 : /*
3382 : * Wrap with FAST
3383 : */
3384 35793 : ret = copy_AS_REQ(&ctx->as_req, &req2);
3385 35793 : if (ret)
3386 0 : goto out;
3387 :
3388 35793 : ret = _krb5_fast_wrap_req(context,
3389 : &ctx->fast_state,
3390 : &req2);
3391 :
3392 35793 : krb5_data_free(&checksum_data);
3393 35793 : if (ret) {
3394 0 : free_AS_REQ(&req2);
3395 0 : goto out;
3396 : }
3397 :
3398 35793 : krb5_data_free(&ctx->req_buffer);
3399 :
3400 35793 : ASN1_MALLOC_ENCODE(AS_REQ,
3401 : ctx->req_buffer.data, ctx->req_buffer.length,
3402 : &req2, &len, ret);
3403 35793 : free_AS_REQ(&req2);
3404 35793 : if (ret)
3405 0 : goto out;
3406 35793 : if(len != ctx->req_buffer.length)
3407 0 : krb5_abortx(context, "internal error in ASN.1 encoder");
3408 :
3409 36963 : ret = krb5_data_copy(out,
3410 35793 : ctx->req_buffer.data,
3411 : ctx->req_buffer.length);
3412 35793 : if (ret)
3413 0 : goto out;
3414 :
3415 35793 : *out_realm = strdup(ctx->cred.client->realm);
3416 35793 : if (*out_realm == NULL) {
3417 0 : krb5_data_free(out);
3418 0 : ret = ENOMEM;
3419 0 : goto out;
3420 : }
3421 :
3422 35793 : *flags = KRB5_INIT_CREDS_STEP_FLAG_CONTINUE;
3423 :
3424 35793 : gettimeofday(&end_time, NULL);
3425 35793 : timevalsub(&end_time, &start_time);
3426 35793 : timevaladd(&ctx->stats.run_time, &end_time);
3427 :
3428 35793 : return 0;
3429 731 : out:
3430 731 : return ret;
3431 : }
3432 :
3433 : /**
3434 : * The core loop if krb5_get_init_creds() function family. Create the
3435 : * packets and have the caller send them off to the KDC.
3436 : *
3437 : * If the caller want all work been done for them, use
3438 : * krb5_init_creds_get() instead.
3439 : *
3440 : * @param context a Kerberos 5 context.
3441 : * @param ctx ctx krb5_init_creds_context context.
3442 : * @param in input data from KDC, first round it should be reset by krb5_data_zero().
3443 : * @param out reply to KDC. The caller needs to call krb5_data_free()
3444 : * @param out_realm the destination realm for 'out', free with krb5_xfree()
3445 : * @param flags status of the round, if
3446 : * KRB5_INIT_CREDS_STEP_FLAG_CONTINUE is set, continue one more round.
3447 : *
3448 : * @return 0 for success, or an Kerberos 5 error code, see
3449 : * krb5_get_error_message().
3450 : *
3451 : * @ingroup krb5_credential
3452 : */
3453 :
3454 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3455 50101 : krb5_init_creds_step(krb5_context context,
3456 : krb5_init_creds_context ctx,
3457 : const krb5_data *in,
3458 : krb5_data *out,
3459 : krb5_realm *out_realm,
3460 : unsigned int *flags)
3461 : {
3462 1755 : krb5_error_code ret;
3463 1755 : krb5_data empty;
3464 :
3465 50101 : krb5_data_zero(&empty);
3466 50101 : krb5_data_zero(out);
3467 50101 : *out_realm = NULL;
3468 :
3469 50101 : if ((ctx->fast_state.flags & KRB5_FAST_ANON_PKINIT_ARMOR) &&
3470 208 : ctx->fast_state.armor_ccache == NULL) {
3471 208 : ret = _krb5_fast_anon_pkinit_step(context, ctx, &ctx->fast_state,
3472 : in, out, out_realm, flags);
3473 208 : if (ret && (ctx->fast_state.flags & KRB5_FAST_OPTIMISTIC)) {
3474 104 : _krb5_debug(context, 5, "Preauth failed with optimistic "
3475 : "FAST, trying w/o FAST");
3476 104 : ctx->fast_state.flags &= ~KRB5_FAST_OPTIMISTIC;
3477 104 : ctx->fast_state.flags &= ~KRB5_FAST_REQUIRED;
3478 104 : ctx->fast_state.flags &= ~KRB5_FAST_ANON_PKINIT_ARMOR;
3479 104 : } else if (ret ||
3480 104 : (*flags & KRB5_INIT_CREDS_STEP_FLAG_CONTINUE))
3481 104 : return ret;
3482 :
3483 104 : in = ∅
3484 : }
3485 :
3486 49997 : return init_creds_step(context, ctx, in, out, out_realm, flags);
3487 : }
3488 :
3489 : /**
3490 : * Extract the newly acquired credentials from krb5_init_creds_context
3491 : * context.
3492 : *
3493 : * @param context A Kerberos 5 context.
3494 : * @param ctx
3495 : * @param cred credentials, free with krb5_free_cred_contents().
3496 : *
3497 : * @return 0 for sucess or An Kerberos error code, see krb5_get_error_message().
3498 : */
3499 :
3500 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3501 13461 : krb5_init_creds_get_creds(krb5_context context,
3502 : krb5_init_creds_context ctx,
3503 : krb5_creds *cred)
3504 : {
3505 13461 : return krb5_copy_creds_contents(context, &ctx->cred, cred);
3506 : }
3507 :
3508 : /**
3509 : * Extract the as-reply key from the context.
3510 : *
3511 : * Only allowed when the as-reply-key is not directly derived from the
3512 : * password like PK-INIT, GSS, FAST hardened key, etc.
3513 : *
3514 : * @param context A Kerberos 5 context.
3515 : * @param ctx ctx krb5_init_creds_context context.
3516 : * @param as_reply_key keyblock, free with krb5_free_keyblock_contents().
3517 : *
3518 : * @return 0 for sucess or An Kerberos error code, see krb5_get_error_message().
3519 : */
3520 :
3521 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3522 0 : krb5_init_creds_get_as_reply_key(krb5_context context,
3523 : krb5_init_creds_context ctx,
3524 : krb5_keyblock *as_reply_key)
3525 : {
3526 0 : if (ctx->as_reply_key == NULL)
3527 0 : return KRB5KDC_ERR_PREAUTH_REQUIRED;
3528 0 : return krb5_copy_keyblock_contents(context, ctx->as_reply_key, as_reply_key);
3529 : }
3530 :
3531 : KRB5_LIB_FUNCTION krb5_timestamp KRB5_LIB_CALL
3532 104 : _krb5_init_creds_get_cred_starttime(krb5_context context, krb5_init_creds_context ctx)
3533 : {
3534 104 : return ctx->cred.times.starttime;
3535 : }
3536 :
3537 : KRB5_LIB_FUNCTION krb5_timestamp KRB5_LIB_CALL
3538 0 : _krb5_init_creds_get_cred_endtime(krb5_context context, krb5_init_creds_context ctx)
3539 : {
3540 0 : return ctx->cred.times.endtime;
3541 : }
3542 :
3543 : KRB5_LIB_FUNCTION krb5_principal KRB5_LIB_CALL
3544 208 : _krb5_init_creds_get_cred_client(krb5_context context, krb5_init_creds_context ctx)
3545 : {
3546 208 : return ctx->cred.client;
3547 : }
3548 :
3549 : /**
3550 : * Get the last error from the transaction.
3551 : *
3552 : * @return Returns 0 or an error code
3553 : *
3554 : * @ingroup krb5_credential
3555 : */
3556 :
3557 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3558 0 : krb5_init_creds_get_error(krb5_context context,
3559 : krb5_init_creds_context ctx,
3560 : KRB_ERROR *error)
3561 : {
3562 0 : krb5_error_code ret;
3563 :
3564 0 : ret = copy_KRB_ERROR(&ctx->error, error);
3565 0 : if (ret)
3566 0 : krb5_enomem(context);
3567 :
3568 0 : return ret;
3569 : }
3570 :
3571 : /**
3572 : * Store config
3573 : *
3574 : * @param context A Kerberos 5 context.
3575 : * @param ctx The krb5_init_creds_context to free.
3576 : * @param id store
3577 : *
3578 : * @return Returns 0 or an error code
3579 : *
3580 : * @ingroup krb5_credential
3581 : */
3582 :
3583 : krb5_error_code KRB5_LIB_FUNCTION
3584 113 : krb5_init_creds_store_config(krb5_context context,
3585 : krb5_init_creds_context ctx,
3586 : krb5_ccache id)
3587 : {
3588 0 : krb5_error_code ret;
3589 :
3590 113 : if (ctx->kdc_hostname) {
3591 0 : krb5_data data;
3592 0 : data.length = strlen(ctx->kdc_hostname);
3593 0 : data.data = ctx->kdc_hostname;
3594 :
3595 0 : ret = krb5_cc_set_config(context, id, NULL, "lkdc-hostname", &data);
3596 0 : if (ret)
3597 0 : return ret;
3598 : }
3599 113 : if (ctx->sitename) {
3600 0 : krb5_data data;
3601 0 : data.length = strlen(ctx->sitename);
3602 0 : data.data = ctx->sitename;
3603 :
3604 0 : ret = krb5_cc_set_config(context, id, NULL, "sitename", &data);
3605 0 : if (ret)
3606 0 : return ret;
3607 : }
3608 :
3609 113 : return 0;
3610 : }
3611 :
3612 : /**
3613 : *
3614 : * @ingroup krb5_credential
3615 : */
3616 :
3617 : krb5_error_code
3618 113 : krb5_init_creds_store(krb5_context context,
3619 : krb5_init_creds_context ctx,
3620 : krb5_ccache id)
3621 : {
3622 0 : krb5_error_code ret;
3623 :
3624 113 : if (ctx->cred.client == NULL) {
3625 0 : ret = KRB5KDC_ERR_PREAUTH_REQUIRED;
3626 0 : krb5_set_error_message(context, ret, "init creds not completed yet");
3627 0 : return ret;
3628 : }
3629 :
3630 113 : ret = krb5_cc_initialize(context, id, ctx->cred.client);
3631 113 : if (ret)
3632 0 : return ret;
3633 :
3634 113 : ret = krb5_cc_store_cred(context, id, &ctx->cred);
3635 113 : if (ret)
3636 0 : return ret;
3637 :
3638 113 : if (ctx->cred.flags.b.enc_pa_rep) {
3639 113 : krb5_data data = { 3, rk_UNCONST("yes") };
3640 113 : ret = krb5_cc_set_config(context, id, ctx->cred.server,
3641 : "fast_avail", &data);
3642 113 : if (ret && ret != KRB5_CC_NOSUPP)
3643 0 : return ret;
3644 : }
3645 :
3646 113 : return 0;
3647 : }
3648 :
3649 : /**
3650 : * Free the krb5_init_creds_context allocated by krb5_init_creds_init().
3651 : *
3652 : * @param context A Kerberos 5 context.
3653 : * @param ctx The krb5_init_creds_context to free.
3654 : *
3655 : * @ingroup krb5_credential
3656 : */
3657 :
3658 : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
3659 21798 : krb5_init_creds_free(krb5_context context,
3660 : krb5_init_creds_context ctx)
3661 : {
3662 21798 : free_init_creds_ctx(context, ctx);
3663 21798 : free(ctx);
3664 21798 : }
3665 :
3666 : /**
3667 : * Get new credentials as setup by the krb5_init_creds_context.
3668 : *
3669 : * @param context A Kerberos 5 context.
3670 : * @param ctx The krb5_init_creds_context to process.
3671 : *
3672 : * @ingroup krb5_credential
3673 : */
3674 :
3675 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3676 21694 : krb5_init_creds_get(krb5_context context, krb5_init_creds_context ctx)
3677 : {
3678 21694 : krb5_sendto_ctx stctx = NULL;
3679 585 : krb5_error_code ret;
3680 585 : krb5_data in, out;
3681 21694 : unsigned int flags = 0;
3682 :
3683 21694 : krb5_data_zero(&in);
3684 21694 : krb5_data_zero(&out);
3685 :
3686 21694 : ret = krb5_sendto_ctx_alloc(context, &stctx);
3687 21694 : if (ret)
3688 0 : goto out;
3689 21694 : krb5_sendto_ctx_set_func(stctx, _krb5_kdc_retry, NULL);
3690 :
3691 21694 : if (ctx->kdc_hostname)
3692 0 : krb5_sendto_set_hostname(context, stctx, ctx->kdc_hostname);
3693 21694 : if (ctx->sitename)
3694 0 : krb5_sendto_set_sitename(context, stctx, ctx->sitename);
3695 :
3696 28199 : while (1) {
3697 1755 : struct timeval nstart, nend;
3698 49893 : krb5_realm realm = NULL;
3699 :
3700 49893 : flags = 0;
3701 49893 : ret = krb5_init_creds_step(context, ctx, &in, &out, &realm, &flags);
3702 49893 : krb5_data_free(&in);
3703 49893 : if (ret)
3704 8233 : goto out;
3705 :
3706 49254 : if ((flags & KRB5_INIT_CREDS_STEP_FLAG_CONTINUE) == 0)
3707 12876 : break;
3708 :
3709 35793 : gettimeofday(&nstart, NULL);
3710 :
3711 35793 : ret = krb5_sendto_context (context, stctx, &out, realm, &in);
3712 35793 : krb5_data_free(&out);
3713 35793 : free(realm);
3714 35793 : if (ret)
3715 7594 : goto out;
3716 :
3717 28199 : gettimeofday(&nend, NULL);
3718 28199 : timevalsub(&nend, &nstart);
3719 28199 : timevaladd(&ctx->stats.run_time, &nend);
3720 : }
3721 :
3722 21694 : out:
3723 21694 : if (stctx)
3724 21694 : krb5_sendto_ctx_free(context, stctx);
3725 :
3726 21694 : return ret;
3727 : }
3728 :
3729 : /**
3730 : * Get new credentials using password.
3731 : *
3732 : * @ingroup krb5_credential
3733 : */
3734 :
3735 :
3736 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3737 21558 : krb5_get_init_creds_password(krb5_context context,
3738 : krb5_creds *creds,
3739 : krb5_principal client,
3740 : const char *password,
3741 : krb5_prompter_fct prompter,
3742 : void *data,
3743 : krb5_deltat start_time,
3744 : const char *in_tkt_service,
3745 : krb5_get_init_creds_opt *options)
3746 : {
3747 582 : krb5_init_creds_context ctx;
3748 582 : char buf[BUFSIZ], buf2[BUFSIZ];
3749 582 : krb5_error_code ret;
3750 21558 : int chpw = 0;
3751 :
3752 21558 : again:
3753 21558 : ret = krb5_init_creds_init(context, client, prompter, data, start_time, options, &ctx);
3754 21558 : if (ret)
3755 0 : goto out;
3756 :
3757 21558 : ret = krb5_init_creds_set_service(context, ctx, in_tkt_service);
3758 21558 : if (ret)
3759 0 : goto out;
3760 :
3761 21558 : if (prompter != NULL && ctx->password == NULL && password == NULL) {
3762 0 : krb5_prompt prompt;
3763 0 : krb5_data password_data;
3764 6 : char *p, *q = NULL;
3765 0 : int aret;
3766 :
3767 6 : ret = krb5_unparse_name(context, client, &p);
3768 6 : if (ret)
3769 0 : goto out;
3770 :
3771 6 : aret = asprintf(&q, "%s's Password: ", p);
3772 6 : free (p);
3773 6 : if (aret == -1 || q == NULL) {
3774 0 : ret = krb5_enomem(context);
3775 0 : goto out;
3776 : }
3777 6 : prompt.prompt = q;
3778 6 : password_data.data = buf;
3779 6 : password_data.length = sizeof(buf);
3780 6 : prompt.hidden = 1;
3781 6 : prompt.reply = &password_data;
3782 6 : prompt.type = KRB5_PROMPT_TYPE_PASSWORD;
3783 :
3784 6 : ret = (*prompter) (context, data, NULL, NULL, 1, &prompt);
3785 6 : free (q);
3786 6 : if (ret) {
3787 0 : memset_s(buf, sizeof(buf), 0, sizeof(buf));
3788 0 : ret = KRB5_LIBOS_PWDINTR;
3789 0 : krb5_clear_error_message (context);
3790 0 : goto out;
3791 : }
3792 6 : password = password_data.data;
3793 : }
3794 :
3795 21558 : if (password) {
3796 21558 : ret = krb5_init_creds_set_password(context, ctx, password);
3797 21558 : if (ret)
3798 0 : goto out;
3799 : }
3800 :
3801 21558 : ret = krb5_init_creds_get(context, ctx);
3802 :
3803 21558 : if (ret == 0)
3804 13336 : krb5_process_last_request(context, options, ctx);
3805 :
3806 :
3807 21558 : if (ret == KRB5KDC_ERR_KEY_EXPIRED && chpw == 0) {
3808 : /* try to avoid recursion */
3809 0 : if (in_tkt_service != NULL && strcmp(in_tkt_service, "kadmin/changepw") == 0)
3810 0 : goto out;
3811 :
3812 : /* don't try to change password if no prompter or prompting disabled */
3813 0 : if (!ctx->runflags.change_password_prompt)
3814 0 : goto out;
3815 :
3816 0 : ret = change_password (context,
3817 : client,
3818 0 : ctx->password,
3819 : buf2,
3820 : sizeof(buf2),
3821 : prompter,
3822 : data,
3823 : options);
3824 0 : if (ret)
3825 0 : goto out;
3826 0 : password = buf2;
3827 0 : chpw = 1;
3828 0 : krb5_init_creds_free(context, ctx);
3829 0 : goto again;
3830 : }
3831 :
3832 21558 : out:
3833 21558 : if (ret == 0)
3834 13336 : krb5_init_creds_get_creds(context, ctx, creds);
3835 :
3836 21558 : if (ctx)
3837 21558 : krb5_init_creds_free(context, ctx);
3838 :
3839 21558 : memset_s(buf, sizeof(buf), 0, sizeof(buf));
3840 21558 : memset_s(buf2, sizeof(buf), 0, sizeof(buf2));
3841 21558 : return ret;
3842 : }
3843 :
3844 : /**
3845 : * Get new credentials using keyblock.
3846 : *
3847 : * @ingroup krb5_credential
3848 : */
3849 :
3850 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3851 12 : krb5_get_init_creds_keyblock(krb5_context context,
3852 : krb5_creds *creds,
3853 : krb5_principal client,
3854 : krb5_keyblock *keyblock,
3855 : krb5_deltat start_time,
3856 : const char *in_tkt_service,
3857 : krb5_get_init_creds_opt *options)
3858 : {
3859 3 : krb5_init_creds_context ctx;
3860 3 : krb5_error_code ret;
3861 :
3862 12 : memset(creds, 0, sizeof(*creds));
3863 :
3864 12 : ret = krb5_init_creds_init(context, client, NULL, NULL, start_time, options, &ctx);
3865 12 : if (ret)
3866 0 : goto out;
3867 :
3868 12 : ret = krb5_init_creds_set_service(context, ctx, in_tkt_service);
3869 12 : if (ret)
3870 0 : goto out;
3871 :
3872 12 : ret = krb5_init_creds_set_keyblock(context, ctx, keyblock);
3873 12 : if (ret)
3874 0 : goto out;
3875 :
3876 12 : ret = krb5_init_creds_get(context, ctx);
3877 :
3878 12 : if (ret == 0)
3879 12 : krb5_process_last_request(context, options, ctx);
3880 :
3881 0 : out:
3882 12 : if (ret == 0)
3883 12 : krb5_init_creds_get_creds(context, ctx, creds);
3884 :
3885 12 : if (ctx)
3886 12 : krb5_init_creds_free(context, ctx);
3887 :
3888 12 : return ret;
3889 : }
3890 :
3891 : /**
3892 : * Get new credentials using keytab.
3893 : *
3894 : * @ingroup krb5_credential
3895 : */
3896 :
3897 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3898 0 : krb5_get_init_creds_keytab(krb5_context context,
3899 : krb5_creds *creds,
3900 : krb5_principal client,
3901 : krb5_keytab keytab,
3902 : krb5_deltat start_time,
3903 : const char *in_tkt_service,
3904 : krb5_get_init_creds_opt *options)
3905 : {
3906 0 : krb5_init_creds_context ctx;
3907 0 : krb5_keytab_entry ktent;
3908 0 : krb5_error_code ret;
3909 :
3910 0 : memset(&ktent, 0, sizeof(ktent));
3911 0 : memset(creds, 0, sizeof(*creds));
3912 :
3913 0 : if (strcmp(client->realm, "") == 0) {
3914 : /*
3915 : * Referral realm. We have a keytab, so pick a realm by
3916 : * matching in the keytab.
3917 : */
3918 0 : ret = krb5_kt_get_entry(context, keytab, client, 0, 0, &ktent);
3919 0 : if (ret == 0)
3920 0 : client = ktent.principal;
3921 : }
3922 :
3923 0 : ret = krb5_init_creds_init(context, client, NULL, NULL, start_time, options, &ctx);
3924 0 : if (ret)
3925 0 : goto out;
3926 :
3927 0 : ret = krb5_init_creds_set_service(context, ctx, in_tkt_service);
3928 0 : if (ret)
3929 0 : goto out;
3930 :
3931 0 : ret = krb5_init_creds_set_keytab(context, ctx, keytab);
3932 0 : if (ret)
3933 0 : goto out;
3934 :
3935 0 : ret = krb5_init_creds_get(context, ctx);
3936 0 : if (ret == 0)
3937 0 : krb5_process_last_request(context, options, ctx);
3938 :
3939 0 : out:
3940 0 : krb5_kt_free_entry(context, &ktent);
3941 0 : if (ret == 0)
3942 0 : krb5_init_creds_get_creds(context, ctx, creds);
3943 :
3944 0 : if (ctx)
3945 0 : krb5_init_creds_free(context, ctx);
3946 :
3947 0 : return ret;
3948 : }
3949 :
3950 : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
3951 0 : _krb5_init_creds_set_gss_mechanism(krb5_context context,
3952 : krb5_gss_init_ctx gssic,
3953 : const struct gss_OID_desc_struct *gss_mech)
3954 : {
3955 0 : gssic->mech = gss_mech; /* OIDs are interned, so no copy required */
3956 0 : }
3957 :
3958 : KRB5_LIB_FUNCTION const struct gss_OID_desc_struct * KRB5_LIB_CALL
3959 0 : _krb5_init_creds_get_gss_mechanism(krb5_context context,
3960 : krb5_gss_init_ctx gssic)
3961 : {
3962 0 : return gssic->mech;
3963 : }
3964 :
3965 : KRB5_LIB_FUNCTION void KRB5_LIB_CALL
3966 0 : _krb5_init_creds_set_gss_cred(krb5_context context,
3967 : krb5_gss_init_ctx gssic,
3968 : struct gss_cred_id_t_desc_struct *gss_cred)
3969 : {
3970 0 : if (gssic->cred != gss_cred && gssic->flags.release_cred)
3971 0 : gssic->release_cred(context, gssic, gssic->cred);
3972 :
3973 0 : gssic->cred = gss_cred;
3974 0 : gssic->flags.release_cred = 1;
3975 0 : }
3976 :
3977 : KRB5_LIB_FUNCTION const struct gss_cred_id_t_desc_struct * KRB5_LIB_CALL
3978 0 : _krb5_init_creds_get_gss_cred(krb5_context context,
3979 : krb5_gss_init_ctx gssic)
3980 : {
3981 0 : return gssic->cred;
3982 : }
3983 :
3984 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
3985 0 : _krb5_init_creds_init_gss(krb5_context context,
3986 : krb5_init_creds_context ctx,
3987 : krb5_gssic_step step,
3988 : krb5_gssic_finish finish,
3989 : krb5_gssic_release_cred release_cred,
3990 : krb5_gssic_delete_sec_context delete_sec_context,
3991 : const struct gss_cred_id_t_desc_struct *gss_cred,
3992 : const struct gss_OID_desc_struct *gss_mech,
3993 : unsigned int flags)
3994 : {
3995 0 : krb5_gss_init_ctx gssic;
3996 :
3997 0 : gssic = calloc(1, sizeof(*gssic));
3998 0 : if (gssic == NULL)
3999 0 : return krb5_enomem(context);
4000 :
4001 0 : if (ctx->gss_init_ctx)
4002 0 : free_gss_init_ctx(context, ctx->gss_init_ctx);
4003 0 : ctx->gss_init_ctx = gssic;
4004 :
4005 0 : gssic->cred = (struct gss_cred_id_t_desc_struct *)gss_cred;
4006 0 : gssic->mech = gss_mech;
4007 0 : if (flags & KRB5_GSS_IC_FLAG_RELEASE_CRED)
4008 0 : gssic->flags.release_cred = 1;
4009 :
4010 0 : gssic->step = step;
4011 0 : gssic->finish = finish;
4012 0 : gssic->release_cred = release_cred;
4013 0 : gssic->delete_sec_context = delete_sec_context;
4014 :
4015 0 : return 0;
4016 : }
|