1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3 * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
4 *
5 */
6
7 #include <k5-int.h>
8 #include <socket-utils.h>
9 #include <gssapi/gssapi.h>
10 #include <gssapi/gssapi_krb5.h> /* for gss_nt_krb5_name */
11 #include <krb5.h>
12 #include <kadm5/admin.h>
13 #include <kadm5/kadm_rpc.h>
14 #include <kadm5/server_internal.h>
15 #include <syslog.h>
16 #include <adm_proto.h> /* krb5_klog_syslog */
17 #include "misc.h"
18 #include "auth.h"
19
20 extern gss_name_t gss_changepw_name;
21 extern gss_name_t gss_oldchangepw_name;
22 extern void * global_server_handle;
23
24 #define CHANGEPW_SERVICE(rqstp) \
25 (cmp_gss_names_rel_1(acceptor_name(rqstp->rq_svccred), gss_changepw_name) | \
26 (gss_oldchangepw_name && \
27 cmp_gss_names_rel_1(acceptor_name(rqstp->rq_svccred), \
28 gss_oldchangepw_name)))
29
30
31 static int gss_to_krb5_name(kadm5_server_handle_t handle,
32 gss_name_t gss_name, krb5_principal *princ);
33
34 static int gss_name_to_string(gss_name_t gss_name, gss_buffer_desc *str);
35
36 static gss_name_t acceptor_name(gss_ctx_id_t context);
37
38 gss_name_t rqst2name(struct svc_req *rqstp);
39
cmp_gss_names(gss_name_t n1,gss_name_t n2)40 static int cmp_gss_names(gss_name_t n1, gss_name_t n2)
41 {
42 OM_uint32 emin;
43 int equal;
44
45 if (GSS_ERROR(gss_compare_name(&emin, n1, n2, &equal)))
46 return(0);
47
48 return(equal);
49 }
50
51 /* Does a comparison of the names and then releases the first entity */
52 /* For use above in CHANGEPW_SERVICE */
cmp_gss_names_rel_1(gss_name_t n1,gss_name_t n2)53 static int cmp_gss_names_rel_1(gss_name_t n1, gss_name_t n2)
54 {
55 OM_uint32 min_stat;
56 int ret;
57
58 ret = cmp_gss_names(n1, n2);
59 if (n1) (void) gss_release_name(&min_stat, &n1);
60 return ret;
61 }
62
63 /*
64 * Function check_handle
65 *
66 * Purpose: Check a server handle and return a com_err code if it is
67 * invalid or 0 if it is valid.
68 *
69 * Arguments:
70 *
71 * handle The server handle.
72 */
73
check_handle(void * handle)74 static int check_handle(void *handle)
75 {
76 CHECK_HANDLE(handle);
77 return 0;
78 }
79
80 /*
81 * Function: new_server_handle
82 *
83 * Purpose: Constructs a server handle suitable for passing into the
84 * server library API functions, by folding the client's API version
85 * and calling principal into the server handle returned by
86 * kadm5_init.
87 *
88 * Arguments:
89 * api_version (input) The API version specified by the client
90 * rqstp (input) The RPC request
91 * handle (output) The returned handle
92 * <return value> (output) An error code, or 0 if no error occurred
93 *
94 * Effects:
95 * Returns a pointer to allocated storage containing the server
96 * handle. If an error occurs, then no allocated storage is
97 * returned, and the return value of the function will be a
98 * non-zero com_err code.
99 *
100 * The allocated storage for the handle should be freed with
101 * free_server_handle (see below) when it is no longer needed.
102 */
103
new_server_handle(krb5_ui_4 api_version,struct svc_req * rqstp,kadm5_server_handle_t * out_handle)104 static kadm5_ret_t new_server_handle(krb5_ui_4 api_version,
105 struct svc_req *rqstp,
106 kadm5_server_handle_t
107 *out_handle)
108 {
109 kadm5_server_handle_t handle;
110
111 *out_handle = NULL;
112
113 if (! (handle = (kadm5_server_handle_t)
114 malloc(sizeof(*handle))))
115 return ENOMEM;
116
117 *handle = *(kadm5_server_handle_t)global_server_handle;
118 handle->api_version = api_version;
119
120 if (! gss_to_krb5_name(handle, rqst2name(rqstp),
121 &handle->current_caller)) {
122 free(handle);
123 return KADM5_FAILURE;
124 }
125
126 *out_handle = handle;
127 return 0;
128 }
129
130 /*
131 * Function: free_server_handle
132 *
133 * Purpose: Free handle memory allocated by new_server_handle
134 *
135 * Arguments:
136 * handle (input/output) The handle to free
137 */
free_server_handle(kadm5_server_handle_t handle)138 static void free_server_handle(kadm5_server_handle_t handle)
139 {
140 if (!handle)
141 return;
142 krb5_free_principal(handle->context, handle->current_caller);
143 free(handle);
144 }
145
146 /* Result is stored in a static buffer and is invalidated by the next call. */
147 const char *
client_addr(SVCXPRT * xprt)148 client_addr(SVCXPRT *xprt)
149 {
150 static char abuf[128];
151 struct sockaddr_storage ss;
152 socklen_t len = sizeof(ss);
153 const char *p = NULL;
154
155 if (getpeername(xprt->xp_sock, ss2sa(&ss), &len) != 0)
156 return "(unknown)";
157 if (ss2sa(&ss)->sa_family == AF_INET)
158 p = inet_ntop(AF_INET, &ss2sin(&ss)->sin_addr, abuf, sizeof(abuf));
159 else if (ss2sa(&ss)->sa_family == AF_INET6)
160 p = inet_ntop(AF_INET6, &ss2sin6(&ss)->sin6_addr, abuf, sizeof(abuf));
161 return (p == NULL) ? "(unknown)" : p;
162 }
163
164 /*
165 * Function: setup_gss_names
166 *
167 * Purpose: Create printable representations of the client and server
168 * names.
169 *
170 * Arguments:
171 * rqstp (r) the RPC request
172 * client_name (w) the gss_buffer_t for the client name
173 * server_name (w) the gss_buffer_t for the server name
174 *
175 * Effects:
176 *
177 * Unparses the client and server names into client_name and
178 * server_name, both of which must be freed by the caller. Returns 0
179 * on success and -1 on failure.
180 */
setup_gss_names(struct svc_req * rqstp,gss_buffer_desc * client_name,gss_buffer_desc * server_name)181 int setup_gss_names(struct svc_req *rqstp,
182 gss_buffer_desc *client_name,
183 gss_buffer_desc *server_name)
184 {
185 OM_uint32 maj_stat, min_stat;
186 gss_name_t server_gss_name;
187
188 if (gss_name_to_string(rqst2name(rqstp), client_name) != 0)
189 return -1;
190 maj_stat = gss_inquire_context(&min_stat, rqstp->rq_svccred, NULL,
191 &server_gss_name, NULL, NULL, NULL,
192 NULL, NULL);
193 if (maj_stat != GSS_S_COMPLETE) {
194 gss_release_buffer(&min_stat, client_name);
195 gss_release_name(&min_stat, &server_gss_name);
196 return -1;
197 }
198 if (gss_name_to_string(server_gss_name, server_name) != 0) {
199 gss_release_buffer(&min_stat, client_name);
200 gss_release_name(&min_stat, &server_gss_name);
201 return -1;
202 }
203 gss_release_name(&min_stat, &server_gss_name);
204 return 0;
205 }
206
acceptor_name(gss_ctx_id_t context)207 static gss_name_t acceptor_name(gss_ctx_id_t context)
208 {
209 OM_uint32 maj_stat, min_stat;
210 gss_name_t name;
211
212 maj_stat = gss_inquire_context(&min_stat, context, NULL, &name,
213 NULL, NULL, NULL, NULL, NULL);
214 if (maj_stat != GSS_S_COMPLETE)
215 return NULL;
216 return name;
217 }
218
gss_to_krb5_name(kadm5_server_handle_t handle,gss_name_t gss_name,krb5_principal * princ)219 static int gss_to_krb5_name(kadm5_server_handle_t handle,
220 gss_name_t gss_name, krb5_principal *princ)
221 {
222 krb5_error_code ret;
223 OM_uint32 minor_stat;
224 gss_buffer_desc gss_str;
225 int success;
226 char *s;
227
228 if (gss_name_to_string(gss_name, &gss_str) != 0)
229 return 0;
230 s = k5memdup0(gss_str.value, gss_str.length, &ret);
231 if (s == NULL) {
232 gss_release_buffer(&minor_stat, &gss_str);
233 return 0;
234 }
235 success = (krb5_parse_name(handle->context, s, princ) == 0);
236 free(s);
237 gss_release_buffer(&minor_stat, &gss_str);
238 return success;
239 }
240
241 static int
gss_name_to_string(gss_name_t gss_name,gss_buffer_desc * str)242 gss_name_to_string(gss_name_t gss_name, gss_buffer_desc *str)
243 {
244 OM_uint32 status, minor_stat;
245 gss_OID gss_type;
246 const char pref[] = KRB5_WELLKNOWN_NAMESTR "/" KRB5_ANONYMOUS_PRINCSTR "@";
247 const size_t preflen = sizeof(pref) - 1;
248
249 status = gss_display_name(&minor_stat, gss_name, str, &gss_type);
250 if (status != GSS_S_COMPLETE)
251 return 1;
252 if (gss_oid_equal(gss_type, GSS_C_NT_ANONYMOUS)) {
253 /* Guard against non-krb5 mechs with different anonymous displays. */
254 if (str->length < preflen || memcmp(str->value, pref, preflen) != 0)
255 return 1;
256 } else if (!gss_oid_equal(gss_type, GSS_KRB5_NT_PRINCIPAL_NAME)) {
257 return 1;
258 }
259 return 0;
260 }
261
262 /*
263 * Perform common initialization for server stub functions. A subset of the
264 * output arguments may be set on failure; the caller is responsible for
265 * initializing outputs and calling stub_cleanup() on success or failure.
266 * princ and princ_str_out may be NULL to omit unparsing a principal name.
267 */
268 static kadm5_ret_t
stub_setup(krb5_ui_4 api_version,struct svc_req * rqstp,krb5_principal princ,kadm5_server_handle_t * handle_out,krb5_ui_4 * api_version_out,gss_buffer_t client_name_out,gss_buffer_t service_name_out,char ** princ_str_out)269 stub_setup(krb5_ui_4 api_version, struct svc_req *rqstp, krb5_principal princ,
270 kadm5_server_handle_t *handle_out, krb5_ui_4 *api_version_out,
271 gss_buffer_t client_name_out, gss_buffer_t service_name_out,
272 char **princ_str_out)
273 {
274 kadm5_ret_t ret;
275
276 ret = new_server_handle(api_version, rqstp, handle_out);
277 if (ret)
278 return ret;
279
280 ret = check_handle(*handle_out);
281 if (ret)
282 return ret;
283
284 *api_version_out = (*handle_out)->api_version;
285
286 if (setup_gss_names(rqstp, client_name_out, service_name_out) < 0)
287 return KADM5_FAILURE;
288
289 if (princ_str_out != NULL) {
290 if (princ == NULL)
291 return KADM5_BAD_PRINCIPAL;
292 if (krb5_unparse_name((*handle_out)->context, princ, princ_str_out))
293 return KADM5_BAD_PRINCIPAL;
294 }
295
296 return KADM5_OK;
297 }
298
299 /* Perform common cleanup for server stub functions. */
300 static void
stub_cleanup(kadm5_server_handle_t handle,char * princ_str,gss_buffer_t client_name,gss_buffer_t service_name)301 stub_cleanup(kadm5_server_handle_t handle, char *princ_str,
302 gss_buffer_t client_name, gss_buffer_t service_name)
303 {
304 OM_uint32 minor_stat;
305
306 auth_end(handle->context);
307 free_server_handle(handle);
308 free(princ_str);
309 gss_release_buffer(&minor_stat, client_name);
310 gss_release_buffer(&minor_stat, service_name);
311 }
312
313 static krb5_boolean
stub_auth(kadm5_server_handle_t handle,int opcode,krb5_const_principal p1,krb5_const_principal p2,const char * s1,const char * s2)314 stub_auth(kadm5_server_handle_t handle, int opcode, krb5_const_principal p1,
315 krb5_const_principal p2, const char *s1, const char *s2)
316 {
317 return auth(handle->context, opcode, handle->current_caller, p1, p2,
318 s1, s2, NULL, 0);
319 }
320
321 static krb5_boolean
stub_auth_pol(kadm5_server_handle_t handle,int opcode,const char * policy,const kadm5_policy_ent_rec * polent,long mask)322 stub_auth_pol(kadm5_server_handle_t handle, int opcode, const char *policy,
323 const kadm5_policy_ent_rec *polent, long mask)
324 {
325 return auth(handle->context, opcode, handle->current_caller, NULL, NULL,
326 policy, NULL, polent, mask);
327 }
328
329 static krb5_boolean
stub_auth_restrict(kadm5_server_handle_t handle,int opcode,kadm5_principal_ent_t ent,long * mask)330 stub_auth_restrict(kadm5_server_handle_t handle, int opcode,
331 kadm5_principal_ent_t ent, long *mask)
332 {
333 return auth_restrict(handle->context, opcode, handle->current_caller,
334 ent, mask);
335 }
336
337 /* Return true if the client authenticated to kadmin/changepw and princ is not
338 * the client principal. */
339 static krb5_boolean
changepw_not_self(kadm5_server_handle_t handle,struct svc_req * rqstp,krb5_const_principal princ)340 changepw_not_self(kadm5_server_handle_t handle, struct svc_req *rqstp,
341 krb5_const_principal princ)
342 {
343 return CHANGEPW_SERVICE(rqstp) &&
344 !krb5_principal_compare(handle->context, handle->current_caller,
345 princ);
346 }
347
348 static krb5_boolean
ticket_is_initial(struct svc_req * rqstp)349 ticket_is_initial(struct svc_req *rqstp)
350 {
351 OM_uint32 status, minor_stat;
352 krb5_flags flags;
353
354 status = gss_krb5_get_tkt_flags(&minor_stat, rqstp->rq_svccred, &flags);
355 if (status != GSS_S_COMPLETE)
356 return 0;
357 return (flags & TKT_FLG_INITIAL) != 0;
358 }
359
360 /* If a key change request is for the client's own principal, verify that the
361 * client used an initial ticket and enforce the policy min_life. */
362 static kadm5_ret_t
check_self_keychange(kadm5_server_handle_t handle,struct svc_req * rqstp,krb5_principal princ)363 check_self_keychange(kadm5_server_handle_t handle, struct svc_req *rqstp,
364 krb5_principal princ)
365 {
366 if (!krb5_principal_compare(handle->context, handle->current_caller,
367 princ))
368 return 0;
369
370 if (!ticket_is_initial(rqstp))
371 return KADM5_AUTH_INITIAL;
372
373 return check_min_life(handle, princ, NULL, 0);
374 }
375
376 static int
log_unauth(char * op,char * target,gss_buffer_t client,gss_buffer_t server,struct svc_req * rqstp)377 log_unauth(
378 char *op,
379 char *target,
380 gss_buffer_t client,
381 gss_buffer_t server,
382 struct svc_req *rqstp)
383 {
384 size_t tlen, clen, slen;
385 char *tdots, *cdots, *sdots;
386
387 tlen = strlen(target);
388 trunc_name(&tlen, &tdots);
389 clen = client->length;
390 trunc_name(&clen, &cdots);
391 slen = server->length;
392 trunc_name(&slen, &sdots);
393
394 /* okay to cast lengths to int because trunc_name limits max value */
395 return krb5_klog_syslog(LOG_NOTICE,
396 _("Unauthorized request: %s, %.*s%s, "
397 "client=%.*s%s, service=%.*s%s, addr=%s"),
398 op, (int)tlen, target, tdots,
399 (int)clen, (char *)client->value, cdots,
400 (int)slen, (char *)server->value, sdots,
401 client_addr(rqstp->rq_xprt));
402 }
403
404 static int
log_done(char * op,char * target,const char * errmsg,gss_buffer_t client,gss_buffer_t server,struct svc_req * rqstp)405 log_done(
406 char *op,
407 char *target,
408 const char *errmsg,
409 gss_buffer_t client,
410 gss_buffer_t server,
411 struct svc_req *rqstp)
412 {
413 size_t tlen, clen, slen;
414 char *tdots, *cdots, *sdots;
415
416 if (errmsg == NULL)
417 errmsg = _("success");
418 tlen = strlen(target);
419 trunc_name(&tlen, &tdots);
420 clen = client->length;
421 trunc_name(&clen, &cdots);
422 slen = server->length;
423 trunc_name(&slen, &sdots);
424
425 /* okay to cast lengths to int because trunc_name limits max value */
426 return krb5_klog_syslog(LOG_NOTICE,
427 _("Request: %s, %.*s%s, %s, "
428 "client=%.*s%s, service=%.*s%s, addr=%s"),
429 op, (int)tlen, target, tdots, errmsg,
430 (int)clen, (char *)client->value, cdots,
431 (int)slen, (char *)server->value, sdots,
432 client_addr(rqstp->rq_xprt));
433 }
434
435 bool_t
create_principal_2_svc(cprinc_arg * arg,generic_ret * ret,struct svc_req * rqstp)436 create_principal_2_svc(cprinc_arg *arg, generic_ret *ret,
437 struct svc_req *rqstp)
438 {
439 char *prime_arg = NULL;
440 gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
441 gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
442 kadm5_server_handle_t handle;
443 const char *errmsg = NULL;
444
445 ret->code = stub_setup(arg->api_version, rqstp, arg->rec.principal,
446 &handle, &ret->api_version, &client_name,
447 &service_name, &prime_arg);
448 if (ret->code)
449 goto exit_func;
450
451 if (CHANGEPW_SERVICE(rqstp) ||
452 !stub_auth_restrict(handle, OP_ADDPRINC, &arg->rec, &arg->mask)) {
453 ret->code = KADM5_AUTH_ADD;
454 log_unauth("kadm5_create_principal", prime_arg,
455 &client_name, &service_name, rqstp);
456 } else {
457 ret->code = kadm5_create_principal(handle, &arg->rec, arg->mask,
458 arg->passwd);
459
460 if (ret->code != 0)
461 errmsg = krb5_get_error_message(handle->context, ret->code);
462
463 log_done("kadm5_create_principal", prime_arg, errmsg,
464 &client_name, &service_name, rqstp);
465
466 if (errmsg != NULL)
467 krb5_free_error_message(handle->context, errmsg);
468 }
469
470 exit_func:
471 stub_cleanup(handle, prime_arg, &client_name, &service_name);
472 return TRUE;
473 }
474
475 bool_t
create_principal3_2_svc(cprinc3_arg * arg,generic_ret * ret,struct svc_req * rqstp)476 create_principal3_2_svc(cprinc3_arg *arg, generic_ret *ret,
477 struct svc_req *rqstp)
478 {
479 char *prime_arg = NULL;
480 gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
481 gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
482 kadm5_server_handle_t handle;
483 const char *errmsg = NULL;
484
485 ret->code = stub_setup(arg->api_version, rqstp, arg->rec.principal,
486 &handle, &ret->api_version, &client_name,
487 &service_name, &prime_arg);
488 if (ret->code)
489 goto exit_func;
490
491 if (CHANGEPW_SERVICE(rqstp) ||
492 !stub_auth_restrict(handle, OP_ADDPRINC, &arg->rec, &arg->mask)) {
493 ret->code = KADM5_AUTH_ADD;
494 log_unauth("kadm5_create_principal", prime_arg,
495 &client_name, &service_name, rqstp);
496 } else {
497 ret->code = kadm5_create_principal_3(handle, &arg->rec, arg->mask,
498 arg->n_ks_tuple, arg->ks_tuple,
499 arg->passwd);
500 if (ret->code != 0)
501 errmsg = krb5_get_error_message(handle->context, ret->code);
502
503 log_done("kadm5_create_principal", prime_arg, errmsg,
504 &client_name, &service_name, rqstp);
505
506 if (errmsg != NULL)
507 krb5_free_error_message(handle->context, errmsg);
508 }
509
510 exit_func:
511 stub_cleanup(handle, prime_arg, &client_name, &service_name);
512 return TRUE;
513 }
514
515 /* Return KADM5_PROTECT_KEYS if KRB5_KDB_LOCKDOWN_KEYS is set for princ. */
516 static kadm5_ret_t
check_lockdown_keys(kadm5_server_handle_t handle,krb5_principal princ)517 check_lockdown_keys(kadm5_server_handle_t handle, krb5_principal princ)
518 {
519 kadm5_principal_ent_rec rec;
520 kadm5_ret_t ret;
521
522 ret = kadm5_get_principal(handle, princ, &rec, KADM5_ATTRIBUTES);
523 if (ret)
524 return ret;
525 ret = (rec.attributes & KRB5_KDB_LOCKDOWN_KEYS) ? KADM5_PROTECT_KEYS : 0;
526 kadm5_free_principal_ent(handle, &rec);
527 return ret;
528 }
529
530 bool_t
delete_principal_2_svc(dprinc_arg * arg,generic_ret * ret,struct svc_req * rqstp)531 delete_principal_2_svc(dprinc_arg *arg, generic_ret *ret,
532 struct svc_req *rqstp)
533 {
534 char *prime_arg = NULL;
535 gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
536 gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
537 kadm5_server_handle_t handle;
538 const char *errmsg = NULL;
539
540 ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
541 &ret->api_version, &client_name, &service_name,
542 &prime_arg);
543 if (ret->code)
544 goto exit_func;
545
546 if (CHANGEPW_SERVICE(rqstp) ||
547 !stub_auth(handle, OP_DELPRINC, arg->princ, NULL, NULL, NULL)) {
548 ret->code = KADM5_AUTH_DELETE;
549 log_unauth("kadm5_delete_principal", prime_arg,
550 &client_name, &service_name, rqstp);
551 } else {
552 ret->code = check_lockdown_keys(handle, arg->princ);
553 if (ret->code == KADM5_PROTECT_KEYS) {
554 log_unauth("kadm5_delete_principal", prime_arg, &client_name,
555 &service_name, rqstp);
556 ret->code = KADM5_AUTH_DELETE;
557 }
558 }
559
560 if (ret->code == KADM5_OK)
561 ret->code = kadm5_delete_principal(handle, arg->princ);
562 if (ret->code != KADM5_AUTH_DELETE) {
563 if (ret->code != 0)
564 errmsg = krb5_get_error_message(handle->context, ret->code);
565
566 log_done("kadm5_delete_principal", prime_arg, errmsg,
567 &client_name, &service_name, rqstp);
568
569 if (errmsg != NULL)
570 krb5_free_error_message(handle->context, errmsg);
571
572 }
573
574 exit_func:
575 stub_cleanup(handle, prime_arg, &client_name, &service_name);
576 return TRUE;
577 }
578
579 bool_t
modify_principal_2_svc(mprinc_arg * arg,generic_ret * ret,struct svc_req * rqstp)580 modify_principal_2_svc(mprinc_arg *arg, generic_ret *ret,
581 struct svc_req *rqstp)
582 {
583 char *prime_arg = NULL;
584 gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
585 gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
586 kadm5_server_handle_t handle;
587 const char *errmsg = NULL;
588
589 ret->code = stub_setup(arg->api_version, rqstp, arg->rec.principal,
590 &handle, &ret->api_version, &client_name,
591 &service_name, &prime_arg);
592 if (ret->code)
593 goto exit_func;
594
595 if (CHANGEPW_SERVICE(rqstp) ||
596 !stub_auth_restrict(handle, OP_MODPRINC, &arg->rec, &arg->mask)) {
597 ret->code = KADM5_AUTH_MODIFY;
598 log_unauth("kadm5_modify_principal", prime_arg,
599 &client_name, &service_name, rqstp);
600 } else if ((arg->mask & KADM5_ATTRIBUTES) &&
601 (!(arg->rec.attributes & KRB5_KDB_LOCKDOWN_KEYS))) {
602 ret->code = check_lockdown_keys(handle, arg->rec.principal);
603 if (ret->code == KADM5_PROTECT_KEYS) {
604 log_unauth("kadm5_modify_principal", prime_arg, &client_name,
605 &service_name, rqstp);
606 ret->code = KADM5_AUTH_MODIFY;
607 }
608 }
609
610 if (ret->code == KADM5_OK) {
611 ret->code = kadm5_modify_principal(handle, &arg->rec, arg->mask);
612 if (ret->code != 0)
613 errmsg = krb5_get_error_message(handle->context, ret->code);
614
615 log_done("kadm5_modify_principal", prime_arg, errmsg,
616 &client_name, &service_name, rqstp);
617
618 if (errmsg != NULL)
619 krb5_free_error_message(handle->context, errmsg);
620 }
621
622 exit_func:
623 stub_cleanup(handle, prime_arg, &client_name, &service_name);
624 return TRUE;
625 }
626
627 bool_t
rename_principal_2_svc(rprinc_arg * arg,generic_ret * ret,struct svc_req * rqstp)628 rename_principal_2_svc(rprinc_arg *arg, generic_ret *ret,
629 struct svc_req *rqstp)
630 {
631 char *prime_arg1 = NULL, *prime_arg2 = NULL;
632 gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
633 gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
634 kadm5_server_handle_t handle;
635 const char *errmsg = NULL;
636 size_t tlen1, tlen2, clen, slen;
637 char *tdots1, *tdots2, *cdots, *sdots;
638
639 ret->code = stub_setup(arg->api_version, rqstp, NULL, &handle,
640 &ret->api_version, &client_name, &service_name,
641 NULL);
642 if (ret->code)
643 goto exit_func;
644
645 if (krb5_unparse_name(handle->context, arg->src, &prime_arg1) ||
646 krb5_unparse_name(handle->context, arg->dest, &prime_arg2)) {
647 ret->code = KADM5_BAD_PRINCIPAL;
648 goto exit_func;
649 }
650 tlen1 = strlen(prime_arg1);
651 trunc_name(&tlen1, &tdots1);
652 tlen2 = strlen(prime_arg2);
653 trunc_name(&tlen2, &tdots2);
654 clen = client_name.length;
655 trunc_name(&clen, &cdots);
656 slen = service_name.length;
657 trunc_name(&slen, &sdots);
658
659 if (CHANGEPW_SERVICE(rqstp) ||
660 !stub_auth(handle, OP_RENPRINC, arg->src, arg->dest, NULL, NULL)) {
661 ret->code = KADM5_AUTH_INSUFFICIENT;
662 log_unauth("kadm5_rename_principal", prime_arg1, &client_name,
663 &service_name, rqstp);
664 } else {
665 ret->code = check_lockdown_keys(handle, arg->src);
666 if (ret->code == KADM5_PROTECT_KEYS) {
667 log_unauth("kadm5_rename_principal", prime_arg1, &client_name,
668 &service_name, rqstp);
669 ret->code = KADM5_AUTH_DELETE;
670 }
671 }
672 if (ret->code != KADM5_OK) {
673 /* okay to cast lengths to int because trunc_name limits max value */
674 krb5_klog_syslog(LOG_NOTICE,
675 _("Unauthorized request: kadm5_rename_principal, "
676 "%.*s%s to %.*s%s, "
677 "client=%.*s%s, service=%.*s%s, addr=%s"),
678 (int)tlen1, prime_arg1, tdots1,
679 (int)tlen2, prime_arg2, tdots2,
680 (int)clen, (char *)client_name.value, cdots,
681 (int)slen, (char *)service_name.value, sdots,
682 client_addr(rqstp->rq_xprt));
683 } else {
684 ret->code = kadm5_rename_principal(handle, arg->src, arg->dest);
685 if (ret->code != 0)
686 errmsg = krb5_get_error_message(handle->context, ret->code);
687
688 /* okay to cast lengths to int because trunc_name limits max value */
689 krb5_klog_syslog(LOG_NOTICE,
690 _("Request: kadm5_rename_principal, "
691 "%.*s%s to %.*s%s, %s, "
692 "client=%.*s%s, service=%.*s%s, addr=%s"),
693 (int)tlen1, prime_arg1, tdots1,
694 (int)tlen2, prime_arg2, tdots2,
695 errmsg ? errmsg : _("success"),
696 (int)clen, (char *)client_name.value, cdots,
697 (int)slen, (char *)service_name.value, sdots,
698 client_addr(rqstp->rq_xprt));
699
700 if (errmsg != NULL)
701 krb5_free_error_message(handle->context, errmsg);
702
703 }
704 exit_func:
705 free(prime_arg1);
706 free(prime_arg2);
707 stub_cleanup(handle, NULL, &client_name, &service_name);
708 return TRUE;
709 }
710
711 bool_t
get_principal_2_svc(gprinc_arg * arg,gprinc_ret * ret,struct svc_req * rqstp)712 get_principal_2_svc(gprinc_arg *arg, gprinc_ret *ret, struct svc_req *rqstp)
713 {
714 char *funcname, *prime_arg = NULL;
715 gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
716 gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
717 kadm5_server_handle_t handle;
718 const char *errmsg = NULL;
719
720 ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
721 &ret->api_version, &client_name, &service_name,
722 &prime_arg);
723 if (ret->code)
724 goto exit_func;
725
726 funcname = "kadm5_get_principal";
727
728 if (changepw_not_self(handle, rqstp, arg->princ) ||
729 !stub_auth(handle, OP_GETPRINC, arg->princ, NULL, NULL, NULL)) {
730 ret->code = KADM5_AUTH_GET;
731 log_unauth(funcname, prime_arg,
732 &client_name, &service_name, rqstp);
733 } else {
734 ret->code = kadm5_get_principal(handle, arg->princ, &ret->rec,
735 arg->mask);
736
737 if (ret->code != 0)
738 errmsg = krb5_get_error_message(handle->context, ret->code);
739
740 log_done(funcname, prime_arg, errmsg,
741 &client_name, &service_name, rqstp);
742
743 if (errmsg != NULL)
744 krb5_free_error_message(handle->context, errmsg);
745 }
746
747 exit_func:
748 stub_cleanup(handle, prime_arg, &client_name, &service_name);
749 return TRUE;
750 }
751
752 bool_t
get_princs_2_svc(gprincs_arg * arg,gprincs_ret * ret,struct svc_req * rqstp)753 get_princs_2_svc(gprincs_arg *arg, gprincs_ret *ret, struct svc_req *rqstp)
754 {
755 char *prime_arg = NULL;
756 gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
757 gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
758 kadm5_server_handle_t handle;
759 const char *errmsg = NULL;
760
761 ret->code = stub_setup(arg->api_version, rqstp, NULL, &handle,
762 &ret->api_version, &client_name, &service_name,
763 NULL);
764 if (ret->code)
765 goto exit_func;
766
767 prime_arg = arg->exp;
768 if (prime_arg == NULL)
769 prime_arg = "*";
770
771 if (CHANGEPW_SERVICE(rqstp) ||
772 !stub_auth(handle, OP_LISTPRINCS, NULL, NULL, NULL, NULL)) {
773 ret->code = KADM5_AUTH_LIST;
774 log_unauth("kadm5_get_principals", prime_arg,
775 &client_name, &service_name, rqstp);
776 } else {
777 ret->code = kadm5_get_principals(handle, arg->exp, &ret->princs,
778 &ret->count);
779 if (ret->code != 0)
780 errmsg = krb5_get_error_message(handle->context, ret->code);
781
782 log_done("kadm5_get_principals", prime_arg, errmsg,
783 &client_name, &service_name, rqstp);
784
785 if (errmsg != NULL)
786 krb5_free_error_message(handle->context, errmsg);
787
788 }
789
790 exit_func:
791 stub_cleanup(handle, NULL, &client_name, &service_name);
792 return TRUE;
793 }
794
795 bool_t
chpass_principal_2_svc(chpass_arg * arg,generic_ret * ret,struct svc_req * rqstp)796 chpass_principal_2_svc(chpass_arg *arg, generic_ret *ret,
797 struct svc_req *rqstp)
798 {
799 char *prime_arg = NULL;
800 gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
801 gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
802 kadm5_server_handle_t handle;
803 const char *errmsg = NULL;
804
805 ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
806 &ret->api_version, &client_name, &service_name,
807 &prime_arg);
808 if (ret->code)
809 goto exit_func;
810
811 ret->code = check_lockdown_keys(handle, arg->princ);
812 if (ret->code != KADM5_OK) {
813 if (ret->code == KADM5_PROTECT_KEYS) {
814 log_unauth("kadm5_chpass_principal", prime_arg, &client_name,
815 &service_name, rqstp);
816 ret->code = KADM5_AUTH_CHANGEPW;
817 }
818 } else if (changepw_not_self(handle, rqstp, arg->princ) ||
819 !stub_auth(handle, OP_CPW, arg->princ, NULL, NULL, NULL)) {
820 ret->code = KADM5_AUTH_CHANGEPW;
821 log_unauth("kadm5_chpass_principal", prime_arg,
822 &client_name, &service_name, rqstp);
823 } else {
824 ret->code = check_self_keychange(handle, rqstp, arg->princ);
825 if (!ret->code)
826 ret->code = kadm5_chpass_principal(handle, arg->princ, arg->pass);
827 }
828
829 if (ret->code != KADM5_AUTH_CHANGEPW) {
830 if (ret->code != 0)
831 errmsg = krb5_get_error_message(handle->context, ret->code);
832
833 log_done("kadm5_chpass_principal", prime_arg, errmsg,
834 &client_name, &service_name, rqstp);
835
836 if (errmsg != NULL)
837 krb5_free_error_message(handle->context, errmsg);
838 }
839
840 exit_func:
841 stub_cleanup(handle, prime_arg, &client_name, &service_name);
842 return TRUE;
843 }
844
845 bool_t
chpass_principal3_2_svc(chpass3_arg * arg,generic_ret * ret,struct svc_req * rqstp)846 chpass_principal3_2_svc(chpass3_arg *arg, generic_ret *ret,
847 struct svc_req *rqstp)
848 {
849 char *prime_arg = NULL;
850 gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
851 gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
852 kadm5_server_handle_t handle;
853 const char *errmsg = NULL;
854
855 ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
856 &ret->api_version, &client_name, &service_name,
857 &prime_arg);
858 if (ret->code)
859 goto exit_func;
860
861 ret->code = check_lockdown_keys(handle, arg->princ);
862 if (ret->code != KADM5_OK) {
863 if (ret->code == KADM5_PROTECT_KEYS) {
864 log_unauth("kadm5_chpass_principal", prime_arg, &client_name,
865 &service_name, rqstp);
866 ret->code = KADM5_AUTH_CHANGEPW;
867 }
868 } else if (changepw_not_self(handle, rqstp, arg->princ) ||
869 !stub_auth(handle, OP_CPW, arg->princ, NULL, NULL, NULL)) {
870 ret->code = KADM5_AUTH_CHANGEPW;
871 log_unauth("kadm5_chpass_principal", prime_arg,
872 &client_name, &service_name, rqstp);
873 } else {
874 ret->code = check_self_keychange(handle, rqstp, arg->princ);
875 if (!ret->code) {
876 ret->code = kadm5_chpass_principal_3(handle, arg->princ,
877 arg->keepold, arg->n_ks_tuple,
878 arg->ks_tuple, arg->pass);
879 }
880 }
881
882 if (ret->code != KADM5_AUTH_CHANGEPW) {
883 if (ret->code != 0)
884 errmsg = krb5_get_error_message(handle->context, ret->code);
885
886 log_done("kadm5_chpass_principal", prime_arg, errmsg,
887 &client_name, &service_name, rqstp);
888
889 if (errmsg != NULL)
890 krb5_free_error_message(handle->context, errmsg);
891 }
892
893 exit_func:
894 stub_cleanup(handle, prime_arg, &client_name, &service_name);
895 return TRUE;
896 }
897
898 bool_t
setkey_principal_2_svc(setkey_arg * arg,generic_ret * ret,struct svc_req * rqstp)899 setkey_principal_2_svc(setkey_arg *arg, generic_ret *ret,
900 struct svc_req *rqstp)
901 {
902 char *prime_arg = NULL;
903 gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
904 gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
905 kadm5_server_handle_t handle;
906 const char *errmsg = NULL;
907
908 ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
909 &ret->api_version, &client_name, &service_name,
910 &prime_arg);
911 if (ret->code)
912 goto exit_func;
913
914 ret->code = check_lockdown_keys(handle, arg->princ);
915 if (ret->code != KADM5_OK) {
916 if (ret->code == KADM5_PROTECT_KEYS) {
917 log_unauth("kadm5_setkey_principal", prime_arg, &client_name,
918 &service_name, rqstp);
919 ret->code = KADM5_AUTH_SETKEY;
920 }
921 } else if (!(CHANGEPW_SERVICE(rqstp)) &&
922 stub_auth(handle, OP_SETKEY, arg->princ, NULL, NULL, NULL)) {
923 ret->code = kadm5_setkey_principal(handle, arg->princ, arg->keyblocks,
924 arg->n_keys);
925 } else {
926 log_unauth("kadm5_setkey_principal", prime_arg,
927 &client_name, &service_name, rqstp);
928 ret->code = KADM5_AUTH_SETKEY;
929 }
930
931 if (ret->code != KADM5_AUTH_SETKEY) {
932 if (ret->code != 0)
933 errmsg = krb5_get_error_message(handle->context, ret->code);
934
935 log_done("kadm5_setkey_principal", prime_arg, errmsg,
936 &client_name, &service_name, rqstp);
937
938 if (errmsg != NULL)
939 krb5_free_error_message(handle->context, errmsg);
940 }
941
942 exit_func:
943 stub_cleanup(handle, prime_arg, &client_name, &service_name);
944 return TRUE;
945 }
946
947 bool_t
setkey_principal3_2_svc(setkey3_arg * arg,generic_ret * ret,struct svc_req * rqstp)948 setkey_principal3_2_svc(setkey3_arg *arg, generic_ret *ret,
949 struct svc_req *rqstp)
950 {
951 char *prime_arg = NULL;
952 gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
953 gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
954 kadm5_server_handle_t handle;
955 const char *errmsg = NULL;
956
957 ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
958 &ret->api_version, &client_name, &service_name,
959 &prime_arg);
960 if (ret->code)
961 goto exit_func;
962
963 ret->code = check_lockdown_keys(handle, arg->princ);
964 if (ret->code != KADM5_OK) {
965 if (ret->code == KADM5_PROTECT_KEYS) {
966 log_unauth("kadm5_setkey_principal", prime_arg, &client_name,
967 &service_name, rqstp);
968 ret->code = KADM5_AUTH_SETKEY;
969 }
970 } else if (!(CHANGEPW_SERVICE(rqstp)) &&
971 stub_auth(handle, OP_SETKEY, arg->princ, NULL, NULL, NULL)) {
972 ret->code = kadm5_setkey_principal_3(handle, arg->princ, arg->keepold,
973 arg->n_ks_tuple, arg->ks_tuple,
974 arg->keyblocks, arg->n_keys);
975 } else {
976 log_unauth("kadm5_setkey_principal", prime_arg,
977 &client_name, &service_name, rqstp);
978 ret->code = KADM5_AUTH_SETKEY;
979 }
980
981 if (ret->code != KADM5_AUTH_SETKEY) {
982 if (ret->code != 0)
983 errmsg = krb5_get_error_message(handle->context, ret->code);
984
985 log_done("kadm5_setkey_principal", prime_arg, errmsg,
986 &client_name, &service_name, rqstp);
987
988 if (errmsg != NULL)
989 krb5_free_error_message(handle->context, errmsg);
990 }
991
992 exit_func:
993 stub_cleanup(handle, prime_arg, &client_name, &service_name);
994 return TRUE;
995 }
996
997 bool_t
setkey_principal4_2_svc(setkey4_arg * arg,generic_ret * ret,struct svc_req * rqstp)998 setkey_principal4_2_svc(setkey4_arg *arg, generic_ret *ret,
999 struct svc_req *rqstp)
1000 {
1001 char *prime_arg = NULL;
1002 gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
1003 gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
1004 kadm5_server_handle_t handle;
1005 const char *errmsg = NULL;
1006
1007 ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
1008 &ret->api_version, &client_name, &service_name,
1009 &prime_arg);
1010 if (ret->code)
1011 goto exit_func;
1012
1013 ret->code = check_lockdown_keys(handle, arg->princ);
1014 if (ret->code != KADM5_OK) {
1015 if (ret->code == KADM5_PROTECT_KEYS) {
1016 log_unauth("kadm5_setkey_principal", prime_arg, &client_name,
1017 &service_name, rqstp);
1018 ret->code = KADM5_AUTH_SETKEY;
1019 }
1020 } else if (!(CHANGEPW_SERVICE(rqstp)) &&
1021 stub_auth(handle, OP_SETKEY, arg->princ, NULL, NULL, NULL)) {
1022 ret->code = kadm5_setkey_principal_4(handle, arg->princ, arg->keepold,
1023 arg->key_data, arg->n_key_data);
1024 } else {
1025 log_unauth("kadm5_setkey_principal", prime_arg, &client_name,
1026 &service_name, rqstp);
1027 ret->code = KADM5_AUTH_SETKEY;
1028 }
1029
1030 if (ret->code != KADM5_AUTH_SETKEY) {
1031 if (ret->code != 0)
1032 errmsg = krb5_get_error_message(handle->context, ret->code);
1033
1034 log_done("kadm5_setkey_principal", prime_arg, errmsg, &client_name,
1035 &service_name, rqstp);
1036
1037 if (errmsg != NULL)
1038 krb5_free_error_message(handle->context, errmsg);
1039 }
1040
1041 exit_func:
1042 stub_cleanup(handle, prime_arg, &client_name, &service_name);
1043 return TRUE;
1044 }
1045
1046 /* Empty out *keys / *nkeys if princ is protected with the lockdown
1047 * attribute, or if we fail to check. */
1048 static kadm5_ret_t
chrand_check_lockdown(kadm5_server_handle_t handle,krb5_principal princ,krb5_keyblock ** keys,int * nkeys)1049 chrand_check_lockdown(kadm5_server_handle_t handle, krb5_principal princ,
1050 krb5_keyblock **keys, int *nkeys)
1051 {
1052 kadm5_ret_t ret;
1053 int i;
1054
1055 ret = check_lockdown_keys(handle, princ);
1056 if (!ret)
1057 return 0;
1058
1059 for (i = 0; i < *nkeys; i++)
1060 krb5_free_keyblock_contents(handle->context, &((*keys)[i]));
1061 free(*keys);
1062 *keys = NULL;
1063 *nkeys = 0;
1064 return (ret == KADM5_PROTECT_KEYS) ? KADM5_OK : ret;
1065 }
1066
1067 bool_t
chrand_principal_2_svc(chrand_arg * arg,chrand_ret * ret,struct svc_req * rqstp)1068 chrand_principal_2_svc(chrand_arg *arg, chrand_ret *ret, struct svc_req *rqstp)
1069 {
1070 char *funcname, *prime_arg = NULL;
1071 gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
1072 gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
1073 krb5_keyblock *k;
1074 int nkeys;
1075 kadm5_server_handle_t handle;
1076 const char *errmsg = NULL;
1077
1078 ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
1079 &ret->api_version, &client_name, &service_name,
1080 &prime_arg);
1081 if (ret->code)
1082 goto exit_func;
1083
1084 funcname = "kadm5_randkey_principal";
1085
1086 if (changepw_not_self(handle, rqstp, arg->princ) ||
1087 !stub_auth(handle, OP_CHRAND, arg->princ, NULL, NULL, NULL)) {
1088 ret->code = KADM5_AUTH_CHANGEPW;
1089 log_unauth(funcname, prime_arg,
1090 &client_name, &service_name, rqstp);
1091 } else {
1092 ret->code = check_self_keychange(handle, rqstp, arg->princ);
1093 if (!ret->code) {
1094 ret->code = kadm5_randkey_principal(handle, arg->princ,
1095 &k, &nkeys);
1096 }
1097 }
1098
1099 if (ret->code == KADM5_OK) {
1100 ret->code = chrand_check_lockdown(handle, arg->princ, &k, &nkeys);
1101 if (ret->code == KADM5_PROTECT_KEYS)
1102 ret->code = KADM5_OK;
1103 ret->keys = k;
1104 ret->n_keys = nkeys;
1105 }
1106
1107 if (ret->code != KADM5_AUTH_CHANGEPW) {
1108 if (ret->code != 0)
1109 errmsg = krb5_get_error_message(handle->context, ret->code);
1110
1111 log_done(funcname, prime_arg, errmsg,
1112 &client_name, &service_name, rqstp);
1113
1114 if (errmsg != NULL)
1115 krb5_free_error_message(handle->context, errmsg);
1116 }
1117
1118 exit_func:
1119 stub_cleanup(handle, prime_arg, &client_name, &service_name);
1120 return TRUE;
1121 }
1122
1123 bool_t
chrand_principal3_2_svc(chrand3_arg * arg,chrand_ret * ret,struct svc_req * rqstp)1124 chrand_principal3_2_svc(chrand3_arg *arg, chrand_ret *ret,
1125 struct svc_req *rqstp)
1126 {
1127 char *funcname, *prime_arg = NULL;
1128 gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
1129 gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
1130 krb5_keyblock *k;
1131 int nkeys;
1132 kadm5_server_handle_t handle;
1133 const char *errmsg = NULL;
1134
1135 ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
1136 &ret->api_version, &client_name, &service_name,
1137 &prime_arg);
1138 if (ret->code)
1139 goto exit_func;
1140
1141 funcname = "kadm5_randkey_principal";
1142
1143 if (changepw_not_self(handle, rqstp, arg->princ) ||
1144 !stub_auth(handle, OP_CHRAND, arg->princ, NULL, NULL, NULL)) {
1145 ret->code = KADM5_AUTH_CHANGEPW;
1146 log_unauth(funcname, prime_arg,
1147 &client_name, &service_name, rqstp);
1148 } else {
1149 ret->code = check_self_keychange(handle, rqstp, arg->princ);
1150 if (!ret->code) {
1151 ret->code = kadm5_randkey_principal_3(handle, arg->princ,
1152 arg->keepold,
1153 arg->n_ks_tuple,
1154 arg->ks_tuple, &k, &nkeys);
1155 }
1156 }
1157
1158 if (ret->code == KADM5_OK) {
1159 ret->code = chrand_check_lockdown(handle, arg->princ, &k, &nkeys);
1160 if (ret->code == KADM5_PROTECT_KEYS)
1161 ret->code = KADM5_OK;
1162 ret->keys = k;
1163 ret->n_keys = nkeys;
1164 }
1165
1166 if (ret->code != KADM5_AUTH_CHANGEPW) {
1167 if (ret->code != 0)
1168 errmsg = krb5_get_error_message(handle->context, ret->code);
1169
1170 log_done(funcname, prime_arg, errmsg,
1171 &client_name, &service_name, rqstp);
1172
1173 if (errmsg != NULL)
1174 krb5_free_error_message(handle->context, errmsg);
1175 }
1176
1177 exit_func:
1178 stub_cleanup(handle, prime_arg, &client_name, &service_name);
1179 return TRUE;
1180 }
1181
1182 bool_t
create_policy_2_svc(cpol_arg * arg,generic_ret * ret,struct svc_req * rqstp)1183 create_policy_2_svc(cpol_arg *arg, generic_ret *ret, struct svc_req *rqstp)
1184 {
1185 char *prime_arg = NULL;
1186 gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
1187 gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
1188 kadm5_server_handle_t handle;
1189 const char *errmsg = NULL;
1190
1191 ret->code = stub_setup(arg->api_version, rqstp, NULL, &handle,
1192 &ret->api_version, &client_name, &service_name,
1193 NULL);
1194 if (ret->code)
1195 goto exit_func;
1196
1197 prime_arg = arg->rec.policy;
1198
1199 if (CHANGEPW_SERVICE(rqstp) ||
1200 !stub_auth_pol(handle, OP_ADDPOL, arg->rec.policy,
1201 &arg->rec, arg->mask)) {
1202 ret->code = KADM5_AUTH_ADD;
1203 log_unauth("kadm5_create_policy", prime_arg,
1204 &client_name, &service_name, rqstp);
1205
1206 } else {
1207 ret->code = kadm5_create_policy(handle, &arg->rec, arg->mask);
1208 if (ret->code != 0)
1209 errmsg = krb5_get_error_message(handle->context, ret->code);
1210
1211 log_done("kadm5_create_policy",
1212 ((prime_arg == NULL) ? "(null)" : prime_arg), errmsg,
1213 &client_name, &service_name, rqstp);
1214
1215 if (errmsg != NULL)
1216 krb5_free_error_message(handle->context, errmsg);
1217 }
1218
1219 exit_func:
1220 stub_cleanup(handle, NULL, &client_name, &service_name);
1221 return TRUE;
1222 }
1223
1224 bool_t
delete_policy_2_svc(dpol_arg * arg,generic_ret * ret,struct svc_req * rqstp)1225 delete_policy_2_svc(dpol_arg *arg, generic_ret *ret, struct svc_req *rqstp)
1226 {
1227 char *prime_arg = NULL;
1228 gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
1229 gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
1230 kadm5_server_handle_t handle;
1231 const char *errmsg = NULL;
1232
1233 ret->code = stub_setup(arg->api_version, rqstp, NULL, &handle,
1234 &ret->api_version, &client_name, &service_name,
1235 NULL);
1236 if (ret->code)
1237 goto exit_func;
1238
1239 prime_arg = arg->name;
1240
1241 if (CHANGEPW_SERVICE(rqstp) ||
1242 !stub_auth(handle, OP_DELPOL, NULL, NULL, arg->name, NULL)) {
1243 log_unauth("kadm5_delete_policy", prime_arg,
1244 &client_name, &service_name, rqstp);
1245 ret->code = KADM5_AUTH_DELETE;
1246 } else {
1247 ret->code = kadm5_delete_policy(handle, arg->name);
1248 if (ret->code != 0)
1249 errmsg = krb5_get_error_message(handle->context, ret->code);
1250
1251 log_done("kadm5_delete_policy",
1252 ((prime_arg == NULL) ? "(null)" : prime_arg), errmsg,
1253 &client_name, &service_name, rqstp);
1254
1255 if (errmsg != NULL)
1256 krb5_free_error_message(handle->context, errmsg);
1257 }
1258
1259 exit_func:
1260 stub_cleanup(handle, NULL, &client_name, &service_name);
1261 return TRUE;
1262 }
1263
1264 bool_t
modify_policy_2_svc(mpol_arg * arg,generic_ret * ret,struct svc_req * rqstp)1265 modify_policy_2_svc(mpol_arg *arg, generic_ret *ret, struct svc_req *rqstp)
1266 {
1267 char *prime_arg = NULL;
1268 gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
1269 gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
1270 kadm5_server_handle_t handle;
1271 const char *errmsg = NULL;
1272
1273 ret->code = stub_setup(arg->api_version, rqstp, NULL, &handle,
1274 &ret->api_version, &client_name, &service_name,
1275 NULL);
1276 if (ret->code)
1277 goto exit_func;
1278
1279 prime_arg = arg->rec.policy;
1280
1281 if (CHANGEPW_SERVICE(rqstp) ||
1282 !stub_auth_pol(handle, OP_MODPOL, arg->rec.policy,
1283 &arg->rec, arg->mask)) {
1284 log_unauth("kadm5_modify_policy", prime_arg,
1285 &client_name, &service_name, rqstp);
1286 ret->code = KADM5_AUTH_MODIFY;
1287 } else {
1288 ret->code = kadm5_modify_policy(handle, &arg->rec, arg->mask);
1289 if (ret->code != 0)
1290 errmsg = krb5_get_error_message(handle->context, ret->code);
1291
1292 log_done("kadm5_modify_policy",
1293 ((prime_arg == NULL) ? "(null)" : prime_arg), errmsg,
1294 &client_name, &service_name, rqstp);
1295
1296 if (errmsg != NULL)
1297 krb5_free_error_message(handle->context, errmsg);
1298 }
1299
1300 exit_func:
1301 stub_cleanup(handle, NULL, &client_name, &service_name);
1302 return TRUE;
1303 }
1304
1305 bool_t
get_policy_2_svc(gpol_arg * arg,gpol_ret * ret,struct svc_req * rqstp)1306 get_policy_2_svc(gpol_arg *arg, gpol_ret *ret, struct svc_req *rqstp)
1307 {
1308 char *funcname, *prime_arg = NULL;
1309 gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
1310 gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
1311 kadm5_ret_t ret2;
1312 kadm5_principal_ent_rec caller_ent;
1313 kadm5_server_handle_t handle;
1314 const char *errmsg = NULL, *cpolicy = NULL;
1315
1316 memset(&caller_ent, 0, sizeof(caller_ent));
1317
1318 ret->code = stub_setup(arg->api_version, rqstp, NULL, &handle,
1319 &ret->api_version, &client_name, &service_name,
1320 NULL);
1321 if (ret->code)
1322 goto exit_func;
1323
1324 funcname = "kadm5_get_policy";
1325
1326 prime_arg = arg->name;
1327
1328 /* Look up the client principal's policy value. */
1329 ret2 = kadm5_get_principal(handle->lhandle, handle->current_caller,
1330 &caller_ent, KADM5_PRINCIPAL_NORMAL_MASK);
1331 if (ret2 == KADM5_OK && (caller_ent.aux_attributes & KADM5_POLICY))
1332 cpolicy = caller_ent.policy;
1333
1334 ret->code = KADM5_AUTH_GET;
1335 if ((CHANGEPW_SERVICE(rqstp) &&
1336 (cpolicy == NULL || strcmp(cpolicy, arg->name) != 0)) ||
1337 !stub_auth(handle, OP_GETPOL, NULL, NULL, arg->name, cpolicy)) {
1338 ret->code = KADM5_AUTH_GET;
1339 log_unauth(funcname, prime_arg, &client_name, &service_name, rqstp);
1340 } else {
1341 ret->code = kadm5_get_policy(handle, arg->name, &ret->rec);
1342 if (ret->code != 0)
1343 errmsg = krb5_get_error_message(handle->context, ret->code);
1344
1345 log_done(funcname,
1346 ((prime_arg == NULL) ? "(null)" : prime_arg), errmsg,
1347 &client_name, &service_name, rqstp);
1348 if (errmsg != NULL)
1349 krb5_free_error_message(handle->context, errmsg);
1350 }
1351
1352 exit_func:
1353 (void)kadm5_free_principal_ent(handle->lhandle, &caller_ent);
1354 stub_cleanup(handle, NULL, &client_name, &service_name);
1355 return TRUE;
1356 }
1357
1358 bool_t
get_pols_2_svc(gpols_arg * arg,gpols_ret * ret,struct svc_req * rqstp)1359 get_pols_2_svc(gpols_arg *arg, gpols_ret *ret, struct svc_req *rqstp)
1360 {
1361 char *prime_arg = NULL;
1362 gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
1363 gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
1364 kadm5_server_handle_t handle;
1365 const char *errmsg = NULL;
1366
1367 ret->code = stub_setup(arg->api_version, rqstp, NULL, &handle,
1368 &ret->api_version, &client_name, &service_name,
1369 NULL);
1370 if (ret->code)
1371 goto exit_func;
1372
1373 prime_arg = arg->exp;
1374 if (prime_arg == NULL)
1375 prime_arg = "*";
1376
1377 if (CHANGEPW_SERVICE(rqstp) ||
1378 !stub_auth(handle, OP_LISTPOLS, NULL, NULL, NULL, NULL)) {
1379 ret->code = KADM5_AUTH_LIST;
1380 log_unauth("kadm5_get_policies", prime_arg,
1381 &client_name, &service_name, rqstp);
1382 } else {
1383 ret->code = kadm5_get_policies(handle, arg->exp, &ret->pols,
1384 &ret->count);
1385 if (ret->code != 0)
1386 errmsg = krb5_get_error_message(handle->context, ret->code);
1387
1388 log_done("kadm5_get_policies", prime_arg, errmsg,
1389 &client_name, &service_name, rqstp);
1390
1391 if (errmsg != NULL)
1392 krb5_free_error_message(handle->context, errmsg);
1393 }
1394
1395 exit_func:
1396 stub_cleanup(handle, NULL, &client_name, &service_name);
1397 return TRUE;
1398 }
1399
1400 bool_t
get_privs_2_svc(krb5_ui_4 * arg,getprivs_ret * ret,struct svc_req * rqstp)1401 get_privs_2_svc(krb5_ui_4 *arg, getprivs_ret *ret, struct svc_req *rqstp)
1402 {
1403 gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
1404 gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
1405 kadm5_server_handle_t handle;
1406 const char *errmsg = NULL;
1407
1408 ret->code = stub_setup(*arg, rqstp, NULL, &handle, &ret->api_version,
1409 &client_name, &service_name, NULL);
1410 if (ret->code)
1411 goto exit_func;
1412
1413 ret->code = kadm5_get_privs(handle, &ret->privs);
1414 if (ret->code != 0)
1415 errmsg = krb5_get_error_message(handle->context, ret->code);
1416
1417 log_done("kadm5_get_privs", client_name.value, errmsg,
1418 &client_name, &service_name, rqstp);
1419
1420 if (errmsg != NULL)
1421 krb5_free_error_message(handle->context, errmsg);
1422
1423 exit_func:
1424 stub_cleanup(handle, NULL, &client_name, &service_name);
1425 return TRUE;
1426 }
1427
1428 bool_t
purgekeys_2_svc(purgekeys_arg * arg,generic_ret * ret,struct svc_req * rqstp)1429 purgekeys_2_svc(purgekeys_arg *arg, generic_ret *ret, struct svc_req *rqstp)
1430 {
1431 char *funcname, *prime_arg = NULL;
1432 gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
1433 gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
1434 kadm5_server_handle_t handle;
1435
1436 const char *errmsg = NULL;
1437
1438 ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
1439 &ret->api_version, &client_name, &service_name,
1440 &prime_arg);
1441 if (ret->code)
1442 goto exit_func;
1443
1444 funcname = "kadm5_purgekeys";
1445
1446 if (CHANGEPW_SERVICE(rqstp) ||
1447 !stub_auth(handle, OP_PURGEKEYS, arg->princ, NULL, NULL, NULL)) {
1448 ret->code = KADM5_AUTH_MODIFY;
1449 log_unauth(funcname, prime_arg, &client_name, &service_name, rqstp);
1450 } else {
1451 ret->code = kadm5_purgekeys(handle, arg->princ, arg->keepkvno);
1452 if (ret->code != 0)
1453 errmsg = krb5_get_error_message(handle->context, ret->code);
1454
1455 log_done(funcname, prime_arg, errmsg,
1456 &client_name, &service_name, rqstp);
1457
1458 if (errmsg != NULL)
1459 krb5_free_error_message(handle->context, errmsg);
1460 }
1461
1462 exit_func:
1463 stub_cleanup(handle, prime_arg, &client_name, &service_name);
1464 return TRUE;
1465 }
1466
1467 bool_t
get_strings_2_svc(gstrings_arg * arg,gstrings_ret * ret,struct svc_req * rqstp)1468 get_strings_2_svc(gstrings_arg *arg, gstrings_ret *ret, struct svc_req *rqstp)
1469 {
1470 char *prime_arg = NULL;
1471 gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
1472 gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
1473 kadm5_server_handle_t handle;
1474 const char *errmsg = NULL;
1475
1476 ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
1477 &ret->api_version, &client_name, &service_name,
1478 &prime_arg);
1479 if (ret->code)
1480 goto exit_func;
1481
1482 if (CHANGEPW_SERVICE(rqstp) ||
1483 !stub_auth(handle, OP_GETSTRS, arg->princ, NULL, NULL, NULL)) {
1484 ret->code = KADM5_AUTH_GET;
1485 log_unauth("kadm5_get_strings", prime_arg,
1486 &client_name, &service_name, rqstp);
1487 } else {
1488 ret->code = kadm5_get_strings(handle, arg->princ, &ret->strings,
1489 &ret->count);
1490 if (ret->code != 0)
1491 errmsg = krb5_get_error_message(handle->context, ret->code);
1492
1493 log_done("kadm5_get_strings", prime_arg, errmsg,
1494 &client_name, &service_name, rqstp);
1495
1496 if (errmsg != NULL)
1497 krb5_free_error_message(handle->context, errmsg);
1498 }
1499
1500 exit_func:
1501 stub_cleanup(handle, prime_arg, &client_name, &service_name);
1502 return TRUE;
1503 }
1504
1505 bool_t
set_string_2_svc(sstring_arg * arg,generic_ret * ret,struct svc_req * rqstp)1506 set_string_2_svc(sstring_arg *arg, generic_ret *ret, struct svc_req *rqstp)
1507 {
1508 char *prime_arg = NULL;
1509 gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
1510 gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
1511 kadm5_server_handle_t handle;
1512 const char *errmsg = NULL;
1513
1514 ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
1515 &ret->api_version, &client_name, &service_name,
1516 &prime_arg);
1517 if (ret->code)
1518 goto exit_func;
1519
1520 if (CHANGEPW_SERVICE(rqstp) ||
1521 !stub_auth(handle, OP_SETSTR, arg->princ, NULL,
1522 arg->key, arg->value)) {
1523 ret->code = KADM5_AUTH_MODIFY;
1524 log_unauth("kadm5_mod_strings", prime_arg,
1525 &client_name, &service_name, rqstp);
1526 } else {
1527 ret->code = kadm5_set_string(handle, arg->princ, arg->key, arg->value);
1528 if (ret->code != 0)
1529 errmsg = krb5_get_error_message(handle->context, ret->code);
1530
1531 log_done("kadm5_mod_strings", prime_arg, errmsg,
1532 &client_name, &service_name, rqstp);
1533
1534 if (errmsg != NULL)
1535 krb5_free_error_message(handle->context, errmsg);
1536 }
1537
1538 exit_func:
1539 stub_cleanup(handle, prime_arg, &client_name, &service_name);
1540 return TRUE;
1541 }
1542
1543 bool_t
init_2_svc(krb5_ui_4 * arg,generic_ret * ret,struct svc_req * rqstp)1544 init_2_svc(krb5_ui_4 *arg, generic_ret *ret, struct svc_req *rqstp)
1545 {
1546 gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
1547 gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
1548 kadm5_server_handle_t handle;
1549 const char *errmsg = NULL;
1550 size_t clen, slen;
1551 char *cdots, *sdots;
1552
1553 ret->code = stub_setup(*arg, rqstp, NULL, &handle, &ret->api_version,
1554 &client_name, &service_name, NULL);
1555 if (ret->code)
1556 goto exit_func;
1557
1558 if (ret->code != 0)
1559 errmsg = krb5_get_error_message(handle->context, ret->code);
1560
1561 clen = client_name.length;
1562 trunc_name(&clen, &cdots);
1563 slen = service_name.length;
1564 trunc_name(&slen, &sdots);
1565 /* okay to cast lengths to int because trunc_name limits max value */
1566 krb5_klog_syslog(LOG_NOTICE, _("Request: kadm5_init, %.*s%s, %s, "
1567 "client=%.*s%s, service=%.*s%s, addr=%s, "
1568 "vers=%d, flavor=%d"),
1569 (int)clen, (char *)client_name.value, cdots,
1570 errmsg ? errmsg : _("success"),
1571 (int)clen, (char *)client_name.value, cdots,
1572 (int)slen, (char *)service_name.value, sdots,
1573 client_addr(rqstp->rq_xprt),
1574 ret->api_version & ~(KADM5_API_VERSION_MASK),
1575 rqstp->rq_cred.oa_flavor);
1576 if (errmsg != NULL)
1577 krb5_free_error_message(handle->context, errmsg);
1578
1579 exit_func:
1580 stub_cleanup(handle, NULL, &client_name, &service_name);
1581 return TRUE;
1582 }
1583
1584 gss_name_t
rqst2name(struct svc_req * rqstp)1585 rqst2name(struct svc_req *rqstp)
1586 {
1587
1588 if (rqstp->rq_cred.oa_flavor == RPCSEC_GSS)
1589 return rqstp->rq_clntname;
1590 else
1591 return rqstp->rq_clntcred;
1592 }
1593
1594 bool_t
get_principal_keys_2_svc(getpkeys_arg * arg,getpkeys_ret * ret,struct svc_req * rqstp)1595 get_principal_keys_2_svc(getpkeys_arg *arg, getpkeys_ret *ret,
1596 struct svc_req *rqstp)
1597 {
1598 char *prime_arg = NULL;
1599 gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
1600 gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
1601 kadm5_server_handle_t handle;
1602 const char *errmsg = NULL;
1603
1604 ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
1605 &ret->api_version, &client_name, &service_name,
1606 &prime_arg);
1607 if (ret->code)
1608 goto exit_func;
1609
1610 if (!(CHANGEPW_SERVICE(rqstp)) &&
1611 stub_auth(handle, OP_EXTRACT, arg->princ, NULL, NULL, NULL)) {
1612 ret->code = kadm5_get_principal_keys(handle, arg->princ, arg->kvno,
1613 &ret->key_data, &ret->n_key_data);
1614 } else {
1615 log_unauth("kadm5_get_principal_keys", prime_arg,
1616 &client_name, &service_name, rqstp);
1617 ret->code = KADM5_AUTH_EXTRACT;
1618 }
1619
1620 if (ret->code == KADM5_OK) {
1621 ret->code = check_lockdown_keys(handle, arg->princ);
1622 if (ret->code != KADM5_OK) {
1623 kadm5_free_kadm5_key_data(handle->context, ret->n_key_data,
1624 ret->key_data);
1625 ret->key_data = NULL;
1626 ret->n_key_data = 0;
1627 }
1628 if (ret->code == KADM5_PROTECT_KEYS) {
1629 log_unauth("kadm5_get_principal_keys", prime_arg,
1630 &client_name, &service_name, rqstp);
1631 ret->code = KADM5_AUTH_EXTRACT;
1632 }
1633 }
1634
1635 if (ret->code != KADM5_AUTH_EXTRACT) {
1636 if (ret->code != 0)
1637 errmsg = krb5_get_error_message(handle->context, ret->code);
1638
1639 log_done("kadm5_get_principal_keys", prime_arg, errmsg,
1640 &client_name, &service_name, rqstp);
1641
1642 if (errmsg != NULL)
1643 krb5_free_error_message(handle->context, errmsg);
1644 }
1645
1646 exit_func:
1647 stub_cleanup(handle, prime_arg, &client_name, &service_name);
1648 return TRUE;
1649 }
1650