xref: /illumos-gate/usr/src/cmd/krb5/kadmin/kclient/kconf.c (revision a2cd9e1884647e1e412c282879881873b71c84df)
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 
35 struct 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  */
47 static errcode_t
48 init_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  */
63 static void
64 end_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  */
82 static errcode_t
83 add_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 
105 static void
106 usage()
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 
115 int
116 main(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 	file = NULL;
126 	domain = NULL;
127 	master = NULL;
128 	kdcs = NULL;
129 	realm = NULL;
130 	(void) setlocale(LC_ALL, "");
131 
132 #if !defined(TEXT_DOMAIN)
133 #define	TEXT_DOMAIN "SYS_TEST"
134 #endif /* TEXT_DOMAIN */
135 
136 	(void) textdomain(TEXT_DOMAIN);
137 
138 	/*
139 	 * kconf -f <file> -r <realm> -k <kdc[,kdc]> -m <master_kdc>
140 	 * -p <kpasswd_protocol> -d <domain>
141 	 */
142 	while ((c = getopt(argc, argv, "f:r:k:a:s:p:d:m:")) != -1) {
143 		switch (c) {
144 		case 'f':
145 			file = optarg;
146 			break;
147 		case 'r':
148 			realm = optarg;
149 			break;
150 		case 'k':
151 			kdcs = optarg;
152 			break;
153 		case 'm':
154 			master = optarg;
155 			break;
156 		case 'p':
157 			if (strcmp(optarg, "SET_CHANGE") == 0)
158 				set_change = TRUE;
159 			break;
160 		case 'd':
161 			domain = optarg;
162 			break;
163 		default:
164 			usage();
165 			break;
166 		}
167 	}
168 
169 	code = __profile_init(file, &profile);
170 	if (code != 0) {
171 		fprintf(stderr, gettext("Wasn't able to initialize profile\n"));
172 		exit(code);
173 	}
174 
175 	if (code = init_list(&values)) {
176 		fprintf(stderr, gettext("Can not initialize list %d\n"), code);
177 		goto error;
178 	}
179 	token = strtok_r(kdcs, ",", &lasts);
180 	do {
181 		if (token != NULL) {
182 			code = add_to_list(&values, token);
183 			if (code != 0) {
184 				fprintf(stderr, gettext("Can not add to list "
185 				    "%d\n"), code);
186 				goto error;
187 			}
188 		} else {
189 			fprintf(stderr, gettext("Couldn't parse kdc list %d\n"),
190 			    code);
191 			goto error;
192 		}
193 	} while ((token = strtok_r(NULL, ",", &lasts)) != NULL);
194 	end_list(&values, &ret_values);
195 
196 	code = __profile_add_realm(profile, realm, master, ret_values,
197 	    set_change, TRUE);
198 	if (code != 0) {
199 		fprintf(stderr, gettext("Wasn't able to add realm "
200 		    "information\n"));
201 		goto error;
202 	}
203 
204 	code = __profile_add_domain_mapping(profile, domain, realm);
205 	if (code != 0) {
206 		fprintf(stderr, gettext("Wasn't able to add domain mapping\n"));
207 		goto error;
208 	}
209 
210 error:
211 	if (ret_values != NULL)
212 		profile_free_list(ret_values);
213 
214 	/*
215 	 * Release profile, which will subsequently flush new profile to file.
216 	 * If this fails then at least free profile memory.
217 	 */
218 	if ((code =  __profile_release(profile)) != 0)
219 		__profile_abandon(profile);
220 
221 	return (code);
222 }
223