2 * Copyright (c) 1997, 1998 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 "kadm5_locl.h"
44 kadmind_dispatch(void *kadm_handle
, krb5_data
*in
, krb5_data
*out
)
47 int32_t cmd
, mask
, tmp
;
48 kadm5_server_context
*context
= kadm_handle
;
49 char client
[128], name
[128], name2
[128];
51 krb5_principal princ
, princ2
;
52 kadm5_principal_ent_rec ent
;
54 krb5_keyblock
*new_keys
;
60 krb5_unparse_name_fixed(context
->context
, context
->caller
,
61 client
, sizeof(client
));
63 sp
= krb5_storage_from_data(in
);
65 krb5_ret_int32(sp
, &cmd
);
69 ret
= krb5_ret_principal(sp
, &princ
);
72 ret
= krb5_ret_int32(sp
, &mask
);
74 krb5_free_principal(context
->context
, princ
);
77 krb5_unparse_name_fixed(context
->context
, princ
, name
, sizeof(name
));
78 krb5_warnx(context
->context
, "%s: %s %s", client
, op
, name
);
79 ret
= _kadm5_acl_check_permission(context
, KADM5_PRIV_GET
);
81 krb5_free_principal(context
->context
, princ
);
84 ret
= kadm5_get_principal(kadm_handle
, princ
, &ent
, mask
);
85 krb5_storage_free(sp
);
86 sp
= krb5_storage_emem();
87 krb5_store_int32(sp
, ret
);
89 kadm5_store_principal_ent(sp
, &ent
);
90 kadm5_free_principal_ent(kadm_handle
, &ent
);
92 krb5_free_principal(context
->context
, princ
);
97 ret
= krb5_ret_principal(sp
, &princ
);
100 krb5_unparse_name_fixed(context
->context
, princ
, name
, sizeof(name
));
101 krb5_warnx(context
->context
, "%s: %s %s", client
, op
, name
);
102 ret
= _kadm5_acl_check_permission(context
, KADM5_PRIV_DELETE
);
104 krb5_free_principal(context
->context
, princ
);
107 ret
= kadm5_delete_principal(kadm_handle
, princ
);
108 krb5_free_principal(context
->context
, princ
);
109 krb5_storage_free(sp
);
110 sp
= krb5_storage_emem();
111 krb5_store_int32(sp
, ret
);
116 ret
= kadm5_ret_principal_ent(sp
, &ent
);
119 ret
= krb5_ret_int32(sp
, &mask
);
121 kadm5_free_principal_ent(context
->context
, &ent
);
124 ret
= krb5_ret_string(sp
, &password
);
126 kadm5_free_principal_ent(context
->context
, &ent
);
129 krb5_unparse_name_fixed(context
->context
, ent
.principal
,
131 krb5_warnx(context
->context
, "%s: %s %s", client
, op
, name
);
132 ret
= _kadm5_acl_check_permission(context
, KADM5_PRIV_ADD
);
134 kadm5_free_principal_ent(context
->context
, &ent
);
135 memset(password
, 0, strlen(password
));
139 ret
= kadm5_create_principal(kadm_handle
, &ent
,
141 kadm5_free_principal_ent(kadm_handle
, &ent
);
142 memset(password
, 0, strlen(password
));
144 krb5_storage_free(sp
);
145 sp
= krb5_storage_emem();
146 krb5_store_int32(sp
, ret
);
151 ret
= kadm5_ret_principal_ent(sp
, &ent
);
154 ret
= krb5_ret_int32(sp
, &mask
);
156 kadm5_free_principal_ent(context
, &ent
);
159 krb5_unparse_name_fixed(context
->context
, ent
.principal
,
161 krb5_warnx(context
->context
, "%s: %s %s", client
, op
, name
);
162 ret
= _kadm5_acl_check_permission(context
, KADM5_PRIV_MODIFY
);
164 kadm5_free_principal_ent(context
, &ent
);
167 ret
= kadm5_modify_principal(kadm_handle
, &ent
, mask
);
168 kadm5_free_principal_ent(kadm_handle
, &ent
);
169 krb5_storage_free(sp
);
170 sp
= krb5_storage_emem();
171 krb5_store_int32(sp
, ret
);
176 ret
= krb5_ret_principal(sp
, &princ
);
179 ret
= krb5_ret_principal(sp
, &princ2
);
181 krb5_free_principal(context
->context
, princ
);
184 krb5_unparse_name_fixed(context
->context
, princ
, name
, sizeof(name
));
185 krb5_unparse_name_fixed(context
->context
, princ2
, name2
, sizeof(name2
));
186 krb5_warnx(context
->context
, "%s: %s %s -> %s",
187 client
, op
, name
, name2
);
188 ret
= _kadm5_acl_check_permission(context
,
189 KADM5_PRIV_ADD
|KADM5_PRIV_DELETE
);
191 krb5_free_principal(context
->context
, princ
);
194 ret
= kadm5_rename_principal(kadm_handle
, princ
, princ2
);
195 krb5_free_principal(context
->context
, princ
);
196 krb5_free_principal(context
->context
, princ2
);
197 krb5_storage_free(sp
);
198 sp
= krb5_storage_emem();
199 krb5_store_int32(sp
, ret
);
204 ret
= krb5_ret_principal(sp
, &princ
);
207 ret
= krb5_ret_string(sp
, &password
);
209 krb5_free_principal(context
->context
, princ
);
212 krb5_unparse_name_fixed(context
->context
, princ
, name
, sizeof(name
));
213 krb5_warnx(context
->context
, "%s: %s %s", client
, op
, name
);
215 /* anyone can change her/his own password */
216 /* but not until there is a way to ensure that the
217 authentication was done via an initial ticket request */
218 if(!krb5_principal_compare(context
->context
, context
->caller
, princ
))
219 ret
= KADM5_AUTH_INSUFFICIENT
;
222 ret
= _kadm5_acl_check_permission(context
, KADM5_PRIV_CPW
);
224 krb5_free_principal(context
->context
, princ
);
227 ret
= kadm5_chpass_principal(kadm_handle
, princ
, password
);
228 krb5_free_principal(context
->context
, princ
);
229 memset(password
, 0, strlen(password
));
231 krb5_storage_free(sp
);
232 sp
= krb5_storage_emem();
233 krb5_store_int32(sp
, ret
);
238 ret
= krb5_ret_principal(sp
, &princ
);
241 krb5_unparse_name_fixed(context
->context
, princ
, name
, sizeof(name
));
242 krb5_warnx(context
->context
, "%s: %s %s", client
, op
, name
);
244 /* anyone can change her/his own password */
245 /* but not until there is a way to ensure that the
246 authentication was done via an initial ticket request */
247 if(!krb5_principal_compare(context
->context
, context
->caller
, princ
))
248 ret
= KADM5_AUTH_INSUFFICIENT
;
251 ret
= _kadm5_acl_check_permission(context
, KADM5_PRIV_CPW
);
253 krb5_free_principal(context
->context
, princ
);
256 ret
= kadm5_randkey_principal(kadm_handle
, princ
,
258 krb5_free_principal(context
->context
, princ
);
259 krb5_storage_free(sp
);
260 sp
= krb5_storage_emem();
261 krb5_store_int32(sp
, ret
);
264 krb5_store_int32(sp
, n_keys
);
265 for(i
= 0; i
< n_keys
; i
++){
266 krb5_store_keyblock(sp
, new_keys
[i
]);
267 krb5_free_keyblock_contents(context
->context
, &new_keys
[i
]);
272 case kadm_get_privs
:{
273 ret
= kadm5_get_privs(kadm_handle
, &mask
);
274 krb5_storage_free(sp
);
275 sp
= krb5_storage_emem();
276 krb5_store_int32(sp
, ret
);
278 krb5_store_int32(sp
, mask
);
281 case kadm_get_princs
:{
283 ret
= krb5_ret_int32(sp
, &tmp
);
287 ret
= krb5_ret_string(sp
, &exp
);
292 krb5_warnx(context
->context
, "%s: %s %s", client
, op
, exp
? exp
: "*");
293 ret
= _kadm5_acl_check_permission(context
, KADM5_PRIV_LIST
);
298 ret
= kadm5_get_principals(kadm_handle
, exp
, &princs
, &n_princs
);
300 krb5_storage_free(sp
);
301 sp
= krb5_storage_emem();
302 krb5_store_int32(sp
, ret
);
305 krb5_store_int32(sp
, n_princs
);
306 for(i
= 0; i
< n_princs
; i
++)
307 krb5_store_string(sp
, princs
[i
]);
308 kadm5_free_name_list(kadm_handle
, princs
, &n_princs
);
313 krb5_warnx(context
->context
, "%s: UNKNOWN OP %d", client
, cmd
);
314 krb5_storage_free(sp
);
315 sp
= krb5_storage_emem();
316 krb5_store_int32(sp
, KADM5_FAILURE
);
319 krb5_storage_to_data(sp
, out
);
320 krb5_storage_free(sp
);
323 krb5_warn(context
->context
, ret
, "%s", op
);
324 sp
->seek(sp
, 0, SEEK_SET
);
325 krb5_store_int32(sp
, ret
);
326 krb5_storage_to_data(sp
, out
);
327 krb5_storage_free(sp
);
332 kadmind_loop(krb5_context context
,
333 krb5_auth_context ac
,
339 ret
= kadm5_init_with_password_ctx(context
,
350 krb5_data in
, out
, msg
, reply
;
351 unsigned char tmp
[4];
355 krb5_boolean krb4_packet
= 0;
357 n
= krb5_net_read(context
, &fd
, tmp
, 4);
361 krb5_errx(context
, 1, "read error: %d", errno
);
363 krb5_errx(context
, 1, "short read (%ld)", (long int)n
);
364 k_get_int(tmp
, &len
, 4);
365 if(len
> 0xffff && (len
& 0xffff) == ('K' << 8) + 'A') {
368 krb5_errx(context
, 1, "packet appears to be version 4");
371 in
.data
= malloc(in
.length
);
372 n
= krb5_net_read(context
, &fd
, in
.data
, in
.length
);
374 krb5_errx(context
, 1, "read error: %d", errno
);
376 krb5_errx(context
, 1, "short read (%ld)", (long int)n
);
378 ret
= krb5_rd_priv(context
, ac
, &in
, &out
, NULL
);
380 kadmind_dispatch(kadm_handle
, &out
, &msg
);
381 krb5_data_free(&out
);
383 ret
= krb5_mk_priv(context
, ac
, &msg
, &reply
, NULL
);
384 krb5_data_free(&msg
);
386 krb5_err(context
, 1, ret
, "krb5_mk_priv");
388 k_put_int(tmp
, reply
.length
, 4);
390 iov
[0].iov_base
= tmp
;
392 iov
[1].iov_base
= reply
.data
;
393 iov
[1].iov_len
= reply
.length
;
394 n
= writev(fd
, iov
, 2);
395 krb5_data_free(&reply
);
397 krb5_err(context
, 1, errno
, "writev");
398 if(n
< iov
[0].iov_len
+ iov
[1].iov_len
)
399 krb5_errx(context
, 1, "short write");