86c162590e4bdfed44ab14bfbb5e38f36ecb8b81
[platform/upstream/krb5.git] / src / kadmin / server / server_stubs.c
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-platform.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 <kadm5/server_acl.h>
16 #include <syslog.h>
17 #include <adm_proto.h>  /* krb5_klog_syslog */
18 #include "misc.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
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 */
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
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
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  */
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 *
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  */
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
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
219 static int cmp_gss_krb5_name(kadm5_server_handle_t handle,
220                              gss_name_t gss_name, krb5_principal princ)
221 {
222     krb5_principal princ2;
223     int status;
224
225     if (! gss_to_krb5_name(handle, gss_name, &princ2))
226         return 0;
227     status = krb5_principal_compare(handle->context, princ, princ2);
228     krb5_free_principal(handle->context, princ2);
229     return status;
230 }
231
232 static int gss_to_krb5_name(kadm5_server_handle_t handle,
233                             gss_name_t gss_name, krb5_principal *princ)
234 {
235     OM_uint32 minor_stat;
236     gss_buffer_desc gss_str;
237     int success;
238     char *s;
239
240     if (gss_name_to_string(gss_name, &gss_str) != 0)
241         return 0;
242     if (asprintf(&s, "%.*s", (int)gss_str.length, (char *)gss_str.value) < 0) {
243         gss_release_buffer(&minor_stat, &gss_str);
244         return 0;
245     }
246     success = (krb5_parse_name(handle->context, s, princ) == 0);
247     free(s);
248     gss_release_buffer(&minor_stat, &gss_str);
249     return success;
250 }
251
252 static int
253 gss_name_to_string(gss_name_t gss_name, gss_buffer_desc *str)
254 {
255     OM_uint32 status, minor_stat;
256     gss_OID gss_type;
257     const char pref[] = KRB5_WELLKNOWN_NAMESTR "/" KRB5_ANONYMOUS_PRINCSTR "@";
258     const size_t preflen = sizeof(pref) - 1;
259
260     status = gss_display_name(&minor_stat, gss_name, str, &gss_type);
261     if (status != GSS_S_COMPLETE)
262         return 1;
263     if (gss_oid_equal(gss_type, GSS_C_NT_ANONYMOUS)) {
264         /* Guard against non-krb5 mechs with different anonymous displays. */
265         if (str->length < preflen || memcmp(str->value, pref, preflen) != 0)
266             return 1;
267     } else if (!gss_oid_equal(gss_type, GSS_KRB5_NT_PRINCIPAL_NAME)) {
268         return 1;
269     }
270     return 0;
271 }
272
273 /*
274  * Perform common initialization for server stub functions.  A subset of the
275  * output arguments may be set on failure; the caller is responsible for
276  * initializing outputs and calling stub_cleanup() on success or failure.
277  * princ and princ_str_out may be NULL to omit unparsing a principal name.
278  */
279 static kadm5_ret_t
280 stub_setup(krb5_ui_4 api_version, struct svc_req *rqstp, krb5_principal princ,
281            kadm5_server_handle_t *handle_out, krb5_ui_4 *api_version_out,
282            gss_buffer_t client_name_out, gss_buffer_t service_name_out,
283            char **princ_str_out)
284 {
285     kadm5_ret_t ret;
286
287     ret = new_server_handle(api_version, rqstp, handle_out);
288     if (ret)
289         return ret;
290
291     ret = check_handle(*handle_out);
292     if (ret)
293         return ret;
294
295     *api_version_out = (*handle_out)->api_version;
296
297     if (setup_gss_names(rqstp, client_name_out, service_name_out) < 0)
298         return KADM5_FAILURE;
299
300     if (princ_str_out != NULL) {
301         if (princ == NULL)
302             return KADM5_BAD_PRINCIPAL;
303         if (krb5_unparse_name((*handle_out)->context, princ, princ_str_out))
304             return KADM5_BAD_PRINCIPAL;
305     }
306
307     return KADM5_OK;
308 }
309
310 /* Perform common cleanup for server stub functions. */
311 static void
312 stub_cleanup(kadm5_server_handle_t handle, char *princ_str,
313              gss_buffer_t client_name, gss_buffer_t service_name)
314 {
315     OM_uint32 minor_stat;
316
317     free_server_handle(handle);
318     free(princ_str);
319     gss_release_buffer(&minor_stat, client_name);
320     gss_release_buffer(&minor_stat, service_name);
321 }
322
323 static int
324 log_unauth(
325     char *op,
326     char *target,
327     gss_buffer_t client,
328     gss_buffer_t server,
329     struct svc_req *rqstp)
330 {
331     size_t tlen, clen, slen;
332     char *tdots, *cdots, *sdots;
333
334     tlen = strlen(target);
335     trunc_name(&tlen, &tdots);
336     clen = client->length;
337     trunc_name(&clen, &cdots);
338     slen = server->length;
339     trunc_name(&slen, &sdots);
340
341     /* okay to cast lengths to int because trunc_name limits max value */
342     return krb5_klog_syslog(LOG_NOTICE,
343                             _("Unauthorized request: %s, %.*s%s, "
344                               "client=%.*s%s, service=%.*s%s, addr=%s"),
345                             op, (int)tlen, target, tdots,
346                             (int)clen, (char *)client->value, cdots,
347                             (int)slen, (char *)server->value, sdots,
348                             client_addr(rqstp->rq_xprt));
349 }
350
351 static int
352 log_done(
353     char *op,
354     char *target,
355     const char *errmsg,
356     gss_buffer_t client,
357     gss_buffer_t server,
358     struct svc_req *rqstp)
359 {
360     size_t tlen, clen, slen;
361     char *tdots, *cdots, *sdots;
362
363     if (errmsg == NULL)
364         errmsg = _("success");
365     tlen = strlen(target);
366     trunc_name(&tlen, &tdots);
367     clen = client->length;
368     trunc_name(&clen, &cdots);
369     slen = server->length;
370     trunc_name(&slen, &sdots);
371
372     /* okay to cast lengths to int because trunc_name limits max value */
373     return krb5_klog_syslog(LOG_NOTICE,
374                             _("Request: %s, %.*s%s, %s, "
375                               "client=%.*s%s, service=%.*s%s, addr=%s"),
376                             op, (int)tlen, target, tdots, errmsg,
377                             (int)clen, (char *)client->value, cdots,
378                             (int)slen, (char *)server->value, sdots,
379                             client_addr(rqstp->rq_xprt));
380 }
381
382 bool_t
383 create_principal_2_svc(cprinc_arg *arg, generic_ret *ret,
384                        struct svc_req *rqstp)
385 {
386     char                        *prime_arg = NULL;
387     gss_buffer_desc             client_name = GSS_C_EMPTY_BUFFER;
388     gss_buffer_desc             service_name = GSS_C_EMPTY_BUFFER;
389     kadm5_server_handle_t       handle;
390     restriction_t               *rp;
391     const char                  *errmsg = NULL;
392
393     ret->code = stub_setup(arg->api_version, rqstp, arg->rec.principal,
394                            &handle, &ret->api_version, &client_name,
395                            &service_name, &prime_arg);
396     if (ret->code)
397         goto exit_func;
398
399     if (CHANGEPW_SERVICE(rqstp)
400         || !kadm5int_acl_check(handle->context, rqst2name(rqstp), ACL_ADD,
401                                arg->rec.principal, &rp)
402         || kadm5int_acl_impose_restrictions(handle->context,
403                                             &arg->rec, &arg->mask, rp)) {
404         ret->code = KADM5_AUTH_ADD;
405         log_unauth("kadm5_create_principal", prime_arg,
406                    &client_name, &service_name, rqstp);
407     } else {
408         ret->code = kadm5_create_principal(handle, &arg->rec, arg->mask,
409                                            arg->passwd);
410
411         if (ret->code != 0)
412             errmsg = krb5_get_error_message(handle->context, ret->code);
413
414         log_done("kadm5_create_principal", prime_arg, errmsg,
415                  &client_name, &service_name, rqstp);
416
417         if (errmsg != NULL)
418             krb5_free_error_message(handle->context, errmsg);
419     }
420
421 exit_func:
422     stub_cleanup(handle, prime_arg, &client_name, &service_name);
423     return TRUE;
424 }
425
426 bool_t
427 create_principal3_2_svc(cprinc3_arg *arg, generic_ret *ret,
428                         struct svc_req *rqstp)
429 {
430     char                        *prime_arg = NULL;
431     gss_buffer_desc             client_name = GSS_C_EMPTY_BUFFER;
432     gss_buffer_desc             service_name = GSS_C_EMPTY_BUFFER;
433     kadm5_server_handle_t       handle;
434     restriction_t               *rp;
435     const char                  *errmsg = NULL;
436
437     ret->code = stub_setup(arg->api_version, rqstp, arg->rec.principal,
438                            &handle, &ret->api_version, &client_name,
439                            &service_name, &prime_arg);
440     if (ret->code)
441         goto exit_func;
442
443     if (CHANGEPW_SERVICE(rqstp)
444         || !kadm5int_acl_check(handle->context, rqst2name(rqstp), ACL_ADD,
445                                arg->rec.principal, &rp)
446         || kadm5int_acl_impose_restrictions(handle->context,
447                                             &arg->rec, &arg->mask, rp)) {
448         ret->code = KADM5_AUTH_ADD;
449         log_unauth("kadm5_create_principal", prime_arg,
450                    &client_name, &service_name, rqstp);
451     } else {
452         ret->code = kadm5_create_principal_3(handle, &arg->rec, arg->mask,
453                                              arg->n_ks_tuple, arg->ks_tuple,
454                                              arg->passwd);
455         if (ret->code != 0)
456             errmsg = krb5_get_error_message(handle->context, ret->code);
457
458         log_done("kadm5_create_principal", prime_arg, errmsg,
459                  &client_name, &service_name, rqstp);
460
461         if (errmsg != NULL)
462             krb5_free_error_message(handle->context, errmsg);
463     }
464
465 exit_func:
466     stub_cleanup(handle, prime_arg, &client_name, &service_name);
467     return TRUE;
468 }
469
470 /* Return KADM5_PROTECT_KEYS if KRB5_KDB_LOCKDOWN_KEYS is set for princ. */
471 static kadm5_ret_t
472 check_lockdown_keys(kadm5_server_handle_t handle, krb5_principal princ)
473 {
474     kadm5_principal_ent_rec rec;
475     kadm5_ret_t ret;
476
477     ret = kadm5_get_principal(handle, princ, &rec, KADM5_ATTRIBUTES);
478     if (ret)
479         return ret;
480     ret = (rec.attributes & KRB5_KDB_LOCKDOWN_KEYS) ? KADM5_PROTECT_KEYS : 0;
481     kadm5_free_principal_ent(handle, &rec);
482     return ret;
483 }
484
485 bool_t
486 delete_principal_2_svc(dprinc_arg *arg, generic_ret *ret,
487                        struct svc_req *rqstp)
488 {
489     char                            *prime_arg = NULL;
490     gss_buffer_desc                 client_name = GSS_C_EMPTY_BUFFER;
491     gss_buffer_desc                 service_name = GSS_C_EMPTY_BUFFER;
492     kadm5_server_handle_t           handle;
493     const char                      *errmsg = NULL;
494
495     ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
496                            &ret->api_version, &client_name, &service_name,
497                            &prime_arg);
498     if (ret->code)
499         goto exit_func;
500
501     if (CHANGEPW_SERVICE(rqstp)
502         || !kadm5int_acl_check(handle->context, rqst2name(rqstp), ACL_DELETE,
503                                arg->princ, NULL)) {
504         ret->code = KADM5_AUTH_DELETE;
505         log_unauth("kadm5_delete_principal", prime_arg,
506                    &client_name, &service_name, rqstp);
507     } else {
508         ret->code = check_lockdown_keys(handle, arg->princ);
509         if (ret->code == KADM5_PROTECT_KEYS) {
510             log_unauth("kadm5_delete_principal", prime_arg, &client_name,
511                        &service_name, rqstp);
512             ret->code = KADM5_AUTH_DELETE;
513         }
514     }
515
516     if (ret->code == KADM5_OK)
517         ret->code = kadm5_delete_principal(handle, arg->princ);
518     if (ret->code != KADM5_AUTH_DELETE) {
519         if (ret->code != 0)
520             errmsg = krb5_get_error_message(handle->context, ret->code);
521
522         log_done("kadm5_delete_principal", prime_arg, errmsg,
523                  &client_name, &service_name, rqstp);
524
525         if (errmsg != NULL)
526             krb5_free_error_message(handle->context, errmsg);
527
528     }
529
530 exit_func:
531     stub_cleanup(handle, prime_arg, &client_name, &service_name);
532     return TRUE;
533 }
534
535 bool_t
536 modify_principal_2_svc(mprinc_arg *arg, generic_ret *ret,
537                        struct svc_req *rqstp)
538 {
539     char                            *prime_arg = NULL;
540     gss_buffer_desc                 client_name = GSS_C_EMPTY_BUFFER;
541     gss_buffer_desc                 service_name = GSS_C_EMPTY_BUFFER;
542     kadm5_server_handle_t           handle;
543     restriction_t                   *rp;
544     const char                      *errmsg = NULL;
545
546     ret->code = stub_setup(arg->api_version, rqstp, arg->rec.principal,
547                            &handle, &ret->api_version, &client_name,
548                            &service_name, &prime_arg);
549     if (ret->code)
550         goto exit_func;
551
552     if (CHANGEPW_SERVICE(rqstp)
553         || !kadm5int_acl_check(handle->context, rqst2name(rqstp), ACL_MODIFY,
554                                arg->rec.principal, &rp)
555         || kadm5int_acl_impose_restrictions(handle->context,
556                                             &arg->rec, &arg->mask, rp)) {
557         ret->code = KADM5_AUTH_MODIFY;
558         log_unauth("kadm5_modify_principal", prime_arg,
559                    &client_name, &service_name, rqstp);
560     } else if ((arg->mask & KADM5_ATTRIBUTES) &&
561                (!(arg->rec.attributes & KRB5_KDB_LOCKDOWN_KEYS))) {
562         ret->code = check_lockdown_keys(handle, arg->rec.principal);
563         if (ret->code == KADM5_PROTECT_KEYS) {
564             log_unauth("kadm5_modify_principal", prime_arg, &client_name,
565                        &service_name, rqstp);
566             ret->code = KADM5_AUTH_MODIFY;
567         }
568     }
569
570     if (ret->code == KADM5_OK) {
571         ret->code = kadm5_modify_principal(handle, &arg->rec, arg->mask);
572         if (ret->code != 0)
573             errmsg = krb5_get_error_message(handle->context, ret->code);
574
575         log_done("kadm5_modify_principal", prime_arg, errmsg,
576                  &client_name, &service_name, rqstp);
577
578         if (errmsg != NULL)
579             krb5_free_error_message(handle->context, errmsg);
580     }
581
582 exit_func:
583     stub_cleanup(handle, prime_arg, &client_name, &service_name);
584     return TRUE;
585 }
586
587 bool_t
588 rename_principal_2_svc(rprinc_arg *arg, generic_ret *ret,
589                        struct svc_req *rqstp)
590 {
591     char                        *prime_arg1 = NULL, *prime_arg2 = NULL;
592     gss_buffer_desc             client_name = GSS_C_EMPTY_BUFFER;
593     gss_buffer_desc             service_name = GSS_C_EMPTY_BUFFER;
594     kadm5_server_handle_t       handle;
595     restriction_t               *rp;
596     const char                  *errmsg = NULL;
597     size_t                      tlen1, tlen2, clen, slen;
598     char                        *tdots1, *tdots2, *cdots, *sdots;
599
600     ret->code = stub_setup(arg->api_version, rqstp, NULL, &handle,
601                            &ret->api_version, &client_name, &service_name,
602                            NULL);
603     if (ret->code)
604         goto exit_func;
605
606     if (krb5_unparse_name(handle->context, arg->src, &prime_arg1) ||
607         krb5_unparse_name(handle->context, arg->dest, &prime_arg2)) {
608         ret->code = KADM5_BAD_PRINCIPAL;
609         goto exit_func;
610     }
611     tlen1 = strlen(prime_arg1);
612     trunc_name(&tlen1, &tdots1);
613     tlen2 = strlen(prime_arg2);
614     trunc_name(&tlen2, &tdots2);
615     clen = client_name.length;
616     trunc_name(&clen, &cdots);
617     slen = service_name.length;
618     trunc_name(&slen, &sdots);
619
620     ret->code = KADM5_OK;
621     if (! CHANGEPW_SERVICE(rqstp)) {
622         if (!kadm5int_acl_check(handle->context, rqst2name(rqstp),
623                                 ACL_DELETE, arg->src, NULL))
624             ret->code = KADM5_AUTH_DELETE;
625         /* any restrictions at all on the ADD kills the RENAME */
626         if (!kadm5int_acl_check(handle->context, rqst2name(rqstp),
627                                 ACL_ADD, arg->dest, &rp) || rp) {
628             if (ret->code == KADM5_AUTH_DELETE)
629                 ret->code = KADM5_AUTH_INSUFFICIENT;
630             else
631                 ret->code = KADM5_AUTH_ADD;
632         }
633         if (ret->code == KADM5_OK) {
634             ret->code = check_lockdown_keys(handle, arg->src);
635             if (ret->code == KADM5_PROTECT_KEYS) {
636                 log_unauth("kadm5_rename_principal", prime_arg1, &client_name,
637                            &service_name, rqstp);
638                 ret->code = KADM5_AUTH_DELETE;
639             }
640         }
641     } else
642         ret->code = KADM5_AUTH_INSUFFICIENT;
643     if (ret->code != KADM5_OK) {
644         /* okay to cast lengths to int because trunc_name limits max value */
645         krb5_klog_syslog(LOG_NOTICE,
646                          _("Unauthorized request: kadm5_rename_principal, "
647                            "%.*s%s to %.*s%s, "
648                            "client=%.*s%s, service=%.*s%s, addr=%s"),
649                          (int)tlen1, prime_arg1, tdots1,
650                          (int)tlen2, prime_arg2, tdots2,
651                          (int)clen, (char *)client_name.value, cdots,
652                          (int)slen, (char *)service_name.value, sdots,
653                          client_addr(rqstp->rq_xprt));
654     } else {
655         ret->code = kadm5_rename_principal(handle, arg->src, arg->dest);
656         if (ret->code != 0)
657             errmsg = krb5_get_error_message(handle->context, ret->code);
658
659         /* okay to cast lengths to int because trunc_name limits max value */
660         krb5_klog_syslog(LOG_NOTICE,
661                          _("Request: kadm5_rename_principal, "
662                            "%.*s%s to %.*s%s, %s, "
663                            "client=%.*s%s, service=%.*s%s, addr=%s"),
664                          (int)tlen1, prime_arg1, tdots1,
665                          (int)tlen2, prime_arg2, tdots2,
666                          errmsg ? errmsg : _("success"),
667                          (int)clen, (char *)client_name.value, cdots,
668                          (int)slen, (char *)service_name.value, sdots,
669                          client_addr(rqstp->rq_xprt));
670
671         if (errmsg != NULL)
672             krb5_free_error_message(handle->context, errmsg);
673
674     }
675 exit_func:
676     free(prime_arg1);
677     free(prime_arg2);
678     stub_cleanup(handle, NULL, &client_name, &service_name);
679     return TRUE;
680 }
681
682 bool_t
683 get_principal_2_svc(gprinc_arg *arg, gprinc_ret *ret, struct svc_req *rqstp)
684 {
685     char                            *funcname, *prime_arg = NULL;
686     gss_buffer_desc                 client_name = GSS_C_EMPTY_BUFFER;
687     gss_buffer_desc                 service_name = GSS_C_EMPTY_BUFFER;
688     kadm5_server_handle_t           handle;
689     const char                      *errmsg = NULL;
690
691     ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
692                            &ret->api_version, &client_name, &service_name,
693                            &prime_arg);
694     if (ret->code)
695         goto exit_func;
696
697     funcname = "kadm5_get_principal";
698
699     if (! cmp_gss_krb5_name(handle, rqst2name(rqstp), arg->princ) &&
700         (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context,
701                                                         rqst2name(rqstp),
702                                                         ACL_INQUIRE,
703                                                         arg->princ,
704                                                         NULL))) {
705         ret->code = KADM5_AUTH_GET;
706         log_unauth(funcname, prime_arg,
707                    &client_name, &service_name, rqstp);
708     } else {
709         ret->code = kadm5_get_principal(handle, arg->princ, &ret->rec,
710                                         arg->mask);
711
712         if (ret->code != 0)
713             errmsg = krb5_get_error_message(handle->context, ret->code);
714
715         log_done(funcname, prime_arg, errmsg,
716                  &client_name, &service_name, rqstp);
717
718         if (errmsg != NULL)
719             krb5_free_error_message(handle->context, errmsg);
720     }
721
722 exit_func:
723     stub_cleanup(handle, prime_arg, &client_name, &service_name);
724     return TRUE;
725 }
726
727 bool_t
728 get_princs_2_svc(gprincs_arg *arg, gprincs_ret *ret, struct svc_req *rqstp)
729 {
730     char                            *prime_arg = NULL;
731     gss_buffer_desc                 client_name = GSS_C_EMPTY_BUFFER;
732     gss_buffer_desc                 service_name = GSS_C_EMPTY_BUFFER;
733     kadm5_server_handle_t           handle;
734     const char                      *errmsg = NULL;
735
736     ret->code = stub_setup(arg->api_version, rqstp, NULL, &handle,
737                            &ret->api_version, &client_name, &service_name,
738                            NULL);
739     if (ret->code)
740         goto exit_func;
741
742     prime_arg = arg->exp;
743     if (prime_arg == NULL)
744         prime_arg = "*";
745
746     if (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context,
747                                                        rqst2name(rqstp),
748                                                        ACL_LIST,
749                                                        NULL,
750                                                        NULL)) {
751         ret->code = KADM5_AUTH_LIST;
752         log_unauth("kadm5_get_principals", prime_arg,
753                    &client_name, &service_name, rqstp);
754     } else {
755         ret->code = kadm5_get_principals(handle, arg->exp, &ret->princs,
756                                          &ret->count);
757         if (ret->code != 0)
758             errmsg = krb5_get_error_message(handle->context, ret->code);
759
760         log_done("kadm5_get_principals", prime_arg, errmsg,
761                  &client_name, &service_name, rqstp);
762
763         if (errmsg != NULL)
764             krb5_free_error_message(handle->context, errmsg);
765
766     }
767
768 exit_func:
769     stub_cleanup(handle, NULL, &client_name, &service_name);
770     return TRUE;
771 }
772
773 bool_t
774 chpass_principal_2_svc(chpass_arg *arg, generic_ret *ret,
775                        struct svc_req *rqstp)
776 {
777     char                            *prime_arg = NULL;
778     gss_buffer_desc                 client_name = GSS_C_EMPTY_BUFFER;
779     gss_buffer_desc                 service_name = GSS_C_EMPTY_BUFFER;
780     kadm5_server_handle_t           handle;
781     const char                      *errmsg = NULL;
782
783     ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
784                            &ret->api_version, &client_name, &service_name,
785                            &prime_arg);
786     if (ret->code)
787         goto exit_func;
788
789     ret->code = check_lockdown_keys(handle, arg->princ);
790     if (ret->code != KADM5_OK) {
791         if (ret->code == KADM5_PROTECT_KEYS) {
792             log_unauth("kadm5_chpass_principal", prime_arg, &client_name,
793                        &service_name, rqstp);
794             ret->code = KADM5_AUTH_CHANGEPW;
795         }
796     } else if (cmp_gss_krb5_name(handle, rqst2name(rqstp), arg->princ)) {
797         ret->code = chpass_principal_wrapper_3(handle, arg->princ, FALSE, 0,
798                                                NULL, arg->pass);
799     } else if (!(CHANGEPW_SERVICE(rqstp)) &&
800                kadm5int_acl_check(handle->context, rqst2name(rqstp),
801                                   ACL_CHANGEPW, arg->princ, NULL)) {
802         ret->code = kadm5_chpass_principal(handle, arg->princ, arg->pass);
803     } else {
804         log_unauth("kadm5_chpass_principal", prime_arg,
805                    &client_name, &service_name, rqstp);
806         ret->code = KADM5_AUTH_CHANGEPW;
807     }
808
809     if (ret->code != KADM5_AUTH_CHANGEPW) {
810         if (ret->code != 0)
811             errmsg = krb5_get_error_message(handle->context, ret->code);
812
813         log_done("kadm5_chpass_principal", prime_arg, errmsg,
814                  &client_name, &service_name, rqstp);
815
816         if (errmsg != NULL)
817             krb5_free_error_message(handle->context, errmsg);
818     }
819
820 exit_func:
821     stub_cleanup(handle, prime_arg, &client_name, &service_name);
822     return TRUE;
823 }
824
825 bool_t
826 chpass_principal3_2_svc(chpass3_arg *arg, generic_ret *ret,
827                         struct svc_req *rqstp)
828 {
829     char                            *prime_arg = NULL;
830     gss_buffer_desc                 client_name = GSS_C_EMPTY_BUFFER;
831     gss_buffer_desc                 service_name = GSS_C_EMPTY_BUFFER;
832     kadm5_server_handle_t           handle;
833     const char                      *errmsg = NULL;
834
835     ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
836                            &ret->api_version, &client_name, &service_name,
837                            &prime_arg);
838     if (ret->code)
839         goto exit_func;
840
841     ret->code = check_lockdown_keys(handle, arg->princ);
842     if (ret->code != KADM5_OK) {
843         if (ret->code == KADM5_PROTECT_KEYS) {
844             log_unauth("kadm5_chpass_principal", prime_arg, &client_name,
845                        &service_name, rqstp);
846             ret->code = KADM5_AUTH_CHANGEPW;
847         }
848     } else if (cmp_gss_krb5_name(handle, rqst2name(rqstp), arg->princ)) {
849         ret->code = chpass_principal_wrapper_3(handle, arg->princ,
850                                                arg->keepold, arg->n_ks_tuple,
851                                                arg->ks_tuple, arg->pass);
852     } else if (!(CHANGEPW_SERVICE(rqstp)) &&
853                kadm5int_acl_check(handle->context, rqst2name(rqstp),
854                                   ACL_CHANGEPW, arg->princ, NULL)) {
855         ret->code = kadm5_chpass_principal_3(handle, arg->princ, arg->keepold,
856                                              arg->n_ks_tuple, arg->ks_tuple,
857                                              arg->pass);
858     } else {
859         log_unauth("kadm5_chpass_principal", prime_arg,
860                    &client_name, &service_name, rqstp);
861         ret->code = KADM5_AUTH_CHANGEPW;
862     }
863
864     if (ret->code != KADM5_AUTH_CHANGEPW) {
865         if (ret->code != 0)
866             errmsg = krb5_get_error_message(handle->context, ret->code);
867
868         log_done("kadm5_chpass_principal", prime_arg, errmsg,
869                  &client_name, &service_name, rqstp);
870
871         if (errmsg != NULL)
872             krb5_free_error_message(handle->context, errmsg);
873     }
874
875 exit_func:
876     stub_cleanup(handle, prime_arg, &client_name, &service_name);
877     return TRUE;
878 }
879
880 bool_t
881 setv4key_principal_2_svc(setv4key_arg *arg, generic_ret *ret,
882                          struct svc_req *rqstp)
883 {
884     char                            *prime_arg = NULL;
885     gss_buffer_desc                 client_name = GSS_C_EMPTY_BUFFER;
886     gss_buffer_desc                 service_name = GSS_C_EMPTY_BUFFER;
887     kadm5_server_handle_t           handle;
888     const char                      *errmsg = NULL;
889
890     ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
891                            &ret->api_version, &client_name, &service_name,
892                            &prime_arg);
893     if (ret->code)
894         goto exit_func;
895
896     ret->code = check_lockdown_keys(handle, arg->princ);
897     if (ret->code != KADM5_OK) {
898         if (ret->code == KADM5_PROTECT_KEYS) {
899             log_unauth("kadm5_setv4key_principal", prime_arg, &client_name,
900                        &service_name, rqstp);
901             ret->code = KADM5_AUTH_SETKEY;
902         }
903     } else if (!(CHANGEPW_SERVICE(rqstp)) &&
904         kadm5int_acl_check(handle->context, rqst2name(rqstp),
905                            ACL_SETKEY, arg->princ, NULL)) {
906         ret->code = kadm5_setv4key_principal(handle, arg->princ,
907                                              arg->keyblock);
908     } else {
909         log_unauth("kadm5_setv4key_principal", prime_arg,
910                    &client_name, &service_name, rqstp);
911         ret->code = KADM5_AUTH_SETKEY;
912     }
913
914     if (ret->code != KADM5_AUTH_SETKEY) {
915         if (ret->code != 0)
916             errmsg = krb5_get_error_message(handle->context, ret->code);
917
918         log_done("kadm5_setv4key_principal", prime_arg, errmsg,
919                  &client_name, &service_name, rqstp);
920
921         if (errmsg != NULL)
922             krb5_free_error_message(handle->context, errmsg);
923     }
924
925 exit_func:
926     stub_cleanup(handle, prime_arg, &client_name, &service_name);
927     return TRUE;
928 }
929
930
931 bool_t
932 setkey_principal_2_svc(setkey_arg *arg, generic_ret *ret,
933                        struct svc_req *rqstp)
934 {
935     char                            *prime_arg = NULL;
936     gss_buffer_desc                 client_name = GSS_C_EMPTY_BUFFER;
937     gss_buffer_desc                 service_name = GSS_C_EMPTY_BUFFER;
938     kadm5_server_handle_t           handle;
939     const char                      *errmsg = NULL;
940
941     ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
942                            &ret->api_version, &client_name, &service_name,
943                            &prime_arg);
944     if (ret->code)
945         goto exit_func;
946
947     ret->code = check_lockdown_keys(handle, arg->princ);
948     if (ret->code != KADM5_OK) {
949         if (ret->code == KADM5_PROTECT_KEYS) {
950             log_unauth("kadm5_setkey_principal", prime_arg, &client_name,
951                        &service_name, rqstp);
952             ret->code = KADM5_AUTH_SETKEY;
953         }
954     } else if (!(CHANGEPW_SERVICE(rqstp)) &&
955         kadm5int_acl_check(handle->context, rqst2name(rqstp),
956                            ACL_SETKEY, arg->princ, NULL)) {
957         ret->code = kadm5_setkey_principal(handle, arg->princ, arg->keyblocks,
958                                            arg->n_keys);
959     } else {
960         log_unauth("kadm5_setkey_principal", prime_arg,
961                    &client_name, &service_name, rqstp);
962         ret->code = KADM5_AUTH_SETKEY;
963     }
964
965     if (ret->code != KADM5_AUTH_SETKEY) {
966         if (ret->code != 0)
967             errmsg = krb5_get_error_message(handle->context, ret->code);
968
969         log_done("kadm5_setkey_principal", prime_arg, errmsg,
970                  &client_name, &service_name, rqstp);
971
972         if (errmsg != NULL)
973             krb5_free_error_message(handle->context, errmsg);
974     }
975
976 exit_func:
977     stub_cleanup(handle, prime_arg, &client_name, &service_name);
978     return TRUE;
979 }
980
981 bool_t
982 setkey_principal3_2_svc(setkey3_arg *arg, generic_ret *ret,
983                         struct svc_req *rqstp)
984 {
985     char                            *prime_arg = NULL;
986     gss_buffer_desc                 client_name = GSS_C_EMPTY_BUFFER;
987     gss_buffer_desc                 service_name = GSS_C_EMPTY_BUFFER;
988     kadm5_server_handle_t           handle;
989     const char                      *errmsg = NULL;
990
991     ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
992                            &ret->api_version, &client_name, &service_name,
993                            &prime_arg);
994     if (ret->code)
995         goto exit_func;
996
997     ret->code = check_lockdown_keys(handle, arg->princ);
998     if (ret->code != KADM5_OK) {
999         if (ret->code == KADM5_PROTECT_KEYS) {
1000             log_unauth("kadm5_setkey_principal", prime_arg, &client_name,
1001                        &service_name, rqstp);
1002             ret->code = KADM5_AUTH_SETKEY;
1003         }
1004     } else if (!(CHANGEPW_SERVICE(rqstp)) &&
1005         kadm5int_acl_check(handle->context, rqst2name(rqstp),
1006                            ACL_SETKEY, arg->princ, NULL)) {
1007         ret->code = kadm5_setkey_principal_3(handle, arg->princ, arg->keepold,
1008                                              arg->n_ks_tuple, arg->ks_tuple,
1009                                              arg->keyblocks, arg->n_keys);
1010     } else {
1011         log_unauth("kadm5_setkey_principal", prime_arg,
1012                    &client_name, &service_name, rqstp);
1013         ret->code = KADM5_AUTH_SETKEY;
1014     }
1015
1016     if (ret->code != KADM5_AUTH_SETKEY) {
1017         if (ret->code != 0)
1018             errmsg = krb5_get_error_message(handle->context, ret->code);
1019
1020         log_done("kadm5_setkey_principal", prime_arg, errmsg,
1021                  &client_name, &service_name, rqstp);
1022
1023         if (errmsg != NULL)
1024             krb5_free_error_message(handle->context, errmsg);
1025     }
1026
1027 exit_func:
1028     stub_cleanup(handle, prime_arg, &client_name, &service_name);
1029     return TRUE;
1030 }
1031
1032 bool_t
1033 setkey_principal4_2_svc(setkey4_arg *arg, generic_ret *ret,
1034                         struct svc_req *rqstp)
1035 {
1036     char                            *prime_arg = NULL;
1037     gss_buffer_desc                 client_name = GSS_C_EMPTY_BUFFER;
1038     gss_buffer_desc                 service_name = GSS_C_EMPTY_BUFFER;
1039     kadm5_server_handle_t           handle;
1040     const char                      *errmsg = NULL;
1041
1042     ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
1043                            &ret->api_version, &client_name, &service_name,
1044                            &prime_arg);
1045     if (ret->code)
1046         goto exit_func;
1047
1048     ret->code = check_lockdown_keys(handle, arg->princ);
1049     if (ret->code != KADM5_OK) {
1050         if (ret->code == KADM5_PROTECT_KEYS) {
1051             log_unauth("kadm5_setkey_principal", prime_arg, &client_name,
1052                        &service_name, rqstp);
1053             ret->code = KADM5_AUTH_SETKEY;
1054         }
1055     } else if (!(CHANGEPW_SERVICE(rqstp)) &&
1056         kadm5int_acl_check(handle->context, rqst2name(rqstp),
1057                            ACL_SETKEY, arg->princ, NULL)) {
1058         ret->code = kadm5_setkey_principal_4(handle, arg->princ, arg->keepold,
1059                                              arg->key_data, arg->n_key_data);
1060     } else {
1061         log_unauth("kadm5_setkey_principal", prime_arg, &client_name,
1062                    &service_name, rqstp);
1063         ret->code = KADM5_AUTH_SETKEY;
1064     }
1065
1066     if (ret->code != KADM5_AUTH_SETKEY) {
1067         if (ret->code != 0)
1068             errmsg = krb5_get_error_message(handle->context, ret->code);
1069
1070         log_done("kadm5_setkey_principal", prime_arg, errmsg, &client_name,
1071                  &service_name, rqstp);
1072
1073         if (errmsg != NULL)
1074             krb5_free_error_message(handle->context, errmsg);
1075     }
1076
1077 exit_func:
1078     stub_cleanup(handle, prime_arg, &client_name, &service_name);
1079     return TRUE;
1080 }
1081
1082 /* Empty out *keys/*nkeys if princ is protected with the lockdown attribute, or
1083  * if we fail to check. */
1084 static kadm5_ret_t
1085 chrand_check_lockdown(kadm5_server_handle_t handle, krb5_principal princ,
1086                       krb5_keyblock **keys, int *nkeys)
1087 {
1088     kadm5_ret_t ret;
1089     int i;
1090
1091     ret = check_lockdown_keys(handle, princ);
1092     if (!ret)
1093         return 0;
1094
1095     for (i = 0; i < *nkeys; i++)
1096         krb5_free_keyblock_contents(handle->context, &((*keys)[i]));
1097     free(*keys);
1098     *keys = NULL;
1099     *nkeys = 0;
1100     return (ret == KADM5_PROTECT_KEYS) ? KADM5_OK : ret;
1101 }
1102
1103 bool_t
1104 chrand_principal_2_svc(chrand_arg *arg, chrand_ret *ret, struct svc_req *rqstp)
1105 {
1106     char                        *funcname, *prime_arg = NULL;
1107     gss_buffer_desc             client_name = GSS_C_EMPTY_BUFFER;
1108     gss_buffer_desc             service_name = GSS_C_EMPTY_BUFFER;
1109     krb5_keyblock               *k;
1110     int                         nkeys;
1111     kadm5_server_handle_t       handle;
1112     const char                  *errmsg = NULL;
1113
1114     ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
1115                            &ret->api_version, &client_name, &service_name,
1116                            &prime_arg);
1117     if (ret->code)
1118         goto exit_func;
1119
1120     funcname = "kadm5_randkey_principal";
1121
1122     if (cmp_gss_krb5_name(handle, rqst2name(rqstp), arg->princ)) {
1123         ret->code = randkey_principal_wrapper_3(handle, arg->princ, FALSE, 0,
1124                                                 NULL, &k, &nkeys);
1125     } else if (!(CHANGEPW_SERVICE(rqstp)) &&
1126                kadm5int_acl_check(handle->context, rqst2name(rqstp),
1127                                   ACL_CHANGEPW, arg->princ, NULL)) {
1128         ret->code = kadm5_randkey_principal(handle, arg->princ, &k, &nkeys);
1129     } else {
1130         log_unauth(funcname, prime_arg,
1131                    &client_name, &service_name, rqstp);
1132         ret->code = KADM5_AUTH_CHANGEPW;
1133     }
1134
1135     if (ret->code == KADM5_OK) {
1136         ret->code = chrand_check_lockdown(handle, arg->princ, &k, &nkeys);
1137         if (ret->code == KADM5_PROTECT_KEYS)
1138             ret->code = KADM5_OK;
1139         ret->keys = k;
1140         ret->n_keys = nkeys;
1141     }
1142
1143     if (ret->code != KADM5_AUTH_CHANGEPW) {
1144         if (ret->code != 0)
1145             errmsg = krb5_get_error_message(handle->context, ret->code);
1146
1147         log_done(funcname, prime_arg, errmsg,
1148                  &client_name, &service_name, rqstp);
1149
1150         if (errmsg != NULL)
1151             krb5_free_error_message(handle->context, errmsg);
1152     }
1153
1154 exit_func:
1155     stub_cleanup(handle, prime_arg, &client_name, &service_name);
1156     return TRUE;
1157 }
1158
1159 bool_t
1160 chrand_principal3_2_svc(chrand3_arg *arg, chrand_ret *ret,
1161                         struct svc_req *rqstp)
1162 {
1163     char                        *funcname, *prime_arg = NULL;
1164     gss_buffer_desc             client_name = GSS_C_EMPTY_BUFFER;
1165     gss_buffer_desc             service_name = GSS_C_EMPTY_BUFFER;
1166     krb5_keyblock               *k;
1167     int                         nkeys;
1168     kadm5_server_handle_t       handle;
1169     const char                  *errmsg = NULL;
1170
1171     ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
1172                            &ret->api_version, &client_name, &service_name,
1173                            &prime_arg);
1174     if (ret->code)
1175         goto exit_func;
1176
1177     funcname = "kadm5_randkey_principal";
1178
1179     if (cmp_gss_krb5_name(handle, rqst2name(rqstp), arg->princ)) {
1180         ret->code = randkey_principal_wrapper_3(handle, arg->princ,
1181                                                 arg->keepold, arg->n_ks_tuple,
1182                                                 arg->ks_tuple, &k, &nkeys);
1183     } else if (!(CHANGEPW_SERVICE(rqstp)) &&
1184                kadm5int_acl_check(handle->context, rqst2name(rqstp),
1185                                   ACL_CHANGEPW, arg->princ, NULL)) {
1186         ret->code = kadm5_randkey_principal_3(handle, arg->princ, arg->keepold,
1187                                               arg->n_ks_tuple, arg->ks_tuple,
1188                                               &k, &nkeys);
1189     } else {
1190         log_unauth(funcname, prime_arg,
1191                    &client_name, &service_name, rqstp);
1192         ret->code = KADM5_AUTH_CHANGEPW;
1193     }
1194
1195     if (ret->code == KADM5_OK) {
1196         ret->code = chrand_check_lockdown(handle, arg->princ, &k, &nkeys);
1197         if (ret->code == KADM5_PROTECT_KEYS)
1198             ret->code = KADM5_OK;
1199         ret->keys = k;
1200         ret->n_keys = nkeys;
1201     }
1202
1203     if (ret->code != KADM5_AUTH_CHANGEPW) {
1204         if (ret->code != 0)
1205             errmsg = krb5_get_error_message(handle->context, ret->code);
1206
1207         log_done(funcname, prime_arg, errmsg,
1208                  &client_name, &service_name, rqstp);
1209
1210         if (errmsg != NULL)
1211             krb5_free_error_message(handle->context, errmsg);
1212     }
1213
1214 exit_func:
1215     stub_cleanup(handle, prime_arg, &client_name, &service_name);
1216     return TRUE;
1217 }
1218
1219 bool_t
1220 create_policy_2_svc(cpol_arg *arg, generic_ret *ret, struct svc_req *rqstp)
1221 {
1222     char                            *prime_arg = NULL;
1223     gss_buffer_desc                 client_name = GSS_C_EMPTY_BUFFER;
1224     gss_buffer_desc                 service_name = GSS_C_EMPTY_BUFFER;
1225     kadm5_server_handle_t           handle;
1226     const char                      *errmsg = NULL;
1227
1228     ret->code = stub_setup(arg->api_version, rqstp, NULL, &handle,
1229                            &ret->api_version, &client_name, &service_name,
1230                            NULL);
1231     if (ret->code)
1232         goto exit_func;
1233
1234     prime_arg = arg->rec.policy;
1235
1236     if (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context,
1237                                                        rqst2name(rqstp),
1238                                                        ACL_ADD, NULL, NULL)) {
1239         ret->code = KADM5_AUTH_ADD;
1240         log_unauth("kadm5_create_policy", prime_arg,
1241                    &client_name, &service_name, rqstp);
1242
1243     } else {
1244         ret->code = kadm5_create_policy(handle, &arg->rec, arg->mask);
1245         if (ret->code != 0)
1246             errmsg = krb5_get_error_message(handle->context, ret->code);
1247
1248         log_done("kadm5_create_policy",
1249                  ((prime_arg == NULL) ? "(null)" : prime_arg), errmsg,
1250                  &client_name, &service_name, rqstp);
1251
1252         if (errmsg != NULL)
1253             krb5_free_error_message(handle->context, errmsg);
1254     }
1255
1256 exit_func:
1257     stub_cleanup(handle, NULL, &client_name, &service_name);
1258     return TRUE;
1259 }
1260
1261 bool_t
1262 delete_policy_2_svc(dpol_arg *arg, generic_ret *ret, struct svc_req *rqstp)
1263 {
1264     char                            *prime_arg = NULL;
1265     gss_buffer_desc                 client_name = GSS_C_EMPTY_BUFFER;
1266     gss_buffer_desc                 service_name = GSS_C_EMPTY_BUFFER;
1267     kadm5_server_handle_t           handle;
1268     const char                      *errmsg = NULL;
1269
1270     ret->code = stub_setup(arg->api_version, rqstp, NULL, &handle,
1271                            &ret->api_version, &client_name, &service_name,
1272                            NULL);
1273     if (ret->code)
1274         goto exit_func;
1275
1276     prime_arg = arg->name;
1277
1278     if (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context,
1279                                                        rqst2name(rqstp),
1280                                                        ACL_DELETE, NULL, NULL)) {
1281         log_unauth("kadm5_delete_policy", prime_arg,
1282                    &client_name, &service_name, rqstp);
1283         ret->code = KADM5_AUTH_DELETE;
1284     } else {
1285         ret->code = kadm5_delete_policy(handle, arg->name);
1286         if (ret->code != 0)
1287             errmsg = krb5_get_error_message(handle->context, ret->code);
1288
1289         log_done("kadm5_delete_policy",
1290                  ((prime_arg == NULL) ? "(null)" : prime_arg), errmsg,
1291                  &client_name, &service_name, rqstp);
1292
1293         if (errmsg != NULL)
1294             krb5_free_error_message(handle->context, errmsg);
1295     }
1296
1297 exit_func:
1298     stub_cleanup(handle, NULL, &client_name, &service_name);
1299     return TRUE;
1300 }
1301
1302 bool_t
1303 modify_policy_2_svc(mpol_arg *arg, generic_ret *ret, struct svc_req *rqstp)
1304 {
1305     char                            *prime_arg = NULL;
1306     gss_buffer_desc                 client_name = GSS_C_EMPTY_BUFFER;
1307     gss_buffer_desc                 service_name = GSS_C_EMPTY_BUFFER;
1308     kadm5_server_handle_t           handle;
1309     const char                      *errmsg = NULL;
1310
1311     ret->code = stub_setup(arg->api_version, rqstp, NULL, &handle,
1312                            &ret->api_version, &client_name, &service_name,
1313                            NULL);
1314     if (ret->code)
1315         goto exit_func;
1316
1317     prime_arg = arg->rec.policy;
1318
1319     if (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context,
1320                                                        rqst2name(rqstp),
1321                                                        ACL_MODIFY, NULL, NULL)) {
1322         log_unauth("kadm5_modify_policy", prime_arg,
1323                    &client_name, &service_name, rqstp);
1324         ret->code = KADM5_AUTH_MODIFY;
1325     } else {
1326         ret->code = kadm5_modify_policy(handle, &arg->rec, arg->mask);
1327         if (ret->code != 0)
1328             errmsg = krb5_get_error_message(handle->context, ret->code);
1329
1330         log_done("kadm5_modify_policy",
1331                  ((prime_arg == NULL) ? "(null)" : prime_arg), errmsg,
1332                  &client_name, &service_name, rqstp);
1333
1334         if (errmsg != NULL)
1335             krb5_free_error_message(handle->context, errmsg);
1336     }
1337
1338 exit_func:
1339     stub_cleanup(handle, NULL, &client_name, &service_name);
1340     return TRUE;
1341 }
1342
1343 bool_t
1344 get_policy_2_svc(gpol_arg *arg, gpol_ret *ret, struct svc_req *rqstp)
1345 {
1346     char                        *funcname, *prime_arg = NULL;
1347     gss_buffer_desc             client_name = GSS_C_EMPTY_BUFFER;
1348     gss_buffer_desc             service_name = GSS_C_EMPTY_BUFFER;
1349     kadm5_ret_t         ret2;
1350     kadm5_principal_ent_rec     caller_ent;
1351     kadm5_server_handle_t       handle;
1352     const char                  *errmsg = NULL;
1353
1354     ret->code = stub_setup(arg->api_version, rqstp, NULL, &handle,
1355                            &ret->api_version, &client_name, &service_name,
1356                            NULL);
1357     if (ret->code)
1358         goto exit_func;
1359
1360     funcname = "kadm5_get_policy";
1361
1362     prime_arg = arg->name;
1363
1364     ret->code = KADM5_AUTH_GET;
1365     if (!CHANGEPW_SERVICE(rqstp) && kadm5int_acl_check(handle->context,
1366                                                        rqst2name(rqstp),
1367                                                        ACL_INQUIRE, NULL, NULL))
1368         ret->code = KADM5_OK;
1369     else {
1370         ret->code = kadm5_get_principal(handle->lhandle,
1371                                         handle->current_caller, &caller_ent,
1372                                         KADM5_PRINCIPAL_NORMAL_MASK);
1373         if (ret->code == KADM5_OK) {
1374             if (caller_ent.aux_attributes & KADM5_POLICY &&
1375                 strcmp(caller_ent.policy, arg->name) == 0) {
1376                 ret->code = KADM5_OK;
1377             } else {
1378                 ret->code = KADM5_AUTH_GET;
1379             }
1380             ret2 = kadm5_free_principal_ent(handle->lhandle,
1381                                             &caller_ent);
1382             ret->code = ret->code ? ret->code : ret2;
1383         }
1384     }
1385
1386     if (ret->code == KADM5_OK) {
1387         ret->code = kadm5_get_policy(handle, arg->name, &ret->rec);
1388
1389         if (ret->code != 0)
1390             errmsg = krb5_get_error_message(handle->context, ret->code);
1391
1392         log_done(funcname,
1393                  ((prime_arg == NULL) ? "(null)" : prime_arg), errmsg,
1394                  &client_name, &service_name, rqstp);
1395         if (errmsg != NULL)
1396             krb5_free_error_message(handle->context, errmsg);
1397
1398     } else {
1399         log_unauth(funcname, prime_arg,
1400                    &client_name, &service_name, rqstp);
1401     }
1402
1403 exit_func:
1404     stub_cleanup(handle, NULL, &client_name, &service_name);
1405     return TRUE;
1406 }
1407
1408 bool_t
1409 get_pols_2_svc(gpols_arg *arg, gpols_ret *ret, struct svc_req *rqstp)
1410 {
1411     char                            *prime_arg = NULL;
1412     gss_buffer_desc                 client_name = GSS_C_EMPTY_BUFFER;
1413     gss_buffer_desc                 service_name = GSS_C_EMPTY_BUFFER;
1414     kadm5_server_handle_t           handle;
1415     const char                      *errmsg = NULL;
1416
1417     ret->code = stub_setup(arg->api_version, rqstp, NULL, &handle,
1418                            &ret->api_version, &client_name, &service_name,
1419                            NULL);
1420     if (ret->code)
1421         goto exit_func;
1422
1423     prime_arg = arg->exp;
1424     if (prime_arg == NULL)
1425         prime_arg = "*";
1426
1427     if (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context,
1428                                                        rqst2name(rqstp),
1429                                                        ACL_LIST, NULL, NULL)) {
1430         ret->code = KADM5_AUTH_LIST;
1431         log_unauth("kadm5_get_policies", prime_arg,
1432                    &client_name, &service_name, rqstp);
1433     } else {
1434         ret->code = kadm5_get_policies(handle, arg->exp, &ret->pols,
1435                                        &ret->count);
1436         if (ret->code != 0)
1437             errmsg = krb5_get_error_message(handle->context, ret->code);
1438
1439         log_done("kadm5_get_policies", prime_arg, errmsg,
1440                  &client_name, &service_name, rqstp);
1441
1442         if (errmsg != NULL)
1443             krb5_free_error_message(handle->context, errmsg);
1444     }
1445
1446 exit_func:
1447     stub_cleanup(handle, NULL, &client_name, &service_name);
1448     return TRUE;
1449 }
1450
1451 bool_t
1452 get_privs_2_svc(krb5_ui_4 *arg, getprivs_ret *ret, struct svc_req *rqstp)
1453 {
1454     gss_buffer_desc                client_name = GSS_C_EMPTY_BUFFER;
1455     gss_buffer_desc                service_name = GSS_C_EMPTY_BUFFER;
1456     kadm5_server_handle_t          handle;
1457     const char                     *errmsg = NULL;
1458
1459     ret->code = stub_setup(*arg, rqstp, NULL, &handle, &ret->api_version,
1460                            &client_name, &service_name, NULL);
1461     if (ret->code)
1462         goto exit_func;
1463
1464     ret->code = kadm5_get_privs(handle, &ret->privs);
1465     if (ret->code != 0)
1466         errmsg = krb5_get_error_message(handle->context, ret->code);
1467
1468     log_done("kadm5_get_privs", client_name.value, errmsg,
1469              &client_name, &service_name, rqstp);
1470
1471     if (errmsg != NULL)
1472         krb5_free_error_message(handle->context, errmsg);
1473
1474 exit_func:
1475     stub_cleanup(handle, NULL, &client_name, &service_name);
1476     return TRUE;
1477 }
1478
1479 bool_t
1480 purgekeys_2_svc(purgekeys_arg *arg, generic_ret *ret, struct svc_req *rqstp)
1481 {
1482     char                        *funcname, *prime_arg = NULL;
1483     gss_buffer_desc             client_name = GSS_C_EMPTY_BUFFER;
1484     gss_buffer_desc             service_name = GSS_C_EMPTY_BUFFER;
1485     kadm5_server_handle_t       handle;
1486
1487     const char                  *errmsg = NULL;
1488
1489     ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
1490                            &ret->api_version, &client_name, &service_name,
1491                            &prime_arg);
1492     if (ret->code)
1493         goto exit_func;
1494
1495     funcname = "kadm5_purgekeys";
1496
1497     if (!cmp_gss_krb5_name(handle, rqst2name(rqstp), arg->princ) &&
1498         (CHANGEPW_SERVICE(rqstp)
1499          || !kadm5int_acl_check(handle->context, rqst2name(rqstp), ACL_MODIFY,
1500                                 arg->princ, NULL))) {
1501         ret->code = KADM5_AUTH_MODIFY;
1502         log_unauth(funcname, prime_arg, &client_name, &service_name, rqstp);
1503     } else {
1504         ret->code = kadm5_purgekeys(handle, arg->princ, arg->keepkvno);
1505         if (ret->code != 0)
1506             errmsg = krb5_get_error_message(handle->context, ret->code);
1507
1508         log_done(funcname, prime_arg, errmsg,
1509                  &client_name, &service_name, rqstp);
1510
1511         if (errmsg != NULL)
1512             krb5_free_error_message(handle->context, errmsg);
1513     }
1514
1515 exit_func:
1516     stub_cleanup(handle, prime_arg, &client_name, &service_name);
1517     return TRUE;
1518 }
1519
1520 bool_t
1521 get_strings_2_svc(gstrings_arg *arg, gstrings_ret *ret, struct svc_req *rqstp)
1522 {
1523     char                            *prime_arg = NULL;
1524     gss_buffer_desc                 client_name = GSS_C_EMPTY_BUFFER;
1525     gss_buffer_desc                 service_name = GSS_C_EMPTY_BUFFER;
1526     kadm5_server_handle_t           handle;
1527     const char                      *errmsg = NULL;
1528
1529     ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
1530                            &ret->api_version, &client_name, &service_name,
1531                            &prime_arg);
1532     if (ret->code)
1533         goto exit_func;
1534
1535     if (! cmp_gss_krb5_name(handle, rqst2name(rqstp), arg->princ) &&
1536         (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context,
1537                                                         rqst2name(rqstp),
1538                                                         ACL_INQUIRE,
1539                                                         arg->princ,
1540                                                         NULL))) {
1541         ret->code = KADM5_AUTH_GET;
1542         log_unauth("kadm5_get_strings", prime_arg,
1543                    &client_name, &service_name, rqstp);
1544     } else {
1545         ret->code = kadm5_get_strings(handle, arg->princ, &ret->strings,
1546                                       &ret->count);
1547         if (ret->code != 0)
1548             errmsg = krb5_get_error_message(handle->context, ret->code);
1549
1550         log_done("kadm5_get_strings", prime_arg, errmsg,
1551                  &client_name, &service_name, rqstp);
1552
1553         if (errmsg != NULL)
1554             krb5_free_error_message(handle->context, errmsg);
1555     }
1556
1557 exit_func:
1558     stub_cleanup(handle, prime_arg, &client_name, &service_name);
1559     return TRUE;
1560 }
1561
1562 bool_t
1563 set_string_2_svc(sstring_arg *arg, generic_ret *ret, struct svc_req *rqstp)
1564 {
1565     char                            *prime_arg = NULL;
1566     gss_buffer_desc                 client_name = GSS_C_EMPTY_BUFFER;
1567     gss_buffer_desc                 service_name = GSS_C_EMPTY_BUFFER;
1568     kadm5_server_handle_t           handle;
1569     const char                      *errmsg = NULL;
1570
1571     ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
1572                            &ret->api_version, &client_name, &service_name,
1573                            &prime_arg);
1574     if (ret->code)
1575         goto exit_func;
1576
1577     if (CHANGEPW_SERVICE(rqstp)
1578         || !kadm5int_acl_check(handle->context, rqst2name(rqstp), ACL_MODIFY,
1579                                arg->princ, NULL)) {
1580         ret->code = KADM5_AUTH_MODIFY;
1581         log_unauth("kadm5_mod_strings", prime_arg,
1582                    &client_name, &service_name, rqstp);
1583     } else {
1584         ret->code = kadm5_set_string(handle, arg->princ, arg->key, arg->value);
1585         if (ret->code != 0)
1586             errmsg = krb5_get_error_message(handle->context, ret->code);
1587
1588         log_done("kadm5_mod_strings", prime_arg, errmsg,
1589                  &client_name, &service_name, rqstp);
1590
1591         if (errmsg != NULL)
1592             krb5_free_error_message(handle->context, errmsg);
1593     }
1594
1595 exit_func:
1596     stub_cleanup(handle, prime_arg, &client_name, &service_name);
1597     return TRUE;
1598 }
1599
1600 bool_t
1601 init_2_svc(krb5_ui_4 *arg, generic_ret *ret, struct svc_req *rqstp)
1602 {
1603     gss_buffer_desc            client_name = GSS_C_EMPTY_BUFFER;
1604     gss_buffer_desc            service_name = GSS_C_EMPTY_BUFFER;
1605     kadm5_server_handle_t      handle;
1606     const char                 *errmsg = NULL;
1607     size_t clen, slen;
1608     char *cdots, *sdots;
1609
1610     ret->code = stub_setup(*arg, rqstp, NULL, &handle, &ret->api_version,
1611                            &client_name, &service_name, NULL);
1612     if (ret->code)
1613         goto exit_func;
1614
1615     if (ret->code != 0)
1616         errmsg = krb5_get_error_message(handle->context, ret->code);
1617
1618     clen = client_name.length;
1619     trunc_name(&clen, &cdots);
1620     slen = service_name.length;
1621     trunc_name(&slen, &sdots);
1622     /* okay to cast lengths to int because trunc_name limits max value */
1623     krb5_klog_syslog(LOG_NOTICE, _("Request: kadm5_init, %.*s%s, %s, "
1624                                    "client=%.*s%s, service=%.*s%s, addr=%s, "
1625                                    "vers=%d, flavor=%d"),
1626                      (int)clen, (char *)client_name.value, cdots,
1627                      errmsg ? errmsg : _("success"),
1628                      (int)clen, (char *)client_name.value, cdots,
1629                      (int)slen, (char *)service_name.value, sdots,
1630                      client_addr(rqstp->rq_xprt),
1631                      ret->api_version & ~(KADM5_API_VERSION_MASK),
1632                      rqstp->rq_cred.oa_flavor);
1633     if (errmsg != NULL)
1634         krb5_free_error_message(handle->context, errmsg);
1635
1636 exit_func:
1637     stub_cleanup(handle, NULL, &client_name, &service_name);
1638     return TRUE;
1639 }
1640
1641 gss_name_t
1642 rqst2name(struct svc_req *rqstp)
1643 {
1644
1645     if (rqstp->rq_cred.oa_flavor == RPCSEC_GSS)
1646         return rqstp->rq_clntname;
1647     else
1648         return rqstp->rq_clntcred;
1649 }
1650
1651 bool_t
1652 get_principal_keys_2_svc(getpkeys_arg *arg, getpkeys_ret *ret,
1653                          struct svc_req *rqstp)
1654 {
1655     char                            *prime_arg = NULL;
1656     gss_buffer_desc                 client_name = GSS_C_EMPTY_BUFFER;
1657     gss_buffer_desc                 service_name = GSS_C_EMPTY_BUFFER;
1658     kadm5_server_handle_t           handle;
1659     const char                      *errmsg = NULL;
1660
1661     ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
1662                            &ret->api_version, &client_name, &service_name,
1663                            &prime_arg);
1664     if (ret->code)
1665         goto exit_func;
1666
1667     if (!(CHANGEPW_SERVICE(rqstp)) &&
1668         kadm5int_acl_check(handle->context, rqst2name(rqstp),
1669                            ACL_EXTRACT, arg->princ, NULL)) {
1670         ret->code = kadm5_get_principal_keys(handle, arg->princ, arg->kvno,
1671                                              &ret->key_data, &ret->n_key_data);
1672     } else {
1673         log_unauth("kadm5_get_principal_keys", prime_arg,
1674                    &client_name, &service_name, rqstp);
1675         ret->code = KADM5_AUTH_EXTRACT;
1676     }
1677
1678     if (ret->code == KADM5_OK) {
1679         ret->code = check_lockdown_keys(handle, arg->princ);
1680         if (ret->code != KADM5_OK) {
1681             kadm5_free_kadm5_key_data(handle->context, ret->n_key_data,
1682                                       ret->key_data);
1683             ret->key_data = NULL;
1684             ret->n_key_data = 0;
1685         }
1686         if (ret->code == KADM5_PROTECT_KEYS) {
1687             log_unauth("kadm5_get_principal_keys", prime_arg,
1688                        &client_name, &service_name, rqstp);
1689             ret->code = KADM5_AUTH_EXTRACT;
1690         }
1691     }
1692
1693     if (ret->code != KADM5_AUTH_EXTRACT) {
1694         if (ret->code != 0)
1695             errmsg = krb5_get_error_message(handle->context, ret->code);
1696
1697         log_done("kadm5_get_principal_keys", prime_arg, errmsg,
1698                  &client_name, &service_name, rqstp);
1699
1700         if (errmsg != NULL)
1701             krb5_free_error_message(handle->context, errmsg);
1702     }
1703
1704 exit_func:
1705     stub_cleanup(handle, prime_arg, &client_name, &service_name);
1706     return TRUE;
1707 }