xref: /freebsd/crypto/heimdal/kuser/kinit.c (revision 23f282aa31e9b6fceacd449020e936e98d6f2298)
1 /*
2  * Copyright (c) 1997-2000 Kungliga Tekniska H�gskolan
3  * (Royal Institute of Technology, Stockholm, Sweden).
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  *
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.
16  *
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.
20  *
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
31  * SUCH DAMAGE.
32  */
33 
34 #include "kuser_locl.h"
35 RCSID("$Id: kinit.c,v 1.60 2000/02/01 14:06:33 joda Exp $");
36 
37 int forwardable		= 0;
38 int proxiable		= 0;
39 int renewable		= 0;
40 int renew_flag		= 0;
41 int validate_flag	= 0;
42 int version_flag	= 0;
43 int help_flag		= 0;
44 int addrs_flag		= 1;
45 char *lifetime 		= NULL;
46 char *renew_life	= NULL;
47 char *server		= NULL;
48 char *cred_cache	= NULL;
49 char *start_str		= NULL;
50 struct getarg_strings etype_str;
51 int use_keytab		= 0;
52 char *keytab_str	= NULL;
53 #ifdef KRB4
54 extern int do_afslog;
55 extern int get_v4_tgt;
56 #endif
57 int fcache_version;
58 
59 struct getargs args[] = {
60 #ifdef KRB4
61     { "524init", 	'4', arg_flag, &get_v4_tgt,
62       "obtain version 4 TGT" },
63 
64     { "afslog", 	0  , arg_flag, &do_afslog,
65       "obtain afs tokens"  },
66 #endif
67     { "cache", 		'c', arg_string, &cred_cache,
68       "credentials cache", "cachename" },
69 
70     { "forwardable",	'f', arg_flag, &forwardable,
71       "get forwardable tickets"},
72 
73     { "keytab",         't', arg_string, &keytab_str,
74       "keytab to use", "keytabname" },
75 
76     { "lifetime",	'l', arg_string, &lifetime,
77       "lifetime of tickets", "seconds"},
78 
79     { "proxiable",	'p', arg_flag, &proxiable,
80       "get proxiable tickets" },
81 
82     { "renew",          'R', arg_flag, &renew_flag,
83       "renew TGT" },
84 
85     { "renewable",	0,   arg_flag, &renewable,
86       "get renewable tickets" },
87 
88     { "renewable-life",	'r', arg_string, &renew_life,
89       "renewable lifetime of tickets", "seconds" },
90 
91     { "server", 	'S', arg_string, &server,
92       "server to get ticket for", "principal" },
93 
94     { "start-time",	's', arg_string, &start_str,
95       "when ticket gets valid", "seconds" },
96 
97     { "use-keytab",     'k', arg_flag, &use_keytab,
98       "get key from keytab" },
99 
100     { "validate",	'v', arg_flag, &validate_flag,
101       "validate TGT" },
102 
103     { "enctypes",	'e', arg_strings, &etype_str,
104       "encryption type to use", "enctype" },
105 
106     { "fcache-version", 0,   arg_integer, &fcache_version,
107       "file cache version to create" },
108 
109     { "addresses",	0,   arg_negative_flag,	&addrs_flag,
110       "request a ticket with no addresses" },
111 
112     { "version", 	0,   arg_flag, &version_flag },
113     { "help",		0,   arg_flag, &help_flag }
114 };
115 
116 static void
117 usage (int ret)
118 {
119     arg_printusage (args,
120 		    sizeof(args)/sizeof(*args),
121 		    NULL,
122 		    "[principal]");
123     exit (ret);
124 }
125 
126 static int
127 renew_validate(krb5_context context,
128 	       int renew,
129 	       int validate,
130 	       krb5_ccache cache,
131 	       const char *server,
132 	       krb5_deltat life)
133 {
134     krb5_error_code ret;
135     krb5_creds in, *out;
136     krb5_kdc_flags flags;
137 
138     memset(&in, 0, sizeof(in));
139 
140     ret = krb5_cc_get_principal(context, cache, &in.client);
141     if(ret) {
142 	krb5_warn(context, ret, "krb5_cc_get_principal");
143 	return ret;
144     }
145     if(server) {
146 	ret = krb5_parse_name(context, server, &in.server);
147 	if(ret) {
148 	    krb5_warn(context, ret, "krb5_parse_name");
149 	    goto out;
150 	}
151     } else {
152 	krb5_realm *client_realm = krb5_princ_realm (context, in.client);
153 
154 	ret = krb5_make_principal(context, &in.server, *client_realm,
155 				  KRB5_TGS_NAME, *client_realm, NULL);
156 	if(ret) {
157 	    krb5_warn(context, ret, "krb5_make_principal");
158 	    goto out;
159 	}
160     }
161     flags.i = 0;
162     flags.b.renewable   = flags.b.renew = renew;
163     flags.b.validate    = validate;
164     flags.b.forwardable = forwardable;
165     flags.b.proxiable   = proxiable;
166     if(life)
167 	in.times.endtime = time(NULL) + life;
168 
169     ret = krb5_get_kdc_cred(context,
170 			    cache,
171 			    flags,
172 			    NULL,
173 			    NULL,
174 			    &in,
175 			    &out);
176     if(ret) {
177 	krb5_warn(context, ret, "krb5_get_kdc_cred");
178 	goto out;
179     }
180     ret = krb5_cc_initialize(context, cache, in.client);
181     if(ret) {
182 	krb5_free_creds (context, out);
183 	krb5_warn(context, ret, "krb5_cc_initialize");
184 	goto out;
185     }
186     ret = krb5_cc_store_cred(context, cache, out);
187     krb5_free_creds (context, out);
188     if(ret) {
189 	krb5_warn(context, ret, "krb5_cc_store_cred");
190 	goto out;
191     }
192 out:
193     krb5_free_creds_contents(context, &in);
194     return ret;
195 }
196 
197 int
198 main (int argc, char **argv)
199 {
200     krb5_error_code ret;
201     krb5_context context;
202     krb5_ccache  ccache;
203     krb5_principal principal;
204     krb5_creds cred;
205     int optind = 0;
206     krb5_get_init_creds_opt opt;
207     krb5_deltat start_time = 0;
208     krb5_deltat ticket_life = 0;
209     krb5_addresses no_addrs;
210 
211     set_progname (argv[0]);
212     memset(&cred, 0, sizeof(cred));
213 
214     ret = krb5_init_context (&context);
215     if (ret)
216 	errx(1, "krb5_init_context failed: %u", ret);
217 
218     forwardable = krb5_config_get_bool (context, NULL,
219 					"libdefaults",
220 					"forwardable",
221 					NULL);
222 
223 #ifdef KRB4
224     get_v4_tgt = krb5_config_get_bool_default (context, NULL,
225 					       get_v4_tgt,
226 					       "libdefaults",
227 					       "krb4_get_tickets",
228 					       NULL);
229 #endif
230 
231     if(getarg(args, sizeof(args) / sizeof(args[0]), argc, argv, &optind))
232 	usage(1);
233 
234     if (help_flag)
235 	usage (0);
236 
237     if(version_flag) {
238 	print_version(NULL);
239 	exit(0);
240     }
241 
242     if(fcache_version)
243 	krb5_set_fcache_version(context, fcache_version);
244 
245     if(cred_cache)
246 	ret = krb5_cc_resolve(context, cred_cache, &ccache);
247     else
248 	ret = krb5_cc_default (context, &ccache);
249     if (ret)
250 	krb5_err (context, 1, ret, "resolving credentials cache");
251 
252     if (lifetime) {
253 	int tmp = parse_time (lifetime, "s");
254 	if (tmp < 0)
255 	    errx (1, "unparsable time: %s", lifetime);
256 
257 	ticket_life = tmp;
258     }
259     if(renew_flag || validate_flag) {
260 	ret = renew_validate(context, renew_flag, validate_flag,
261 			     ccache, server, ticket_life);
262 	exit(ret != 0);
263     }
264 
265     krb5_get_init_creds_opt_init (&opt);
266 
267     krb5_get_init_creds_opt_set_forwardable (&opt, forwardable);
268     krb5_get_init_creds_opt_set_proxiable (&opt, proxiable);
269 
270     if (!addrs_flag) {
271 	no_addrs.len = 0;
272 	no_addrs.val = NULL;
273 
274 	krb5_get_init_creds_opt_set_address_list (&opt, &no_addrs);
275     }
276 
277     if(renew_life) {
278 	int tmp = parse_time (renew_life, "s");
279 	if (tmp < 0)
280 	    errx (1, "unparsable time: %s", renew_life);
281 
282 	krb5_get_init_creds_opt_set_renew_life (&opt, tmp);
283     } else if (renewable)
284 	krb5_get_init_creds_opt_set_renew_life (&opt, 1 << 30);
285 
286     if(ticket_life != 0)
287 	krb5_get_init_creds_opt_set_tkt_life (&opt, ticket_life);
288 
289     if(start_str) {
290 	int tmp = parse_time (start_str, "s");
291 	if (tmp < 0)
292 	    errx (1, "unparsable time: %s", start_str);
293 
294 	start_time = tmp;
295     }
296 
297     if(etype_str.num_strings) {
298 	krb5_enctype *enctype = NULL;
299 	int i;
300 	enctype = malloc(etype_str.num_strings * sizeof(*enctype));
301 	if(enctype == NULL)
302 	    errx(1, "out of memory");
303 	for(i = 0; i < etype_str.num_strings; i++) {
304 	    ret = krb5_string_to_enctype(context,
305 					 etype_str.strings[i],
306 					 &enctype[i]);
307 	    if(ret)
308 		errx(1, "unrecognized enctype: %s", etype_str.strings[i]);
309 	}
310 	krb5_get_init_creds_opt_set_etype_list(&opt, enctype,
311 					       etype_str.num_strings);
312     }
313 
314     argc -= optind;
315     argv += optind;
316 
317     if (argc > 1)
318 	usage (1);
319 
320     if (argv[0]) {
321 	ret = krb5_parse_name (context, argv[0], &principal);
322 	if (ret)
323 	    krb5_err (context, 1, ret, "krb5_parse_name");
324     } else
325 	principal = NULL;
326 
327     if(use_keytab || keytab_str) {
328 	krb5_keytab kt;
329 	if(keytab_str)
330 	    ret = krb5_kt_resolve(context, keytab_str, &kt);
331 	else
332 	    ret = krb5_kt_default(context, &kt);
333 	if (ret)
334 	    krb5_err (context, 1, ret, "resolving keytab");
335 	ret = krb5_get_init_creds_keytab (context,
336 					  &cred,
337 					  principal,
338 					  kt,
339 					  start_time,
340 					  server,
341 					  &opt);
342 	krb5_kt_close(context, kt);
343     } else
344 	ret = krb5_get_init_creds_password (context,
345 					    &cred,
346 					    principal,
347 					    NULL,
348 					    krb5_prompter_posix,
349 					    NULL,
350 					    start_time,
351 					    server,
352 					    &opt);
353     switch(ret){
354     case 0:
355 	break;
356     case KRB5_LIBOS_PWDINTR: /* don't print anything if it was just C-c:ed */
357 	exit(1);
358     case KRB5KRB_AP_ERR_BAD_INTEGRITY:
359     case KRB5KRB_AP_ERR_MODIFIED:
360 	krb5_errx(context, 1, "Password incorrect");
361 	break;
362     default:
363 	krb5_err(context, 1, ret, "krb5_get_init_creds");
364     }
365 
366     ret = krb5_cc_initialize (context, ccache, cred.client);
367     if (ret)
368 	krb5_err (context, 1, ret, "krb5_cc_initialize");
369 
370     ret = krb5_cc_store_cred (context, ccache, &cred);
371     if (ret)
372 	krb5_err (context, 1, ret, "krb5_cc_store_cred");
373 
374 #ifdef KRB4
375     if(get_v4_tgt) {
376 	CREDENTIALS c;
377 	ret = krb524_convert_creds_kdc(context, ccache, &cred, &c);
378 	if(ret)
379 	    krb5_warn(context, ret, "converting creds");
380 	else
381 	    tf_setup(&c, c.pname, c.pinst);
382 	memset(&c, 0, sizeof(c));
383     }
384     if(do_afslog && k_hasafs())
385 	krb5_afslog(context, ccache, NULL, NULL);
386 #endif
387     krb5_free_creds_contents (context, &cred);
388     krb5_cc_close (context, ccache);
389     krb5_free_context (context);
390     return 0;
391 }
392