2 * Copyright (c) 1997-1999 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. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Kungliga Tekniska
20 * Högskolan and its contributors.
22 * 4. Neither the name of the Institute nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 #include "kadmin_locl.h"
40 #include <krb5-private.h>
45 kadmind_dispatch(void *kadm_handle
, krb5_data
*in
, krb5_data
*out
)
48 int32_t cmd
, mask
, tmp
;
49 kadm5_server_context
*context
= kadm_handle
;
50 char client
[128], name
[128], name2
[128];
52 krb5_principal princ
, princ2
;
53 kadm5_principal_ent_rec ent
;
55 krb5_keyblock
*new_keys
;
61 krb5_unparse_name_fixed(context
->context
, context
->caller
,
62 client
, sizeof(client
));
64 sp
= krb5_storage_from_data(in
);
66 krb5_ret_int32(sp
, &cmd
);
70 ret
= krb5_ret_principal(sp
, &princ
);
73 ret
= krb5_ret_int32(sp
, &mask
);
75 krb5_free_principal(context
->context
, princ
);
78 krb5_unparse_name_fixed(context
->context
, princ
, name
, sizeof(name
));
79 krb5_warnx(context
->context
, "%s: %s %s", client
, op
, name
);
80 ret
= _kadm5_acl_check_permission(context
, KADM5_PRIV_GET
);
82 krb5_free_principal(context
->context
, princ
);
85 ret
= kadm5_get_principal(kadm_handle
, princ
, &ent
, mask
);
86 krb5_storage_free(sp
);
87 sp
= krb5_storage_emem();
88 krb5_store_int32(sp
, ret
);
90 kadm5_store_principal_ent(sp
, &ent
);
91 kadm5_free_principal_ent(kadm_handle
, &ent
);
93 krb5_free_principal(context
->context
, princ
);
98 ret
= krb5_ret_principal(sp
, &princ
);
101 krb5_unparse_name_fixed(context
->context
, princ
, name
, sizeof(name
));
102 krb5_warnx(context
->context
, "%s: %s %s", client
, op
, name
);
103 ret
= _kadm5_acl_check_permission(context
, KADM5_PRIV_DELETE
);
105 krb5_free_principal(context
->context
, princ
);
108 ret
= kadm5_delete_principal(kadm_handle
, princ
);
109 krb5_free_principal(context
->context
, princ
);
110 krb5_storage_free(sp
);
111 sp
= krb5_storage_emem();
112 krb5_store_int32(sp
, ret
);
117 ret
= kadm5_ret_principal_ent(sp
, &ent
);
120 ret
= krb5_ret_int32(sp
, &mask
);
122 kadm5_free_principal_ent(context
->context
, &ent
);
125 ret
= krb5_ret_string(sp
, &password
);
127 kadm5_free_principal_ent(context
->context
, &ent
);
130 krb5_unparse_name_fixed(context
->context
, ent
.principal
,
132 krb5_warnx(context
->context
, "%s: %s %s", client
, op
, name
);
133 ret
= _kadm5_acl_check_permission(context
, KADM5_PRIV_ADD
);
135 kadm5_free_principal_ent(context
->context
, &ent
);
136 memset(password
, 0, strlen(password
));
140 ret
= kadm5_create_principal(kadm_handle
, &ent
,
142 kadm5_free_principal_ent(kadm_handle
, &ent
);
143 memset(password
, 0, strlen(password
));
145 krb5_storage_free(sp
);
146 sp
= krb5_storage_emem();
147 krb5_store_int32(sp
, ret
);
152 ret
= kadm5_ret_principal_ent(sp
, &ent
);
155 ret
= krb5_ret_int32(sp
, &mask
);
157 kadm5_free_principal_ent(context
, &ent
);
160 krb5_unparse_name_fixed(context
->context
, ent
.principal
,
162 krb5_warnx(context
->context
, "%s: %s %s", client
, op
, name
);
163 ret
= _kadm5_acl_check_permission(context
, KADM5_PRIV_MODIFY
);
165 kadm5_free_principal_ent(context
, &ent
);
168 ret
= kadm5_modify_principal(kadm_handle
, &ent
, mask
);
169 kadm5_free_principal_ent(kadm_handle
, &ent
);
170 krb5_storage_free(sp
);
171 sp
= krb5_storage_emem();
172 krb5_store_int32(sp
, ret
);
177 ret
= krb5_ret_principal(sp
, &princ
);
180 ret
= krb5_ret_principal(sp
, &princ2
);
182 krb5_free_principal(context
->context
, princ
);
185 krb5_unparse_name_fixed(context
->context
, princ
, name
, sizeof(name
));
186 krb5_unparse_name_fixed(context
->context
, princ2
, name2
, sizeof(name2
));
187 krb5_warnx(context
->context
, "%s: %s %s -> %s",
188 client
, op
, name
, name2
);
189 ret
= _kadm5_acl_check_permission(context
,
190 KADM5_PRIV_ADD
|KADM5_PRIV_DELETE
);
192 krb5_free_principal(context
->context
, princ
);
195 ret
= kadm5_rename_principal(kadm_handle
, princ
, princ2
);
196 krb5_free_principal(context
->context
, princ
);
197 krb5_free_principal(context
->context
, princ2
);
198 krb5_storage_free(sp
);
199 sp
= krb5_storage_emem();
200 krb5_store_int32(sp
, ret
);
205 ret
= krb5_ret_principal(sp
, &princ
);
208 ret
= krb5_ret_string(sp
, &password
);
210 krb5_free_principal(context
->context
, princ
);
213 krb5_unparse_name_fixed(context
->context
, princ
, name
, sizeof(name
));
214 krb5_warnx(context
->context
, "%s: %s %s", client
, op
, name
);
216 /* anyone can change her/his own password */
217 /* but not until there is a way to ensure that the
218 authentication was done via an initial ticket request */
219 if(!krb5_principal_compare(context
->context
, context
->caller
, princ
))
220 ret
= KADM5_AUTH_INSUFFICIENT
;
223 ret
= _kadm5_acl_check_permission(context
, KADM5_PRIV_CPW
);
225 krb5_free_principal(context
->context
, princ
);
228 ret
= kadm5_chpass_principal(kadm_handle
, princ
, password
);
229 krb5_free_principal(context
->context
, princ
);
230 memset(password
, 0, strlen(password
));
232 krb5_storage_free(sp
);
233 sp
= krb5_storage_emem();
234 krb5_store_int32(sp
, ret
);
239 ret
= krb5_ret_principal(sp
, &princ
);
242 krb5_unparse_name_fixed(context
->context
, princ
, name
, sizeof(name
));
243 krb5_warnx(context
->context
, "%s: %s %s", client
, op
, name
);
245 /* anyone can change her/his own password */
246 /* but not until there is a way to ensure that the
247 authentication was done via an initial ticket request */
248 if(!krb5_principal_compare(context
->context
, context
->caller
, princ
))
249 ret
= KADM5_AUTH_INSUFFICIENT
;
252 ret
= _kadm5_acl_check_permission(context
, KADM5_PRIV_CPW
);
254 krb5_free_principal(context
->context
, princ
);
257 ret
= kadm5_randkey_principal(kadm_handle
, princ
,
259 krb5_free_principal(context
->context
, princ
);
260 krb5_storage_free(sp
);
261 sp
= krb5_storage_emem();
262 krb5_store_int32(sp
, ret
);
265 krb5_store_int32(sp
, n_keys
);
266 for(i
= 0; i
< n_keys
; i
++){
267 krb5_store_keyblock(sp
, new_keys
[i
]);
268 krb5_free_keyblock_contents(context
->context
, &new_keys
[i
]);
273 case kadm_get_privs
:{
274 ret
= kadm5_get_privs(kadm_handle
, &mask
);
275 krb5_storage_free(sp
);
276 sp
= krb5_storage_emem();
277 krb5_store_int32(sp
, ret
);
279 krb5_store_int32(sp
, mask
);
282 case kadm_get_princs
:{
284 ret
= krb5_ret_int32(sp
, &tmp
);
288 ret
= krb5_ret_string(sp
, &exp
);
293 krb5_warnx(context
->context
, "%s: %s %s", client
, op
, exp
? exp
: "*");
294 ret
= _kadm5_acl_check_permission(context
, KADM5_PRIV_LIST
);
299 ret
= kadm5_get_principals(kadm_handle
, exp
, &princs
, &n_princs
);
301 krb5_storage_free(sp
);
302 sp
= krb5_storage_emem();
303 krb5_store_int32(sp
, ret
);
306 krb5_store_int32(sp
, n_princs
);
307 for(i
= 0; i
< n_princs
; i
++)
308 krb5_store_string(sp
, princs
[i
]);
309 kadm5_free_name_list(kadm_handle
, princs
, &n_princs
);
314 krb5_warnx(context
->context
, "%s: UNKNOWN OP %d", client
, cmd
);
315 krb5_storage_free(sp
);
316 sp
= krb5_storage_emem();
317 krb5_store_int32(sp
, KADM5_FAILURE
);
320 krb5_storage_to_data(sp
, out
);
321 krb5_storage_free(sp
);
324 krb5_warn(context
->context
, ret
, "%s", op
);
325 sp
->seek(sp
, 0, SEEK_SET
);
326 krb5_store_int32(sp
, ret
);
327 krb5_storage_to_data(sp
, out
);
328 krb5_storage_free(sp
);
333 v5_loop (krb5_context context
,
334 krb5_auth_context ac
,
343 krb5_data in
, out
, msg
, reply
;
346 krb5_net_read(context
, &fd
, tmp
, 4);
347 _krb5_get_int (tmp
, &len
, 4);
350 in
.data
= malloc(in
.length
);
351 n
= krb5_net_read(context
, &fd
, in
.data
, in
.length
);
355 krb5_errx(context
, 1, "read error: %d", errno
);
357 krb5_errx(context
, 1, "short read (%ld)", (long int)n
);
358 ret
= krb5_rd_priv(context
, ac
, &in
, &out
, NULL
);
360 kadmind_dispatch(kadm_handle
, &out
, &msg
);
361 krb5_data_free(&out
);
362 ret
= krb5_mk_priv(context
, ac
, &msg
, &reply
, NULL
);
363 krb5_data_free(&msg
);
365 krb5_err(context
, 1, ret
, "krb5_mk_priv");
367 _krb5_put_int(tmp
, reply
.length
, 4);
369 iov
[0].iov_base
= tmp
;
371 iov
[1].iov_base
= reply
.data
;
372 iov
[1].iov_len
= reply
.length
;
373 n
= writev(fd
, iov
, 2);
374 krb5_data_free(&reply
);
376 krb5_err(context
, 1, errno
, "writev");
377 if(n
< iov
[0].iov_len
+ iov
[1].iov_len
)
378 krb5_errx(context
, 1, "short write");
383 handle_v5(krb5_context context
,
384 krb5_auth_context ac
,
392 krb5_principal server
;
396 krb5_net_read(context
, &fd
, tmp
, len
);
397 if(len
!= sizeof(KRB5_SENDAUTH_VERSION
) ||
398 memcmp(tmp
, KRB5_SENDAUTH_VERSION
, len
) != 0)
399 krb5_errx(context
, 1, "bad sendauth version %.8s", tmp
);
401 krb5_parse_name(context
, KADM5_ADMIN_SERVICE
, &server
);
402 ret
= krb5_recvauth(context
, &ac
, &fd
, KADMIN_APPL_VERSION
,
403 server
, KRB5_RECVAUTH_IGNORE_VERSION
,
405 krb5_free_principal(context
, server
);
408 krb5_err(context
, 1, ret
, "krb5_recvauth");
409 krb5_unparse_name(context
, ticket
->client
, &client
);
410 ret
= kadm5_init_with_password_ctx(context
,
417 krb5_err (context
, 1, ret
, "kadm5_init_with_password_ctx");
418 v5_loop (context
, ac
, kadm_handle
, fd
);
422 kadmind_loop(krb5_context context
,
423 krb5_auth_context ac
,
427 unsigned char tmp
[4];
431 n
= krb5_net_read(context
, &fd
, tmp
, 4);
435 krb5_errx(context
, 1, "read error: %d", errno
);
437 krb5_errx(context
, 1, "short read (%ld)", (long int)n
);
438 _krb5_get_int(tmp
, &len
, 4);
439 if(len
> 0xffff && (len
& 0xffff) == ('K' << 8) + 'A') {
442 handle_v4(context
, len
, fd
);
444 krb5_errx(context
, 1, "packet appears to be version 4");
447 handle_v5(context
, ac
, keytab
, len
, fd
);