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 */
44 static 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  */
52 static const char *const conf_yes[] = {
53     "y", "yes", "true", "t", "1", "on",
54     0,
55 };
56 
57 static const char *const conf_no[] = {
58     "n", "no", "false", "nil", "0", "off",
59     0,
60 };
61 
62 static int
_krb5_conf_boolean(const char * s)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  */
93 krb5_error_code
pkinit_kdcdefault_strings(krb5_context context,const char * realmname,const char * option,char *** ret_value)94 pkinit_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 
140 goodbye:
141     if (values == NULL)
142 	retval = ENOENT;
143 
144     *ret_value = values;
145 
146     return retval;
147 
148 }
149 
150 krb5_error_code
pkinit_kdcdefault_string(krb5_context context,const char * realmname,const char * option,char ** ret_value)151 pkinit_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 
178 krb5_error_code
pkinit_kdcdefault_boolean(krb5_context context,const char * realmname,const char * option,int default_value,int * ret_value)179 pkinit_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 
196 krb5_error_code
pkinit_kdcdefault_integer(krb5_context context,const char * realmname,const char * option,int default_value,int * ret_value)197 pkinit_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 
230 krb5_error_code
pkinit_libdefault_strings(krb5_context context,const krb5_data * realm,const char * option,char *** ret_value)231 pkinit_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 
305 goodbye:
306     if (values == NULL)
307 	return ENOENT;
308 
309     *ret_value = values;
310 
311     return retval;
312 }
313 
314 krb5_error_code
pkinit_libdefault_string(krb5_context context,const krb5_data * realm,const char * option,char ** ret_value)315 pkinit_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 
339 krb5_error_code
pkinit_libdefault_boolean(krb5_context context,const krb5_data * realm,const char * option,int default_value,int * ret_value)340 pkinit_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 
358 krb5_error_code
pkinit_libdefault_integer(krb5_context context,const krb5_data * realm,const char * option,int default_value,int * ret_value)359 pkinit_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