xref: /freebsd/crypto/krb5/src/plugins/preauth/pkinit/pkinit_profile.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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