1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* clients/kinit/kinit.c - Initialize a credential cache */
3 /*
4 * Copyright 1990, 2008 by the Massachusetts Institute of Technology.
5 * All Rights Reserved.
6 *
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
11 *
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
25 */
26
27 #include "autoconf.h"
28 #include <k5-int.h>
29 #include "k5-platform.h" /* For asprintf and getopt */
30 #include <krb5.h>
31 #include "extern.h"
32 #include <locale.h>
33 #include <string.h>
34 #include <stdio.h>
35 #include <time.h>
36 #include <errno.h>
37 #include <com_err.h>
38
39 #ifndef _WIN32
40 #define GET_PROGNAME(x) (strrchr((x), '/') ? strrchr((x), '/') + 1 : (x))
41 #else
42 #define GET_PROGNAME(x) max(max(strrchr((x), '/'), strrchr((x), '\\')) + 1,(x))
43 #endif
44
45 #ifdef HAVE_PWD_H
46 #include <pwd.h>
47 static char *
get_name_from_os()48 get_name_from_os()
49 {
50 struct passwd *pw;
51
52 pw = getpwuid(getuid());
53 return (pw != NULL) ? pw->pw_name : NULL;
54 }
55 #else /* HAVE_PWD_H */
56 #ifdef _WIN32
57 static char *
get_name_from_os()58 get_name_from_os()
59 {
60 static char name[1024];
61 DWORD name_size = sizeof(name);
62
63 if (GetUserName(name, &name_size)) {
64 name[sizeof(name) - 1] = '\0'; /* Just to be extra safe */
65 return name;
66 } else {
67 return NULL;
68 }
69 }
70 #else /* _WIN32 */
71 static char *
get_name_from_os()72 get_name_from_os()
73 {
74 return NULL;
75 }
76 #endif /* _WIN32 */
77 #endif /* HAVE_PWD_H */
78
79 static char *progname;
80
81 typedef enum { INIT_PW, INIT_KT, RENEW, VALIDATE } action_type;
82
83 struct k_opts
84 {
85 /* In seconds */
86 krb5_deltat starttime;
87 krb5_deltat lifetime;
88 krb5_deltat rlife;
89
90 int forwardable;
91 int proxiable;
92 int request_pac;
93 int anonymous;
94 int addresses;
95
96 int not_forwardable;
97 int not_proxiable;
98 int not_request_pac;
99 int no_addresses;
100
101 int verbose;
102
103 char *principal_name;
104 char *service_name;
105 char *keytab_name;
106 char *k5_in_cache_name;
107 char *k5_out_cache_name;
108 char *armor_ccache;
109
110 action_type action;
111 int use_client_keytab;
112
113 int num_pa_opts;
114 krb5_gic_opt_pa_data *pa_opts;
115
116 int canonicalize;
117 int enterprise;
118 };
119
120 struct k5_data
121 {
122 krb5_context ctx;
123 krb5_ccache in_cc, out_cc;
124 krb5_principal me;
125 char *name;
126 krb5_boolean switch_to_cache;
127 };
128
129 /*
130 * If struct[2] == NULL, then long_getopt acts as if the short flag struct[3]
131 * were specified. If struct[2] != NULL, then struct[3] is stored in
132 * *(struct[2]), the array index which was specified is stored in *index, and
133 * long_getopt() returns 0.
134 */
135 const char *shopts = "r:fpFPn54aAVl:s:c:kit:T:RS:vX:CEI:";
136
137 #define USAGE_BREAK "\n\t"
138
139 static void
usage()140 usage()
141 {
142 fprintf(stderr,
143 _("Usage: %s [-V] [-l lifetime] [-s start_time] "
144 "[-r renewable_life]\n"
145 "\t[-f | -F] [-p | -P] [-n] [-a | -A] [-C] [-E]\n"
146 "\t[--request-pac | --no-request-pac]\n"
147 "\t[-v] [-R] [-k [-i|-t keytab_file]] [-c cachename]\n"
148 "\t[-S service_name] [-I input_ccache] [-T ticket_armor_cache]\n"
149 "\t[-X <attribute>[=<value>]] [principal]\n"
150 "\n"), progname);
151
152 fprintf(stderr, " options:\n");
153 fprintf(stderr, _("\t-V verbose\n"));
154 fprintf(stderr, _("\t-l lifetime\n"));
155 fprintf(stderr, _("\t-s start time\n"));
156 fprintf(stderr, _("\t-r renewable lifetime\n"));
157 fprintf(stderr, _("\t-f forwardable\n"));
158 fprintf(stderr, _("\t-F not forwardable\n"));
159 fprintf(stderr, _("\t-p proxiable\n"));
160 fprintf(stderr, _("\t-P not proxiable\n"));
161 fprintf(stderr, _("\t-n anonymous\n"));
162 fprintf(stderr, _("\t-a include addresses\n"));
163 fprintf(stderr, _("\t-A do not include addresses\n"));
164 fprintf(stderr, _("\t-v validate\n"));
165 fprintf(stderr, _("\t-R renew\n"));
166 fprintf(stderr, _("\t-C canonicalize\n"));
167 fprintf(stderr, _("\t-E client is enterprise principal name\n"));
168 fprintf(stderr, _("\t-k use keytab\n"));
169 fprintf(stderr, _("\t-i use default client keytab (with -k)\n"));
170 fprintf(stderr, _("\t-t filename of keytab to use\n"));
171 fprintf(stderr, _("\t-c Kerberos 5 cache name\n"));
172 fprintf(stderr, _("\t-S service\n"));
173 fprintf(stderr, _("\t-I input credential cache\n"));
174 fprintf(stderr, _("\t-T armor credential cache\n"));
175 fprintf(stderr, _("\t-X <attribute>[=<value>]\n"));
176 fprintf(stderr,
177 _("\t--{,no}-request-pac request KDC include/exclude a PAC\n"));
178 exit(2);
179 }
180
181 static krb5_context errctx;
182 static void
extended_com_err_fn(const char * myprog,errcode_t code,const char * fmt,va_list args)183 extended_com_err_fn(const char *myprog, errcode_t code, const char *fmt,
184 va_list args)
185 {
186 const char *emsg;
187
188 emsg = krb5_get_error_message(errctx, code);
189 fprintf(stderr, "%s: %s ", myprog, emsg);
190 krb5_free_error_message(errctx, emsg);
191 vfprintf(stderr, fmt, args);
192 fprintf(stderr, "\n");
193 }
194
195 static int
add_preauth_opt(struct k_opts * opts,char * av)196 add_preauth_opt(struct k_opts *opts, char *av)
197 {
198 char *sep, *v;
199 krb5_gic_opt_pa_data *p, *x;
200 size_t newsize = (opts->num_pa_opts + 1) * sizeof(*opts->pa_opts);
201
202 x = realloc(opts->pa_opts, newsize);
203 if (x == NULL)
204 return ENOMEM;
205 opts->pa_opts = x;
206
207 p = &opts->pa_opts[opts->num_pa_opts];
208 sep = strchr(av, '=');
209 if (sep) {
210 *sep = '\0';
211 v = ++sep;
212 p->value = v;
213 } else {
214 p->value = "yes";
215 }
216 p->attr = av;
217 opts->num_pa_opts++;
218 return 0;
219 }
220
221 static char *
parse_options(int argc,char ** argv,struct k_opts * opts)222 parse_options(int argc, char **argv, struct k_opts *opts)
223 {
224 struct option long_options[] = {
225 { "noforwardable", 0, NULL, 'F' },
226 { "noproxiable", 0, NULL, 'P' },
227 { "addresses", 0, NULL, 'a'},
228 { "forwardable", 0, NULL, 'f' },
229 { "proxiable", 0, NULL, 'p' },
230 { "noaddresses", 0, NULL, 'A' },
231 { "canonicalize", 0, NULL, 'C' },
232 { "enterprise", 0, NULL, 'E' },
233 { "request-pac", 0, &opts->request_pac, 1 },
234 { "no-request-pac", 0, &opts->not_request_pac, 1 },
235 { NULL, 0, NULL, 0 }
236 };
237 krb5_error_code ret;
238 int errflg = 0;
239 int i;
240
241 while ((i = getopt_long(argc, argv, shopts, long_options, 0)) != -1) {
242 switch (i) {
243 case 'V':
244 opts->verbose = 1;
245 break;
246 case 'l':
247 /* Lifetime */
248 ret = krb5_string_to_deltat(optarg, &opts->lifetime);
249 if (ret || opts->lifetime == 0) {
250 fprintf(stderr, _("Bad lifetime value %s\n"), optarg);
251 errflg++;
252 }
253 break;
254 case 'r':
255 /* Renewable Time */
256 ret = krb5_string_to_deltat(optarg, &opts->rlife);
257 if (ret || opts->rlife == 0) {
258 fprintf(stderr, _("Bad lifetime value %s\n"), optarg);
259 errflg++;
260 }
261 break;
262 case 'f':
263 opts->forwardable = 1;
264 break;
265 case 'F':
266 opts->not_forwardable = 1;
267 break;
268 case 'p':
269 opts->proxiable = 1;
270 break;
271 case 'P':
272 opts->not_proxiable = 1;
273 break;
274 case 'n':
275 opts->anonymous = 1;
276 break;
277 case 'a':
278 opts->addresses = 1;
279 break;
280 case 'A':
281 opts->no_addresses = 1;
282 break;
283 case 's':
284 ret = krb5_string_to_deltat(optarg, &opts->starttime);
285 if (ret || opts->starttime == 0) {
286 /* Parse as an absolute time; intentionally undocumented
287 * but left for backwards compatibility. */
288 krb5_timestamp abs_starttime;
289
290 ret = krb5_string_to_timestamp(optarg, &abs_starttime);
291 if (ret || abs_starttime == 0) {
292 fprintf(stderr, _("Bad start time value %s\n"), optarg);
293 errflg++;
294 } else {
295 opts->starttime = ts_delta(abs_starttime, time(NULL));
296 }
297 }
298 break;
299 case 'S':
300 opts->service_name = optarg;
301 break;
302 case 'k':
303 opts->action = INIT_KT;
304 break;
305 case 'i':
306 opts->use_client_keytab = 1;
307 break;
308 case 't':
309 if (opts->keytab_name != NULL) {
310 fprintf(stderr, _("Only one -t option allowed.\n"));
311 errflg++;
312 } else {
313 opts->keytab_name = optarg;
314 }
315 break;
316 case 'T':
317 if (opts->armor_ccache != NULL) {
318 fprintf(stderr, _("Only one armor_ccache\n"));
319 errflg++;
320 } else {
321 opts->armor_ccache = optarg;
322 }
323 break;
324 case 'R':
325 opts->action = RENEW;
326 break;
327 case 'v':
328 opts->action = VALIDATE;
329 break;
330 case 'c':
331 if (opts->k5_out_cache_name != NULL) {
332 fprintf(stderr, _("Only one -c option allowed\n"));
333 errflg++;
334 } else {
335 opts->k5_out_cache_name = optarg;
336 }
337 break;
338 case 'I':
339 if (opts->k5_in_cache_name != NULL) {
340 fprintf(stderr, _("Only one -I option allowed\n"));
341 errflg++;
342 } else {
343 opts->k5_in_cache_name = optarg;
344 }
345 break;
346 case 'X':
347 ret = add_preauth_opt(opts, optarg);
348 if (ret) {
349 com_err(progname, ret, _("while adding preauth option"));
350 errflg++;
351 }
352 break;
353 case 'C':
354 opts->canonicalize = 1;
355 break;
356 case 'E':
357 opts->enterprise = 1;
358 break;
359 case '4':
360 fprintf(stderr, _("Kerberos 4 is no longer supported\n"));
361 exit(3);
362 break;
363 case '5':
364 break;
365 case 0:
366 /* If this option set a flag, do nothing else now. */
367 break;
368 default:
369 errflg++;
370 break;
371 }
372 }
373
374 if (opts->forwardable && opts->not_forwardable) {
375 fprintf(stderr, _("Only one of -f and -F allowed\n"));
376 errflg++;
377 }
378 if (opts->proxiable && opts->not_proxiable) {
379 fprintf(stderr, _("Only one of -p and -P allowed\n"));
380 errflg++;
381 }
382 if (opts->request_pac && opts->not_request_pac) {
383 fprintf(stderr, _("Only one of --request-pac and --no-request-pac "
384 "allowed\n"));
385 errflg++;
386 }
387 if (opts->addresses && opts->no_addresses) {
388 fprintf(stderr, _("Only one of -a and -A allowed\n"));
389 errflg++;
390 }
391 if (opts->keytab_name != NULL && opts->use_client_keytab == 1) {
392 fprintf(stderr, _("Only one of -t and -i allowed\n"));
393 errflg++;
394 }
395 if ((opts->keytab_name != NULL || opts->use_client_keytab == 1) &&
396 opts->action != INIT_KT) {
397 opts->action = INIT_KT;
398 fprintf(stderr, _("keytab specified, forcing -k\n"));
399 }
400 if (argc - optind > 1) {
401 fprintf(stderr, _("Extra arguments (starting with \"%s\").\n"),
402 argv[optind + 1]);
403 errflg++;
404 }
405
406 if (errflg)
407 usage();
408
409 opts->principal_name = (optind == argc - 1) ? argv[optind] : 0;
410 return opts->principal_name;
411 }
412
413 static int
k5_begin(struct k_opts * opts,struct k5_data * k5)414 k5_begin(struct k_opts *opts, struct k5_data *k5)
415 {
416 krb5_error_code ret;
417 int success = 0;
418 int flags = opts->enterprise ? KRB5_PRINCIPAL_PARSE_ENTERPRISE : 0;
419 krb5_ccache defcache = NULL;
420 krb5_principal defcache_princ = NULL, princ;
421 krb5_keytab keytab;
422 const char *deftype = NULL;
423 char *defrealm, *name;
424
425 ret = krb5_init_context(&k5->ctx);
426 if (ret) {
427 com_err(progname, ret, _("while initializing Kerberos 5 library"));
428 return 0;
429 }
430 errctx = k5->ctx;
431
432 if (opts->k5_out_cache_name) {
433 ret = krb5_cc_resolve(k5->ctx, opts->k5_out_cache_name, &k5->out_cc);
434 if (ret) {
435 com_err(progname, ret, _("resolving ccache %s"),
436 opts->k5_out_cache_name);
437 goto cleanup;
438 }
439 if (opts->verbose) {
440 fprintf(stderr, _("Using specified cache: %s\n"),
441 opts->k5_out_cache_name);
442 }
443 } else {
444 /* Resolve the default ccache and get its type and default principal
445 * (if it is initialized). */
446 ret = krb5_cc_default(k5->ctx, &defcache);
447 if (ret) {
448 com_err(progname, ret, _("while getting default ccache"));
449 goto cleanup;
450 }
451 deftype = krb5_cc_get_type(k5->ctx, defcache);
452 if (krb5_cc_get_principal(k5->ctx, defcache, &defcache_princ) != 0)
453 defcache_princ = NULL;
454 }
455
456 /* Choose a client principal name. */
457 if (opts->principal_name != NULL) {
458 /* Use the specified principal name. */
459 ret = krb5_parse_name_flags(k5->ctx, opts->principal_name, flags,
460 &k5->me);
461 if (ret) {
462 com_err(progname, ret, _("when parsing name %s"),
463 opts->principal_name);
464 goto cleanup;
465 }
466 } else if (opts->anonymous) {
467 /* Use the anonymous principal for the local realm. */
468 ret = krb5_get_default_realm(k5->ctx, &defrealm);
469 if (ret) {
470 com_err(progname, ret, _("while getting default realm"));
471 goto cleanup;
472 }
473 ret = krb5_build_principal_ext(k5->ctx, &k5->me,
474 strlen(defrealm), defrealm,
475 strlen(KRB5_WELLKNOWN_NAMESTR),
476 KRB5_WELLKNOWN_NAMESTR,
477 strlen(KRB5_ANONYMOUS_PRINCSTR),
478 KRB5_ANONYMOUS_PRINCSTR, 0);
479 krb5_free_default_realm(k5->ctx, defrealm);
480 if (ret) {
481 com_err(progname, ret, _("while building principal"));
482 goto cleanup;
483 }
484 } else if (opts->action == INIT_KT && opts->use_client_keytab) {
485 /* Use the first entry from the client keytab. */
486 ret = krb5_kt_client_default(k5->ctx, &keytab);
487 if (ret) {
488 com_err(progname, ret,
489 _("When resolving the default client keytab"));
490 goto cleanup;
491 }
492 ret = k5_kt_get_principal(k5->ctx, keytab, &k5->me);
493 krb5_kt_close(k5->ctx, keytab);
494 if (ret) {
495 com_err(progname, ret,
496 _("When determining client principal name from keytab"));
497 goto cleanup;
498 }
499 } else if (opts->action == INIT_KT) {
500 /* Use the default host/service name. */
501 ret = krb5_sname_to_principal(k5->ctx, NULL, NULL, KRB5_NT_SRV_HST,
502 &k5->me);
503 if (ret) {
504 com_err(progname, ret,
505 _("when creating default server principal name"));
506 goto cleanup;
507 }
508 } else if (k5->out_cc != NULL) {
509 /* If the output ccache is initialized, use its principal. */
510 if (krb5_cc_get_principal(k5->ctx, k5->out_cc, &princ) == 0)
511 k5->me = princ;
512 } else if (defcache_princ != NULL) {
513 /* Use the default cache's principal, and use the default cache as the
514 * output cache. */
515 k5->out_cc = defcache;
516 defcache = NULL;
517 k5->me = defcache_princ;
518 defcache_princ = NULL;
519 }
520
521 /* If we still haven't chosen, use the local username. */
522 if (k5->me == NULL) {
523 name = get_name_from_os();
524 if (name == NULL) {
525 fprintf(stderr, _("Unable to identify user\n"));
526 goto cleanup;
527 }
528 ret = krb5_parse_name_flags(k5->ctx, name, flags, &k5->me);
529 if (ret) {
530 com_err(progname, ret, _("when parsing name %s"), name);
531 goto cleanup;
532 }
533 }
534
535 if (k5->out_cc == NULL && krb5_cc_support_switch(k5->ctx, deftype)) {
536 /* Use an existing cache for the client principal if we can. */
537 ret = krb5_cc_cache_match(k5->ctx, k5->me, &k5->out_cc);
538 if (ret && ret != KRB5_CC_NOTFOUND) {
539 com_err(progname, ret, _("while searching for ccache for %s"),
540 opts->principal_name);
541 goto cleanup;
542 }
543 if (!ret) {
544 if (opts->verbose) {
545 fprintf(stderr, _("Using existing cache: %s\n"),
546 krb5_cc_get_name(k5->ctx, k5->out_cc));
547 }
548 k5->switch_to_cache = 1;
549 } else if (defcache_princ != NULL) {
550 /* Create a new cache to avoid overwriting the initialized default
551 * cache. */
552 ret = krb5_cc_new_unique(k5->ctx, deftype, NULL, &k5->out_cc);
553 if (ret) {
554 com_err(progname, ret, _("while generating new ccache"));
555 goto cleanup;
556 }
557 if (opts->verbose) {
558 fprintf(stderr, _("Using new cache: %s\n"),
559 krb5_cc_get_name(k5->ctx, k5->out_cc));
560 }
561 k5->switch_to_cache = 1;
562 }
563 }
564
565 /* Use the default cache if we haven't picked one yet. */
566 if (k5->out_cc == NULL) {
567 k5->out_cc = defcache;
568 defcache = NULL;
569 if (opts->verbose) {
570 fprintf(stderr, _("Using default cache: %s\n"),
571 krb5_cc_get_name(k5->ctx, k5->out_cc));
572 }
573 }
574
575 if (opts->k5_in_cache_name) {
576 ret = krb5_cc_resolve(k5->ctx, opts->k5_in_cache_name, &k5->in_cc);
577 if (ret) {
578 com_err(progname, ret, _("resolving ccache %s"),
579 opts->k5_in_cache_name);
580 goto cleanup;
581 }
582 if (opts->verbose) {
583 fprintf(stderr, _("Using specified input cache: %s\n"),
584 opts->k5_in_cache_name);
585 }
586 }
587
588 ret = krb5_unparse_name(k5->ctx, k5->me, &k5->name);
589 if (ret) {
590 com_err(progname, ret, _("when unparsing name"));
591 goto cleanup;
592 }
593 if (opts->verbose)
594 fprintf(stderr, _("Using principal: %s\n"), k5->name);
595
596 opts->principal_name = k5->name;
597
598 success = 1;
599
600 cleanup:
601 if (defcache != NULL)
602 krb5_cc_close(k5->ctx, defcache);
603 krb5_free_principal(k5->ctx, defcache_princ);
604 return success;
605 }
606
607 static void
k5_end(struct k5_data * k5)608 k5_end(struct k5_data *k5)
609 {
610 krb5_free_unparsed_name(k5->ctx, k5->name);
611 krb5_free_principal(k5->ctx, k5->me);
612 if (k5->in_cc != NULL)
613 krb5_cc_close(k5->ctx, k5->in_cc);
614 if (k5->out_cc != NULL)
615 krb5_cc_close(k5->ctx, k5->out_cc);
616 krb5_free_context(k5->ctx);
617 errctx = NULL;
618 memset(k5, 0, sizeof(*k5));
619 }
620
621 static krb5_error_code KRB5_CALLCONV
kinit_prompter(krb5_context ctx,void * data,const char * name,const char * banner,int num_prompts,krb5_prompt prompts[])622 kinit_prompter(krb5_context ctx, void *data, const char *name,
623 const char *banner, int num_prompts, krb5_prompt prompts[])
624 {
625 krb5_boolean *pwprompt = data;
626 krb5_prompt_type *ptypes;
627 int i;
628
629 /* Make a note if we receive a password prompt. */
630 ptypes = krb5_get_prompt_types(ctx);
631 for (i = 0; i < num_prompts; i++) {
632 if (ptypes != NULL && ptypes[i] == KRB5_PROMPT_TYPE_PASSWORD)
633 *pwprompt = TRUE;
634 }
635 return krb5_prompter_posix(ctx, data, name, banner, num_prompts, prompts);
636 }
637
638 static int
k5_kinit(struct k_opts * opts,struct k5_data * k5)639 k5_kinit(struct k_opts *opts, struct k5_data *k5)
640 {
641 int notix = 1;
642 krb5_keytab keytab = 0;
643 krb5_creds my_creds;
644 krb5_error_code ret;
645 krb5_get_init_creds_opt *options = NULL;
646 krb5_boolean pwprompt = FALSE;
647 krb5_address **addresses = NULL;
648 krb5_principal cprinc;
649 krb5_ccache mcc = NULL;
650 int i;
651
652 memset(&my_creds, 0, sizeof(my_creds));
653
654 ret = krb5_get_init_creds_opt_alloc(k5->ctx, &options);
655 if (ret)
656 goto cleanup;
657
658 if (opts->lifetime)
659 krb5_get_init_creds_opt_set_tkt_life(options, opts->lifetime);
660 if (opts->rlife)
661 krb5_get_init_creds_opt_set_renew_life(options, opts->rlife);
662 if (opts->forwardable)
663 krb5_get_init_creds_opt_set_forwardable(options, 1);
664 if (opts->not_forwardable)
665 krb5_get_init_creds_opt_set_forwardable(options, 0);
666 if (opts->proxiable)
667 krb5_get_init_creds_opt_set_proxiable(options, 1);
668 if (opts->not_proxiable)
669 krb5_get_init_creds_opt_set_proxiable(options, 0);
670 if (opts->canonicalize)
671 krb5_get_init_creds_opt_set_canonicalize(options, 1);
672 if (opts->anonymous)
673 krb5_get_init_creds_opt_set_anonymous(options, 1);
674 if (opts->addresses) {
675 ret = krb5_os_localaddr(k5->ctx, &addresses);
676 if (ret) {
677 com_err(progname, ret, _("getting local addresses"));
678 goto cleanup;
679 }
680 krb5_get_init_creds_opt_set_address_list(options, addresses);
681 }
682 if (opts->no_addresses)
683 krb5_get_init_creds_opt_set_address_list(options, NULL);
684 if (opts->armor_ccache != NULL) {
685 krb5_get_init_creds_opt_set_fast_ccache_name(k5->ctx, options,
686 opts->armor_ccache);
687 }
688 if (opts->request_pac)
689 krb5_get_init_creds_opt_set_pac_request(k5->ctx, options, TRUE);
690 if (opts->not_request_pac)
691 krb5_get_init_creds_opt_set_pac_request(k5->ctx, options, FALSE);
692
693
694 if (opts->action == INIT_KT && opts->keytab_name != NULL) {
695 #ifndef _WIN32
696 if (strncmp(opts->keytab_name, "KDB:", 4) == 0) {
697 ret = kinit_kdb_init(&k5->ctx, k5->me->realm.data);
698 errctx = k5->ctx;
699 if (ret) {
700 com_err(progname, ret,
701 _("while setting up KDB keytab for realm %s"),
702 k5->me->realm.data);
703 goto cleanup;
704 }
705 }
706 #endif
707
708 ret = krb5_kt_resolve(k5->ctx, opts->keytab_name, &keytab);
709 if (ret) {
710 com_err(progname, ret, _("resolving keytab %s"),
711 opts->keytab_name);
712 goto cleanup;
713 }
714 if (opts->verbose)
715 fprintf(stderr, _("Using keytab: %s\n"), opts->keytab_name);
716 } else if (opts->action == INIT_KT && opts->use_client_keytab) {
717 ret = krb5_kt_client_default(k5->ctx, &keytab);
718 if (ret) {
719 com_err(progname, ret, _("resolving default client keytab"));
720 goto cleanup;
721 }
722 }
723
724 for (i = 0; i < opts->num_pa_opts; i++) {
725 ret = krb5_get_init_creds_opt_set_pa(k5->ctx, options,
726 opts->pa_opts[i].attr,
727 opts->pa_opts[i].value);
728 if (ret) {
729 com_err(progname, ret, _("while setting '%s'='%s'"),
730 opts->pa_opts[i].attr, opts->pa_opts[i].value);
731 goto cleanup;
732 }
733 if (opts->verbose) {
734 fprintf(stderr, _("PA Option %s = %s\n"), opts->pa_opts[i].attr,
735 opts->pa_opts[i].value);
736 }
737 }
738 if (k5->in_cc) {
739 ret = krb5_get_init_creds_opt_set_in_ccache(k5->ctx, options,
740 k5->in_cc);
741 if (ret)
742 goto cleanup;
743 }
744 ret = krb5_get_init_creds_opt_set_out_ccache(k5->ctx, options, k5->out_cc);
745 if (ret)
746 goto cleanup;
747
748 switch (opts->action) {
749 case INIT_PW:
750 ret = krb5_get_init_creds_password(k5->ctx, &my_creds, k5->me, 0,
751 kinit_prompter, &pwprompt,
752 opts->starttime, opts->service_name,
753 options);
754 break;
755 case INIT_KT:
756 ret = krb5_get_init_creds_keytab(k5->ctx, &my_creds, k5->me, keytab,
757 opts->starttime, opts->service_name,
758 options);
759 break;
760 case VALIDATE:
761 ret = krb5_get_validated_creds(k5->ctx, &my_creds, k5->me, k5->out_cc,
762 opts->service_name);
763 break;
764 case RENEW:
765 ret = krb5_get_renewed_creds(k5->ctx, &my_creds, k5->me, k5->out_cc,
766 opts->service_name);
767 break;
768 }
769
770 if (ret) {
771 char *doing = NULL;
772 switch (opts->action) {
773 case INIT_PW:
774 case INIT_KT:
775 doing = _("getting initial credentials");
776 break;
777 case VALIDATE:
778 doing = _("validating credentials");
779 break;
780 case RENEW:
781 doing = _("renewing credentials");
782 break;
783 }
784
785 /* If reply decryption failed, or if pre-authentication failed and we
786 * were prompted for a password, assume the password was wrong. */
787 if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY ||
788 (pwprompt && ret == KRB5KDC_ERR_PREAUTH_FAILED)) {
789 fprintf(stderr, _("%s: Password incorrect while %s\n"), progname,
790 doing);
791 } else {
792 com_err(progname, ret, _("while %s"), doing);
793 }
794 goto cleanup;
795 }
796
797 if (opts->action != INIT_PW && opts->action != INIT_KT) {
798 cprinc = opts->canonicalize ? my_creds.client : k5->me;
799 ret = krb5_cc_new_unique(k5->ctx, "MEMORY", NULL, &mcc);
800 if (!ret)
801 ret = krb5_cc_initialize(k5->ctx, mcc, cprinc);
802 if (ret) {
803 com_err(progname, ret, _("when creating temporary cache"));
804 goto cleanup;
805 }
806 if (opts->verbose)
807 fprintf(stderr, _("Initialized cache\n"));
808
809 ret = k5_cc_store_primary_cred(k5->ctx, mcc, &my_creds);
810 if (ret) {
811 com_err(progname, ret, _("while storing credentials"));
812 goto cleanup;
813 }
814 ret = krb5_cc_move(k5->ctx, mcc, k5->out_cc);
815 if (ret) {
816 com_err(progname, ret, _("while saving to cache %s"),
817 opts->k5_out_cache_name ? opts->k5_out_cache_name : "");
818 goto cleanup;
819 }
820 mcc = NULL;
821 if (opts->verbose)
822 fprintf(stderr, _("Stored credentials\n"));
823 }
824 notix = 0;
825 if (k5->switch_to_cache) {
826 ret = krb5_cc_switch(k5->ctx, k5->out_cc);
827 if (ret) {
828 com_err(progname, ret, _("while switching to new ccache"));
829 goto cleanup;
830 }
831 }
832
833 cleanup:
834 #ifndef _WIN32
835 kinit_kdb_fini();
836 #endif
837 if (mcc != NULL)
838 krb5_cc_destroy(k5->ctx, mcc);
839 if (options)
840 krb5_get_init_creds_opt_free(k5->ctx, options);
841 if (my_creds.client == k5->me)
842 my_creds.client = 0;
843 if (opts->pa_opts) {
844 free(opts->pa_opts);
845 opts->pa_opts = NULL;
846 opts->num_pa_opts = 0;
847 }
848 krb5_free_cred_contents(k5->ctx, &my_creds);
849 if (keytab != NULL)
850 krb5_kt_close(k5->ctx, keytab);
851 return notix ? 0 : 1;
852 }
853
854 int
main(int argc,char * argv[])855 main(int argc, char *argv[])
856 {
857 struct k_opts opts;
858 struct k5_data k5;
859 int authed_k5 = 0;
860
861 setlocale(LC_ALL, "");
862 progname = GET_PROGNAME(argv[0]);
863
864 /* Ensure we can be driven from a pipe */
865 if (!isatty(fileno(stdin)))
866 setvbuf(stdin, 0, _IONBF, 0);
867 if (!isatty(fileno(stdout)))
868 setvbuf(stdout, 0, _IONBF, 0);
869 if (!isatty(fileno(stderr)))
870 setvbuf(stderr, 0, _IONBF, 0);
871
872 memset(&opts, 0, sizeof(opts));
873 opts.action = INIT_PW;
874
875 memset(&k5, 0, sizeof(k5));
876
877 set_com_err_hook(extended_com_err_fn);
878
879 parse_options(argc, argv, &opts);
880
881 if (k5_begin(&opts, &k5))
882 authed_k5 = k5_kinit(&opts, &k5);
883
884 if (authed_k5 && opts.verbose)
885 fprintf(stderr, _("Authenticated to Kerberos v5\n"));
886
887 k5_end(&k5);
888
889 if (!authed_k5)
890 exit(1);
891 return 0;
892 }
893