2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
8 * clients/kinit/kinit.c
10 * Copyright 1990 by the Massachusetts Institute of Technology.
11 * All Rights Reserved.
13 * Export of this software from the United States of America may
14 * require a specific license from the United States Government.
15 * It is the responsibility of any person or organization contemplating
16 * export to obtain such a license before exporting.
18 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
19 * distribute this software and its documentation for any purpose and
20 * without fee is hereby granted, provided that the above copyright
21 * notice appear in all copies and that both that copyright notice and
22 * this permission notice appear in supporting documentation, and that
23 * the name of M.I.T. not be used in advertising or publicity pertaining
24 * to distribution of the software without specific, written prior
25 * permission. Furthermore if you modify this software you must label
26 * your software as modified software and not distribute it in such a
27 * fashion that it might be confused with the original M.I.T. software.
28 * M.I.T. makes no representations about the suitability of
29 * this software for any purpose. It is provided "as is" without express
30 * or implied warranty.
33 * Initialize a credentials cache.
36 #include <profile/prof_int.h>
41 #ifdef KRB5_KRB4_COMPAT
42 #include <kerberosIV/krb.h>
61 /* SunOS4 unistd didn't declare these; okay to make unconditional? */
69 #endif /* HAVE_UNISTD_H */
70 #endif /* GETOPT_LONG */
73 #define GET_PROGNAME(x) (strrchr((x), '/') ? strrchr((x), '/')+1 : (x))
75 #define GET_PROGNAME(x) max(max(strrchr((x), '/'), strrchr((x), '\\')) + 1,(x))
81 char * get_name_from_os()
84 if ((pw
= getpwuid((int) getuid())))
88 #else /* HAVE_PWD_H */
91 char * get_name_from_os()
93 static char name
[1024];
94 DWORD name_size
= sizeof(name
);
95 if (GetUserName(name
, &name_size
)) {
96 name
[sizeof(name
)-1] = 0; /* Just to be extra safe */
104 char * get_name_from_os()
109 #endif /* HAVE_PWD_H */
111 static char* progname_v5
= 0;
112 #ifdef KRB5_KRB4_COMPAT
113 static char* progname_v4
= 0;
114 static char* progname_v524
= 0;
118 static int got_k5
= 0;
119 static int got_k4
= 0;
121 static int default_k5
= 1;
122 #if defined(KRB5_KRB4_COMPAT) && defined(KINIT_DEFAULT_BOTH)
123 static int default_k4
= 1;
125 static int default_k4
= 0;
128 static int authed_k5
= 0;
129 static int authed_k4
= 0;
131 #define KRB4_BACKUP_DEFAULT_LIFE_SECS 24*60*60 /* 1 day */
132 #define ROOT_UNAME "root"
134 typedef enum { INIT_PW
, INIT_KT
, RENEW
, VALIDATE
} action_type
;
139 krb5_deltat starttime
;
140 krb5_deltat lifetime
;
153 char* principal_name
;
162 krb5_gic_opt_pa_data
*pa_opts
;
165 int forwardable_flag
= 0;
166 int renewable_flag
= 0;
167 int proxiable_flag
= 0;
168 int no_address_flag
= 0;
169 profile_options_boolean config_option
[] = {
170 { "forwardable", &forwardable_flag
, 0 },
171 { "renewable", &renewable_flag
, 0 },
172 { "proxiable", &proxiable_flag
, 0 },
173 { "no_addresses", &no_address_flag
, 0 },
177 char *renew_timeval
=NULL
;
178 char *life_timeval
=NULL
;
179 int lifetime_specified
;
180 int renewtime_specified
;
181 profile_option_strings config_times
[] = {
182 { "max_life", &life_timeval
, 0 },
183 { "max_renewable_life", &renew_timeval
, 0 },
197 krb5_deltat lifetime
;
198 #ifdef KRB5_KRB4_COMPAT
199 char aname
[ANAME_SZ
+ 1];
200 char inst
[INST_SZ
+ 1];
201 char realm
[REALM_SZ
+ 1];
202 char name
[ANAME_SZ
+ 1 + INST_SZ
+ 1 + REALM_SZ
+ 1];
206 char *realmdef
[] = { "realms", NULL
, "kinit", NULL
};
207 char *appdef
[] = { "appdefaults", "kinit", NULL
};
209 #define krb_realm (*(realmdef + 1))
211 #define lifetime_specified config_times[0].found
212 #define renewtime_specified config_times[1].found
215 * Try no preauthentication first; then try the encrypted timestamp
217 krb5_preauthtype
* preauth
= NULL
;
218 krb5_preauthtype preauth_list
[2] = { 0, -1 };
220 static void _kwarnd_add_warning(char *, char *, time_t);
221 static void _kwarnd_del_warning(char *, char *);
224 /* if struct[2] == NULL, then long_getopt acts as if the short flag
225 struct[3] was specified. If struct[2] != NULL, then struct[3] is
226 stored in *(struct[2]), the array index which was specified is
227 stored in *index, and long_getopt() returns 0. */
229 struct option long_options
[] = {
230 { "noforwardable", 0, NULL
, 'F' },
231 { "noproxiable", 0, NULL
, 'P' },
232 { "addresses", 0, NULL
, 'a'},
233 { "forwardable", 0, NULL
, 'f' },
234 { "proxiable", 0, NULL
, 'p' },
235 { "noaddresses", 0, NULL
, 'A' },
239 #define GETOPT(argc, argv, str) getopt_long(argc, argv, str, long_options, 0)
241 #define GETOPT(argc, argv, str) getopt(argc, argv, str)
248 #define USAGE_BREAK "\n\t"
251 #define USAGE_LONG_FORWARDABLE " | --forwardable | --noforwardable"
252 #define USAGE_LONG_PROXIABLE " | --proxiable | --noproxiable"
253 #define USAGE_LONG_ADDRESSES " | --addresses | --noaddresses"
254 #define USAGE_BREAK_LONG USAGE_BREAK
256 #define USAGE_LONG_FORWARDABLE ""
257 #define USAGE_LONG_PROXIABLE ""
258 #define USAGE_LONG_ADDRESSES ""
259 #define USAGE_BREAK_LONG ""
262 fprintf(stderr
, "%s : %s [-V] "
263 "[-l lifetime] [-s start_time] "
265 "[-r renewable_life] "
266 "[-f | -F" USAGE_LONG_FORWARDABLE
"] "
268 "[-p | -P" USAGE_LONG_PROXIABLE
"] "
270 "[-a | -A" USAGE_LONG_ADDRESSES
"] "
273 "[-k [-t keytab_file]] "
277 "[-X <attribute>[=<value>]] [principal]"
279 gettext("Usage"), progname
);
281 #define KRB_AVAIL_STRING(x) ((x)?gettext("available"):gettext("not available"))
283 #define OPTTYPE_KRB5 "5"
284 #define OPTTYPE_KRB4 "4"
285 #define OPTTYPE_EITHER "Either 4 or 5"
287 #define OPTTYPE_BOTH "5, or both 5 and 4"
289 #define OPTTYPE_BOTH "5"
292 #ifdef KRB5_KRB4_COMPAT
293 #define USAGE_OPT_FMT "%s%-50s%s\n"
294 #define ULINE(indent, col1, col2) \
295 fprintf(stderr, USAGE_OPT_FMT, indent, col1, col2)
297 #define USAGE_OPT_FMT "%s%s\n"
298 #define ULINE(indent, col1, col2) \
299 fprintf(stderr, USAGE_OPT_FMT, indent, col1)
302 ULINE(" ", "options:", "valid with Kerberos:");
303 fprintf(stderr
, "\t-5 Kerberos 5 (%s)\n", KRB_AVAIL_STRING(got_k5
));
304 fprintf(stderr
, "\t-4 Kerberos 4 (%s)\n", KRB_AVAIL_STRING(got_k4
));
305 fprintf(stderr
, "\t (Default behavior is to try %s%s%s%s)\n",
306 default_k5
?"Kerberos 5":"",
307 (default_k5
&& default_k4
)?gettext(" and "):"",
308 default_k4
?"Kerberos 4":"",
309 (!default_k5
&& !default_k4
)?gettext("neither"):"");
310 ULINE("\t", gettext("-V verbose"), OPTTYPE_EITHER
);
311 ULINE("\t", gettext("-l lifetime"), OPTTYPE_EITHER
);
312 ULINE("\t", gettext("-s start time"), OPTTYPE_KRB5
);
313 ULINE("\t", gettext("-r renewable lifetime"), OPTTYPE_KRB5
);
314 ULINE("\t", gettext("-f forwardable"), OPTTYPE_KRB5
);
315 ULINE("\t", gettext("-F not forwardable"), OPTTYPE_KRB5
);
316 ULINE("\t", gettext("-p proxiable"), OPTTYPE_KRB5
);
317 ULINE("\t", gettext("-P not proxiable"), OPTTYPE_KRB5
);
318 ULINE("\t", gettext("-A do not include addresses"), OPTTYPE_KRB5
);
319 ULINE("\t", gettext("-a include addresses"), OPTTYPE_KRB5
);
320 ULINE("\t", gettext("-v validate"), OPTTYPE_KRB5
);
321 ULINE("\t", gettext("-R renew"), OPTTYPE_BOTH
);
322 ULINE("\t", gettext("-k use keytab"), OPTTYPE_BOTH
);
323 ULINE("\t", gettext("-t filename of keytab to use"), OPTTYPE_BOTH
);
324 ULINE("\t", gettext("-c Kerberos 5 cache name"), OPTTYPE_KRB5
);
325 /* This options is not yet available: */
326 /* ULINE("\t", "-C Kerberos 4 cache name", OPTTYPE_KRB4); */
327 ULINE("\t", gettext("-S service"), OPTTYPE_BOTH
);
328 ULINE("\t", gettext("-X <attribute>[=<value>]"), OPTTYPE_KRB5
);
332 static krb5_context errctx
;
333 static void extended_com_err_fn (const char *myprog
, errcode_t code
,
334 const char *fmt
, va_list args
)
337 emsg
= krb5_get_error_message (errctx
, code
);
338 fprintf (stderr
, "%s: %s ", myprog
, emsg
);
339 krb5_free_error_message (errctx
, emsg
);
340 vfprintf (stderr
, fmt
, args
);
341 fprintf (stderr
, "\n");
345 add_preauth_opt(struct k_opts
*opts
, char *av
)
348 krb5_gic_opt_pa_data
*p
, *x
;
350 if (opts
->num_pa_opts
== 0) {
351 opts
->pa_opts
= malloc(sizeof(krb5_gic_opt_pa_data
));
352 if (opts
->pa_opts
== NULL
)
355 size_t newsize
= (opts
->num_pa_opts
+ 1) * sizeof(krb5_gic_opt_pa_data
);
356 x
= realloc(opts
->pa_opts
, newsize
);
361 p
= &opts
->pa_opts
[opts
->num_pa_opts
];
362 sep
= strchr(av
, '=');
376 parse_options(argc
, argv
, opts
, progname
)
382 krb5_error_code code
;
388 while ((i
= GETOPT(argc
, argv
, "r:fpFP54aAVl:s:c:kt:RS:vX:"))
396 code
= krb5_string_to_deltat(optarg
, &opts
->lifetime
);
397 if (code
!= 0 || opts
->lifetime
== 0) {
398 fprintf(stderr
, gettext("Bad lifetime value %s\n"), optarg
);
404 code
= krb5_string_to_deltat(optarg
, &opts
->rlife
);
405 if (code
!= 0 || opts
->rlife
== 0) {
406 fprintf(stderr
, gettext("Bad lifetime value %s\n"), optarg
);
411 opts
->forwardable
= 1;
414 opts
->not_forwardable
= 1;
420 opts
->not_proxiable
= 1;
423 /* Note: This is supported only with GETOPT_LONG */
427 opts
->no_addresses
= 1;
430 code
= krb5_string_to_deltat(optarg
, &opts
->starttime
);
431 if (code
!= 0 || opts
->starttime
== 0) {
432 krb5_timestamp abs_starttime
;
434 code
= krb5_string_to_timestamp(optarg
, &abs_starttime
);
435 if (code
!= 0 || abs_starttime
== 0) {
436 fprintf(stderr
, gettext("Bad start time value %s\n"), optarg
);
439 opts
->starttime
= abs_starttime
- time(0);
444 opts
->service_name
= optarg
;
447 opts
->action
= INIT_KT
;
450 if (opts
->keytab_name
)
452 fprintf(stderr
, gettext("Only one -t option allowed.\n"));
455 opts
->keytab_name
= optarg
;
459 opts
->action
= RENEW
;
462 opts
->action
= VALIDATE
;
465 if (opts
->k5_cache_name
)
467 fprintf(stderr
, gettext("Only one -c option allowed\n"));
470 opts
->k5_cache_name
= optarg
;
474 code
= add_preauth_opt(opts
, optarg
);
477 com_err(progname
, code
, "while adding preauth option");
483 A little more work is needed before we can enable this
487 if (opts
->k4_cache_name
)
489 fprintf(stderr
, "Only one -C option allowed\n");
492 opts
->k4_cache_name
= optarg
;
499 #ifdef KRB5_KRB4_COMPAT
500 fprintf(stderr
, "Kerberos 4 support could not be loaded\n");
502 fprintf(stderr
, gettext("This was not built with Kerberos 4 support\n"));
511 fprintf(stderr
, gettext("Kerberos 5 support could not be loaded\n"));
522 if (opts
->forwardable
&& opts
->not_forwardable
)
524 fprintf(stderr
, gettext("Only one of -f and -F allowed\n"));
527 if (opts
->proxiable
&& opts
->not_proxiable
)
529 fprintf(stderr
, gettext("Only one of -p and -P allowed\n"));
532 if (opts
->addresses
&& opts
->no_addresses
)
534 fprintf(stderr
, gettext("Only one of -a and -A allowed\n"));
538 if (argc
- optind
> 1) {
539 fprintf(stderr
, gettext("Extra arguments (starting with \"%s\").\n"),
544 /* At this point, if errorless, we know we only have one option
546 if (!use_k5
&& !use_k4
) {
551 /* Now, we encode the OPTTYPE stuff here... */
553 (opts
->starttime
|| opts
->rlife
|| opts
->forwardable
||
554 opts
->proxiable
|| opts
->addresses
|| opts
->not_forwardable
||
555 opts
->not_proxiable
|| opts
->no_addresses
||
556 (opts
->action
== VALIDATE
) || opts
->k5_cache_name
))
558 fprintf(stderr
, gettext("Specified option that requires Kerberos 5\n"));
564 fprintf(stderr
, gettext("Specified option that require Kerberos 4\n"));
573 && (opts
->service_name
|| opts
->keytab_name
||
574 (opts
->action
== INIT_KT
) || (opts
->action
== RENEW
))
577 fprintf(stderr
, gettext("Specified option that requires Kerberos 5\n"));
585 got_k5
= got_k5
&& use_k5
;
586 got_k4
= got_k4
&& use_k4
;
588 opts
->principal_name
= (optind
== argc
-1) ? argv
[optind
] : 0;
589 return opts
->principal_name
;
593 k5_begin(opts
, k5
, k4
)
598 char* progname
= progname_v5
;
599 krb5_error_code code
= 0;
604 code
= krb5_init_context(&k5
->ctx
);
606 com_err(progname
, code
, gettext("while initializing Kerberos 5 library"));
610 if (opts
->k5_cache_name
)
612 code
= krb5_cc_resolve(k5
->ctx
, opts
->k5_cache_name
, &k5
->cc
);
614 com_err(progname
, code
, gettext("resolving ccache %s"),
615 opts
->k5_cache_name
);
621 if ((code
= krb5_cc_default(k5
->ctx
, &k5
->cc
))) {
622 com_err(progname
, code
, gettext("while getting default ccache"));
627 if (opts
->principal_name
)
629 /* Use specified name */
630 if ((code
= krb5_parse_name(k5
->ctx
, opts
->principal_name
,
632 com_err(progname
, code
, gettext("when parsing name %s"),
633 opts
->principal_name
);
639 /* No principal name specified */
640 if (opts
->action
== INIT_KT
) {
641 /* Use the default host/service name */
642 code
= krb5_sname_to_principal(k5
->ctx
, NULL
, NULL
,
643 KRB5_NT_SRV_HST
, &k5
->me
);
645 com_err(progname
, code
, gettext(
646 "when creating default server principal name"));
650 /* Get default principal from cache if one exists */
651 code
= krb5_cc_get_principal(k5
->ctx
, k5
->cc
,
655 char *name
= get_name_from_os();
658 fprintf(stderr
, gettext("Unable to identify user\n"));
661 /* use strcmp to ensure only "root" is matched */
662 if (strcmp(name
, ROOT_UNAME
) == 0)
664 if (code
= krb5_sname_to_principal(k5
->ctx
, NULL
, ROOT_UNAME
,
665 KRB5_NT_SRV_HST
, &k5
->me
)) {
666 com_err(progname
, code
, gettext(
667 "when creating default server principal name"));
671 if ((code
= krb5_parse_name(k5
->ctx
, name
,
674 com_err(progname
, code
, gettext("when parsing name %s"),
682 code
= krb5_unparse_name(k5
->ctx
, k5
->me
, &k5
->name
);
684 com_err(progname
, code
, gettext("when unparsing name"));
687 opts
->principal_name
= k5
->name
;
689 #ifdef KRB5_KRB4_COMPAT
692 /* Translate to a Kerberos 4 principal */
693 code
= krb5_524_conv_principal(k5
->ctx
, k5
->me
,
694 k4
->aname
, k4
->inst
, k4
->realm
);
710 krb5_free_unparsed_name(k5
->ctx
, k5
->name
);
712 krb5_free_principal(k5
->ctx
, k5
->me
);
714 krb5_cc_close(k5
->ctx
, k5
->cc
);
716 krb5_free_context(k5
->ctx
);
718 memset(k5
, 0, sizeof(*k5
));
726 #ifdef KRB5_KRB4_COMPAT
727 char* progname
= progname_v4
;
734 #ifdef KRB5_KRB4_COMPAT
738 if (opts
->principal_name
)
740 /* Use specified name */
741 k_errno
= kname_parse(k4
->aname
, k4
->inst
, k4
->realm
,
742 opts
->principal_name
);
745 fprintf(stderr
, "%s: %s\n", progname
,
746 krb_get_err_text(k_errno
));
750 /* No principal name specified */
751 if (opts
->action
== INIT_KT
) {
752 /* Use the default host/service name */
753 /* XXX - need to add this functionality */
754 fprintf(stderr
, "%s: Kerberos 4 srvtab support is not "
755 "implemented\n", progname
);
758 /* Get default principal from cache if one exists */
759 k_errno
= krb_get_tf_fullname(tkt_string(), k4
->aname
,
760 k4
->inst
, k4
->realm
);
763 char *name
= get_name_from_os();
766 fprintf(stderr
, "Unable to identify user\n");
769 k_errno
= kname_parse(k4
->aname
, k4
->inst
, k4
->realm
,
773 fprintf(stderr
, "%s: %s\n", progname
,
774 krb_get_err_text(k_errno
));
782 krb_get_lrealm(k4
->realm
, 1);
785 sprintf(k4
->name
, "%s.%s@%s", k4
->aname
, k4
->inst
, k4
->realm
);
787 sprintf(k4
->name
, "%s@%s", k4
->aname
, k4
->realm
);
788 opts
->principal_name
= k4
->name
;
791 if (k4
->aname
[0] && !k_isname(k4
->aname
))
793 fprintf(stderr
, "%s: bad Kerberos 4 name format\n", progname
);
797 if (k4
->inst
[0] && !k_isinst(k4
->inst
))
799 fprintf(stderr
, "%s: bad Kerberos 4 instance format\n", progname
);
803 if (k4
->realm
[0] && !k_isrealm(k4
->realm
))
805 fprintf(stderr
, "%s: bad Kerberos 4 realm format\n", progname
);
808 #endif /* KRB5_KRB4_COMPAT */
816 memset(k4
, 0, sizeof(*k4
));
819 #ifdef KRB5_KRB4_COMPAT
820 static char stash_password
[1024];
821 static int got_password
= 0;
822 #endif /* KRB5_KRB4_COMPAT */
824 static krb5_error_code
832 krb5_prompt prompts
[]
836 krb5_prompt_type
*types
;
838 krb5_prompter_posix(ctx
, data
, name
, banner
, num_prompts
, prompts
);
839 if (!rc
&& (types
= krb5_get_prompt_types(ctx
)))
840 for (i
= 0; i
< num_prompts
; i
++)
841 if ((types
[i
] == KRB5_PROMPT_TYPE_PASSWORD
) ||
842 (types
[i
] == KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN
))
844 #ifdef KRB5_KRB4_COMPAT
845 strncpy(stash_password
, prompts
[i
].reply
->data
,
846 sizeof(stash_password
));
858 char* progname
= progname_v5
;
860 krb5_keytab keytab
= 0;
862 krb5_error_code code
= 0;
863 krb5_get_init_creds_opt
*options
= NULL
;
866 krb5_deltat lifetime
= 0, rlife
= 0, krb5_max_duration
;
871 code
= krb5_get_init_creds_opt_alloc(k5
->ctx
, &options
);
874 memset(&my_creds
, 0, sizeof(my_creds
));
877 * Solaris Kerberos: added support for max_life and max_renewable_life
878 * which should be removed in the next minor release. See PSARC 2003/545
881 * Also, check krb5.conf for proxiable/forwardable/renewable/no_address
884 /* If either tkt life or renew life weren't set earlier take common steps to
885 * get the krb5.conf parameter values.
888 if ((code
= krb5_timeofday(k5
->ctx
, &now
))) {
889 com_err(progname
, code
, gettext("while getting time of day"));
892 krb5_max_duration
= KRB5_KDB_EXPIRATION
- now
- 60*60;
894 if (opts
->lifetime
== 0 || opts
->rlife
== 0) {
896 krb_realm
= krb5_princ_realm(k5
->ctx
, k5
->me
)->data
;
897 /* realm params take precedence */
898 profile_get_options_string(k5
->ctx
->profile
, realmdef
, config_times
);
899 profile_get_options_string(k5
->ctx
->profile
, appdef
, config_times
);
901 /* if the input opts doesn't have lifetime set and the krb5.conf
902 * parameter has been set, use that.
904 if (opts
->lifetime
== 0 && life_timeval
!= NULL
) {
905 code
= krb5_string_to_deltat(life_timeval
, &lifetime
);
906 if (code
!= 0 || lifetime
== 0 || lifetime
> krb5_max_duration
) {
907 fprintf(stderr
, gettext("Bad max_life "
908 "value in Kerberos config file %s\n"),
912 opts
->lifetime
= lifetime
;
914 if (opts
->rlife
== 0 && renew_timeval
!= NULL
) {
915 code
= krb5_string_to_deltat(renew_timeval
, &rlife
);
916 if (code
!= 0 || rlife
== 0 || rlife
> krb5_max_duration
) {
917 fprintf(stderr
, gettext("Bad max_renewable_life "
918 "value in Kerberos config file %s\n"),
927 * If lifetime is not set on the cmdline or in the krb5.conf
928 * file, default to max.
930 if (opts
->lifetime
== 0)
931 opts
->lifetime
= krb5_max_duration
;
934 profile_get_options_boolean(k5
->ctx
->profile
,
935 realmdef
, config_option
);
936 profile_get_options_boolean(k5
->ctx
->profile
,
937 appdef
, config_option
);
940 /* cmdline opts take precedence over krb5.conf file values */
941 if (!opts
->not_proxiable
&& proxiable_flag
) {
942 krb5_get_init_creds_opt_set_proxiable(options
, 1);
944 if (!opts
->not_forwardable
&& forwardable_flag
) {
945 krb5_get_init_creds_opt_set_forwardable(options
, 1);
947 if (renewable_flag
) {
949 * If this flag is set in krb5.conf, but rlife is 0, then
950 * set it to the max (and let the KDC sort it out).
952 opts
->rlife
= opts
->rlife
? opts
->rlife
: krb5_max_duration
;
954 if (no_address_flag
) {
955 /* cmdline opts will overwrite this below if needbe */
956 krb5_get_init_creds_opt_set_address_list(options
, NULL
);
961 From this point on, we can goto cleanup because my_creds is
966 krb5_get_init_creds_opt_set_tkt_life(options
, opts
->lifetime
);
968 krb5_get_init_creds_opt_set_renew_life(options
, opts
->rlife
);
969 if (opts
->forwardable
)
970 krb5_get_init_creds_opt_set_forwardable(options
, 1);
971 if (opts
->not_forwardable
)
972 krb5_get_init_creds_opt_set_forwardable(options
, 0);
974 krb5_get_init_creds_opt_set_proxiable(options
, 1);
975 if (opts
->not_proxiable
)
976 krb5_get_init_creds_opt_set_proxiable(options
, 0);
979 krb5_address
**addresses
= NULL
;
980 code
= krb5_os_localaddr(k5
->ctx
, &addresses
);
982 com_err(progname
, code
, gettext("getting local addresses"));
985 krb5_get_init_creds_opt_set_address_list(options
, addresses
);
987 if (opts
->no_addresses
)
988 krb5_get_init_creds_opt_set_address_list(options
, NULL
);
990 if ((opts
->action
== INIT_KT
) && opts
->keytab_name
)
992 code
= krb5_kt_resolve(k5
->ctx
, opts
->keytab_name
, &keytab
);
994 com_err(progname
, code
, gettext("resolving keytab %s"),
1000 for (i
= 0; i
< opts
->num_pa_opts
; i
++) {
1001 code
= krb5_get_init_creds_opt_set_pa(k5
->ctx
, options
,
1002 opts
->pa_opts
[i
].attr
,
1003 opts
->pa_opts
[i
].value
);
1005 com_err(progname
, code
, "while setting '%s'='%s'",
1006 opts
->pa_opts
[i
].attr
, opts
->pa_opts
[i
].value
);
1011 switch (opts
->action
) {
1013 code
= krb5_get_init_creds_password(k5
->ctx
, &my_creds
, k5
->me
,
1014 0, kinit_prompter
, 0,
1020 code
= krb5_get_init_creds_keytab(k5
->ctx
, &my_creds
, k5
->me
,
1027 code
= krb5_get_validated_creds(k5
->ctx
, &my_creds
, k5
->me
, k5
->cc
,
1028 opts
->service_name
);
1031 code
= krb5_get_renewed_creds(k5
->ctx
, &my_creds
, k5
->me
, k5
->cc
,
1032 opts
->service_name
);
1038 switch (opts
->action
) {
1041 doing
= gettext("getting initial credentials");
1044 doing
= gettext("validating credentials");
1047 doing
= gettext("renewing credentials");
1051 /* If got code == KRB5_AP_ERR_V4_REPLY && got_k4, we should
1052 let the user know that maybe he/she wants -4. */
1053 if (code
== KRB5KRB_AP_ERR_V4_REPLY
&& got_k4
)
1054 com_err(progname
, code
, "while %s\n"
1055 "The KDC doesn't support v5. "
1056 "You may want the -4 option in the future",
1058 else if (code
== KRB5KRB_AP_ERR_BAD_INTEGRITY
)
1059 fprintf(stderr
, gettext("%s: Password incorrect while %s\n"), progname
,
1062 com_err(progname
, code
, gettext("while %s"), doing
);
1066 if (!opts
->lifetime
) {
1067 /* We need to figure out what lifetime to use for Kerberos 4. */
1068 opts
->lifetime
= my_creds
.times
.endtime
- my_creds
.times
.authtime
;
1071 code
= krb5_cc_initialize(k5
->ctx
, k5
->cc
, k5
->me
);
1073 com_err(progname
, code
, gettext("when initializing cache %s"),
1074 opts
->k5_cache_name
?opts
->k5_cache_name
:"");
1078 code
= krb5_cc_store_cred(k5
->ctx
, k5
->cc
, &my_creds
);
1080 com_err(progname
, code
, gettext("while storing credentials"));
1084 if (opts
->action
== RENEW
) {
1085 _kwarnd_del_warning(progname
, opts
->principal_name
);
1086 _kwarnd_add_warning(progname
, opts
->principal_name
, my_creds
.times
.endtime
);
1087 } else if ((opts
->action
== INIT_KT
) || (opts
->action
== INIT_PW
)) {
1088 _kwarnd_add_warning(progname
, opts
->principal_name
, my_creds
.times
.endtime
);
1095 krb5_get_init_creds_opt_free(k5
->ctx
, options
);
1096 if (my_creds
.client
== k5
->me
) {
1097 my_creds
.client
= 0;
1099 if (opts
->pa_opts
) {
1100 free(opts
->pa_opts
);
1101 opts
->pa_opts
= NULL
;
1102 opts
->num_pa_opts
= 0;
1104 krb5_free_cred_contents(k5
->ctx
, &my_creds
);
1106 krb5_kt_close(k5
->ctx
, keytab
);
1111 k4_kinit(opts
, k4
, ctx
)
1112 struct k_opts
* opts
;
1116 #ifdef KRB5_KRB4_COMPAT
1117 char* progname
= progname_v4
;
1124 if (opts
->starttime
)
1127 #ifdef KRB5_KRB4_COMPAT
1129 k4
->lifetime
= opts
->lifetime
;
1131 k4
->lifetime
= KRB4_BACKUP_DEFAULT_LIFE_SECS
;
1133 k4
->lifetime
= krb_time_to_life(0, k4
->lifetime
);
1135 switch (opts
->action
)
1138 if (!got_password
) {
1139 unsigned int pwsize
= sizeof(stash_password
);
1140 krb5_error_code code
;
1143 sprintf(prompt
, gettext("Password for %s: "), opts
->principal_name
);
1144 stash_password
[0] = 0;
1146 Note: krb5_read_password does not actually look at the
1147 context, so we're ok even if we don't have a context. If
1148 we cannot dynamically load krb5, we can substitute any
1149 decent read password function instead of the krb5 one.
1151 code
= krb5_read_password(ctx
, prompt
, 0, stash_password
, &pwsize
);
1152 if (code
|| pwsize
== 0)
1154 fprintf(stderr
, gettext("Error while reading password for '%s'\n"),
1155 opts
->principal_name
);
1156 memset(stash_password
, 0, sizeof(stash_password
));
1161 k_errno
= krb_get_pw_in_tkt(k4
->aname
, k4
->inst
, k4
->realm
, "krbtgt",
1162 k4
->realm
, k4
->lifetime
, stash_password
);
1165 fprintf(stderr
, "%s: %s\n", progname
,
1166 krb_get_err_text(k_errno
));
1168 fprintf(stderr
, gettext("Maybe your KDC does not support v4. "
1169 "Try the -5 option next time.\n"));
1175 fprintf(stderr
, gettext("%s: srvtabs are not supported\n"), progname
);
1178 fprintf(stderr
, gettext("%s: renewal of krb4 tickets is not supported\n"),
1182 /* These cases are handled by the 524 code - this prevents the compiler
1183 warnings of not using all the enumerated types.
1196 getvprogname(v
, progname
)
1199 unsigned int len
= strlen(progname
) + 2 + strlen(v
) + 2;
1200 char *ret
= malloc(len
);
1202 sprintf(ret
, "%s(v%s)", progname
, v
);
1209 /* Convert krb5 tickets to krb4. */
1210 static int try_convert524(k5
)
1213 char * progname
= progname_v524
;
1214 krb5_error_code code
= 0;
1216 krb5_principal kpcserver
= 0;
1217 krb5_creds
*v5creds
= 0;
1219 CREDENTIALS v4creds
;
1221 if (!got_k4
|| !got_k5
)
1224 memset((char *) &increds
, 0, sizeof(increds
));
1226 From this point on, we can goto cleanup because increds is
1230 if ((code
= krb5_build_principal(k5
->ctx
,
1232 krb5_princ_realm(k5
->ctx
, k5
->me
)->length
,
1233 krb5_princ_realm(k5
->ctx
, k5
->me
)->data
,
1235 krb5_princ_realm(k5
->ctx
, k5
->me
)->data
,
1237 com_err(progname
, code
, gettext(
1238 "while creating service principal name"));
1242 increds
.client
= k5
->me
;
1243 increds
.server
= kpcserver
;
1244 /* Prevent duplicate free calls. */
1247 increds
.times
.endtime
= 0;
1248 increds
.keyblock
.enctype
= ENCTYPE_DES_CBC_CRC
;
1249 if ((code
= krb5_get_credentials(k5
->ctx
, 0,
1253 com_err(progname
, code
,
1254 gettext("getting V5 credentials"));
1257 if ((icode
= krb524_convert_creds_kdc(k5
->ctx
,
1260 com_err(progname
, icode
,
1261 gettext("converting to V4 credentials"));
1264 /* this is stolen from the v4 kinit */
1265 /* initialize ticket cache */
1266 if ((icode
= in_tkt(v4creds
.pname
, v4creds
.pinst
)
1268 com_err(progname
, icode
, gettext(
1269 "trying to create the V4 ticket file"));
1272 /* stash ticket, session key, etc. for future use */
1273 if ((icode
= krb_save_credentials(v4creds
.service
,
1279 &(v4creds
.ticket_st
),
1280 v4creds
.issue_date
))) {
1281 com_err(progname
, icode
, gettext(
1282 "trying to save the V4 ticket"));
1287 memset(&v4creds
, 0, sizeof(v4creds
));
1289 krb5_free_creds(k5
->ctx
, v5creds
);
1291 krb5_free_cred_contents(k5
->ctx
, &increds
);
1293 krb5_free_principal(k5
->ctx
, kpcserver
);
1294 return !(code
|| icode
);
1296 #endif /* HAVE_KRB524 */
1308 (void) setlocale(LC_ALL
, "");
1310 #if !defined(TEXT_DOMAIN)
1311 #define TEXT_DOMAIN "SYS_TEST"
1314 (void) textdomain(TEXT_DOMAIN
);
1316 progname
= GET_PROGNAME(argv
[0]);
1317 progname_v5
= getvprogname("5", progname
);
1318 #ifdef KRB5_KRB4_COMPAT
1319 progname_v4
= getvprogname("4", progname
);
1320 progname_v524
= getvprogname("524", progname
);
1323 /* Ensure we can be driven from a pipe */
1324 if(!isatty(fileno(stdin
)))
1325 setvbuf(stdin
, 0, _IONBF
, 0);
1326 if(!isatty(fileno(stdout
)))
1327 setvbuf(stdout
, 0, _IONBF
, 0);
1328 if(!isatty(fileno(stderr
)))
1329 setvbuf(stderr
, 0, _IONBF
, 0);
1332 This is where we would put in code to dynamically load Kerberos
1333 libraries. Currenlty, we just get them implicitly.
1336 #ifdef KRB5_KRB4_COMPAT
1340 memset(&opts
, 0, sizeof(opts
));
1341 opts
.action
= INIT_PW
;
1343 memset(&k5
, 0, sizeof(k5
));
1344 memset(&k4
, 0, sizeof(k4
));
1346 set_com_err_hook (extended_com_err_fn
);
1348 parse_options(argc
, argv
, &opts
, progname
);
1350 got_k5
= k5_begin(&opts
, &k5
, &k4
);
1351 got_k4
= k4_begin(&opts
, &k4
);
1353 authed_k5
= k5_kinit(&opts
, &k5
);
1356 authed_k4
= try_convert524(&k5
);
1359 authed_k4
= k4_kinit(&opts
, &k4
, k5
.ctx
);
1360 #ifdef KRB5_KRB4_COMPAT
1361 memset(stash_password
, 0, sizeof(stash_password
));
1364 if (authed_k5
&& opts
.verbose
)
1365 fprintf(stderr
, gettext("Authenticated to Kerberos v5\n"));
1366 if (authed_k4
&& opts
.verbose
)
1367 fprintf(stderr
, gettext("Authenticated to Kerberos v4\n"));
1372 if ((got_k5
&& !authed_k5
) || (got_k4
&& !authed_k4
) ||
1373 (!got_k5
&& !got_k4
))
1379 _kwarnd_add_warning(char *progname
, char *me
, time_t endtime
)
1381 if (kwarn_add_warning(me
, endtime
) != 0)
1382 fprintf(stderr
, gettext(
1383 "%s: no ktkt_warnd warning possible\n"), progname
);
1389 _kwarnd_del_warning(char *progname
, char *me
)
1391 if (kwarn_del_warning(me
) != 0)
1392 fprintf(stderr
, gettext(
1393 "%s: unable to delete ktkt_warnd message for %s\n"),