server.c revision 55682
155682Smarkm/*
255682Smarkm * Copyright (c) 1997 - 2000 Kungliga Tekniska H�gskolan
355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden).
455682Smarkm * All rights reserved.
555682Smarkm *
655682Smarkm * Redistribution and use in source and binary forms, with or without
755682Smarkm * modification, are permitted provided that the following conditions
855682Smarkm * are met:
955682Smarkm *
1055682Smarkm * 1. Redistributions of source code must retain the above copyright
1155682Smarkm *    notice, this list of conditions and the following disclaimer.
1255682Smarkm *
1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1455682Smarkm *    notice, this list of conditions and the following disclaimer in the
1555682Smarkm *    documentation and/or other materials provided with the distribution.
1655682Smarkm *
1755682Smarkm * 3. Neither the name of the Institute nor the names of its contributors
1855682Smarkm *    may be used to endorse or promote products derived from this software
1955682Smarkm *    without specific prior written permission.
2055682Smarkm *
2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2455682Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3155682Smarkm * SUCH DAMAGE.
3255682Smarkm */
3355682Smarkm
3455682Smarkm#include "kadmin_locl.h"
3555682Smarkm#include <krb5-private.h>
3655682Smarkm
3755682SmarkmRCSID("$Id: server.c,v 1.24 2000/01/02 03:58:45 assar Exp $");
3855682Smarkm
3955682Smarkmstatic kadm5_ret_t
4055682Smarkmkadmind_dispatch(void *kadm_handle, krb5_boolean initial,
4155682Smarkm		 krb5_data *in, krb5_data *out)
4255682Smarkm{
4355682Smarkm    kadm5_ret_t ret;
4455682Smarkm    int32_t cmd, mask, tmp;
4555682Smarkm    kadm5_server_context *context = kadm_handle;
4655682Smarkm    char client[128], name[128], name2[128];
4755682Smarkm    char *op = "";
4855682Smarkm    krb5_principal princ, princ2;
4955682Smarkm    kadm5_principal_ent_rec ent;
5055682Smarkm    char *password, *exp;
5155682Smarkm    krb5_keyblock *new_keys;
5255682Smarkm    int n_keys;
5355682Smarkm    char **princs;
5455682Smarkm    int n_princs;
5555682Smarkm    krb5_storage *sp;
5655682Smarkm
5755682Smarkm    krb5_unparse_name_fixed(context->context, context->caller,
5855682Smarkm			    client, sizeof(client));
5955682Smarkm
6055682Smarkm    sp = krb5_storage_from_data(in);
6155682Smarkm
6255682Smarkm    krb5_ret_int32(sp, &cmd);
6355682Smarkm    switch(cmd){
6455682Smarkm    case kadm_get:{
6555682Smarkm	op = "GET";
6655682Smarkm	ret = krb5_ret_principal(sp, &princ);
6755682Smarkm	if(ret)
6855682Smarkm	    goto fail;
6955682Smarkm	ret = krb5_ret_int32(sp, &mask);
7055682Smarkm	if(ret){
7155682Smarkm	    krb5_free_principal(context->context, princ);
7255682Smarkm	    goto fail;
7355682Smarkm	}
7455682Smarkm	krb5_unparse_name_fixed(context->context, princ, name, sizeof(name));
7555682Smarkm	krb5_warnx(context->context, "%s: %s %s", client, op, name);
7655682Smarkm	ret = _kadm5_acl_check_permission(context, KADM5_PRIV_GET);
7755682Smarkm	if(ret){
7855682Smarkm	    krb5_free_principal(context->context, princ);
7955682Smarkm	    goto fail;
8055682Smarkm	}
8155682Smarkm	ret = kadm5_get_principal(kadm_handle, princ, &ent, mask);
8255682Smarkm	krb5_storage_free(sp);
8355682Smarkm	sp = krb5_storage_emem();
8455682Smarkm	krb5_store_int32(sp, ret);
8555682Smarkm	if(ret == 0){
8655682Smarkm	    kadm5_store_principal_ent(sp, &ent);
8755682Smarkm	    kadm5_free_principal_ent(kadm_handle, &ent);
8855682Smarkm	}
8955682Smarkm	krb5_free_principal(context->context, princ);
9055682Smarkm	break;
9155682Smarkm    }
9255682Smarkm    case kadm_delete:{
9355682Smarkm	op = "DELETE";
9455682Smarkm	ret = krb5_ret_principal(sp, &princ);
9555682Smarkm	if(ret)
9655682Smarkm	    goto fail;
9755682Smarkm	krb5_unparse_name_fixed(context->context, princ, name, sizeof(name));
9855682Smarkm	krb5_warnx(context->context, "%s: %s %s", client, op, name);
9955682Smarkm	ret = _kadm5_acl_check_permission(context, KADM5_PRIV_DELETE);
10055682Smarkm	if(ret){
10155682Smarkm	    krb5_free_principal(context->context, princ);
10255682Smarkm	    goto fail;
10355682Smarkm	}
10455682Smarkm	ret = kadm5_delete_principal(kadm_handle, princ);
10555682Smarkm	krb5_free_principal(context->context, princ);
10655682Smarkm	krb5_storage_free(sp);
10755682Smarkm	sp = krb5_storage_emem();
10855682Smarkm	krb5_store_int32(sp, ret);
10955682Smarkm	break;
11055682Smarkm    }
11155682Smarkm    case kadm_create:{
11255682Smarkm	op = "CREATE";
11355682Smarkm	ret = kadm5_ret_principal_ent(sp, &ent);
11455682Smarkm	if(ret)
11555682Smarkm	    goto fail;
11655682Smarkm	ret = krb5_ret_int32(sp, &mask);
11755682Smarkm	if(ret){
11855682Smarkm	    kadm5_free_principal_ent(context->context, &ent);
11955682Smarkm	    goto fail;
12055682Smarkm	}
12155682Smarkm	ret = krb5_ret_string(sp, &password);
12255682Smarkm	if(ret){
12355682Smarkm	    kadm5_free_principal_ent(context->context, &ent);
12455682Smarkm	    goto fail;
12555682Smarkm	}
12655682Smarkm	krb5_unparse_name_fixed(context->context, ent.principal,
12755682Smarkm				name, sizeof(name));
12855682Smarkm	krb5_warnx(context->context, "%s: %s %s", client, op, name);
12955682Smarkm	ret = _kadm5_acl_check_permission(context, KADM5_PRIV_ADD);
13055682Smarkm	if(ret){
13155682Smarkm	    kadm5_free_principal_ent(context->context, &ent);
13255682Smarkm	    memset(password, 0, strlen(password));
13355682Smarkm	    free(password);
13455682Smarkm	    goto fail;
13555682Smarkm	}
13655682Smarkm	ret = kadm5_create_principal(kadm_handle, &ent,
13755682Smarkm				     mask, password);
13855682Smarkm	kadm5_free_principal_ent(kadm_handle, &ent);
13955682Smarkm	memset(password, 0, strlen(password));
14055682Smarkm	free(password);
14155682Smarkm	krb5_storage_free(sp);
14255682Smarkm	sp = krb5_storage_emem();
14355682Smarkm	krb5_store_int32(sp, ret);
14455682Smarkm	break;
14555682Smarkm    }
14655682Smarkm    case kadm_modify:{
14755682Smarkm	op = "MODIFY";
14855682Smarkm	ret = kadm5_ret_principal_ent(sp, &ent);
14955682Smarkm	if(ret)
15055682Smarkm	    goto fail;
15155682Smarkm	ret = krb5_ret_int32(sp, &mask);
15255682Smarkm	if(ret){
15355682Smarkm	    kadm5_free_principal_ent(context, &ent);
15455682Smarkm	    goto fail;
15555682Smarkm	}
15655682Smarkm	krb5_unparse_name_fixed(context->context, ent.principal,
15755682Smarkm				name, sizeof(name));
15855682Smarkm	krb5_warnx(context->context, "%s: %s %s", client, op, name);
15955682Smarkm	ret = _kadm5_acl_check_permission(context, KADM5_PRIV_MODIFY);
16055682Smarkm	if(ret){
16155682Smarkm	    kadm5_free_principal_ent(context, &ent);
16255682Smarkm	    goto fail;
16355682Smarkm	}
16455682Smarkm	ret = kadm5_modify_principal(kadm_handle, &ent, mask);
16555682Smarkm	kadm5_free_principal_ent(kadm_handle, &ent);
16655682Smarkm	krb5_storage_free(sp);
16755682Smarkm	sp = krb5_storage_emem();
16855682Smarkm	krb5_store_int32(sp, ret);
16955682Smarkm	break;
17055682Smarkm    }
17155682Smarkm    case kadm_rename:{
17255682Smarkm	op = "RENAME";
17355682Smarkm	ret = krb5_ret_principal(sp, &princ);
17455682Smarkm	if(ret)
17555682Smarkm	    goto fail;
17655682Smarkm	ret = krb5_ret_principal(sp, &princ2);
17755682Smarkm	if(ret){
17855682Smarkm	    krb5_free_principal(context->context, princ);
17955682Smarkm	    goto fail;
18055682Smarkm	}
18155682Smarkm	krb5_unparse_name_fixed(context->context, princ, name, sizeof(name));
18255682Smarkm	krb5_unparse_name_fixed(context->context, princ2, name2, sizeof(name2));
18355682Smarkm	krb5_warnx(context->context, "%s: %s %s -> %s",
18455682Smarkm		   client, op, name, name2);
18555682Smarkm	ret = _kadm5_acl_check_permission(context,
18655682Smarkm					  KADM5_PRIV_ADD|KADM5_PRIV_DELETE);
18755682Smarkm	if(ret){
18855682Smarkm	    krb5_free_principal(context->context, princ);
18955682Smarkm	    goto fail;
19055682Smarkm	}
19155682Smarkm	ret = kadm5_rename_principal(kadm_handle, princ, princ2);
19255682Smarkm	krb5_free_principal(context->context, princ);
19355682Smarkm	krb5_free_principal(context->context, princ2);
19455682Smarkm	krb5_storage_free(sp);
19555682Smarkm	sp = krb5_storage_emem();
19655682Smarkm	krb5_store_int32(sp, ret);
19755682Smarkm	break;
19855682Smarkm    }
19955682Smarkm    case kadm_chpass:{
20055682Smarkm	op = "CHPASS";
20155682Smarkm	ret = krb5_ret_principal(sp, &princ);
20255682Smarkm	if(ret)
20355682Smarkm	    goto fail;
20455682Smarkm	ret = krb5_ret_string(sp, &password);
20555682Smarkm	if(ret){
20655682Smarkm	    krb5_free_principal(context->context, princ);
20755682Smarkm	    goto fail;
20855682Smarkm	}
20955682Smarkm	krb5_unparse_name_fixed(context->context, princ, name, sizeof(name));
21055682Smarkm	krb5_warnx(context->context, "%s: %s %s", client, op, name);
21155682Smarkm
21255682Smarkm	/*
21355682Smarkm	 * The change is allowed if at least one of:
21455682Smarkm	 * a) it's for the principal him/herself and this was an initial ticket
21555682Smarkm	 * b) the user is on the CPW ACL.
21655682Smarkm	 */
21755682Smarkm
21855682Smarkm	if (initial
21955682Smarkm	    && krb5_principal_compare (context->context, context->caller,
22055682Smarkm				       princ))
22155682Smarkm	    ret = 0;
22255682Smarkm	else
22355682Smarkm	    ret = _kadm5_acl_check_permission(context, KADM5_PRIV_CPW);
22455682Smarkm
22555682Smarkm	if(ret) {
22655682Smarkm	    krb5_free_principal(context->context, princ);
22755682Smarkm	    goto fail;
22855682Smarkm	}
22955682Smarkm	ret = kadm5_chpass_principal(kadm_handle, princ, password);
23055682Smarkm	krb5_free_principal(context->context, princ);
23155682Smarkm	memset(password, 0, strlen(password));
23255682Smarkm	free(password);
23355682Smarkm	krb5_storage_free(sp);
23455682Smarkm	sp = krb5_storage_emem();
23555682Smarkm	krb5_store_int32(sp, ret);
23655682Smarkm	break;
23755682Smarkm    }
23855682Smarkm    case kadm_randkey:{
23955682Smarkm	op = "RANDKEY";
24055682Smarkm	ret = krb5_ret_principal(sp, &princ);
24155682Smarkm	if(ret)
24255682Smarkm	    goto fail;
24355682Smarkm	krb5_unparse_name_fixed(context->context, princ, name, sizeof(name));
24455682Smarkm	krb5_warnx(context->context, "%s: %s %s", client, op, name);
24555682Smarkm	/*
24655682Smarkm	 * The change is allowed if at least one of:
24755682Smarkm	 * a) it's for the principal him/herself and this was an initial ticket
24855682Smarkm	 * b) the user is on the CPW ACL.
24955682Smarkm	 */
25055682Smarkm
25155682Smarkm	if (initial
25255682Smarkm	    && krb5_principal_compare (context->context, context->caller,
25355682Smarkm				       princ))
25455682Smarkm	    ret = 0;
25555682Smarkm	else
25655682Smarkm	    ret = _kadm5_acl_check_permission(context, KADM5_PRIV_CPW);
25755682Smarkm
25855682Smarkm	if(ret) {
25955682Smarkm	    krb5_free_principal(context->context, princ);
26055682Smarkm	    goto fail;
26155682Smarkm	}
26255682Smarkm	ret = kadm5_randkey_principal(kadm_handle, princ,
26355682Smarkm				      &new_keys, &n_keys);
26455682Smarkm	krb5_free_principal(context->context, princ);
26555682Smarkm	krb5_storage_free(sp);
26655682Smarkm	sp = krb5_storage_emem();
26755682Smarkm	krb5_store_int32(sp, ret);
26855682Smarkm	if(ret == 0){
26955682Smarkm	    int i;
27055682Smarkm	    krb5_store_int32(sp, n_keys);
27155682Smarkm	    for(i = 0; i < n_keys; i++){
27255682Smarkm		krb5_store_keyblock(sp, new_keys[i]);
27355682Smarkm		krb5_free_keyblock_contents(context->context, &new_keys[i]);
27455682Smarkm	    }
27555682Smarkm	}
27655682Smarkm	break;
27755682Smarkm    }
27855682Smarkm    case kadm_get_privs:{
27955682Smarkm	ret = kadm5_get_privs(kadm_handle, &mask);
28055682Smarkm	krb5_storage_free(sp);
28155682Smarkm	sp = krb5_storage_emem();
28255682Smarkm	krb5_store_int32(sp, ret);
28355682Smarkm	if(ret == 0)
28455682Smarkm	    krb5_store_int32(sp, mask);
28555682Smarkm	break;
28655682Smarkm    }
28755682Smarkm    case kadm_get_princs:{
28855682Smarkm	op = "LIST";
28955682Smarkm	ret = krb5_ret_int32(sp, &tmp);
29055682Smarkm	if(ret)
29155682Smarkm	    goto fail;
29255682Smarkm	if(tmp){
29355682Smarkm	    ret = krb5_ret_string(sp, &exp);
29455682Smarkm	    if(ret)
29555682Smarkm		goto fail;
29655682Smarkm	}else
29755682Smarkm	    exp = NULL;
29855682Smarkm	krb5_warnx(context->context, "%s: %s %s", client, op, exp ? exp : "*");
29955682Smarkm	ret = _kadm5_acl_check_permission(context, KADM5_PRIV_LIST);
30055682Smarkm	if(ret){
30155682Smarkm	    free(exp);
30255682Smarkm	    goto fail;
30355682Smarkm	}
30455682Smarkm	ret = kadm5_get_principals(kadm_handle, exp, &princs, &n_princs);
30555682Smarkm	free(exp);
30655682Smarkm	krb5_storage_free(sp);
30755682Smarkm	sp = krb5_storage_emem();
30855682Smarkm	krb5_store_int32(sp, ret);
30955682Smarkm	if(ret == 0){
31055682Smarkm	    int i;
31155682Smarkm	    krb5_store_int32(sp, n_princs);
31255682Smarkm	    for(i = 0; i < n_princs; i++)
31355682Smarkm		krb5_store_string(sp, princs[i]);
31455682Smarkm	    kadm5_free_name_list(kadm_handle, princs, &n_princs);
31555682Smarkm	}
31655682Smarkm	break;
31755682Smarkm    }
31855682Smarkm    default:
31955682Smarkm	krb5_warnx(context->context, "%s: UNKNOWN OP %d", client, cmd);
32055682Smarkm	krb5_storage_free(sp);
32155682Smarkm	sp = krb5_storage_emem();
32255682Smarkm	krb5_store_int32(sp, KADM5_FAILURE);
32355682Smarkm	break;
32455682Smarkm    }
32555682Smarkm    krb5_storage_to_data(sp, out);
32655682Smarkm    krb5_storage_free(sp);
32755682Smarkm    return 0;
32855682Smarkmfail:
32955682Smarkm    krb5_warn(context->context, ret, "%s", op);
33055682Smarkm    sp->seek(sp, 0, SEEK_SET);
33155682Smarkm    krb5_store_int32(sp, ret);
33255682Smarkm    krb5_storage_to_data(sp, out);
33355682Smarkm    krb5_storage_free(sp);
33455682Smarkm    return 0;
33555682Smarkm}
33655682Smarkm
33755682Smarkmstatic void
33855682Smarkmv5_loop (krb5_context context,
33955682Smarkm	 krb5_auth_context ac,
34055682Smarkm	 krb5_boolean initial,
34155682Smarkm	 void *kadm_handle,
34255682Smarkm	 int fd)
34355682Smarkm{
34455682Smarkm    krb5_error_code ret;
34555682Smarkm    ssize_t n;
34655682Smarkm    unsigned long len;
34755682Smarkm    u_char tmp[4];
34855682Smarkm    struct iovec iov[2];
34955682Smarkm    krb5_data in, out, msg, reply;
35055682Smarkm
35155682Smarkm    for (;;) {
35255682Smarkm	n = krb5_net_read(context, &fd, tmp, 4);
35355682Smarkm	if (n < 0)
35455682Smarkm	    krb5_err (context, 1, errno, "krb5_net_read");
35555682Smarkm	if (n == 0)
35655682Smarkm	    exit (0);
35755682Smarkm	_krb5_get_int (tmp, &len, 4);
35855682Smarkm
35955682Smarkm	ret = krb5_data_alloc(&in, len);
36055682Smarkm	if (ret)
36155682Smarkm	    krb5_err (context, 1, ret, "krb5_data_alloc");
36255682Smarkm
36355682Smarkm	n = krb5_net_read(context, &fd, in.data, in.length);
36455682Smarkm	if (n == 0)
36555682Smarkm	    exit (0);
36655682Smarkm	if(n < 0)
36755682Smarkm	    krb5_errx(context, 1, "read error: %d", errno);
36855682Smarkm	ret = krb5_rd_priv(context, ac, &in, &out, NULL);
36955682Smarkm	if (ret)
37055682Smarkm	    krb5_err(context, 1, ret, "krb5_rd_priv");
37155682Smarkm	krb5_data_free(&in);
37255682Smarkm	kadmind_dispatch(kadm_handle, initial, &out, &msg);
37355682Smarkm	krb5_data_free(&out);
37455682Smarkm	ret = krb5_mk_priv(context, ac, &msg, &reply, NULL);
37555682Smarkm	krb5_data_free(&msg);
37655682Smarkm	if(ret)
37755682Smarkm	    krb5_err(context, 1, ret, "krb5_mk_priv");
37855682Smarkm
37955682Smarkm	_krb5_put_int(tmp, reply.length, 4);
38055682Smarkm
38155682Smarkm	iov[0].iov_base = tmp;
38255682Smarkm	iov[0].iov_len  = 4;
38355682Smarkm	iov[1].iov_base = reply.data;
38455682Smarkm	iov[1].iov_len  = reply.length;
38555682Smarkm	n = writev(fd, iov, 2);
38655682Smarkm	krb5_data_free(&reply);
38755682Smarkm	if(n < 0)
38855682Smarkm	    krb5_err(context, 1, errno, "writev");
38955682Smarkm	if(n < iov[0].iov_len + iov[1].iov_len)
39055682Smarkm	    krb5_errx(context, 1, "short write");
39155682Smarkm    }
39255682Smarkm}
39355682Smarkm
39455682Smarkmstatic krb5_boolean
39555682Smarkmmatch_appl_version(void *data, const char *appl_version)
39655682Smarkm{
39755682Smarkm    unsigned minor;
39855682Smarkm    if(sscanf(appl_version, "KADM0.%u", &minor) != 1)
39955682Smarkm	return 0;
40055682Smarkm    *(unsigned*)data = minor;
40155682Smarkm    return 1;
40255682Smarkm}
40355682Smarkm
40455682Smarkmstatic void
40555682Smarkmhandle_v5(krb5_context context,
40655682Smarkm	  krb5_auth_context ac,
40755682Smarkm	  krb5_keytab keytab,
40855682Smarkm	  int len,
40955682Smarkm	  int fd)
41055682Smarkm{
41155682Smarkm    krb5_error_code ret;
41255682Smarkm    u_char version[sizeof(KRB5_SENDAUTH_VERSION)];
41355682Smarkm    krb5_ticket *ticket;
41455682Smarkm    krb5_principal server;
41555682Smarkm    char *client;
41655682Smarkm    void *kadm_handle;
41755682Smarkm    ssize_t n;
41855682Smarkm    krb5_boolean initial;
41955682Smarkm
42055682Smarkm    unsigned kadm_version;
42155682Smarkm    kadm5_config_params realm_params;
42255682Smarkm
42355682Smarkm    if (len != sizeof(KRB5_SENDAUTH_VERSION))
42455682Smarkm	krb5_errx(context, 1, "bad sendauth len %d", len);
42555682Smarkm    n = krb5_net_read(context, &fd, version, len);
42655682Smarkm    if (n < 0)
42755682Smarkm	krb5_err (context, 1, errno, "reading sendauth version");
42855682Smarkm    if (n == 0)
42955682Smarkm	krb5_errx (context, 1, "EOF reading sendauth version");
43055682Smarkm    if(memcmp(version, KRB5_SENDAUTH_VERSION, len) != 0)
43155682Smarkm	krb5_errx(context, 1, "bad sendauth version %.8s", version);
43255682Smarkm
43355682Smarkm    ret = krb5_parse_name(context, KADM5_ADMIN_SERVICE, &server);
43455682Smarkm    if (ret)
43555682Smarkm	krb5_err (context, 1, ret, "krb5_parse_name %s", KADM5_ADMIN_SERVICE);
43655682Smarkm    ret = krb5_recvauth_match_version(context, &ac, &fd,
43755682Smarkm				      match_appl_version, &kadm_version,
43855682Smarkm				      server, KRB5_RECVAUTH_IGNORE_VERSION,
43955682Smarkm				      keytab, &ticket);
44055682Smarkm    if(ret == KRB5_KT_NOTFOUND) {
44155682Smarkm	char *name;
44255682Smarkm	krb5_unparse_name(context, server, &name);
44355682Smarkm	krb5_errx(context, 1, "krb5_recvauth: %s (%s)",
44455682Smarkm		  krb5_get_err_text(context, ret),
44555682Smarkm		  name);
44655682Smarkm    }
44755682Smarkm    krb5_free_principal(context, server);
44855682Smarkm
44955682Smarkm    if(ret)
45055682Smarkm	krb5_err(context, 1, ret, "krb5_recvauth");
45155682Smarkm
45255682Smarkm    memset(&realm_params, 0, sizeof(realm_params));
45355682Smarkm
45455682Smarkm    if(kadm_version == 1) {
45555682Smarkm	krb5_data enc_data, params;
45655682Smarkm	ret = krb5_read_message(context, &fd, &enc_data);
45755682Smarkm	ret = krb5_rd_priv(context, ac, &enc_data, &params, NULL);
45855682Smarkm	krb5_data_free(&enc_data);
45955682Smarkm	_kadm5_unmarshal_params(context, &params, &realm_params);
46055682Smarkm    }
46155682Smarkm
46255682Smarkm    initial = ticket->ticket.flags.initial;
46355682Smarkm    ret = krb5_unparse_name(context, ticket->client, &client);
46455682Smarkm    if (ret)
46555682Smarkm	krb5_err (context, 1, ret, "krb5_unparse_name");
46655682Smarkm    krb5_free_ticket (context, ticket);
46755682Smarkm    ret = kadm5_init_with_password_ctx(context,
46855682Smarkm				       client,
46955682Smarkm				       NULL,
47055682Smarkm				       KADM5_ADMIN_SERVICE,
47155682Smarkm				       &realm_params,
47255682Smarkm				       0, 0,
47355682Smarkm				       &kadm_handle);
47455682Smarkm    if(ret)
47555682Smarkm	krb5_err (context, 1, ret, "kadm5_init_with_password_ctx");
47655682Smarkm    v5_loop (context, ac, initial, kadm_handle, fd);
47755682Smarkm}
47855682Smarkm
47955682Smarkmkrb5_error_code
48055682Smarkmkadmind_loop(krb5_context context,
48155682Smarkm	     krb5_auth_context ac,
48255682Smarkm	     krb5_keytab keytab,
48355682Smarkm	     int fd)
48455682Smarkm{
48555682Smarkm    unsigned char tmp[4];
48655682Smarkm    ssize_t n;
48755682Smarkm    unsigned long len;
48855682Smarkm
48955682Smarkm    n = krb5_net_read(context, &fd, tmp, 4);
49055682Smarkm    if(n == 0)
49155682Smarkm	exit(0);
49255682Smarkm    if(n < 0)
49355682Smarkm	krb5_errx(context, 1, "read error: %d", errno);
49455682Smarkm    _krb5_get_int(tmp, &len, 4);
49555682Smarkm    if(len > 0xffff && (len & 0xffff) == ('K' << 8) + 'A') {
49655682Smarkm	len >>= 16;
49755682Smarkm#ifdef KRB4
49855682Smarkm	handle_v4(context, len, fd);
49955682Smarkm#else
50055682Smarkm	krb5_errx(context, 1, "packet appears to be version 4");
50155682Smarkm#endif
50255682Smarkm    } else {
50355682Smarkm	handle_v5(context, ac, keytab, len, fd);
50455682Smarkm    }
50555682Smarkm    return 0;
50655682Smarkm}
507