1/*
2 * Copyright (c) 1997 - 2004 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 "krb5_locl.h"
35
36RCSID("$Id: init_creds.c 21711 2007-07-27 14:22:02Z lha $");
37
38void KRB5_LIB_FUNCTION
39krb5_get_init_creds_opt_init(krb5_get_init_creds_opt *opt)
40{
41    memset (opt, 0, sizeof(*opt));
42    opt->flags = 0;
43    opt->opt_private = NULL;
44}
45
46krb5_error_code KRB5_LIB_FUNCTION
47krb5_get_init_creds_opt_alloc(krb5_context context,
48			      krb5_get_init_creds_opt **opt)
49{
50    krb5_get_init_creds_opt *o;
51
52    *opt = NULL;
53    o = calloc(1, sizeof(*o));
54    if (o == NULL) {
55	krb5_set_error_string(context, "out of memory");
56	return ENOMEM;
57    }
58    krb5_get_init_creds_opt_init(o);
59    o->opt_private = calloc(1, sizeof(*o->opt_private));
60    if (o->opt_private == NULL) {
61	krb5_set_error_string(context, "out of memory");
62	free(o);
63	return ENOMEM;
64    }
65    o->opt_private->refcount = 1;
66    *opt = o;
67    return 0;
68}
69
70krb5_error_code
71_krb5_get_init_creds_opt_copy(krb5_context context,
72			      const krb5_get_init_creds_opt *in,
73			      krb5_get_init_creds_opt **out)
74{
75    krb5_get_init_creds_opt *opt;
76
77    *out = NULL;
78    opt = calloc(1, sizeof(*opt));
79    if (opt == NULL) {
80	krb5_set_error_string(context, "out of memory");
81	return ENOMEM;
82    }
83    if (in)
84	*opt = *in;
85    if(opt->opt_private == NULL) {
86	opt->opt_private = calloc(1, sizeof(*opt->opt_private));
87	if (opt->opt_private == NULL) {
88	    krb5_set_error_string(context, "out of memory");
89	    free(opt);
90	    return ENOMEM;
91	}
92	opt->opt_private->refcount = 1;
93    } else
94	opt->opt_private->refcount++;
95    *out = opt;
96    return 0;
97}
98
99void KRB5_LIB_FUNCTION
100_krb5_get_init_creds_opt_free_krb5_error(krb5_get_init_creds_opt *opt)
101{
102    if (opt->opt_private == NULL || opt->opt_private->error == NULL)
103	return;
104    free_KRB_ERROR(opt->opt_private->error);
105    free(opt->opt_private->error);
106    opt->opt_private->error = NULL;
107}
108
109void KRB5_LIB_FUNCTION
110_krb5_get_init_creds_opt_set_krb5_error(krb5_context context,
111					krb5_get_init_creds_opt *opt,
112					const KRB_ERROR *error)
113{
114    krb5_error_code ret;
115
116    if (opt->opt_private == NULL)
117	return;
118
119    _krb5_get_init_creds_opt_free_krb5_error(opt);
120
121    opt->opt_private->error = malloc(sizeof(*opt->opt_private->error));
122    if (opt->opt_private->error == NULL)
123	return;
124    ret = copy_KRB_ERROR(error, opt->opt_private->error);
125    if (ret) {
126	free(opt->opt_private->error);
127	opt->opt_private->error = NULL;
128    }
129}
130
131
132void KRB5_LIB_FUNCTION
133krb5_get_init_creds_opt_free(krb5_context context,
134			     krb5_get_init_creds_opt *opt)
135{
136    if (opt == NULL || opt->opt_private == NULL)
137	return;
138    if (opt->opt_private->refcount < 1) /* abort ? */
139	return;
140    if (--opt->opt_private->refcount == 0) {
141	_krb5_get_init_creds_opt_free_krb5_error(opt);
142	_krb5_get_init_creds_opt_free_pkinit(opt);
143	free(opt->opt_private);
144    }
145    memset(opt, 0, sizeof(*opt));
146    free(opt);
147}
148
149static int
150get_config_time (krb5_context context,
151		 const char *realm,
152		 const char *name,
153		 int def)
154{
155    int ret;
156
157    ret = krb5_config_get_time (context, NULL,
158				"realms",
159				realm,
160				name,
161				NULL);
162    if (ret >= 0)
163	return ret;
164    ret = krb5_config_get_time (context, NULL,
165				"libdefaults",
166				name,
167				NULL);
168    if (ret >= 0)
169	return ret;
170    return def;
171}
172
173static krb5_boolean
174get_config_bool (krb5_context context,
175		 const char *realm,
176		 const char *name)
177{
178    return krb5_config_get_bool (context,
179				 NULL,
180				 "realms",
181				 realm,
182				 name,
183				 NULL)
184	|| krb5_config_get_bool (context,
185				 NULL,
186				 "libdefaults",
187				 name,
188				 NULL);
189}
190
191/*
192 * set all the values in `opt' to the appropriate values for
193 * application `appname' (default to getprogname() if NULL), and realm
194 * `realm'.  First looks in [appdefaults] but falls back to
195 * [realms] or [libdefaults] for some of the values.
196 */
197
198void KRB5_LIB_FUNCTION
199krb5_get_init_creds_opt_set_default_flags(krb5_context context,
200					  const char *appname,
201					  krb5_const_realm realm,
202					  krb5_get_init_creds_opt *opt)
203{
204    krb5_boolean b;
205    time_t t;
206
207    b = get_config_bool (context, realm, "forwardable");
208    krb5_appdefault_boolean(context, appname, realm, "forwardable", b, &b);
209    krb5_get_init_creds_opt_set_forwardable(opt, b);
210
211    b = get_config_bool (context, realm, "proxiable");
212    krb5_appdefault_boolean(context, appname, realm, "proxiable", b, &b);
213    krb5_get_init_creds_opt_set_proxiable (opt, b);
214
215    krb5_appdefault_time(context, appname, realm, "ticket_lifetime", 0, &t);
216    if (t == 0)
217	t = get_config_time (context, realm, "ticket_lifetime", 0);
218    if(t != 0)
219	krb5_get_init_creds_opt_set_tkt_life(opt, t);
220
221    krb5_appdefault_time(context, appname, realm, "renew_lifetime", 0, &t);
222    if (t == 0)
223	t = get_config_time (context, realm, "renew_lifetime", 0);
224    if(t != 0)
225	krb5_get_init_creds_opt_set_renew_life(opt, t);
226
227    krb5_appdefault_boolean(context, appname, realm, "no-addresses",
228			    KRB5_ADDRESSLESS_DEFAULT, &b);
229    krb5_get_init_creds_opt_set_addressless (context, opt, b);
230
231#if 0
232    krb5_appdefault_boolean(context, appname, realm, "anonymous", FALSE, &b);
233    krb5_get_init_creds_opt_set_anonymous (opt, b);
234
235    krb5_get_init_creds_opt_set_etype_list(opt, enctype,
236					   etype_str.num_strings);
237
238    krb5_get_init_creds_opt_set_salt(krb5_get_init_creds_opt *opt,
239				     krb5_data *salt);
240
241    krb5_get_init_creds_opt_set_preauth_list(krb5_get_init_creds_opt *opt,
242					     krb5_preauthtype *preauth_list,
243					     int preauth_list_length);
244#endif
245}
246
247
248void KRB5_LIB_FUNCTION
249krb5_get_init_creds_opt_set_tkt_life(krb5_get_init_creds_opt *opt,
250				     krb5_deltat tkt_life)
251{
252    opt->flags |= KRB5_GET_INIT_CREDS_OPT_TKT_LIFE;
253    opt->tkt_life = tkt_life;
254}
255
256void KRB5_LIB_FUNCTION
257krb5_get_init_creds_opt_set_renew_life(krb5_get_init_creds_opt *opt,
258				       krb5_deltat renew_life)
259{
260    opt->flags |= KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE;
261    opt->renew_life = renew_life;
262}
263
264void KRB5_LIB_FUNCTION
265krb5_get_init_creds_opt_set_forwardable(krb5_get_init_creds_opt *opt,
266					int forwardable)
267{
268    opt->flags |= KRB5_GET_INIT_CREDS_OPT_FORWARDABLE;
269    opt->forwardable = forwardable;
270}
271
272void KRB5_LIB_FUNCTION
273krb5_get_init_creds_opt_set_proxiable(krb5_get_init_creds_opt *opt,
274				      int proxiable)
275{
276    opt->flags |= KRB5_GET_INIT_CREDS_OPT_PROXIABLE;
277    opt->proxiable = proxiable;
278}
279
280void KRB5_LIB_FUNCTION
281krb5_get_init_creds_opt_set_etype_list(krb5_get_init_creds_opt *opt,
282				       krb5_enctype *etype_list,
283				       int etype_list_length)
284{
285    opt->flags |= KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST;
286    opt->etype_list = etype_list;
287    opt->etype_list_length = etype_list_length;
288}
289
290void KRB5_LIB_FUNCTION
291krb5_get_init_creds_opt_set_address_list(krb5_get_init_creds_opt *opt,
292					 krb5_addresses *addresses)
293{
294    opt->flags |= KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST;
295    opt->address_list = addresses;
296}
297
298void KRB5_LIB_FUNCTION
299krb5_get_init_creds_opt_set_preauth_list(krb5_get_init_creds_opt *opt,
300					 krb5_preauthtype *preauth_list,
301					 int preauth_list_length)
302{
303    opt->flags |= KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST;
304    opt->preauth_list_length = preauth_list_length;
305    opt->preauth_list = preauth_list;
306}
307
308void KRB5_LIB_FUNCTION
309krb5_get_init_creds_opt_set_salt(krb5_get_init_creds_opt *opt,
310				 krb5_data *salt)
311{
312    opt->flags |= KRB5_GET_INIT_CREDS_OPT_SALT;
313    opt->salt = salt;
314}
315
316void KRB5_LIB_FUNCTION
317krb5_get_init_creds_opt_set_anonymous(krb5_get_init_creds_opt *opt,
318				      int anonymous)
319{
320    opt->flags |= KRB5_GET_INIT_CREDS_OPT_ANONYMOUS;
321    opt->anonymous = anonymous;
322}
323
324static krb5_error_code
325require_ext_opt(krb5_context context,
326		krb5_get_init_creds_opt *opt,
327		const char *type)
328{
329    if (opt->opt_private == NULL) {
330	krb5_set_error_string(context, "%s on non extendable opt", type);
331	return EINVAL;
332    }
333    return 0;
334}
335
336krb5_error_code KRB5_LIB_FUNCTION
337krb5_get_init_creds_opt_set_pa_password(krb5_context context,
338					krb5_get_init_creds_opt *opt,
339					const char *password,
340					krb5_s2k_proc key_proc)
341{
342    krb5_error_code ret;
343    ret = require_ext_opt(context, opt, "init_creds_opt_set_pa_password");
344    if (ret)
345	return ret;
346    opt->opt_private->password = password;
347    opt->opt_private->key_proc = key_proc;
348    return 0;
349}
350
351krb5_error_code KRB5_LIB_FUNCTION
352krb5_get_init_creds_opt_set_pac_request(krb5_context context,
353					krb5_get_init_creds_opt *opt,
354					krb5_boolean req_pac)
355{
356    krb5_error_code ret;
357    ret = require_ext_opt(context, opt, "init_creds_opt_set_pac_req");
358    if (ret)
359	return ret;
360    opt->opt_private->req_pac = req_pac ?
361	KRB5_INIT_CREDS_TRISTATE_TRUE :
362	KRB5_INIT_CREDS_TRISTATE_FALSE;
363    return 0;
364}
365
366krb5_error_code KRB5_LIB_FUNCTION
367krb5_get_init_creds_opt_get_error(krb5_context context,
368				  krb5_get_init_creds_opt *opt,
369				  KRB_ERROR **error)
370{
371    krb5_error_code ret;
372
373    *error = NULL;
374
375    ret = require_ext_opt(context, opt, "init_creds_opt_get_error");
376    if (ret)
377	return ret;
378
379    if (opt->opt_private->error == NULL)
380	return 0;
381
382    *error = malloc(sizeof(**error));
383    if (*error == NULL) {
384	krb5_set_error_string(context, "malloc - out memory");
385	return ENOMEM;
386    }
387
388    ret = copy_KRB_ERROR(opt->opt_private->error, *error);
389    if (ret)
390	krb5_clear_error_string(context);
391
392    return 0;
393}
394
395krb5_error_code KRB5_LIB_FUNCTION
396krb5_get_init_creds_opt_set_addressless(krb5_context context,
397					krb5_get_init_creds_opt *opt,
398					krb5_boolean addressless)
399{
400    krb5_error_code ret;
401    ret = require_ext_opt(context, opt, "init_creds_opt_set_pac_req");
402    if (ret)
403	return ret;
404    if (addressless)
405	opt->opt_private->addressless = KRB5_INIT_CREDS_TRISTATE_TRUE;
406    else
407	opt->opt_private->addressless = KRB5_INIT_CREDS_TRISTATE_FALSE;
408    return 0;
409}
410
411krb5_error_code KRB5_LIB_FUNCTION
412krb5_get_init_creds_opt_set_canonicalize(krb5_context context,
413					 krb5_get_init_creds_opt *opt,
414					 krb5_boolean req)
415{
416    krb5_error_code ret;
417    ret = require_ext_opt(context, opt, "init_creds_opt_set_canonicalize");
418    if (ret)
419	return ret;
420    if (req)
421	opt->opt_private->flags |= KRB5_INIT_CREDS_CANONICALIZE;
422    else
423	opt->opt_private->flags &= ~KRB5_INIT_CREDS_CANONICALIZE;
424    return 0;
425}
426
427krb5_error_code KRB5_LIB_FUNCTION
428krb5_get_init_creds_opt_set_win2k(krb5_context context,
429				  krb5_get_init_creds_opt *opt,
430				  krb5_boolean req)
431{
432    krb5_error_code ret;
433    ret = require_ext_opt(context, opt, "init_creds_opt_set_win2k");
434    if (ret)
435	return ret;
436    if (req)
437	opt->opt_private->flags |= KRB5_INIT_CREDS_NO_C_CANON_CHECK;
438    else
439	opt->opt_private->flags &= ~KRB5_INIT_CREDS_NO_C_CANON_CHECK;
440    return 0;
441}
442
443