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