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