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