b34e3eb325c81ed41d85ec7065431ab16f26c764
[samba.git] / source4 / heimdal / lib / krb5 / init_creds.c
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 #undef __attribute__
39 #define __attribute__(x)
40
41 /**
42  * @page krb5_init_creds_intro The initial credential handing functions
43  * @section section_krb5_init_creds Initial credential
44  *
45  * Functions to get initial credentials: @ref krb5_credential .
46  */
47
48 /**
49  * Allocate a new krb5_get_init_creds_opt structure, free with
50  * krb5_get_init_creds_opt_free().
51  *
52  * @ingroup krb5_credential
53  */
54
55 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
56 krb5_get_init_creds_opt_alloc(krb5_context context,
57                               krb5_get_init_creds_opt **opt)
58 {
59     krb5_get_init_creds_opt *o;
60
61     *opt = NULL;
62     o = calloc(1, sizeof(*o));
63     if (o == NULL)
64         return krb5_enomem(context);
65
66     o->opt_private = calloc(1, sizeof(*o->opt_private));
67     if (o->opt_private == NULL) {
68         free(o);
69         return krb5_enomem(context);
70     }
71     o->opt_private->refcount = 1;
72     *opt = o;
73     return 0;
74 }
75
76 /**
77  * Free krb5_get_init_creds_opt structure.
78  *
79  * @ingroup krb5_credential
80  */
81
82 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
83 krb5_get_init_creds_opt_free(krb5_context context,
84                              krb5_get_init_creds_opt *opt)
85 {
86     if (opt == NULL || opt->opt_private == NULL)
87         return;
88     if (opt->opt_private->refcount < 1) /* abort ? */
89         return;
90     if (--opt->opt_private->refcount == 0) {
91         _krb5_get_init_creds_opt_free_pkinit(opt);
92         free(opt->opt_private);
93     }
94     memset(opt, 0, sizeof(*opt));
95     free(opt);
96 }
97
98 static int
99 get_config_time (krb5_context context,
100                  const char *realm,
101                  const char *name,
102                  int def)
103 {
104     int ret;
105
106     ret = krb5_config_get_time (context, NULL,
107                                 "realms",
108                                 realm,
109                                 name,
110                                 NULL);
111     if (ret >= 0)
112         return ret;
113     ret = krb5_config_get_time (context, NULL,
114                                 "libdefaults",
115                                 name,
116                                 NULL);
117     if (ret >= 0)
118         return ret;
119     return def;
120 }
121
122 static krb5_boolean
123 get_config_bool (krb5_context context,
124                  krb5_boolean def_value,
125                  const char *realm,
126                  const char *name)
127 {
128     krb5_boolean b;
129
130     b = krb5_config_get_bool_default(context, NULL, def_value,
131                                      "realms", realm, name, NULL);
132     if (b != def_value)
133         return b;
134     b = krb5_config_get_bool_default (context, NULL, def_value,
135                                       "libdefaults", name, NULL);
136     if (b != def_value)
137         return b;
138     return def_value;
139 }
140
141 /*
142  * set all the values in `opt' to the appropriate values for
143  * application `appname' (default to getprogname() if NULL), and realm
144  * `realm'.  First looks in [appdefaults] but falls back to
145  * [realms] or [libdefaults] for some of the values.
146  */
147
148 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
149 krb5_get_init_creds_opt_set_default_flags(krb5_context context,
150                                           const char *appname,
151                                           krb5_const_realm realm,
152                                           krb5_get_init_creds_opt *opt)
153 {
154     krb5_boolean b;
155     time_t t;
156
157     b = get_config_bool (context, KRB5_FORWARDABLE_DEFAULT,
158                          realm, "forwardable");
159     krb5_appdefault_boolean(context, appname, realm, "forwardable", b, &b);
160     krb5_get_init_creds_opt_set_forwardable(opt, b);
161
162     b = get_config_bool (context, FALSE, realm, "proxiable");
163     krb5_appdefault_boolean(context, appname, realm, "proxiable", b, &b);
164     krb5_get_init_creds_opt_set_proxiable (opt, b);
165
166     krb5_appdefault_time(context, appname, realm, "ticket_lifetime", 0, &t);
167     if (t == 0)
168         t = get_config_time (context, realm, "ticket_lifetime", 0);
169     if(t != 0)
170         krb5_get_init_creds_opt_set_tkt_life(opt, t);
171
172     krb5_appdefault_time(context, appname, realm, "renew_lifetime", 0, &t);
173     if (t == 0)
174         t = get_config_time (context, realm, "renew_lifetime", 0);
175     if(t != 0)
176         krb5_get_init_creds_opt_set_renew_life(opt, t);
177
178     krb5_appdefault_boolean(context, appname, realm, "no-addresses",
179                             KRB5_ADDRESSLESS_DEFAULT, &b);
180     krb5_get_init_creds_opt_set_addressless (context, opt, b);
181
182 #if 0
183     krb5_appdefault_boolean(context, appname, realm, "anonymous", FALSE, &b);
184     krb5_get_init_creds_opt_set_anonymous (opt, b);
185
186     krb5_get_init_creds_opt_set_etype_list(opt, enctype,
187                                            etype_str.num_strings);
188
189     krb5_get_init_creds_opt_set_salt(krb5_get_init_creds_opt *opt,
190                                      krb5_data *salt);
191
192     krb5_get_init_creds_opt_set_preauth_list(krb5_get_init_creds_opt *opt,
193                                              krb5_preauthtype *preauth_list,
194                                              int preauth_list_length);
195 #endif
196 }
197
198 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
199 krb5_get_init_creds_opt_set_change_password_prompt(krb5_get_init_creds_opt *opt,
200                                                    int change_password_prompt)
201 {
202         opt->flags |= KRB5_GET_INIT_CREDS_OPT_CHANGE_PASSWORD_PROMPT;
203         opt->change_password_prompt = change_password_prompt;
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         opt->opt_private->flags |= KRB5_INIT_CREDS_PKINIT_NO_KRBTGT_OTHERNAME_CHECK;
370     } else {
371         opt->opt_private->flags &= ~KRB5_INIT_CREDS_NO_C_CANON_CHECK;
372         opt->opt_private->flags &= ~KRB5_INIT_CREDS_NO_C_NO_EKU_CHECK;
373         opt->opt_private->flags &= ~KRB5_INIT_CREDS_PKINIT_NO_KRBTGT_OTHERNAME_CHECK;
374     }
375     return 0;
376 }
377
378
379 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
380 krb5_get_init_creds_opt_set_process_last_req(krb5_context context,
381                                              krb5_get_init_creds_opt *opt,
382                                              krb5_gic_process_last_req func,
383                                              void *ctx)
384 {
385     krb5_error_code ret;
386     ret = require_ext_opt(context, opt, "init_creds_opt_set_process_last_req");
387     if (ret)
388         return ret;
389
390     opt->opt_private->lr.func = func;
391     opt->opt_private->lr.ctx = ctx;
392
393     return 0;
394 }
395
396
397 #ifndef HEIMDAL_SMALLER
398
399 /**
400  * Deprecated: use krb5_get_init_creds_opt_alloc().
401  *
402  * The reason krb5_get_init_creds_opt_init() is deprecated is that
403  * krb5_get_init_creds_opt is a static structure and for ABI reason it
404  * can't grow, ie can't add new functionality.
405  *
406  * @ingroup krb5_deprecated
407  */
408
409 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
410 krb5_get_init_creds_opt_init(krb5_get_init_creds_opt *opt)
411     KRB5_DEPRECATED_FUNCTION("Use X instead")
412 {
413     memset (opt, 0, sizeof(*opt));
414 }
415
416 /**
417  * Deprecated: use the new krb5_init_creds_init() and
418  * krb5_init_creds_get_error().
419  *
420  * @ingroup krb5_deprecated
421  */
422
423 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
424 krb5_get_init_creds_opt_get_error(krb5_context context,
425                                   krb5_get_init_creds_opt *opt,
426                                   KRB_ERROR **error)
427     KRB5_DEPRECATED_FUNCTION("Use X instead")
428 {
429     *error = calloc(1, sizeof(**error));
430     if (*error == NULL)
431         return krb5_enomem(context);
432
433     return 0;
434 }
435
436 #endif /* HEIMDAL_SMALLER */