1/*
2 * COPYRIGHT (C) 2006,2007
3 * THE REGENTS OF THE UNIVERSITY OF MICHIGAN
4 * ALL RIGHTS RESERVED
5 *
6 * Permission is granted to use, copy, create derivative works
7 * and redistribute this software and such derivative works
8 * for any purpose, so long as the name of The University of
9 * Michigan is not used in any advertising or publicity
10 * pertaining to the use of distribution of this software
11 * without specific, written prior authorization.  If the
12 * above copyright notice or any other identification of the
13 * University of Michigan is included in any copy of any
14 * portion of this software, then the disclaimer below must
15 * also be included.
16 *
17 * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
18 * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
19 * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
20 * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
21 * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
22 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
23 * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
24 * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
25 * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
26 * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
27 * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGES.
29 */
30
31#include <stdio.h>
32#include <stdlib.h>
33#include <errno.h>
34#include <string.h>
35
36#include "k5-int.h"
37#include "pkinit.h"
38
39/*
40 * Routines for handling profile [config file] options
41 */
42
43/* Forward prototypes */
44static int _krb5_conf_boolean(const char *s);
45
46/*
47 * XXX
48 * The following is duplicated verbatim from src/lib/krb5/krb/get_in_tkt.c,
49 * which is duplicated from somewhere else. :-/
50 * XXX
51 */
52static const char *const conf_yes[] = {
53    "y", "yes", "true", "t", "1", "on",
54    0,
55};
56
57static const char *const conf_no[] = {
58    "n", "no", "false", "nil", "0", "off",
59    0,
60};
61
62static int
63_krb5_conf_boolean(const char *s)
64{
65    const char *const *p;
66
67    for(p=conf_yes; *p; p++) {
68	if (strcasecmp(*p,s) == 0)
69	    return 1;
70    }
71
72    for(p=conf_no; *p; p++) {
73	if (strcasecmp(*p,s) == 0)
74	    return 0;
75    }
76
77    /* Default to "no" */
78    return 0;
79}
80
81/*
82 * XXX
83 * End duplicated code from src/lib/krb5/krb/get_in_tkt.c
84 * XXX
85 */
86
87/*
88 * The following are based on krb5_libdefault_* functions in
89 * src/lib/krb5/krb/get_in_tkt.c
90 * N.B.  This assumes that context->default_realm has
91 * already been established.
92 */
93krb5_error_code
94pkinit_kdcdefault_strings(krb5_context context, const char *realmname,
95			  const char *option, char ***ret_value)
96{
97    profile_t profile = NULL;
98    const char *names[5];
99    char **values = NULL;
100    krb5_error_code retval;
101
102    if (context == NULL)
103	return KV5M_CONTEXT;
104
105    profile = context->profile;
106
107    if (realmname != NULL) {
108	/*
109	 * Try number one:
110	 *
111	 * [realms]
112	 *	    REALM = {
113	 *		option = <value>
114	 *	    }
115	 */
116
117	names[0] = "realms";
118	names[1] = realmname;
119	names[2] = option;
120	names[3] = 0;
121	retval = profile_get_values(profile, names, &values);
122	if (retval == 0 && values != NULL)
123	    goto goodbye;
124    }
125
126    /*
127     * Try number two:
128     *
129     * [kdcdefaults]
130     *	    option = <value>
131     */
132
133    names[0] = "kdcdefaults";
134    names[1] = option;
135    names[2] = 0;
136    retval = profile_get_values(profile, names, &values);
137    if (retval == 0 && values != NULL)
138	goto goodbye;
139
140goodbye:
141    if (values == NULL)
142	retval = ENOENT;
143
144    *ret_value = values;
145
146    return retval;
147
148}
149
150krb5_error_code
151pkinit_kdcdefault_string(krb5_context context, const char *realmname,
152			 const char *option, char **ret_value)
153{
154    krb5_error_code retval;
155    char **values = NULL;
156
157    retval = pkinit_kdcdefault_strings(context, realmname, option, &values);
158    if (retval)
159	return retval;
160
161    if (values[0] == NULL) {
162	retval = ENOENT;
163    } else {
164	*ret_value = malloc(strlen(values[0]) + 1);
165	/* Solaris Kerberos */
166	if (*ret_value == NULL) {
167	    pkiDebug(error_message(ENOMEM));
168	    retval = ENOMEM;
169	}
170	else /* Solaris Kerberos */
171	    (void) strlcpy(*ret_value, values[0], strlen(values[0]) + 1);
172    }
173
174    profile_free_list(values);
175    return retval;
176}
177
178krb5_error_code
179pkinit_kdcdefault_boolean(krb5_context context, const char *realmname,
180			  const char *option, int default_value, int *ret_value)
181{
182    char *string = NULL;
183    krb5_error_code retval;
184
185    retval = pkinit_kdcdefault_string(context, realmname, option, &string);
186
187    if (retval == 0) {
188	*ret_value = _krb5_conf_boolean(string);
189	free(string);
190    } else
191	*ret_value = default_value;
192
193    return 0;
194}
195
196krb5_error_code
197pkinit_kdcdefault_integer(krb5_context context, const char *realmname,
198			  const char *option, int default_value, int *ret_value)
199{
200    char *string = NULL;
201    krb5_error_code retval;
202
203    retval = pkinit_kdcdefault_string(context, realmname, option, &string);
204
205    if (retval == 0) {
206	char *endptr;
207	long l;
208	l = strtol(string, &endptr, 0);
209	if (endptr == string)
210	    *ret_value = default_value;
211	else
212	    *ret_value = l;
213	free(string);
214    } else
215	*ret_value = default_value;
216
217    return 0;
218}
219
220
221/*
222 * krb5_libdefault_string() is defined as static in
223 * src/lib/krb5/krb/get_in_tkt.c.  Create local versions of
224 * krb5_libdefault_* functions here.  We need a libdefaults_strings()
225 * function which is not currently supported there anyway.  Also,
226 * add the ability to supply a default value for the boolean and
227 * integer functions.
228 */
229
230krb5_error_code
231pkinit_libdefault_strings(krb5_context context, const krb5_data *realm,
232			  const char *option, char ***ret_value)
233{
234    profile_t profile;
235    const char *names[5];
236    char **values = NULL;
237    krb5_error_code retval;
238    char realmstr[1024];
239
240    if (realm != NULL && realm->length > sizeof(realmstr)-1)
241	return EINVAL;
242
243    if (realm != NULL) {
244	/* Solaris Kerberos */
245	(void) strlcpy(realmstr, realm->data, realm->length + 1);
246	realmstr[realm->length] = '\0';
247    }
248
249    if (!context || (context->magic != KV5M_CONTEXT))
250	return KV5M_CONTEXT;
251
252    profile = context->profile;
253
254
255    if (realm != NULL) {
256	/*
257	 * Try number one:
258	 *
259	 * [libdefaults]
260	 *	  REALM = {
261	 *		  option = <value>
262	 *	  }
263	 */
264
265	names[0] = "libdefaults";
266	names[1] = realmstr;
267	names[2] = option;
268	names[3] = 0;
269	retval = profile_get_values(profile, names, &values);
270	if (retval == 0 && values != NULL && values[0] != NULL)
271	    goto goodbye;
272
273	/*
274	 * Try number two:
275	 *
276	 * [realms]
277	 *	REALM = {
278	 *		option = <value>
279	 *	}
280	 */
281
282	names[0] = "realms";
283	names[1] = realmstr;
284	names[2] = option;
285	names[3] = 0;
286	retval = profile_get_values(profile, names, &values);
287	if (retval == 0 && values != NULL && values[0] != NULL)
288	    goto goodbye;
289    }
290
291    /*
292     * Try number three:
293     *
294     * [libdefaults]
295     *	      option = <value>
296     */
297
298    names[0] = "libdefaults";
299    names[1] = option;
300    names[2] = 0;
301    retval = profile_get_values(profile, names, &values);
302    if (retval == 0 && values != NULL && values[0] != NULL)
303	goto goodbye;
304
305goodbye:
306    if (values == NULL)
307	return ENOENT;
308
309    *ret_value = values;
310
311    return retval;
312}
313
314krb5_error_code
315pkinit_libdefault_string(krb5_context context, const krb5_data *realm,
316			 const char *option, char **ret_value)
317{
318    krb5_error_code retval;
319    char **values = NULL;
320
321    retval = pkinit_libdefault_strings(context, realm, option, &values);
322    if (retval)
323	return retval;
324
325    if (values[0] == NULL) {
326	retval = ENOENT;
327    } else {
328	*ret_value = malloc(strlen(values[0]) + 1);
329	if (*ret_value == NULL)
330	    retval = ENOMEM;
331	else /* Solaris Kerberos */
332	    (void) strlcpy(*ret_value, values[0], strlen(values[0]) + 1);
333    }
334
335    profile_free_list(values);
336    return retval;
337}
338
339krb5_error_code
340pkinit_libdefault_boolean(krb5_context context, const krb5_data *realm,
341			  const char *option, int default_value,
342			  int *ret_value)
343{
344    char *string = NULL;
345    krb5_error_code retval;
346
347    retval = pkinit_libdefault_string(context, realm, option, &string);
348
349   if (retval == 0) {
350	*ret_value = _krb5_conf_boolean(string);
351	free(string);
352    } else
353	*ret_value = default_value;
354
355    return 0;
356}
357
358krb5_error_code
359pkinit_libdefault_integer(krb5_context context, const krb5_data *realm,
360			  const char *option, int default_value,
361			  int *ret_value)
362{
363    char *string = NULL;
364    krb5_error_code retval;
365
366    retval = pkinit_libdefault_string(context, realm, option, &string);
367
368    if (retval == 0) {
369	char *endptr;
370	long l;
371	l = strtol(string, &endptr, 0);
372	if (endptr == string)
373	    *ret_value = default_value;
374	else
375	    *ret_value = l;
376	free(string);
377    }
378
379    return retval;
380}
381