Imported Upstream version 1.17
[platform/upstream/krb5.git] / src / clients / kinit / kinit.c
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 *
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 *
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 *
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
140 usage()
141 {
142     fprintf(stderr, "Usage: %s [-V] "
143             "[-l lifetime] [-s start_time] "
144             USAGE_BREAK
145             "[-r renewable_life] "
146             "[-f | -F | --forwardable | --noforwardable] "
147             USAGE_BREAK
148             "[-p | -P | --proxiable | --noproxiable] "
149             USAGE_BREAK
150             "-n "
151             "[-a | -A | --addresses | --noaddresses] "
152             USAGE_BREAK
153             "[--request-pac | --no-request-pac] "
154             USAGE_BREAK
155             "[-C | --canonicalize] "
156             USAGE_BREAK
157             "[-E | --enterprise] "
158             USAGE_BREAK
159             "[-v] [-R] "
160             "[-k [-i|-t keytab_file]] "
161             "[-c cachename] "
162             USAGE_BREAK
163             "[-S service_name] [-T ticket_armor_cache]"
164             USAGE_BREAK
165             "[-X <attribute>[=<value>]] [principal]"
166             "\n\n",
167             progname);
168
169     fprintf(stderr, "    options:\n");
170     fprintf(stderr, _("\t-V verbose\n"));
171     fprintf(stderr, _("\t-l lifetime\n"));
172     fprintf(stderr, _("\t-s start time\n"));
173     fprintf(stderr, _("\t-r renewable lifetime\n"));
174     fprintf(stderr, _("\t-f forwardable\n"));
175     fprintf(stderr, _("\t-F not forwardable\n"));
176     fprintf(stderr, _("\t-p proxiable\n"));
177     fprintf(stderr, _("\t-P not proxiable\n"));
178     fprintf(stderr, _("\t-n anonymous\n"));
179     fprintf(stderr, _("\t-a include addresses\n"));
180     fprintf(stderr, _("\t-A do not include addresses\n"));
181     fprintf(stderr, _("\t-v validate\n"));
182     fprintf(stderr, _("\t-R renew\n"));
183     fprintf(stderr, _("\t-C canonicalize\n"));
184     fprintf(stderr, _("\t-E client is enterprise principal name\n"));
185     fprintf(stderr, _("\t-k use keytab\n"));
186     fprintf(stderr, _("\t-i use default client keytab (with -k)\n"));
187     fprintf(stderr, _("\t-t filename of keytab to use\n"));
188     fprintf(stderr, _("\t-c Kerberos 5 cache name\n"));
189     fprintf(stderr, _("\t-S service\n"));
190     fprintf(stderr, _("\t-T armor credential cache\n"));
191     fprintf(stderr, _("\t-X <attribute>[=<value>]\n"));
192     exit(2);
193 }
194
195 static krb5_context errctx;
196 static void
197 extended_com_err_fn(const char *myprog, errcode_t code, const char *fmt,
198                     va_list args)
199 {
200     const char *emsg;
201
202     emsg = krb5_get_error_message(errctx, code);
203     fprintf(stderr, "%s: %s ", myprog, emsg);
204     krb5_free_error_message(errctx, emsg);
205     vfprintf(stderr, fmt, args);
206     fprintf(stderr, "\n");
207 }
208
209 static int
210 add_preauth_opt(struct k_opts *opts, char *av)
211 {
212     char *sep, *v;
213     krb5_gic_opt_pa_data *p, *x;
214     size_t newsize = (opts->num_pa_opts + 1) * sizeof(*opts->pa_opts);
215
216     x = realloc(opts->pa_opts, newsize);
217     if (x == NULL)
218         return ENOMEM;
219     opts->pa_opts = x;
220
221     p = &opts->pa_opts[opts->num_pa_opts];
222     sep = strchr(av, '=');
223     if (sep) {
224         *sep = '\0';
225         v = ++sep;
226         p->value = v;
227     } else {
228         p->value = "yes";
229     }
230     p->attr = av;
231     opts->num_pa_opts++;
232     return 0;
233 }
234
235 static char *
236 parse_options(int argc, char **argv, struct k_opts *opts)
237 {
238     struct option long_options[] = {
239         { "noforwardable", 0, NULL, 'F' },
240         { "noproxiable", 0, NULL, 'P' },
241         { "addresses", 0, NULL, 'a'},
242         { "forwardable", 0, NULL, 'f' },
243         { "proxiable", 0, NULL, 'p' },
244         { "noaddresses", 0, NULL, 'A' },
245         { "canonicalize", 0, NULL, 'C' },
246         { "enterprise", 0, NULL, 'E' },
247         { "request-pac", 0, &opts->request_pac, 1 },
248         { "no-request-pac", 0, &opts->not_request_pac, 1 },
249         { NULL, 0, NULL, 0 }
250     };
251     krb5_error_code ret;
252     int errflg = 0;
253     int i;
254
255     while ((i = getopt_long(argc, argv, shopts, long_options, 0)) != -1) {
256         switch (i) {
257         case 'V':
258             opts->verbose = 1;
259             break;
260         case 'l':
261             /* Lifetime */
262             ret = krb5_string_to_deltat(optarg, &opts->lifetime);
263             if (ret || opts->lifetime == 0) {
264                 fprintf(stderr, _("Bad lifetime value %s\n"), optarg);
265                 errflg++;
266             }
267             break;
268         case 'r':
269             /* Renewable Time */
270             ret = krb5_string_to_deltat(optarg, &opts->rlife);
271             if (ret || opts->rlife == 0) {
272                 fprintf(stderr, _("Bad lifetime value %s\n"), optarg);
273                 errflg++;
274             }
275             break;
276         case 'f':
277             opts->forwardable = 1;
278             break;
279         case 'F':
280             opts->not_forwardable = 1;
281             break;
282         case 'p':
283             opts->proxiable = 1;
284             break;
285         case 'P':
286             opts->not_proxiable = 1;
287             break;
288         case 'n':
289             opts->anonymous = 1;
290             break;
291         case 'a':
292             opts->addresses = 1;
293             break;
294         case 'A':
295             opts->no_addresses = 1;
296             break;
297         case 's':
298             ret = krb5_string_to_deltat(optarg, &opts->starttime);
299             if (ret || opts->starttime == 0) {
300                 /* Parse as an absolute time; intentionally undocumented
301                  * but left for backwards compatibility. */
302                 krb5_timestamp abs_starttime;
303
304                 ret = krb5_string_to_timestamp(optarg, &abs_starttime);
305                 if (ret || abs_starttime == 0) {
306                     fprintf(stderr, _("Bad start time value %s\n"), optarg);
307                     errflg++;
308                 } else {
309                     opts->starttime = ts_delta(abs_starttime, time(NULL));
310                 }
311             }
312             break;
313         case 'S':
314             opts->service_name = optarg;
315             break;
316         case 'k':
317             opts->action = INIT_KT;
318             break;
319         case 'i':
320             opts->use_client_keytab = 1;
321             break;
322         case 't':
323             if (opts->keytab_name != NULL) {
324                 fprintf(stderr, _("Only one -t option allowed.\n"));
325                 errflg++;
326             } else {
327                 opts->keytab_name = optarg;
328             }
329             break;
330         case 'T':
331             if (opts->armor_ccache != NULL) {
332                 fprintf(stderr, _("Only one armor_ccache\n"));
333                 errflg++;
334             } else {
335                 opts->armor_ccache = optarg;
336             }
337             break;
338         case 'R':
339             opts->action = RENEW;
340             break;
341         case 'v':
342             opts->action = VALIDATE;
343             break;
344         case 'c':
345             if (opts->k5_out_cache_name != NULL) {
346                 fprintf(stderr, _("Only one -c option allowed\n"));
347                 errflg++;
348             } else {
349                 opts->k5_out_cache_name = optarg;
350             }
351             break;
352         case 'I':
353             if (opts->k5_in_cache_name != NULL) {
354                 fprintf(stderr, _("Only one -I option allowed\n"));
355                 errflg++;
356             } else {
357                 opts->k5_in_cache_name = optarg;
358             }
359             break;
360         case 'X':
361             ret = add_preauth_opt(opts, optarg);
362             if (ret) {
363                 com_err(progname, ret, _("while adding preauth option"));
364                 errflg++;
365             }
366             break;
367         case 'C':
368             opts->canonicalize = 1;
369             break;
370         case 'E':
371             opts->enterprise = 1;
372             break;
373         case '4':
374             fprintf(stderr, _("Kerberos 4 is no longer supported\n"));
375             exit(3);
376             break;
377         case '5':
378             break;
379         case 0:
380             /* If this option set a flag, do nothing else now. */
381             break;
382         default:
383             errflg++;
384             break;
385         }
386     }
387
388     if (opts->forwardable && opts->not_forwardable) {
389         fprintf(stderr, _("Only one of -f and -F allowed\n"));
390         errflg++;
391     }
392     if (opts->proxiable && opts->not_proxiable) {
393         fprintf(stderr, _("Only one of -p and -P allowed\n"));
394         errflg++;
395     }
396     if (opts->request_pac && opts->not_request_pac) {
397         fprintf(stderr, _("Only one of --request-pac and --no-request-pac "
398                           "allowed\n"));
399         errflg++;
400     }
401     if (opts->addresses && opts->no_addresses) {
402         fprintf(stderr, _("Only one of -a and -A allowed\n"));
403         errflg++;
404     }
405     if (opts->keytab_name != NULL && opts->use_client_keytab == 1) {
406         fprintf(stderr, _("Only one of -t and -i allowed\n"));
407         errflg++;
408     }
409     if ((opts->keytab_name != NULL || opts->use_client_keytab == 1) &&
410         opts->action != INIT_KT) {
411         opts->action = INIT_KT;
412         fprintf(stderr, _("keytab specified, forcing -k\n"));
413     }
414     if (argc - optind > 1) {
415         fprintf(stderr, _("Extra arguments (starting with \"%s\").\n"),
416                 argv[optind + 1]);
417         errflg++;
418     }
419
420     if (errflg)
421         usage();
422
423     opts->principal_name = (optind == argc - 1) ? argv[optind] : 0;
424     return opts->principal_name;
425 }
426
427 static int
428 k5_begin(struct k_opts *opts, struct k5_data *k5)
429 {
430     krb5_error_code ret;
431     int success = 0;
432     int flags = opts->enterprise ? KRB5_PRINCIPAL_PARSE_ENTERPRISE : 0;
433     krb5_ccache defcache = NULL;
434     krb5_principal defcache_princ = NULL, princ;
435     krb5_keytab keytab;
436     const char *deftype = NULL;
437     char *defrealm, *name;
438
439     ret = krb5_init_context(&k5->ctx);
440     if (ret) {
441         com_err(progname, ret, _("while initializing Kerberos 5 library"));
442         return 0;
443     }
444     errctx = k5->ctx;
445
446     if (opts->k5_out_cache_name) {
447         ret = krb5_cc_resolve(k5->ctx, opts->k5_out_cache_name, &k5->out_cc);
448         if (ret) {
449             com_err(progname, ret, _("resolving ccache %s"),
450                     opts->k5_out_cache_name);
451             goto cleanup;
452         }
453         if (opts->verbose) {
454             fprintf(stderr, _("Using specified cache: %s\n"),
455                     opts->k5_out_cache_name);
456         }
457     } else {
458         /* Resolve the default ccache and get its type and default principal
459          * (if it is initialized). */
460         ret = krb5_cc_default(k5->ctx, &defcache);
461         if (ret) {
462             com_err(progname, ret, _("while getting default ccache"));
463             goto cleanup;
464         }
465         deftype = krb5_cc_get_type(k5->ctx, defcache);
466         if (krb5_cc_get_principal(k5->ctx, defcache, &defcache_princ) != 0)
467             defcache_princ = NULL;
468     }
469
470     /* Choose a client principal name. */
471     if (opts->principal_name != NULL) {
472         /* Use the specified principal name. */
473         ret = krb5_parse_name_flags(k5->ctx, opts->principal_name, flags,
474                                     &k5->me);
475         if (ret) {
476             com_err(progname, ret, _("when parsing name %s"),
477                     opts->principal_name);
478             goto cleanup;
479         }
480     } else if (opts->anonymous) {
481         /* Use the anonymous principal for the local realm. */
482         ret = krb5_get_default_realm(k5->ctx, &defrealm);
483         if (ret) {
484             com_err(progname, ret, _("while getting default realm"));
485             goto cleanup;
486         }
487         ret = krb5_build_principal_ext(k5->ctx, &k5->me,
488                                        strlen(defrealm), defrealm,
489                                        strlen(KRB5_WELLKNOWN_NAMESTR),
490                                        KRB5_WELLKNOWN_NAMESTR,
491                                        strlen(KRB5_ANONYMOUS_PRINCSTR),
492                                        KRB5_ANONYMOUS_PRINCSTR, 0);
493         krb5_free_default_realm(k5->ctx, defrealm);
494         if (ret) {
495             com_err(progname, ret, _("while building principal"));
496             goto cleanup;
497         }
498     } else if (opts->action == INIT_KT && opts->use_client_keytab) {
499         /* Use the first entry from the client keytab. */
500         ret = krb5_kt_client_default(k5->ctx, &keytab);
501         if (ret) {
502             com_err(progname, ret,
503                     _("When resolving the default client keytab"));
504             goto cleanup;
505         }
506         ret = k5_kt_get_principal(k5->ctx, keytab, &k5->me);
507         krb5_kt_close(k5->ctx, keytab);
508         if (ret) {
509             com_err(progname, ret,
510                     _("When determining client principal name from keytab"));
511             goto cleanup;
512         }
513     } else if (opts->action == INIT_KT) {
514         /* Use the default host/service name. */
515         ret = krb5_sname_to_principal(k5->ctx, NULL, NULL, KRB5_NT_SRV_HST,
516                                       &k5->me);
517         if (ret) {
518             com_err(progname, ret,
519                     _("when creating default server principal name"));
520             goto cleanup;
521         }
522         if (k5->me->realm.data[0] == 0) {
523             ret = krb5_unparse_name(k5->ctx, k5->me, &k5->name);
524             if (ret == 0) {
525                 com_err(progname, KRB5_ERR_HOST_REALM_UNKNOWN,
526                         _("(principal %s)"), k5->name);
527             } else {
528                 com_err(progname, KRB5_ERR_HOST_REALM_UNKNOWN,
529                         _("for local services"));
530             }
531             goto cleanup;
532         }
533     } else if (k5->out_cc != NULL) {
534         /* If the output ccache is initialized, use its principal. */
535         if (krb5_cc_get_principal(k5->ctx, k5->out_cc, &princ) == 0)
536             k5->me = princ;
537     } else if (defcache_princ != NULL) {
538         /* Use the default cache's principal, and use the default cache as the
539          * output cache. */
540         k5->out_cc = defcache;
541         defcache = NULL;
542         k5->me = defcache_princ;
543         defcache_princ = NULL;
544     }
545
546     /* If we still haven't chosen, use the local username. */
547     if (k5->me == NULL) {
548         name = get_name_from_os();
549         if (name == NULL) {
550             fprintf(stderr, _("Unable to identify user\n"));
551             goto cleanup;
552         }
553         ret = krb5_parse_name_flags(k5->ctx, name, flags, &k5->me);
554         if (ret) {
555             com_err(progname, ret, _("when parsing name %s"), name);
556             goto cleanup;
557         }
558     }
559
560     if (k5->out_cc == NULL && krb5_cc_support_switch(k5->ctx, deftype)) {
561         /* Use an existing cache for the client principal if we can. */
562         ret = krb5_cc_cache_match(k5->ctx, k5->me, &k5->out_cc);
563         if (ret && ret != KRB5_CC_NOTFOUND) {
564             com_err(progname, ret, _("while searching for ccache for %s"),
565                     opts->principal_name);
566             goto cleanup;
567         }
568         if (!ret) {
569             if (opts->verbose) {
570                 fprintf(stderr, _("Using existing cache: %s\n"),
571                         krb5_cc_get_name(k5->ctx, k5->out_cc));
572             }
573             k5->switch_to_cache = 1;
574         } else if (defcache_princ != NULL) {
575             /* Create a new cache to avoid overwriting the initialized default
576              * cache. */
577             ret = krb5_cc_new_unique(k5->ctx, deftype, NULL, &k5->out_cc);
578             if (ret) {
579                 com_err(progname, ret, _("while generating new ccache"));
580                 goto cleanup;
581             }
582             if (opts->verbose) {
583                 fprintf(stderr, _("Using new cache: %s\n"),
584                         krb5_cc_get_name(k5->ctx, k5->out_cc));
585             }
586             k5->switch_to_cache = 1;
587         }
588     }
589
590     /* Use the default cache if we haven't picked one yet. */
591     if (k5->out_cc == NULL) {
592         k5->out_cc = defcache;
593         defcache = NULL;
594         if (opts->verbose) {
595             fprintf(stderr, _("Using default cache: %s\n"),
596                     krb5_cc_get_name(k5->ctx, k5->out_cc));
597         }
598     }
599
600     if (opts->k5_in_cache_name) {
601         ret = krb5_cc_resolve(k5->ctx, opts->k5_in_cache_name, &k5->in_cc);
602         if (ret) {
603             com_err(progname, ret, _("resolving ccache %s"),
604                     opts->k5_in_cache_name);
605             goto cleanup;
606         }
607         if (opts->verbose) {
608             fprintf(stderr, _("Using specified input cache: %s\n"),
609                     opts->k5_in_cache_name);
610         }
611     }
612
613     ret = krb5_unparse_name(k5->ctx, k5->me, &k5->name);
614     if (ret) {
615         com_err(progname, ret, _("when unparsing name"));
616         goto cleanup;
617     }
618     if (opts->verbose)
619         fprintf(stderr, _("Using principal: %s\n"), k5->name);
620
621     opts->principal_name = k5->name;
622
623     success = 1;
624
625 cleanup:
626     if (defcache != NULL)
627         krb5_cc_close(k5->ctx, defcache);
628     krb5_free_principal(k5->ctx, defcache_princ);
629     return success;
630 }
631
632 static void
633 k5_end(struct k5_data *k5)
634 {
635     krb5_free_unparsed_name(k5->ctx, k5->name);
636     krb5_free_principal(k5->ctx, k5->me);
637     if (k5->in_cc != NULL)
638         krb5_cc_close(k5->ctx, k5->in_cc);
639     if (k5->out_cc != NULL)
640         krb5_cc_close(k5->ctx, k5->out_cc);
641     krb5_free_context(k5->ctx);
642     errctx = NULL;
643     memset(k5, 0, sizeof(*k5));
644 }
645
646 static krb5_error_code KRB5_CALLCONV
647 kinit_prompter(krb5_context ctx, void *data, const char *name,
648                const char *banner, int num_prompts, krb5_prompt prompts[])
649 {
650     krb5_boolean *pwprompt = data;
651     krb5_prompt_type *ptypes;
652     int i;
653
654     /* Make a note if we receive a password prompt. */
655     ptypes = krb5_get_prompt_types(ctx);
656     for (i = 0; i < num_prompts; i++) {
657         if (ptypes != NULL && ptypes[i] == KRB5_PROMPT_TYPE_PASSWORD)
658             *pwprompt = TRUE;
659     }
660     return krb5_prompter_posix(ctx, data, name, banner, num_prompts, prompts);
661 }
662
663 static int
664 k5_kinit(struct k_opts *opts, struct k5_data *k5)
665 {
666     int notix = 1;
667     krb5_keytab keytab = 0;
668     krb5_creds my_creds;
669     krb5_error_code ret;
670     krb5_get_init_creds_opt *options = NULL;
671     krb5_boolean pwprompt = FALSE;
672     krb5_address **addresses = NULL;
673     int i;
674
675     memset(&my_creds, 0, sizeof(my_creds));
676
677     ret = krb5_get_init_creds_opt_alloc(k5->ctx, &options);
678     if (ret)
679         goto cleanup;
680
681     if (opts->lifetime)
682         krb5_get_init_creds_opt_set_tkt_life(options, opts->lifetime);
683     if (opts->rlife)
684         krb5_get_init_creds_opt_set_renew_life(options, opts->rlife);
685     if (opts->forwardable)
686         krb5_get_init_creds_opt_set_forwardable(options, 1);
687     if (opts->not_forwardable)
688         krb5_get_init_creds_opt_set_forwardable(options, 0);
689     if (opts->proxiable)
690         krb5_get_init_creds_opt_set_proxiable(options, 1);
691     if (opts->not_proxiable)
692         krb5_get_init_creds_opt_set_proxiable(options, 0);
693     if (opts->canonicalize)
694         krb5_get_init_creds_opt_set_canonicalize(options, 1);
695     if (opts->anonymous)
696         krb5_get_init_creds_opt_set_anonymous(options, 1);
697     if (opts->addresses) {
698         ret = krb5_os_localaddr(k5->ctx, &addresses);
699         if (ret) {
700             com_err(progname, ret, _("getting local addresses"));
701             goto cleanup;
702         }
703         krb5_get_init_creds_opt_set_address_list(options, addresses);
704     }
705     if (opts->no_addresses)
706         krb5_get_init_creds_opt_set_address_list(options, NULL);
707     if (opts->armor_ccache != NULL) {
708         krb5_get_init_creds_opt_set_fast_ccache_name(k5->ctx, options,
709                                                      opts->armor_ccache);
710     }
711     if (opts->request_pac)
712         krb5_get_init_creds_opt_set_pac_request(k5->ctx, options, TRUE);
713     if (opts->not_request_pac)
714         krb5_get_init_creds_opt_set_pac_request(k5->ctx, options, FALSE);
715
716
717     if (opts->action == INIT_KT && opts->keytab_name != NULL) {
718 #ifndef _WIN32
719         if (strncmp(opts->keytab_name, "KDB:", 4) == 0) {
720             ret = kinit_kdb_init(&k5->ctx, k5->me->realm.data);
721             errctx = k5->ctx;
722             if (ret) {
723                 com_err(progname, ret,
724                         _("while setting up KDB keytab for realm %s"),
725                         k5->me->realm.data);
726                 goto cleanup;
727             }
728         }
729 #endif
730
731         ret = krb5_kt_resolve(k5->ctx, opts->keytab_name, &keytab);
732         if (ret) {
733             com_err(progname, ret, _("resolving keytab %s"),
734                     opts->keytab_name);
735             goto cleanup;
736         }
737         if (opts->verbose)
738             fprintf(stderr, _("Using keytab: %s\n"), opts->keytab_name);
739     } else if (opts->action == INIT_KT && opts->use_client_keytab) {
740         ret = krb5_kt_client_default(k5->ctx, &keytab);
741         if (ret) {
742             com_err(progname, ret, _("resolving default client keytab"));
743             goto cleanup;
744         }
745     }
746
747     for (i = 0; i < opts->num_pa_opts; i++) {
748         ret = krb5_get_init_creds_opt_set_pa(k5->ctx, options,
749                                              opts->pa_opts[i].attr,
750                                              opts->pa_opts[i].value);
751         if (ret) {
752             com_err(progname, ret, _("while setting '%s'='%s'"),
753                     opts->pa_opts[i].attr, opts->pa_opts[i].value);
754             goto cleanup;
755         }
756         if (opts->verbose) {
757             fprintf(stderr, _("PA Option %s = %s\n"), opts->pa_opts[i].attr,
758                     opts->pa_opts[i].value);
759         }
760     }
761     if (k5->in_cc) {
762         ret = krb5_get_init_creds_opt_set_in_ccache(k5->ctx, options,
763                                                     k5->in_cc);
764         if (ret)
765             goto cleanup;
766     }
767     ret = krb5_get_init_creds_opt_set_out_ccache(k5->ctx, options, k5->out_cc);
768     if (ret)
769         goto cleanup;
770
771     switch (opts->action) {
772     case INIT_PW:
773         ret = krb5_get_init_creds_password(k5->ctx, &my_creds, k5->me, 0,
774                                            kinit_prompter, &pwprompt,
775                                            opts->starttime, opts->service_name,
776                                            options);
777         break;
778     case INIT_KT:
779         ret = krb5_get_init_creds_keytab(k5->ctx, &my_creds, k5->me, keytab,
780                                          opts->starttime, opts->service_name,
781                                          options);
782         break;
783     case VALIDATE:
784         ret = krb5_get_validated_creds(k5->ctx, &my_creds, k5->me, k5->out_cc,
785                                        opts->service_name);
786         break;
787     case RENEW:
788         ret = krb5_get_renewed_creds(k5->ctx, &my_creds, k5->me, k5->out_cc,
789                                      opts->service_name);
790         break;
791     }
792
793     if (ret) {
794         char *doing = NULL;
795         switch (opts->action) {
796         case INIT_PW:
797         case INIT_KT:
798             doing = _("getting initial credentials");
799             break;
800         case VALIDATE:
801             doing = _("validating credentials");
802             break;
803         case RENEW:
804             doing = _("renewing credentials");
805             break;
806         }
807
808         /* If reply decryption failed, or if pre-authentication failed and we
809          * were prompted for a password, assume the password was wrong. */
810         if (ret == KRB5KRB_AP_ERR_BAD_INTEGRITY ||
811             (pwprompt && ret == KRB5KDC_ERR_PREAUTH_FAILED)) {
812             fprintf(stderr, _("%s: Password incorrect while %s\n"), progname,
813                     doing);
814         } else {
815             com_err(progname, ret, _("while %s"), doing);
816         }
817         goto cleanup;
818     }
819
820     if (opts->action != INIT_PW && opts->action != INIT_KT) {
821         ret = krb5_cc_initialize(k5->ctx, k5->out_cc, opts->canonicalize ?
822                                  my_creds.client : k5->me);
823         if (ret) {
824             com_err(progname, ret, _("when initializing cache %s"),
825                     opts->k5_out_cache_name ? opts->k5_out_cache_name : "");
826             goto cleanup;
827         }
828         if (opts->verbose)
829             fprintf(stderr, _("Initialized cache\n"));
830
831         ret = krb5_cc_store_cred(k5->ctx, k5->out_cc, &my_creds);
832         if (ret) {
833             com_err(progname, ret, _("while storing credentials"));
834             goto cleanup;
835         }
836         if (opts->verbose)
837             fprintf(stderr, _("Stored credentials\n"));
838     }
839     notix = 0;
840     if (k5->switch_to_cache) {
841         ret = krb5_cc_switch(k5->ctx, k5->out_cc);
842         if (ret) {
843             com_err(progname, ret, _("while switching to new ccache"));
844             goto cleanup;
845         }
846     }
847
848 cleanup:
849 #ifndef _WIN32
850     kinit_kdb_fini();
851 #endif
852     if (options)
853         krb5_get_init_creds_opt_free(k5->ctx, options);
854     if (my_creds.client == k5->me)
855         my_creds.client = 0;
856     if (opts->pa_opts) {
857         free(opts->pa_opts);
858         opts->pa_opts = NULL;
859         opts->num_pa_opts = 0;
860     }
861     krb5_free_cred_contents(k5->ctx, &my_creds);
862     if (keytab != NULL)
863         krb5_kt_close(k5->ctx, keytab);
864     return notix ? 0 : 1;
865 }
866
867 int
868 main(int argc, char *argv[])
869 {
870     struct k_opts opts;
871     struct k5_data k5;
872     int authed_k5 = 0;
873
874     setlocale(LC_ALL, "");
875     progname = GET_PROGNAME(argv[0]);
876
877     /* Ensure we can be driven from a pipe */
878     if (!isatty(fileno(stdin)))
879         setvbuf(stdin, 0, _IONBF, 0);
880     if (!isatty(fileno(stdout)))
881         setvbuf(stdout, 0, _IONBF, 0);
882     if (!isatty(fileno(stderr)))
883         setvbuf(stderr, 0, _IONBF, 0);
884
885     memset(&opts, 0, sizeof(opts));
886     opts.action = INIT_PW;
887
888     memset(&k5, 0, sizeof(k5));
889
890     set_com_err_hook(extended_com_err_fn);
891
892     parse_options(argc, argv, &opts);
893
894     if (k5_begin(&opts, &k5))
895         authed_k5 = k5_kinit(&opts, &k5);
896
897     if (authed_k5 && opts.verbose)
898         fprintf(stderr, _("Authenticated to Kerberos v5\n"));
899
900     k5_end(&k5);
901
902     if (!authed_k5)
903         exit(1);
904     return 0;
905 }