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