xref: /freebsd/crypto/krb5/src/lib/kadm5/alt_prof.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/kadm5/alt_prof.c */
3 /*
4  * Copyright 1995,2001,2008,2009 by the Massachusetts Institute of Technology.
5  * All Rights Reserved.
6  *
7  * Export of this software from the United States of America may
8  *   require a specific license from the United States Government.
9  *   It is the responsibility of any person or organization contemplating
10  *   export to obtain such a license before exporting.
11  *
12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13  * distribute this software and its documentation for any purpose and
14  * without fee is hereby granted, provided that the above copyright
15  * notice appear in all copies and that both that copyright notice and
16  * this permission notice appear in supporting documentation, and that
17  * the name of M.I.T. not be used in advertising or publicity pertaining
18  * to distribution of the software without specific, written prior
19  * permission.  Furthermore if you modify this software you must label
20  * your software as modified software and not distribute it in such a
21  * fashion that it might be confused with the original M.I.T. software.
22  * M.I.T. makes no representations about the suitability of
23  * this software for any purpose.  It is provided "as is" without express
24  * or implied warranty.
25  */
26 /*
27  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
28  * Use is subject to license terms.
29  */
30 
31 /* Implement alternate profile file handling. */
32 #include "k5-int.h"
33 #include "fake-addrinfo.h"
34 #include <kadm5/admin.h>
35 #include "adm_proto.h"
36 #include <stdio.h>
37 #include <ctype.h>
38 #include <kdb_log.h>
39 
40 static krb5_key_salt_tuple *
copy_key_salt_tuple(krb5_key_salt_tuple * ksalt,krb5_int32 len)41 copy_key_salt_tuple(krb5_key_salt_tuple *ksalt, krb5_int32 len)
42 {
43     krb5_key_salt_tuple *knew;
44 
45     knew = calloc(len, sizeof(krb5_key_salt_tuple));
46     if (knew == NULL)
47         return NULL;
48     memcpy(knew, ksalt, len * sizeof(krb5_key_salt_tuple));
49     return knew;
50 }
51 
52 /*
53  * krb5_aprof_getvals()     - Get values from alternate profile.
54  *
55  * Parameters:
56  *        acontext          - opaque context for alternate profile.
57  *        hierarchy         - hierarchy of value to retrieve.
58  *        retdata           - Returned data values.
59  *
60  * Returns:
61  *         error codes from profile_get_values()
62  */
63 krb5_error_code
krb5_aprof_getvals(krb5_pointer acontext,const char ** hierarchy,char *** retdata)64 krb5_aprof_getvals(krb5_pointer acontext, const char **hierarchy,
65                    char ***retdata)
66 {
67     return profile_get_values(acontext, hierarchy, retdata);
68 }
69 
70 /*
71  * krb5_aprof_get_boolean()
72  *
73  * Parameters:
74  *        acontext          - opaque context for alternate profile
75  *        hierarchy         - hierarchy of value to retrieve
76  *        retdata           - Returned data value
77  * Returns:
78  *        error codes
79  */
80 
81 static krb5_error_code
string_to_boolean(const char * string,krb5_boolean * out)82 string_to_boolean(const char *string, krb5_boolean *out)
83 {
84     static const char *const yes[] = { "y", "yes", "true", "t", "1", "on" };
85     static const char *const no[] = { "n", "no", "false", "f", "nil", "0",
86                                       "off" };
87     unsigned int i;
88 
89     for (i = 0; i < sizeof(yes) / sizeof(yes[0]); i++) {
90         if (!strcasecmp(string, yes[i])) {
91             *out = TRUE;
92             return 0;
93         }
94     }
95     for (i = 0; i < sizeof(no) / sizeof(no[0]); i++) {
96         if (!strcasecmp(string, no[i])) {
97             *out = FALSE;
98             return 0;
99         }
100     }
101     return PROF_BAD_BOOLEAN;
102 }
103 
104 krb5_error_code
krb5_aprof_get_boolean(krb5_pointer acontext,const char ** hierarchy,int uselast,krb5_boolean * retdata)105 krb5_aprof_get_boolean(krb5_pointer acontext, const char **hierarchy,
106                        int uselast, krb5_boolean *retdata)
107 {
108     krb5_error_code ret;
109     char **values, *valp;
110     int idx;
111     krb5_boolean val;
112 
113     ret = krb5_aprof_getvals(acontext, hierarchy, &values);
114     if (ret)
115         return ret;
116     idx = 0;
117     if (uselast) {
118         while (values[idx] != NULL)
119             idx++;
120         idx--;
121     }
122     valp = values[idx];
123     ret = string_to_boolean(valp, &val);
124     profile_free_list(values);
125     if (ret)
126         return ret;
127     *retdata = val;
128     return 0;
129 }
130 
131 /*
132  * krb5_aprof_get_deltat()  - Get a delta time value from the alternate
133  *                            profile.
134  *
135  * Parameters:
136  *        acontext          - opaque context for alternate profile.
137  *        hierarchy         - hierarchy of value to retrieve.
138  *        uselast           - if true, use last value, otherwise use first
139  *                            value found.
140  *        deltatp           - returned delta time value.
141  *
142  * Returns:
143  *        error codes from profile_get_values()
144  *        error codes from krb5_string_to_deltat()
145  */
146 krb5_error_code
krb5_aprof_get_deltat(krb5_pointer acontext,const char ** hierarchy,krb5_boolean uselast,krb5_deltat * deltatp)147 krb5_aprof_get_deltat(krb5_pointer acontext, const char **hierarchy,
148                       krb5_boolean uselast, krb5_deltat *deltatp)
149 {
150     krb5_error_code ret;
151     char **values, *valp;
152     int idx;
153 
154     ret = krb5_aprof_getvals(acontext, hierarchy, &values);
155     if (ret)
156         return ret;
157 
158     idx = 0;
159     if (uselast) {
160         for (idx = 0; values[idx] != NULL; idx++);
161         idx--;
162     }
163     valp = values[idx];
164 
165     ret = krb5_string_to_deltat(valp, deltatp);
166     profile_free_list(values);
167     return ret;
168 }
169 
170 /*
171  * krb5_aprof_get_string()  - Get a string value from the alternate profile.
172  *
173  * Parameters:
174  *        acontext          - opaque context for alternate profile.
175  *        hierarchy         - hierarchy of value to retrieve.
176  *        uselast           - if true, use last value, otherwise use first
177  *                            value found.
178  *        stringp           - returned string value.
179  *
180  * Returns:
181  *         error codes from profile_get_values()
182  */
183 krb5_error_code
krb5_aprof_get_string(krb5_pointer acontext,const char ** hierarchy,krb5_boolean uselast,char ** stringp)184 krb5_aprof_get_string(krb5_pointer acontext, const char **hierarchy,
185                       krb5_boolean uselast, char **stringp)
186 {
187     krb5_error_code ret;
188     char **values;
189     int lastidx;
190 
191     ret = krb5_aprof_getvals(acontext, hierarchy, &values);
192     if (ret)
193         return ret;
194 
195     for (lastidx = 0; values[lastidx] != NULL; lastidx++);
196     lastidx--;
197 
198     /* Excise the entry we want from the null-terminated list,
199      * and free up the rest. */
200     if (uselast) {
201         *stringp = values[lastidx];
202         values[lastidx] = NULL;
203     } else {
204         *stringp = values[0];
205         values[0] = values[lastidx];
206         values[lastidx] = NULL;
207     }
208 
209     profile_free_list(values);
210     return 0;
211 }
212 
213 /*
214  * krb5_aprof_get_string_all() - When the attr identified by "hierarchy" is
215  *                               specified multiple times, concatenate all of
216  *                               its string values from the alternate profile,
217  *                               separated with spaces.
218  *
219  * Parameters:
220  *        acontext             - opaque context for alternate profile.
221  *        hierarchy            - hierarchy of value to retrieve.
222  *        stringp              - Returned string value.
223  *
224  * Returns:
225  *        error codes from profile_get_values() or ENOMEM
226  *        Caller is responsible for deallocating stringp buffer
227  */
228 krb5_error_code
krb5_aprof_get_string_all(krb5_pointer acontext,const char ** hierarchy,char ** stringp)229 krb5_aprof_get_string_all(krb5_pointer acontext, const char **hierarchy,
230                           char **stringp)
231 {
232     krb5_error_code ret;
233     char **values;
234     int idx = 0;
235     size_t buf_size = 0;
236 
237     ret = krb5_aprof_getvals(acontext, hierarchy, &values);
238     if (ret)
239         return ret;
240 
241     buf_size = strlen(values[0]) + 3;
242     for (idx = 1; values[idx] != NULL; idx++)
243         buf_size += strlen(values[idx]) + 3;
244 
245     *stringp = calloc(1, buf_size);
246     if (*stringp == NULL) {
247         profile_free_list(values);
248         return ENOMEM;
249     }
250     strlcpy(*stringp, values[0], buf_size);
251     for (idx = 1; values[idx] != NULL; idx++) {
252         strlcat(*stringp, " ", buf_size);
253         strlcat(*stringp, values[idx], buf_size);
254     }
255 
256     profile_free_list(values);
257     return 0;
258 }
259 
260 
261 /*
262  * krb5_aprof_get_int32()   - Get a 32-bit integer value from the alternate
263  *                            profile.
264  *
265  * Parameters:
266  *        acontext          - opaque context for alternate profile.
267  *        hierarchy         - hierarchy of value to retrieve.
268  *        uselast           - if true, use last value, otherwise use first
269  *                            value found.
270  *        intp              - returned 32-bit integer value.
271  *
272  * Returns:
273  *        error codes from profile_get_values()
274  *        EINVAL            - value is not an integer
275  */
276 krb5_error_code
krb5_aprof_get_int32(krb5_pointer acontext,const char ** hierarchy,krb5_boolean uselast,krb5_int32 * intp)277 krb5_aprof_get_int32(krb5_pointer acontext, const char **hierarchy,
278                      krb5_boolean uselast, krb5_int32 *intp)
279 {
280     krb5_error_code ret;
281     char **values;
282     int idx;
283 
284     ret = krb5_aprof_getvals(acontext, hierarchy, &values);
285     if (ret)
286         return ret;
287 
288     idx = 0;
289     if (uselast) {
290         for (idx = 0; values[idx] != NULL; idx++);
291         idx--;
292     }
293 
294     if (sscanf(values[idx], "%d", intp) != 1)
295         ret = EINVAL;
296 
297     profile_free_list(values);
298     return ret;
299 }
300 
301 /*
302  * Returns nonzero if it found something to copy; the caller may still need to
303  * check the output field or mask to see if the copy (allocation) was
304  * successful.  Returns zero if nothing was found to copy, and thus the caller
305  * may want to apply some default heuristic.  If the default action is just to
306  * use a fixed, compiled-in string, supply it as the default value here and
307  * ignore the return value.
308  */
309 static int
get_string_param(char ** param_out,char * param_in,long * mask_out,long mask_in,long mask_bit,krb5_pointer aprofile,const char ** hierarchy,const char * config_name,const char * default_value)310 get_string_param(char **param_out, char *param_in, long *mask_out,
311                  long mask_in, long mask_bit, krb5_pointer aprofile,
312                  const char **hierarchy, const char *config_name,
313                  const char *default_value)
314 {
315     char *svalue;
316 
317     hierarchy[2] = config_name;
318     if (mask_in & mask_bit) {
319         *param_out = strdup(param_in);
320         if (*param_out)
321             *mask_out |= mask_bit;
322         return 1;
323     } else if (aprofile != NULL &&
324                !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
325         *param_out = svalue;
326         *mask_out |= mask_bit;
327         return 1;
328     } else if (default_value) {
329         *param_out = strdup(default_value);
330         if (*param_out)
331             *mask_out |= mask_bit;
332         return 1;
333     } else {
334         return 0;
335     }
336 }
337 /*
338  * Similar, for (host-order) port number, if not already set in the output
339  * field; default_value == 0 means no default.
340  */
341 static void
get_port_param(int * param_out,int param_in,long * mask_out,long mask_in,long mask_bit,krb5_pointer aprofile,const char ** hierarchy,const char * config_name,int default_value)342 get_port_param(int *param_out, int param_in, long *mask_out, long mask_in,
343                long mask_bit, krb5_pointer aprofile, const char **hierarchy,
344                const char *config_name, int default_value)
345 {
346     krb5_int32 ivalue;
347 
348     if (*mask_out & mask_bit)
349         return;
350     hierarchy[2] = config_name;
351     if (mask_in & mask_bit) {
352         *mask_out |= mask_bit;
353         *param_out = param_in;
354     } else if (aprofile != NULL &&
355                !krb5_aprof_get_int32(aprofile, hierarchy, TRUE, &ivalue)) {
356         *param_out = ivalue;
357         *mask_out |= mask_bit;
358     } else if (default_value) {
359         *param_out = default_value;
360         *mask_out |= mask_bit;
361     }
362 }
363 
364 /*
365  * Similar, for delta_t; default is required.
366  */
367 static void
get_deltat_param(krb5_deltat * param_out,krb5_deltat param_in,long * mask_out,long mask_in,long mask_bit,krb5_pointer aprofile,const char ** hierarchy,const char * config_name,krb5_deltat default_value)368 get_deltat_param(krb5_deltat *param_out, krb5_deltat param_in, long *mask_out,
369                  long mask_in, long mask_bit, krb5_pointer aprofile,
370                  const char **hierarchy, const char *config_name,
371                  krb5_deltat default_value)
372 {
373     krb5_deltat dtvalue;
374 
375     hierarchy[2] = config_name;
376     if (mask_in & mask_bit) {
377         *mask_out |= mask_bit;
378         *param_out = param_in;
379     } else if (aprofile &&
380                !krb5_aprof_get_deltat(aprofile, hierarchy, TRUE, &dtvalue)) {
381         *param_out = dtvalue;
382         *mask_out |= mask_bit;
383     } else {
384         *param_out = default_value;
385         *mask_out |= mask_bit;
386     }
387 }
388 
389 /*
390  * Parse out the port number from an admin_server setting.  Modify server to
391  * contain just the hostname or address.  If a port is given, set *port, and
392  * set the appropriate bit in *mask.
393  */
394 static void
parse_admin_server_port(char * server,int * port,long * mask)395 parse_admin_server_port(char *server, int *port, long *mask)
396 {
397     char *end, *portstr;
398 
399     /* Allow the name or addr to be enclosed in brackets, for IPv6 addrs. */
400     if (*server == '[' && (end = strchr(server + 1, ']')) != NULL) {
401         portstr = (*(end + 1) == ':') ? end + 2 : NULL;
402         /* Shift the bracketed name or address back into server. */
403         memmove(server, server + 1, end - (server + 1));
404         *(end - 1) = '\0';
405     } else {
406         /* Terminate the name at the colon, if any. */
407         end = server + strcspn(server, ":");
408         portstr = (*end == ':') ? end + 1 : NULL;
409         *end = '\0';
410     }
411 
412     /* If we found a port string, parse it and set the appropriate bit. */
413     if (portstr) {
414         *port = atoi(portstr);
415         *mask |= KADM5_CONFIG_KADMIND_PORT;
416     }
417 }
418 
419 /*
420  * Function: kadm5_get_config_params
421  *
422  * Purpose: Merge configuration parameters provided by the caller with values
423  * specified in configuration files and with default values.
424  *
425  * Arguments:
426  *
427  *        context     (r) krb5_context to use
428  *        profile     (r) profile file to use
429  *        envname     (r) envname that contains a profile name to
430  *                        override profile
431  *        params_in   (r) params structure containing user-supplied
432  *                        values, or NULL
433  *        params_out  (w) params structure to be filled in
434  *
435  * Effects:
436  *
437  * The fields and mask of params_out are filled in with values obtained from
438  * params_in, the specified profile, and default values.  Only and all fields
439  * specified in params_out->mask are set.  The context of params_out must be
440  * freed with kadm5_free_config_params.
441  *
442  * params_in and params_out may be the same pointer.  However, all pointers in
443  * params_in for which the mask is set will be re-assigned to newly copied
444  * versions, overwriting the old pointer value.
445  */
kadm5_get_config_params(krb5_context context,int use_kdc_config,kadm5_config_params * params_in,kadm5_config_params * params_out)446 krb5_error_code kadm5_get_config_params(krb5_context context,
447                                         int use_kdc_config,
448                                         kadm5_config_params *params_in,
449                                         kadm5_config_params *params_out)
450 {
451     char *lrealm, *svalue, *sp, *ep, *tp;
452     krb5_pointer aprofile = context->profile;
453     const char *hierarchy[4];
454     krb5_int32 ivalue;
455     kadm5_config_params params, empty_params;
456     krb5_boolean bvalue;
457     krb5_error_code ret = 0;
458 
459     memset(&params, 0, sizeof(params));
460     memset(&empty_params, 0, sizeof(empty_params));
461 
462     if (params_in == NULL)
463         params_in = &empty_params;
464 
465     if (params_in->mask & KADM5_CONFIG_REALM) {
466         lrealm = params.realm = strdup(params_in->realm);
467         if (params.realm == NULL) {
468             ret = ENOMEM;
469             goto cleanup;
470         }
471         params.mask |= KADM5_CONFIG_REALM;
472     } else {
473         ret = krb5_get_default_realm(context, &lrealm);
474         if (ret)
475             goto cleanup;
476         params.realm = lrealm;
477         params.mask |= KADM5_CONFIG_REALM;
478     }
479 
480     if (params_in->mask & KADM5_CONFIG_KVNO) {
481         params.kvno = params_in->kvno;
482         params.mask |= KADM5_CONFIG_KVNO;
483     }
484 
485     /* Initialize realm parameters. */
486     hierarchy[0] = KRB5_CONF_REALMS;
487     hierarchy[1] = lrealm;
488     hierarchy[3] = NULL;
489 
490 #define GET_STRING_PARAM(FIELD, BIT, CONFTAG, DEFAULT)          \
491     get_string_param(&params.FIELD, params_in->FIELD,           \
492                      &params.mask, params_in->mask, BIT,        \
493                      aprofile, hierarchy, CONFTAG, DEFAULT)
494 
495     /* Get the value for the admin server. */
496     GET_STRING_PARAM(admin_server, KADM5_CONFIG_ADMIN_SERVER,
497                      KRB5_CONF_ADMIN_SERVER, NULL);
498 
499     if (params.mask & KADM5_CONFIG_ADMIN_SERVER) {
500         parse_admin_server_port(params.admin_server, &params.kadmind_port,
501                                 &params.mask);
502     }
503 
504     /* Get the value for the database. */
505     GET_STRING_PARAM(dbname, KADM5_CONFIG_DBNAME, KRB5_CONF_DATABASE_NAME,
506                      DEFAULT_KDB_FILE);
507 
508     /* Get the name of the acl file. */
509     GET_STRING_PARAM(acl_file, KADM5_CONFIG_ACL_FILE, KRB5_CONF_ACL_FILE,
510                      DEFAULT_KADM5_ACL_FILE);
511 
512     /* Get the name of the dict file. */
513     GET_STRING_PARAM(dict_file, KADM5_CONFIG_DICT_FILE, KRB5_CONF_DICT_FILE,
514                      NULL);
515 
516     /* Get the kadmind listen addresses. */
517     GET_STRING_PARAM(kadmind_listen, KADM5_CONFIG_KADMIND_LISTEN,
518                      KRB5_CONF_KADMIND_LISTEN, NULL);
519     GET_STRING_PARAM(kpasswd_listen, KADM5_CONFIG_KPASSWD_LISTEN,
520                      KRB5_CONF_KPASSWD_LISTEN, NULL);
521     GET_STRING_PARAM(iprop_listen, KADM5_CONFIG_IPROP_LISTEN,
522                      KRB5_CONF_IPROP_LISTEN, NULL);
523 
524 #define GET_PORT_PARAM(FIELD, BIT, CONFTAG, DEFAULT)            \
525     get_port_param(&params.FIELD, params_in->FIELD,             \
526                    &params.mask, params_in->mask, BIT,          \
527                    aprofile, hierarchy, CONFTAG, DEFAULT)
528 
529     /* Get the value for the kadmind port. */
530     GET_PORT_PARAM(kadmind_port, KADM5_CONFIG_KADMIND_PORT,
531                    KRB5_CONF_KADMIND_PORT, DEFAULT_KADM5_PORT);
532 
533     /* Get the value for the kpasswd port. */
534     GET_PORT_PARAM(kpasswd_port, KADM5_CONFIG_KPASSWD_PORT,
535                    KRB5_CONF_KPASSWD_PORT, DEFAULT_KPASSWD_PORT);
536 
537     /* Get the value for the master key name. */
538     GET_STRING_PARAM(mkey_name, KADM5_CONFIG_MKEY_NAME,
539                      KRB5_CONF_MASTER_KEY_NAME, NULL);
540 
541     /* Get the value for the master key type. */
542     hierarchy[2] = KRB5_CONF_MASTER_KEY_TYPE;
543     if (params_in->mask & KADM5_CONFIG_ENCTYPE) {
544         params.mask |= KADM5_CONFIG_ENCTYPE;
545         params.enctype = params_in->enctype;
546     } else if (aprofile != NULL &&
547                !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
548         if (!krb5_string_to_enctype(svalue, &params.enctype)) {
549             params.mask |= KADM5_CONFIG_ENCTYPE;
550             free(svalue);
551         }
552     } else {
553         params.mask |= KADM5_CONFIG_ENCTYPE;
554         params.enctype = DEFAULT_KDC_ENCTYPE;
555     }
556 
557     /* Get the value for mkey_from_kbd. */
558     if (params_in->mask & KADM5_CONFIG_MKEY_FROM_KBD) {
559         params.mask |= KADM5_CONFIG_MKEY_FROM_KBD;
560         params.mkey_from_kbd = params_in->mkey_from_kbd;
561     }
562 
563     /* Get the value for the stashfile. */
564     GET_STRING_PARAM(stash_file, KADM5_CONFIG_STASH_FILE,
565                      KRB5_CONF_KEY_STASH_FILE, NULL);
566 
567     /* Get the value for maximum ticket lifetime. */
568 #define GET_DELTAT_PARAM(FIELD, BIT, CONFTAG, DEFAULT)          \
569     get_deltat_param(&params.FIELD, params_in->FIELD,           \
570                      &params.mask, params_in->mask, BIT,        \
571                      aprofile, hierarchy, CONFTAG, DEFAULT)
572 
573     GET_DELTAT_PARAM(max_life, KADM5_CONFIG_MAX_LIFE, KRB5_CONF_MAX_LIFE,
574                      24 * 60 * 60); /* 1 day */
575 
576     /* Get the value for maximum renewable ticket lifetime. */
577     GET_DELTAT_PARAM(max_rlife, KADM5_CONFIG_MAX_RLIFE,
578                      KRB5_CONF_MAX_RENEWABLE_LIFE, 0);
579 
580     /* Get the value for the default principal expiration */
581     hierarchy[2] = KRB5_CONF_DEFAULT_PRINCIPAL_EXPIRATION;
582     if (params_in->mask & KADM5_CONFIG_EXPIRATION) {
583         params.mask |= KADM5_CONFIG_EXPIRATION;
584         params.expiration = params_in->expiration;
585     } else if (aprofile &&
586                !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
587         if (!krb5_string_to_timestamp(svalue, &params.expiration)) {
588             params.mask |= KADM5_CONFIG_EXPIRATION;
589             free(svalue);
590         }
591     } else {
592         params.mask |= KADM5_CONFIG_EXPIRATION;
593         params.expiration = 0;
594     }
595 
596     /* Get the value for the default principal flags */
597     hierarchy[2] = KRB5_CONF_DEFAULT_PRINCIPAL_FLAGS;
598     if (params_in->mask & KADM5_CONFIG_FLAGS) {
599         params.mask |= KADM5_CONFIG_FLAGS;
600         params.flags = params_in->flags;
601     } else if (aprofile != NULL &&
602                !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
603         sp = svalue;
604         params.flags = 0;
605         while (sp != NULL) {
606             if ((ep = strchr(sp, ',')) != NULL ||
607                 (ep = strchr(sp, ' ')) != NULL ||
608                 (ep = strchr(sp, '\t')) != NULL) {
609                 /* Fill in trailing whitespace of sp. */
610                 tp = ep - 1;
611                 while (isspace((unsigned char)*tp) && tp > sp) {
612                     *tp = '\0';
613                     tp--;
614                 }
615                 *ep = '\0';
616                 ep++;
617                 /* Skip over trailing whitespace of ep. */
618                 while (isspace((unsigned char)*ep) && *ep != '\0')
619                     ep++;
620             }
621             /* Convert this flag. */
622             if (krb5_flagspec_to_mask(sp, &params.flags, &params.flags))
623                 break;
624             sp = ep;
625         }
626         if (sp == NULL)
627             params.mask |= KADM5_CONFIG_FLAGS;
628         free(svalue);
629     } else {
630         params.mask |= KADM5_CONFIG_FLAGS;
631         params.flags = KRB5_KDB_DEF_FLAGS;
632     }
633 
634     /* Get the value for the supported enctype/salttype matrix. */
635     hierarchy[2] = KRB5_CONF_SUPPORTED_ENCTYPES;
636     if (params_in->mask & KADM5_CONFIG_ENCTYPES) {
637         if (params_in->keysalts) {
638             params.keysalts = copy_key_salt_tuple(params_in->keysalts,
639                                                   params_in->num_keysalts);
640             if (params.keysalts) {
641                 params.mask |= KADM5_CONFIG_ENCTYPES;
642                 params.num_keysalts = params_in->num_keysalts;
643             }
644         } else {
645             params.mask |= KADM5_CONFIG_ENCTYPES;
646             params.keysalts = NULL;
647             params.num_keysalts = params_in->num_keysalts;
648         }
649     } else {
650         svalue = NULL;
651         if (aprofile != NULL)
652             krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue);
653         if (svalue == NULL)
654             svalue = strdup(KRB5_DEFAULT_SUPPORTED_ENCTYPES);
655         if (svalue == NULL) {
656             ret = ENOMEM;
657             goto cleanup;
658         }
659 
660         params.keysalts = NULL;
661         params.num_keysalts = 0;
662         krb5_string_to_keysalts(svalue,
663                                 NULL, /* Tuple separators */
664                                 NULL, /* Key/salt separators */
665                                 0,      /* No duplicates */
666                                 &params.keysalts,
667                                 &params.num_keysalts);
668         if (params.num_keysalts)
669             params.mask |= KADM5_CONFIG_ENCTYPES;
670 
671         free(svalue);
672     }
673 
674     hierarchy[2] = KRB5_CONF_IPROP_ENABLE;
675 
676     params.iprop_enabled = FALSE;
677     params.mask |= KADM5_CONFIG_IPROP_ENABLED;
678 
679     if (params_in->mask & KADM5_CONFIG_IPROP_ENABLED) {
680         params.mask |= KADM5_CONFIG_IPROP_ENABLED;
681         params.iprop_enabled = params_in->iprop_enabled;
682     } else {
683         if (aprofile &&
684             !krb5_aprof_get_boolean(aprofile, hierarchy, TRUE, &bvalue)) {
685             params.iprop_enabled = bvalue;
686             params.mask |= KADM5_CONFIG_IPROP_ENABLED;
687         }
688     }
689 
690     if (!GET_STRING_PARAM(iprop_logfile, KADM5_CONFIG_IPROP_LOGFILE,
691                           KRB5_CONF_IPROP_LOGFILE, NULL)) {
692         if (params.mask & KADM5_CONFIG_DBNAME) {
693             if (asprintf(&params.iprop_logfile, "%s.ulog",
694                          params.dbname) >= 0)
695                 params.mask |= KADM5_CONFIG_IPROP_LOGFILE;
696         }
697     }
698 
699     GET_PORT_PARAM(iprop_port, KADM5_CONFIG_IPROP_PORT, KRB5_CONF_IPROP_PORT,
700                    0);
701 
702     /* 5 min for large KDBs */
703     GET_DELTAT_PARAM(iprop_resync_timeout, KADM5_CONFIG_IPROP_RESYNC_TIMEOUT,
704                      KRB5_CONF_IPROP_RESYNC_TIMEOUT, 60 * 5);
705 
706     if (params_in->mask & KADM5_CONFIG_ULOG_SIZE) {
707         params.mask |= KADM5_CONFIG_ULOG_SIZE;
708         params.iprop_ulogsize = params_in->iprop_ulogsize;
709     } else {
710         params.iprop_ulogsize = 0;
711         hierarchy[2] = KRB5_CONF_IPROP_ULOGSIZE;
712         if (aprofile != NULL &&
713             !krb5_aprof_get_int32(aprofile, hierarchy, TRUE, &ivalue) &&
714             ivalue > 0)
715             params.iprop_ulogsize = ivalue;
716         hierarchy[2] = KRB5_CONF_IPROP_MASTER_ULOGSIZE;
717         if (params.iprop_ulogsize == 0 && aprofile != NULL &&
718             !krb5_aprof_get_int32(aprofile, hierarchy, TRUE, &ivalue) &&
719             ivalue > 0)
720             params.iprop_ulogsize = ivalue;
721         if (params.iprop_ulogsize == 0)
722             params.iprop_ulogsize = DEF_ULOGENTRIES;
723     }
724     params.mask |= KADM5_CONFIG_ULOG_SIZE;
725 
726     GET_DELTAT_PARAM(iprop_poll_time, KADM5_CONFIG_POLL_TIME,
727                      KRB5_CONF_IPROP_REPLICA_POLL, -1);
728     if (params.iprop_poll_time == -1) {
729         GET_DELTAT_PARAM(iprop_poll_time, KADM5_CONFIG_POLL_TIME,
730                          KRB5_CONF_IPROP_SLAVE_POLL, 2 * 60);
731     }
732 
733     *params_out = params;
734 
735 cleanup:
736     if (ret) {
737         kadm5_free_config_params(context, &params);
738         params_out->mask = 0;
739     }
740     return ret;
741 }
742 
743 /*
744  * kadm5_free_config_params()        - Free data allocated by above.
745  */
746 krb5_error_code
kadm5_free_config_params(krb5_context context,kadm5_config_params * params)747 kadm5_free_config_params(krb5_context context, kadm5_config_params *params)
748 {
749     if (params == NULL)
750         return 0;
751     free(params->dbname);
752     free(params->mkey_name);
753     free(params->stash_file);
754     free(params->keysalts);
755     free(params->admin_server);
756     free(params->dict_file);
757     free(params->acl_file);
758     free(params->realm);
759     free(params->iprop_logfile);
760     return 0;
761 }
762 
763 krb5_error_code
kadm5_get_admin_service_name(krb5_context ctx,char * realm_in,char * admin_name,size_t maxlen)764 kadm5_get_admin_service_name(krb5_context ctx, char *realm_in,
765                              char *admin_name, size_t maxlen)
766 {
767     krb5_error_code ret;
768     kadm5_config_params params_in, params_out;
769     char *canonhost = NULL;
770 
771     memset(&params_in, 0, sizeof(params_in));
772     memset(&params_out, 0, sizeof(params_out));
773 
774     params_in.mask |= KADM5_CONFIG_REALM;
775     params_in.realm = realm_in;
776     ret = kadm5_get_config_params(ctx, 0, &params_in, &params_out);
777     if (ret)
778         return ret;
779 
780     if (!(params_out.mask & KADM5_CONFIG_ADMIN_SERVER)) {
781         ret = KADM5_MISSING_KRB5_CONF_PARAMS;
782         goto err_params;
783     }
784 
785     ret = krb5_expand_hostname(ctx, params_out.admin_server, &canonhost);
786     if (ret)
787         goto err_params;
788 
789     if (strlen(canonhost) + sizeof("kadmin/") > maxlen) {
790         ret = ENOMEM;
791         goto err_params;
792     }
793     snprintf(admin_name, maxlen, "kadmin/%s", canonhost);
794 
795 err_params:
796     krb5_free_string(ctx, canonhost);
797     kadm5_free_config_params(ctx, &params_out);
798     return ret;
799 }
800