Imported Upstream version 1.20.1
[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-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
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 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }