xref: /titanic_51/usr/src/lib/krb5/kadm5/alt_prof.c (revision d2ec54f7875f7e05edd56195adbeb593c947763f)
1 /*
2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 #pragma ident	"%Z%%M%	%I%	%E% SMI"
7 
8 /*
9  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
10  *
11  *	Openvision retains the copyright to derivative works of
12  *	this source code.  Do *NOT* create a derivative of this
13  *	source code before consulting with your legal department.
14  *	Do *NOT* integrate *ANY* of this source code into another
15  *	product before consulting with your legal department.
16  *
17  *	For further information, read the top-level Openvision
18  *	copyright which is contained in the top-level MIT Kerberos
19  *	copyright.
20  *
21  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
22  *
23  */
24 
25 
26 /*
27  * lib/kadm/alt_prof.c
28  *
29  * Copyright 1995,2001 by the Massachusetts Institute of Technology.
30  * All Rights Reserved.
31  *
32  * Export of this software from the United States of America may
33  *   require a specific license from the United States Government.
34  *   It is the responsibility of any person or organization contemplating
35  *   export to obtain such a license before exporting.
36  *
37  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
38  * distribute this software and its documentation for any purpose and
39  * without fee is hereby granted, provided that the above copyright
40  * notice appear in all copies and that both that copyright notice and
41  * this permission notice appear in supporting documentation, and that
42  * the name of M.I.T. not be used in advertising or publicity pertaining
43  * to distribution of the software without specific, written prior
44  * permission.  Furthermore if you modify this software you must label
45  * your software as modified software and not distribute it in such a
46  * fashion that it might be confused with the original M.I.T. software.
47  * M.I.T. makes no representations about the suitability of
48  * this software for any purpose.  It is provided "as is" without express
49  * or implied warranty.
50  *
51  */
52 
53 /*
54  * alt_prof.c - Implement alternate profile file handling.
55  */
56 #include <k5-int.h>
57 #include <kadm5/admin.h>
58 #include <adm_proto.h>
59 #include <stdio.h>
60 #include <ctype.h>
61 #include <os-proto.h>
62 #include <kdb/kdb_log.h>
63 
64 krb5_error_code kadm5_free_config_params();
65 
66 #define	DEFAULT_ENCTYPE_LIST \
67 	"aes256-cts-hmac-sha1-96:normal " \
68 	"aes128-cts-hmac-sha1-96:normal " \
69 	"des3-cbc-hmac-sha1-kd:normal " \
70 	"arcfour-hmac-md5:normal " \
71 	"arcfour-hmac-md5-exp:normal " \
72 	"des-cbc-md5:normal " \
73 	"des-cbc-crc:normal"
74 
75 static krb5_key_salt_tuple *copy_key_salt_tuple(ksalt, len)
76 krb5_key_salt_tuple *ksalt;
77 krb5_int32 len;
78 {
79     krb5_key_salt_tuple *knew;
80 
81     if((knew = (krb5_key_salt_tuple *)
82 		malloc((len ) * sizeof(krb5_key_salt_tuple)))) {
83          memcpy(knew, ksalt, len * sizeof(krb5_key_salt_tuple));
84 	 return knew;
85     }
86     return 0;
87 }
88 
89 /*
90  * krb5_aprof_init()	- Initialize alternate profile context.
91  *
92  * Parameters:
93  *	fname		- default file name of the profile.
94  *	envname		- environment variable name which can override fname.
95  *	acontextp	- Pointer to opaque context for alternate profile.
96  *
97  * Returns:
98  *	error codes from profile_init()
99  */
100 krb5_error_code
101 krb5_aprof_init(fname, envname, acontextp)
102     char		*fname;
103     char		*envname;
104     krb5_pointer	*acontextp;
105 {
106     krb5_error_code	kret;
107     const_profile_filespec_t 	namelist[2];
108     profile_t		profile;
109 
110     namelist[1] = (profile_filespec_t) NULL;
111     profile = (profile_t) NULL;
112     if (envname) {
113 	if ((namelist[0] = getenv(envname))) {
114 	    kret = profile_init(namelist, &profile);
115 	    if (kret)
116 		return kret;
117 	    *acontextp = (krb5_pointer) profile;
118 	    return 0;
119 	}
120     }
121     profile = (profile_t) NULL;
122     if (fname) {
123 	kret = profile_init_path(fname, &profile);
124 	if (kret == ENOENT) {
125 	    profile = 0;
126 	} else if (kret)
127 	    return kret;
128 	*acontextp = (krb5_pointer) profile;
129 	return 0;
130     }
131     return 0;
132 }
133 
134 /*
135  * krb5_aprof_getvals()	- Get values from alternate profile.
136  *
137  * Parameters:
138  *	acontext	- opaque context for alternate profile.
139  *	hierarchy	- hierarchy of value to retrieve.
140  *	retdata		- Returned data values.
141  *
142  * Returns:
143  * 	error codes from profile_get_values()
144  */
145 krb5_error_code
146 krb5_aprof_getvals(acontext, hierarchy, retdata)
147     krb5_pointer	acontext;
148     const char		**hierarchy;
149     char		***retdata;
150 {
151     return(profile_get_values((profile_t) acontext,
152 			      hierarchy,
153 			      retdata));
154 }
155 
156 /*
157  * krb5_aprof_get_boolean()
158  *
159  * Parameters:
160  *	acontext	- opaque context for alternate profile
161  *	hierarchy	- hierarchy of value to retrieve
162  *	retdata		- Returned data value
163  * Returns:
164  *	error codes
165  */
166 
167 static krb5_error_code
168 string_to_boolean (const char *string, krb5_boolean *out)
169 {
170     static const char *const yes[] = { "y", "yes", "true", "t", "1", "on" };
171     static const char *const no[] = { "n", "no", "false", "f", "nil", "0", "off" };
172     int i;
173 
174     for (i = 0; i < sizeof(yes)/sizeof(yes[0]); i++)
175 	if (!strcasecmp(string, yes[i])) {
176 	    *out = 1;
177 	    return 0;
178 	}
179     for (i = 0; i < sizeof(no)/sizeof(no[0]); i++)
180 	if (!strcasecmp(string, no[i])) {
181 	    *out = 0;
182 	    return 0;
183 	}
184     return PROF_BAD_BOOLEAN;
185 }
186 
187 krb5_error_code
188 krb5_aprof_get_boolean(krb5_pointer acontext, const char **hierarchy,
189 		       int uselast, krb5_boolean *retdata)
190 {
191     krb5_error_code kret;
192     char **values;
193     char *valp;
194     int idx;
195     krb5_boolean val;
196 
197     kret = krb5_aprof_getvals (acontext, hierarchy, &values);
198     if (kret)
199 	return kret;
200     idx = 0;
201     if (uselast) {
202 	while (values[idx])
203 	    idx++;
204 	idx--;
205     }
206     valp = values[idx];
207     kret = string_to_boolean (valp, &val);
208     if (kret)
209 	return kret;
210     *retdata = val;
211     return 0;
212 }
213 
214 /*
215  * krb5_aprof_get_deltat()	- Get a delta time value from the alternate
216  *				  profile.
217  *
218  * Parameters:
219  *	acontext		- opaque context for alternate profile.
220  *	hierarchy		- hierarchy of value to retrieve.
221  *	uselast			- if true, use last value, otherwise use
222  *				  first value found.
223  *	deltatp			- returned delta time value.
224  *
225  * Returns:
226  * 	error codes from profile_get_values()
227  *	error codes from krb5_string_to_deltat()
228  */
229 krb5_error_code
230 krb5_aprof_get_deltat(acontext, hierarchy, uselast, deltatp)
231     krb5_pointer	acontext;
232     const char		**hierarchy;
233     krb5_boolean	uselast;
234     krb5_deltat		*deltatp;
235 {
236     krb5_error_code	kret;
237     char		**values;
238     char		*valp;
239     int			idx;
240 
241     if (!(kret = krb5_aprof_getvals(acontext, hierarchy, &values))) {
242 	idx = 0;
243 	if (uselast) {
244 	    for (idx=0; values[idx]; idx++);
245 	    idx--;
246 	}
247 	valp = values[idx];
248 	kret = krb5_string_to_deltat(valp, deltatp);
249 
250 	/* Free the string storage */
251 	for (idx=0; values[idx]; idx++)
252 	    krb5_xfree(values[idx]);
253 	krb5_xfree(values);
254     }
255     return(kret);
256 }
257 
258 /*
259  * krb5_aprof_get_string()	- Get a string value from the alternate
260  *				  profile.
261  *
262  * Parameters:
263  *	acontext		- opaque context for alternate profile.
264  *	hierarchy		- hierarchy of value to retrieve.
265  *	uselast			- if true, use last value, otherwise use
266  *				  first value found.
267  *	stringp			- returned string value.
268  *
269  * Returns:
270  * 	error codes from profile_get_values()
271  */
272 krb5_error_code
273 krb5_aprof_get_string(acontext, hierarchy, uselast, stringp)
274     krb5_pointer	acontext;
275     const char		**hierarchy;
276     krb5_boolean	uselast;
277     char		**stringp;
278 {
279     krb5_error_code	kret;
280     char		**values;
281     int			idx, i;
282 
283     if (!(kret = krb5_aprof_getvals(acontext, hierarchy, &values))) {
284 	idx = 0;
285 	if (uselast) {
286 	    for (idx=0; values[idx]; idx++);
287 	    idx--;
288 	}
289 
290 	*stringp = values[idx];
291 
292 	/* Free the string storage */
293 	for (i=0; values[i]; i++)
294 	    if (i != idx)
295 		krb5_xfree(values[i]);
296 	krb5_xfree(values);
297     }
298     return(kret);
299 }
300 
301 /*
302  * krb5_aprof_get_int32()	- Get a 32-bit integer value from the alternate
303  *				  profile.
304  *
305  * Parameters:
306  *	acontext		- opaque context for alternate profile.
307  *	hierarchy		- hierarchy of value to retrieve.
308  *	uselast			- if true, use last value, otherwise use
309  *				  first value found.
310  *	intp			- returned 32-bit integer value.
311  *
312  * Returns:
313  * 	error codes from profile_get_values()
314  *	EINVAL			- value is not an integer
315  */
316 krb5_error_code
317 krb5_aprof_get_int32(acontext, hierarchy, uselast, intp)
318     krb5_pointer	acontext;
319     const char		**hierarchy;
320     krb5_boolean	uselast;
321     krb5_int32		*intp;
322 {
323     krb5_error_code	kret;
324     char		**values;
325     int			idx;
326 
327     if (!(kret = krb5_aprof_getvals(acontext, hierarchy, &values))) {
328 	idx = 0;
329 	if (uselast) {
330 	    for (idx=0; values[idx]; idx++);
331 	    idx--;
332 	}
333 
334 	if (sscanf(values[idx], "%d", intp) != 1)
335 	    kret = EINVAL;
336 
337 	/* Free the string storage */
338 	for (idx=0; values[idx]; idx++)
339 	    krb5_xfree(values[idx]);
340 	krb5_xfree(values);
341     }
342     return(kret);
343 }
344 
345 /*
346  * krb5_aprof_finish()	- Finish alternate profile context.
347  *
348  * Parameter:
349  *	acontext	- opaque context for alternate profile.
350  *
351  * Returns:
352  *	0 on success, something else on failure.
353  */
354 krb5_error_code
355 krb5_aprof_finish(acontext)
356     krb5_pointer	acontext;
357 {
358     profile_release(acontext);
359     return(0);
360 }
361 
362 /*
363  * Function: kadm5_get_config_params
364  *
365  * Purpose: Merge configuration parameters provided by the caller with
366  * values specified in configuration files and with default values.
367  *
368  * Arguments:
369  *
370  *	context		(r) krb5_context to use
371  *	profile		(r) profile file to use
372  *	envname		(r) envname that contains a profile name to
373  *			override profile
374  *	params_in	(r) params structure containing user-supplied
375  *			values, or NULL
376  *	params_out	(w) params structure to be filled in
377  *
378  * Effects:
379  *
380  * The fields and mask of params_out are filled in with values
381  * obtained from params_in, the specified profile, and default
382  * values.  Only and all fields specified in params_out->mask are
383  * set.  The context of params_out must be freed with
384  * kadm5_free_config_params.
385  *
386  * params_in and params_out may be the same pointer.  However, all pointers
387  * in params_in for which the mask is set will be re-assigned to newly copied
388  * versions, overwriting the old pointer value.
389  */
390 krb5_error_code kadm5_get_config_params(context, kdcprofile, kdcenv,
391 					params_in, params_out)
392    krb5_context		context;
393    char			*kdcprofile;
394    char			*kdcenv;
395    kadm5_config_params	*params_in, *params_out;
396 {
397     char		*filename;
398     char		*envname;
399     char		*lrealm;
400     krb5_pointer	aprofile = 0;
401     const char		*hierarchy[4];
402     char		*svalue;
403     krb5_int32		ivalue;
404     kadm5_config_params params, empty_params;
405 
406     krb5_error_code	kret = 0;
407 	krb5_error_code dnsret = 1;
408 
409 #ifdef KRB5_DNS_LOOKUP
410 	char dns_host[MAX_DNS_NAMELEN];
411 	unsigned short dns_portno;
412 	krb5_data dns_realm;
413 	memset((char *)&dns_realm, 0, sizeof (dns_realm));
414 #endif /* KRB5_DNS_LOOKUP */
415 
416     memset((char *) &params, 0, sizeof(params));
417     memset((char *) &empty_params, 0, sizeof(empty_params));
418 
419     if (params_in == NULL) params_in = &empty_params;
420 
421     if (params_in->mask & KADM5_CONFIG_REALM) {
422 	 lrealm = params.realm = strdup(params_in->realm);
423 	 if (params.realm)
424 	      params.mask |= KADM5_CONFIG_REALM;
425     } else {
426 	 kret = krb5_get_default_realm(context, &lrealm);
427 	 if (kret)
428 	      goto cleanup;
429 	 params.realm = lrealm;
430 	 params.mask |= KADM5_CONFIG_REALM;
431     }
432     if (params_in->mask & KADM5_CONFIG_PROFILE) {
433 	 filename = params.profile = strdup(params_in->profile);
434 	 if (params.profile)
435 	      params.mask |= KADM5_CONFIG_PROFILE;
436 	 envname = NULL;
437     } else {
438 	 /*
439 	  * XXX These defaults should to work on both client and
440 	  * server.  kadm5_get_config_params can be implemented as a
441 	  * wrapper function in each library that provides correct
442 	  * defaults for NULL values.
443 	  */
444 	 filename = (kdcprofile) ? kdcprofile : DEFAULT_KDC_PROFILE;
445 	 envname = (kdcenv) ? kdcenv : KDC_PROFILE_ENV;
446 	 if (context->profile_secure == TRUE) envname = 0;
447     }
448 
449     kret = krb5_aprof_init(filename, envname, &aprofile);
450     if (kret)
451 	    goto cleanup;
452 
453     /* Initialize realm parameters */
454     hierarchy[0] = "realms";
455     hierarchy[1] = lrealm;
456     hierarchy[3] = (char *) NULL;
457 
458 #ifdef KRB5_DNS_LOOKUP
459 	/*
460 	 * Initialize realm info for (possible) DNS lookups.
461 	 */
462 	dns_realm.data = strdup(lrealm);
463 	dns_realm.length = strlen(lrealm);
464 	dns_realm.magic = 0;
465 #endif /* KRB5_DNS_LOOKUP */
466 
467     /* Get the value for the admin server */
468     hierarchy[2] = "admin_server";
469     if (params_in->mask & KADM5_CONFIG_ADMIN_SERVER) {
470 	 params.admin_server = strdup(params_in->admin_server);
471 	 if (params.admin_server)
472 	      params.mask |= KADM5_CONFIG_ADMIN_SERVER;
473     } else if (aprofile &&
474 	       !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
475 	 params.admin_server = svalue;
476 	 params.mask |= KADM5_CONFIG_ADMIN_SERVER;
477     }
478 #ifdef KRB5_DNS_LOOKUP
479 	else if (strcmp(envname, "KRB5_CONFIG") == 0) {
480 		/*
481 		 * Solaris Kerberos: only do DNS lookup for admin_server if this
482 		 * is a krb5.conf type of config file.  Note, the filename may
483 		 * not be /etc/krb5/krb5.conf so we assume that the KRB5_CONFIG
484 		 * envname string will consistently indicate the type of config
485 		 * file.
486 		 */
487 		dnsret = krb5_get_servername(context, &dns_realm,
488 					"_kerberos-adm", "_udp",
489 					dns_host, &dns_portno);
490 		if (dnsret == 0) {
491 			params.admin_server = strdup(dns_host);
492 			if (params.admin_server)
493 				params.mask |= KADM5_CONFIG_ADMIN_SERVER;
494 			params.kadmind_port = dns_portno;
495 			params.mask |= KADM5_CONFIG_KADMIND_PORT;
496 		}
497 	}
498 #endif /* KRB5_DNS_LOOKUP */
499 
500     if ((params.mask & KADM5_CONFIG_ADMIN_SERVER) && dnsret) {
501 	 char *p;
502 	 p = strchr(params.admin_server, ':');
503 	 if (p) {
504 	      params.kadmind_port = atoi(p+1);
505 	      params.mask |= KADM5_CONFIG_KADMIND_PORT;
506 	      *p = '\0';
507 	 }
508     }
509 
510     /* Get the value for the database */
511     hierarchy[2] = "database_name";
512     if (params_in->mask & KADM5_CONFIG_DBNAME) {
513 	 params.dbname = strdup(params_in->dbname);
514 	 if (params.dbname)
515 	      params.mask |= KADM5_CONFIG_DBNAME;
516     } else if (aprofile &&
517 	       !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
518 	 params.dbname = svalue;
519 	 params.mask |= KADM5_CONFIG_DBNAME;
520     } else {
521 	 params.dbname = strdup(DEFAULT_KDB_FILE);
522 	 if (params.dbname)
523 	      params.mask |= KADM5_CONFIG_DBNAME;
524     }
525 
526     /*
527      * admin database name and lockfile are now always derived from dbname
528      */
529     if (params.mask & KADM5_CONFIG_DBNAME) {
530 	 params.admin_dbname = (char *) malloc(strlen(params.dbname) + 7);
531 	 if (params.admin_dbname) {
532 	      sprintf(params.admin_dbname, "%s.kadm5", params.dbname);
533 	      params.mask |= KADM5_CONFIG_ADBNAME;
534 	 }
535     }
536 
537     if (params.mask & KADM5_CONFIG_ADBNAME) {
538 	 params.admin_lockfile = (char *) malloc(strlen(params.admin_dbname)
539 						 + 6);
540 	 if (params.admin_lockfile) {
541 	      sprintf(params.admin_lockfile, "%s.lock", params.admin_dbname);
542 	      params.mask |= KADM5_CONFIG_ADB_LOCKFILE;
543 	 }
544     }
545 
546     /* Get the value for the admin (policy) database lock file*/
547     hierarchy[2] = "admin_keytab";
548     if (params_in->mask & KADM5_CONFIG_ADMIN_KEYTAB) {
549 	 params.admin_keytab = strdup(params_in->admin_keytab);
550 	 if (params.admin_keytab)
551 	      params.mask |= KADM5_CONFIG_ADMIN_KEYTAB;
552     } else if (aprofile &&
553 	       !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
554 	 params.mask |= KADM5_CONFIG_ADMIN_KEYTAB;
555 	 params.admin_keytab = svalue;
556     } else if ((params.admin_keytab = (char *) getenv("KRB5_KTNAME"))) {
557 	 params.admin_keytab = strdup(params.admin_keytab);
558 	 if (params.admin_keytab)
559 	      params.mask |= KADM5_CONFIG_ADMIN_KEYTAB;
560     } else {
561 	 params.admin_keytab = strdup(DEFAULT_KADM5_KEYTAB);
562 	 if (params.admin_keytab)
563 	      params.mask |= KADM5_CONFIG_ADMIN_KEYTAB;
564     }
565 
566     /* Get the name of the acl file */
567     hierarchy[2] = "acl_file";
568     if (params_in->mask & KADM5_CONFIG_ACL_FILE) {
569 	 params.acl_file = strdup(params_in->acl_file);
570 	 if (params.acl_file)
571 	      params.mask |= KADM5_CONFIG_ACL_FILE;
572     } else if (aprofile &&
573 	       !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
574 	 params.mask |= KADM5_CONFIG_ACL_FILE;
575 	 params.acl_file = svalue;
576     } else {
577 	 params.acl_file = strdup(DEFAULT_KADM5_ACL_FILE);
578 	 if (params.acl_file)
579 	      params.mask |= KADM5_CONFIG_ACL_FILE;
580     }
581 
582     /* Get the name of the dict file */
583     hierarchy[2] = "dict_file";
584     if (params_in->mask & KADM5_CONFIG_DICT_FILE) {
585 	 params.dict_file = strdup(params_in->dict_file);
586 	 if (params.dict_file)
587 	      params.mask |= KADM5_CONFIG_DICT_FILE;
588     } else if (aprofile &&
589 	       !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
590 	 params.mask |= KADM5_CONFIG_DICT_FILE;
591 	 params.dict_file = svalue;
592     }
593 
594     /* Get the value for the kadmind port */
595     if (! (params.mask & KADM5_CONFIG_KADMIND_PORT)) {
596 	 hierarchy[2] = "kadmind_port";
597 	 if (params_in->mask & KADM5_CONFIG_KADMIND_PORT) {
598 	      params.mask |= KADM5_CONFIG_KADMIND_PORT;
599 	      params.kadmind_port = params_in->kadmind_port;
600 	 } else if (aprofile &&
601 		    !krb5_aprof_get_int32(aprofile, hierarchy, TRUE,
602 					  &ivalue)) {
603 	      params.kadmind_port = ivalue;
604 	      params.mask |= KADM5_CONFIG_KADMIND_PORT;
605 	 } else {
606 	      params.kadmind_port = DEFAULT_KADM5_PORT;
607 	      params.mask |= KADM5_CONFIG_KADMIND_PORT;
608 	 }
609     }
610 
611     /* Get the value for the kpasswd port */
612     if (! (params.mask & KADM5_CONFIG_KPASSWD_PORT)) {
613 	hierarchy[2] = "kpasswd_port";
614 	if (params_in->mask & KADM5_CONFIG_KPASSWD_PORT) {
615 	    params.mask |= KADM5_CONFIG_KPASSWD_PORT;
616 	    params.kpasswd_port = params_in->kpasswd_port;
617 	} else if (aprofile &&
618 		   !krb5_aprof_get_int32(aprofile, hierarchy, TRUE,
619 					 &ivalue)) {
620 	    params.kpasswd_port = ivalue;
621 	    params.mask |= KADM5_CONFIG_KPASSWD_PORT;
622 	} else {
623 	    params.kpasswd_port = DEFAULT_KPASSWD_PORT;
624 	    params.mask |= KADM5_CONFIG_KPASSWD_PORT;
625 	}
626     }
627 
628     /* Get the value for the master key name */
629 	 hierarchy[2] = "master_key_name";
630     if (params_in->mask & KADM5_CONFIG_MKEY_NAME) {
631 	 params.mkey_name = strdup(params_in->mkey_name);
632 	 if (params.mkey_name)
633 	      params.mask |= KADM5_CONFIG_MKEY_NAME;
634     } else if (aprofile &&
635 	       !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
636 	 params.mask |= KADM5_CONFIG_MKEY_NAME;
637 	 params.mkey_name = svalue;
638     }
639 
640     /* Get the value for the master key type */
641     hierarchy[2] = "master_key_type";
642     if (params_in->mask & KADM5_CONFIG_ENCTYPE) {
643 	 params.mask |= KADM5_CONFIG_ENCTYPE;
644 	 params.enctype = params_in->enctype;
645     } else if (aprofile &&
646 	       !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
647 	 if (!krb5_string_to_enctype(svalue, &params.enctype)) {
648 	      params.mask |= KADM5_CONFIG_ENCTYPE;
649 	      krb5_xfree(svalue);
650 	 }
651     } else {
652 	 params.mask |= KADM5_CONFIG_ENCTYPE;
653 	 params.enctype = DEFAULT_KDC_ENCTYPE;
654     }
655 
656     /* Get the value for mkey_from_kbd */
657     if (params_in->mask & KADM5_CONFIG_MKEY_FROM_KBD) {
658 	 params.mask |= KADM5_CONFIG_MKEY_FROM_KBD;
659 	 params.mkey_from_kbd = params_in->mkey_from_kbd;
660     }
661 
662     /* Get the value for the stashfile */
663     hierarchy[2] = "key_stash_file";
664     if (params_in->mask & KADM5_CONFIG_STASH_FILE) {
665 	 params.stash_file = strdup(params_in->stash_file);
666 	 if (params.stash_file)
667 	      params.mask |= KADM5_CONFIG_STASH_FILE;
668     } else if (aprofile &&
669 	       !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
670 	 params.mask |= KADM5_CONFIG_STASH_FILE;
671 	 params.stash_file = svalue;
672     }
673 
674     /*
675 	 * Get the value for maximum ticket lifetime.
676 	 * See SEAM documentation or the Bug ID 4184504
677 	 * We have changed the logic so that the entries are
678 	 * created in the database with the maximum duration
679 	 * for life and renew life KRB5_INT32_MAX
680 	 * However this wil get negotiated down when
681 	 * as or tgs request is processed by KDC.
682 	 */
683     hierarchy[2] = "max_life";
684     if (params_in->mask & KADM5_CONFIG_MAX_LIFE) {
685 	 params.mask |= KADM5_CONFIG_MAX_LIFE;
686 	 params.max_life = params_in->max_life;
687     } else {
688 	 params.max_life = KRB5_INT32_MAX;
689 	 params.mask |= KADM5_CONFIG_MAX_LIFE;
690     }
691 
692     /* Get the value for maximum renewable ticket lifetime. */
693     hierarchy[2] = "max_renewable_life";
694     if (params_in->mask & KADM5_CONFIG_MAX_RLIFE) {
695 	 params.mask |= KADM5_CONFIG_MAX_RLIFE;
696 	 params.max_rlife = params_in->max_rlife;
697     } else {
698 	 params.max_rlife =  KRB5_INT32_MAX;
699 	 params.mask |= KADM5_CONFIG_MAX_RLIFE;
700     }
701 
702     /* Get the value for the default principal expiration */
703     hierarchy[2] = "default_principal_expiration";
704     if (params_in->mask & KADM5_CONFIG_EXPIRATION) {
705 	 params.mask |= KADM5_CONFIG_EXPIRATION;
706 	 params.expiration = params_in->expiration;
707     } else if (aprofile &&
708 	       !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
709 	 if (!krb5_string_to_timestamp(svalue, &params.expiration)) {
710 	      params.mask |= KADM5_CONFIG_EXPIRATION;
711 	      krb5_xfree(svalue);
712 	 }
713     } else {
714 	 params.mask |= KADM5_CONFIG_EXPIRATION;
715 	 params.expiration = 0;
716     }
717 
718     /* Get the value for the default principal flags */
719     hierarchy[2] = "default_principal_flags";
720     if (params_in->mask & KADM5_CONFIG_FLAGS) {
721 	 params.mask |= KADM5_CONFIG_FLAGS;
722 	 params.flags = params_in->flags;
723     } else if (aprofile &&
724 	       !krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
725 	 char *sp, *ep, *tp;
726 
727 	 sp = svalue;
728 	 params.flags = 0;
729 	 while (sp) {
730 	      if ((ep = strchr(sp, (int) ',')) ||
731 		  (ep = strchr(sp, (int) ' ')) ||
732 		  (ep = strchr(sp, (int) '\t'))) {
733 		   /* Fill in trailing whitespace of sp */
734 		   tp = ep - 1;
735 		   while (isspace((int) *tp) && (tp > sp)) {
736 			*tp = '\0';
737 			tp--;
738 		   }
739 		   *ep = '\0';
740 		   ep++;
741 		   /* Skip over trailing whitespace of ep */
742 		   while (isspace((int) *ep) && (*ep)) ep++;
743 	      }
744 	      /* Convert this flag */
745 	      if (krb5_string_to_flags(sp,
746 				       "+",
747 				       "-",
748 				       &params.flags))
749 		   break;
750 	      sp = ep;
751 	 }
752 	 if (!sp)
753 	      params.mask |= KADM5_CONFIG_FLAGS;
754 	 krb5_xfree(svalue);
755     } else {
756 	 params.mask |= KADM5_CONFIG_FLAGS;
757 	 params.flags = KRB5_KDB_DEF_FLAGS;
758     }
759 
760     /* Get the value for the supported enctype/salttype matrix */
761     hierarchy[2] = "supported_enctypes";
762     if (params_in->mask & KADM5_CONFIG_ENCTYPES) {
763 		params.mask |= KADM5_CONFIG_ENCTYPES;
764 		if (params_in->num_keysalts > 0) {
765 		    params.keysalts = malloc(params_in->num_keysalts *
766 			    sizeof (*params.keysalts));
767 		    if (params.keysalts == NULL) {
768 			kret = ENOMEM;
769 			goto cleanup;
770 		    }
771 		    (void) memcpy(params.keysalts, params_in->keysalts,
772 			    (params_in->num_keysalts *
773 			    sizeof (*params.keysalts)));
774 		 params.num_keysalts = params_in->num_keysalts;
775 	 }
776     } else {
777 	 svalue = NULL;
778 	 if (aprofile)
779 	      krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue);
780 	 if (svalue == NULL)
781 	     svalue = strdup(DEFAULT_ENCTYPE_LIST);
782 
783 	 params.keysalts = NULL;
784 	 params.num_keysalts = 0;
785 	 krb5_string_to_keysalts(svalue,
786 				 ", \t",/* Tuple separators	*/
787 				 ":.-",	/* Key/salt separators	*/
788 				 0,	/* No duplicates	*/
789 				 &params.keysalts,
790 				 &params.num_keysalts);
791 	 if (params.num_keysalts)
792 	      params.mask |= KADM5_CONFIG_ENCTYPES;
793 
794 	 if (svalue)
795 	      krb5_xfree(svalue);
796     }
797 
798 	hierarchy[2] = "kpasswd_server";
799 	if (params_in->mask & KADM5_CONFIG_KPASSWD_SERVER) {
800 		params.mask |= KADM5_CONFIG_KPASSWD_SERVER;
801 		params.kpasswd_server = strdup(params_in->kpasswd_server);
802 	} else {
803 		svalue = NULL;
804 
805 		if (aprofile)
806 			krb5_aprof_get_string(aprofile, hierarchy,
807 					    TRUE, &svalue);
808 		if (svalue == NULL) {
809 #ifdef KRB5_DNS_LOOKUP
810 			if (strcmp(envname, "KRB5_CONFIG") == 0) {
811 				/*
812 				 * Solaris Kerberos: only do DNS lookup for
813 				 * kpasswd_server if this is a krb5.conf type of
814 				 * config file.  Note, the filename may not be
815 				 * /etc/krb5/krb5.conf so we assume that the
816 				 * KRB5_CONFIG envname string will consistently
817 				 * indicate the type of config file.
818 				 */
819 				dnsret = krb5_get_servername(context,
820 				    &dns_realm, "_kpasswd", "_udp",
821 				    dns_host, &dns_portno);
822 
823 				if (dnsret == 0) {
824 					params.kpasswd_server =
825 					    strdup(dns_host);
826 					if (params.kpasswd_server) {
827 						params.mask |=
828 						    KADM5_CONFIG_KPASSWD_SERVER;
829 					}
830 					params.kpasswd_port = dns_portno;
831 					params.mask |=
832 					    KADM5_CONFIG_KPASSWD_PORT;
833 				}
834 			}
835 #endif /* KRB5_DNS_LOOKUP */
836 
837 			/*
838 			 * If a unique 'kpasswd_server' is not specified,
839 			 * use the normal 'admin_server'.
840 			 */
841 			if ((params.mask & KADM5_CONFIG_ADMIN_SERVER) &&
842 				    dnsret) {
843 				params.kpasswd_server =
844 					strdup(params.admin_server);
845 				params.mask |= KADM5_CONFIG_KPASSWD_SERVER;
846 			}
847 		} else {
848 			char *p;
849 			params.kpasswd_server = svalue;
850 			params.mask |= KADM5_CONFIG_KPASSWD_SERVER;
851 
852 			if ((p = strchr(params.kpasswd_server, ':'))) {
853 				params.kpasswd_port = atoi(p+1);
854 				params.mask |= KADM5_CONFIG_KPASSWD_PORT;
855 				*p = '\0';
856 			}
857 		}
858 	}
859 
860 	hierarchy[2] = "kpasswd_protocol";
861 
862 	/* default to current RPCSEC_GSS protocol */
863 	params.kpasswd_protocol = KRB5_CHGPWD_RPCSEC;
864 	params.mask |= KADM5_CONFIG_KPASSWD_PROTOCOL;
865 
866 	if (params_in->mask & KADM5_CONFIG_KPASSWD_PROTOCOL) {
867 		params.mask |= KADM5_CONFIG_KPASSWD_PROTOCOL;
868 		params.kpasswd_protocol = params_in->kpasswd_protocol;
869 	} else {
870 		svalue = NULL;
871 
872 		if (aprofile)
873 			krb5_aprof_get_string(aprofile, hierarchy,
874 					    TRUE, &svalue);
875 		if (svalue != NULL) {
876 			if (strcasecmp(svalue, "RPCSEC_GSS") == 0) {
877 				params.kpasswd_protocol = KRB5_CHGPWD_RPCSEC;
878 				params.mask |= KADM5_CONFIG_KPASSWD_PROTOCOL;
879 			} else if (strcasecmp(svalue, "SET_CHANGE") == 0) {
880 				params.kpasswd_protocol =
881 					KRB5_CHGPWD_CHANGEPW_V2;
882 				params.mask |= KADM5_CONFIG_KPASSWD_PROTOCOL;
883 			}
884 		}
885 		if (svalue)
886 			krb5_xfree(svalue);
887 	}
888 
889 	/*
890 	 * If the kpasswd_port is not yet defined, define it now.
891 	 */
892 	if (! (params.mask & KADM5_CONFIG_KPASSWD_PORT)) {
893 		if (params_in->mask & KADM5_CONFIG_KPASSWD_PORT)
894 			params.kpasswd_port = params_in->kpasswd_port;
895 		/*
896 		 * If kpasswd_port is not explicitly defined,
897 		 * determine the port to use based on the protocol.
898 		 * The alternative protocol uses a different port
899 		 * than the standard admind port.
900 		 */
901 		else if (params.kpasswd_protocol == KRB5_CHGPWD_RPCSEC) {
902 			params.kpasswd_port = DEFAULT_KADM5_PORT;
903 		} else {
904 			/*
905 			 * When using the Horowitz/IETF protocol for
906 			 * password changing, the default port is 464
907 			 * (officially recognized by IANA).
908 			 */
909 			params.kpasswd_port = DEFAULT_KPASSWD_PORT;
910 		}
911 		params.mask |= KADM5_CONFIG_KPASSWD_PORT;
912 	}
913 
914 	hierarchy[2] = "sunw_dbprop_enable";
915 
916 	params.iprop_enabled = FALSE;
917 	params.mask |= KADM5_CONFIG_IPROP_ENABLED;
918 
919 	if (params_in->mask & KADM5_CONFIG_IPROP_ENABLED) {
920 		params.mask |= KADM5_CONFIG_IPROP_ENABLED;
921 		params.iprop_enabled = params_in->iprop_enabled;
922 	} else {
923 		if (aprofile && !krb5_aprof_get_string(aprofile, hierarchy,
924 		    TRUE, &svalue)) {
925 			if (strncasecmp(svalue, "Y", 1) == 0)
926 				params.iprop_enabled = TRUE;
927 			if (strncasecmp(svalue, "true", 4) == 0)
928 				params.iprop_enabled = TRUE;
929 			params.mask |= KADM5_CONFIG_IPROP_ENABLED;
930 			krb5_xfree(svalue);
931 		}
932 	}
933 
934 	hierarchy[2] = "sunw_dbprop_master_ulogsize";
935 
936 	params.iprop_ulogsize = DEF_ULOGENTRIES;
937 	params.mask |= KADM5_CONFIG_ULOG_SIZE;
938 
939 	if (params_in->mask & KADM5_CONFIG_ULOG_SIZE) {
940 		params.mask |= KADM5_CONFIG_ULOG_SIZE;
941 		params.iprop_ulogsize = params_in->iprop_ulogsize;
942 	} else {
943 		if (aprofile && !krb5_aprof_get_int32(aprofile, hierarchy,
944 		    TRUE, &ivalue)) {
945 			if (ivalue > MAX_ULOGENTRIES)
946 				params.iprop_ulogsize = MAX_ULOGENTRIES;
947 			else if (ivalue <= 0)
948 				params.iprop_ulogsize = DEF_ULOGENTRIES;
949 			else
950 				params.iprop_ulogsize = ivalue;
951 			params.mask |= KADM5_CONFIG_ULOG_SIZE;
952 		}
953 	}
954 
955 	hierarchy[2] = "sunw_dbprop_slave_poll";
956 
957 	params.iprop_polltime = strdup("2m");
958 	if (params.iprop_polltime)
959 		params.mask |= KADM5_CONFIG_POLL_TIME;
960 
961 	if (params_in->mask & KADM5_CONFIG_POLL_TIME) {
962 		if (params.iprop_polltime)
963 			free(params.iprop_polltime);
964 		params.iprop_polltime = strdup(params_in->iprop_polltime);
965 		if (params.iprop_polltime)
966 			params.mask |= KADM5_CONFIG_POLL_TIME;
967 	} else {
968 		if (aprofile && !krb5_aprof_get_string(aprofile, hierarchy,
969 		    TRUE, &svalue)) {
970 			if (params.iprop_polltime)
971 				free(params.iprop_polltime);
972 			params.iprop_polltime = strdup(svalue);
973 			params.mask |= KADM5_CONFIG_POLL_TIME;
974 			krb5_xfree(svalue);
975 		}
976 	}
977 
978 	*params_out = params;
979 
980 cleanup:
981     if (aprofile)
982 	krb5_aprof_finish(aprofile);
983     if (kret) {
984 	 kadm5_free_config_params(context, &params);
985 	 params_out->mask = 0;
986     }
987 #ifdef KRB5_DNS_LOOKUP
988 	if (dns_realm.data)
989 		free(dns_realm.data);
990 #endif /* KRB5_DNS_LOOKUP */
991 
992     return(kret);
993 }
994 /*
995  * kadm5_free_config_params()	- Free data allocated by above.
996  */
997 /*ARGSUSED*/
998 krb5_error_code
999 kadm5_free_config_params(context, params)
1000     krb5_context	context;
1001     kadm5_config_params	*params;
1002 {
1003     if (params) {
1004 		if (params->profile) {
1005 			krb5_xfree(params->profile);
1006 			params->profile = NULL;
1007 		}
1008 		if (params->dbname) {
1009 			krb5_xfree(params->dbname);
1010 			params->dbname = NULL;
1011 		}
1012 		if (params->mkey_name) {
1013 			krb5_xfree(params->mkey_name);
1014 			params->mkey_name = NULL;
1015 		}
1016 		if (params->stash_file) {
1017 			krb5_xfree(params->stash_file);
1018 			params->stash_file = NULL;
1019 		}
1020 		if (params->keysalts) {
1021 			krb5_xfree(params->keysalts);
1022 			params->keysalts = NULL;
1023 			params->num_keysalts = 0;
1024 		}
1025 		if (params->admin_keytab) {
1026 			free(params->admin_keytab);
1027 			params->admin_keytab = NULL;
1028 		}
1029 		if (params->dict_file) {
1030 			free(params->dict_file);
1031 			params->dict_file = NULL;
1032 		}
1033 		if (params->acl_file) {
1034 			free(params->acl_file);
1035 			params->acl_file = NULL;
1036 		}
1037 		if (params->realm) {
1038 			free(params->realm);
1039 			params->realm = NULL;
1040 		}
1041 		if (params->admin_dbname) {
1042 			free(params->admin_dbname);
1043 			params->admin_dbname = NULL;
1044 		}
1045 		if (params->admin_lockfile) {
1046 			free(params->admin_lockfile);
1047 			params->admin_lockfile = NULL;
1048 		}
1049 		if (params->admin_server) {
1050 			free(params->admin_server);
1051 			params->admin_server = NULL;
1052 		}
1053 		if (params->kpasswd_server) {
1054 			free(params->kpasswd_server);
1055 			params->kpasswd_server = NULL;
1056 		}
1057 		if (params->iprop_polltime) {
1058 			free(params->iprop_polltime);
1059 			params->iprop_polltime = NULL;
1060 		}
1061 	}
1062 	return (0);
1063 }
1064 
1065 krb5_error_code
1066 kadm5_get_admin_service_name(krb5_context ctx,
1067 			     char *realm_in,
1068 			     char *admin_name,
1069 			     size_t maxlen)
1070 {
1071     krb5_error_code ret;
1072     kadm5_config_params params_in, params_out;
1073     struct hostent *hp;
1074 
1075     memset(&params_in, 0, sizeof(params_in));
1076     memset(&params_out, 0, sizeof(params_out));
1077 
1078     params_in.mask |= KADM5_CONFIG_REALM;
1079     params_in.realm = realm_in;
1080     ret = kadm5_get_config_params(ctx, DEFAULT_PROFILE_PATH,
1081 				  "KRB5_CONFIG", &params_in, &params_out);
1082     if (ret)
1083 	return ret;
1084 
1085     if (!(params_out.mask & KADM5_CONFIG_ADMIN_SERVER)) {
1086 	ret = KADM5_MISSING_KRB5_CONF_PARAMS;
1087 	goto err_params;
1088     }
1089 
1090     hp = gethostbyname(params_out.admin_server);
1091     if (hp == NULL) {
1092 	ret = errno;
1093 	goto err_params;
1094     }
1095     if (strlen(hp->h_name) + sizeof("kadmin/") > maxlen) {
1096 	ret = ENOMEM;
1097 	goto err_params;
1098     }
1099     sprintf(admin_name, "kadmin/%s", hp->h_name);
1100 
1101 err_params:
1102     kadm5_free_config_params(ctx, &params_out);
1103     return ret;
1104 }
1105 
1106 /***********************************************************************
1107  * This is the old krb5_realm_read_params, which I mutated into
1108  * kadm5_get_config_params but which old code (kdb5_* and krb5kdc)
1109  * still uses.
1110  ***********************************************************************/
1111 
1112 /*
1113  * krb5_read_realm_params()	- Read per-realm parameters from KDC
1114  *				  alternate profile.
1115  */
1116 krb5_error_code
1117 krb5_read_realm_params(kcontext, realm, kdcprofile, kdcenv, rparamp)
1118     krb5_context	kcontext;
1119     char		*realm;
1120     char		*kdcprofile;
1121     char		*kdcenv;
1122     krb5_realm_params	**rparamp;
1123 {
1124     char		*filename;
1125     char		*envname;
1126     char		*lrealm;
1127     krb5_pointer	aprofile = 0;
1128     krb5_realm_params	*rparams;
1129     const char		*hierarchy[4];
1130     char		*svalue;
1131     krb5_int32		ivalue;
1132     krb5_boolean	bvalue;
1133     krb5_deltat		dtvalue;
1134 
1135     krb5_error_code	kret;
1136 
1137     filename = (kdcprofile) ? kdcprofile : DEFAULT_KDC_PROFILE;
1138     envname = (kdcenv) ? kdcenv : KDC_PROFILE_ENV;
1139 
1140     if (kcontext->profile_secure == TRUE) envname = 0;
1141 
1142     rparams = (krb5_realm_params *) NULL;
1143     if (realm)
1144 	lrealm = strdup(realm);
1145     else {
1146 	kret = krb5_get_default_realm(kcontext, &lrealm);
1147 	if (kret)
1148 	    goto cleanup;
1149     }
1150 
1151     kret = krb5_aprof_init(filename, envname, &aprofile);
1152     if (kret)
1153 	goto cleanup;
1154 
1155     rparams = (krb5_realm_params *) malloc(sizeof(krb5_realm_params));
1156     if (rparams == 0) {
1157 	kret = ENOMEM;
1158 	goto cleanup;
1159     }
1160 
1161     /* Initialize realm parameters */
1162     memset((char *) rparams, 0, sizeof(krb5_realm_params));
1163 
1164     /* Get the value for the database */
1165     hierarchy[0] = "realms";
1166     hierarchy[1] = lrealm;
1167     hierarchy[2] = "database_name";
1168     hierarchy[3] = (char *) NULL;
1169     if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue))
1170 	rparams->realm_dbname = svalue;
1171 
1172     /* Get the value for the KDC port list */
1173     hierarchy[2] = "kdc_ports";
1174     if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue))
1175 	rparams->realm_kdc_ports = svalue;
1176     hierarchy[2] = "kdc_tcp_ports";
1177     if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue))
1178 	rparams->realm_kdc_tcp_ports = svalue;
1179 
1180     /* Get the name of the acl file */
1181     hierarchy[2] = "acl_file";
1182     if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue))
1183 	rparams->realm_acl_file = svalue;
1184 
1185     /* Get the value for the kadmind port */
1186     hierarchy[2] = "kadmind_port";
1187     if (!krb5_aprof_get_int32(aprofile, hierarchy, TRUE, &ivalue)) {
1188 	rparams->realm_kadmind_port = ivalue;
1189 	rparams->realm_kadmind_port_valid = 1;
1190     }
1191 
1192     /* Get the value for the master key name */
1193     hierarchy[2] = "master_key_name";
1194     if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue))
1195 	rparams->realm_mkey_name = svalue;
1196 
1197     /* Get the value for the master key type */
1198     hierarchy[2] = "master_key_type";
1199     if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
1200 	if (!krb5_string_to_enctype(svalue, &rparams->realm_enctype))
1201 	    rparams->realm_enctype_valid = 1;
1202 	krb5_xfree(svalue);
1203     }
1204 
1205     /* Get the value for the stashfile */
1206     hierarchy[2] = "key_stash_file";
1207     if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue))
1208 	rparams->realm_stash_file = svalue;
1209 
1210     /* Get the value for maximum ticket lifetime. */
1211     hierarchy[2] = "max_life";
1212     if (!krb5_aprof_get_deltat(aprofile, hierarchy, TRUE, &dtvalue)) {
1213 	rparams->realm_max_life = dtvalue;
1214 	rparams->realm_max_life_valid = 1;
1215     }
1216 
1217     /* Get the value for maximum renewable ticket lifetime. */
1218     hierarchy[2] = "max_renewable_life";
1219     if (!krb5_aprof_get_deltat(aprofile, hierarchy, TRUE, &dtvalue)) {
1220 	rparams->realm_max_rlife = dtvalue;
1221 	rparams->realm_max_rlife_valid = 1;
1222     }
1223 
1224     /* Get the value for the default principal expiration */
1225     hierarchy[2] = "default_principal_expiration";
1226     if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
1227 	if (!krb5_string_to_timestamp(svalue,
1228 				      &rparams->realm_expiration))
1229 	    rparams->realm_expiration_valid = 1;
1230 	krb5_xfree(svalue);
1231     }
1232 
1233     hierarchy[2] = "reject_bad_transit";
1234     if (!krb5_aprof_get_boolean(aprofile, hierarchy, TRUE, &bvalue)) {
1235 	rparams->realm_reject_bad_transit = bvalue;
1236 	rparams->realm_reject_bad_transit_valid = 1;
1237     }
1238 
1239     /* Get the value for the default principal flags */
1240     hierarchy[2] = "default_principal_flags";
1241     if (!krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue)) {
1242 	char *sp, *ep, *tp;
1243 
1244 	sp = svalue;
1245 	rparams->realm_flags = 0;
1246 	while (sp) {
1247 	    if ((ep = strchr(sp, (int) ',')) ||
1248 		(ep = strchr(sp, (int) ' ')) ||
1249 		(ep = strchr(sp, (int) '\t'))) {
1250 		/* Fill in trailing whitespace of sp */
1251 		tp = ep - 1;
1252 		while (isspace((int) *tp) && (tp < sp)) {
1253 		    *tp = '\0';
1254 		    tp--;
1255 		}
1256 		*ep = '\0';
1257 		ep++;
1258 		/* Skip over trailing whitespace of ep */
1259 		while (isspace((int) *ep) && (*ep)) ep++;
1260 	    }
1261 	    /* Convert this flag */
1262 	    if (krb5_string_to_flags(sp,
1263 				     "+",
1264 				     "-",
1265 				     &rparams->realm_flags))
1266 		break;
1267 	    sp = ep;
1268 	}
1269 	if (!sp)
1270 	    rparams->realm_flags_valid = 1;
1271 	krb5_xfree(svalue);
1272     }
1273 
1274 	/* Get the value for the supported enctype/salttype matrix */
1275 	/*
1276 	 * SUNWresync121
1277 	 * Solaris kerberos: updated this code to support default values for
1278 	 * the supported_enctypes.
1279 	 */
1280 	hierarchy[2] = "supported_enctypes";
1281 	svalue = NULL;
1282 	krb5_aprof_get_string(aprofile, hierarchy, TRUE, &svalue);
1283 
1284 	/*
1285 	 * Set the default value if supported_enctypes was not explicitly
1286 	 * set in the kdc.conf.
1287 	 */
1288 	if (svalue == NULL) {
1289 	    svalue = strdup(DEFAULT_ENCTYPE_LIST);
1290 	}
1291 	if (svalue != NULL) {
1292 	    krb5_string_to_keysalts(svalue,
1293 				    ", \t",	/* Tuple separators	*/
1294 				    ":.-",	/* Key/salt separators	*/
1295 				    0,	/* No duplicates	*/
1296 				    &rparams->realm_keysalts,
1297 				    &rparams->realm_num_keysalts);
1298 	    krb5_xfree(svalue);
1299 	    svalue = NULL;
1300 	}
1301 cleanup:
1302     if (aprofile)
1303 	krb5_aprof_finish(aprofile);
1304     if (lrealm)
1305 	free(lrealm);
1306     if (kret) {
1307 	if (rparams)
1308 	    krb5_free_realm_params(kcontext, rparams);
1309 	rparams = 0;
1310     }
1311     *rparamp = rparams;
1312     return(kret);
1313 }
1314 
1315 /*
1316  * krb5_free_realm_params()	- Free data allocated by above.
1317  */
1318 krb5_error_code
1319 krb5_free_realm_params(kcontext, rparams)
1320     krb5_context	kcontext;
1321     krb5_realm_params	*rparams;
1322 {
1323     if (rparams) {
1324 	if (rparams->realm_profile)
1325 	    krb5_xfree(rparams->realm_profile);
1326 	if (rparams->realm_dbname)
1327 	    krb5_xfree(rparams->realm_dbname);
1328 	if (rparams->realm_mkey_name)
1329 	    krb5_xfree(rparams->realm_mkey_name);
1330 	if (rparams->realm_stash_file)
1331 	    krb5_xfree(rparams->realm_stash_file);
1332 	if (rparams->realm_keysalts)
1333 	    krb5_xfree(rparams->realm_keysalts);
1334 	if (rparams->realm_kdc_ports)
1335 	    krb5_xfree(rparams->realm_kdc_ports);
1336 	if (rparams->realm_kdc_tcp_ports)
1337 	    krb5_xfree(rparams->realm_kdc_tcp_ports);
1338 	if (rparams->realm_acl_file)
1339 	    krb5_xfree(rparams->realm_acl_file);
1340 	krb5_xfree(rparams);
1341     }
1342     return(0);
1343 }
1344 
1345