2 * Copyright (c) 1997-2002 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include "kuser_locl.h"
35 RCSID("$Id: kinit.c,v 1.90.4.5 2004/06/21 08:17:06 lha Exp $");
37 int forwardable_flag
= -1;
38 int proxiable_flag
= -1;
39 int renewable_flag
= -1;
41 int validate_flag
= 0;
45 struct getarg_strings extra_addresses
;
46 int anonymous_flag
= 0;
47 char *lifetime
= NULL
;
48 char *renew_life
= NULL
;
50 char *cred_cache
= NULL
;
51 char *start_str
= NULL
;
52 struct getarg_strings etype_str
;
54 char *keytab_str
= NULL
;
62 static struct getargs args
[] = {
64 { "524init", '4', arg_flag
, &get_v4_tgt
,
65 "obtain version 4 TGT" },
67 { "524convert", '9', arg_flag
, &convert_524
,
68 "only convert ticket to version 4" },
70 { "afslog", 0 , arg_flag
, &do_afslog
,
71 "obtain afs tokens" },
73 { "cache", 'c', arg_string
, &cred_cache
,
74 "credentials cache", "cachename" },
76 { "forwardable", 'f', arg_flag
, &forwardable_flag
,
77 "get forwardable tickets"},
79 { "keytab", 't', arg_string
, &keytab_str
,
80 "keytab to use", "keytabname" },
82 { "lifetime", 'l', arg_string
, &lifetime
,
83 "lifetime of tickets", "time"},
85 { "proxiable", 'p', arg_flag
, &proxiable_flag
,
86 "get proxiable tickets" },
88 { "renew", 'R', arg_flag
, &renew_flag
,
91 { "renewable", 0, arg_flag
, &renewable_flag
,
92 "get renewable tickets" },
94 { "renewable-life", 'r', arg_string
, &renew_life
,
95 "renewable lifetime of tickets", "time" },
97 { "server", 'S', arg_string
, &server
,
98 "server to get ticket for", "principal" },
100 { "start-time", 's', arg_string
, &start_str
,
101 "when ticket gets valid", "time" },
103 { "use-keytab", 'k', arg_flag
, &use_keytab
,
104 "get key from keytab" },
106 { "validate", 'v', arg_flag
, &validate_flag
,
109 { "enctypes", 'e', arg_strings
, &etype_str
,
110 "encryption types to use", "enctypes" },
112 { "fcache-version", 0, arg_integer
, &fcache_version
,
113 "file cache version to create" },
115 { "addresses", 0, arg_negative_flag
, &addrs_flag
,
116 "request a ticket with no addresses" },
118 { "extra-addresses",'a', arg_strings
, &extra_addresses
,
119 "include these extra addresses", "addresses" },
121 { "anonymous", 0, arg_flag
, &anonymous_flag
,
122 "request an anonymous ticket" },
124 { "version", 0, arg_flag
, &version_flag
},
125 { "help", 0, arg_flag
, &help_flag
}
131 arg_printusage (args
,
132 sizeof(args
)/sizeof(*args
),
134 "[principal [command]]");
139 /* for when the KDC tells us it's a v4 one, we try to talk that */
142 key_to_key(const char *user
,
148 memcpy(key
, arg
, sizeof(des_cblock
));
153 do_v4_fallback (krb5_context context
,
154 const krb5_principal principal
,
156 int use_srvtab
, const char *srvtab_str
,
162 krb5_error_code kret
;
165 lifetime
= DEFAULT_TKT_LIFE
;
167 lifetime
= krb_time_to_life (0, lifetime
);
169 kret
= krb5_524_conv_principal (context
, principal
,
174 krb5_warn (context
, kret
, "krb5_524_conv_principal");
178 if (use_srvtab
|| srvtab_str
) {
179 if (srvtab_str
== NULL
)
180 srvtab_str
= KEYFILE
;
182 ret
= read_service_key (princ
.name
, princ
.instance
, princ
.realm
,
183 0, srvtab_str
, (char *)&key
);
185 warnx ("read_service_key %s: %s", srvtab_str
,
186 krb_get_err_text (ret
));
189 ret
= krb_get_in_tkt (princ
.name
, princ
.instance
, princ
.realm
,
190 KRB_TICKET_GRANTING_TICKET
, princ
.realm
,
191 lifetime
, key_to_key
, NULL
, key
);
193 ret
= krb_get_pw_in_tkt(princ
.name
, princ
.instance
, princ
.realm
,
194 KRB_TICKET_GRANTING_TICKET
, princ
.realm
,
197 memset (key
, 0, sizeof(key
));
199 warnx ("%s", krb_get_err_text(ret
));
202 if (do_afslog
&& k_hasafs()) {
203 if ((ret
= krb_afslog(NULL
, NULL
)) != 0 && ret
!= KDC_PR_UNKNOWN
) {
205 warnx ("%s", krb_get_err_text(ret
));
207 warnx ("failed to store AFS token");
215 * the special version of get_default_principal that takes v4 into account
218 static krb5_error_code
219 kinit_get_default_principal (krb5_context context
,
220 krb5_principal
*princ
)
224 krb_principal v4_princ
;
227 ret
= krb5_cc_default (context
, &id
);
229 ret
= krb5_cc_get_principal (context
, id
, princ
);
230 krb5_cc_close (context
, id
);
235 kret
= krb_get_tf_fullname (tkt_string(),
239 if (kret
== KSUCCESS
) {
240 ret
= krb5_425_conv_principal (context
,
248 return krb5_get_default_principal (context
, princ
);
253 static krb5_error_code
254 kinit_get_default_principal (krb5_context context
,
255 krb5_principal
*princ
)
257 return krb5_get_default_principal (context
, princ
);
262 static krb5_error_code
263 get_server(krb5_context context
,
264 krb5_principal client
,
266 krb5_principal
*princ
)
268 krb5_realm
*client_realm
;
270 return krb5_parse_name(context
, server
, princ
);
272 client_realm
= krb5_princ_realm (context
, client
);
273 return krb5_make_principal(context
, princ
, *client_realm
,
274 KRB5_TGS_NAME
, *client_realm
, NULL
);
278 static krb5_error_code
279 do_524init(krb5_context context
, krb5_ccache ccache
,
280 krb5_creds
*creds
, const char *server
)
284 krb5_creds in_creds
, *real_creds
;
289 krb5_principal client
;
290 krb5_cc_get_principal(context
, ccache
, &client
);
291 memset(&in_creds
, 0, sizeof(in_creds
));
292 ret
= get_server(context
, client
, server
, &in_creds
.server
);
294 krb5_free_principal(context
, client
);
297 in_creds
.client
= client
;
298 ret
= krb5_get_credentials(context
, 0, ccache
, &in_creds
, &real_creds
);
299 krb5_free_principal(context
, client
);
300 krb5_free_principal(context
, in_creds
.server
);
304 ret
= krb524_convert_creds_kdc_ccache(context
, ccache
, real_creds
, &c
);
306 krb5_warn(context
, ret
, "converting creds");
308 int tret
= tf_setup(&c
, c
.pname
, c
.pinst
);
310 krb5_warnx(context
, "saving v4 creds: %s", krb_get_err_text(tret
));
314 krb5_free_creds(context
, real_creds
);
315 memset(&c
, 0, sizeof(c
));
322 renew_validate(krb5_context context
,
331 krb5_kdc_flags flags
;
333 memset(&in
, 0, sizeof(in
));
335 ret
= krb5_cc_get_principal(context
, cache
, &in
.client
);
337 krb5_warn(context
, ret
, "krb5_cc_get_principal");
340 ret
= get_server(context
, in
.client
, server
, &in
.server
);
342 krb5_warn(context
, ret
, "get_server");
346 flags
.b
.renewable
= flags
.b
.renew
= renew
;
347 flags
.b
.validate
= validate
;
348 if (forwardable_flag
!= -1)
349 flags
.b
.forwardable
= forwardable_flag
;
350 if (proxiable_flag
!= -1)
351 flags
.b
.proxiable
= proxiable_flag
;
352 if (anonymous_flag
!= -1)
353 flags
.b
.request_anonymous
= anonymous_flag
;
355 in
.times
.endtime
= time(NULL
) + life
;
357 ret
= krb5_get_kdc_cred(context
,
365 krb5_warn(context
, ret
, "krb5_get_kdc_cred");
368 ret
= krb5_cc_initialize(context
, cache
, in
.client
);
370 krb5_free_creds (context
, out
);
371 krb5_warn(context
, ret
, "krb5_cc_initialize");
374 ret
= krb5_cc_store_cred(context
, cache
, out
);
376 if(ret
== 0 && server
== NULL
) {
378 /* only do this if it's a general renew-my-tgt request */
380 do_524init(context
, cache
, out
, NULL
);
382 if(do_afslog
&& k_hasafs())
383 krb5_afslog(context
, cache
, NULL
, NULL
);
386 krb5_free_creds (context
, out
);
388 krb5_warn(context
, ret
, "krb5_cc_store_cred");
392 krb5_free_creds_contents(context
, &in
);
396 static krb5_error_code
397 get_new_tickets(krb5_context context
,
398 krb5_principal principal
,
400 krb5_deltat ticket_life
)
403 krb5_get_init_creds_opt opt
;
404 krb5_addresses no_addrs
;
407 krb5_deltat start_time
= 0;
408 krb5_deltat renew
= 0;
410 memset(&cred
, 0, sizeof(cred
));
412 krb5_get_init_creds_opt_init (&opt
);
414 krb5_get_init_creds_opt_set_default_flags(context
, "kinit",
415 /* XXX */principal
->realm
, &opt
);
417 if(forwardable_flag
!= -1)
418 krb5_get_init_creds_opt_set_forwardable (&opt
, forwardable_flag
);
419 if(proxiable_flag
!= -1)
420 krb5_get_init_creds_opt_set_proxiable (&opt
, proxiable_flag
);
421 if(anonymous_flag
!= -1)
422 krb5_get_init_creds_opt_set_anonymous (&opt
, anonymous_flag
);
428 krb5_get_init_creds_opt_set_address_list (&opt
, &no_addrs
);
431 if (renew_life
== NULL
&& renewable_flag
)
432 renew_life
= "1 month";
434 renew
= parse_time (renew_life
, "s");
436 errx (1, "unparsable time: %s", renew_life
);
438 krb5_get_init_creds_opt_set_renew_life (&opt
, renew
);
442 krb5_get_init_creds_opt_set_tkt_life (&opt
, ticket_life
);
445 int tmp
= parse_time (start_str
, "s");
447 errx (1, "unparsable time: %s", start_str
);
452 if(etype_str
.num_strings
) {
453 krb5_enctype
*enctype
= NULL
;
455 enctype
= malloc(etype_str
.num_strings
* sizeof(*enctype
));
457 errx(1, "out of memory");
458 for(i
= 0; i
< etype_str
.num_strings
; i
++) {
459 ret
= krb5_string_to_enctype(context
,
460 etype_str
.strings
[i
],
463 errx(1, "unrecognized enctype: %s", etype_str
.strings
[i
]);
465 krb5_get_init_creds_opt_set_etype_list(&opt
, enctype
,
466 etype_str
.num_strings
);
469 if(use_keytab
|| keytab_str
) {
472 ret
= krb5_kt_resolve(context
, keytab_str
, &kt
);
474 ret
= krb5_kt_default(context
, &kt
);
476 krb5_err (context
, 1, ret
, "resolving keytab");
477 ret
= krb5_get_init_creds_keytab (context
,
484 krb5_kt_close(context
, kt
);
488 krb5_unparse_name (context
, principal
, &p
);
489 asprintf (&prompt
, "%s's Password: ", p
);
492 if (des_read_pw_string(passwd
, sizeof(passwd
)-1, prompt
, 0)){
493 memset(passwd
, 0, sizeof(passwd
));
499 ret
= krb5_get_init_creds_password (context
,
510 if (ret
== KRB5KRB_AP_ERR_V4_REPLY
|| ret
== KRB5_KDC_UNREACH
) {
513 exit_val
= do_v4_fallback (context
, principal
, ticket_life
,
514 use_keytab
, keytab_str
, passwd
);
517 memset(passwd
, 0, sizeof(passwd
));
518 if (exit_val
== 0 || ret
== KRB5KRB_AP_ERR_V4_REPLY
)
522 memset(passwd
, 0, sizeof(passwd
));
527 case KRB5_LIBOS_PWDINTR
: /* don't print anything if it was just C-c:ed */
529 case KRB5KRB_AP_ERR_BAD_INTEGRITY
:
530 case KRB5KRB_AP_ERR_MODIFIED
:
531 krb5_errx(context
, 1, "Password incorrect");
534 krb5_err(context
, 1, ret
, "krb5_get_init_creds");
537 if(ticket_life
!= 0) {
538 if(abs(cred
.times
.endtime
- cred
.times
.starttime
- ticket_life
) > 30) {
540 unparse_time(cred
.times
.endtime
- cred
.times
.starttime
,
542 krb5_warnx(context
, "NOTICE: ticket lifetime is %s", life
);
546 if(abs(cred
.times
.renew_till
- cred
.times
.starttime
- renew
) > 30) {
548 unparse_time(cred
.times
.renew_till
- cred
.times
.starttime
,
550 krb5_warnx(context
, "NOTICE: ticket renewable lifetime is %s",
555 ret
= krb5_cc_initialize (context
, ccache
, cred
.client
);
557 krb5_err (context
, 1, ret
, "krb5_cc_initialize");
559 ret
= krb5_cc_store_cred (context
, ccache
, &cred
);
561 krb5_err (context
, 1, ret
, "krb5_cc_store_cred");
563 krb5_free_creds_contents (context
, &cred
);
569 main (int argc
, char **argv
)
572 krb5_context context
;
574 krb5_principal principal
;
576 krb5_deltat ticket_life
= 0;
578 setprogname (argv
[0]);
580 ret
= krb5_init_context (&context
);
582 errx(1, "krb5_init_context failed: %d", ret
);
584 if(getarg(args
, sizeof(args
) / sizeof(args
[0]), argc
, argv
, &optind
))
599 ret
= krb5_parse_name (context
, argv
[0], &principal
);
601 krb5_err (context
, 1, ret
, "krb5_parse_name");
603 ret
= kinit_get_default_principal (context
, &principal
);
605 krb5_err (context
, 1, ret
, "krb5_get_default_principal");
609 krb5_set_fcache_version(context
, fcache_version
);
612 ret
= krb5_cc_resolve(context
, cred_cache
, &ccache
);
616 ret
= krb5_cc_gen_new(context
, &krb5_fcc_ops
, &ccache
);
618 krb5_err(context
, 1, ret
, "creating cred cache");
619 snprintf(s
, sizeof(s
), "%s:%s",
620 krb5_cc_get_type(context
, ccache
),
621 krb5_cc_get_name(context
, ccache
));
622 setenv("KRB5CCNAME", s
, 1);
626 snprintf(s
, sizeof(s
), "%s_XXXXXX", TKT_ROOT
);
627 if((fd
= mkstemp(s
)) >= 0) {
629 setenv("KRBTKFILE", s
, 1);
634 ret
= krb5_cc_default (context
, &ccache
);
637 krb5_err (context
, 1, ret
, "resolving credentials cache");
639 if (argc
> 1 && k_hasafs ())
643 int tmp
= parse_time (lifetime
, "s");
645 errx (1, "unparsable time: %s", lifetime
);
651 krb5_appdefault_boolean(context
, "kinit",
652 krb5_principal_get_realm(context
, principal
),
653 "krb4_get_tickets", TRUE
, &get_v4_tgt
);
656 krb5_appdefault_boolean(context
, "kinit",
657 krb5_principal_get_realm(context
, principal
),
658 "afslog", TRUE
, &do_afslog
);
660 if(!addrs_flag
&& extra_addresses
.num_strings
> 0)
661 krb5_errx(context
, 1, "specifying both extra addresses and "
662 "no addresses makes no sense");
665 krb5_addresses addresses
;
666 memset(&addresses
, 0, sizeof(addresses
));
667 for(i
= 0; i
< extra_addresses
.num_strings
; i
++) {
668 ret
= krb5_parse_address(context
, extra_addresses
.strings
[i
],
671 krb5_add_extra_addresses(context
, &addresses
);
672 krb5_free_addresses(context
, &addresses
);
675 free_getarg_strings(&extra_addresses
);
679 if(renew_flag
|| validate_flag
) {
680 ret
= renew_validate(context
, renew_flag
, validate_flag
,
681 ccache
, server
, ticket_life
);
688 get_new_tickets(context
, principal
, ccache
, ticket_life
);
692 do_524init(context
, ccache
, NULL
, server
);
694 if(do_afslog
&& k_hasafs())
695 krb5_afslog(context
, ccache
, NULL
, NULL
);
697 ret
= simple_execvp(argv
[1], argv
+1);
698 krb5_cc_destroy(context
, ccache
);
705 krb5_cc_close (context
, ccache
);
708 krb5_free_principal(context
, principal
);
709 krb5_free_context (context
);