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