server.c revision 72445
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
3772445SassarRCSID("$Id: server.c,v 1.32 2000/09/19 12:46:01 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);
7672445Sassar	ret = _kadm5_acl_check_permission(context, KADM5_PRIV_GET, princ);
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);
9972445Sassar	ret = _kadm5_acl_check_permission(context, KADM5_PRIV_DELETE, princ);
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);
12972445Sassar	ret = _kadm5_acl_check_permission(context, KADM5_PRIV_ADD,
13072445Sassar					  ent.principal);
13155682Smarkm	if(ret){
13255682Smarkm	    kadm5_free_principal_ent(context->context, &ent);
13355682Smarkm	    memset(password, 0, strlen(password));
13455682Smarkm	    free(password);
13555682Smarkm	    goto fail;
13655682Smarkm	}
13755682Smarkm	ret = kadm5_create_principal(kadm_handle, &ent,
13855682Smarkm				     mask, password);
13955682Smarkm	kadm5_free_principal_ent(kadm_handle, &ent);
14055682Smarkm	memset(password, 0, strlen(password));
14155682Smarkm	free(password);
14255682Smarkm	krb5_storage_free(sp);
14355682Smarkm	sp = krb5_storage_emem();
14455682Smarkm	krb5_store_int32(sp, ret);
14555682Smarkm	break;
14655682Smarkm    }
14755682Smarkm    case kadm_modify:{
14855682Smarkm	op = "MODIFY";
14955682Smarkm	ret = kadm5_ret_principal_ent(sp, &ent);
15055682Smarkm	if(ret)
15155682Smarkm	    goto fail;
15255682Smarkm	ret = krb5_ret_int32(sp, &mask);
15355682Smarkm	if(ret){
15455682Smarkm	    kadm5_free_principal_ent(context, &ent);
15555682Smarkm	    goto fail;
15655682Smarkm	}
15755682Smarkm	krb5_unparse_name_fixed(context->context, ent.principal,
15855682Smarkm				name, sizeof(name));
15955682Smarkm	krb5_warnx(context->context, "%s: %s %s", client, op, name);
16072445Sassar	ret = _kadm5_acl_check_permission(context, KADM5_PRIV_MODIFY,
16172445Sassar					  ent.principal);
16255682Smarkm	if(ret){
16355682Smarkm	    kadm5_free_principal_ent(context, &ent);
16455682Smarkm	    goto fail;
16555682Smarkm	}
16655682Smarkm	ret = kadm5_modify_principal(kadm_handle, &ent, mask);
16755682Smarkm	kadm5_free_principal_ent(kadm_handle, &ent);
16855682Smarkm	krb5_storage_free(sp);
16955682Smarkm	sp = krb5_storage_emem();
17055682Smarkm	krb5_store_int32(sp, ret);
17155682Smarkm	break;
17255682Smarkm    }
17355682Smarkm    case kadm_rename:{
17455682Smarkm	op = "RENAME";
17555682Smarkm	ret = krb5_ret_principal(sp, &princ);
17655682Smarkm	if(ret)
17755682Smarkm	    goto fail;
17855682Smarkm	ret = krb5_ret_principal(sp, &princ2);
17955682Smarkm	if(ret){
18055682Smarkm	    krb5_free_principal(context->context, princ);
18155682Smarkm	    goto fail;
18255682Smarkm	}
18355682Smarkm	krb5_unparse_name_fixed(context->context, princ, name, sizeof(name));
18455682Smarkm	krb5_unparse_name_fixed(context->context, princ2, name2, sizeof(name2));
18555682Smarkm	krb5_warnx(context->context, "%s: %s %s -> %s",
18655682Smarkm		   client, op, name, name2);
18755682Smarkm	ret = _kadm5_acl_check_permission(context,
18872445Sassar					  KADM5_PRIV_ADD,
18972445Sassar					  princ2)
19072445Sassar	    || _kadm5_acl_check_permission(context,
19172445Sassar					   KADM5_PRIV_DELETE,
19272445Sassar					   princ);
19355682Smarkm	if(ret){
19455682Smarkm	    krb5_free_principal(context->context, princ);
19555682Smarkm	    goto fail;
19655682Smarkm	}
19755682Smarkm	ret = kadm5_rename_principal(kadm_handle, princ, princ2);
19855682Smarkm	krb5_free_principal(context->context, princ);
19955682Smarkm	krb5_free_principal(context->context, princ2);
20055682Smarkm	krb5_storage_free(sp);
20155682Smarkm	sp = krb5_storage_emem();
20255682Smarkm	krb5_store_int32(sp, ret);
20355682Smarkm	break;
20455682Smarkm    }
20555682Smarkm    case kadm_chpass:{
20655682Smarkm	op = "CHPASS";
20755682Smarkm	ret = krb5_ret_principal(sp, &princ);
20855682Smarkm	if(ret)
20955682Smarkm	    goto fail;
21055682Smarkm	ret = krb5_ret_string(sp, &password);
21155682Smarkm	if(ret){
21255682Smarkm	    krb5_free_principal(context->context, princ);
21355682Smarkm	    goto fail;
21455682Smarkm	}
21555682Smarkm	krb5_unparse_name_fixed(context->context, princ, name, sizeof(name));
21655682Smarkm	krb5_warnx(context->context, "%s: %s %s", client, op, name);
21755682Smarkm
21855682Smarkm	/*
21955682Smarkm	 * The change is allowed if at least one of:
22055682Smarkm	 * a) it's for the principal him/herself and this was an initial ticket
22155682Smarkm	 * b) the user is on the CPW ACL.
22255682Smarkm	 */
22355682Smarkm
22455682Smarkm	if (initial
22555682Smarkm	    && krb5_principal_compare (context->context, context->caller,
22655682Smarkm				       princ))
22755682Smarkm	    ret = 0;
22855682Smarkm	else
22972445Sassar	    ret = _kadm5_acl_check_permission(context, KADM5_PRIV_CPW, princ);
23055682Smarkm
23155682Smarkm	if(ret) {
23255682Smarkm	    krb5_free_principal(context->context, princ);
23355682Smarkm	    goto fail;
23455682Smarkm	}
23555682Smarkm	ret = kadm5_chpass_principal(kadm_handle, princ, password);
23655682Smarkm	krb5_free_principal(context->context, princ);
23755682Smarkm	memset(password, 0, strlen(password));
23855682Smarkm	free(password);
23955682Smarkm	krb5_storage_free(sp);
24055682Smarkm	sp = krb5_storage_emem();
24155682Smarkm	krb5_store_int32(sp, ret);
24255682Smarkm	break;
24355682Smarkm    }
24472445Sassar    case kadm_chpass_with_key:{
24572445Sassar	int i;
24672445Sassar	krb5_key_data *key_data;
24772445Sassar	int n_key_data;
24872445Sassar
24972445Sassar	op = "CHPASS_WITH_KEY";
25072445Sassar	ret = krb5_ret_principal(sp, &princ);
25172445Sassar	if(ret)
25272445Sassar	    goto fail;
25372445Sassar	ret = krb5_ret_int32(sp, &n_key_data);
25472445Sassar	if (ret) {
25572445Sassar	    krb5_free_principal(context->context, princ);
25672445Sassar	    goto fail;
25772445Sassar	}
25872445Sassar
25972445Sassar	key_data = malloc (n_key_data * sizeof(*key_data));
26072445Sassar	if (key_data == NULL) {
26172445Sassar	    ret = ENOMEM;
26272445Sassar	    krb5_free_principal(context->context, princ);
26372445Sassar	    goto fail;
26472445Sassar	}
26572445Sassar
26672445Sassar	for (i = 0; i < n_key_data; ++i) {
26772445Sassar	    ret = kadm5_ret_key_data (sp, &key_data[i]);
26872445Sassar	    if (ret) {
26972445Sassar		int16_t dummy = i;
27072445Sassar
27172445Sassar		kadm5_free_key_data (context, &dummy, key_data);
27272445Sassar		free (key_data);
27372445Sassar		krb5_free_principal(context->context, princ);
27472445Sassar		goto fail;
27572445Sassar	    }
27672445Sassar	}
27772445Sassar
27872445Sassar	krb5_unparse_name_fixed(context->context, princ, name, sizeof(name));
27972445Sassar	krb5_warnx(context->context, "%s: %s %s", client, op, name);
28072445Sassar
28172445Sassar	/*
28272445Sassar	 * The change is allowed if at least one of:
28372445Sassar	 * a) it's for the principal him/herself and this was an initial ticket
28472445Sassar	 * b) the user is on the CPW ACL.
28572445Sassar	 */
28672445Sassar
28772445Sassar	if (initial
28872445Sassar	    && krb5_principal_compare (context->context, context->caller,
28972445Sassar				       princ))
29072445Sassar	    ret = 0;
29172445Sassar	else
29272445Sassar	    ret = _kadm5_acl_check_permission(context, KADM5_PRIV_CPW, princ);
29372445Sassar
29472445Sassar	if(ret) {
29572445Sassar	    int16_t dummy = n_key_data;
29672445Sassar
29772445Sassar	    kadm5_free_key_data (context, &dummy, key_data);
29872445Sassar	    free (key_data);
29972445Sassar	    krb5_free_principal(context->context, princ);
30072445Sassar	    goto fail;
30172445Sassar	}
30272445Sassar	ret = kadm5_chpass_principal_with_key(kadm_handle, princ,
30372445Sassar					      n_key_data, key_data);
30472445Sassar	{
30572445Sassar	    int16_t dummy = n_key_data;
30672445Sassar	    kadm5_free_key_data (context, &dummy, key_data);
30772445Sassar	}
30872445Sassar	free (key_data);
30972445Sassar	krb5_free_principal(context->context, princ);
31072445Sassar	krb5_storage_free(sp);
31172445Sassar	sp = krb5_storage_emem();
31272445Sassar	krb5_store_int32(sp, ret);
31372445Sassar	break;
31472445Sassar    }
31555682Smarkm    case kadm_randkey:{
31655682Smarkm	op = "RANDKEY";
31755682Smarkm	ret = krb5_ret_principal(sp, &princ);
31855682Smarkm	if(ret)
31955682Smarkm	    goto fail;
32055682Smarkm	krb5_unparse_name_fixed(context->context, princ, name, sizeof(name));
32155682Smarkm	krb5_warnx(context->context, "%s: %s %s", client, op, name);
32255682Smarkm	/*
32355682Smarkm	 * The change is allowed if at least one of:
32455682Smarkm	 * a) it's for the principal him/herself and this was an initial ticket
32555682Smarkm	 * b) the user is on the CPW ACL.
32655682Smarkm	 */
32755682Smarkm
32855682Smarkm	if (initial
32955682Smarkm	    && krb5_principal_compare (context->context, context->caller,
33055682Smarkm				       princ))
33155682Smarkm	    ret = 0;
33255682Smarkm	else
33372445Sassar	    ret = _kadm5_acl_check_permission(context, KADM5_PRIV_CPW, princ);
33455682Smarkm
33555682Smarkm	if(ret) {
33655682Smarkm	    krb5_free_principal(context->context, princ);
33755682Smarkm	    goto fail;
33855682Smarkm	}
33955682Smarkm	ret = kadm5_randkey_principal(kadm_handle, princ,
34055682Smarkm				      &new_keys, &n_keys);
34155682Smarkm	krb5_free_principal(context->context, princ);
34255682Smarkm	krb5_storage_free(sp);
34355682Smarkm	sp = krb5_storage_emem();
34455682Smarkm	krb5_store_int32(sp, ret);
34555682Smarkm	if(ret == 0){
34655682Smarkm	    int i;
34755682Smarkm	    krb5_store_int32(sp, n_keys);
34855682Smarkm	    for(i = 0; i < n_keys; i++){
34955682Smarkm		krb5_store_keyblock(sp, new_keys[i]);
35055682Smarkm		krb5_free_keyblock_contents(context->context, &new_keys[i]);
35155682Smarkm	    }
35255682Smarkm	}
35355682Smarkm	break;
35455682Smarkm    }
35555682Smarkm    case kadm_get_privs:{
35655682Smarkm	ret = kadm5_get_privs(kadm_handle, &mask);
35755682Smarkm	krb5_storage_free(sp);
35855682Smarkm	sp = krb5_storage_emem();
35955682Smarkm	krb5_store_int32(sp, ret);
36055682Smarkm	if(ret == 0)
36155682Smarkm	    krb5_store_int32(sp, mask);
36255682Smarkm	break;
36355682Smarkm    }
36455682Smarkm    case kadm_get_princs:{
36555682Smarkm	op = "LIST";
36655682Smarkm	ret = krb5_ret_int32(sp, &tmp);
36755682Smarkm	if(ret)
36855682Smarkm	    goto fail;
36955682Smarkm	if(tmp){
37055682Smarkm	    ret = krb5_ret_string(sp, &exp);
37155682Smarkm	    if(ret)
37255682Smarkm		goto fail;
37355682Smarkm	}else
37455682Smarkm	    exp = NULL;
37555682Smarkm	krb5_warnx(context->context, "%s: %s %s", client, op, exp ? exp : "*");
37672445Sassar	ret = _kadm5_acl_check_permission(context, KADM5_PRIV_LIST, NULL);
37755682Smarkm	if(ret){
37855682Smarkm	    free(exp);
37955682Smarkm	    goto fail;
38055682Smarkm	}
38155682Smarkm	ret = kadm5_get_principals(kadm_handle, exp, &princs, &n_princs);
38255682Smarkm	free(exp);
38355682Smarkm	krb5_storage_free(sp);
38455682Smarkm	sp = krb5_storage_emem();
38555682Smarkm	krb5_store_int32(sp, ret);
38655682Smarkm	if(ret == 0){
38755682Smarkm	    int i;
38855682Smarkm	    krb5_store_int32(sp, n_princs);
38955682Smarkm	    for(i = 0; i < n_princs; i++)
39055682Smarkm		krb5_store_string(sp, princs[i]);
39155682Smarkm	    kadm5_free_name_list(kadm_handle, princs, &n_princs);
39255682Smarkm	}
39355682Smarkm	break;
39455682Smarkm    }
39555682Smarkm    default:
39655682Smarkm	krb5_warnx(context->context, "%s: UNKNOWN OP %d", client, cmd);
39755682Smarkm	krb5_storage_free(sp);
39855682Smarkm	sp = krb5_storage_emem();
39955682Smarkm	krb5_store_int32(sp, KADM5_FAILURE);
40055682Smarkm	break;
40155682Smarkm    }
40255682Smarkm    krb5_storage_to_data(sp, out);
40355682Smarkm    krb5_storage_free(sp);
40455682Smarkm    return 0;
40555682Smarkmfail:
40655682Smarkm    krb5_warn(context->context, ret, "%s", op);
40755682Smarkm    sp->seek(sp, 0, SEEK_SET);
40855682Smarkm    krb5_store_int32(sp, ret);
40955682Smarkm    krb5_storage_to_data(sp, out);
41055682Smarkm    krb5_storage_free(sp);
41155682Smarkm    return 0;
41255682Smarkm}
41355682Smarkm
41455682Smarkmstatic void
41555682Smarkmv5_loop (krb5_context context,
41655682Smarkm	 krb5_auth_context ac,
41755682Smarkm	 krb5_boolean initial,
41855682Smarkm	 void *kadm_handle,
41955682Smarkm	 int fd)
42055682Smarkm{
42155682Smarkm    krb5_error_code ret;
42272445Sassar    krb5_data in, out;
42355682Smarkm
42455682Smarkm    for (;;) {
42572445Sassar	doing_useful_work = 0;
42672445Sassar	if(term_flag)
42772445Sassar	    exit(0);
42872445Sassar	ret = krb5_read_priv_message(context, ac, &fd, &in);
42972445Sassar	if(ret == HEIM_ERR_EOF)
43072445Sassar	    exit(0);
43172445Sassar	if(ret)
43272445Sassar	    krb5_err(context, 1, ret, "krb5_read_priv_message");
43372445Sassar	doing_useful_work = 1;
43472445Sassar	kadmind_dispatch(kadm_handle, initial, &in, &out);
43555682Smarkm	krb5_data_free(&in);
43672445Sassar	ret = krb5_write_priv_message(context, ac, &fd, &out);
43772445Sassar	if(ret)
43872445Sassar	    krb5_err(context, 1, ret, "krb5_write_priv_message");
43955682Smarkm    }
44055682Smarkm}
44155682Smarkm
44255682Smarkmstatic krb5_boolean
44355682Smarkmmatch_appl_version(void *data, const char *appl_version)
44455682Smarkm{
44555682Smarkm    unsigned minor;
44655682Smarkm    if(sscanf(appl_version, "KADM0.%u", &minor) != 1)
44755682Smarkm	return 0;
44855682Smarkm    *(unsigned*)data = minor;
44955682Smarkm    return 1;
45055682Smarkm}
45155682Smarkm
45255682Smarkmstatic void
45355682Smarkmhandle_v5(krb5_context context,
45455682Smarkm	  krb5_auth_context ac,
45555682Smarkm	  krb5_keytab keytab,
45655682Smarkm	  int len,
45755682Smarkm	  int fd)
45855682Smarkm{
45955682Smarkm    krb5_error_code ret;
46055682Smarkm    u_char version[sizeof(KRB5_SENDAUTH_VERSION)];
46155682Smarkm    krb5_ticket *ticket;
46272445Sassar    char *server_name;
46355682Smarkm    char *client;
46455682Smarkm    void *kadm_handle;
46555682Smarkm    ssize_t n;
46655682Smarkm    krb5_boolean initial;
46755682Smarkm
46855682Smarkm    unsigned kadm_version;
46955682Smarkm    kadm5_config_params realm_params;
47055682Smarkm
47155682Smarkm    if (len != sizeof(KRB5_SENDAUTH_VERSION))
47255682Smarkm	krb5_errx(context, 1, "bad sendauth len %d", len);
47355682Smarkm    n = krb5_net_read(context, &fd, version, len);
47455682Smarkm    if (n < 0)
47555682Smarkm	krb5_err (context, 1, errno, "reading sendauth version");
47655682Smarkm    if (n == 0)
47755682Smarkm	krb5_errx (context, 1, "EOF reading sendauth version");
47855682Smarkm    if(memcmp(version, KRB5_SENDAUTH_VERSION, len) != 0)
47955682Smarkm	krb5_errx(context, 1, "bad sendauth version %.8s", version);
48055682Smarkm
48155682Smarkm    ret = krb5_recvauth_match_version(context, &ac, &fd,
48255682Smarkm				      match_appl_version, &kadm_version,
48372445Sassar				      NULL, KRB5_RECVAUTH_IGNORE_VERSION,
48455682Smarkm				      keytab, &ticket);
48572445Sassar    if(ret == KRB5_KT_NOTFOUND)
48672445Sassar	krb5_errx(context, 1, "krb5_recvauth: key no found");
48755682Smarkm    if(ret)
48855682Smarkm	krb5_err(context, 1, ret, "krb5_recvauth");
48955682Smarkm
49072445Sassar    ret = krb5_unparse_name (context, ticket->server, &server_name);
49172445Sassar    if (ret)
49272445Sassar	krb5_err (context, 1, ret, "krb5_unparse_name");
49372445Sassar
49472445Sassar    if (strncmp (server_name, KADM5_ADMIN_SERVICE,
49572445Sassar		 strlen(KADM5_ADMIN_SERVICE)) != 0)
49672445Sassar	krb5_errx (context, 1, "ticket for strange principal (%s)",
49772445Sassar		   server_name);
49872445Sassar
49972445Sassar    free (server_name);
50072445Sassar
50155682Smarkm    memset(&realm_params, 0, sizeof(realm_params));
50255682Smarkm
50355682Smarkm    if(kadm_version == 1) {
50472445Sassar	krb5_data params;
50572445Sassar	ret = krb5_read_priv_message(context, ac, &fd, &params);
50672445Sassar	if(ret)
50772445Sassar	    krb5_err(context, 1, ret, "krb5_read_priv_message");
50855682Smarkm	_kadm5_unmarshal_params(context, &params, &realm_params);
50955682Smarkm    }
51055682Smarkm
51155682Smarkm    initial = ticket->ticket.flags.initial;
51255682Smarkm    ret = krb5_unparse_name(context, ticket->client, &client);
51355682Smarkm    if (ret)
51455682Smarkm	krb5_err (context, 1, ret, "krb5_unparse_name");
51555682Smarkm    krb5_free_ticket (context, ticket);
51655682Smarkm    ret = kadm5_init_with_password_ctx(context,
51755682Smarkm				       client,
51855682Smarkm				       NULL,
51955682Smarkm				       KADM5_ADMIN_SERVICE,
52055682Smarkm				       &realm_params,
52155682Smarkm				       0, 0,
52255682Smarkm				       &kadm_handle);
52355682Smarkm    if(ret)
52455682Smarkm	krb5_err (context, 1, ret, "kadm5_init_with_password_ctx");
52555682Smarkm    v5_loop (context, ac, initial, kadm_handle, fd);
52655682Smarkm}
52755682Smarkm
52855682Smarkmkrb5_error_code
52955682Smarkmkadmind_loop(krb5_context context,
53055682Smarkm	     krb5_auth_context ac,
53155682Smarkm	     krb5_keytab keytab,
53255682Smarkm	     int fd)
53355682Smarkm{
53455682Smarkm    unsigned char tmp[4];
53555682Smarkm    ssize_t n;
53655682Smarkm    unsigned long len;
53755682Smarkm
53855682Smarkm    n = krb5_net_read(context, &fd, tmp, 4);
53955682Smarkm    if(n == 0)
54055682Smarkm	exit(0);
54155682Smarkm    if(n < 0)
54272445Sassar	krb5_err(context, 1, errno, "read");
54355682Smarkm    _krb5_get_int(tmp, &len, 4);
54455682Smarkm    if(len > 0xffff && (len & 0xffff) == ('K' << 8) + 'A') {
54555682Smarkm	len >>= 16;
54655682Smarkm#ifdef KRB4
54772445Sassar	handle_v4(context, keytab, len, fd);
54855682Smarkm#else
54955682Smarkm	krb5_errx(context, 1, "packet appears to be version 4");
55055682Smarkm#endif
55155682Smarkm    } else {
55255682Smarkm	handle_v5(context, ac, keytab, len, fd);
55355682Smarkm    }
55455682Smarkm    return 0;
55555682Smarkm}
556