server.c revision 178826
1139734Simp/*
2139734Simp * Copyright (c) 1997 - 2005 Kungliga Tekniska H�gskolan
317773Swosch * (Royal Institute of Technology, Stockholm, Sweden).
417773Swosch * All rights reserved.
517773Swosch *
617773Swosch * Redistribution and use in source and binary forms, with or without
717773Swosch * modification, are permitted provided that the following conditions
817773Swosch * are met:
917773Swosch *
1017773Swosch * 1. Redistributions of source code must retain the above copyright
1117773Swosch *    notice, this list of conditions and the following disclaimer.
1217773Swosch *
1317773Swosch * 2. Redistributions in binary form must reproduce the above copyright
1417773Swosch *    notice, this list of conditions and the following disclaimer in the
1517773Swosch *    documentation and/or other materials provided with the distribution.
1617773Swosch *
1717773Swosch * 3. Neither the name of the Institute nor the names of its contributors
1817773Swosch *    may be used to endorse or promote products derived from this software
1917773Swosch *    without specific prior written permission.
2017773Swosch *
2117773Swosch * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
2217773Swosch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2317773Swosch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2417773Swosch * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
2517773Swosch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26146319Sru * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27141580Sru * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28141580Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29217087Strasz * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3012823Sphk * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3179538Sru * SUCH DAMAGE.
3212823Sphk */
3314003Smpp
3475670Sru#include "kadmin_locl.h"
3512823Sphk#include <krb5-private.h>
3626192Speter
3768716SruRCSID("$Id: server.c 17611 2006-06-02 22:10:21Z lha $");
3887529Sru
3987774Simpstatic kadm5_ret_t
4087773Simpkadmind_dispatch(void *kadm_handle, krb5_boolean initial,
4187773Simp		 krb5_data *in, krb5_data *out)
4287858Sru{
4387773Simp    kadm5_ret_t ret;
4471895Sru    int32_t cmd, mask, tmp;
4512823Sphk    kadm5_server_context *context = kadm_handle;
4675820Sobrien    char client[128], name[128], name2[128];
4775820Sobrien    char *op = "";
4875820Sobrien    krb5_principal princ, princ2;
4975820Sobrien    kadm5_principal_ent_rec ent;
5012823Sphk    char *password, *expression;
5112823Sphk    krb5_keyblock *new_keys;
5212823Sphk    int n_keys;
5312823Sphk    char **princs;
5412823Sphk    int n_princs;
5512823Sphk    krb5_storage *sp;
5612823Sphk
5712823Sphk    krb5_unparse_name_fixed(context->context, context->caller,
5812823Sphk			    client, sizeof(client));
5912951Sphk
6012951Sphk    sp = krb5_storage_from_data(in);
6112823Sphk
6214966Sjoerg    krb5_ret_int32(sp, &cmd);
6314966Sjoerg    switch(cmd){
64139947Skeramida    case kadm_get:{
65139725Simp	op = "GET";
66139725Simp	ret = krb5_ret_principal(sp, &princ);
67139725Simp	if(ret)
68166323Sjoel	    goto fail;
69166323Sjoel	ret = krb5_ret_int32(sp, &mask);
70139725Simp	if(ret){
71175108Sgrog	    krb5_free_principal(context->context, princ);
72139725Simp	    goto fail;
73139725Simp	}
74139947Skeramida	krb5_unparse_name_fixed(context->context, princ, name, sizeof(name));
75139734Simp	krb5_warnx(context->context, "%s: %s %s", client, op, name);
76139734Simp	ret = _kadm5_acl_check_permission(context, KADM5_PRIV_GET, princ);
77139734Simp	if(ret){
78139734Simp	    krb5_free_principal(context->context, princ);
79140173Sru	    goto fail;
80139734Simp	}
81139734Simp	ret = kadm5_get_principal(kadm_handle, princ, &ent, mask);
82139734Simp	krb5_storage_free(sp);
83146307Skeramida	sp = krb5_storage_emem();
84139734Simp	krb5_store_int32(sp, ret);
85139725Simp	if(ret == 0){
8675820Sobrien	    kadm5_store_principal_ent(sp, &ent);
87146319Sru	    kadm5_free_principal_ent(kadm_handle, &ent);
88146323Sobrien	}
8975820Sobrien	krb5_free_principal(context->context, princ);
9090018Sbde	break;
9183041Sgrog    }
9283041Sgrog    case kadm_delete:{
9390018Sbde	op = "DELETE";
9483041Sgrog	ret = krb5_ret_principal(sp, &princ);
9576708Sobrien	if(ret)
9690042Sobrien	    goto fail;
9792569Sru	krb5_unparse_name_fixed(context->context, princ, name, sizeof(name));
9892569Sru	krb5_warnx(context->context, "%s: %s %s", client, op, name);
9990018Sbde	ret = _kadm5_acl_check_permission(context, KADM5_PRIV_DELETE, princ);
10090018Sbde	if(ret){
10190018Sbde	    krb5_free_principal(context->context, princ);
10290018Sbde	    goto fail;
10390018Sbde	}
10490018Sbde	ret = kadm5_delete_principal(kadm_handle, princ);
10590018Sbde	krb5_free_principal(context->context, princ);
10675820Sobrien	krb5_storage_free(sp);
10790018Sbde	sp = krb5_storage_emem();
10890018Sbde	krb5_store_int32(sp, ret);
10990018Sbde	break;
110112629Sjhb    }
11190018Sbde    case kadm_create:{
112131132Sbde	op = "CREATE";
11383517Sobrien	ret = kadm5_ret_principal_ent(sp, &ent);
11484307Sru	if(ret)
11575820Sobrien	    goto fail;
11675820Sobrien	ret = krb5_ret_int32(sp, &mask);
11783041Sgrog	if(ret){
11875820Sobrien	    kadm5_free_principal_ent(context->context, &ent);
11987529Sru	    goto fail;
12087529Sru	}
12187529Sru	ret = krb5_ret_string(sp, &password);
122119893Sru	if(ret){
12387529Sru	    kadm5_free_principal_ent(context->context, &ent);
124119893Sru	    goto fail;
12587529Sru	}
126119893Sru	krb5_unparse_name_fixed(context->context, ent.principal,
12787529Sru				name, sizeof(name));
128119893Sru	krb5_warnx(context->context, "%s: %s %s", client, op, name);
12987529Sru	ret = _kadm5_acl_check_permission(context, KADM5_PRIV_ADD,
13071895Sru					  ent.principal);
13163324Sben	if(ret){
13214966Sjoerg	    kadm5_free_principal_ent(context->context, &ent);
13314966Sjoerg	    memset(password, 0, strlen(password));
13483041Sgrog	    free(password);
13571895Sru	    goto fail;
13612823Sphk	}
13712823Sphk	ret = kadm5_create_principal(kadm_handle, &ent,
13812823Sphk				     mask, password);
13912823Sphk	kadm5_free_principal_ent(kadm_handle, &ent);
14012823Sphk	memset(password, 0, strlen(password));
14114966Sjoerg	free(password);
14214966Sjoerg	krb5_storage_free(sp);
14387773Simp	sp = krb5_storage_emem();
14487773Simp	krb5_store_int32(sp, ret);
14587773Simp	break;
14687773Simp    }
14787529Sru    case kadm_modify:{
148130582Sru	op = "MODIFY";
149120530Simp	ret = kadm5_ret_principal_ent(sp, &ent);
15083041Sgrog	if(ret)
15171895Sru	    goto fail;
15212823Sphk	ret = krb5_ret_int32(sp, &mask);
15314966Sjoerg	if(ret){
15414966Sjoerg	    kadm5_free_principal_ent(context, &ent);
15587529Sru	    goto fail;
156119893Sru	}
15787529Sru	krb5_unparse_name_fixed(context->context, ent.principal,
15887529Sru				name, sizeof(name));
15987529Sru	krb5_warnx(context->context, "%s: %s %s", client, op, name);
16087529Sru	ret = _kadm5_acl_check_permission(context, KADM5_PRIV_MODIFY,
16171895Sru					  ent.principal);
16212823Sphk	if(ret){
16314966Sjoerg	    kadm5_free_principal_ent(context, &ent);
16414966Sjoerg	    goto fail;
16583041Sgrog	}
16671895Sru	ret = kadm5_modify_principal(kadm_handle, &ent, mask);
16712951Sphk	kadm5_free_principal_ent(kadm_handle, &ent);
16814966Sjoerg	krb5_storage_free(sp);
16914966Sjoerg	sp = krb5_storage_emem();
17087529Sru	krb5_store_int32(sp, ret);
17187529Sru	break;
17287529Sru    }
17364395Ssheldonh    case kadm_rename:{
17464395Ssheldonh	op = "RENAME";
17564395Ssheldonh	ret = krb5_ret_principal(sp, &princ);
17686725Sru	if(ret)
17764395Ssheldonh	    goto fail;
17864395Ssheldonh	ret = krb5_ret_principal(sp, &princ2);
17964395Ssheldonh	if(ret){
18064395Ssheldonh	    krb5_free_principal(context->context, princ);
18179727Sschweikh	    goto fail;
18287529Sru	}
18379727Sschweikh	krb5_unparse_name_fixed(context->context, princ, name, sizeof(name));
18464395Ssheldonh	krb5_unparse_name_fixed(context->context, princ2, name2, sizeof(name2));
18564395Ssheldonh	krb5_warnx(context->context, "%s: %s %s -> %s",
18664395Ssheldonh		   client, op, name, name2);
18764395Ssheldonh	ret = _kadm5_acl_check_permission(context,
18864395Ssheldonh					  KADM5_PRIV_ADD,
18964395Ssheldonh					  princ2)
19063427Sben	    || _kadm5_acl_check_permission(context,
19149363Shoek					   KADM5_PRIV_DELETE,
19231613Swollman					   princ);
19387529Sru	if(ret){
19431613Swollman	    krb5_free_principal(context->context, princ);
19579727Sschweikh	    krb5_free_principal(context->context, princ2);
19687529Sru	    goto fail;
19731613Swollman	}
19831614Swollman	ret = kadm5_rename_principal(kadm_handle, princ, princ2);
19931613Swollman	krb5_free_principal(context->context, princ);
20031613Swollman	krb5_free_principal(context->context, princ2);
20171895Sru	krb5_storage_free(sp);
20231613Swollman	sp = krb5_storage_emem();
20312951Sphk	krb5_store_int32(sp, ret);
20412951Sphk	break;
20591436Simp    }
20614966Sjoerg    case kadm_chpass:{
20714966Sjoerg	op = "CHPASS";
208106302Srwatson	ret = krb5_ret_principal(sp, &princ);
209106092Srwatson	if(ret)
210106092Srwatson	    goto fail;
211106092Srwatson	ret = krb5_ret_string(sp, &password);
212106092Srwatson	if(ret){
213106092Srwatson	    krb5_free_principal(context->context, princ);
214106092Srwatson	    goto fail;
215106092Srwatson	}
216106302Srwatson	krb5_unparse_name_fixed(context->context, princ, name, sizeof(name));
217106092Srwatson	krb5_warnx(context->context, "%s: %s %s", client, op, name);
218106092Srwatson
219106092Srwatson	/*
220106092Srwatson	 * The change is allowed if at least one of:
221106092Srwatson
222106302Srwatson	 * a) it's for the principal him/herself and this was an
223107383Sru	 *    initial ticket, but then, check with the password quality
224107383Sru	 *    function.
225107383Sru	 * b) the user is on the CPW ACL.
226106302Srwatson	 */
227106092Srwatson
228106092Srwatson	if (initial
229106092Srwatson	    && krb5_principal_compare (context->context, context->caller,
230106092Srwatson				       princ))
231106302Srwatson	{
232106092Srwatson	    krb5_data pwd_data;
233106092Srwatson	    const char *pwd_reason;
234106092Srwatson
235106092Srwatson	    pwd_data.data = password;
236106302Srwatson	    pwd_data.length = strlen(password);
237106092Srwatson
238106092Srwatson	    pwd_reason = kadm5_check_password_quality (context->context,
239106092Srwatson						       princ, &pwd_data);
240106092Srwatson	    if (pwd_reason != NULL)
241106092Srwatson		ret = KADM5_PASS_Q_DICT;
242106302Srwatson	    else
243106302Srwatson		ret = 0;
244106302Srwatson	} else
245106092Srwatson	    ret = _kadm5_acl_check_permission(context, KADM5_PRIV_CPW, princ);
246106302Srwatson
247106302Srwatson	if(ret) {
248106302Srwatson	    krb5_free_principal(context->context, princ);
249106092Srwatson	    memset(password, 0, strlen(password));
250106092Srwatson	    free(password);
251106092Srwatson	    goto fail;
252106092Srwatson	}
253106092Srwatson	ret = kadm5_chpass_principal(kadm_handle, princ, password);
254106092Srwatson	krb5_free_principal(context->context, princ);
255106092Srwatson	memset(password, 0, strlen(password));
256106092Srwatson	free(password);
257106092Srwatson	krb5_storage_free(sp);
258106092Srwatson	sp = krb5_storage_emem();
259106092Srwatson	krb5_store_int32(sp, ret);
260106092Srwatson	break;
261106092Srwatson    }
262106092Srwatson    case kadm_chpass_with_key:{
263106302Srwatson	int i;
264106092Srwatson	krb5_key_data *key_data;
265106092Srwatson	int n_key_data;
266106092Srwatson
267106092Srwatson	op = "CHPASS_WITH_KEY";
268106092Srwatson	ret = krb5_ret_principal(sp, &princ);
269106302Srwatson	if(ret)
270106092Srwatson	    goto fail;
271106092Srwatson	ret = krb5_ret_int32(sp, &n_key_data);
272130432Sle	if (ret) {
273106092Srwatson	    krb5_free_principal(context->context, princ);
274106092Srwatson	    goto fail;
275130582Sru	}
276130582Sru	/* n_key_data will be squeezed into an int16_t below. */
277120530Simp	if (n_key_data < 0 || n_key_data >= 1 << 16 ||
278130582Sru	    n_key_data > UINT_MAX/sizeof(*key_data)) {
279130582Sru	    ret = ERANGE;
280130582Sru	    krb5_free_principal(context->context, princ);
281130582Sru	    goto fail;
282130582Sru	}
283120530Simp
284120530Simp	key_data = malloc (n_key_data * sizeof(*key_data));
285130582Sru	if (key_data == NULL) {
286130582Sru	    ret = ENOMEM;
287120530Simp	    krb5_free_principal(context->context, princ);
288130582Sru	    goto fail;
289120530Simp	}
290120530Simp
29131613Swollman	for (i = 0; i < n_key_data; ++i) {
29271895Sru	    ret = kadm5_ret_key_data (sp, &key_data[i]);
29312823Sphk	    if (ret) {
29414966Sjoerg		int16_t dummy = i;
29514966Sjoerg
296209546Scperciva		kadm5_free_key_data (context, &dummy, key_data);
297209546Scperciva		free (key_data);
298209546Scperciva		krb5_free_principal(context->context, princ);
299103189Srobert		goto fail;
300103189Srobert	    }
301107383Sru	}
302107383Sru
303107383Sru	krb5_unparse_name_fixed(context->context, princ, name, sizeof(name));
304107383Sru	krb5_warnx(context->context, "%s: %s %s", client, op, name);
305107383Sru
306108317Sschweikh	/*
307103189Srobert	 * The change is only allowed if the user is on the CPW ACL,
30814966Sjoerg	 * this it to force password quality check on the user.
309138327Sdds	 */
31087529Sru
31187529Sru	ret = _kadm5_acl_check_permission(context, KADM5_PRIV_CPW, princ);
31285367Sjulian	if(ret) {
31385445Sjulian	    int16_t dummy = n_key_data;
31485480Sbde
31599240Simp	    kadm5_free_key_data (context, &dummy, key_data);
31699240Simp	    free (key_data);
31785445Sjulian	    krb5_free_principal(context->context, princ);
31885480Sbde	    goto fail;
31914966Sjoerg	}
32014966Sjoerg	ret = kadm5_chpass_principal_with_key(kadm_handle, princ,
32149363Shoek					      n_key_data, key_data);
32287529Sru	{
32387529Sru	    int16_t dummy = n_key_data;
32487529Sru	    kadm5_free_key_data (context, &dummy, key_data);
32587529Sru	}
32687529Sru	free (key_data);
32771895Sru	krb5_free_principal(context->context, princ);
32812823Sphk	krb5_storage_free(sp);
32985445Sjulian	sp = krb5_storage_emem();
33085445Sjulian	krb5_store_int32(sp, ret);
33185445Sjulian	break;
33285445Sjulian    }
33312823Sphk    case kadm_randkey:{
33485445Sjulian	op = "RANDKEY";
33531612Swollman	ret = krb5_ret_principal(sp, &princ);
33631613Swollman	if(ret)
33731612Swollman	    goto fail;
33831612Swollman	krb5_unparse_name_fixed(context->context, princ, name, sizeof(name));
33987529Sru	krb5_warnx(context->context, "%s: %s %s", client, op, name);
34087529Sru	/*
34131612Swollman	 * The change is allowed if at least one of:
34271895Sru	 * a) it's for the principal him/herself and this was an initial ticket
34331612Swollman	 * b) the user is on the CPW ACL.
34487529Sru	 */
34582952Sobrien
34685480Sbde	if (initial
34785445Sjulian	    && krb5_principal_compare (context->context, context->caller,
34885445Sjulian				       princ))
34985445Sjulian	    ret = 0;
35031612Swollman	else
35185445Sjulian	    ret = _kadm5_acl_check_permission(context, KADM5_PRIV_CPW, princ);
35231612Swollman
35331612Swollman	if(ret) {
35487529Sru	    krb5_free_principal(context->context, princ);
355122424Sfanf	    goto fail;
356122424Sfanf	}
357122424Sfanf	ret = kadm5_randkey_principal(kadm_handle, princ,
358122424Sfanf				      &new_keys, &n_keys);
359122424Sfanf	krb5_free_principal(context->context, princ);
360122424Sfanf	krb5_storage_free(sp);
361122424Sfanf	sp = krb5_storage_emem();
362122554Sfanf	krb5_store_int32(sp, ret);
363122424Sfanf	if(ret == 0){
364122424Sfanf	    int i;
365122424Sfanf	    krb5_store_int32(sp, n_keys);
366122424Sfanf	    for(i = 0; i < n_keys; i++){
36787529Sru		krb5_store_keyblock(sp, new_keys[i]);
36887529Sru		krb5_free_keyblock_contents(context->context, &new_keys[i]);
36987529Sru	    }
37087529Sru	}
37187529Sru	break;
372107282Sru    }
373107282Sru    case kadm_get_privs:{
37471895Sru	uint32_t privs;
37512823Sphk	ret = kadm5_get_privs(kadm_handle, &privs);
37687569Sobrien	krb5_storage_free(sp);
37712951Sphk	sp = krb5_storage_emem();
37812823Sphk	krb5_store_int32(sp, ret);
37987569Sobrien	if(ret == 0)
38087569Sobrien	    krb5_store_uint32(sp, privs);
38114966Sjoerg	break;
38214966Sjoerg    }
38314966Sjoerg    case kadm_get_princs:{
38414966Sjoerg	op = "LIST";
385131530Sru	ret = krb5_ret_int32(sp, &tmp);
38687529Sru	if(ret)
38787529Sru	    goto fail;
38814966Sjoerg	if(tmp){
38987529Sru	    ret = krb5_ret_string(sp, &expression);
39014966Sjoerg	    if(ret)
39114966Sjoerg		goto fail;
39214966Sjoerg	}else
393102212Simp	    expression = NULL;
394103011Srobert	krb5_warnx(context->context, "%s: %s %s", client, op,
395102212Simp		   expression ? expression : "*");
39614966Sjoerg	ret = _kadm5_acl_check_permission(context, KADM5_PRIV_LIST, NULL);
39714966Sjoerg	if(ret){
39881449Sru	    free(expression);
39987529Sru	    goto fail;
40014966Sjoerg	}
40190043Simp	ret = kadm5_get_principals(kadm_handle, expression, &princs, &n_princs);
40287529Sru	free(expression);
40390043Simp	krb5_storage_free(sp);
40414966Sjoerg	sp = krb5_storage_emem();
40526192Speter	krb5_store_int32(sp, ret);
40687529Sru	if(ret == 0){
40787529Sru	    int i;
40887529Sru	    krb5_store_int32(sp, n_princs);
40987529Sru	    for(i = 0; i < n_princs; i++)
41087529Sru		krb5_store_string(sp, princs[i]);
41187529Sru	    kadm5_free_name_list(kadm_handle, princs, &n_princs);
41226192Speter	}
41326192Speter	break;
41414966Sjoerg    }
41571895Sru    default:
41626192Speter	krb5_warnx(context->context, "%s: UNKNOWN OP %d", client, cmd);
41714966Sjoerg	krb5_storage_free(sp);
41814966Sjoerg	sp = krb5_storage_emem();
41949363Shoek	krb5_store_int32(sp, KADM5_FAILURE);
42084408Sobrien	break;
42186725Sru    }
42287529Sru    krb5_storage_to_data(sp, out);
42387529Sru    krb5_storage_free(sp);
42484408Sobrien    return 0;
42581449Srufail:
42671895Sru    krb5_warn(context->context, ret, "%s", op);
42726192Speter    krb5_storage_seek(sp, 0, SEEK_SET);
42826192Speter    krb5_store_int32(sp, ret);
42926192Speter    krb5_storage_to_data(sp, out);
43026192Speter    krb5_storage_free(sp);
43171895Sru    return 0;
43226192Speter}
43326192Speter
43426192Speterstatic void
43526192Speterv5_loop (krb5_context context,
43626192Speter	 krb5_auth_context ac,
43771895Sru	 krb5_boolean initial,
43826192Speter	 void *kadm_handle,
43975819Sobrien	 int fd)
44026192Speter{
44112951Sphk    krb5_error_code ret;
44212823Sphk    krb5_data in, out;
44312823Sphk
44412823Sphk    for (;;) {
44512823Sphk	doing_useful_work = 0;
44612823Sphk	if(term_flag)
44712823Sphk	    exit(0);
44826192Speter	ret = krb5_read_priv_message(context, ac, &fd, &in);
44912823Sphk	if(ret == HEIM_ERR_EOF)
45093107Sobrien	    exit(0);
45112951Sphk	if(ret)
45212951Sphk	    krb5_err(context, 1, ret, "krb5_read_priv_message");
45314966Sjoerg	doing_useful_work = 1;
45414966Sjoerg	kadmind_dispatch(kadm_handle, initial, &in, &out);
45587529Sru	krb5_data_free(&in);
45687529Sru	ret = krb5_write_priv_message(context, ac, &fd, &out);
45787529Sru	if(ret)
45887529Sru	    krb5_err(context, 1, ret, "krb5_write_priv_message");
45987529Sru    }
46087529Sru}
46187529Sru
46287529Srustatic krb5_boolean
46387529Srumatch_appl_version(const void *data, const char *appl_version)
46487529Sru{
46587529Sru    unsigned minor;
46687529Sru    if(sscanf(appl_version, "KADM0.%u", &minor) != 1)
46787529Sru	return 0;
46887529Sru    *(unsigned*)data = minor;
46987529Sru    return 1;
47087529Sru}
47187529Sru
47287529Srustatic void
473217087Straszhandle_v5(krb5_context context,
474217087Strasz	  krb5_auth_context ac,
475217087Strasz	  krb5_keytab keytab,
47671895Sru	  int len,
477131127Sobrien	  int fd)
47812951Sphk{
47912951Sphk    krb5_error_code ret;
480164639Sobrien    u_char version[sizeof(KRB5_SENDAUTH_VERSION)];
48112951Sphk    krb5_ticket *ticket;
48212951Sphk    char *server_name;
48312951Sphk    char *client;
48412951Sphk    void *kadm_handle;
485131127Sobrien    ssize_t n;
486131127Sobrien    krb5_boolean initial;
487131127Sobrien
48812951Sphk    unsigned kadm_version;
48912951Sphk    kadm5_config_params realm_params;
49049361Shoek
49149361Shoek    if (len != sizeof(KRB5_SENDAUTH_VERSION))
49249361Shoek	krb5_errx(context, 1, "bad sendauth len %d", len);
49349361Shoek    n = krb5_net_read(context, &fd, version, len);
49449361Shoek    if (n < 0)
49512951Sphk	krb5_err (context, 1, errno, "reading sendauth version");
49617812Swosch    if (n == 0)
49712951Sphk	krb5_errx (context, 1, "EOF reading sendauth version");
49812951Sphk    if(memcmp(version, KRB5_SENDAUTH_VERSION, len) != 0)
49912951Sphk	krb5_errx(context, 1, "bad sendauth version %.8s", version);
50012951Sphk
50112951Sphk    ret = krb5_recvauth_match_version(context, &ac, &fd,
50214966Sjoerg				      match_appl_version, &kadm_version,
50314966Sjoerg				      NULL, KRB5_RECVAUTH_IGNORE_VERSION,
50487529Sru				      keytab, &ticket);
50587529Sru    if(ret == KRB5_KT_NOTFOUND)
506103179Sfanf	krb5_errx(context, 1, "krb5_recvauth: key not found");
507103179Sfanf    if(ret)
508103179Sfanf	krb5_err(context, 1, ret, "krb5_recvauth");
509103179Sfanf
510103179Sfanf    ret = krb5_unparse_name (context, ticket->server, &server_name);
51143406Sjulian    if (ret)
51243406Sjulian	krb5_err (context, 1, ret, "krb5_unparse_name");
51387529Sru
51487529Sru    if (strncmp (server_name, KADM5_ADMIN_SERVICE,
51587529Sru		 strlen(KADM5_ADMIN_SERVICE)) != 0)
51687529Sru	krb5_errx (context, 1, "ticket for strange principal (%s)",
51771895Sru		   server_name);
51826192Speter
51926192Speter    free (server_name);
52012951Sphk
52112951Sphk    memset(&realm_params, 0, sizeof(realm_params));
52243406Sjulian
52343406Sjulian    if(kadm_version == 1) {
52494682Sasmodai	krb5_data params;
52543406Sjulian	ret = krb5_read_priv_message(context, ac, &fd, &params);
52643406Sjulian	if(ret)
52743406Sjulian	    krb5_err(context, 1, ret, "krb5_read_priv_message");
52843406Sjulian	_kadm5_unmarshal_params(context, &params, &realm_params);
52943406Sjulian    }
53043406Sjulian
53126192Speter    initial = ticket->ticket.flags.initial;
53226192Speter    ret = krb5_unparse_name(context, ticket->client, &client);
53314966Sjoerg    if (ret)
53414966Sjoerg	krb5_err (context, 1, ret, "krb5_unparse_name");
53587529Sru    krb5_free_ticket (context, ticket);
53687529Sru    ret = kadm5_init_with_password_ctx(context,
53787529Sru				       client,
53887529Sru				       NULL,
53914966Sjoerg				       KADM5_ADMIN_SERVICE,
54071895Sru				       &realm_params,
54112951Sphk				       0, 0,
54212951Sphk				       &kadm_handle);
54312951Sphk    if(ret)
54412951Sphk	krb5_err (context, 1, ret, "kadm5_init_with_password_ctx");
54514966Sjoerg    v5_loop (context, ac, initial, kadm_handle, fd);
54614966Sjoerg}
54726192Speter
54814966Sjoergkrb5_error_code
54980139Sddkadmind_loop(krb5_context context,
55080139Sdd	     krb5_auth_context ac,
55171895Sru	     krb5_keytab keytab,
55294682Sasmodai	     int fd)
55380139Sdd{
55415095Smpp    unsigned char tmp[4];
55594682Sasmodai    ssize_t n;
55678432Sdd    unsigned long len;
55714966Sjoerg
55814966Sjoerg    n = krb5_net_read(context, &fd, tmp, 4);
55949363Shoek    if(n == 0)
56049363Shoek	exit(0);
56187529Sru    if(n < 0)
56287529Sru	krb5_err(context, 1, errno, "read");
56326192Speter    _krb5_get_int(tmp, &len, 4);
56426192Speter    /* this v4 test could probably also go away */
56587529Sru    if(len > 0xffff && (len & 0xffff) == ('K' << 8) + 'A') {
56687529Sru	unsigned char v4reply[] = {
56787529Sru	    0x00, 0x0c,
56871895Sru	    'K', 'Y', 'O', 'U', 'L', 'O', 'S', 'E',
56912951Sphk	    0x95, 0xb7, 0xa7, 0x08 /* KADM_BAD_VER */
57012951Sphk	};
57112951Sphk	krb5_net_write(context, &fd, v4reply, sizeof(v4reply));
57212951Sphk	krb5_errx(context, 1, "packet appears to be version 4");
57312951Sphk    } else {
57412951Sphk	handle_v5(context, ac, keytab, len, fd);
57512951Sphk    }
57614966Sjoerg    return 0;
57714966Sjoerg}
57887529Sru