summaryrefslogtreecommitdiff
path: root/src/kadmin/server/server_stubs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/kadmin/server/server_stubs.c')
-rw-r--r--src/kadmin/server/server_stubs.c1707
1 files changed, 1707 insertions, 0 deletions
diff --git a/src/kadmin/server/server_stubs.c b/src/kadmin/server/server_stubs.c
new file mode 100644
index 000000000000..86c162590e4b
--- /dev/null
+++ b/src/kadmin/server/server_stubs.c
@@ -0,0 +1,1707 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved
+ *
+ */
+
+#include <k5-platform.h>
+#include <socket-utils.h>
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_krb5.h> /* for gss_nt_krb5_name */
+#include <krb5.h>
+#include <kadm5/admin.h>
+#include <kadm5/kadm_rpc.h>
+#include <kadm5/server_internal.h>
+#include <kadm5/server_acl.h>
+#include <syslog.h>
+#include <adm_proto.h> /* krb5_klog_syslog */
+#include "misc.h"
+
+extern gss_name_t gss_changepw_name;
+extern gss_name_t gss_oldchangepw_name;
+extern void * global_server_handle;
+
+#define CHANGEPW_SERVICE(rqstp) \
+ (cmp_gss_names_rel_1(acceptor_name(rqstp->rq_svccred), gss_changepw_name) | \
+ (gss_oldchangepw_name && \
+ cmp_gss_names_rel_1(acceptor_name(rqstp->rq_svccred), \
+ gss_oldchangepw_name)))
+
+
+static int gss_to_krb5_name(kadm5_server_handle_t handle,
+ gss_name_t gss_name, krb5_principal *princ);
+
+static int gss_name_to_string(gss_name_t gss_name, gss_buffer_desc *str);
+
+static gss_name_t acceptor_name(gss_ctx_id_t context);
+
+gss_name_t rqst2name(struct svc_req *rqstp);
+
+static int cmp_gss_names(gss_name_t n1, gss_name_t n2)
+{
+ OM_uint32 emin;
+ int equal;
+
+ if (GSS_ERROR(gss_compare_name(&emin, n1, n2, &equal)))
+ return(0);
+
+ return(equal);
+}
+
+/* Does a comparison of the names and then releases the first entity */
+/* For use above in CHANGEPW_SERVICE */
+static int cmp_gss_names_rel_1(gss_name_t n1, gss_name_t n2)
+{
+ OM_uint32 min_stat;
+ int ret;
+
+ ret = cmp_gss_names(n1, n2);
+ if (n1) (void) gss_release_name(&min_stat, &n1);
+ return ret;
+}
+
+/*
+ * Function check_handle
+ *
+ * Purpose: Check a server handle and return a com_err code if it is
+ * invalid or 0 if it is valid.
+ *
+ * Arguments:
+ *
+ * handle The server handle.
+ */
+
+static int check_handle(void *handle)
+{
+ CHECK_HANDLE(handle);
+ return 0;
+}
+
+/*
+ * Function: new_server_handle
+ *
+ * Purpose: Constructs a server handle suitable for passing into the
+ * server library API functions, by folding the client's API version
+ * and calling principal into the server handle returned by
+ * kadm5_init.
+ *
+ * Arguments:
+ * api_version (input) The API version specified by the client
+ * rqstp (input) The RPC request
+ * handle (output) The returned handle
+ * <return value> (output) An error code, or 0 if no error occurred
+ *
+ * Effects:
+ * Returns a pointer to allocated storage containing the server
+ * handle. If an error occurs, then no allocated storage is
+ * returned, and the return value of the function will be a
+ * non-zero com_err code.
+ *
+ * The allocated storage for the handle should be freed with
+ * free_server_handle (see below) when it is no longer needed.
+ */
+
+static kadm5_ret_t new_server_handle(krb5_ui_4 api_version,
+ struct svc_req *rqstp,
+ kadm5_server_handle_t
+ *out_handle)
+{
+ kadm5_server_handle_t handle;
+
+ *out_handle = NULL;
+
+ if (! (handle = (kadm5_server_handle_t)
+ malloc(sizeof(*handle))))
+ return ENOMEM;
+
+ *handle = *(kadm5_server_handle_t)global_server_handle;
+ handle->api_version = api_version;
+
+ if (! gss_to_krb5_name(handle, rqst2name(rqstp),
+ &handle->current_caller)) {
+ free(handle);
+ return KADM5_FAILURE;
+ }
+
+ *out_handle = handle;
+ return 0;
+}
+
+/*
+ * Function: free_server_handle
+ *
+ * Purpose: Free handle memory allocated by new_server_handle
+ *
+ * Arguments:
+ * handle (input/output) The handle to free
+ */
+static void free_server_handle(kadm5_server_handle_t handle)
+{
+ if (!handle)
+ return;
+ krb5_free_principal(handle->context, handle->current_caller);
+ free(handle);
+}
+
+/* Result is stored in a static buffer and is invalidated by the next call. */
+const char *
+client_addr(SVCXPRT *xprt)
+{
+ static char abuf[128];
+ struct sockaddr_storage ss;
+ socklen_t len = sizeof(ss);
+ const char *p = NULL;
+
+ if (getpeername(xprt->xp_sock, ss2sa(&ss), &len) != 0)
+ return "(unknown)";
+ if (ss2sa(&ss)->sa_family == AF_INET)
+ p = inet_ntop(AF_INET, &ss2sin(&ss)->sin_addr, abuf, sizeof(abuf));
+ else if (ss2sa(&ss)->sa_family == AF_INET6)
+ p = inet_ntop(AF_INET6, &ss2sin6(&ss)->sin6_addr, abuf, sizeof(abuf));
+ return (p == NULL) ? "(unknown)" : p;
+}
+
+/*
+ * Function: setup_gss_names
+ *
+ * Purpose: Create printable representations of the client and server
+ * names.
+ *
+ * Arguments:
+ * rqstp (r) the RPC request
+ * client_name (w) the gss_buffer_t for the client name
+ * server_name (w) the gss_buffer_t for the server name
+ *
+ * Effects:
+ *
+ * Unparses the client and server names into client_name and
+ * server_name, both of which must be freed by the caller. Returns 0
+ * on success and -1 on failure.
+ */
+int setup_gss_names(struct svc_req *rqstp,
+ gss_buffer_desc *client_name,
+ gss_buffer_desc *server_name)
+{
+ OM_uint32 maj_stat, min_stat;
+ gss_name_t server_gss_name;
+
+ if (gss_name_to_string(rqst2name(rqstp), client_name) != 0)
+ return -1;
+ maj_stat = gss_inquire_context(&min_stat, rqstp->rq_svccred, NULL,
+ &server_gss_name, NULL, NULL, NULL,
+ NULL, NULL);
+ if (maj_stat != GSS_S_COMPLETE) {
+ gss_release_buffer(&min_stat, client_name);
+ gss_release_name(&min_stat, &server_gss_name);
+ return -1;
+ }
+ if (gss_name_to_string(server_gss_name, server_name) != 0) {
+ gss_release_buffer(&min_stat, client_name);
+ gss_release_name(&min_stat, &server_gss_name);
+ return -1;
+ }
+ gss_release_name(&min_stat, &server_gss_name);
+ return 0;
+}
+
+static gss_name_t acceptor_name(gss_ctx_id_t context)
+{
+ OM_uint32 maj_stat, min_stat;
+ gss_name_t name;
+
+ maj_stat = gss_inquire_context(&min_stat, context, NULL, &name,
+ NULL, NULL, NULL, NULL, NULL);
+ if (maj_stat != GSS_S_COMPLETE)
+ return NULL;
+ return name;
+}
+
+static int cmp_gss_krb5_name(kadm5_server_handle_t handle,
+ gss_name_t gss_name, krb5_principal princ)
+{
+ krb5_principal princ2;
+ int status;
+
+ if (! gss_to_krb5_name(handle, gss_name, &princ2))
+ return 0;
+ status = krb5_principal_compare(handle->context, princ, princ2);
+ krb5_free_principal(handle->context, princ2);
+ return status;
+}
+
+static int gss_to_krb5_name(kadm5_server_handle_t handle,
+ gss_name_t gss_name, krb5_principal *princ)
+{
+ OM_uint32 minor_stat;
+ gss_buffer_desc gss_str;
+ int success;
+ char *s;
+
+ if (gss_name_to_string(gss_name, &gss_str) != 0)
+ return 0;
+ if (asprintf(&s, "%.*s", (int)gss_str.length, (char *)gss_str.value) < 0) {
+ gss_release_buffer(&minor_stat, &gss_str);
+ return 0;
+ }
+ success = (krb5_parse_name(handle->context, s, princ) == 0);
+ free(s);
+ gss_release_buffer(&minor_stat, &gss_str);
+ return success;
+}
+
+static int
+gss_name_to_string(gss_name_t gss_name, gss_buffer_desc *str)
+{
+ OM_uint32 status, minor_stat;
+ gss_OID gss_type;
+ const char pref[] = KRB5_WELLKNOWN_NAMESTR "/" KRB5_ANONYMOUS_PRINCSTR "@";
+ const size_t preflen = sizeof(pref) - 1;
+
+ status = gss_display_name(&minor_stat, gss_name, str, &gss_type);
+ if (status != GSS_S_COMPLETE)
+ return 1;
+ if (gss_oid_equal(gss_type, GSS_C_NT_ANONYMOUS)) {
+ /* Guard against non-krb5 mechs with different anonymous displays. */
+ if (str->length < preflen || memcmp(str->value, pref, preflen) != 0)
+ return 1;
+ } else if (!gss_oid_equal(gss_type, GSS_KRB5_NT_PRINCIPAL_NAME)) {
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Perform common initialization for server stub functions. A subset of the
+ * output arguments may be set on failure; the caller is responsible for
+ * initializing outputs and calling stub_cleanup() on success or failure.
+ * princ and princ_str_out may be NULL to omit unparsing a principal name.
+ */
+static kadm5_ret_t
+stub_setup(krb5_ui_4 api_version, struct svc_req *rqstp, krb5_principal princ,
+ kadm5_server_handle_t *handle_out, krb5_ui_4 *api_version_out,
+ gss_buffer_t client_name_out, gss_buffer_t service_name_out,
+ char **princ_str_out)
+{
+ kadm5_ret_t ret;
+
+ ret = new_server_handle(api_version, rqstp, handle_out);
+ if (ret)
+ return ret;
+
+ ret = check_handle(*handle_out);
+ if (ret)
+ return ret;
+
+ *api_version_out = (*handle_out)->api_version;
+
+ if (setup_gss_names(rqstp, client_name_out, service_name_out) < 0)
+ return KADM5_FAILURE;
+
+ if (princ_str_out != NULL) {
+ if (princ == NULL)
+ return KADM5_BAD_PRINCIPAL;
+ if (krb5_unparse_name((*handle_out)->context, princ, princ_str_out))
+ return KADM5_BAD_PRINCIPAL;
+ }
+
+ return KADM5_OK;
+}
+
+/* Perform common cleanup for server stub functions. */
+static void
+stub_cleanup(kadm5_server_handle_t handle, char *princ_str,
+ gss_buffer_t client_name, gss_buffer_t service_name)
+{
+ OM_uint32 minor_stat;
+
+ free_server_handle(handle);
+ free(princ_str);
+ gss_release_buffer(&minor_stat, client_name);
+ gss_release_buffer(&minor_stat, service_name);
+}
+
+static int
+log_unauth(
+ char *op,
+ char *target,
+ gss_buffer_t client,
+ gss_buffer_t server,
+ struct svc_req *rqstp)
+{
+ size_t tlen, clen, slen;
+ char *tdots, *cdots, *sdots;
+
+ tlen = strlen(target);
+ trunc_name(&tlen, &tdots);
+ clen = client->length;
+ trunc_name(&clen, &cdots);
+ slen = server->length;
+ trunc_name(&slen, &sdots);
+
+ /* okay to cast lengths to int because trunc_name limits max value */
+ return krb5_klog_syslog(LOG_NOTICE,
+ _("Unauthorized request: %s, %.*s%s, "
+ "client=%.*s%s, service=%.*s%s, addr=%s"),
+ op, (int)tlen, target, tdots,
+ (int)clen, (char *)client->value, cdots,
+ (int)slen, (char *)server->value, sdots,
+ client_addr(rqstp->rq_xprt));
+}
+
+static int
+log_done(
+ char *op,
+ char *target,
+ const char *errmsg,
+ gss_buffer_t client,
+ gss_buffer_t server,
+ struct svc_req *rqstp)
+{
+ size_t tlen, clen, slen;
+ char *tdots, *cdots, *sdots;
+
+ if (errmsg == NULL)
+ errmsg = _("success");
+ tlen = strlen(target);
+ trunc_name(&tlen, &tdots);
+ clen = client->length;
+ trunc_name(&clen, &cdots);
+ slen = server->length;
+ trunc_name(&slen, &sdots);
+
+ /* okay to cast lengths to int because trunc_name limits max value */
+ return krb5_klog_syslog(LOG_NOTICE,
+ _("Request: %s, %.*s%s, %s, "
+ "client=%.*s%s, service=%.*s%s, addr=%s"),
+ op, (int)tlen, target, tdots, errmsg,
+ (int)clen, (char *)client->value, cdots,
+ (int)slen, (char *)server->value, sdots,
+ client_addr(rqstp->rq_xprt));
+}
+
+bool_t
+create_principal_2_svc(cprinc_arg *arg, generic_ret *ret,
+ struct svc_req *rqstp)
+{
+ char *prime_arg = NULL;
+ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
+ kadm5_server_handle_t handle;
+ restriction_t *rp;
+ const char *errmsg = NULL;
+
+ ret->code = stub_setup(arg->api_version, rqstp, arg->rec.principal,
+ &handle, &ret->api_version, &client_name,
+ &service_name, &prime_arg);
+ if (ret->code)
+ goto exit_func;
+
+ if (CHANGEPW_SERVICE(rqstp)
+ || !kadm5int_acl_check(handle->context, rqst2name(rqstp), ACL_ADD,
+ arg->rec.principal, &rp)
+ || kadm5int_acl_impose_restrictions(handle->context,
+ &arg->rec, &arg->mask, rp)) {
+ ret->code = KADM5_AUTH_ADD;
+ log_unauth("kadm5_create_principal", prime_arg,
+ &client_name, &service_name, rqstp);
+ } else {
+ ret->code = kadm5_create_principal(handle, &arg->rec, arg->mask,
+ arg->passwd);
+
+ if (ret->code != 0)
+ errmsg = krb5_get_error_message(handle->context, ret->code);
+
+ log_done("kadm5_create_principal", prime_arg, errmsg,
+ &client_name, &service_name, rqstp);
+
+ if (errmsg != NULL)
+ krb5_free_error_message(handle->context, errmsg);
+ }
+
+exit_func:
+ stub_cleanup(handle, prime_arg, &client_name, &service_name);
+ return TRUE;
+}
+
+bool_t
+create_principal3_2_svc(cprinc3_arg *arg, generic_ret *ret,
+ struct svc_req *rqstp)
+{
+ char *prime_arg = NULL;
+ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
+ kadm5_server_handle_t handle;
+ restriction_t *rp;
+ const char *errmsg = NULL;
+
+ ret->code = stub_setup(arg->api_version, rqstp, arg->rec.principal,
+ &handle, &ret->api_version, &client_name,
+ &service_name, &prime_arg);
+ if (ret->code)
+ goto exit_func;
+
+ if (CHANGEPW_SERVICE(rqstp)
+ || !kadm5int_acl_check(handle->context, rqst2name(rqstp), ACL_ADD,
+ arg->rec.principal, &rp)
+ || kadm5int_acl_impose_restrictions(handle->context,
+ &arg->rec, &arg->mask, rp)) {
+ ret->code = KADM5_AUTH_ADD;
+ log_unauth("kadm5_create_principal", prime_arg,
+ &client_name, &service_name, rqstp);
+ } else {
+ ret->code = kadm5_create_principal_3(handle, &arg->rec, arg->mask,
+ arg->n_ks_tuple, arg->ks_tuple,
+ arg->passwd);
+ if (ret->code != 0)
+ errmsg = krb5_get_error_message(handle->context, ret->code);
+
+ log_done("kadm5_create_principal", prime_arg, errmsg,
+ &client_name, &service_name, rqstp);
+
+ if (errmsg != NULL)
+ krb5_free_error_message(handle->context, errmsg);
+ }
+
+exit_func:
+ stub_cleanup(handle, prime_arg, &client_name, &service_name);
+ return TRUE;
+}
+
+/* Return KADM5_PROTECT_KEYS if KRB5_KDB_LOCKDOWN_KEYS is set for princ. */
+static kadm5_ret_t
+check_lockdown_keys(kadm5_server_handle_t handle, krb5_principal princ)
+{
+ kadm5_principal_ent_rec rec;
+ kadm5_ret_t ret;
+
+ ret = kadm5_get_principal(handle, princ, &rec, KADM5_ATTRIBUTES);
+ if (ret)
+ return ret;
+ ret = (rec.attributes & KRB5_KDB_LOCKDOWN_KEYS) ? KADM5_PROTECT_KEYS : 0;
+ kadm5_free_principal_ent(handle, &rec);
+ return ret;
+}
+
+bool_t
+delete_principal_2_svc(dprinc_arg *arg, generic_ret *ret,
+ struct svc_req *rqstp)
+{
+ char *prime_arg = NULL;
+ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
+ kadm5_server_handle_t handle;
+ const char *errmsg = NULL;
+
+ ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
+ &ret->api_version, &client_name, &service_name,
+ &prime_arg);
+ if (ret->code)
+ goto exit_func;
+
+ if (CHANGEPW_SERVICE(rqstp)
+ || !kadm5int_acl_check(handle->context, rqst2name(rqstp), ACL_DELETE,
+ arg->princ, NULL)) {
+ ret->code = KADM5_AUTH_DELETE;
+ log_unauth("kadm5_delete_principal", prime_arg,
+ &client_name, &service_name, rqstp);
+ } else {
+ ret->code = check_lockdown_keys(handle, arg->princ);
+ if (ret->code == KADM5_PROTECT_KEYS) {
+ log_unauth("kadm5_delete_principal", prime_arg, &client_name,
+ &service_name, rqstp);
+ ret->code = KADM5_AUTH_DELETE;
+ }
+ }
+
+ if (ret->code == KADM5_OK)
+ ret->code = kadm5_delete_principal(handle, arg->princ);
+ if (ret->code != KADM5_AUTH_DELETE) {
+ if (ret->code != 0)
+ errmsg = krb5_get_error_message(handle->context, ret->code);
+
+ log_done("kadm5_delete_principal", prime_arg, errmsg,
+ &client_name, &service_name, rqstp);
+
+ if (errmsg != NULL)
+ krb5_free_error_message(handle->context, errmsg);
+
+ }
+
+exit_func:
+ stub_cleanup(handle, prime_arg, &client_name, &service_name);
+ return TRUE;
+}
+
+bool_t
+modify_principal_2_svc(mprinc_arg *arg, generic_ret *ret,
+ struct svc_req *rqstp)
+{
+ char *prime_arg = NULL;
+ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
+ kadm5_server_handle_t handle;
+ restriction_t *rp;
+ const char *errmsg = NULL;
+
+ ret->code = stub_setup(arg->api_version, rqstp, arg->rec.principal,
+ &handle, &ret->api_version, &client_name,
+ &service_name, &prime_arg);
+ if (ret->code)
+ goto exit_func;
+
+ if (CHANGEPW_SERVICE(rqstp)
+ || !kadm5int_acl_check(handle->context, rqst2name(rqstp), ACL_MODIFY,
+ arg->rec.principal, &rp)
+ || kadm5int_acl_impose_restrictions(handle->context,
+ &arg->rec, &arg->mask, rp)) {
+ ret->code = KADM5_AUTH_MODIFY;
+ log_unauth("kadm5_modify_principal", prime_arg,
+ &client_name, &service_name, rqstp);
+ } else if ((arg->mask & KADM5_ATTRIBUTES) &&
+ (!(arg->rec.attributes & KRB5_KDB_LOCKDOWN_KEYS))) {
+ ret->code = check_lockdown_keys(handle, arg->rec.principal);
+ if (ret->code == KADM5_PROTECT_KEYS) {
+ log_unauth("kadm5_modify_principal", prime_arg, &client_name,
+ &service_name, rqstp);
+ ret->code = KADM5_AUTH_MODIFY;
+ }
+ }
+
+ if (ret->code == KADM5_OK) {
+ ret->code = kadm5_modify_principal(handle, &arg->rec, arg->mask);
+ if (ret->code != 0)
+ errmsg = krb5_get_error_message(handle->context, ret->code);
+
+ log_done("kadm5_modify_principal", prime_arg, errmsg,
+ &client_name, &service_name, rqstp);
+
+ if (errmsg != NULL)
+ krb5_free_error_message(handle->context, errmsg);
+ }
+
+exit_func:
+ stub_cleanup(handle, prime_arg, &client_name, &service_name);
+ return TRUE;
+}
+
+bool_t
+rename_principal_2_svc(rprinc_arg *arg, generic_ret *ret,
+ struct svc_req *rqstp)
+{
+ char *prime_arg1 = NULL, *prime_arg2 = NULL;
+ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
+ kadm5_server_handle_t handle;
+ restriction_t *rp;
+ const char *errmsg = NULL;
+ size_t tlen1, tlen2, clen, slen;
+ char *tdots1, *tdots2, *cdots, *sdots;
+
+ ret->code = stub_setup(arg->api_version, rqstp, NULL, &handle,
+ &ret->api_version, &client_name, &service_name,
+ NULL);
+ if (ret->code)
+ goto exit_func;
+
+ if (krb5_unparse_name(handle->context, arg->src, &prime_arg1) ||
+ krb5_unparse_name(handle->context, arg->dest, &prime_arg2)) {
+ ret->code = KADM5_BAD_PRINCIPAL;
+ goto exit_func;
+ }
+ tlen1 = strlen(prime_arg1);
+ trunc_name(&tlen1, &tdots1);
+ tlen2 = strlen(prime_arg2);
+ trunc_name(&tlen2, &tdots2);
+ clen = client_name.length;
+ trunc_name(&clen, &cdots);
+ slen = service_name.length;
+ trunc_name(&slen, &sdots);
+
+ ret->code = KADM5_OK;
+ if (! CHANGEPW_SERVICE(rqstp)) {
+ if (!kadm5int_acl_check(handle->context, rqst2name(rqstp),
+ ACL_DELETE, arg->src, NULL))
+ ret->code = KADM5_AUTH_DELETE;
+ /* any restrictions at all on the ADD kills the RENAME */
+ if (!kadm5int_acl_check(handle->context, rqst2name(rqstp),
+ ACL_ADD, arg->dest, &rp) || rp) {
+ if (ret->code == KADM5_AUTH_DELETE)
+ ret->code = KADM5_AUTH_INSUFFICIENT;
+ else
+ ret->code = KADM5_AUTH_ADD;
+ }
+ if (ret->code == KADM5_OK) {
+ ret->code = check_lockdown_keys(handle, arg->src);
+ if (ret->code == KADM5_PROTECT_KEYS) {
+ log_unauth("kadm5_rename_principal", prime_arg1, &client_name,
+ &service_name, rqstp);
+ ret->code = KADM5_AUTH_DELETE;
+ }
+ }
+ } else
+ ret->code = KADM5_AUTH_INSUFFICIENT;
+ if (ret->code != KADM5_OK) {
+ /* okay to cast lengths to int because trunc_name limits max value */
+ krb5_klog_syslog(LOG_NOTICE,
+ _("Unauthorized request: kadm5_rename_principal, "
+ "%.*s%s to %.*s%s, "
+ "client=%.*s%s, service=%.*s%s, addr=%s"),
+ (int)tlen1, prime_arg1, tdots1,
+ (int)tlen2, prime_arg2, tdots2,
+ (int)clen, (char *)client_name.value, cdots,
+ (int)slen, (char *)service_name.value, sdots,
+ client_addr(rqstp->rq_xprt));
+ } else {
+ ret->code = kadm5_rename_principal(handle, arg->src, arg->dest);
+ if (ret->code != 0)
+ errmsg = krb5_get_error_message(handle->context, ret->code);
+
+ /* okay to cast lengths to int because trunc_name limits max value */
+ krb5_klog_syslog(LOG_NOTICE,
+ _("Request: kadm5_rename_principal, "
+ "%.*s%s to %.*s%s, %s, "
+ "client=%.*s%s, service=%.*s%s, addr=%s"),
+ (int)tlen1, prime_arg1, tdots1,
+ (int)tlen2, prime_arg2, tdots2,
+ errmsg ? errmsg : _("success"),
+ (int)clen, (char *)client_name.value, cdots,
+ (int)slen, (char *)service_name.value, sdots,
+ client_addr(rqstp->rq_xprt));
+
+ if (errmsg != NULL)
+ krb5_free_error_message(handle->context, errmsg);
+
+ }
+exit_func:
+ free(prime_arg1);
+ free(prime_arg2);
+ stub_cleanup(handle, NULL, &client_name, &service_name);
+ return TRUE;
+}
+
+bool_t
+get_principal_2_svc(gprinc_arg *arg, gprinc_ret *ret, struct svc_req *rqstp)
+{
+ char *funcname, *prime_arg = NULL;
+ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
+ kadm5_server_handle_t handle;
+ const char *errmsg = NULL;
+
+ ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
+ &ret->api_version, &client_name, &service_name,
+ &prime_arg);
+ if (ret->code)
+ goto exit_func;
+
+ funcname = "kadm5_get_principal";
+
+ if (! cmp_gss_krb5_name(handle, rqst2name(rqstp), arg->princ) &&
+ (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context,
+ rqst2name(rqstp),
+ ACL_INQUIRE,
+ arg->princ,
+ NULL))) {
+ ret->code = KADM5_AUTH_GET;
+ log_unauth(funcname, prime_arg,
+ &client_name, &service_name, rqstp);
+ } else {
+ ret->code = kadm5_get_principal(handle, arg->princ, &ret->rec,
+ arg->mask);
+
+ if (ret->code != 0)
+ errmsg = krb5_get_error_message(handle->context, ret->code);
+
+ log_done(funcname, prime_arg, errmsg,
+ &client_name, &service_name, rqstp);
+
+ if (errmsg != NULL)
+ krb5_free_error_message(handle->context, errmsg);
+ }
+
+exit_func:
+ stub_cleanup(handle, prime_arg, &client_name, &service_name);
+ return TRUE;
+}
+
+bool_t
+get_princs_2_svc(gprincs_arg *arg, gprincs_ret *ret, struct svc_req *rqstp)
+{
+ char *prime_arg = NULL;
+ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
+ kadm5_server_handle_t handle;
+ const char *errmsg = NULL;
+
+ ret->code = stub_setup(arg->api_version, rqstp, NULL, &handle,
+ &ret->api_version, &client_name, &service_name,
+ NULL);
+ if (ret->code)
+ goto exit_func;
+
+ prime_arg = arg->exp;
+ if (prime_arg == NULL)
+ prime_arg = "*";
+
+ if (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context,
+ rqst2name(rqstp),
+ ACL_LIST,
+ NULL,
+ NULL)) {
+ ret->code = KADM5_AUTH_LIST;
+ log_unauth("kadm5_get_principals", prime_arg,
+ &client_name, &service_name, rqstp);
+ } else {
+ ret->code = kadm5_get_principals(handle, arg->exp, &ret->princs,
+ &ret->count);
+ if (ret->code != 0)
+ errmsg = krb5_get_error_message(handle->context, ret->code);
+
+ log_done("kadm5_get_principals", prime_arg, errmsg,
+ &client_name, &service_name, rqstp);
+
+ if (errmsg != NULL)
+ krb5_free_error_message(handle->context, errmsg);
+
+ }
+
+exit_func:
+ stub_cleanup(handle, NULL, &client_name, &service_name);
+ return TRUE;
+}
+
+bool_t
+chpass_principal_2_svc(chpass_arg *arg, generic_ret *ret,
+ struct svc_req *rqstp)
+{
+ char *prime_arg = NULL;
+ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
+ kadm5_server_handle_t handle;
+ const char *errmsg = NULL;
+
+ ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
+ &ret->api_version, &client_name, &service_name,
+ &prime_arg);
+ if (ret->code)
+ goto exit_func;
+
+ ret->code = check_lockdown_keys(handle, arg->princ);
+ if (ret->code != KADM5_OK) {
+ if (ret->code == KADM5_PROTECT_KEYS) {
+ log_unauth("kadm5_chpass_principal", prime_arg, &client_name,
+ &service_name, rqstp);
+ ret->code = KADM5_AUTH_CHANGEPW;
+ }
+ } else if (cmp_gss_krb5_name(handle, rqst2name(rqstp), arg->princ)) {
+ ret->code = chpass_principal_wrapper_3(handle, arg->princ, FALSE, 0,
+ NULL, arg->pass);
+ } else if (!(CHANGEPW_SERVICE(rqstp)) &&
+ kadm5int_acl_check(handle->context, rqst2name(rqstp),
+ ACL_CHANGEPW, arg->princ, NULL)) {
+ ret->code = kadm5_chpass_principal(handle, arg->princ, arg->pass);
+ } else {
+ log_unauth("kadm5_chpass_principal", prime_arg,
+ &client_name, &service_name, rqstp);
+ ret->code = KADM5_AUTH_CHANGEPW;
+ }
+
+ if (ret->code != KADM5_AUTH_CHANGEPW) {
+ if (ret->code != 0)
+ errmsg = krb5_get_error_message(handle->context, ret->code);
+
+ log_done("kadm5_chpass_principal", prime_arg, errmsg,
+ &client_name, &service_name, rqstp);
+
+ if (errmsg != NULL)
+ krb5_free_error_message(handle->context, errmsg);
+ }
+
+exit_func:
+ stub_cleanup(handle, prime_arg, &client_name, &service_name);
+ return TRUE;
+}
+
+bool_t
+chpass_principal3_2_svc(chpass3_arg *arg, generic_ret *ret,
+ struct svc_req *rqstp)
+{
+ char *prime_arg = NULL;
+ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
+ kadm5_server_handle_t handle;
+ const char *errmsg = NULL;
+
+ ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
+ &ret->api_version, &client_name, &service_name,
+ &prime_arg);
+ if (ret->code)
+ goto exit_func;
+
+ ret->code = check_lockdown_keys(handle, arg->princ);
+ if (ret->code != KADM5_OK) {
+ if (ret->code == KADM5_PROTECT_KEYS) {
+ log_unauth("kadm5_chpass_principal", prime_arg, &client_name,
+ &service_name, rqstp);
+ ret->code = KADM5_AUTH_CHANGEPW;
+ }
+ } else if (cmp_gss_krb5_name(handle, rqst2name(rqstp), arg->princ)) {
+ ret->code = chpass_principal_wrapper_3(handle, arg->princ,
+ arg->keepold, arg->n_ks_tuple,
+ arg->ks_tuple, arg->pass);
+ } else if (!(CHANGEPW_SERVICE(rqstp)) &&
+ kadm5int_acl_check(handle->context, rqst2name(rqstp),
+ ACL_CHANGEPW, arg->princ, NULL)) {
+ ret->code = kadm5_chpass_principal_3(handle, arg->princ, arg->keepold,
+ arg->n_ks_tuple, arg->ks_tuple,
+ arg->pass);
+ } else {
+ log_unauth("kadm5_chpass_principal", prime_arg,
+ &client_name, &service_name, rqstp);
+ ret->code = KADM5_AUTH_CHANGEPW;
+ }
+
+ if (ret->code != KADM5_AUTH_CHANGEPW) {
+ if (ret->code != 0)
+ errmsg = krb5_get_error_message(handle->context, ret->code);
+
+ log_done("kadm5_chpass_principal", prime_arg, errmsg,
+ &client_name, &service_name, rqstp);
+
+ if (errmsg != NULL)
+ krb5_free_error_message(handle->context, errmsg);
+ }
+
+exit_func:
+ stub_cleanup(handle, prime_arg, &client_name, &service_name);
+ return TRUE;
+}
+
+bool_t
+setv4key_principal_2_svc(setv4key_arg *arg, generic_ret *ret,
+ struct svc_req *rqstp)
+{
+ char *prime_arg = NULL;
+ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
+ kadm5_server_handle_t handle;
+ const char *errmsg = NULL;
+
+ ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
+ &ret->api_version, &client_name, &service_name,
+ &prime_arg);
+ if (ret->code)
+ goto exit_func;
+
+ ret->code = check_lockdown_keys(handle, arg->princ);
+ if (ret->code != KADM5_OK) {
+ if (ret->code == KADM5_PROTECT_KEYS) {
+ log_unauth("kadm5_setv4key_principal", prime_arg, &client_name,
+ &service_name, rqstp);
+ ret->code = KADM5_AUTH_SETKEY;
+ }
+ } else if (!(CHANGEPW_SERVICE(rqstp)) &&
+ kadm5int_acl_check(handle->context, rqst2name(rqstp),
+ ACL_SETKEY, arg->princ, NULL)) {
+ ret->code = kadm5_setv4key_principal(handle, arg->princ,
+ arg->keyblock);
+ } else {
+ log_unauth("kadm5_setv4key_principal", prime_arg,
+ &client_name, &service_name, rqstp);
+ ret->code = KADM5_AUTH_SETKEY;
+ }
+
+ if (ret->code != KADM5_AUTH_SETKEY) {
+ if (ret->code != 0)
+ errmsg = krb5_get_error_message(handle->context, ret->code);
+
+ log_done("kadm5_setv4key_principal", prime_arg, errmsg,
+ &client_name, &service_name, rqstp);
+
+ if (errmsg != NULL)
+ krb5_free_error_message(handle->context, errmsg);
+ }
+
+exit_func:
+ stub_cleanup(handle, prime_arg, &client_name, &service_name);
+ return TRUE;
+}
+
+
+bool_t
+setkey_principal_2_svc(setkey_arg *arg, generic_ret *ret,
+ struct svc_req *rqstp)
+{
+ char *prime_arg = NULL;
+ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
+ kadm5_server_handle_t handle;
+ const char *errmsg = NULL;
+
+ ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
+ &ret->api_version, &client_name, &service_name,
+ &prime_arg);
+ if (ret->code)
+ goto exit_func;
+
+ ret->code = check_lockdown_keys(handle, arg->princ);
+ if (ret->code != KADM5_OK) {
+ if (ret->code == KADM5_PROTECT_KEYS) {
+ log_unauth("kadm5_setkey_principal", prime_arg, &client_name,
+ &service_name, rqstp);
+ ret->code = KADM5_AUTH_SETKEY;
+ }
+ } else if (!(CHANGEPW_SERVICE(rqstp)) &&
+ kadm5int_acl_check(handle->context, rqst2name(rqstp),
+ ACL_SETKEY, arg->princ, NULL)) {
+ ret->code = kadm5_setkey_principal(handle, arg->princ, arg->keyblocks,
+ arg->n_keys);
+ } else {
+ log_unauth("kadm5_setkey_principal", prime_arg,
+ &client_name, &service_name, rqstp);
+ ret->code = KADM5_AUTH_SETKEY;
+ }
+
+ if (ret->code != KADM5_AUTH_SETKEY) {
+ if (ret->code != 0)
+ errmsg = krb5_get_error_message(handle->context, ret->code);
+
+ log_done("kadm5_setkey_principal", prime_arg, errmsg,
+ &client_name, &service_name, rqstp);
+
+ if (errmsg != NULL)
+ krb5_free_error_message(handle->context, errmsg);
+ }
+
+exit_func:
+ stub_cleanup(handle, prime_arg, &client_name, &service_name);
+ return TRUE;
+}
+
+bool_t
+setkey_principal3_2_svc(setkey3_arg *arg, generic_ret *ret,
+ struct svc_req *rqstp)
+{
+ char *prime_arg = NULL;
+ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
+ kadm5_server_handle_t handle;
+ const char *errmsg = NULL;
+
+ ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
+ &ret->api_version, &client_name, &service_name,
+ &prime_arg);
+ if (ret->code)
+ goto exit_func;
+
+ ret->code = check_lockdown_keys(handle, arg->princ);
+ if (ret->code != KADM5_OK) {
+ if (ret->code == KADM5_PROTECT_KEYS) {
+ log_unauth("kadm5_setkey_principal", prime_arg, &client_name,
+ &service_name, rqstp);
+ ret->code = KADM5_AUTH_SETKEY;
+ }
+ } else if (!(CHANGEPW_SERVICE(rqstp)) &&
+ kadm5int_acl_check(handle->context, rqst2name(rqstp),
+ ACL_SETKEY, arg->princ, NULL)) {
+ ret->code = kadm5_setkey_principal_3(handle, arg->princ, arg->keepold,
+ arg->n_ks_tuple, arg->ks_tuple,
+ arg->keyblocks, arg->n_keys);
+ } else {
+ log_unauth("kadm5_setkey_principal", prime_arg,
+ &client_name, &service_name, rqstp);
+ ret->code = KADM5_AUTH_SETKEY;
+ }
+
+ if (ret->code != KADM5_AUTH_SETKEY) {
+ if (ret->code != 0)
+ errmsg = krb5_get_error_message(handle->context, ret->code);
+
+ log_done("kadm5_setkey_principal", prime_arg, errmsg,
+ &client_name, &service_name, rqstp);
+
+ if (errmsg != NULL)
+ krb5_free_error_message(handle->context, errmsg);
+ }
+
+exit_func:
+ stub_cleanup(handle, prime_arg, &client_name, &service_name);
+ return TRUE;
+}
+
+bool_t
+setkey_principal4_2_svc(setkey4_arg *arg, generic_ret *ret,
+ struct svc_req *rqstp)
+{
+ char *prime_arg = NULL;
+ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
+ kadm5_server_handle_t handle;
+ const char *errmsg = NULL;
+
+ ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
+ &ret->api_version, &client_name, &service_name,
+ &prime_arg);
+ if (ret->code)
+ goto exit_func;
+
+ ret->code = check_lockdown_keys(handle, arg->princ);
+ if (ret->code != KADM5_OK) {
+ if (ret->code == KADM5_PROTECT_KEYS) {
+ log_unauth("kadm5_setkey_principal", prime_arg, &client_name,
+ &service_name, rqstp);
+ ret->code = KADM5_AUTH_SETKEY;
+ }
+ } else if (!(CHANGEPW_SERVICE(rqstp)) &&
+ kadm5int_acl_check(handle->context, rqst2name(rqstp),
+ ACL_SETKEY, arg->princ, NULL)) {
+ ret->code = kadm5_setkey_principal_4(handle, arg->princ, arg->keepold,
+ arg->key_data, arg->n_key_data);
+ } else {
+ log_unauth("kadm5_setkey_principal", prime_arg, &client_name,
+ &service_name, rqstp);
+ ret->code = KADM5_AUTH_SETKEY;
+ }
+
+ if (ret->code != KADM5_AUTH_SETKEY) {
+ if (ret->code != 0)
+ errmsg = krb5_get_error_message(handle->context, ret->code);
+
+ log_done("kadm5_setkey_principal", prime_arg, errmsg, &client_name,
+ &service_name, rqstp);
+
+ if (errmsg != NULL)
+ krb5_free_error_message(handle->context, errmsg);
+ }
+
+exit_func:
+ stub_cleanup(handle, prime_arg, &client_name, &service_name);
+ return TRUE;
+}
+
+/* Empty out *keys/*nkeys if princ is protected with the lockdown attribute, or
+ * if we fail to check. */
+static kadm5_ret_t
+chrand_check_lockdown(kadm5_server_handle_t handle, krb5_principal princ,
+ krb5_keyblock **keys, int *nkeys)
+{
+ kadm5_ret_t ret;
+ int i;
+
+ ret = check_lockdown_keys(handle, princ);
+ if (!ret)
+ return 0;
+
+ for (i = 0; i < *nkeys; i++)
+ krb5_free_keyblock_contents(handle->context, &((*keys)[i]));
+ free(*keys);
+ *keys = NULL;
+ *nkeys = 0;
+ return (ret == KADM5_PROTECT_KEYS) ? KADM5_OK : ret;
+}
+
+bool_t
+chrand_principal_2_svc(chrand_arg *arg, chrand_ret *ret, struct svc_req *rqstp)
+{
+ char *funcname, *prime_arg = NULL;
+ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
+ krb5_keyblock *k;
+ int nkeys;
+ kadm5_server_handle_t handle;
+ const char *errmsg = NULL;
+
+ ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
+ &ret->api_version, &client_name, &service_name,
+ &prime_arg);
+ if (ret->code)
+ goto exit_func;
+
+ funcname = "kadm5_randkey_principal";
+
+ if (cmp_gss_krb5_name(handle, rqst2name(rqstp), arg->princ)) {
+ ret->code = randkey_principal_wrapper_3(handle, arg->princ, FALSE, 0,
+ NULL, &k, &nkeys);
+ } else if (!(CHANGEPW_SERVICE(rqstp)) &&
+ kadm5int_acl_check(handle->context, rqst2name(rqstp),
+ ACL_CHANGEPW, arg->princ, NULL)) {
+ ret->code = kadm5_randkey_principal(handle, arg->princ, &k, &nkeys);
+ } else {
+ log_unauth(funcname, prime_arg,
+ &client_name, &service_name, rqstp);
+ ret->code = KADM5_AUTH_CHANGEPW;
+ }
+
+ if (ret->code == KADM5_OK) {
+ ret->code = chrand_check_lockdown(handle, arg->princ, &k, &nkeys);
+ if (ret->code == KADM5_PROTECT_KEYS)
+ ret->code = KADM5_OK;
+ ret->keys = k;
+ ret->n_keys = nkeys;
+ }
+
+ if (ret->code != KADM5_AUTH_CHANGEPW) {
+ if (ret->code != 0)
+ errmsg = krb5_get_error_message(handle->context, ret->code);
+
+ log_done(funcname, prime_arg, errmsg,
+ &client_name, &service_name, rqstp);
+
+ if (errmsg != NULL)
+ krb5_free_error_message(handle->context, errmsg);
+ }
+
+exit_func:
+ stub_cleanup(handle, prime_arg, &client_name, &service_name);
+ return TRUE;
+}
+
+bool_t
+chrand_principal3_2_svc(chrand3_arg *arg, chrand_ret *ret,
+ struct svc_req *rqstp)
+{
+ char *funcname, *prime_arg = NULL;
+ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
+ krb5_keyblock *k;
+ int nkeys;
+ kadm5_server_handle_t handle;
+ const char *errmsg = NULL;
+
+ ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
+ &ret->api_version, &client_name, &service_name,
+ &prime_arg);
+ if (ret->code)
+ goto exit_func;
+
+ funcname = "kadm5_randkey_principal";
+
+ if (cmp_gss_krb5_name(handle, rqst2name(rqstp), arg->princ)) {
+ ret->code = randkey_principal_wrapper_3(handle, arg->princ,
+ arg->keepold, arg->n_ks_tuple,
+ arg->ks_tuple, &k, &nkeys);
+ } else if (!(CHANGEPW_SERVICE(rqstp)) &&
+ kadm5int_acl_check(handle->context, rqst2name(rqstp),
+ ACL_CHANGEPW, arg->princ, NULL)) {
+ ret->code = kadm5_randkey_principal_3(handle, arg->princ, arg->keepold,
+ arg->n_ks_tuple, arg->ks_tuple,
+ &k, &nkeys);
+ } else {
+ log_unauth(funcname, prime_arg,
+ &client_name, &service_name, rqstp);
+ ret->code = KADM5_AUTH_CHANGEPW;
+ }
+
+ if (ret->code == KADM5_OK) {
+ ret->code = chrand_check_lockdown(handle, arg->princ, &k, &nkeys);
+ if (ret->code == KADM5_PROTECT_KEYS)
+ ret->code = KADM5_OK;
+ ret->keys = k;
+ ret->n_keys = nkeys;
+ }
+
+ if (ret->code != KADM5_AUTH_CHANGEPW) {
+ if (ret->code != 0)
+ errmsg = krb5_get_error_message(handle->context, ret->code);
+
+ log_done(funcname, prime_arg, errmsg,
+ &client_name, &service_name, rqstp);
+
+ if (errmsg != NULL)
+ krb5_free_error_message(handle->context, errmsg);
+ }
+
+exit_func:
+ stub_cleanup(handle, prime_arg, &client_name, &service_name);
+ return TRUE;
+}
+
+bool_t
+create_policy_2_svc(cpol_arg *arg, generic_ret *ret, struct svc_req *rqstp)
+{
+ char *prime_arg = NULL;
+ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
+ kadm5_server_handle_t handle;
+ const char *errmsg = NULL;
+
+ ret->code = stub_setup(arg->api_version, rqstp, NULL, &handle,
+ &ret->api_version, &client_name, &service_name,
+ NULL);
+ if (ret->code)
+ goto exit_func;
+
+ prime_arg = arg->rec.policy;
+
+ if (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context,
+ rqst2name(rqstp),
+ ACL_ADD, NULL, NULL)) {
+ ret->code = KADM5_AUTH_ADD;
+ log_unauth("kadm5_create_policy", prime_arg,
+ &client_name, &service_name, rqstp);
+
+ } else {
+ ret->code = kadm5_create_policy(handle, &arg->rec, arg->mask);
+ if (ret->code != 0)
+ errmsg = krb5_get_error_message(handle->context, ret->code);
+
+ log_done("kadm5_create_policy",
+ ((prime_arg == NULL) ? "(null)" : prime_arg), errmsg,
+ &client_name, &service_name, rqstp);
+
+ if (errmsg != NULL)
+ krb5_free_error_message(handle->context, errmsg);
+ }
+
+exit_func:
+ stub_cleanup(handle, NULL, &client_name, &service_name);
+ return TRUE;
+}
+
+bool_t
+delete_policy_2_svc(dpol_arg *arg, generic_ret *ret, struct svc_req *rqstp)
+{
+ char *prime_arg = NULL;
+ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
+ kadm5_server_handle_t handle;
+ const char *errmsg = NULL;
+
+ ret->code = stub_setup(arg->api_version, rqstp, NULL, &handle,
+ &ret->api_version, &client_name, &service_name,
+ NULL);
+ if (ret->code)
+ goto exit_func;
+
+ prime_arg = arg->name;
+
+ if (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context,
+ rqst2name(rqstp),
+ ACL_DELETE, NULL, NULL)) {
+ log_unauth("kadm5_delete_policy", prime_arg,
+ &client_name, &service_name, rqstp);
+ ret->code = KADM5_AUTH_DELETE;
+ } else {
+ ret->code = kadm5_delete_policy(handle, arg->name);
+ if (ret->code != 0)
+ errmsg = krb5_get_error_message(handle->context, ret->code);
+
+ log_done("kadm5_delete_policy",
+ ((prime_arg == NULL) ? "(null)" : prime_arg), errmsg,
+ &client_name, &service_name, rqstp);
+
+ if (errmsg != NULL)
+ krb5_free_error_message(handle->context, errmsg);
+ }
+
+exit_func:
+ stub_cleanup(handle, NULL, &client_name, &service_name);
+ return TRUE;
+}
+
+bool_t
+modify_policy_2_svc(mpol_arg *arg, generic_ret *ret, struct svc_req *rqstp)
+{
+ char *prime_arg = NULL;
+ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
+ kadm5_server_handle_t handle;
+ const char *errmsg = NULL;
+
+ ret->code = stub_setup(arg->api_version, rqstp, NULL, &handle,
+ &ret->api_version, &client_name, &service_name,
+ NULL);
+ if (ret->code)
+ goto exit_func;
+
+ prime_arg = arg->rec.policy;
+
+ if (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context,
+ rqst2name(rqstp),
+ ACL_MODIFY, NULL, NULL)) {
+ log_unauth("kadm5_modify_policy", prime_arg,
+ &client_name, &service_name, rqstp);
+ ret->code = KADM5_AUTH_MODIFY;
+ } else {
+ ret->code = kadm5_modify_policy(handle, &arg->rec, arg->mask);
+ if (ret->code != 0)
+ errmsg = krb5_get_error_message(handle->context, ret->code);
+
+ log_done("kadm5_modify_policy",
+ ((prime_arg == NULL) ? "(null)" : prime_arg), errmsg,
+ &client_name, &service_name, rqstp);
+
+ if (errmsg != NULL)
+ krb5_free_error_message(handle->context, errmsg);
+ }
+
+exit_func:
+ stub_cleanup(handle, NULL, &client_name, &service_name);
+ return TRUE;
+}
+
+bool_t
+get_policy_2_svc(gpol_arg *arg, gpol_ret *ret, struct svc_req *rqstp)
+{
+ char *funcname, *prime_arg = NULL;
+ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
+ kadm5_ret_t ret2;
+ kadm5_principal_ent_rec caller_ent;
+ kadm5_server_handle_t handle;
+ const char *errmsg = NULL;
+
+ ret->code = stub_setup(arg->api_version, rqstp, NULL, &handle,
+ &ret->api_version, &client_name, &service_name,
+ NULL);
+ if (ret->code)
+ goto exit_func;
+
+ funcname = "kadm5_get_policy";
+
+ prime_arg = arg->name;
+
+ ret->code = KADM5_AUTH_GET;
+ if (!CHANGEPW_SERVICE(rqstp) && kadm5int_acl_check(handle->context,
+ rqst2name(rqstp),
+ ACL_INQUIRE, NULL, NULL))
+ ret->code = KADM5_OK;
+ else {
+ ret->code = kadm5_get_principal(handle->lhandle,
+ handle->current_caller, &caller_ent,
+ KADM5_PRINCIPAL_NORMAL_MASK);
+ if (ret->code == KADM5_OK) {
+ if (caller_ent.aux_attributes & KADM5_POLICY &&
+ strcmp(caller_ent.policy, arg->name) == 0) {
+ ret->code = KADM5_OK;
+ } else {
+ ret->code = KADM5_AUTH_GET;
+ }
+ ret2 = kadm5_free_principal_ent(handle->lhandle,
+ &caller_ent);
+ ret->code = ret->code ? ret->code : ret2;
+ }
+ }
+
+ if (ret->code == KADM5_OK) {
+ ret->code = kadm5_get_policy(handle, arg->name, &ret->rec);
+
+ if (ret->code != 0)
+ errmsg = krb5_get_error_message(handle->context, ret->code);
+
+ log_done(funcname,
+ ((prime_arg == NULL) ? "(null)" : prime_arg), errmsg,
+ &client_name, &service_name, rqstp);
+ if (errmsg != NULL)
+ krb5_free_error_message(handle->context, errmsg);
+
+ } else {
+ log_unauth(funcname, prime_arg,
+ &client_name, &service_name, rqstp);
+ }
+
+exit_func:
+ stub_cleanup(handle, NULL, &client_name, &service_name);
+ return TRUE;
+}
+
+bool_t
+get_pols_2_svc(gpols_arg *arg, gpols_ret *ret, struct svc_req *rqstp)
+{
+ char *prime_arg = NULL;
+ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
+ kadm5_server_handle_t handle;
+ const char *errmsg = NULL;
+
+ ret->code = stub_setup(arg->api_version, rqstp, NULL, &handle,
+ &ret->api_version, &client_name, &service_name,
+ NULL);
+ if (ret->code)
+ goto exit_func;
+
+ prime_arg = arg->exp;
+ if (prime_arg == NULL)
+ prime_arg = "*";
+
+ if (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context,
+ rqst2name(rqstp),
+ ACL_LIST, NULL, NULL)) {
+ ret->code = KADM5_AUTH_LIST;
+ log_unauth("kadm5_get_policies", prime_arg,
+ &client_name, &service_name, rqstp);
+ } else {
+ ret->code = kadm5_get_policies(handle, arg->exp, &ret->pols,
+ &ret->count);
+ if (ret->code != 0)
+ errmsg = krb5_get_error_message(handle->context, ret->code);
+
+ log_done("kadm5_get_policies", prime_arg, errmsg,
+ &client_name, &service_name, rqstp);
+
+ if (errmsg != NULL)
+ krb5_free_error_message(handle->context, errmsg);
+ }
+
+exit_func:
+ stub_cleanup(handle, NULL, &client_name, &service_name);
+ return TRUE;
+}
+
+bool_t
+get_privs_2_svc(krb5_ui_4 *arg, getprivs_ret *ret, struct svc_req *rqstp)
+{
+ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
+ kadm5_server_handle_t handle;
+ const char *errmsg = NULL;
+
+ ret->code = stub_setup(*arg, rqstp, NULL, &handle, &ret->api_version,
+ &client_name, &service_name, NULL);
+ if (ret->code)
+ goto exit_func;
+
+ ret->code = kadm5_get_privs(handle, &ret->privs);
+ if (ret->code != 0)
+ errmsg = krb5_get_error_message(handle->context, ret->code);
+
+ log_done("kadm5_get_privs", client_name.value, errmsg,
+ &client_name, &service_name, rqstp);
+
+ if (errmsg != NULL)
+ krb5_free_error_message(handle->context, errmsg);
+
+exit_func:
+ stub_cleanup(handle, NULL, &client_name, &service_name);
+ return TRUE;
+}
+
+bool_t
+purgekeys_2_svc(purgekeys_arg *arg, generic_ret *ret, struct svc_req *rqstp)
+{
+ char *funcname, *prime_arg = NULL;
+ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
+ kadm5_server_handle_t handle;
+
+ const char *errmsg = NULL;
+
+ ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
+ &ret->api_version, &client_name, &service_name,
+ &prime_arg);
+ if (ret->code)
+ goto exit_func;
+
+ funcname = "kadm5_purgekeys";
+
+ if (!cmp_gss_krb5_name(handle, rqst2name(rqstp), arg->princ) &&
+ (CHANGEPW_SERVICE(rqstp)
+ || !kadm5int_acl_check(handle->context, rqst2name(rqstp), ACL_MODIFY,
+ arg->princ, NULL))) {
+ ret->code = KADM5_AUTH_MODIFY;
+ log_unauth(funcname, prime_arg, &client_name, &service_name, rqstp);
+ } else {
+ ret->code = kadm5_purgekeys(handle, arg->princ, arg->keepkvno);
+ if (ret->code != 0)
+ errmsg = krb5_get_error_message(handle->context, ret->code);
+
+ log_done(funcname, prime_arg, errmsg,
+ &client_name, &service_name, rqstp);
+
+ if (errmsg != NULL)
+ krb5_free_error_message(handle->context, errmsg);
+ }
+
+exit_func:
+ stub_cleanup(handle, prime_arg, &client_name, &service_name);
+ return TRUE;
+}
+
+bool_t
+get_strings_2_svc(gstrings_arg *arg, gstrings_ret *ret, struct svc_req *rqstp)
+{
+ char *prime_arg = NULL;
+ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
+ kadm5_server_handle_t handle;
+ const char *errmsg = NULL;
+
+ ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
+ &ret->api_version, &client_name, &service_name,
+ &prime_arg);
+ if (ret->code)
+ goto exit_func;
+
+ if (! cmp_gss_krb5_name(handle, rqst2name(rqstp), arg->princ) &&
+ (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context,
+ rqst2name(rqstp),
+ ACL_INQUIRE,
+ arg->princ,
+ NULL))) {
+ ret->code = KADM5_AUTH_GET;
+ log_unauth("kadm5_get_strings", prime_arg,
+ &client_name, &service_name, rqstp);
+ } else {
+ ret->code = kadm5_get_strings(handle, arg->princ, &ret->strings,
+ &ret->count);
+ if (ret->code != 0)
+ errmsg = krb5_get_error_message(handle->context, ret->code);
+
+ log_done("kadm5_get_strings", prime_arg, errmsg,
+ &client_name, &service_name, rqstp);
+
+ if (errmsg != NULL)
+ krb5_free_error_message(handle->context, errmsg);
+ }
+
+exit_func:
+ stub_cleanup(handle, prime_arg, &client_name, &service_name);
+ return TRUE;
+}
+
+bool_t
+set_string_2_svc(sstring_arg *arg, generic_ret *ret, struct svc_req *rqstp)
+{
+ char *prime_arg = NULL;
+ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
+ kadm5_server_handle_t handle;
+ const char *errmsg = NULL;
+
+ ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
+ &ret->api_version, &client_name, &service_name,
+ &prime_arg);
+ if (ret->code)
+ goto exit_func;
+
+ if (CHANGEPW_SERVICE(rqstp)
+ || !kadm5int_acl_check(handle->context, rqst2name(rqstp), ACL_MODIFY,
+ arg->princ, NULL)) {
+ ret->code = KADM5_AUTH_MODIFY;
+ log_unauth("kadm5_mod_strings", prime_arg,
+ &client_name, &service_name, rqstp);
+ } else {
+ ret->code = kadm5_set_string(handle, arg->princ, arg->key, arg->value);
+ if (ret->code != 0)
+ errmsg = krb5_get_error_message(handle->context, ret->code);
+
+ log_done("kadm5_mod_strings", prime_arg, errmsg,
+ &client_name, &service_name, rqstp);
+
+ if (errmsg != NULL)
+ krb5_free_error_message(handle->context, errmsg);
+ }
+
+exit_func:
+ stub_cleanup(handle, prime_arg, &client_name, &service_name);
+ return TRUE;
+}
+
+bool_t
+init_2_svc(krb5_ui_4 *arg, generic_ret *ret, struct svc_req *rqstp)
+{
+ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
+ kadm5_server_handle_t handle;
+ const char *errmsg = NULL;
+ size_t clen, slen;
+ char *cdots, *sdots;
+
+ ret->code = stub_setup(*arg, rqstp, NULL, &handle, &ret->api_version,
+ &client_name, &service_name, NULL);
+ if (ret->code)
+ goto exit_func;
+
+ if (ret->code != 0)
+ errmsg = krb5_get_error_message(handle->context, ret->code);
+
+ clen = client_name.length;
+ trunc_name(&clen, &cdots);
+ slen = service_name.length;
+ trunc_name(&slen, &sdots);
+ /* okay to cast lengths to int because trunc_name limits max value */
+ krb5_klog_syslog(LOG_NOTICE, _("Request: kadm5_init, %.*s%s, %s, "
+ "client=%.*s%s, service=%.*s%s, addr=%s, "
+ "vers=%d, flavor=%d"),
+ (int)clen, (char *)client_name.value, cdots,
+ errmsg ? errmsg : _("success"),
+ (int)clen, (char *)client_name.value, cdots,
+ (int)slen, (char *)service_name.value, sdots,
+ client_addr(rqstp->rq_xprt),
+ ret->api_version & ~(KADM5_API_VERSION_MASK),
+ rqstp->rq_cred.oa_flavor);
+ if (errmsg != NULL)
+ krb5_free_error_message(handle->context, errmsg);
+
+exit_func:
+ stub_cleanup(handle, NULL, &client_name, &service_name);
+ return TRUE;
+}
+
+gss_name_t
+rqst2name(struct svc_req *rqstp)
+{
+
+ if (rqstp->rq_cred.oa_flavor == RPCSEC_GSS)
+ return rqstp->rq_clntname;
+ else
+ return rqstp->rq_clntcred;
+}
+
+bool_t
+get_principal_keys_2_svc(getpkeys_arg *arg, getpkeys_ret *ret,
+ struct svc_req *rqstp)
+{
+ char *prime_arg = NULL;
+ gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
+ kadm5_server_handle_t handle;
+ const char *errmsg = NULL;
+
+ ret->code = stub_setup(arg->api_version, rqstp, arg->princ, &handle,
+ &ret->api_version, &client_name, &service_name,
+ &prime_arg);
+ if (ret->code)
+ goto exit_func;
+
+ if (!(CHANGEPW_SERVICE(rqstp)) &&
+ kadm5int_acl_check(handle->context, rqst2name(rqstp),
+ ACL_EXTRACT, arg->princ, NULL)) {
+ ret->code = kadm5_get_principal_keys(handle, arg->princ, arg->kvno,
+ &ret->key_data, &ret->n_key_data);
+ } else {
+ log_unauth("kadm5_get_principal_keys", prime_arg,
+ &client_name, &service_name, rqstp);
+ ret->code = KADM5_AUTH_EXTRACT;
+ }
+
+ if (ret->code == KADM5_OK) {
+ ret->code = check_lockdown_keys(handle, arg->princ);
+ if (ret->code != KADM5_OK) {
+ kadm5_free_kadm5_key_data(handle->context, ret->n_key_data,
+ ret->key_data);
+ ret->key_data = NULL;
+ ret->n_key_data = 0;
+ }
+ if (ret->code == KADM5_PROTECT_KEYS) {
+ log_unauth("kadm5_get_principal_keys", prime_arg,
+ &client_name, &service_name, rqstp);
+ ret->code = KADM5_AUTH_EXTRACT;
+ }
+ }
+
+ if (ret->code != KADM5_AUTH_EXTRACT) {
+ if (ret->code != 0)
+ errmsg = krb5_get_error_message(handle->context, ret->code);
+
+ log_done("kadm5_get_principal_keys", prime_arg, errmsg,
+ &client_name, &service_name, rqstp);
+
+ if (errmsg != NULL)
+ krb5_free_error_message(handle->context, errmsg);
+ }
+
+exit_func:
+ stub_cleanup(handle, prime_arg, &client_name, &service_name);
+ return TRUE;
+}