1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26#include <stdio.h>
27#include <stdlib.h>
28#include <strings.h>
29#include <locale.h>
30#include <errno.h>
31#include <krb5.h>
32#include <profile.h>
33#include <com_err.h>
34
35struct profile_string_list {
36	char	**list;
37	int	num;
38	int	max;
39};
40
41/*
42 * From prof_get.c as the following four functions are private in mech_krb5.
43 */
44/*
45 * Initialize the string list abstraction.
46 */
47static errcode_t
48init_list(struct profile_string_list *list)
49{
50	list->num = 0;
51	list->max = 10;
52	list->list = malloc(list->max * sizeof (char *));
53	if (list->list == NULL)
54		return (ENOMEM);
55	list->list[0] = NULL;
56	return (0);
57}
58
59/*
60 * If re_list is non-NULL then pass the list header to the caller else free
61 * the previously allocated list.
62 */
63static void
64end_list(struct profile_string_list *list, char ***ret_list)
65{
66
67	if (list == NULL)
68		return;
69
70	if (ret_list) {
71		*ret_list = list->list;
72		return;
73	} else
74		profile_free_list(list->list);
75	list->num = list->max = 0;
76	list->list = NULL;
77}
78
79/*
80 * Add a string to the list.
81 */
82static errcode_t
83add_to_list(struct profile_string_list *list, const char *str)
84{
85	char 	*newstr, **newlist;
86	int	newmax;
87
88	if (list->num + 1 >= list->max) {
89		newmax = list->max + 10;
90		newlist = realloc(list->list, newmax * sizeof (char *));
91		if (newlist == NULL)
92			return (ENOMEM);
93		list->max = newmax;
94		list->list = newlist;
95	}
96	newstr = strdup(str);
97	if (newstr == NULL)
98		return (ENOMEM);
99
100	list->list[list->num++] = newstr;
101	list->list[list->num] = NULL;
102	return (0);
103}
104
105static void
106usage()
107{
108	(void) fprintf(stderr, gettext("kconf -f <file> -r <realm> "
109	    "-k <kdc[,kdc]> -m <master_kdc>\n -p <kpasswd_protocol> "
110	    "-d <domain>\n"));
111
112	exit(1);
113}
114
115int
116main(int argc, char **argv)
117{
118	profile_t	profile;
119	errcode_t	code;
120	char		c, *realm, *kdcs, *master, *domain, *token, *lasts;
121	char		*file, **ret_values = NULL;
122	boolean_t	set_change = FALSE;
123	struct profile_string_list values;
124
125	(void) setlocale(LC_ALL, "");
126
127#if !defined(TEXT_DOMAIN)
128#define	TEXT_DOMAIN "SYS_TEST"
129#endif /* TEXT_DOMAIN */
130
131	(void) textdomain(TEXT_DOMAIN);
132
133	/*
134	 * kconf -f <file> -r <realm> -k <kdc[,kdc]> -m <master_kdc>
135	 * -p <kpasswd_protocol> -d <domain>
136	 */
137	while ((c = getopt(argc, argv, "f:r:k:a:s:p:d:m:")) != -1) {
138		switch (c) {
139		case 'f':
140			file = optarg;
141			break;
142		case 'r':
143			realm = optarg;
144			break;
145		case 'k':
146			kdcs = optarg;
147			break;
148		case 'm':
149			master = optarg;
150			break;
151		case 'p':
152			if (strcmp(optarg, "SET_CHANGE") == 0)
153				set_change = TRUE;
154			break;
155		case 'd':
156			domain = optarg;
157			break;
158		default:
159			usage();
160			break;
161		}
162	}
163
164	code = __profile_init(file, &profile);
165	if (code != 0) {
166		fprintf(stderr, gettext("Wasn't able to initialize profile\n"));
167		exit(code);
168	}
169
170	if (code = init_list(&values)) {
171		fprintf(stderr, gettext("Can not initialize list %d\n"), code);
172		goto error;
173	}
174	token = strtok_r(kdcs, ",", &lasts);
175	do {
176		if (token != NULL) {
177			code = add_to_list(&values, token);
178			if (code != 0) {
179				fprintf(stderr, gettext("Can not add to list "
180				    "%d\n"), code);
181				goto error;
182			}
183		} else {
184			fprintf(stderr, gettext("Couldn't parse kdc list %d\n"),
185			    code);
186			goto error;
187		}
188	} while ((token = strtok_r(NULL, ",", &lasts)) != NULL);
189	end_list(&values, &ret_values);
190
191	code = __profile_add_realm(profile, realm, master, ret_values,
192	    set_change, TRUE);
193	if (code != 0) {
194		fprintf(stderr, gettext("Wasn't able to add realm "
195		    "information\n"));
196		goto error;
197	}
198
199	code = __profile_add_domain_mapping(profile, domain, realm);
200	if (code != 0) {
201		fprintf(stderr, gettext("Wasn't able to add domain mapping\n"));
202		goto error;
203	}
204
205error:
206	if (ret_values != NULL)
207		profile_free_list(ret_values);
208
209	/*
210	 * Release profile, which will subsequently flush new profile to file.
211	 * If this fails then at least free profile memory.
212	 */
213	if ((code =  __profile_release(profile)) != 0)
214		__profile_abandon(profile);
215
216	return (code);
217}
218