context.c revision 120945
1/*
2 * Copyright (c) 1997 - 2002 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#include <com_err.h>
36
37RCSID("$Id: context.c,v 1.83 2003/03/10 00:24:13 lha Exp $");
38
39#define INIT_FIELD(C, T, E, D, F)					\
40    (C)->E = krb5_config_get_ ## T ## _default ((C), NULL, (D), 	\
41						"libdefaults", F, NULL)
42
43/*
44 * Set the list of etypes `ret_etypes' from the configuration variable
45 * `name'
46 */
47
48static krb5_error_code
49set_etypes (krb5_context context,
50	    const char *name,
51	    krb5_enctype **ret_enctypes)
52{
53    char **etypes_str;
54    krb5_enctype *etypes = NULL;
55
56    etypes_str = krb5_config_get_strings(context, NULL, "libdefaults",
57					 name, NULL);
58    if(etypes_str){
59	int i, j, k;
60	for(i = 0; etypes_str[i]; i++);
61	etypes = malloc((i+1) * sizeof(*etypes));
62	if (etypes == NULL) {
63	    krb5_config_free_strings (etypes_str);
64	    krb5_set_error_string (context, "malloc: out of memory");
65	    return ENOMEM;
66	}
67	for(j = 0, k = 0; j < i; j++) {
68	    if(krb5_string_to_enctype(context, etypes_str[j], &etypes[k]) == 0)
69		k++;
70	}
71	etypes[k] = ETYPE_NULL;
72	krb5_config_free_strings(etypes_str);
73    }
74    *ret_enctypes = etypes;
75    return 0;
76}
77
78/*
79 * read variables from the configuration file and set in `context'
80 */
81
82static krb5_error_code
83init_context_from_config_file(krb5_context context)
84{
85    krb5_error_code ret;
86    const char * tmp;
87    krb5_enctype *tmptypes;
88
89    INIT_FIELD(context, time, max_skew, 5 * 60, "clockskew");
90    INIT_FIELD(context, time, kdc_timeout, 3, "kdc_timeout");
91    INIT_FIELD(context, int, max_retries, 3, "max_retries");
92
93    INIT_FIELD(context, string, http_proxy, NULL, "http_proxy");
94
95    ret = set_etypes (context, "default_etypes", &tmptypes);
96    if(ret)
97	return ret;
98    free(context->etypes);
99    context->etypes = tmptypes;
100
101    ret = set_etypes (context, "default_etypes_des", &tmptypes);
102    if(ret)
103	return ret;
104    free(context->etypes_des);
105    context->etypes_des = tmptypes;
106
107    /* default keytab name */
108    tmp = NULL;
109    if(!issuid())
110	tmp = getenv("KRB5_KTNAME");
111    if(tmp != NULL)
112	context->default_keytab = tmp;
113    else
114	INIT_FIELD(context, string, default_keytab,
115		   KEYTAB_DEFAULT, "default_keytab_name");
116
117    INIT_FIELD(context, string, default_keytab_modify,
118	       NULL, "default_keytab_modify_name");
119
120    INIT_FIELD(context, string, time_fmt,
121	       "%Y-%m-%dT%H:%M:%S", "time_format");
122
123    INIT_FIELD(context, string, date_fmt,
124	       "%Y-%m-%d", "date_format");
125
126    INIT_FIELD(context, bool, log_utc,
127	       FALSE, "log_utc");
128
129
130
131    /* init dns-proxy slime */
132    tmp = krb5_config_get_string(context, NULL, "libdefaults",
133				 "dns_proxy", NULL);
134    if(tmp)
135	roken_gethostby_setup(context->http_proxy, tmp);
136    krb5_free_host_realm (context, context->default_realms);
137    context->default_realms = NULL;
138
139    {
140	krb5_addresses addresses;
141	char **adr, **a;
142
143	krb5_set_extra_addresses(context, NULL);
144	adr = krb5_config_get_strings(context, NULL,
145				      "libdefaults",
146				      "extra_addresses",
147				      NULL);
148	memset(&addresses, 0, sizeof(addresses));
149	for(a = adr; a && *a; a++) {
150	    ret = krb5_parse_address(context, *a, &addresses);
151	    if (ret == 0) {
152		krb5_add_extra_addresses(context, &addresses);
153		krb5_free_addresses(context, &addresses);
154	    }
155	}
156	krb5_config_free_strings(adr);
157
158	krb5_set_ignore_addresses(context, NULL);
159	adr = krb5_config_get_strings(context, NULL,
160				      "libdefaults",
161				      "ignore_addresses",
162				      NULL);
163	memset(&addresses, 0, sizeof(addresses));
164	for(a = adr; a && *a; a++) {
165	    ret = krb5_parse_address(context, *a, &addresses);
166	    if (ret == 0) {
167		krb5_add_ignore_addresses(context, &addresses);
168		krb5_free_addresses(context, &addresses);
169	    }
170	}
171	krb5_config_free_strings(adr);
172    }
173
174    INIT_FIELD(context, bool, scan_interfaces, TRUE, "scan_interfaces");
175    INIT_FIELD(context, int, fcache_vno, 0, "fcache_version");
176    /* prefer dns_lookup_kdc over srv_lookup. */
177    INIT_FIELD(context, bool, srv_lookup, TRUE, "srv_lookup");
178    INIT_FIELD(context, bool, srv_lookup, context->srv_lookup, "dns_lookup_kdc");
179    context->default_cc_name = NULL;
180    return 0;
181}
182
183krb5_error_code
184krb5_init_context(krb5_context *context)
185{
186    krb5_context p;
187    krb5_error_code ret;
188    char **files;
189
190    p = calloc(1, sizeof(*p));
191    if(!p)
192	return ENOMEM;
193
194    ret = krb5_get_default_config_files(&files);
195    if(ret)
196	goto out;
197    ret = krb5_set_config_files(p, files);
198    krb5_free_config_files(files);
199    if(ret)
200	goto out;
201
202    /* init error tables */
203    krb5_init_ets(p);
204
205    p->cc_ops = NULL;
206    p->num_cc_ops = 0;
207    krb5_cc_register(p, &krb5_fcc_ops, TRUE);
208    krb5_cc_register(p, &krb5_mcc_ops, TRUE);
209
210    p->num_kt_types = 0;
211    p->kt_types     = NULL;
212    krb5_kt_register (p, &krb5_fkt_ops);
213    krb5_kt_register (p, &krb5_mkt_ops);
214    krb5_kt_register (p, &krb5_akf_ops);
215    krb5_kt_register (p, &krb4_fkt_ops);
216    krb5_kt_register (p, &krb5_srvtab_fkt_ops);
217    krb5_kt_register (p, &krb5_any_ops);
218
219out:
220    if(ret) {
221	krb5_free_context(p);
222	p = NULL;
223    }
224    *context = p;
225    return ret;
226}
227
228void
229krb5_free_context(krb5_context context)
230{
231    if (context->default_cc_name)
232	free(context->default_cc_name);
233    free(context->etypes);
234    free(context->etypes_des);
235    krb5_free_host_realm (context, context->default_realms);
236    krb5_config_file_free (context, context->cf);
237    free_error_table (context->et_list);
238    free(context->cc_ops);
239    free(context->kt_types);
240    krb5_clear_error_string(context);
241    if(context->warn_dest != NULL)
242	krb5_closelog(context, context->warn_dest);
243    krb5_set_extra_addresses(context, NULL);
244    krb5_set_ignore_addresses(context, NULL);
245    free(context);
246}
247
248krb5_error_code
249krb5_set_config_files(krb5_context context, char **filenames)
250{
251    krb5_error_code ret;
252    krb5_config_binding *tmp = NULL;
253    while(filenames != NULL && *filenames != NULL && **filenames != '\0') {
254	ret = krb5_config_parse_file_multi(context, *filenames, &tmp);
255	if(ret != 0 && ret != ENOENT) {
256	    krb5_config_file_free(context, tmp);
257	    return ret;
258	}
259	filenames++;
260    }
261#if 0
262    /* with this enabled and if there are no config files, Kerberos is
263       considererd disabled */
264    if(tmp == NULL)
265	return ENXIO;
266#endif
267    krb5_config_file_free(context, context->cf);
268    context->cf = tmp;
269    ret = init_context_from_config_file(context);
270    return ret;
271}
272
273krb5_error_code
274krb5_get_default_config_files(char ***pfilenames)
275{
276    const char *p, *q;
277    char **pp;
278    int n, i;
279
280    const char *files = NULL;
281    if (pfilenames == NULL)
282        return EINVAL;
283    if(!issuid())
284	files = getenv("KRB5_CONFIG");
285    if (files == NULL)
286	files = krb5_config_file;
287
288    for(n = 0, p = files; strsep_copy(&p, ":", NULL, 0) != -1; n++);
289    pp = malloc((n + 1) * sizeof(*pp));
290    if(pp == NULL)
291	return ENOMEM;
292
293    n = 0;
294    p = files;
295    while(1) {
296	ssize_t l;
297	q = p;
298	l = strsep_copy(&q, ":", NULL, 0);
299	if(l == -1)
300	    break;
301	pp[n] = malloc(l + 1);
302	if(pp[n] == NULL) {
303	    krb5_free_config_files(pp);
304	    return ENOMEM;
305	}
306	l = strsep_copy(&p, ":", pp[n], l + 1);
307	for(i = 0; i < n; i++)
308	    if(strcmp(pp[i], pp[n]) == 0) {
309		free(pp[n]);
310		goto skip;
311	    }
312	n++;
313    skip:;
314    }
315    pp[n] = NULL;
316    *pfilenames = pp;
317    return 0;
318}
319
320void
321krb5_free_config_files(char **filenames)
322{
323    char **p;
324    for(p = filenames; *p != NULL; p++)
325	free(*p);
326    free(filenames);
327}
328
329/*
330 * set `etype' to a malloced list of the default enctypes
331 */
332
333static krb5_error_code
334default_etypes(krb5_context context, krb5_enctype **etype)
335{
336    krb5_enctype p[] = {
337	ETYPE_DES3_CBC_SHA1,
338	ETYPE_DES3_CBC_MD5,
339	ETYPE_ARCFOUR_HMAC_MD5,
340	ETYPE_DES_CBC_MD5,
341	ETYPE_DES_CBC_MD4,
342	ETYPE_DES_CBC_CRC,
343	ETYPE_NULL
344    };
345
346    *etype = malloc(sizeof(p));
347    if(*etype == NULL) {
348	krb5_set_error_string (context, "malloc: out of memory");
349	return ENOMEM;
350    }
351    memcpy(*etype, p, sizeof(p));
352    return 0;
353}
354
355krb5_error_code
356krb5_set_default_in_tkt_etypes(krb5_context context,
357			       const krb5_enctype *etypes)
358{
359    int i;
360    krb5_enctype *p = NULL;
361
362    if(etypes) {
363	for (i = 0; etypes[i]; ++i)
364	    if(!krb5_enctype_valid(context, etypes[i])) {
365		krb5_set_error_string(context, "enctype %d not supported",
366				      etypes[i]);
367		return KRB5_PROG_ETYPE_NOSUPP;
368	    }
369	++i;
370	ALLOC(p, i);
371	if(!p) {
372	    krb5_set_error_string (context, "malloc: out of memory");
373	    return ENOMEM;
374	}
375	memmove(p, etypes, i * sizeof(krb5_enctype));
376    }
377    if(context->etypes)
378	free(context->etypes);
379    context->etypes = p;
380    return 0;
381}
382
383
384krb5_error_code
385krb5_get_default_in_tkt_etypes(krb5_context context,
386			       krb5_enctype **etypes)
387{
388  krb5_enctype *p;
389  int i;
390  krb5_error_code ret;
391
392  if(context->etypes) {
393    for(i = 0; context->etypes[i]; i++);
394    ++i;
395    ALLOC(p, i);
396    if(!p) {
397      krb5_set_error_string (context, "malloc: out of memory");
398      return ENOMEM;
399    }
400    memmove(p, context->etypes, i * sizeof(krb5_enctype));
401  } else {
402    ret = default_etypes(context, &p);
403    if (ret)
404      return ret;
405  }
406  *etypes = p;
407  return 0;
408}
409
410const char *
411krb5_get_err_text(krb5_context context, krb5_error_code code)
412{
413    const char *p = NULL;
414    if(context != NULL)
415	p = com_right(context->et_list, code);
416    if(p == NULL)
417	p = strerror(code);
418    return p;
419}
420
421void
422krb5_init_ets(krb5_context context)
423{
424    if(context->et_list == NULL){
425	krb5_add_et_list(context, initialize_krb5_error_table_r);
426	krb5_add_et_list(context, initialize_asn1_error_table_r);
427	krb5_add_et_list(context, initialize_heim_error_table_r);
428	krb5_add_et_list(context, initialize_k524_error_table_r);
429    }
430}
431
432void
433krb5_set_use_admin_kdc (krb5_context context, krb5_boolean flag)
434{
435    context->use_admin_kdc = flag;
436}
437
438krb5_boolean
439krb5_get_use_admin_kdc (krb5_context context)
440{
441    return context->use_admin_kdc;
442}
443
444krb5_error_code
445krb5_add_extra_addresses(krb5_context context, krb5_addresses *addresses)
446{
447
448    if(context->extra_addresses)
449	return krb5_append_addresses(context,
450				     context->extra_addresses, addresses);
451    else
452	return krb5_set_extra_addresses(context, addresses);
453}
454
455krb5_error_code
456krb5_set_extra_addresses(krb5_context context, const krb5_addresses *addresses)
457{
458    if(context->extra_addresses)
459	krb5_free_addresses(context, context->extra_addresses);
460
461    if(addresses == NULL) {
462	if(context->extra_addresses != NULL) {
463	    free(context->extra_addresses);
464	    context->extra_addresses = NULL;
465	}
466	return 0;
467    }
468    if(context->extra_addresses == NULL) {
469	context->extra_addresses = malloc(sizeof(*context->extra_addresses));
470	if(context->extra_addresses == NULL) {
471	    krb5_set_error_string (context, "malloc: out of memory");
472	    return ENOMEM;
473	}
474    }
475    return krb5_copy_addresses(context, addresses, context->extra_addresses);
476}
477
478krb5_error_code
479krb5_get_extra_addresses(krb5_context context, krb5_addresses *addresses)
480{
481    if(context->extra_addresses == NULL) {
482	memset(addresses, 0, sizeof(*addresses));
483	return 0;
484    }
485    return krb5_copy_addresses(context,context->extra_addresses, addresses);
486}
487
488krb5_error_code
489krb5_add_ignore_addresses(krb5_context context, krb5_addresses *addresses)
490{
491
492    if(context->ignore_addresses)
493	return krb5_append_addresses(context,
494				     context->ignore_addresses, addresses);
495    else
496	return krb5_set_ignore_addresses(context, addresses);
497}
498
499krb5_error_code
500krb5_set_ignore_addresses(krb5_context context, const krb5_addresses *addresses)
501{
502    if(context->ignore_addresses)
503	krb5_free_addresses(context, context->ignore_addresses);
504    if(addresses == NULL) {
505	if(context->ignore_addresses != NULL) {
506	    free(context->ignore_addresses);
507	    context->ignore_addresses = NULL;
508	}
509	return 0;
510    }
511    if(context->ignore_addresses == NULL) {
512	context->ignore_addresses = malloc(sizeof(*context->ignore_addresses));
513	if(context->ignore_addresses == NULL) {
514	    krb5_set_error_string (context, "malloc: out of memory");
515	    return ENOMEM;
516	}
517    }
518    return krb5_copy_addresses(context, addresses, context->ignore_addresses);
519}
520
521krb5_error_code
522krb5_get_ignore_addresses(krb5_context context, krb5_addresses *addresses)
523{
524    if(context->ignore_addresses == NULL) {
525	memset(addresses, 0, sizeof(*addresses));
526	return 0;
527    }
528    return krb5_copy_addresses(context, context->ignore_addresses, addresses);
529}
530
531krb5_error_code
532krb5_set_fcache_version(krb5_context context, int version)
533{
534    context->fcache_vno = version;
535    return 0;
536}
537
538krb5_error_code
539krb5_get_fcache_version(krb5_context context, int *version)
540{
541    *version = context->fcache_vno;
542    return 0;
543}
544