xref: /freebsd/crypto/heimdal/kadmin/server.c (revision 3deefb0d147d71047a13ec2328b1b721da2ce256)
1b528cefcSMark Murray /*
2ae771770SStanislav Sedov  * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
3b528cefcSMark Murray  * (Royal Institute of Technology, Stockholm, Sweden).
4b528cefcSMark Murray  * All rights reserved.
5b528cefcSMark Murray  *
6b528cefcSMark Murray  * Redistribution and use in source and binary forms, with or without
7b528cefcSMark Murray  * modification, are permitted provided that the following conditions
8b528cefcSMark Murray  * are met:
9b528cefcSMark Murray  *
10b528cefcSMark Murray  * 1. Redistributions of source code must retain the above copyright
11b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer.
12b528cefcSMark Murray  *
13b528cefcSMark Murray  * 2. Redistributions in binary form must reproduce the above copyright
14b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer in the
15b528cefcSMark Murray  *    documentation and/or other materials provided with the distribution.
16b528cefcSMark Murray  *
17b528cefcSMark Murray  * 3. Neither the name of the Institute nor the names of its contributors
18b528cefcSMark Murray  *    may be used to endorse or promote products derived from this software
19b528cefcSMark Murray  *    without specific prior written permission.
20b528cefcSMark Murray  *
21b528cefcSMark Murray  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22b528cefcSMark Murray  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23b528cefcSMark Murray  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24b528cefcSMark Murray  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25b528cefcSMark Murray  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26b528cefcSMark Murray  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27b528cefcSMark Murray  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28b528cefcSMark Murray  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29b528cefcSMark Murray  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30b528cefcSMark Murray  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31b528cefcSMark Murray  * SUCH DAMAGE.
32b528cefcSMark Murray  */
33b528cefcSMark Murray 
34b528cefcSMark Murray #include "kadmin_locl.h"
35b528cefcSMark Murray #include <krb5-private.h>
36b528cefcSMark Murray 
37b528cefcSMark Murray static kadm5_ret_t
kadmind_dispatch(void * kadm_handlep,krb5_boolean initial,krb5_data * in,krb5_data * out)38ae771770SStanislav Sedov kadmind_dispatch(void *kadm_handlep, krb5_boolean initial,
39b528cefcSMark Murray 		 krb5_data *in, krb5_data *out)
40b528cefcSMark Murray {
4180999dcdSCy Schubert     kadm5_ret_t ret = 0;
4280999dcdSCy Schubert     kadm5_ret_t ret_sp = 0;
43b528cefcSMark Murray     int32_t cmd, mask, tmp;
44ae771770SStanislav Sedov     kadm5_server_context *contextp = kadm_handlep;
45b528cefcSMark Murray     char client[128], name[128], name2[128];
46ae771770SStanislav Sedov     const char *op = "";
47b528cefcSMark Murray     krb5_principal princ, princ2;
48b528cefcSMark Murray     kadm5_principal_ent_rec ent;
49c19800e8SDoug Rabson     char *password, *expression;
50b528cefcSMark Murray     krb5_keyblock *new_keys;
51b528cefcSMark Murray     int n_keys;
52b528cefcSMark Murray     char **princs;
53b528cefcSMark Murray     int n_princs;
5480999dcdSCy Schubert     krb5_storage *rsp = NULL; /* response goes here */
5580999dcdSCy Schubert     krb5_storage *sp = NULL;
56b528cefcSMark Murray 
5780999dcdSCy Schubert     memset(&ent, 0, sizeof(ent));
5880999dcdSCy Schubert     krb5_data_zero(out);
5980999dcdSCy Schubert     ret = krb5_unparse_name_fixed(contextp->context, contextp->caller,
60b528cefcSMark Murray 			    client, sizeof(client));
61b528cefcSMark Murray 
62b528cefcSMark Murray     sp = krb5_storage_from_data(in);
63ae771770SStanislav Sedov     if (sp == NULL)
64ae771770SStanislav Sedov 	krb5_errx(contextp->context, 1, "out of memory");
65b528cefcSMark Murray 
6680999dcdSCy Schubert     ret = krb5_ret_int32(sp, &cmd);
6780999dcdSCy Schubert     if (ret) {
6880999dcdSCy Schubert 	krb5_storage_free(sp);
6980999dcdSCy Schubert 	goto fail;
7080999dcdSCy Schubert     }
71b528cefcSMark Murray     switch(cmd){
72b528cefcSMark Murray     case kadm_get:{
73b528cefcSMark Murray 	op = "GET";
74b528cefcSMark Murray 	ret = krb5_ret_principal(sp, &princ);
75b528cefcSMark Murray 	if(ret)
76b528cefcSMark Murray 	    goto fail;
77b528cefcSMark Murray 	ret = krb5_ret_int32(sp, &mask);
78b528cefcSMark Murray 	if(ret){
79ae771770SStanislav Sedov 	    krb5_free_principal(contextp->context, princ);
80b528cefcSMark Murray 	    goto fail;
81b528cefcSMark Murray 	}
82ae771770SStanislav Sedov 	mask |= KADM5_PRINCIPAL;
8380999dcdSCy Schubert 	ret = krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name));
84ae771770SStanislav Sedov 	krb5_warnx(contextp->context, "%s: %s %s", client, op, name);
8580999dcdSCy Schubert 	if (ret == 0)
86ae771770SStanislav Sedov 	    ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_GET, princ);
87b528cefcSMark Murray 	if(ret){
88ae771770SStanislav Sedov 	    krb5_free_principal(contextp->context, princ);
89b528cefcSMark Murray 	    goto fail;
90b528cefcSMark Murray 	}
91ae771770SStanislav Sedov 	ret = kadm5_get_principal(kadm_handlep, princ, &ent, mask);
92b528cefcSMark Murray 	krb5_storage_free(sp);
93b528cefcSMark Murray 	sp = krb5_storage_emem();
94b528cefcSMark Murray 	krb5_store_int32(sp, ret);
95b528cefcSMark Murray 	if(ret == 0){
96b528cefcSMark Murray 	    kadm5_store_principal_ent(sp, &ent);
97ae771770SStanislav Sedov 	    kadm5_free_principal_ent(kadm_handlep, &ent);
98b528cefcSMark Murray 	}
99ae771770SStanislav Sedov 	krb5_free_principal(contextp->context, princ);
100b528cefcSMark Murray 	break;
101b528cefcSMark Murray     }
102b528cefcSMark Murray     case kadm_delete:{
103b528cefcSMark Murray 	op = "DELETE";
104b528cefcSMark Murray 	ret = krb5_ret_principal(sp, &princ);
105b528cefcSMark Murray 	if(ret)
106b528cefcSMark Murray 	    goto fail;
10780999dcdSCy Schubert 	ret = krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name));
108ae771770SStanislav Sedov 	krb5_warnx(contextp->context, "%s: %s %s", client, op, name);
10980999dcdSCy Schubert 	if (ret == 0)
110ae771770SStanislav Sedov 	    ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_DELETE, princ);
111b528cefcSMark Murray 	if(ret){
112ae771770SStanislav Sedov 	    krb5_free_principal(contextp->context, princ);
113b528cefcSMark Murray 	    goto fail;
114b528cefcSMark Murray 	}
115ae771770SStanislav Sedov 	ret = kadm5_delete_principal(kadm_handlep, princ);
116ae771770SStanislav Sedov 	krb5_free_principal(contextp->context, princ);
117b528cefcSMark Murray 	krb5_storage_free(sp);
118b528cefcSMark Murray 	sp = krb5_storage_emem();
119b528cefcSMark Murray 	krb5_store_int32(sp, ret);
120b528cefcSMark Murray 	break;
121b528cefcSMark Murray     }
122b528cefcSMark Murray     case kadm_create:{
123b528cefcSMark Murray 	op = "CREATE";
124b528cefcSMark Murray 	ret = kadm5_ret_principal_ent(sp, &ent);
125b528cefcSMark Murray 	if(ret)
126b528cefcSMark Murray 	    goto fail;
127b528cefcSMark Murray 	ret = krb5_ret_int32(sp, &mask);
128b528cefcSMark Murray 	if(ret){
129ae771770SStanislav Sedov 	    kadm5_free_principal_ent(contextp->context, &ent);
130b528cefcSMark Murray 	    goto fail;
131b528cefcSMark Murray 	}
132b528cefcSMark Murray 	ret = krb5_ret_string(sp, &password);
133b528cefcSMark Murray 	if(ret){
134ae771770SStanislav Sedov 	    kadm5_free_principal_ent(contextp->context, &ent);
135b528cefcSMark Murray 	    goto fail;
136b528cefcSMark Murray 	}
13780999dcdSCy Schubert 	ret = krb5_unparse_name_fixed(contextp->context, ent.principal,
138b528cefcSMark Murray 				name, sizeof(name));
139ae771770SStanislav Sedov 	krb5_warnx(contextp->context, "%s: %s %s", client, op, name);
14080999dcdSCy Schubert 	if (ret == 0)
141ae771770SStanislav Sedov 	    ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_ADD,
1425e9cd1aeSAssar Westerlund 					  ent.principal);
143b528cefcSMark Murray 	if(ret){
144ae771770SStanislav Sedov 	    kadm5_free_principal_ent(contextp->context, &ent);
145b528cefcSMark Murray 	    memset(password, 0, strlen(password));
146b528cefcSMark Murray 	    free(password);
147b528cefcSMark Murray 	    goto fail;
148b528cefcSMark Murray 	}
149ae771770SStanislav Sedov 	ret = kadm5_create_principal(kadm_handlep, &ent,
150b528cefcSMark Murray 				     mask, password);
151ae771770SStanislav Sedov 	kadm5_free_principal_ent(kadm_handlep, &ent);
152b528cefcSMark Murray 	memset(password, 0, strlen(password));
153b528cefcSMark Murray 	free(password);
154b528cefcSMark Murray 	krb5_storage_free(sp);
155b528cefcSMark Murray 	sp = krb5_storage_emem();
156b528cefcSMark Murray 	krb5_store_int32(sp, ret);
157b528cefcSMark Murray 	break;
158b528cefcSMark Murray     }
159b528cefcSMark Murray     case kadm_modify:{
160b528cefcSMark Murray 	op = "MODIFY";
161b528cefcSMark Murray 	ret = kadm5_ret_principal_ent(sp, &ent);
162b528cefcSMark Murray 	if(ret)
163b528cefcSMark Murray 	    goto fail;
164b528cefcSMark Murray 	ret = krb5_ret_int32(sp, &mask);
165b528cefcSMark Murray 	if(ret){
166ae771770SStanislav Sedov 	    kadm5_free_principal_ent(contextp, &ent);
167b528cefcSMark Murray 	    goto fail;
168b528cefcSMark Murray 	}
16980999dcdSCy Schubert 	ret = krb5_unparse_name_fixed(contextp->context, ent.principal,
170b528cefcSMark Murray 				name, sizeof(name));
171ae771770SStanislav Sedov 	krb5_warnx(contextp->context, "%s: %s %s", client, op, name);
17280999dcdSCy Schubert 	if (ret == 0)
173ae771770SStanislav Sedov 	    ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_MODIFY,
1745e9cd1aeSAssar Westerlund 					  ent.principal);
175b528cefcSMark Murray 	if(ret){
176ae771770SStanislav Sedov 	    kadm5_free_principal_ent(contextp, &ent);
177b528cefcSMark Murray 	    goto fail;
178b528cefcSMark Murray 	}
179ae771770SStanislav Sedov 	ret = kadm5_modify_principal(kadm_handlep, &ent, mask);
180ae771770SStanislav Sedov 	kadm5_free_principal_ent(kadm_handlep, &ent);
181b528cefcSMark Murray 	krb5_storage_free(sp);
182b528cefcSMark Murray 	sp = krb5_storage_emem();
183b528cefcSMark Murray 	krb5_store_int32(sp, ret);
184b528cefcSMark Murray 	break;
185b528cefcSMark Murray     }
186b528cefcSMark Murray     case kadm_rename:{
187b528cefcSMark Murray 	op = "RENAME";
188b528cefcSMark Murray 	ret = krb5_ret_principal(sp, &princ);
189b528cefcSMark Murray 	if(ret)
190b528cefcSMark Murray 	    goto fail;
191b528cefcSMark Murray 	ret = krb5_ret_principal(sp, &princ2);
192b528cefcSMark Murray 	if(ret){
193ae771770SStanislav Sedov 	    krb5_free_principal(contextp->context, princ);
194b528cefcSMark Murray 	    goto fail;
195b528cefcSMark Murray 	}
19680999dcdSCy Schubert 	ret = krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name));
19780999dcdSCy Schubert 	if (ret == 0)
19880999dcdSCy Schubert 	    ret = krb5_unparse_name_fixed(contextp->context, princ2, name2, sizeof(name2));
199ae771770SStanislav Sedov 	krb5_warnx(contextp->context, "%s: %s %s -> %s",
200b528cefcSMark Murray 		   client, op, name, name2);
20180999dcdSCy Schubert 	if (ret == 0)
202ae771770SStanislav Sedov 	    ret = _kadm5_acl_check_permission(contextp,
2035e9cd1aeSAssar Westerlund 					  KADM5_PRIV_ADD,
2045e9cd1aeSAssar Westerlund 					  princ2)
205ae771770SStanislav Sedov 	    || _kadm5_acl_check_permission(contextp,
2065e9cd1aeSAssar Westerlund 					   KADM5_PRIV_DELETE,
2075e9cd1aeSAssar Westerlund 					   princ);
208b528cefcSMark Murray 	if(ret){
209ae771770SStanislav Sedov 	    krb5_free_principal(contextp->context, princ);
210ae771770SStanislav Sedov 	    krb5_free_principal(contextp->context, princ2);
211b528cefcSMark Murray 	    goto fail;
212b528cefcSMark Murray 	}
213ae771770SStanislav Sedov 	ret = kadm5_rename_principal(kadm_handlep, princ, princ2);
214ae771770SStanislav Sedov 	krb5_free_principal(contextp->context, princ);
215ae771770SStanislav Sedov 	krb5_free_principal(contextp->context, princ2);
216b528cefcSMark Murray 	krb5_storage_free(sp);
217b528cefcSMark Murray 	sp = krb5_storage_emem();
218b528cefcSMark Murray 	krb5_store_int32(sp, ret);
219b528cefcSMark Murray 	break;
220b528cefcSMark Murray     }
221b528cefcSMark Murray     case kadm_chpass:{
222b528cefcSMark Murray 	op = "CHPASS";
223b528cefcSMark Murray 	ret = krb5_ret_principal(sp, &princ);
224b528cefcSMark Murray 	if(ret)
225b528cefcSMark Murray 	    goto fail;
226b528cefcSMark Murray 	ret = krb5_ret_string(sp, &password);
227b528cefcSMark Murray 	if(ret){
228ae771770SStanislav Sedov 	    krb5_free_principal(contextp->context, princ);
229b528cefcSMark Murray 	    goto fail;
230b528cefcSMark Murray 	}
23180999dcdSCy Schubert 	ret = krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name));
232ae771770SStanislav Sedov 	krb5_warnx(contextp->context, "%s: %s %s", client, op, name);
233b528cefcSMark Murray 
234b528cefcSMark Murray 	/*
235b528cefcSMark Murray 	 * The change is allowed if at least one of:
236ae771770SStanislav Sedov 	 *
237ae771770SStanislav Sedov 	 * a) allowed by sysadmin
238ae771770SStanislav Sedov 	 * b) it's for the principal him/herself and this was an
239bbd80c28SJacques Vidrine 	 *    initial ticket, but then, check with the password quality
240bbd80c28SJacques Vidrine 	 *    function.
241ae771770SStanislav Sedov 	 * c) the user is on the CPW ACL.
242b528cefcSMark Murray 	 */
243b528cefcSMark Murray 
24480999dcdSCy Schubert 	if (ret == 0) {
245ae771770SStanislav Sedov 	    if (krb5_config_get_bool_default(contextp->context, NULL, TRUE,
246ae771770SStanislav Sedov 						 "kadmin", "allow_self_change_password", NULL)
247ae771770SStanislav Sedov 		&& initial
248ae771770SStanislav Sedov 		&& krb5_principal_compare (contextp->context, contextp->caller,
249b528cefcSMark Murray 					       princ))
250bbd80c28SJacques Vidrine 		{
251bbd80c28SJacques Vidrine 		    krb5_data pwd_data;
252bbd80c28SJacques Vidrine 		    const char *pwd_reason;
253bbd80c28SJacques Vidrine 
254bbd80c28SJacques Vidrine 		    pwd_data.data = password;
255bbd80c28SJacques Vidrine 		    pwd_data.length = strlen(password);
256bbd80c28SJacques Vidrine 
257ae771770SStanislav Sedov 		    pwd_reason = kadm5_check_password_quality (contextp->context,
258bbd80c28SJacques Vidrine 							       princ, &pwd_data);
259bbd80c28SJacques Vidrine 		    if (pwd_reason != NULL)
260bbd80c28SJacques Vidrine 			ret = KADM5_PASS_Q_DICT;
261b528cefcSMark Murray 		    else
262bbd80c28SJacques Vidrine 			ret = 0;
263bbd80c28SJacques Vidrine 		} else
264ae771770SStanislav Sedov 		    ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ);
26580999dcdSCy Schubert 	}
266b528cefcSMark Murray 
267b528cefcSMark Murray 	if(ret) {
268ae771770SStanislav Sedov 	    krb5_free_principal(contextp->context, princ);
269bbd80c28SJacques Vidrine 	    memset(password, 0, strlen(password));
270bbd80c28SJacques Vidrine 	    free(password);
271b528cefcSMark Murray 	    goto fail;
272b528cefcSMark Murray 	}
273ae771770SStanislav Sedov 	ret = kadm5_chpass_principal(kadm_handlep, princ, password);
274ae771770SStanislav Sedov 	krb5_free_principal(contextp->context, princ);
275b528cefcSMark Murray 	memset(password, 0, strlen(password));
276b528cefcSMark Murray 	free(password);
277b528cefcSMark Murray 	krb5_storage_free(sp);
278b528cefcSMark Murray 	sp = krb5_storage_emem();
279b528cefcSMark Murray 	krb5_store_int32(sp, ret);
280b528cefcSMark Murray 	break;
281b528cefcSMark Murray     }
2825e9cd1aeSAssar Westerlund     case kadm_chpass_with_key:{
2835e9cd1aeSAssar Westerlund 	int i;
2845e9cd1aeSAssar Westerlund 	krb5_key_data *key_data;
2855e9cd1aeSAssar Westerlund 	int n_key_data;
2865e9cd1aeSAssar Westerlund 
2875e9cd1aeSAssar Westerlund 	op = "CHPASS_WITH_KEY";
2885e9cd1aeSAssar Westerlund 	ret = krb5_ret_principal(sp, &princ);
2895e9cd1aeSAssar Westerlund 	if(ret)
2905e9cd1aeSAssar Westerlund 	    goto fail;
2915e9cd1aeSAssar Westerlund 	ret = krb5_ret_int32(sp, &n_key_data);
2925e9cd1aeSAssar Westerlund 	if (ret) {
293ae771770SStanislav Sedov 	    krb5_free_principal(contextp->context, princ);
2945e9cd1aeSAssar Westerlund 	    goto fail;
2955e9cd1aeSAssar Westerlund 	}
2960cadf2f4SJacques Vidrine 	/* n_key_data will be squeezed into an int16_t below. */
2970cadf2f4SJacques Vidrine 	if (n_key_data < 0 || n_key_data >= 1 << 16 ||
298ae771770SStanislav Sedov 	    (size_t)n_key_data > UINT_MAX/sizeof(*key_data)) {
2990cadf2f4SJacques Vidrine 	    ret = ERANGE;
300ae771770SStanislav Sedov 	    krb5_free_principal(contextp->context, princ);
3010cadf2f4SJacques Vidrine 	    goto fail;
3020cadf2f4SJacques Vidrine 	}
3035e9cd1aeSAssar Westerlund 
3045e9cd1aeSAssar Westerlund 	key_data = malloc (n_key_data * sizeof(*key_data));
305ae771770SStanislav Sedov 	if (key_data == NULL && n_key_data != 0) {
3065e9cd1aeSAssar Westerlund 	    ret = ENOMEM;
307ae771770SStanislav Sedov 	    krb5_free_principal(contextp->context, princ);
3085e9cd1aeSAssar Westerlund 	    goto fail;
3095e9cd1aeSAssar Westerlund 	}
3105e9cd1aeSAssar Westerlund 
3115e9cd1aeSAssar Westerlund 	for (i = 0; i < n_key_data; ++i) {
3125e9cd1aeSAssar Westerlund 	    ret = kadm5_ret_key_data (sp, &key_data[i]);
3135e9cd1aeSAssar Westerlund 	    if (ret) {
3145e9cd1aeSAssar Westerlund 		int16_t dummy = i;
3155e9cd1aeSAssar Westerlund 
316ae771770SStanislav Sedov 		kadm5_free_key_data (contextp, &dummy, key_data);
3175e9cd1aeSAssar Westerlund 		free (key_data);
318ae771770SStanislav Sedov 		krb5_free_principal(contextp->context, princ);
3195e9cd1aeSAssar Westerlund 		goto fail;
3205e9cd1aeSAssar Westerlund 	    }
3215e9cd1aeSAssar Westerlund 	}
3225e9cd1aeSAssar Westerlund 
32380999dcdSCy Schubert 	ret = krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name));
324ae771770SStanislav Sedov 	krb5_warnx(contextp->context, "%s: %s %s", client, op, name);
3255e9cd1aeSAssar Westerlund 
3265e9cd1aeSAssar Westerlund 	/*
327bbd80c28SJacques Vidrine 	 * The change is only allowed if the user is on the CPW ACL,
328bbd80c28SJacques Vidrine 	 * this it to force password quality check on the user.
3295e9cd1aeSAssar Westerlund 	 */
3305e9cd1aeSAssar Westerlund 
33180999dcdSCy Schubert 	if (ret == 0)
332ae771770SStanislav Sedov 	    ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ);
3335e9cd1aeSAssar Westerlund 	if(ret) {
3345e9cd1aeSAssar Westerlund 	    int16_t dummy = n_key_data;
3355e9cd1aeSAssar Westerlund 
336ae771770SStanislav Sedov 	    kadm5_free_key_data (contextp, &dummy, key_data);
3375e9cd1aeSAssar Westerlund 	    free (key_data);
338ae771770SStanislav Sedov 	    krb5_free_principal(contextp->context, princ);
3395e9cd1aeSAssar Westerlund 	    goto fail;
3405e9cd1aeSAssar Westerlund 	}
341ae771770SStanislav Sedov 	ret = kadm5_chpass_principal_with_key(kadm_handlep, princ,
3425e9cd1aeSAssar Westerlund 					      n_key_data, key_data);
3435e9cd1aeSAssar Westerlund 	{
3445e9cd1aeSAssar Westerlund 	    int16_t dummy = n_key_data;
345ae771770SStanislav Sedov 	    kadm5_free_key_data (contextp, &dummy, key_data);
3465e9cd1aeSAssar Westerlund 	}
3475e9cd1aeSAssar Westerlund 	free (key_data);
348ae771770SStanislav Sedov 	krb5_free_principal(contextp->context, princ);
3495e9cd1aeSAssar Westerlund 	krb5_storage_free(sp);
3505e9cd1aeSAssar Westerlund 	sp = krb5_storage_emem();
3515e9cd1aeSAssar Westerlund 	krb5_store_int32(sp, ret);
3525e9cd1aeSAssar Westerlund 	break;
3535e9cd1aeSAssar Westerlund     }
354b528cefcSMark Murray     case kadm_randkey:{
355b528cefcSMark Murray 	op = "RANDKEY";
356b528cefcSMark Murray 	ret = krb5_ret_principal(sp, &princ);
357b528cefcSMark Murray 	if(ret)
358b528cefcSMark Murray 	    goto fail;
35980999dcdSCy Schubert 	ret = krb5_unparse_name_fixed(contextp->context, princ, name, sizeof(name));
360ae771770SStanislav Sedov 	krb5_warnx(contextp->context, "%s: %s %s", client, op, name);
361b528cefcSMark Murray 	/*
362b528cefcSMark Murray 	 * The change is allowed if at least one of:
363b528cefcSMark Murray 	 * a) it's for the principal him/herself and this was an initial ticket
364b528cefcSMark Murray 	 * b) the user is on the CPW ACL.
365b528cefcSMark Murray 	 */
366b528cefcSMark Murray 
36780999dcdSCy Schubert 	if (ret == 0) {
368b528cefcSMark Murray 	    if (initial
369ae771770SStanislav Sedov 		&& krb5_principal_compare (contextp->context, contextp->caller,
370b528cefcSMark Murray 				       princ))
371b528cefcSMark Murray 		ret = 0;
372b528cefcSMark Murray 	    else
373ae771770SStanislav Sedov 		ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_CPW, princ);
37480999dcdSCy Schubert 	}
375b528cefcSMark Murray 	if(ret) {
376ae771770SStanislav Sedov 	    krb5_free_principal(contextp->context, princ);
377b528cefcSMark Murray 	    goto fail;
378b528cefcSMark Murray 	}
379ae771770SStanislav Sedov 	ret = kadm5_randkey_principal(kadm_handlep, princ,
380b528cefcSMark Murray 				      &new_keys, &n_keys);
381ae771770SStanislav Sedov 	krb5_free_principal(contextp->context, princ);
382b528cefcSMark Murray 	krb5_storage_free(sp);
383b528cefcSMark Murray 	sp = krb5_storage_emem();
384b528cefcSMark Murray 	krb5_store_int32(sp, ret);
385b528cefcSMark Murray 	if(ret == 0){
386b528cefcSMark Murray 	    int i;
387b528cefcSMark Murray 	    krb5_store_int32(sp, n_keys);
388b528cefcSMark Murray 	    for(i = 0; i < n_keys; i++){
389b528cefcSMark Murray 		krb5_store_keyblock(sp, new_keys[i]);
390ae771770SStanislav Sedov 		krb5_free_keyblock_contents(contextp->context, &new_keys[i]);
391b528cefcSMark Murray 	    }
392ae771770SStanislav Sedov 	    free(new_keys);
393b528cefcSMark Murray 	}
394b528cefcSMark Murray 	break;
395b528cefcSMark Murray     }
396b528cefcSMark Murray     case kadm_get_privs:{
397c19800e8SDoug Rabson 	uint32_t privs;
398ae771770SStanislav Sedov 	ret = kadm5_get_privs(kadm_handlep, &privs);
399b528cefcSMark Murray 	krb5_storage_free(sp);
400b528cefcSMark Murray 	sp = krb5_storage_emem();
401b528cefcSMark Murray 	krb5_store_int32(sp, ret);
402b528cefcSMark Murray 	if(ret == 0)
403c19800e8SDoug Rabson 	    krb5_store_uint32(sp, privs);
404b528cefcSMark Murray 	break;
405b528cefcSMark Murray     }
406b528cefcSMark Murray     case kadm_get_princs:{
407b528cefcSMark Murray 	op = "LIST";
408b528cefcSMark Murray 	ret = krb5_ret_int32(sp, &tmp);
409b528cefcSMark Murray 	if(ret)
410b528cefcSMark Murray 	    goto fail;
411b528cefcSMark Murray 	if(tmp){
412c19800e8SDoug Rabson 	    ret = krb5_ret_string(sp, &expression);
413b528cefcSMark Murray 	    if(ret)
414b528cefcSMark Murray 		goto fail;
415b528cefcSMark Murray 	}else
416c19800e8SDoug Rabson 	    expression = NULL;
417ae771770SStanislav Sedov 	krb5_warnx(contextp->context, "%s: %s %s", client, op,
418c19800e8SDoug Rabson 		   expression ? expression : "*");
419ae771770SStanislav Sedov 	ret = _kadm5_acl_check_permission(contextp, KADM5_PRIV_LIST, NULL);
420b528cefcSMark Murray 	if(ret){
421c19800e8SDoug Rabson 	    free(expression);
422b528cefcSMark Murray 	    goto fail;
423b528cefcSMark Murray 	}
424ae771770SStanislav Sedov 	ret = kadm5_get_principals(kadm_handlep, expression, &princs, &n_princs);
425c19800e8SDoug Rabson 	free(expression);
426b528cefcSMark Murray 	krb5_storage_free(sp);
427b528cefcSMark Murray 	sp = krb5_storage_emem();
428b528cefcSMark Murray 	krb5_store_int32(sp, ret);
429b528cefcSMark Murray 	if(ret == 0){
430b528cefcSMark Murray 	    int i;
431d24b2728SCy Schubert 	    if ((ret = krb5_store_int32(sp, n_princs)))
432d24b2728SCy Schubert 		goto fail;
433b528cefcSMark Murray 	    for(i = 0; i < n_princs; i++)
434d24b2728SCy Schubert 		if ((ret = krb5_store_string(sp, princs[i])))
435d24b2728SCy Schubert 			goto fail;
436ae771770SStanislav Sedov 	    kadm5_free_name_list(kadm_handlep, princs, &n_princs);
437b528cefcSMark Murray 	}
438b528cefcSMark Murray 	break;
439b528cefcSMark Murray     }
440b528cefcSMark Murray     default:
441ae771770SStanislav Sedov 	krb5_warnx(contextp->context, "%s: UNKNOWN OP %d", client, cmd);
442b528cefcSMark Murray 	krb5_storage_free(sp);
443b528cefcSMark Murray 	sp = krb5_storage_emem();
444b528cefcSMark Murray 	krb5_store_int32(sp, KADM5_FAILURE);
445b528cefcSMark Murray 	break;
446b528cefcSMark Murray     }
447b528cefcSMark Murray     krb5_storage_to_data(sp, out);
448b528cefcSMark Murray     krb5_storage_free(sp);
449b528cefcSMark Murray     return 0;
450b528cefcSMark Murray fail:
451ae771770SStanislav Sedov     krb5_warn(contextp->context, ret, "%s", op);
4528373020dSJacques Vidrine     krb5_storage_seek(sp, 0, SEEK_SET);
453b528cefcSMark Murray     krb5_store_int32(sp, ret);
454b528cefcSMark Murray     krb5_storage_to_data(sp, out);
455b528cefcSMark Murray     krb5_storage_free(sp);
456d24b2728SCy Schubert     return ret;
457b528cefcSMark Murray }
458b528cefcSMark Murray 
459b528cefcSMark Murray static void
v5_loop(krb5_context contextp,krb5_auth_context ac,krb5_boolean initial,void * kadm_handlep,krb5_socket_t fd)460ae771770SStanislav Sedov v5_loop (krb5_context contextp,
461b528cefcSMark Murray 	 krb5_auth_context ac,
462b528cefcSMark Murray 	 krb5_boolean initial,
463ae771770SStanislav Sedov 	 void *kadm_handlep,
464ae771770SStanislav Sedov 	 krb5_socket_t fd)
465b528cefcSMark Murray {
466b528cefcSMark Murray     krb5_error_code ret;
4675e9cd1aeSAssar Westerlund     krb5_data in, out;
468b528cefcSMark Murray 
469b528cefcSMark Murray     for (;;) {
4705e9cd1aeSAssar Westerlund 	doing_useful_work = 0;
4715e9cd1aeSAssar Westerlund 	if(term_flag)
472b528cefcSMark Murray 	    exit(0);
473ae771770SStanislav Sedov 	ret = krb5_read_priv_message(contextp, ac, &fd, &in);
4745e9cd1aeSAssar Westerlund 	if(ret == HEIM_ERR_EOF)
475b528cefcSMark Murray 	    exit(0);
476*3deefb0dSCy Schubert 	if (in.length == 0)
477*3deefb0dSCy Schubert 	    ret = HEIM_ERR_OPNOTSUPP;
478b528cefcSMark Murray 	if(ret)
479ae771770SStanislav Sedov 	    krb5_err(contextp, 1, ret, "krb5_read_priv_message");
4805e9cd1aeSAssar Westerlund 	doing_useful_work = 1;
481ae771770SStanislav Sedov 	kadmind_dispatch(kadm_handlep, initial, &in, &out);
482b528cefcSMark Murray 	krb5_data_free(&in);
483ae771770SStanislav Sedov 	ret = krb5_write_priv_message(contextp, ac, &fd, &out);
484b528cefcSMark Murray 	if(ret)
485ae771770SStanislav Sedov 	    krb5_err(contextp, 1, ret, "krb5_write_priv_message");
486b528cefcSMark Murray     }
487b528cefcSMark Murray }
488b528cefcSMark Murray 
489b528cefcSMark Murray static krb5_boolean
match_appl_version(const void * data,const char * appl_version)4900cadf2f4SJacques Vidrine match_appl_version(const void *data, const char *appl_version)
491b528cefcSMark Murray {
492b528cefcSMark Murray     unsigned minor;
493b528cefcSMark Murray     if(sscanf(appl_version, "KADM0.%u", &minor) != 1)
494b528cefcSMark Murray 	return 0;
495ae771770SStanislav Sedov     /*XXX*/
496ae771770SStanislav Sedov     *(unsigned*)(intptr_t)data = minor;
497b528cefcSMark Murray     return 1;
498b528cefcSMark Murray }
499b528cefcSMark Murray 
500b528cefcSMark Murray static void
handle_v5(krb5_context contextp,krb5_keytab keytab,krb5_socket_t fd)501ae771770SStanislav Sedov handle_v5(krb5_context contextp,
502b528cefcSMark Murray 	  krb5_keytab keytab,
503ae771770SStanislav Sedov 	  krb5_socket_t fd)
504b528cefcSMark Murray {
505b528cefcSMark Murray     krb5_error_code ret;
506b528cefcSMark Murray     krb5_ticket *ticket;
5075e9cd1aeSAssar Westerlund     char *server_name;
508b528cefcSMark Murray     char *client;
509ae771770SStanislav Sedov     void *kadm_handlep;
510b528cefcSMark Murray     krb5_boolean initial;
511ae771770SStanislav Sedov     krb5_auth_context ac = NULL;
512b528cefcSMark Murray 
513b528cefcSMark Murray     unsigned kadm_version;
514b528cefcSMark Murray     kadm5_config_params realm_params;
515b528cefcSMark Murray 
516ae771770SStanislav Sedov     ret = krb5_recvauth_match_version(contextp, &ac, &fd,
517b528cefcSMark Murray 				      match_appl_version, &kadm_version,
5185e9cd1aeSAssar Westerlund 				      NULL, KRB5_RECVAUTH_IGNORE_VERSION,
519b528cefcSMark Murray 				      keytab, &ticket);
520b528cefcSMark Murray     if (ret)
521ae771770SStanislav Sedov 	krb5_err(contextp, 1, ret, "krb5_recvauth");
522b528cefcSMark Murray 
523ae771770SStanislav Sedov     ret = krb5_unparse_name (contextp, ticket->server, &server_name);
5245e9cd1aeSAssar Westerlund     if (ret)
525ae771770SStanislav Sedov 	krb5_err (contextp, 1, ret, "krb5_unparse_name");
5265e9cd1aeSAssar Westerlund 
5275e9cd1aeSAssar Westerlund     if (strncmp (server_name, KADM5_ADMIN_SERVICE,
5285e9cd1aeSAssar Westerlund 		 strlen(KADM5_ADMIN_SERVICE)) != 0)
529ae771770SStanislav Sedov 	krb5_errx (contextp, 1, "ticket for strange principal (%s)",
5305e9cd1aeSAssar Westerlund 		   server_name);
5315e9cd1aeSAssar Westerlund 
5325e9cd1aeSAssar Westerlund     free (server_name);
5335e9cd1aeSAssar Westerlund 
534b528cefcSMark Murray     memset(&realm_params, 0, sizeof(realm_params));
535b528cefcSMark Murray 
536b528cefcSMark Murray     if(kadm_version == 1) {
5375e9cd1aeSAssar Westerlund 	krb5_data params;
538ae771770SStanislav Sedov 	ret = krb5_read_priv_message(contextp, ac, &fd, &params);
5395e9cd1aeSAssar Westerlund 	if(ret)
540ae771770SStanislav Sedov 	    krb5_err(contextp, 1, ret, "krb5_read_priv_message");
54105bc50bdSCy Schubert 	ret = _kadm5_unmarshal_params(contextp, &params, &realm_params);
54205bc50bdSCy Schubert 	if(ret)
54305bc50bdSCy Schubert 	    krb5_err(contextp, 1, ret, "Could not read or parse kadm5 parameters");
544b528cefcSMark Murray     }
545b528cefcSMark Murray 
546b528cefcSMark Murray     initial = ticket->ticket.flags.initial;
547ae771770SStanislav Sedov     ret = krb5_unparse_name(contextp, ticket->client, &client);
548b528cefcSMark Murray     if (ret)
549ae771770SStanislav Sedov 	krb5_err (contextp, 1, ret, "krb5_unparse_name");
550ae771770SStanislav Sedov     krb5_free_ticket (contextp, ticket);
551ae771770SStanislav Sedov     ret = kadm5_s_init_with_password_ctx(contextp,
552b528cefcSMark Murray 					 client,
553b528cefcSMark Murray 					 NULL,
554b528cefcSMark Murray 					 KADM5_ADMIN_SERVICE,
555b528cefcSMark Murray 					 &realm_params,
556b528cefcSMark Murray 					 0, 0,
557ae771770SStanislav Sedov 					 &kadm_handlep);
558b528cefcSMark Murray     if(ret)
559ae771770SStanislav Sedov 	krb5_err (contextp, 1, ret, "kadm5_init_with_password_ctx");
560ae771770SStanislav Sedov     v5_loop (contextp, ac, initial, kadm_handlep, fd);
561b528cefcSMark Murray }
562b528cefcSMark Murray 
563b528cefcSMark Murray krb5_error_code
kadmind_loop(krb5_context contextp,krb5_keytab keytab,krb5_socket_t sock)564ae771770SStanislav Sedov kadmind_loop(krb5_context contextp,
565b528cefcSMark Murray 	     krb5_keytab keytab,
566ae771770SStanislav Sedov 	     krb5_socket_t sock)
567b528cefcSMark Murray {
568ae771770SStanislav Sedov     u_char buf[sizeof(KRB5_SENDAUTH_VERSION) + 4];
569b528cefcSMark Murray     ssize_t n;
570b528cefcSMark Murray     unsigned long len;
571b528cefcSMark Murray 
572ae771770SStanislav Sedov     n = krb5_net_read(contextp, &sock, buf, 4);
573b528cefcSMark Murray     if(n == 0)
574b528cefcSMark Murray 	exit(0);
575b528cefcSMark Murray     if(n < 0)
576ae771770SStanislav Sedov 	krb5_err(contextp, 1, errno, "read");
577ae771770SStanislav Sedov     _krb5_get_int(buf, &len, 4);
578ae771770SStanislav Sedov 
579ae771770SStanislav Sedov     if (len == sizeof(KRB5_SENDAUTH_VERSION)) {
580ae771770SStanislav Sedov 
581ae771770SStanislav Sedov 	n = krb5_net_read(contextp, &sock, buf + 4, len);
582ae771770SStanislav Sedov 	if (n < 0)
583ae771770SStanislav Sedov 	    krb5_err (contextp, 1, errno, "reading sendauth version");
584ae771770SStanislav Sedov 	if (n == 0)
585ae771770SStanislav Sedov 	    krb5_errx (contextp, 1, "EOF reading sendauth version");
586ae771770SStanislav Sedov 
587ae771770SStanislav Sedov 	if(memcmp(buf + 4, KRB5_SENDAUTH_VERSION, len) == 0) {
588ae771770SStanislav Sedov 	    handle_v5(contextp, keytab, sock);
589ae771770SStanislav Sedov 	    return 0;
590b528cefcSMark Murray 	}
591ae771770SStanislav Sedov 	len += 4;
592ae771770SStanislav Sedov     } else
593ae771770SStanislav Sedov 	len = 4;
594ae771770SStanislav Sedov 
595ae771770SStanislav Sedov     handle_mit(contextp, buf, len, sock);
596ae771770SStanislav Sedov 
597b528cefcSMark Murray     return 0;
598b528cefcSMark Murray }
599