155682Smarkm/*
2233294Sstas * Copyright (c) 1997 - 2004 Kungliga Tekniska H��gskolan
3178825Sdfr * (Royal Institute of Technology, Stockholm, Sweden).
4178825Sdfr * All rights reserved.
555682Smarkm *
6233294Sstas * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
7233294Sstas *
8178825Sdfr * Redistribution and use in source and binary forms, with or without
9178825Sdfr * modification, are permitted provided that the following conditions
10178825Sdfr * are met:
1155682Smarkm *
12178825Sdfr * 1. Redistributions of source code must retain the above copyright
13178825Sdfr *    notice, this list of conditions and the following disclaimer.
1455682Smarkm *
15178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright
16178825Sdfr *    notice, this list of conditions and the following disclaimer in the
17178825Sdfr *    documentation and/or other materials provided with the distribution.
1855682Smarkm *
19178825Sdfr * 3. Neither the name of the Institute nor the names of its contributors
20178825Sdfr *    may be used to endorse or promote products derived from this software
21178825Sdfr *    without specific prior written permission.
2255682Smarkm *
23178825Sdfr * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26178825Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33178825Sdfr * SUCH DAMAGE.
3455682Smarkm */
3555682Smarkm
3655682Smarkm#include "krb5_locl.h"
3755682Smarkm
38233294Sstas#undef __attribute__
39233294Sstas#define __attribute__(x)
4055682Smarkm
41233294Sstas/**
42233294Sstas * @page krb5_init_creds_intro The initial credential handing functions
43233294Sstas * @section section_krb5_init_creds Initial credential
44233294Sstas *
45233294Sstas * Functions to get initial credentials: @ref krb5_credential .
46233294Sstas */
4755682Smarkm
48233294Sstas/**
49233294Sstas * Allocate a new krb5_get_init_creds_opt structure, free with
50233294Sstas * krb5_get_init_creds_opt_free().
51233294Sstas *
52233294Sstas * @ingroup krb5_credential
53233294Sstas */
54233294Sstas
55233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
56233294Sstaskrb5_get_init_creds_opt_alloc(krb5_context context,
57178825Sdfr			      krb5_get_init_creds_opt **opt)
58178825Sdfr{
59178825Sdfr    krb5_get_init_creds_opt *o;
60233294Sstas
61178825Sdfr    *opt = NULL;
62178825Sdfr    o = calloc(1, sizeof(*o));
63178825Sdfr    if (o == NULL) {
64233294Sstas	krb5_set_error_message(context, ENOMEM,
65233294Sstas			       N_("malloc: out of memory", ""));
66178825Sdfr	return ENOMEM;
67178825Sdfr    }
68233294Sstas
69178825Sdfr    o->opt_private = calloc(1, sizeof(*o->opt_private));
70178825Sdfr    if (o->opt_private == NULL) {
71233294Sstas	krb5_set_error_message(context, ENOMEM,
72233294Sstas			       N_("malloc: out of memory", ""));
73178825Sdfr	free(o);
74178825Sdfr	return ENOMEM;
75178825Sdfr    }
76178825Sdfr    o->opt_private->refcount = 1;
77178825Sdfr    *opt = o;
78178825Sdfr    return 0;
79178825Sdfr}
80178825Sdfr
81233294Sstas/**
82233294Sstas * Free krb5_get_init_creds_opt structure.
83233294Sstas *
84233294Sstas * @ingroup krb5_credential
85233294Sstas */
86178825Sdfr
87233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL
88178825Sdfrkrb5_get_init_creds_opt_free(krb5_context context,
89178825Sdfr			     krb5_get_init_creds_opt *opt)
90178825Sdfr{
91178825Sdfr    if (opt == NULL || opt->opt_private == NULL)
92178825Sdfr	return;
93178825Sdfr    if (opt->opt_private->refcount < 1) /* abort ? */
94178825Sdfr	return;
95178825Sdfr    if (--opt->opt_private->refcount == 0) {
96178825Sdfr	_krb5_get_init_creds_opt_free_pkinit(opt);
97178825Sdfr	free(opt->opt_private);
98178825Sdfr    }
99178825Sdfr    memset(opt, 0, sizeof(*opt));
100178825Sdfr    free(opt);
101178825Sdfr}
102178825Sdfr
10390926Snectarstatic int
10490926Snectarget_config_time (krb5_context context,
10590926Snectar		 const char *realm,
10690926Snectar		 const char *name,
10790926Snectar		 int def)
10890926Snectar{
10990926Snectar    int ret;
11090926Snectar
11190926Snectar    ret = krb5_config_get_time (context, NULL,
11290926Snectar				"realms",
11390926Snectar				realm,
11490926Snectar				name,
11590926Snectar				NULL);
11690926Snectar    if (ret >= 0)
11790926Snectar	return ret;
11890926Snectar    ret = krb5_config_get_time (context, NULL,
11990926Snectar				"libdefaults",
12090926Snectar				name,
12190926Snectar				NULL);
12290926Snectar    if (ret >= 0)
12390926Snectar	return ret;
12490926Snectar    return def;
12590926Snectar}
12690926Snectar
12790926Snectarstatic krb5_boolean
12890926Snectarget_config_bool (krb5_context context,
129233294Sstas		 krb5_boolean def_value,
13090926Snectar		 const char *realm,
13190926Snectar		 const char *name)
13290926Snectar{
133233294Sstas    krb5_boolean b;
134233294Sstas
135233294Sstas    b = krb5_config_get_bool_default(context, NULL, def_value,
136233294Sstas				     "realms", realm, name, NULL);
137233294Sstas    if (b != def_value)
138233294Sstas	return b;
139233294Sstas    b = krb5_config_get_bool_default (context, NULL, def_value,
140233294Sstas				      "libdefaults", name, NULL);
141233294Sstas    if (b != def_value)
142233294Sstas	return b;
143233294Sstas    return def_value;
14490926Snectar}
14590926Snectar
14690926Snectar/*
14790926Snectar * set all the values in `opt' to the appropriate values for
14890926Snectar * application `appname' (default to getprogname() if NULL), and realm
14990926Snectar * `realm'.  First looks in [appdefaults] but falls back to
15090926Snectar * [realms] or [libdefaults] for some of the values.
15190926Snectar */
15290926Snectar
153233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL
15472445Sassarkrb5_get_init_creds_opt_set_default_flags(krb5_context context,
155178825Sdfr					  const char *appname,
15690926Snectar					  krb5_const_realm realm,
15772445Sassar					  krb5_get_init_creds_opt *opt)
15872445Sassar{
15972445Sassar    krb5_boolean b;
16072445Sassar    time_t t;
16172445Sassar
162233294Sstas    b = get_config_bool (context, KRB5_FORWARDABLE_DEFAULT,
163233294Sstas			 realm, "forwardable");
16490926Snectar    krb5_appdefault_boolean(context, appname, realm, "forwardable", b, &b);
16572445Sassar    krb5_get_init_creds_opt_set_forwardable(opt, b);
16672445Sassar
167233294Sstas    b = get_config_bool (context, FALSE, realm, "proxiable");
16890926Snectar    krb5_appdefault_boolean(context, appname, realm, "proxiable", b, &b);
16972445Sassar    krb5_get_init_creds_opt_set_proxiable (opt, b);
17072445Sassar
17190926Snectar    krb5_appdefault_time(context, appname, realm, "ticket_lifetime", 0, &t);
17290926Snectar    if (t == 0)
17390926Snectar	t = get_config_time (context, realm, "ticket_lifetime", 0);
17472445Sassar    if(t != 0)
17572445Sassar	krb5_get_init_creds_opt_set_tkt_life(opt, t);
176178825Sdfr
17790926Snectar    krb5_appdefault_time(context, appname, realm, "renew_lifetime", 0, &t);
17890926Snectar    if (t == 0)
17990926Snectar	t = get_config_time (context, realm, "renew_lifetime", 0);
18072445Sassar    if(t != 0)
18172445Sassar	krb5_get_init_creds_opt_set_renew_life(opt, t);
18272445Sassar
183233294Sstas    krb5_appdefault_boolean(context, appname, realm, "no-addresses",
184178825Sdfr			    KRB5_ADDRESSLESS_DEFAULT, &b);
185178825Sdfr    krb5_get_init_creds_opt_set_addressless (context, opt, b);
18690926Snectar
18772445Sassar#if 0
18872445Sassar    krb5_appdefault_boolean(context, appname, realm, "anonymous", FALSE, &b);
18972445Sassar    krb5_get_init_creds_opt_set_anonymous (opt, b);
19072445Sassar
191178825Sdfr    krb5_get_init_creds_opt_set_etype_list(opt, enctype,
19272445Sassar					   etype_str.num_strings);
19372445Sassar
19472445Sassar    krb5_get_init_creds_opt_set_salt(krb5_get_init_creds_opt *opt,
19572445Sassar				     krb5_data *salt);
19672445Sassar
19772445Sassar    krb5_get_init_creds_opt_set_preauth_list(krb5_get_init_creds_opt *opt,
19872445Sassar					     krb5_preauthtype *preauth_list,
19972445Sassar					     int preauth_list_length);
20072445Sassar#endif
20172445Sassar}
20272445Sassar
20372445Sassar
204233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL
20555682Smarkmkrb5_get_init_creds_opt_set_tkt_life(krb5_get_init_creds_opt *opt,
20655682Smarkm				     krb5_deltat tkt_life)
20755682Smarkm{
20855682Smarkm    opt->flags |= KRB5_GET_INIT_CREDS_OPT_TKT_LIFE;
20955682Smarkm    opt->tkt_life = tkt_life;
21055682Smarkm}
21155682Smarkm
212233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL
21355682Smarkmkrb5_get_init_creds_opt_set_renew_life(krb5_get_init_creds_opt *opt,
21455682Smarkm				       krb5_deltat renew_life)
21555682Smarkm{
21655682Smarkm    opt->flags |= KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE;
21755682Smarkm    opt->renew_life = renew_life;
21855682Smarkm}
21955682Smarkm
220233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL
22155682Smarkmkrb5_get_init_creds_opt_set_forwardable(krb5_get_init_creds_opt *opt,
22255682Smarkm					int forwardable)
22355682Smarkm{
22455682Smarkm    opt->flags |= KRB5_GET_INIT_CREDS_OPT_FORWARDABLE;
22555682Smarkm    opt->forwardable = forwardable;
22655682Smarkm}
22755682Smarkm
228233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL
22955682Smarkmkrb5_get_init_creds_opt_set_proxiable(krb5_get_init_creds_opt *opt,
23055682Smarkm				      int proxiable)
23155682Smarkm{
23255682Smarkm    opt->flags |= KRB5_GET_INIT_CREDS_OPT_PROXIABLE;
23355682Smarkm    opt->proxiable = proxiable;
23455682Smarkm}
23555682Smarkm
236233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL
23755682Smarkmkrb5_get_init_creds_opt_set_etype_list(krb5_get_init_creds_opt *opt,
23855682Smarkm				       krb5_enctype *etype_list,
23955682Smarkm				       int etype_list_length)
24055682Smarkm{
24155682Smarkm    opt->flags |= KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST;
24255682Smarkm    opt->etype_list = etype_list;
24355682Smarkm    opt->etype_list_length = etype_list_length;
24455682Smarkm}
24555682Smarkm
246233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL
24755682Smarkmkrb5_get_init_creds_opt_set_address_list(krb5_get_init_creds_opt *opt,
24855682Smarkm					 krb5_addresses *addresses)
24955682Smarkm{
25055682Smarkm    opt->flags |= KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST;
25155682Smarkm    opt->address_list = addresses;
25255682Smarkm}
25355682Smarkm
254233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL
25555682Smarkmkrb5_get_init_creds_opt_set_preauth_list(krb5_get_init_creds_opt *opt,
25655682Smarkm					 krb5_preauthtype *preauth_list,
25755682Smarkm					 int preauth_list_length)
25855682Smarkm{
25955682Smarkm    opt->flags |= KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST;
26055682Smarkm    opt->preauth_list_length = preauth_list_length;
26155682Smarkm    opt->preauth_list = preauth_list;
26255682Smarkm}
26355682Smarkm
264233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL
26555682Smarkmkrb5_get_init_creds_opt_set_salt(krb5_get_init_creds_opt *opt,
26655682Smarkm				 krb5_data *salt)
26755682Smarkm{
26855682Smarkm    opt->flags |= KRB5_GET_INIT_CREDS_OPT_SALT;
26955682Smarkm    opt->salt = salt;
27055682Smarkm}
27172445Sassar
272233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL
27372445Sassarkrb5_get_init_creds_opt_set_anonymous(krb5_get_init_creds_opt *opt,
27472445Sassar				      int anonymous)
27572445Sassar{
27672445Sassar    opt->flags |= KRB5_GET_INIT_CREDS_OPT_ANONYMOUS;
27772445Sassar    opt->anonymous = anonymous;
27872445Sassar}
279178825Sdfr
280178825Sdfrstatic krb5_error_code
281178825Sdfrrequire_ext_opt(krb5_context context,
282178825Sdfr		krb5_get_init_creds_opt *opt,
283178825Sdfr		const char *type)
284178825Sdfr{
285178825Sdfr    if (opt->opt_private == NULL) {
286233294Sstas	krb5_set_error_message(context, EINVAL,
287233294Sstas			       N_("%s on non extendable opt", ""), type);
288178825Sdfr	return EINVAL;
289178825Sdfr    }
290178825Sdfr    return 0;
291178825Sdfr}
292178825Sdfr
293233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
294178825Sdfrkrb5_get_init_creds_opt_set_pa_password(krb5_context context,
295178825Sdfr					krb5_get_init_creds_opt *opt,
296178825Sdfr					const char *password,
297178825Sdfr					krb5_s2k_proc key_proc)
298178825Sdfr{
299178825Sdfr    krb5_error_code ret;
300178825Sdfr    ret = require_ext_opt(context, opt, "init_creds_opt_set_pa_password");
301178825Sdfr    if (ret)
302178825Sdfr	return ret;
303178825Sdfr    opt->opt_private->password = password;
304178825Sdfr    opt->opt_private->key_proc = key_proc;
305178825Sdfr    return 0;
306178825Sdfr}
307178825Sdfr
308233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
309178825Sdfrkrb5_get_init_creds_opt_set_pac_request(krb5_context context,
310178825Sdfr					krb5_get_init_creds_opt *opt,
311178825Sdfr					krb5_boolean req_pac)
312178825Sdfr{
313178825Sdfr    krb5_error_code ret;
314178825Sdfr    ret = require_ext_opt(context, opt, "init_creds_opt_set_pac_req");
315178825Sdfr    if (ret)
316178825Sdfr	return ret;
317178825Sdfr    opt->opt_private->req_pac = req_pac ?
318178825Sdfr	KRB5_INIT_CREDS_TRISTATE_TRUE :
319178825Sdfr	KRB5_INIT_CREDS_TRISTATE_FALSE;
320178825Sdfr    return 0;
321178825Sdfr}
322178825Sdfr
323233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
324178825Sdfrkrb5_get_init_creds_opt_set_addressless(krb5_context context,
325178825Sdfr					krb5_get_init_creds_opt *opt,
326178825Sdfr					krb5_boolean addressless)
327178825Sdfr{
328178825Sdfr    krb5_error_code ret;
329178825Sdfr    ret = require_ext_opt(context, opt, "init_creds_opt_set_pac_req");
330178825Sdfr    if (ret)
331178825Sdfr	return ret;
332178825Sdfr    if (addressless)
333178825Sdfr	opt->opt_private->addressless = KRB5_INIT_CREDS_TRISTATE_TRUE;
334178825Sdfr    else
335178825Sdfr	opt->opt_private->addressless = KRB5_INIT_CREDS_TRISTATE_FALSE;
336178825Sdfr    return 0;
337178825Sdfr}
338178825Sdfr
339233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
340178825Sdfrkrb5_get_init_creds_opt_set_canonicalize(krb5_context context,
341178825Sdfr					 krb5_get_init_creds_opt *opt,
342178825Sdfr					 krb5_boolean req)
343178825Sdfr{
344178825Sdfr    krb5_error_code ret;
345178825Sdfr    ret = require_ext_opt(context, opt, "init_creds_opt_set_canonicalize");
346178825Sdfr    if (ret)
347178825Sdfr	return ret;
348178825Sdfr    if (req)
349178825Sdfr	opt->opt_private->flags |= KRB5_INIT_CREDS_CANONICALIZE;
350178825Sdfr    else
351178825Sdfr	opt->opt_private->flags &= ~KRB5_INIT_CREDS_CANONICALIZE;
352178825Sdfr    return 0;
353178825Sdfr}
354178825Sdfr
355233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
356178825Sdfrkrb5_get_init_creds_opt_set_win2k(krb5_context context,
357178825Sdfr				  krb5_get_init_creds_opt *opt,
358178825Sdfr				  krb5_boolean req)
359178825Sdfr{
360178825Sdfr    krb5_error_code ret;
361178825Sdfr    ret = require_ext_opt(context, opt, "init_creds_opt_set_win2k");
362178825Sdfr    if (ret)
363178825Sdfr	return ret;
364233294Sstas    if (req) {
365178825Sdfr	opt->opt_private->flags |= KRB5_INIT_CREDS_NO_C_CANON_CHECK;
366233294Sstas	opt->opt_private->flags |= KRB5_INIT_CREDS_NO_C_NO_EKU_CHECK;
367233294Sstas    } else {
368178825Sdfr	opt->opt_private->flags &= ~KRB5_INIT_CREDS_NO_C_CANON_CHECK;
369233294Sstas	opt->opt_private->flags &= ~KRB5_INIT_CREDS_NO_C_NO_EKU_CHECK;
370233294Sstas    }
371178825Sdfr    return 0;
372178825Sdfr}
373178825Sdfr
374233294Sstas
375233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
376233294Sstaskrb5_get_init_creds_opt_set_process_last_req(krb5_context context,
377233294Sstas					     krb5_get_init_creds_opt *opt,
378233294Sstas					     krb5_gic_process_last_req func,
379233294Sstas					     void *ctx)
380233294Sstas{
381233294Sstas    krb5_error_code ret;
382233294Sstas    ret = require_ext_opt(context, opt, "init_creds_opt_set_win2k");
383233294Sstas    if (ret)
384233294Sstas	return ret;
385233294Sstas
386233294Sstas    opt->opt_private->lr.func = func;
387233294Sstas    opt->opt_private->lr.ctx = ctx;
388233294Sstas
389233294Sstas    return 0;
390233294Sstas}
391233294Sstas
392233294Sstas
393233294Sstas#ifndef HEIMDAL_SMALLER
394233294Sstas
395233294Sstas/**
396233294Sstas * Deprecated: use krb5_get_init_creds_opt_alloc().
397233294Sstas *
398233294Sstas * The reason krb5_get_init_creds_opt_init() is deprecated is that
399233294Sstas * krb5_get_init_creds_opt is a static structure and for ABI reason it
400233294Sstas * can't grow, ie can't add new functionality.
401233294Sstas *
402233294Sstas * @ingroup krb5_deprecated
403233294Sstas */
404233294Sstas
405233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL
406233294Sstaskrb5_get_init_creds_opt_init(krb5_get_init_creds_opt *opt)
407233294Sstas    KRB5_DEPRECATED_FUNCTION("Use X instead")
408233294Sstas{
409233294Sstas    memset (opt, 0, sizeof(*opt));
410233294Sstas}
411233294Sstas
412233294Sstas/**
413233294Sstas * Deprecated: use the new krb5_init_creds_init() and
414233294Sstas * krb5_init_creds_get_error().
415233294Sstas *
416233294Sstas * @ingroup krb5_deprecated
417233294Sstas */
418233294Sstas
419233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
420233294Sstaskrb5_get_init_creds_opt_get_error(krb5_context context,
421233294Sstas				  krb5_get_init_creds_opt *opt,
422233294Sstas				  KRB_ERROR **error)
423233294Sstas    KRB5_DEPRECATED_FUNCTION("Use X instead")
424233294Sstas{
425233294Sstas    *error = calloc(1, sizeof(**error));
426233294Sstas    if (*error == NULL) {
427233294Sstas	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
428233294Sstas	return ENOMEM;
429233294Sstas    }
430233294Sstas
431233294Sstas    return 0;
432233294Sstas}
433233294Sstas
434233294Sstas#endif /* HEIMDAL_SMALLER */
435