server.c revision 120945
155682Smarkm/*
2120945Snectar * Copyright (c) 1997 - 2003 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
37120945SnectarRCSID("$Id: server.c,v 1.38 2003/01/29 12:33:05 lha 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:
220120945Snectar
221120945Snectar	 * a) it's for the principal him/herself and this was an
222120945Snectar	 *    initial ticket, but then, check with the password quality
223120945Snectar	 *    function.
22455682Smarkm	 * b) the user is on the CPW ACL.
22555682Smarkm	 */
22655682Smarkm
22755682Smarkm	if (initial
22855682Smarkm	    && krb5_principal_compare (context->context, context->caller,
22955682Smarkm				       princ))
230120945Snectar	{
231120945Snectar	    krb5_data pwd_data;
232120945Snectar	    const char *pwd_reason;
233120945Snectar
234120945Snectar	    pwd_data.data = password;
235120945Snectar	    pwd_data.length = strlen(password);
236120945Snectar
237120945Snectar	    pwd_reason = kadm5_check_password_quality (context->context,
238120945Snectar						       princ, &pwd_data);
239120945Snectar	    if (pwd_reason != NULL)
240120945Snectar		ret = KADM5_PASS_Q_DICT;
241120945Snectar	    else
242120945Snectar		ret = 0;
243120945Snectar	} else
24472445Sassar	    ret = _kadm5_acl_check_permission(context, KADM5_PRIV_CPW, princ);
24555682Smarkm
24655682Smarkm	if(ret) {
24755682Smarkm	    krb5_free_principal(context->context, princ);
248120945Snectar	    memset(password, 0, strlen(password));
249120945Snectar	    free(password);
25055682Smarkm	    goto fail;
25155682Smarkm	}
25255682Smarkm	ret = kadm5_chpass_principal(kadm_handle, princ, password);
25355682Smarkm	krb5_free_principal(context->context, princ);
25455682Smarkm	memset(password, 0, strlen(password));
25555682Smarkm	free(password);
25655682Smarkm	krb5_storage_free(sp);
25755682Smarkm	sp = krb5_storage_emem();
25855682Smarkm	krb5_store_int32(sp, ret);
25955682Smarkm	break;
26055682Smarkm    }
26172445Sassar    case kadm_chpass_with_key:{
26272445Sassar	int i;
26372445Sassar	krb5_key_data *key_data;
26472445Sassar	int n_key_data;
26572445Sassar
26672445Sassar	op = "CHPASS_WITH_KEY";
26772445Sassar	ret = krb5_ret_principal(sp, &princ);
26872445Sassar	if(ret)
26972445Sassar	    goto fail;
27072445Sassar	ret = krb5_ret_int32(sp, &n_key_data);
27172445Sassar	if (ret) {
27272445Sassar	    krb5_free_principal(context->context, princ);
27372445Sassar	    goto fail;
27472445Sassar	}
275103423Snectar	/* n_key_data will be squeezed into an int16_t below. */
276103423Snectar	if (n_key_data < 0 || n_key_data >= 1 << 16 ||
277103423Snectar	    n_key_data > UINT_MAX/sizeof(*key_data)) {
278103423Snectar	    ret = ERANGE;
279103423Snectar	    krb5_free_principal(context->context, princ);
280103423Snectar	    goto fail;
281103423Snectar	}
28272445Sassar
28372445Sassar	key_data = malloc (n_key_data * sizeof(*key_data));
28472445Sassar	if (key_data == NULL) {
28572445Sassar	    ret = ENOMEM;
28672445Sassar	    krb5_free_principal(context->context, princ);
28772445Sassar	    goto fail;
28872445Sassar	}
28972445Sassar
29072445Sassar	for (i = 0; i < n_key_data; ++i) {
29172445Sassar	    ret = kadm5_ret_key_data (sp, &key_data[i]);
29272445Sassar	    if (ret) {
29372445Sassar		int16_t dummy = i;
29472445Sassar
29572445Sassar		kadm5_free_key_data (context, &dummy, key_data);
29672445Sassar		free (key_data);
29772445Sassar		krb5_free_principal(context->context, princ);
29872445Sassar		goto fail;
29972445Sassar	    }
30072445Sassar	}
30172445Sassar
30272445Sassar	krb5_unparse_name_fixed(context->context, princ, name, sizeof(name));
30372445Sassar	krb5_warnx(context->context, "%s: %s %s", client, op, name);
30472445Sassar
30572445Sassar	/*
306120945Snectar	 * The change is only allowed if the user is on the CPW ACL,
307120945Snectar	 * this it to force password quality check on the user.
30872445Sassar	 */
30972445Sassar
310120945Snectar	ret = _kadm5_acl_check_permission(context, KADM5_PRIV_CPW, princ);
31172445Sassar	if(ret) {
31272445Sassar	    int16_t dummy = n_key_data;
31372445Sassar
31472445Sassar	    kadm5_free_key_data (context, &dummy, key_data);
31572445Sassar	    free (key_data);
31672445Sassar	    krb5_free_principal(context->context, princ);
31772445Sassar	    goto fail;
31872445Sassar	}
31972445Sassar	ret = kadm5_chpass_principal_with_key(kadm_handle, princ,
32072445Sassar					      n_key_data, key_data);
32172445Sassar	{
32272445Sassar	    int16_t dummy = n_key_data;
32372445Sassar	    kadm5_free_key_data (context, &dummy, key_data);
32472445Sassar	}
32572445Sassar	free (key_data);
32672445Sassar	krb5_free_principal(context->context, princ);
32772445Sassar	krb5_storage_free(sp);
32872445Sassar	sp = krb5_storage_emem();
32972445Sassar	krb5_store_int32(sp, ret);
33072445Sassar	break;
33172445Sassar    }
33255682Smarkm    case kadm_randkey:{
33355682Smarkm	op = "RANDKEY";
33455682Smarkm	ret = krb5_ret_principal(sp, &princ);
33555682Smarkm	if(ret)
33655682Smarkm	    goto fail;
33755682Smarkm	krb5_unparse_name_fixed(context->context, princ, name, sizeof(name));
33855682Smarkm	krb5_warnx(context->context, "%s: %s %s", client, op, name);
33955682Smarkm	/*
34055682Smarkm	 * The change is allowed if at least one of:
34155682Smarkm	 * a) it's for the principal him/herself and this was an initial ticket
34255682Smarkm	 * b) the user is on the CPW ACL.
34355682Smarkm	 */
34455682Smarkm
34555682Smarkm	if (initial
34655682Smarkm	    && krb5_principal_compare (context->context, context->caller,
34755682Smarkm				       princ))
34855682Smarkm	    ret = 0;
34955682Smarkm	else
35072445Sassar	    ret = _kadm5_acl_check_permission(context, KADM5_PRIV_CPW, princ);
35155682Smarkm
35255682Smarkm	if(ret) {
35355682Smarkm	    krb5_free_principal(context->context, princ);
35455682Smarkm	    goto fail;
35555682Smarkm	}
35655682Smarkm	ret = kadm5_randkey_principal(kadm_handle, princ,
35755682Smarkm				      &new_keys, &n_keys);
35855682Smarkm	krb5_free_principal(context->context, princ);
35955682Smarkm	krb5_storage_free(sp);
36055682Smarkm	sp = krb5_storage_emem();
36155682Smarkm	krb5_store_int32(sp, ret);
36255682Smarkm	if(ret == 0){
36355682Smarkm	    int i;
36455682Smarkm	    krb5_store_int32(sp, n_keys);
36555682Smarkm	    for(i = 0; i < n_keys; i++){
36655682Smarkm		krb5_store_keyblock(sp, new_keys[i]);
36755682Smarkm		krb5_free_keyblock_contents(context->context, &new_keys[i]);
36855682Smarkm	    }
36955682Smarkm	}
37055682Smarkm	break;
37155682Smarkm    }
37255682Smarkm    case kadm_get_privs:{
37355682Smarkm	ret = kadm5_get_privs(kadm_handle, &mask);
37455682Smarkm	krb5_storage_free(sp);
37555682Smarkm	sp = krb5_storage_emem();
37655682Smarkm	krb5_store_int32(sp, ret);
37755682Smarkm	if(ret == 0)
37855682Smarkm	    krb5_store_int32(sp, mask);
37955682Smarkm	break;
38055682Smarkm    }
38155682Smarkm    case kadm_get_princs:{
38255682Smarkm	op = "LIST";
38355682Smarkm	ret = krb5_ret_int32(sp, &tmp);
38455682Smarkm	if(ret)
38555682Smarkm	    goto fail;
38655682Smarkm	if(tmp){
38755682Smarkm	    ret = krb5_ret_string(sp, &exp);
38855682Smarkm	    if(ret)
38955682Smarkm		goto fail;
39055682Smarkm	}else
39155682Smarkm	    exp = NULL;
39255682Smarkm	krb5_warnx(context->context, "%s: %s %s", client, op, exp ? exp : "*");
39372445Sassar	ret = _kadm5_acl_check_permission(context, KADM5_PRIV_LIST, NULL);
39455682Smarkm	if(ret){
39555682Smarkm	    free(exp);
39655682Smarkm	    goto fail;
39755682Smarkm	}
39855682Smarkm	ret = kadm5_get_principals(kadm_handle, exp, &princs, &n_princs);
39955682Smarkm	free(exp);
40055682Smarkm	krb5_storage_free(sp);
40155682Smarkm	sp = krb5_storage_emem();
40255682Smarkm	krb5_store_int32(sp, ret);
40355682Smarkm	if(ret == 0){
40455682Smarkm	    int i;
40555682Smarkm	    krb5_store_int32(sp, n_princs);
40655682Smarkm	    for(i = 0; i < n_princs; i++)
40755682Smarkm		krb5_store_string(sp, princs[i]);
40855682Smarkm	    kadm5_free_name_list(kadm_handle, princs, &n_princs);
40955682Smarkm	}
41055682Smarkm	break;
41155682Smarkm    }
41255682Smarkm    default:
41355682Smarkm	krb5_warnx(context->context, "%s: UNKNOWN OP %d", client, cmd);
41455682Smarkm	krb5_storage_free(sp);
41555682Smarkm	sp = krb5_storage_emem();
41655682Smarkm	krb5_store_int32(sp, KADM5_FAILURE);
41755682Smarkm	break;
41855682Smarkm    }
41955682Smarkm    krb5_storage_to_data(sp, out);
42055682Smarkm    krb5_storage_free(sp);
42155682Smarkm    return 0;
42255682Smarkmfail:
42355682Smarkm    krb5_warn(context->context, ret, "%s", op);
424102644Snectar    krb5_storage_seek(sp, 0, SEEK_SET);
42555682Smarkm    krb5_store_int32(sp, ret);
42655682Smarkm    krb5_storage_to_data(sp, out);
42755682Smarkm    krb5_storage_free(sp);
42855682Smarkm    return 0;
42955682Smarkm}
43055682Smarkm
43155682Smarkmstatic void
43255682Smarkmv5_loop (krb5_context context,
43355682Smarkm	 krb5_auth_context ac,
43455682Smarkm	 krb5_boolean initial,
43555682Smarkm	 void *kadm_handle,
43655682Smarkm	 int fd)
43755682Smarkm{
43855682Smarkm    krb5_error_code ret;
43972445Sassar    krb5_data in, out;
44055682Smarkm
44155682Smarkm    for (;;) {
44272445Sassar	doing_useful_work = 0;
44372445Sassar	if(term_flag)
44472445Sassar	    exit(0);
44572445Sassar	ret = krb5_read_priv_message(context, ac, &fd, &in);
44672445Sassar	if(ret == HEIM_ERR_EOF)
44772445Sassar	    exit(0);
44872445Sassar	if(ret)
44972445Sassar	    krb5_err(context, 1, ret, "krb5_read_priv_message");
45072445Sassar	doing_useful_work = 1;
45172445Sassar	kadmind_dispatch(kadm_handle, initial, &in, &out);
45255682Smarkm	krb5_data_free(&in);
45372445Sassar	ret = krb5_write_priv_message(context, ac, &fd, &out);
45472445Sassar	if(ret)
45572445Sassar	    krb5_err(context, 1, ret, "krb5_write_priv_message");
45655682Smarkm    }
45755682Smarkm}
45855682Smarkm
45955682Smarkmstatic krb5_boolean
460103423Snectarmatch_appl_version(const void *data, const char *appl_version)
46155682Smarkm{
46255682Smarkm    unsigned minor;
46355682Smarkm    if(sscanf(appl_version, "KADM0.%u", &minor) != 1)
46455682Smarkm	return 0;
46555682Smarkm    *(unsigned*)data = minor;
46655682Smarkm    return 1;
46755682Smarkm}
46855682Smarkm
46955682Smarkmstatic void
47055682Smarkmhandle_v5(krb5_context context,
47155682Smarkm	  krb5_auth_context ac,
47255682Smarkm	  krb5_keytab keytab,
47355682Smarkm	  int len,
47455682Smarkm	  int fd)
47555682Smarkm{
47655682Smarkm    krb5_error_code ret;
47755682Smarkm    u_char version[sizeof(KRB5_SENDAUTH_VERSION)];
47855682Smarkm    krb5_ticket *ticket;
47972445Sassar    char *server_name;
48055682Smarkm    char *client;
48155682Smarkm    void *kadm_handle;
48255682Smarkm    ssize_t n;
48355682Smarkm    krb5_boolean initial;
48455682Smarkm
48555682Smarkm    unsigned kadm_version;
48655682Smarkm    kadm5_config_params realm_params;
48755682Smarkm
48855682Smarkm    if (len != sizeof(KRB5_SENDAUTH_VERSION))
48955682Smarkm	krb5_errx(context, 1, "bad sendauth len %d", len);
49055682Smarkm    n = krb5_net_read(context, &fd, version, len);
49155682Smarkm    if (n < 0)
49255682Smarkm	krb5_err (context, 1, errno, "reading sendauth version");
49355682Smarkm    if (n == 0)
49455682Smarkm	krb5_errx (context, 1, "EOF reading sendauth version");
49555682Smarkm    if(memcmp(version, KRB5_SENDAUTH_VERSION, len) != 0)
49655682Smarkm	krb5_errx(context, 1, "bad sendauth version %.8s", version);
49755682Smarkm
49855682Smarkm    ret = krb5_recvauth_match_version(context, &ac, &fd,
49955682Smarkm				      match_appl_version, &kadm_version,
50072445Sassar				      NULL, KRB5_RECVAUTH_IGNORE_VERSION,
50155682Smarkm				      keytab, &ticket);
50272445Sassar    if(ret == KRB5_KT_NOTFOUND)
50390926Snectar	krb5_errx(context, 1, "krb5_recvauth: key not found");
50455682Smarkm    if(ret)
50555682Smarkm	krb5_err(context, 1, ret, "krb5_recvauth");
50655682Smarkm
50772445Sassar    ret = krb5_unparse_name (context, ticket->server, &server_name);
50872445Sassar    if (ret)
50972445Sassar	krb5_err (context, 1, ret, "krb5_unparse_name");
51072445Sassar
51172445Sassar    if (strncmp (server_name, KADM5_ADMIN_SERVICE,
51272445Sassar		 strlen(KADM5_ADMIN_SERVICE)) != 0)
51372445Sassar	krb5_errx (context, 1, "ticket for strange principal (%s)",
51472445Sassar		   server_name);
51572445Sassar
51672445Sassar    free (server_name);
51772445Sassar
51855682Smarkm    memset(&realm_params, 0, sizeof(realm_params));
51955682Smarkm
52055682Smarkm    if(kadm_version == 1) {
52172445Sassar	krb5_data params;
52272445Sassar	ret = krb5_read_priv_message(context, ac, &fd, &params);
52372445Sassar	if(ret)
52472445Sassar	    krb5_err(context, 1, ret, "krb5_read_priv_message");
52555682Smarkm	_kadm5_unmarshal_params(context, &params, &realm_params);
52655682Smarkm    }
52755682Smarkm
52855682Smarkm    initial = ticket->ticket.flags.initial;
52955682Smarkm    ret = krb5_unparse_name(context, ticket->client, &client);
53055682Smarkm    if (ret)
53155682Smarkm	krb5_err (context, 1, ret, "krb5_unparse_name");
53255682Smarkm    krb5_free_ticket (context, ticket);
53355682Smarkm    ret = kadm5_init_with_password_ctx(context,
53455682Smarkm				       client,
53555682Smarkm				       NULL,
53655682Smarkm				       KADM5_ADMIN_SERVICE,
53755682Smarkm				       &realm_params,
53855682Smarkm				       0, 0,
53955682Smarkm				       &kadm_handle);
54055682Smarkm    if(ret)
54155682Smarkm	krb5_err (context, 1, ret, "kadm5_init_with_password_ctx");
54255682Smarkm    v5_loop (context, ac, initial, kadm_handle, fd);
54355682Smarkm}
54455682Smarkm
545107207Snectarextern int do_kerberos4;
546107207Snectar
54755682Smarkmkrb5_error_code
54855682Smarkmkadmind_loop(krb5_context context,
54955682Smarkm	     krb5_auth_context ac,
55055682Smarkm	     krb5_keytab keytab,
55155682Smarkm	     int fd)
55255682Smarkm{
55355682Smarkm    unsigned char tmp[4];
55455682Smarkm    ssize_t n;
55555682Smarkm    unsigned long len;
55655682Smarkm
55755682Smarkm    n = krb5_net_read(context, &fd, tmp, 4);
55855682Smarkm    if(n == 0)
55955682Smarkm	exit(0);
56055682Smarkm    if(n < 0)
56172445Sassar	krb5_err(context, 1, errno, "read");
56255682Smarkm    _krb5_get_int(tmp, &len, 4);
56355682Smarkm    if(len > 0xffff && (len & 0xffff) == ('K' << 8) + 'A') {
56455682Smarkm	len >>= 16;
56555682Smarkm#ifdef KRB4
566107207Snectar	if(do_kerberos4)
567107207Snectar	    handle_v4(context, keytab, len, fd);
568107207Snectar	else
569107207Snectar	    krb5_errx(context, 1, "version 4 kadmin is disabled");
57055682Smarkm#else
57155682Smarkm	krb5_errx(context, 1, "packet appears to be version 4");
57255682Smarkm#endif
57355682Smarkm    } else {
57455682Smarkm	handle_v5(context, ac, keytab, len, fd);
57555682Smarkm    }
57655682Smarkm    return 0;
57755682Smarkm}
578