1 /*	$NetBSD: init_creds.c,v 1.1.1.1 2011/04/13 18:15:34 elric Exp $	*/
2 
3 /*
4  * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan
5  * (Royal Institute of Technology, Stockholm, Sweden).
6  * All rights reserved.
7  *
8  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  *
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  *
21  * 3. Neither the name of the Institute nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  */
37 
38 #include "krb5_locl.h"
39 
40 #undef __attribute__
41 #define __attribute__(x)
42 
43 /**
44  * @page krb5_init_creds_intro The initial credential handing functions
45  * @section section_krb5_init_creds Initial credential
46  *
47  * Functions to get initial credentials: @ref krb5_credential .
48  */
49 
50 /**
51  * Allocate a new krb5_get_init_creds_opt structure, free with
52  * krb5_get_init_creds_opt_free().
53  *
54  * @ingroup krb5_credential
55  */
56 
57 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
58 krb5_get_init_creds_opt_alloc(krb5_context context,
59 			      krb5_get_init_creds_opt **opt)
60 {
61     krb5_get_init_creds_opt *o;
62 
63     *opt = NULL;
64     o = calloc(1, sizeof(*o));
65     if (o == NULL) {
66 	krb5_set_error_message(context, ENOMEM,
67 			       N_("malloc: out of memory", ""));
68 	return ENOMEM;
69     }
70 
71     o->opt_private = calloc(1, sizeof(*o->opt_private));
72     if (o->opt_private == NULL) {
73 	krb5_set_error_message(context, ENOMEM,
74 			       N_("malloc: out of memory", ""));
75 	free(o);
76 	return ENOMEM;
77     }
78     o->opt_private->refcount = 1;
79     *opt = o;
80     return 0;
81 }
82 
83 /**
84  * Free krb5_get_init_creds_opt structure.
85  *
86  * @ingroup krb5_credential
87  */
88 
89 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
90 krb5_get_init_creds_opt_free(krb5_context context,
91 			     krb5_get_init_creds_opt *opt)
92 {
93     if (opt == NULL || opt->opt_private == NULL)
94 	return;
95     if (opt->opt_private->refcount < 1) /* abort ? */
96 	return;
97     if (--opt->opt_private->refcount == 0) {
98 	_krb5_get_init_creds_opt_free_pkinit(opt);
99 	free(opt->opt_private);
100     }
101     memset(opt, 0, sizeof(*opt));
102     free(opt);
103 }
104 
105 static int
106 get_config_time (krb5_context context,
107 		 const char *realm,
108 		 const char *name,
109 		 int def)
110 {
111     int ret;
112 
113     ret = krb5_config_get_time (context, NULL,
114 				"realms",
115 				realm,
116 				name,
117 				NULL);
118     if (ret >= 0)
119 	return ret;
120     ret = krb5_config_get_time (context, NULL,
121 				"libdefaults",
122 				name,
123 				NULL);
124     if (ret >= 0)
125 	return ret;
126     return def;
127 }
128 
129 static krb5_boolean
130 get_config_bool (krb5_context context,
131 		 krb5_boolean def_value,
132 		 const char *realm,
133 		 const char *name)
134 {
135     krb5_boolean b;
136 
137     b = krb5_config_get_bool_default(context, NULL, def_value,
138 				     "realms", realm, name, NULL);
139     if (b != def_value)
140 	return b;
141     b = krb5_config_get_bool_default (context, NULL, def_value,
142 				      "libdefaults", name, NULL);
143     if (b != def_value)
144 	return b;
145     return def_value;
146 }
147 
148 /*
149  * set all the values in `opt' to the appropriate values for
150  * application `appname' (default to getprogname() if NULL), and realm
151  * `realm'.  First looks in [appdefaults] but falls back to
152  * [realms] or [libdefaults] for some of the values.
153  */
154 
155 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
156 krb5_get_init_creds_opt_set_default_flags(krb5_context context,
157 					  const char *appname,
158 					  krb5_const_realm realm,
159 					  krb5_get_init_creds_opt *opt)
160 {
161     krb5_boolean b;
162     time_t t;
163 
164     b = get_config_bool (context, KRB5_FORWARDABLE_DEFAULT,
165 			 realm, "forwardable");
166     krb5_appdefault_boolean(context, appname, realm, "forwardable", b, &b);
167     krb5_get_init_creds_opt_set_forwardable(opt, b);
168 
169     b = get_config_bool (context, FALSE, realm, "proxiable");
170     krb5_appdefault_boolean(context, appname, realm, "proxiable", b, &b);
171     krb5_get_init_creds_opt_set_proxiable (opt, b);
172 
173     krb5_appdefault_time(context, appname, realm, "ticket_lifetime", 0, &t);
174     if (t == 0)
175 	t = get_config_time (context, realm, "ticket_lifetime", 0);
176     if(t != 0)
177 	krb5_get_init_creds_opt_set_tkt_life(opt, t);
178 
179     krb5_appdefault_time(context, appname, realm, "renew_lifetime", 0, &t);
180     if (t == 0)
181 	t = get_config_time (context, realm, "renew_lifetime", 0);
182     if(t != 0)
183 	krb5_get_init_creds_opt_set_renew_life(opt, t);
184 
185     krb5_appdefault_boolean(context, appname, realm, "no-addresses",
186 			    KRB5_ADDRESSLESS_DEFAULT, &b);
187     krb5_get_init_creds_opt_set_addressless (context, opt, b);
188 
189 #if 0
190     krb5_appdefault_boolean(context, appname, realm, "anonymous", FALSE, &b);
191     krb5_get_init_creds_opt_set_anonymous (opt, b);
192 
193     krb5_get_init_creds_opt_set_etype_list(opt, enctype,
194 					   etype_str.num_strings);
195 
196     krb5_get_init_creds_opt_set_salt(krb5_get_init_creds_opt *opt,
197 				     krb5_data *salt);
198 
199     krb5_get_init_creds_opt_set_preauth_list(krb5_get_init_creds_opt *opt,
200 					     krb5_preauthtype *preauth_list,
201 					     int preauth_list_length);
202 #endif
203 }
204 
205 
206 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
207 krb5_get_init_creds_opt_set_tkt_life(krb5_get_init_creds_opt *opt,
208 				     krb5_deltat tkt_life)
209 {
210     opt->flags |= KRB5_GET_INIT_CREDS_OPT_TKT_LIFE;
211     opt->tkt_life = tkt_life;
212 }
213 
214 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
215 krb5_get_init_creds_opt_set_renew_life(krb5_get_init_creds_opt *opt,
216 				       krb5_deltat renew_life)
217 {
218     opt->flags |= KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE;
219     opt->renew_life = renew_life;
220 }
221 
222 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
223 krb5_get_init_creds_opt_set_forwardable(krb5_get_init_creds_opt *opt,
224 					int forwardable)
225 {
226     opt->flags |= KRB5_GET_INIT_CREDS_OPT_FORWARDABLE;
227     opt->forwardable = forwardable;
228 }
229 
230 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
231 krb5_get_init_creds_opt_set_proxiable(krb5_get_init_creds_opt *opt,
232 				      int proxiable)
233 {
234     opt->flags |= KRB5_GET_INIT_CREDS_OPT_PROXIABLE;
235     opt->proxiable = proxiable;
236 }
237 
238 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
239 krb5_get_init_creds_opt_set_etype_list(krb5_get_init_creds_opt *opt,
240 				       krb5_enctype *etype_list,
241 				       int etype_list_length)
242 {
243     opt->flags |= KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST;
244     opt->etype_list = etype_list;
245     opt->etype_list_length = etype_list_length;
246 }
247 
248 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
249 krb5_get_init_creds_opt_set_address_list(krb5_get_init_creds_opt *opt,
250 					 krb5_addresses *addresses)
251 {
252     opt->flags |= KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST;
253     opt->address_list = addresses;
254 }
255 
256 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
257 krb5_get_init_creds_opt_set_preauth_list(krb5_get_init_creds_opt *opt,
258 					 krb5_preauthtype *preauth_list,
259 					 int preauth_list_length)
260 {
261     opt->flags |= KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST;
262     opt->preauth_list_length = preauth_list_length;
263     opt->preauth_list = preauth_list;
264 }
265 
266 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
267 krb5_get_init_creds_opt_set_salt(krb5_get_init_creds_opt *opt,
268 				 krb5_data *salt)
269 {
270     opt->flags |= KRB5_GET_INIT_CREDS_OPT_SALT;
271     opt->salt = salt;
272 }
273 
274 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
275 krb5_get_init_creds_opt_set_anonymous(krb5_get_init_creds_opt *opt,
276 				      int anonymous)
277 {
278     opt->flags |= KRB5_GET_INIT_CREDS_OPT_ANONYMOUS;
279     opt->anonymous = anonymous;
280 }
281 
282 static krb5_error_code
283 require_ext_opt(krb5_context context,
284 		krb5_get_init_creds_opt *opt,
285 		const char *type)
286 {
287     if (opt->opt_private == NULL) {
288 	krb5_set_error_message(context, EINVAL,
289 			       N_("%s on non extendable opt", ""), type);
290 	return EINVAL;
291     }
292     return 0;
293 }
294 
295 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
296 krb5_get_init_creds_opt_set_pa_password(krb5_context context,
297 					krb5_get_init_creds_opt *opt,
298 					const char *password,
299 					krb5_s2k_proc key_proc)
300 {
301     krb5_error_code ret;
302     ret = require_ext_opt(context, opt, "init_creds_opt_set_pa_password");
303     if (ret)
304 	return ret;
305     opt->opt_private->password = password;
306     opt->opt_private->key_proc = key_proc;
307     return 0;
308 }
309 
310 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
311 krb5_get_init_creds_opt_set_pac_request(krb5_context context,
312 					krb5_get_init_creds_opt *opt,
313 					krb5_boolean req_pac)
314 {
315     krb5_error_code ret;
316     ret = require_ext_opt(context, opt, "init_creds_opt_set_pac_req");
317     if (ret)
318 	return ret;
319     opt->opt_private->req_pac = req_pac ?
320 	KRB5_INIT_CREDS_TRISTATE_TRUE :
321 	KRB5_INIT_CREDS_TRISTATE_FALSE;
322     return 0;
323 }
324 
325 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
326 krb5_get_init_creds_opt_set_addressless(krb5_context context,
327 					krb5_get_init_creds_opt *opt,
328 					krb5_boolean addressless)
329 {
330     krb5_error_code ret;
331     ret = require_ext_opt(context, opt, "init_creds_opt_set_pac_req");
332     if (ret)
333 	return ret;
334     if (addressless)
335 	opt->opt_private->addressless = KRB5_INIT_CREDS_TRISTATE_TRUE;
336     else
337 	opt->opt_private->addressless = KRB5_INIT_CREDS_TRISTATE_FALSE;
338     return 0;
339 }
340 
341 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
342 krb5_get_init_creds_opt_set_canonicalize(krb5_context context,
343 					 krb5_get_init_creds_opt *opt,
344 					 krb5_boolean req)
345 {
346     krb5_error_code ret;
347     ret = require_ext_opt(context, opt, "init_creds_opt_set_canonicalize");
348     if (ret)
349 	return ret;
350     if (req)
351 	opt->opt_private->flags |= KRB5_INIT_CREDS_CANONICALIZE;
352     else
353 	opt->opt_private->flags &= ~KRB5_INIT_CREDS_CANONICALIZE;
354     return 0;
355 }
356 
357 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
358 krb5_get_init_creds_opt_set_win2k(krb5_context context,
359 				  krb5_get_init_creds_opt *opt,
360 				  krb5_boolean req)
361 {
362     krb5_error_code ret;
363     ret = require_ext_opt(context, opt, "init_creds_opt_set_win2k");
364     if (ret)
365 	return ret;
366     if (req) {
367 	opt->opt_private->flags |= KRB5_INIT_CREDS_NO_C_CANON_CHECK;
368 	opt->opt_private->flags |= KRB5_INIT_CREDS_NO_C_NO_EKU_CHECK;
369     } else {
370 	opt->opt_private->flags &= ~KRB5_INIT_CREDS_NO_C_CANON_CHECK;
371 	opt->opt_private->flags &= ~KRB5_INIT_CREDS_NO_C_NO_EKU_CHECK;
372     }
373     return 0;
374 }
375 
376 
377 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
378 krb5_get_init_creds_opt_set_process_last_req(krb5_context context,
379 					     krb5_get_init_creds_opt *opt,
380 					     krb5_gic_process_last_req func,
381 					     void *ctx)
382 {
383     krb5_error_code ret;
384     ret = require_ext_opt(context, opt, "init_creds_opt_set_win2k");
385     if (ret)
386 	return ret;
387 
388     opt->opt_private->lr.func = func;
389     opt->opt_private->lr.ctx = ctx;
390 
391     return 0;
392 }
393 
394 
395 #ifndef HEIMDAL_SMALLER
396 
397 /**
398  * Deprecated: use krb5_get_init_creds_opt_alloc().
399  *
400  * The reason krb5_get_init_creds_opt_init() is deprecated is that
401  * krb5_get_init_creds_opt is a static structure and for ABI reason it
402  * can't grow, ie can't add new functionality.
403  *
404  * @ingroup krb5_deprecated
405  */
406 
407 KRB5_DEPRECATED
408 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
409 krb5_get_init_creds_opt_init(krb5_get_init_creds_opt *opt)
410 {
411     memset (opt, 0, sizeof(*opt));
412 }
413 
414 /**
415  * Deprecated: use the new krb5_init_creds_init() and
416  * krb5_init_creds_get_error().
417  *
418  * @ingroup krb5_deprecated
419  */
420 
421 KRB5_DEPRECATED
422 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
423 krb5_get_init_creds_opt_get_error(krb5_context context,
424 				  krb5_get_init_creds_opt *opt,
425 				  KRB_ERROR **error)
426 {
427     *error = calloc(1, sizeof(**error));
428     if (*error == NULL) {
429 	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
430 	return ENOMEM;
431     }
432 
433     return 0;
434 }
435 
436 #endif /* HEIMDAL_SMALLER */
437