2 * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 #include "kadmin_locl.h"
35 #include <krb5-private.h>
37 static kadm5_ret_t
check_aliases(kadm5_server_context
*,
38 kadm5_principal_ent_rec
*,
39 kadm5_principal_ent_rec
*);
42 kadmind_dispatch(void *kadm_handlep
, krb5_boolean initial
,
43 krb5_data
*in
, krb5_data
*out
, int readonly
)
46 int32_t cmd
, mask
, kvno
, tmp
;
47 kadm5_server_context
*contextp
= kadm_handlep
;
48 char client
[128], name
[128], name2
[128];
50 krb5_principal princ
= NULL
, princ2
= NULL
;
51 kadm5_principal_ent_rec ent
, ent_prev
;
52 char *password
= NULL
, *expression
;
53 krb5_keyblock
*new_keys
;
54 krb5_key_salt_tuple
*ks_tuple
= NULL
;
64 krb5_unparse_name_fixed(contextp
->context
, contextp
->caller
,
65 client
, sizeof(client
));
67 sp
= krb5_storage_from_data(in
);
69 ret
= krb5_enomem(contextp
->context
);
73 krb5_ret_int32(sp
, &cmd
);
77 ret
= krb5_ret_principal(sp
, &princ
);
80 ret
= krb5_ret_int32(sp
, &mask
);
84 mask
|= KADM5_PRINCIPAL
;
85 krb5_unparse_name_fixed(contextp
->context
, princ
, name
, sizeof(name
));
86 krb5_warnx(contextp
->context
, "%s: %s %s", client
, op
, name
);
88 /* If the caller doesn't have KADM5_PRIV_GET, we're done. */
89 ret
= _kadm5_acl_check_permission(contextp
, KADM5_PRIV_GET
, princ
);
93 /* Then check to see if it is ok to return keys */
94 if ((mask
& KADM5_KEY_DATA
) != 0) {
95 ret
= _kadm5_acl_check_permission(contextp
, KADM5_PRIV_GET_KEYS
,
99 } else if ((mask
== (KADM5_PRINCIPAL
|KADM5_KEY_DATA
)) ||
100 (mask
== (KADM5_PRINCIPAL
|KADM5_KVNO
|KADM5_KEY_DATA
))) {
102 * Requests for keys will get bogus keys, which is useful if
103 * the client just wants to see what (kvno, enctype)s the
104 * principal has keys for, but terrible if the client wants to
105 * write the keys into a keytab or modify the principal and
106 * write the bogus keys back to the server.
108 * We use a heuristic to detect which case we're handling here.
109 * If the client only asks for the flags in the above
110 * condition, then it's very likely a kadmin ext_keytab,
111 * add_enctype, or other request that should not see bogus
112 * keys. We deny them.
114 * The kadmin get command can be coaxed into making a request
115 * with the same mask. But the default long and terse output
116 * modes request other things too, so in all likelihood this
117 * heuristic will not hurt any kadmin get uses.
123 ret
= kadm5_get_principal(kadm_handlep
, princ
, &ent
, mask
);
124 krb5_storage_free(sp
);
125 sp
= krb5_storage_emem();
127 ret
= krb5_enomem(contextp
->context
);
130 krb5_store_int32(sp
, ret
);
133 kadm5_store_principal_ent(sp
, &ent
);
135 kadm5_store_principal_ent_nokeys(sp
, &ent
);
136 kadm5_free_principal_ent(kadm_handlep
, &ent
);
143 ret
= KADM5_READ_ONLY
;
146 ret
= krb5_ret_principal(sp
, &princ
);
149 krb5_unparse_name_fixed(contextp
->context
, princ
, name
, sizeof(name
));
150 krb5_warnx(contextp
->context
, "%s: %s %s", client
, op
, name
);
151 ret
= _kadm5_acl_check_permission(contextp
, KADM5_PRIV_DELETE
, princ
);
156 * There's no need to check that the caller has permission to
157 * delete the victim principal's aliases.
160 ret
= kadm5_delete_principal(kadm_handlep
, princ
);
161 krb5_storage_free(sp
);
162 sp
= krb5_storage_emem();
164 ret
= krb5_enomem(contextp
->context
);
167 krb5_store_int32(sp
, ret
);
173 ret
= KADM5_READ_ONLY
;
176 ret
= kadm5_ret_principal_ent(sp
, &ent
);
179 ret
= krb5_ret_int32(sp
, &mask
);
181 kadm5_free_principal_ent(kadm_handlep
, &ent
);
184 ret
= krb5_ret_string(sp
, &password
);
186 kadm5_free_principal_ent(kadm_handlep
, &ent
);
189 krb5_unparse_name_fixed(contextp
->context
, ent
.principal
,
191 krb5_warnx(contextp
->context
, "%s: %s %s", client
, op
, name
);
192 ret
= _kadm5_acl_check_permission(contextp
, KADM5_PRIV_ADD
,
195 kadm5_free_principal_ent(kadm_handlep
, &ent
);
198 if ((mask
& KADM5_TL_DATA
)) {
200 * Also check that the caller can create the aliases, if the
201 * new principal has any.
203 ret
= check_aliases(contextp
, &ent
, NULL
);
205 kadm5_free_principal_ent(kadm_handlep
, &ent
);
209 ret
= kadm5_create_principal(kadm_handlep
, &ent
,
211 kadm5_free_principal_ent(kadm_handlep
, &ent
);
212 krb5_storage_free(sp
);
213 sp
= krb5_storage_emem();
215 ret
= krb5_enomem(contextp
->context
);
218 krb5_store_int32(sp
, ret
);
224 ret
= KADM5_READ_ONLY
;
227 ret
= kadm5_ret_principal_ent(sp
, &ent
);
230 ret
= krb5_ret_int32(sp
, &mask
);
232 kadm5_free_principal_ent(contextp
, &ent
);
235 krb5_unparse_name_fixed(contextp
->context
, ent
.principal
,
237 krb5_warnx(contextp
->context
, "%s: %s %s", client
, op
, name
);
238 ret
= _kadm5_acl_check_permission(contextp
, KADM5_PRIV_MODIFY
,
241 kadm5_free_principal_ent(contextp
, &ent
);
244 if ((mask
& KADM5_TL_DATA
)) {
246 * Also check that the caller can create aliases that are in
247 * the new entry but not the old one. There's no need to
248 * check that the caller can delete aliases it wants to
249 * drop. See also handling of rename.
251 ret
= kadm5_get_principal(kadm_handlep
, ent
.principal
, &ent_prev
, mask
);
253 kadm5_free_principal_ent(contextp
, &ent
);
256 ret
= check_aliases(contextp
, &ent
, &ent_prev
);
257 kadm5_free_principal_ent(contextp
, &ent_prev
);
259 kadm5_free_principal_ent(contextp
, &ent
);
263 ret
= kadm5_modify_principal(kadm_handlep
, &ent
, mask
);
264 kadm5_free_principal_ent(kadm_handlep
, &ent
);
265 krb5_storage_free(sp
);
266 sp
= krb5_storage_emem();
268 ret
= krb5_enomem(contextp
->context
);
271 krb5_store_int32(sp
, ret
);
277 ret
= KADM5_READ_ONLY
;
280 ret
= krb5_ret_principal(sp
, &princ
);
283 ret
= krb5_ret_int32(sp
, &kvno
);
284 if (ret
== HEIM_ERR_EOF
) {
289 krb5_unparse_name_fixed(contextp
->context
, princ
, name
, sizeof(name
));
290 krb5_warnx(contextp
->context
, "%s: %s %s", client
, op
, name
);
291 ret
= _kadm5_acl_check_permission(contextp
, KADM5_PRIV_CPW
, princ
);
295 ret
= kadm5_prune_principal(kadm_handlep
, princ
, kvno
);
296 krb5_storage_free(sp
);
297 sp
= krb5_storage_emem();
299 ret
= krb5_enomem(contextp
->context
);
302 krb5_store_int32(sp
, ret
);
308 ret
= KADM5_READ_ONLY
;
311 ret
= krb5_ret_principal(sp
, &princ
);
314 ret
= krb5_ret_principal(sp
, &princ2
);
318 krb5_unparse_name_fixed(contextp
->context
, princ
, name
, sizeof(name
));
319 krb5_unparse_name_fixed(contextp
->context
, princ2
,
320 name2
, sizeof(name2
));
321 krb5_warnx(contextp
->context
, "%s: %s %s -> %s",
322 client
, op
, name
, name2
);
323 ret
= _kadm5_acl_check_permission(contextp
,
328 * Also require modify for the principal. For backwards
329 * compatibility, allow delete permission on the old name to
330 * cure lack of modify permission on the old name.
332 ret
= _kadm5_acl_check_permission(contextp
,
336 ret
= _kadm5_acl_check_permission(contextp
,
344 ret
= kadm5_rename_principal(kadm_handlep
, princ
, princ2
);
345 krb5_storage_free(sp
);
346 sp
= krb5_storage_emem();
348 ret
= krb5_enomem(contextp
->context
);
351 krb5_store_int32(sp
, ret
);
355 krb5_boolean is_self_cpw
, allow_self_cpw
;
359 ret
= KADM5_READ_ONLY
;
362 ret
= krb5_ret_principal(sp
, &princ
);
365 ret
= krb5_ret_string(sp
, &password
);
369 ret
= krb5_ret_int32(sp
, &keepold
);
370 if (ret
&& ret
!= HEIM_ERR_EOF
)
373 krb5_unparse_name_fixed(contextp
->context
, princ
, name
, sizeof(name
));
374 krb5_warnx(contextp
->context
, "%s: %s %s", client
, op
, name
);
377 * Change password requests are subject to ACLs unless the principal is
378 * changing their own password and the initial ticket flag is set, and
379 * the allow_self_change_password configuration option is TRUE.
382 krb5_principal_compare(contextp
->context
, contextp
->caller
, princ
);
384 krb5_config_get_bool_default(contextp
->context
, NULL
, TRUE
,
385 "kadmin", "allow_self_change_password", NULL
);
386 if (!(is_self_cpw
&& initial
&& allow_self_cpw
)) {
387 ret
= _kadm5_acl_check_permission(contextp
, KADM5_PRIV_CPW
, princ
);
392 ret
= kadm5_chpass_principal_3(kadm_handlep
, princ
, keepold
, 0, NULL
,
394 krb5_storage_free(sp
);
395 sp
= krb5_storage_emem();
397 ret
= krb5_enomem(contextp
->context
);
400 krb5_store_int32(sp
, ret
);
403 case kadm_chpass_with_key
:{
405 krb5_key_data
*key_data
;
408 op
= "CHPASS_WITH_KEY";
410 ret
= KADM5_READ_ONLY
;
413 ret
= krb5_ret_principal(sp
, &princ
);
416 ret
= krb5_ret_int32(sp
, &n_key_data
);
420 ret
= krb5_ret_int32(sp
, &keepold
);
421 if (ret
&& ret
!= HEIM_ERR_EOF
)
424 /* n_key_data will be squeezed into an int16_t below. */
425 if (n_key_data
< 0 || n_key_data
>= 1 << 16 ||
426 (size_t)n_key_data
> UINT_MAX
/sizeof(*key_data
)) {
431 key_data
= malloc (n_key_data
* sizeof(*key_data
));
432 if (key_data
== NULL
&& n_key_data
!= 0) {
433 ret
= krb5_enomem(contextp
->context
);
437 for (i
= 0; i
< n_key_data
; ++i
) {
438 ret
= kadm5_ret_key_data (sp
, &key_data
[i
]);
442 kadm5_free_key_data (contextp
, &dummy
, key_data
);
448 krb5_unparse_name_fixed(contextp
->context
, princ
, name
, sizeof(name
));
449 krb5_warnx(contextp
->context
, "%s: %s %s", client
, op
, name
);
452 * The change is only allowed if the user is on the CPW ACL,
453 * this it to force password quality check on the user.
456 ret
= _kadm5_acl_check_permission(contextp
, KADM5_PRIV_CPW
, princ
);
458 int16_t dummy
= n_key_data
;
460 kadm5_free_key_data (contextp
, &dummy
, key_data
);
464 ret
= kadm5_chpass_principal_with_key_3(kadm_handlep
, princ
, keepold
,
465 n_key_data
, key_data
);
467 int16_t dummy
= n_key_data
;
468 kadm5_free_key_data (contextp
, &dummy
, key_data
);
471 krb5_storage_free(sp
);
472 sp
= krb5_storage_emem();
474 ret
= krb5_enomem(contextp
->context
);
477 krb5_store_int32(sp
, ret
);
485 ret
= KADM5_READ_ONLY
;
488 ret
= krb5_ret_principal(sp
, &princ
);
491 krb5_unparse_name_fixed(contextp
->context
, princ
, name
, sizeof(name
));
492 krb5_warnx(contextp
->context
, "%s: %s %s", client
, op
, name
);
494 * The change is allowed if at least one of:
495 * a) it's for the principal him/herself and this was an initial ticket
496 * b) the user is on the CPW ACL.
500 && krb5_principal_compare (contextp
->context
, contextp
->caller
,
504 ret
= _kadm5_acl_check_permission(contextp
, KADM5_PRIV_CPW
, princ
);
510 * See comments in kadm5_c_randkey_principal() regarding the
513 ret
= krb5_ret_int32(sp
, &keepold
);
514 if (ret
!= 0 && ret
!= HEIM_ERR_EOF
)
517 ret
= krb5_ret_int32(sp
, &n_ks_tuple
);
518 if (ret
== HEIM_ERR_EOF
) {
519 const char *enctypes
;
522 enctypes
= krb5_config_get_string(contextp
->context
, NULL
,
524 krb5_principal_get_realm(contextp
->context
,
526 "supported_enctypes", NULL
);
527 if (enctypes
== NULL
|| enctypes
[0] == '\0')
528 enctypes
= "aes128-cts-hmac-sha1-96";
529 ret
= krb5_string_to_keysalts2(contextp
->context
, enctypes
,
536 if (n_ks_tuple
< 0) {
541 if ((ks_tuple
= calloc(n_ks_tuple
, sizeof (*ks_tuple
))) == NULL
) {
546 for (i
= 0; i
< n_ks_tuple
; i
++) {
547 ret
= krb5_ret_int32(sp
, &ks_tuple
[i
].ks_enctype
);
552 ret
= krb5_ret_int32(sp
, &ks_tuple
[i
].ks_salttype
);
558 ret
= kadm5_randkey_principal_3(kadm_handlep
, princ
, keepold
,
559 n_ks_tuple
, ks_tuple
, &new_keys
,
563 krb5_storage_free(sp
);
564 sp
= krb5_storage_emem();
566 ret
= krb5_enomem(contextp
->context
);
569 krb5_store_int32(sp
, ret
);
571 krb5_store_int32(sp
, n_keys
);
572 for (i
= 0; i
< n_keys
; i
++){
574 ret
= krb5_store_keyblock(sp
, new_keys
[i
]);
575 krb5_free_keyblock_contents(contextp
->context
, &new_keys
[i
]);
581 case kadm_get_privs
:{
583 ret
= kadm5_get_privs(kadm_handlep
, &privs
);
584 krb5_storage_free(sp
);
585 sp
= krb5_storage_emem();
587 ret
= krb5_enomem(contextp
->context
);
590 krb5_store_int32(sp
, ret
);
592 krb5_store_uint32(sp
, privs
);
595 case kadm_get_princs
:{
597 ret
= krb5_ret_int32(sp
, &tmp
);
601 ret
= krb5_ret_string(sp
, &expression
);
606 krb5_warnx(contextp
->context
, "%s: %s %s", client
, op
,
607 expression
? expression
: "*");
608 ret
= _kadm5_acl_check_permission(contextp
, KADM5_PRIV_LIST
, NULL
);
613 ret
= kadm5_get_principals(kadm_handlep
, expression
, &princs
, &n_princs
);
615 krb5_storage_free(sp
);
616 sp
= krb5_storage_emem();
618 ret
= krb5_enomem(contextp
->context
);
621 krb5_store_int32(sp
, ret
);
624 krb5_store_int32(sp
, n_princs
);
625 for(i
= 0; i
< n_princs
; i
++)
626 krb5_store_string(sp
, princs
[i
]);
627 kadm5_free_name_list(kadm_handlep
, princs
, &n_princs
);
632 krb5_warnx(contextp
->context
, "%s: UNKNOWN OP %d", client
, cmd
);
633 krb5_storage_free(sp
);
634 sp
= krb5_storage_emem();
636 ret
= krb5_enomem(contextp
->context
);
639 krb5_store_int32(sp
, KADM5_FAILURE
);
642 if (password
!= NULL
) {
643 len
= strlen(password
);
644 memset_s(password
, len
, 0, len
);
647 krb5_storage_to_data(sp
, out
);
648 krb5_storage_free(sp
);
650 krb5_free_principal(contextp
->context
, princ
);
652 krb5_free_principal(contextp
->context
, princ2
);
655 if (password
!= NULL
) {
656 len
= strlen(password
);
657 memset_s(password
, len
, 0, len
);
660 krb5_warn(contextp
->context
, ret
, "%s", op
);
662 krb5_storage_seek(sp
, 0, SEEK_SET
);
663 krb5_store_int32(sp
, ret
);
664 krb5_storage_to_data(sp
, out
);
665 krb5_storage_free(sp
);
668 krb5_free_principal(contextp
->context
, princ
);
670 krb5_free_principal(contextp
->context
, princ2
);
674 struct iter_aliases_ctx
{
675 HDB_Ext_Aliases aliases
;
682 iter_aliases(kadm5_principal_ent_rec
*from
,
683 struct iter_aliases_ctx
*ctx
,
695 if (ctx
->done
== 0) {
696 if (ctx
->alias_idx
< ctx
->aliases
.aliases
.len
) {
697 *out
= &ctx
->aliases
.aliases
.val
[ctx
->alias_idx
++];
700 /* Out of aliases in this TL, step to next TL */
701 ctx
->tl
= ctx
->tl
->tl_data_next
;
702 } else if (ctx
->done
< 0) {
703 /* Setup iteration context */
704 memset(ctx
, 0, sizeof(*ctx
));
706 ctx
->aliases
.aliases
.val
= NULL
;
707 ctx
->aliases
.aliases
.len
= 0;
708 ctx
->tl
= from
->tl_data
;
711 free_HDB_Ext_Aliases(&ctx
->aliases
);
714 /* Find TL with aliases */
715 for (; ctx
->tl
!= NULL
; ctx
->tl
= ctx
->tl
->tl_data_next
) {
716 if (ctx
->tl
->tl_data_type
!= KRB5_TL_EXTENSION
)
719 ret
= decode_HDB_extension(ctx
->tl
->tl_data_contents
,
720 ctx
->tl
->tl_data_length
,
724 if (ext
.data
.element
== choice_HDB_extension_data_aliases
&&
725 ext
.data
.u
.aliases
.aliases
.len
> 0) {
726 ctx
->aliases
= ext
.data
.u
.aliases
;
729 free_HDB_extension(&ext
);
732 if (ctx
->tl
!= NULL
&& ctx
->aliases
.aliases
.len
> 0) {
733 *out
= &ctx
->aliases
.aliases
.val
[ctx
->alias_idx
++];
742 check_aliases(kadm5_server_context
*contextp
,
743 kadm5_principal_ent_rec
*add_princ
,
744 kadm5_principal_ent_rec
*del_princ
)
747 struct iter_aliases_ctx iter
;
748 struct iter_aliases_ctx iter_del
;
749 krb5_principal new_name
, old_name
;
753 * Yeah, this is O(N^2). Gathering and sorting all the aliases
754 * would be a bit of a pain; if we ever have principals with enough
755 * aliases for this to be a problem, we can fix it then.
757 for (iter
.done
= -1; iter
.done
!= 1;) {
759 ret
= iter_aliases(add_princ
, &iter
, &new_name
);
764 for (iter_del
.done
= -1; iter_del
.done
!= 1;) {
765 ret
= iter_aliases(del_princ
, &iter_del
, &old_name
);
768 if (iter_del
.done
== 1)
770 if (!krb5_principal_compare(contextp
->context
, new_name
, old_name
))
772 free_HDB_Ext_Aliases(&iter_del
.aliases
);
778 ret
= _kadm5_acl_check_permission(contextp
, KADM5_PRIV_ADD
, new_name
);
780 free_HDB_Ext_Aliases(&iter
.aliases
);
789 v5_loop (krb5_context contextp
,
790 krb5_auth_context ac
,
791 krb5_boolean initial
,
800 doing_useful_work
= 0;
803 ret
= krb5_read_priv_message(contextp
, ac
, &fd
, &in
);
804 if(ret
== HEIM_ERR_EOF
)
807 krb5_err(contextp
, 1, ret
, "krb5_read_priv_message");
808 doing_useful_work
= 1;
809 ret
= kadmind_dispatch(kadm_handlep
, initial
, &in
, &out
, readonly
);
811 krb5_err(contextp
, 1, ret
, "kadmind_dispatch");
813 ret
= krb5_write_priv_message(contextp
, ac
, &fd
, &out
);
814 krb5_data_free(&out
);
816 krb5_err(contextp
, 1, ret
, "krb5_write_priv_message");
821 match_appl_version(const void *data
, const char *appl_version
)
824 if(sscanf(appl_version
, "KADM0.%u", &minor
) != 1)
827 *(unsigned*)(intptr_t)data
= minor
;
832 handle_v5(krb5_context contextp
,
842 krb5_boolean initial
;
843 krb5_auth_context ac
= NULL
;
845 unsigned kadm_version
= 1;
846 kadm5_config_params realm_params
;
848 ret
= krb5_recvauth_match_version(contextp
, &ac
, &fd
,
849 match_appl_version
, &kadm_version
,
850 NULL
, KRB5_RECVAUTH_IGNORE_VERSION
,
853 krb5_err(contextp
, 1, ret
, "krb5_recvauth");
855 ret
= krb5_unparse_name (contextp
, ticket
->server
, &server_name
);
857 krb5_err (contextp
, 1, ret
, "krb5_unparse_name");
859 if (strncmp (server_name
, KADM5_ADMIN_SERVICE
,
860 strlen(KADM5_ADMIN_SERVICE
)) != 0)
861 krb5_errx (contextp
, 1, "ticket for strange principal (%s)",
866 memset(&realm_params
, 0, sizeof(realm_params
));
868 if(kadm_version
== 1) {
870 ret
= krb5_read_priv_message(contextp
, ac
, &fd
, ¶ms
);
872 krb5_err(contextp
, 1, ret
, "krb5_read_priv_message");
873 _kadm5_unmarshal_params(contextp
, ¶ms
, &realm_params
);
876 initial
= ticket
->ticket
.flags
.initial
;
877 ret
= krb5_unparse_name(contextp
, ticket
->client
, &client
);
879 krb5_err (contextp
, 1, ret
, "krb5_unparse_name");
880 krb5_free_ticket (contextp
, ticket
);
881 ret
= kadm5_s_init_with_password_ctx(contextp
,
889 krb5_err (contextp
, 1, ret
, "kadm5_init_with_password_ctx");
890 v5_loop (contextp
, ac
, initial
, kadm_handlep
, fd
, readonly
);
894 kadmind_loop(krb5_context contextp
,
899 u_char buf
[sizeof(KRB5_SENDAUTH_VERSION
) + 4];
903 n
= krb5_net_read(contextp
, &sock
, buf
, 4);
907 krb5_err(contextp
, 1, errno
, "read");
908 _krb5_get_int(buf
, &len
, 4);
910 if (len
== sizeof(KRB5_SENDAUTH_VERSION
)) {
912 n
= krb5_net_read(contextp
, &sock
, buf
+ 4, len
);
914 krb5_err (contextp
, 1, errno
, "reading sendauth version");
916 krb5_errx (contextp
, 1, "EOF reading sendauth version");
918 if(memcmp(buf
+ 4, KRB5_SENDAUTH_VERSION
, len
) == 0) {
919 handle_v5(contextp
, keytab
, sock
, readonly
);
926 handle_mit(contextp
, buf
, len
, sock
, readonly
);