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