diff options
Diffstat (limited to 'src/kadmin/server/server_stubs.c')
| -rw-r--r-- | src/kadmin/server/server_stubs.c | 1707 |
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; +} |
