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