diff options
Diffstat (limited to 'src/kadmin/server')
| -rw-r--r-- | src/kadmin/server/Makefile.in | 15 | ||||
| -rw-r--r-- | src/kadmin/server/Makefile.ov | 39 | ||||
| -rw-r--r-- | src/kadmin/server/acls.l | 190 | ||||
| -rw-r--r-- | src/kadmin/server/configure.in | 17 | ||||
| -rw-r--r-- | src/kadmin/server/kadm_rpc_svc.c | 248 | ||||
| -rw-r--r-- | src/kadmin/server/misc.c | 138 | ||||
| -rw-r--r-- | src/kadmin/server/misc.h | 53 | ||||
| -rw-r--r-- | src/kadmin/server/ovsec_kadmd.c | 762 | ||||
| -rw-r--r-- | src/kadmin/server/server_glue_v1.c | 31 | ||||
| -rw-r--r-- | src/kadmin/server/server_stubs.c | 1045 |
10 files changed, 2538 insertions, 0 deletions
diff --git a/src/kadmin/server/Makefile.in b/src/kadmin/server/Makefile.in new file mode 100644 index 0000000000..41bea4f455 --- /dev/null +++ b/src/kadmin/server/Makefile.in @@ -0,0 +1,15 @@ +CFLAGS = $(CCOPTS) $(DEFS) $(LOCALINCLUDE) + +PROG = kadmind +OBJS = kadm_rpc_svc.o server_stubs.o ovsec_kadmd.o misc.o server_glue_v1.o + +all:: $(PROG) + +$(PROG): $(OBJS) $(DEPLIBS) + $(CC) $(LDFLAGS) $(LDARGS) -o $(PROG) $(OBJS) $(LIBS) + +install:: + $(INSTALL_PROGRAM) $(PROG) ${DESTDIR}$(ADMIN_BINDIR)/$(PROG) + +clean:: + $(RM) $(PROG) $(OBJS) diff --git a/src/kadmin/server/Makefile.ov b/src/kadmin/server/Makefile.ov new file mode 100644 index 0000000000..4f8e489fbb --- /dev/null +++ b/src/kadmin/server/Makefile.ov @@ -0,0 +1,39 @@ +TOP = .. +include $(TOP)/config.mk/template +CFLAGS := $(CFLAGS) + +ifdef KRB5B4 +CFLAGS += -DKRB5B4 +endif + +PROG := kadmind +SRCS := kadm_rpc_svc.c server_stubs.c ovsec_kadmd.c misc.c server_glue_v1.c +OBJS := kadm_rpc_svc.o server_stubs.o ovsec_kadmd.o misc.o server_glue_v1.o +LIBS := $(LIBADMSRV) $(LIBRPCLIB) $(LIBGSSAPI_KRB5) $(LIBDYN) \ + $(LIBKDB5) $(LIBKRB5_ALL) $(LIBDB) \ + $(NDBMLIB) $(NETLIB) $(BSDLIB) $(REGEXLIB) + +expand InstallServer +expand Depend + +clean:: + $(CLEAN) acls.c + +expand Saber + +SABER_LIBS := $(LIBDB) $(LIBGSSAPI_KRB5) $(LIBDYN) $(LIBKDB5) \ + $(LIBKRB5) $(LIBCRYPTO) $(LIBISODE) $(LIBCOM_ERR) +SABER_FLAGS := -G + +saber:: + #cd ../../rpc + #make saber + #cd ../admin/lib/adb + #make saber + #cd ../common + #make saber + #cd ../server + #make saber + #cd ../../server + #load /usr/local/lib/gcc-lib/sparc-sun-sunos4.1.3/2.4.5/libgcc.a + #load $(SABER_FLAGS) $(LDFLAGS) $(GSSLIB) $(SABER_LIBS) diff --git a/src/kadmin/server/acls.l b/src/kadmin/server/acls.l new file mode 100644 index 0000000000..aee4801e99 --- /dev/null +++ b/src/kadmin/server/acls.l @@ -0,0 +1,190 @@ +%{ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. + * + * $Id$ + * $Source$ + * + * $Log$ + * Revision 1.3 1996/07/22 20:28:49 marc + * this commit includes all the changes on the OV_9510_INTEGRATION and + * OV_MERGE branches. This includes, but is not limited to, the new openvision + * admin system, and major changes to gssapi to add functionality, and bring + * the implementation in line with rfc1964. before committing, the + * code was built and tested for netbsd and solaris. + * + * Revision 1.2.4.1 1996/07/18 03:03:31 marc + * merged in changes from OV_9510_BP to OV_9510_FINAL1 + * + * Revision 1.2.2.1 1996/06/20 21:56:31 marc + * File added to the repository on a branch + * + * Revision 1.2 1993/11/05 07:47:46 bjaspan + * add and use cmp_gss_names, fix regexp bug + * + * Revision 1.1 1993/11/05 07:08:48 bjaspan + * Initial revision + * + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +enum tokens { + NEWLINE = 257, + COMMA, + SEMI, + + GET = 300, + ADD, + MODIFY, + DELETE, + + ID = 350, +}; + +typedef union { + char *s; +} toktype; + +toktype tokval; +int acl_lineno = 0; + +%} + +%% + +\n acl_lineno++; +[ \t]* ; +[ ]*#.* ; +"," return (COMMA); +";" return (SEMI); +"get" return (GET); +"add" return (ADD); +"modify" return (MODIFY); +"delete" return (DELETE); +^[^ \t\n]+ { tokval.s = yytext; return (ID); } + +%% + +#include <string.h> +#include <syslog.h> +#include <gssapi/gssapi.h> +#include <gssapi/gssapi_krb5.h> +#include <ovsec_admin/admin.h> + +typedef struct _entry { + gss_name_t gss_name; + char *name; + u_int privs; + struct _entry *next; +} acl_entry; + +static acl_entry *acl_head = NULL; + +static void error(char *msg); + +int parse_aclfile(FILE *acl_file) +{ + OM_uint32 gssstat, minor_stat; + gss_buffer_desc in_buf; + acl_entry *entry; + enum tokens tok; + + yyin = acl_file; + + acl_lineno = 1; + while ((tok = yylex()) != 0) { + if (tok != ID) { + error("expected identifier"); + goto error; + } + + entry = (acl_entry *) malloc(sizeof(acl_entry)); + if (entry == NULL) { + error("out of memory"); + goto error; + } + entry->name = strdup(tokval.s); + entry->privs = 0; + while (1) { + switch (tok = yylex()) { + case GET: + entry->privs |= OVSEC_KADM_PRIV_GET; + break; + case ADD: + entry->privs |= OVSEC_KADM_PRIV_ADD; + break; + case MODIFY: + entry->privs |= OVSEC_KADM_PRIV_MODIFY; + break; + case DELETE: + entry->privs |= OVSEC_KADM_PRIV_DELETE; + break; + default: + error("expected privilege"); + goto error; + } + tok = yylex(); + if (tok == COMMA) + continue; + else if (tok == SEMI) + break; + else { + error("expected comma or semicolon"); + goto error; + } + } + + in_buf.value = entry->name; + in_buf.length = strlen(entry->name) + 1; + gssstat = gss_import_name(&minor_stat, &in_buf, + gss_nt_krb5_name, &entry->gss_name); + if (gssstat != GSS_S_COMPLETE) { + error("invalid name"); + goto error; + } + + if (acl_head == NULL) { + entry->next = NULL; + acl_head = entry; + } else { + entry->next = acl_head; + acl_head = entry; + } + } + return 0; + +error: + return 1; +} + +int acl_check(gss_name_t caller, int priv) +{ + acl_entry *entry; + + entry = acl_head; + while (entry) { + if (cmp_gss_names(entry->gss_name, caller) && entry->privs & priv) + return 1; + entry = entry->next; + } + return 0; +} + +int cmp_gss_names(gss_name_t name1, gss_name_t name2) +{ + OM_uint32 minor_stat; + int eq; + (void) gss_compare_name(&minor_stat, name1, name2, &eq); + return eq; +} + +static void error(char *msg) +{ + syslog(LOG_ERR, "Error while parsing acl file, line %d: %s\n", + acl_lineno, msg); +} + +yywrap() { return(1); } diff --git a/src/kadmin/server/configure.in b/src/kadmin/server/configure.in new file mode 100644 index 0000000000..98492f909c --- /dev/null +++ b/src/kadmin/server/configure.in @@ -0,0 +1,17 @@ +AC_INIT(ovsec_kadmd.c) +CONFIG_RULES +AC_PROG_INSTALL +dnl AC_CHECK_FUNCS(waitpid vsprintf) +dnl AC_CHECK_HEADERS(sys/select.h) +dnl CHECK_SIGNALS +dnl CHECK_SETJMP +dnl CHECK_WAIT_TYPE +dnl ET_RULES +USE_KADMSRV_LIBRARY +USE_GSSRPC_LIBRARY +USE_GSSAPI_LIBRARY +USE_KDB5_LIBRARY +USE_DYN_LIBRARY +KRB5_LIBRARIES +V5_USE_SHARED_LIB +V5_AC_OUTPUT_MAKEFILE diff --git a/src/kadmin/server/kadm_rpc_svc.c b/src/kadmin/server/kadm_rpc_svc.c new file mode 100644 index 0000000000..9128821d50 --- /dev/null +++ b/src/kadmin/server/kadm_rpc_svc.c @@ -0,0 +1,248 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved. + * + * $Id$ + * $Source$ + * + * $Log$ + * Revision 1.12 1996/07/22 20:28:53 marc + * this commit includes all the changes on the OV_9510_INTEGRATION and + * OV_MERGE branches. This includes, but is not limited to, the new openvision + * admin system, and major changes to gssapi to add functionality, and bring + * the implementation in line with rfc1964. before committing, the + * code was built and tested for netbsd and solaris. + * + * Revision 1.11.4.1 1996/07/18 03:03:35 marc + * merged in changes from OV_9510_BP to OV_9510_FINAL1 + * + * Revision 1.11.2.2 1996/07/09 20:07:57 marc + * * kadm_rpc_svc.c: renamed <ovsec_admin/foo.h> to <kadm5/foo.h> + * + * Revision 1.11.2.1 1996/06/20 21:56:44 marc + * File added to the repository on a branch + * + * Revision 1.11 1996/06/17 19:49:28 bjaspan + * use krb5_klog_syslog + * + * Revision 1.10 1996/05/29 21:07:53 bjaspan + * be a bit more loud when warning, and don't exit when args can't be freed + * + * Revision 1.9 1996/05/20 21:34:56 bjaspan + * log an error when sendreply fails + * + * Revision 1.8 1996/05/12 07:06:23 marc + * - fixup includes to match beta6 + * + * Revision 1.7 1995/08/01 19:25:59 bjaspan + * [secure/1318] allow retrieval of some/all principal/policy names + * + * Revision 1.6 1994/09/20 16:25:33 bjaspan + * [secure-admin/2436: API versioning fixes to various admin files] + * [secure-releng/2502: audit secure-admin/2436: random API versioning fixes] + * + * Sandbox: + * + * More API versioning stuff -- need to add api_version field to RPC + * return structures in addition to calling structures. + * + * Revision 1.6 1994/09/12 20:19:16 jik + * More API versioning stuff -- need to add api_version field to RPC + * return structures in addition to calling structures. + * + * Revision 1.5 1994/08/16 18:55:46 jik + * Versioning changes. + * + * Revision 1.4 1994/04/25 17:05:05 bjaspan + * [secure-admin/1832] accept old gssapi number, log error when number + * is wrong + * + * Revision 1.3 1993/11/15 02:30:54 shanzer + * added funky procedure header comments. + * + * Revision 1.2 1993/11/10 23:11:21 bjaspan + * added getprivs + * + * Revision 1.1 1993/11/05 07:09:00 bjaspan + * Initial revision + * + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#include <stdio.h> +#include <rpc/rpc.h> +#include <syslog.h> +#include <memory.h> +#include <kadm5/kadm_rpc.h> +#include <krb5.h> +#include <kadm5/admin.h> + +/* + * Function: kadm_1 + * + * Purpose: RPC proccessing procedure. + * originally generated from rpcgen + * + * Arguments: + * rqstp (input) rpc request structure + * transp (input) rpc transport structure + * (input/output) + * <return value> + * + * Requires: + * Effects: + * Modifies: + */ + +void kadm_1(rqstp, transp) + struct svc_req *rqstp; + register SVCXPRT *transp; +{ + union { + cprinc_arg create_principal_1_arg; + dprinc_arg delete_principal_1_arg; + mprinc_arg modify_principal_1_arg; + rprinc_arg rename_principal_1_arg; + gprinc_arg get_principal_1_arg; + chpass_arg chpass_principal_1_arg; + chrand_arg chrand_principal_1_arg; + cpol_arg create_policy_1_arg; + dpol_arg delete_policy_1_arg; + mpol_arg modify_policy_1_arg; + gpol_arg get_policy_1_arg; + } argument; + char *result; + bool_t (*xdr_argument)(), (*xdr_result)(); + char *(*local)(); + + if (rqstp->rq_cred.oa_flavor != AUTH_GSSAPI && + rqstp->rq_cred.oa_flavor != AUTH_GSSAPI_COMPAT) { + krb5_klog_syslog(LOG_ERR, "Authentication attempt failed: %s, invalid " + "RPC authentication flavor %d", + inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr), + rqstp->rq_cred.oa_flavor); + svcerr_weakauth(transp); + return; + } + + switch (rqstp->rq_proc) { + case NULLPROC: + (void) svc_sendreply(transp, xdr_void, (char *)NULL); + return; + + case CREATE_PRINCIPAL: + xdr_argument = xdr_cprinc_arg; + xdr_result = xdr_generic_ret; + local = (char *(*)()) create_principal_1; + break; + + case DELETE_PRINCIPAL: + xdr_argument = xdr_dprinc_arg; + xdr_result = xdr_generic_ret; + local = (char *(*)()) delete_principal_1; + break; + + case MODIFY_PRINCIPAL: + xdr_argument = xdr_mprinc_arg; + xdr_result = xdr_generic_ret; + local = (char *(*)()) modify_principal_1; + break; + + case RENAME_PRINCIPAL: + xdr_argument = xdr_rprinc_arg; + xdr_result = xdr_generic_ret; + local = (char *(*)()) rename_principal_1; + break; + + case GET_PRINCIPAL: + xdr_argument = xdr_gprinc_arg; + xdr_result = xdr_gprinc_ret; + local = (char *(*)()) get_principal_1; + break; + + case GET_PRINCS: + xdr_argument = xdr_gprincs_arg; + xdr_result = xdr_gprincs_ret; + local = (char *(*)()) get_princs_1; + break; + + case CHPASS_PRINCIPAL: + xdr_argument = xdr_chpass_arg; + xdr_result = xdr_generic_ret; + local = (char *(*)()) chpass_principal_1; + break; + + case CHRAND_PRINCIPAL: + xdr_argument = xdr_chrand_arg; + xdr_result = xdr_chrand_ret; + local = (char *(*)()) chrand_principal_1; + break; + + case CREATE_POLICY: + xdr_argument = xdr_cpol_arg; + xdr_result = xdr_generic_ret; + local = (char *(*)()) create_policy_1; + break; + + case DELETE_POLICY: + xdr_argument = xdr_dpol_arg; + xdr_result = xdr_generic_ret; + local = (char *(*)()) delete_policy_1; + break; + + case MODIFY_POLICY: + xdr_argument = xdr_mpol_arg; + xdr_result = xdr_generic_ret; + local = (char *(*)()) modify_policy_1; + break; + + case GET_POLICY: + xdr_argument = xdr_gpol_arg; + xdr_result = xdr_gpol_ret; + local = (char *(*)()) get_policy_1; + break; + + case GET_POLS: + xdr_argument = xdr_gpols_arg; + xdr_result = xdr_gpols_ret; + local = (char *(*)()) get_pols_1; + break; + + case GET_PRIVS: + xdr_argument = xdr_u_int32; + xdr_result = xdr_getprivs_ret; + local = (char *(*)()) get_privs_1; + break; + + case INIT: + xdr_argument = xdr_u_int32; + xdr_result = xdr_generic_ret; + local = (char *(*)()) init_1; + break; + + default: + krb5_klog_syslog(LOG_ERR, "Invalid OVSEC_KADM procedure number: %s, %d", + inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr), + rqstp->rq_proc); + svcerr_noproc(transp); + return; + } + memset((char *)&argument, 0, sizeof(argument)); + if (!svc_getargs(transp, xdr_argument, &argument)) { + svcerr_decode(transp); + return; + } + result = (*local)(&argument, rqstp); + if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { + krb5_klog_syslog(LOG_ERR, "WARNING! Unable to send function results, " + "continuing."); + svcerr_systemerr(transp); + } + if (!svc_freeargs(transp, xdr_argument, &argument)) { + krb5_klog_syslog(LOG_ERR, "WARNING! Unable to free arguments, " + "continuing."); + } + return; +} diff --git a/src/kadmin/server/misc.c b/src/kadmin/server/misc.c new file mode 100644 index 0000000000..9dc3d9d28f --- /dev/null +++ b/src/kadmin/server/misc.c @@ -0,0 +1,138 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved + * + * $Header$ + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#include <kadm5/adb.h> +#include <kadm5/server_internal.h> +#include <krb5/kdb.h> +#include "misc.h" + +/* + * Function: chpass_principal_wrapper + * + * Purpose: wrapper to kadm5_chpass_principal that checks to see if + * pw_min_life has been reached. if not it returns an error. + * otherwise it calls kadm5_chpass_principal + * + * Arguments: + * principal (input) krb5_principals whose password we are + * changing + * passoword (input) passowrd we are going to change to. + * <return value> 0 on sucsess error code on failure. + * + * Requires: + * kadm5_init to have been run. + * + * Effects: + * calls kadm5_chpass_principal which changes the kdb and the + * the admin db. + * + */ +kadm5_ret_t +chpass_principal_wrapper(void *server_handle, + krb5_principal principal, char *password) +{ + krb5_int32 now; + kadm5_ret_t ret; + kadm5_policy_ent_rec pol; + kadm5_principal_ent_rec princ; + kadm5_server_handle_t handle = server_handle; + + if (ret = krb5_timeofday(handle->context, &now)) + return ret; + + if((ret = kadm5_get_principal(handle->lhandle, principal, + &princ, + KADM5_PRINCIPAL_NORMAL_MASK)) != + KADM5_OK) + return ret; + if(princ.aux_attributes & KADM5_POLICY) { + if((ret=kadm5_get_policy(handle->lhandle, + princ.policy, &pol)) != KADM5_OK) { + (void) kadm5_free_principal_ent(handle->lhandle, &princ); + return ret; + } + if((now - princ.last_pwd_change) < pol.pw_min_life && + !(princ.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { + (void) kadm5_free_policy_ent(handle->lhandle, &pol); + (void) kadm5_free_principal_ent(handle->lhandle, &princ); + return KADM5_PASS_TOOSOON; + } + if (ret = kadm5_free_policy_ent(handle->lhandle, &pol)) { + (void) kadm5_free_principal_ent(handle->lhandle, &princ); + return ret; + } + } + if (ret = kadm5_free_principal_ent(handle->lhandle, &princ)) + return ret; + + return kadm5_chpass_principal(server_handle, principal, password); +} + + +/* + * Function: randkey_principal_wrapper + * + * Purpose: wrapper to kadm5_randkey_principal which checks the + passwords min. life. + * + * Arguments: + * principal (input) krb5_principal whose password we are + * changing + * key (output) new random key + * <return value> 0, error code on error. + * + * Requires: + * kadm5_init needs to be run + * + * Effects: + * calls kadm5_randkey_principal + * + */ +kadm5_ret_t +randkey_principal_wrapper(void *server_handle, + krb5_principal principal, + krb5_keyblock **keys, int *n_keys) +{ + + krb5_int32 now; + kadm5_ret_t ret; + kadm5_policy_ent_rec pol; + kadm5_principal_ent_rec princ; + kadm5_server_handle_t handle = server_handle; + + if (ret = krb5_timeofday(handle->context, &now)) + return ret; + + if((ret = kadm5_get_principal(handle->lhandle, + principal, &princ, + KADM5_PRINCIPAL_NORMAL_MASK)) != + OSA_ADB_OK) + return ret; + if(princ.aux_attributes & KADM5_POLICY) { + if((ret=kadm5_get_policy(handle->lhandle, + princ.policy, &pol)) != KADM5_OK) { + (void) kadm5_free_principal_ent(handle->lhandle, &princ); + return ret; + } + if((now - princ.last_pwd_change) < pol.pw_min_life && + !(princ.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) { + (void) kadm5_free_policy_ent(handle->lhandle, &pol); + (void) kadm5_free_principal_ent(handle->lhandle, &princ); + return KADM5_PASS_TOOSOON; + } + if (ret = kadm5_free_policy_ent(handle->lhandle, &pol)) { + (void) kadm5_free_principal_ent(handle->lhandle, &princ); + return ret; + } + } + if (ret = kadm5_free_principal_ent(handle->lhandle, &princ)) + return ret; + return kadm5_randkey_principal(server_handle, principal, keys, n_keys); +} diff --git a/src/kadmin/server/misc.h b/src/kadmin/server/misc.h new file mode 100644 index 0000000000..c92f5fe32f --- /dev/null +++ b/src/kadmin/server/misc.h @@ -0,0 +1,53 @@ +/* + * Copyright 1994 OpenVision Technologies, Inc., All Rights Reserved + * + * $Header$ + * + * $Log$ + * Revision 1.6 1996/07/22 20:28:56 marc + * this commit includes all the changes on the OV_9510_INTEGRATION and + * OV_MERGE branches. This includes, but is not limited to, the new openvision + * admin system, and major changes to gssapi to add functionality, and bring + * the implementation in line with rfc1964. before committing, the + * code was built and tested for netbsd and solaris. + * + * Revision 1.5.4.1 1996/07/18 03:03:40 marc + * merged in changes from OV_9510_BP to OV_9510_FINAL1 + * + * Revision 1.5.2.1 1996/06/20 21:57:20 marc + * File added to the repository on a branch + * + * Revision 1.5 1996/05/30 21:13:24 bjaspan + * kadm5_get_principal_v1 takes a kadm5_principal_ent_t_v1 + * add kadm5_get_policy_v1 + * + * Revision 1.4 1996/05/20 21:39:05 bjaspan + * rename to kadm5 + * add kadm5_get_principal_v1 + * + * Revision 1.3 1994/09/13 18:24:41 jik + * Back out randkey changes. + * + * Revision 1.2 1994/09/12 20:26:12 jik + * randkey_principal_wrapper now takes a new_kvno option. + * + * Revision 1.1 1994/08/11 17:00:44 jik + * Initial revision + * + */ + +kadm5_ret_t chpass_principal_wrapper(void *server_handle, + krb5_principal principal, + char *password); + +kadm5_ret_t randkey_principal_wrapper(void *server_handle, + krb5_principal principal, + krb5_keyblock **key, + int *n_keys); + +kadm5_ret_t kadm5_get_principal_v1(void *server_handle, + krb5_principal principal, + kadm5_principal_ent_t_v1 *ent); + +kadm5_ret_t kadm5_get_policy_v1(void *server_handle, kadm5_policy_t name, + kadm5_policy_ent_t *ent); diff --git a/src/kadmin/server/ovsec_kadmd.c b/src/kadmin/server/ovsec_kadmd.c new file mode 100644 index 0000000000..34f2338934 --- /dev/null +++ b/src/kadmin/server/ovsec_kadmd.c @@ -0,0 +1,762 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved + * + * $Header$ + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#include <stdio.h> +#include <signal.h> +#include <syslog.h> +#include <sys/types.h> +#ifdef _AIX +#include <sys/select.h> +#endif +#include <sys/time.h> +#include <sys/socket.h> +#include <unistd.h> +#include <netinet/in.h> +#include <arpa/inet.h> /* inet_ntoa */ +#include <netdb.h> +#include <rpc/rpc.h> +#include <gssapi/gssapi_krb5.h> +#include <rpc/auth_gssapi.h> +#include <kadm5/admin.h> +#include <kadm5/kadm_rpc.h> +#include <string.h> + +#ifdef PURIFY +#include "purify.h" + +int signal_pure_report = 0; +int signal_pure_clear = 0; +void request_pure_report(int); +void request_pure_clear(int); +#endif /* PURIFY */ + +int signal_request_exit = 0; +int signal_request_reset = 0; +void request_exit(int); +void request_reset_db(int); +void reset_db(void); +void sig_pipe(int); +void kadm_svc_run(void); + +#define TIMEOUT 15 + +gss_name_t gss_changepw_name = NULL, gss_oldchangepw_name = NULL; +void *global_server_handle; + +/* + * This is a kludge, but the server needs these constants to be + * compatible with old clients. They are defined in <kadm5/admin.h>, + * but only if USE_KADM5_API_VERSION == 1. + */ +#define OVSEC_KADM_ADMIN_SERVICE "ovsec_adm/admin" +#define OVSEC_KADM_CHANGEPW_SERVICE "ovsec_adm/changepw" + +/* + * This enables us to set the keytab that gss_acquire_cred uses, but + * it also restricts us to linking against the Kv5 GSS-API library. + * Since this is *k*admind, that shouldn't be a problem. + */ +extern char *krb5_defkeyname; + +char *build_princ_name(char *name, char *realm); +void log_badauth(OM_uint32 major, OM_uint32 minor, + struct sockaddr_in *addr, char *data); +void log_badverf(gss_name_t client_name, gss_name_t server_name, + struct svc_req *rqst, struct rpc_msg *msg, + char *data); +void log_miscerr(struct svc_req *rqst, struct rpc_msg *msg, char + *error, char *data); +void log_badauth_display_status(char *msg, OM_uint32 major, OM_uint32 minor); +void log_badauth_display_status_1(char *m, OM_uint32 code, int type, + int rec); + + +/* + * Function: usage + * + * Purpose: print out the server usage message + * + * Arguments: + * Requires: + * Effects: + * Modifies: + */ + +void usage() +{ + fprintf(stderr, "Usage: kadmind [-r realm] [-m] [-nofork] " + "[-port port-number]\n"); + exit(1); +} + +/* XXX yuck. the signal handlers need this */ +static krb5_context context; + +int main(int argc, char *argv[]) +{ + void kadm_1(struct svc_req *, SVCXPRT *); + register SVCXPRT *transp; + extern char *optarg; + extern int optind, opterr; + int ret, rlen, nofork, oldnames = 0; + OM_uint32 OMret; + char *whoami; + FILE *acl_file; + gss_buffer_desc in_buf; + struct servent *srv; + struct sockaddr_in addr; + int s; + short port = 0; + auth_gssapi_name names[4]; + kadm5_config_params params; + + names[0].name = names[1].name = names[2].name = names[3].name = NULL; + names[0].type = names[1].type = names[2].type = names[3].type = + gss_nt_krb5_name; + +#ifdef PURIFY + purify_start_batch(); +#endif /* PURIFY */ + whoami = argv[0]; + + nofork = 0; + + memset((char *) ¶ms, 0, sizeof(params)); + + argc--; argv++; + while (argc) { + if (strcmp(*argv, "-r") == 0) { + argc--; argv++; + if (!argc) + usage(); + params.realm = *argv; + params.mask |= KADM5_CONFIG_REALM; + argc--; argv++; + continue; + } else if (strcmp(*argv, "-m") == 0) { + params.mkey_from_kbd = 1; + params.mask |= KADM5_CONFIG_MKEY_FROM_KBD; + } else if (strcmp(*argv, "-nofork") == 0) { + nofork = 1; + } else if(strcmp(*argv, "-port") == 0) { + argc--; argv++; + if(!argc) + usage(); + params.kadmind_port = atoi(*argv); + params.mask |= KADM5_CONFIG_KADMIND_PORT; + } else + break; + argc--; argv++; + } + + if (argc != 0) + usage(); + + if (ret = krb5_init_context(&context)) { + fprintf(stderr, "%s: %s while initializing context, aborting\n", + whoami, error_message(ret)); + exit(1); + } + + krb5_klog_init(context, "admin_server", whoami, 1); + + if((ret = kadm5_init("kadmind", NULL, + NULL, ¶ms, + KADM5_STRUCT_VERSION, + KADM5_API_VERSION_2, + &global_server_handle)) != + KADM5_OK) { + krb5_klog_syslog(LOG_ERR, "%s while initializing, aborting", + error_message(ret)); + fprintf(stderr, "%s: %s while initializing, aborting\n", + whoami, error_message(ret)); + krb5_klog_close(); + exit(1); + } + + if (ret = kadm5_get_config_params(context, NULL, NULL, ¶ms, + ¶ms)) { + krb5_klog_syslog(LOG_ERR, "%s: %s while initializing, aborting\n", + whoami, error_message(ret)); + fprintf(stderr, "%s: %s while initializing, aborting\n", + whoami, error_message(ret)); + kadm5_destroy(global_server_handle); + krb5_klog_close(); + exit(1); + } + +#define REQUIRED_PARAMS (KADM5_CONFIG_REALM | KADM5_CONFIG_ACL_FILE | \ + KADM5_CONFIG_ADMIN_KEYTAB) + + if ((params.mask & REQUIRED_PARAMS) != REQUIRED_PARAMS) { + krb5_klog_syslog(LOG_ERR, "%s: Missing required configuration values " + "(%x) while initializing, aborting\n", whoami, + (params.mask & REQUIRED_PARAMS) ^ REQUIRED_PARAMS); + fprintf(stderr, "%s: Missing required configuration values " + "(%x) while initializing, aborting\n", whoami, + (params.mask & REQUIRED_PARAMS) ^ REQUIRED_PARAMS); + krb5_klog_close(); + kadm5_destroy(global_server_handle); + exit(1); + } + + memset(&addr, 0, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = htons(params.kadmind_port); + + if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + krb5_klog_syslog(LOG_ERR, "Cannot create TCP socket: %s", + error_message(errno)); + fprintf(stderr, "Cannot create TCP socket: %s", + error_message(errno)); + kadm5_destroy(global_server_handle); + krb5_klog_close(); + exit(1); + } + + #ifdef SO_REUSEADDR + /* the old admin server turned on SO_REUSEADDR for non-default + port numbers. this was necessary, on solaris, for the tests + to work. jhawk argues that the debug and production modes + should be the same. I think I agree, so I'm always going to set + SO_REUSEADDR. The other option is to have the unit tests wait + until the port is useable, or use a different port each time. + --marc */ + + { + int allowed; + + allowed = 1; + if (setsockopt(s, + SOL_SOCKET, + SO_REUSEADDR, + (char *) &allowed, + sizeof(allowed)) < 0) { + krb5_klog_syslog(LOG_ERR, "Cannot set SO_REUSEADDR: %s", + error_message(errno)); + fprintf(stderr, "Cannot set SO_REUSEADDR: %s", + error_message(errno)); + kadm5_destroy(global_server_handle); + krb5_klog_close(); + exit(1); + } + } + #endif + if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) { + int oerrno = errno; + fprintf(stderr, "%s: Cannot bind socket.\n", whoami); + fprintf(stderr, "bind: %s\n", error_message(oerrno)); + errno = oerrno; + krb5_klog_syslog(LOG_ERR, "Cannot bind socket: %m"); + if(oerrno == EADDRINUSE) { + char *w = strrchr(whoami, '/'); + if (w) { + w++; + } + else { + w = whoami; + } + fprintf(stderr, +"This probably means that another %s process is already\n" +"running, or that another program is using the server port (number %d)\n" +"after being assigned it by the RPC portmap deamon. If another\n" +"%s is already running, you should kill it before\n" +"restarting the server. If, on the other hand, another program is\n" +"using the server port, you should kill it before running\n" +"%s, and ensure that the conflict does not occur in the\n" +"future by making sure that %s is started on reboot\n" + "before portmap.\n", w, ntohs(addr.sin_port), w, w, w); + krb5_klog_syslog(LOG_ERR, "Check for already-running %s or for " + "another process using port %d", w, + htons(addr.sin_port)); + } + kadm5_destroy(global_server_handle); + krb5_klog_close(); + exit(1); + } + + transp = svctcp_create(s, 0, 0); + if(transp == NULL) { + fprintf(stderr, "%s: Cannot create RPC service.\n", whoami); + krb5_klog_syslog(LOG_ERR, "Cannot create RPC service: %m"); + kadm5_destroy(global_server_handle); + krb5_klog_close(); + exit(1); + } + if(!svc_register(transp, KADM, KADMVERS, kadm_1, 0)) { + fprintf(stderr, "%s: Cannot register RPC service.\n", whoami); + krb5_klog_syslog(LOG_ERR, "Cannot register RPC service, failing."); + kadm5_destroy(global_server_handle); + krb5_klog_close(); + exit(1); + } + + names[0].name = build_princ_name(KADM5_ADMIN_SERVICE, params.realm); + names[1].name = build_princ_name(KADM5_CHANGEPW_SERVICE, params.realm); + names[2].name = build_princ_name(OVSEC_KADM_ADMIN_SERVICE, params.realm); + names[3].name = build_princ_name(OVSEC_KADM_CHANGEPW_SERVICE, + params.realm); + if (names[0].name == NULL || names[1].name == NULL || + names[2].name == NULL || names[3].name == NULL) { + krb5_klog_syslog(LOG_ERR, "Cannot initialize GSS-API authentication, " + "failing."); + fprintf(stderr, "%s: Cannot initialize GSS-API authentication.\n", + whoami); + kadm5_destroy(global_server_handle); + krb5_klog_close(); + exit(1); + } + + krb5_defkeyname = params.admin_keytab; + + /* + * Try to acquire creds for the old OV services as well as the + * new names, but if that fails just fall back on the new names. + */ + if (_svcauth_gssapi_set_names(names, 4) == TRUE) + oldnames++; + if (!oldnames && _svcauth_gssapi_set_names(names, 2) == FALSE) { + krb5_klog_syslog(LOG_ERR, "Cannot initialize GSS-API authentication, " + "failing."); + fprintf(stderr, "%s: Cannot initialize GSS-API authentication.\n", + whoami); + kadm5_destroy(global_server_handle); + krb5_klog_close(); + exit(1); + } + + /* if set_names succeeded, this will too */ + in_buf.value = names[1].name; + in_buf.length = strlen(names[1].name) + 1; + (void) gss_import_name(&OMret, &in_buf, gss_nt_krb5_name, + &gss_changepw_name); + if (oldnames) { + in_buf.value = names[3].name; + in_buf.length = strlen(names[3].name) + 1; + (void) gss_import_name(&OMret, &in_buf, gss_nt_krb5_name, + &gss_oldchangepw_name); + } + + _svcauth_gssapi_set_log_badauth_func(log_badauth, NULL); + _svcauth_gssapi_set_log_badverf_func(log_badverf, NULL); + _svcauth_gssapi_set_log_miscerr_func(log_miscerr, NULL); + + if (ret = acl_init(context, 0, params.acl_file)) { + krb5_klog_syslog(LOG_ERR, "Cannot initialize acl file: %s", + error_message(ret)); + fprintf(stderr, "%s: Cannot initialize acl file: %s\n", + whoami, error_message(ret)); + kadm5_destroy(global_server_handle); + krb5_klog_close(); + exit(1); + } + + if (!nofork && (ret = daemon(0, 0))) { + ret = errno; + krb5_klog_syslog(LOG_ERR, "Cannot detach from tty: %s", error_message(ret)); + fprintf(stderr, "%s: Cannot detach from tty: %s\n", + whoami, error_message(ret)); + kadm5_destroy(global_server_handle); + krb5_klog_close(); + exit(1); + } + + signal(SIGINT, request_exit); + signal(SIGTERM, request_exit); + signal(SIGQUIT, request_exit); + signal(SIGHUP, request_reset_db); + signal(SIGPIPE, sig_pipe); +#ifdef PURIFY + signal(SIGUSR1, request_pure_report); + signal(SIGUSR2, request_pure_clear); +#endif /* PURIFY */ + krb5_klog_syslog(LOG_INFO, "starting"); + + kadm_svc_run(); + krb5_klog_syslog(LOG_INFO, "finished, exiting"); + kadm5_destroy(global_server_handle); + close(s); + krb5_klog_close(); + exit(2); +} + +/* + * Function: kadm_svc_run + * + * Purpose: modified version of sunrpc svc_run. + * which closes the database every TIMEOUT seconds. + * + * Arguments: + * Requires: + * Effects: + * Modifies: + */ + +void kadm_svc_run(void) +{ + fd_set rfd; + int sz = _rpc_dtablesize(); + struct timeval timeout; + + while(signal_request_exit == 0) { + if (signal_request_reset) + reset_db(); +#ifdef PURIFY + if (signal_pure_report) /* check to see if a report */ + /* should be dumped... */ + { + purify_new_reports(); + signal_pure_report = 0; + } + if (signal_pure_clear) /* ...before checking whether */ + /* the info should be cleared. */ + { + purify_clear_new_reports(); + signal_pure_clear = 0; + } +#endif /* PURIFY */ + timeout.tv_sec = TIMEOUT; + timeout.tv_usec = 0; + rfd = svc_fdset; + switch(select(sz, (fd_set *) &rfd, NULL, NULL, &timeout)) { + case -1: + if(errno == EINTR) + continue; + perror("select"); + return; + case 0: + reset_db(); + break; + default: + svc_getreqset(&rfd); + } + } +} + +#ifdef PURIFY +/* + * Function: request_pure_report + * + * Purpose: sets flag saying the server got a signal and that it should + * dump a purify report when convenient. + * + * Arguments: + * Requires: + * Effects: + * Modifies: + * sets signal_pure_report to one + */ + +void request_pure_report(int signum) +{ + krb5_klog_syslog(LOG_DEBUG, "Got signal to request a Purify report"); + signal_pure_report = 1; + return; +} + +/* + * Function: request_pure_clear + * + * Purpose: sets flag saying the server got a signal and that it should + * dump a purify report when convenient, then clear the + * purify tables. + * + * Arguments: + * Requires: + * Effects: + * Modifies: + * sets signal_pure_report to one + * sets signal_pure_clear to one + */ + +void request_pure_clear(int signum) +{ + krb5_klog_syslog(LOG_DEBUG, "Got signal to request a Purify report and clear the old Purify info"); + signal_pure_report = 1; + signal_pure_clear = 1; + return; +} +#endif /* PURIFY */ + +/* + * Function: request_reset_db + * + * Purpose: sets flag saying the server got a signal and that it should + * reset the database files when convenient. + * + * Arguments: + * Requires: + * Effects: + * Modifies: + * sets signal_request_reset to one + */ + +void request_reset_db(int signum) +{ + krb5_klog_syslog(LOG_DEBUG, "Got signal to request resetting the databases"); + signal_request_reset = 1; + return; +} + +/* + * Function: reset-db + * + * Purpose: flushes the currently opened database files to disk. + * + * Arguments: + * Requires: + * Effects: + * + * Currently, just sets signal_request_reset to 0. The kdb and adb + * libraries used to be sufficiently broken that it was prudent to + * close and reopen the databases periodically. They are no longer + * that broken, so this function is not necessary. + */ +void reset_db(void) +{ +#ifdef notdef + kadm5_ret_t ret; + + if (ret = kadm5_flush(global_server_handle)) { + krb5_klog_syslog(LOG_ERR, "FATAL ERROR! %s while flushing databases. " + "Databases may be corrupt! Aborting.", + error_message(ret)); + krb5_klog_close(); + exit(3); + } +#endif + + signal_request_reset = 0; + return; +} + +/* + * Function: request-exit + * + * Purpose: sets flags saying the server got a signal and that it + * should exit when convient. + * + * Arguments: + * Requires: + * Effects: + * modifies signal_request_exit which ideally makes the server exit + * at some point. + * + * Modifies: + * signal_request_exit + */ + +void request_exit(int signum) +{ + krb5_klog_syslog(LOG_DEBUG, "Got signal to request exit"); + signal_request_exit = 1; + return; +} + +/* + * Function: sig_pipe + * + * Purpose: SIGPIPE handler + * + * Effects: krb5_klog_syslogs a message that a SIGPIPE occurred and returns, + * thus causing the read() or write() to fail and, presumable, the RPC + * to recover. Otherwise, the process aborts. + */ +void sig_pipe(int unused) +{ + krb5_klog_syslog(LOG_NOTICE, "Warning: Received a SIGPIPE; probably a " + "client aborted. Continuing."); + return; +} + +/* + * Function: build_princ_name + * + * Purpose: takes a name and a realm and builds a string that can be + * consumed by krb5_parse_name. + * + * Arguments: + * name (input) name to be part of principal + * realm (input) realm part of principal + * <return value> char * pointing to "name@realm" + * + * Requires: + * name be non-null. + * + * Effects: + * Modifies: + */ + +char *build_princ_name(char *name, char *realm) +{ + char *fullname; + + fullname = (char *) malloc(strlen(name) + 1 + + (realm ? strlen(realm) + 1 : 0)); + if (fullname == NULL) + return NULL; + if (realm) + sprintf(fullname, "%s@%s", name, realm); + else + strcpy(fullname, name); + return fullname; +} + +/* + * Function: log_badverf + * + * Purpose: Call from GSS-API Sun RPC for garbled/forged/replayed/etc + * messages. + * + * Argiments: + * client_name (r) GSS-API client name + * server_name (r) GSS-API server name + * rqst (r) RPC service request + * msg (r) RPC message + * data (r) arbitrary data (NULL), not used + * + * Effects: + * + * Logs the invalid request via krb5_klog_syslog(); see functional spec for + * format. + */ +void log_badverf(gss_name_t client_name, gss_name_t server_name, + struct svc_req *rqst, struct rpc_msg *msg, char + *data) +{ + static const char *const proc_names[] = { + "kadm5_create_principal", + "kadm5_delete_principal", + "kadm5_modify_principal", + "kadm5_rename_principal", + "kadm5_get_principal", + "kadm5_chpass_principal", + "kadm5_randkey_principal", + "kadm5_create_policy", + "kadm5_delete_policy", + "kadm5_modify_policy", + "kadm5_get_policy", + "kadm5_get_privs", + }; + OM_uint32 minor; + gss_buffer_desc client, server; + gss_OID gss_type; + char *a; + + (void) gss_display_name(&minor, client_name, &client, &gss_type); + (void) gss_display_name(&minor, server_name, &server, &gss_type); + a = inet_ntoa(rqst->rq_xprt->xp_raddr.sin_addr); + + krb5_klog_syslog(LOG_NOTICE, "WARNING! Forged/garbled request: %s, " + "claimed client = %s, server = %s, addr = %s", + proc_names[msg->rm_call.cb_proc], client.value, + server.value, a); + + (void) gss_release_buffer(&minor, &client); + (void) gss_release_buffer(&minor, &server); +} + +/* + * Function: log_miscerr + * + * Purpose: Callback from GSS-API Sun RPC for miscellaneous errors + * + * Arguments: + * rqst (r) RPC service request + * msg (r) RPC message + * error (r) error message from RPC + * data (r) arbitrary data (NULL), not used + * + * Effects: + * + * Logs the error via krb5_klog_syslog(); see functional spec for + * format. + */ +void log_miscerr(struct svc_req *rqst, struct rpc_msg *msg, + char *error, char *data) +{ + char *a; + + a = inet_ntoa(rqst->rq_xprt->xp_raddr.sin_addr); + krb5_klog_syslog(LOG_NOTICE, "Miscellaneous RPC error: %s, %s", a, error); +} + + + +/* + * Function: log_badauth + * + * Purpose: Callback from GSS-API Sun RPC for authentication + * failures/errors. + * + * Arguments: + * major (r) GSS-API major status + * minor (r) GSS-API minor status + * addr (r) originating address + * data (r) arbitrary data (NULL), not used + * + * Effects: + * + * Logs the GSS-API error via krb5_klog_syslog(); see functional spec for + * format. + */ +void log_badauth(OM_uint32 major, OM_uint32 minor, + struct sockaddr_in *addr, char *data) +{ + char *a; + + /* Authentication attempt failed: <IP address>, <GSS-API error */ + /* strings> */ + + a = inet_ntoa(addr->sin_addr); + + krb5_klog_syslog(LOG_NOTICE, "Authentication attempt failed: %s, GSS-API " + "error strings are:", a); + log_badauth_display_status(" ", major, minor); + krb5_klog_syslog(LOG_NOTICE, " GSS-API error strings complete.\n"); +} + +void log_badauth_display_status(char *msg, OM_uint32 major, OM_uint32 minor) +{ + log_badauth_display_status_1(msg, major, GSS_C_GSS_CODE, 0); + log_badauth_display_status_1(msg, minor, GSS_C_MECH_CODE, 0); +} + +void log_badauth_display_status_1(char *m, OM_uint32 code, int type, + int rec) +{ + OM_uint32 gssstat, minor_stat; + gss_buffer_desc msg; + int msg_ctx; + + msg_ctx = 0; + while (1) { + gssstat = gss_display_status(&minor_stat, code, + type, GSS_C_NULL_OID, + &msg_ctx, &msg); + if (gssstat != GSS_S_COMPLETE) { + if (!rec) { + log_badauth_display_status_1(m,gssstat,GSS_C_GSS_CODE,1); + log_badauth_display_status_1(m, minor_stat, + GSS_C_MECH_CODE, 1); + } else + krb5_klog_syslog(LOG_ERR, "GSS-API authentication error %s: " + "recursive failure!\n", msg); + return; + } + + krb5_klog_syslog(LOG_NOTICE, "%s %s\n", m, (char *)msg.value); + (void) gss_release_buffer(&minor_stat, &msg); + + if (!msg_ctx) + break; + } +} diff --git a/src/kadmin/server/server_glue_v1.c b/src/kadmin/server/server_glue_v1.c new file mode 100644 index 0000000000..c0bec26e61 --- /dev/null +++ b/src/kadmin/server/server_glue_v1.c @@ -0,0 +1,31 @@ +#define USE_KADM5_API_VERSION 1 +#include <kadm5/admin.h> + +/* + * In server_stubs.c, kadmind has to be able to call kadm5 functions + * with the arguments appropriate for any api version. Because of the + * prototypes in admin.h, however, the compiler will only allow one + * set of arguments to be passed. This file exports the old api + * definitions with a different name, so they can be called from + * server_stubs.c, and just passes on the call to the real api + * function; it uses the old api version, however, so it can actually + * call the real api functions whereas server_stubs.c cannot. + * + * This is most useful for functions like kadm5_get_principal that + * take a different number of arguments based on API version. For + * kadm5_get_policy, the same thing could be accomplished with + * typecasts instead. + */ + +kadm5_ret_t kadm5_get_principal_v1(void *server_handle, + krb5_principal principal, + kadm5_principal_ent_t_v1 *ent) +{ + return kadm5_get_principal(server_handle, principal, ent); +} + +kadm5_ret_t kadm5_get_policy_v1(void *server_handle, kadm5_policy_t name, + kadm5_policy_ent_t *ent) +{ + return kadm5_get_policy(server_handle, name, ent); +} diff --git a/src/kadmin/server/server_stubs.c b/src/kadmin/server/server_stubs.c new file mode 100644 index 0000000000..8107160afa --- /dev/null +++ b/src/kadmin/server/server_stubs.c @@ -0,0 +1,1045 @@ +/* + * Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved + * + * $Header$ + */ + +#if !defined(lint) && !defined(__CODECENTER__) +static char *rcsid = "$Header$"; +#endif + +#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 "misc.h" + +#define LOG_UNAUTH "Unauthorized request: %s, %s, client=%s, service=%s, addr=%s" +#define LOG_DONE "Request: %s, %s, %s, client=%s, service=%s, addr=%s" + +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(acceptor_name(rqstp->rq_svccred), gss_changepw_name) |\ + (gss_oldchangepw_name && \ + cmp_gss_names(acceptor_name(rqstp->rq_svccred), \ + gss_oldchangepw_name))) + +int cmp_gss_names(gss_name_t n1, gss_name_t n2) +{ + OM_uint32 emaj, emin; + int equal; + + if (GSS_ERROR(emaj = gss_compare_name(&emin, n1, n2, &equal))) + return(0); + + return(equal); +} + +/* + * 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; + + 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, rqstp->rq_clntcred, + &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) +{ + krb5_free_principal(handle->context, handle->current_caller); + free(handle); +} + +/* + * 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(rqstp->rq_clntcred, 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); + return -1; + } + if (gss_name_to_string(server_gss_name, server_name) != 0) { + gss_release_buffer(&min_stat, client_name); + return -1; + } + return 0; +} + +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; +} + +int cmp_gss_krb5_name(kadm5_server_handle_t handle, + gss_name_t gss_name, krb5_principal princ) +{ + krb5_principal princ2; + int stat; + + if (! gss_to_krb5_name(handle, gss_name, &princ2)) + return 0; + stat = krb5_principal_compare(handle->context, princ, princ2); + krb5_free_principal(handle->context, princ2); + return stat; +} + +int gss_to_krb5_name(kadm5_server_handle_t handle, + gss_name_t gss_name, krb5_principal *princ) +{ + OM_uint32 stat, minor_stat; + gss_buffer_desc gss_str; + gss_OID gss_type; + int success; + + stat = gss_display_name(&minor_stat, gss_name, &gss_str, &gss_type); + if ((stat != GSS_S_COMPLETE) || (gss_type != gss_nt_krb5_name)) + return 0; + success = (krb5_parse_name(handle->context, gss_str.value, princ) == 0); + gss_release_buffer(&minor_stat, &gss_str); + return success; +} +int +gss_name_to_string(gss_name_t gss_name, gss_buffer_desc *str) +{ + OM_uint32 stat, minor_stat; + gss_OID gss_type; + int ret; + + stat = gss_display_name(&minor_stat, gss_name, str, &gss_type); + if ((stat != GSS_S_COMPLETE) || (gss_type != gss_nt_krb5_name)) + return 1; + return 0; +} + +generic_ret * +create_principal_1(cprinc_arg *arg, struct svc_req *rqstp) +{ + static generic_ret ret; + char *prime_arg; + gss_buffer_desc client_name, service_name; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + + xdr_free(xdr_generic_ret, &ret); + + if (ret.code = new_server_handle(arg->api_version, rqstp, &handle)) + return &ret; + + if (ret.code = check_handle((void *)handle)) { + free_server_handle(handle); + return &ret; + } + + ret.api_version = handle->api_version; + + if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { + ret.code = KADM5_FAILURE; + return &ret; + } + krb5_unparse_name(handle->context, arg->rec.principal, &prime_arg); + + if (CHANGEPW_SERVICE(rqstp) || !acl_check(handle->context, + rqstp->rq_clntcred, + ACL_ADD, + arg->rec.principal)) { + ret.code = KADM5_AUTH_ADD; + krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_create_principal", + prime_arg, client_name.value, service_name.value, + inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr)); + } else { + ret.code = kadm5_create_principal((void *)handle, + &arg->rec, arg->mask, + arg->passwd); + krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_create_principal", + prime_arg,((ret.code == 0) ? "success" : + error_message(ret.code)), + client_name.value, service_name.value, + inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr)); + } + free_server_handle(handle); + free(prime_arg); + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); + return &ret; +} + +generic_ret * +delete_principal_1(dprinc_arg *arg, struct svc_req *rqstp) +{ + static generic_ret ret; + char *prime_arg; + gss_buffer_desc client_name, + service_name; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + + xdr_free(xdr_generic_ret, &ret); + + if (ret.code = new_server_handle(arg->api_version, rqstp, &handle)) + return &ret; + + if (ret.code = check_handle((void *)handle)) { + free_server_handle(handle); + return &ret; + } + + ret.api_version = handle->api_version; + + if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { + ret.code = KADM5_FAILURE; + return &ret; + } + krb5_unparse_name(handle->context, arg->princ, &prime_arg); + + if (CHANGEPW_SERVICE(rqstp) || !acl_check(handle->context, + rqstp->rq_clntcred, + ACL_DELETE, + arg->princ)) { + ret.code = KADM5_AUTH_DELETE; + krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_delete_principal", + prime_arg, client_name.value, service_name.value, + inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr)); + } else { + ret.code = kadm5_delete_principal((void *)handle, arg->princ); + krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_delete_principal", prime_arg, + ((ret.code == 0) ? "success" : error_message(ret.code)), + client_name.value, service_name.value, + inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr)); + } + free(prime_arg); + free_server_handle(handle); + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); + return &ret; +} + +generic_ret * +modify_principal_1(mprinc_arg *arg, struct svc_req *rqstp) +{ + static generic_ret ret; + char *prime_arg; + gss_buffer_desc client_name, + service_name; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + + xdr_free(xdr_generic_ret, &ret); + + if (ret.code = new_server_handle(arg->api_version, rqstp, &handle)) + return &ret; + + if (ret.code = check_handle((void *)handle)) { + free_server_handle(handle); + return &ret; + } + + if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { + ret.code = KADM5_FAILURE; + return &ret; + } + krb5_unparse_name(handle->context, arg->rec.principal, &prime_arg); + + if (CHANGEPW_SERVICE(rqstp) || !acl_check(handle->context, + rqstp->rq_clntcred, + ACL_MODIFY, + arg->rec.principal)) { + ret.code = KADM5_AUTH_MODIFY; + krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_modify_principal", + prime_arg, client_name.value, service_name.value, + inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr)); + } else { + ret.code = kadm5_modify_principal((void *)handle, &arg->rec, + arg->mask); + krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_modify_principal", + prime_arg, ((ret.code == 0) ? "success" : + error_message(ret.code)), + client_name.value, service_name.value, + inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr)); + } + free_server_handle(handle); + free(prime_arg); + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); + return &ret; +} + +generic_ret * +rename_principal_1(rprinc_arg *arg, struct svc_req *rqstp) +{ + static generic_ret ret; + char *prime_arg1, + *prime_arg2; + char prime_arg[BUFSIZ]; + gss_buffer_desc client_name, + service_name; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + + xdr_free(xdr_generic_ret, &ret); + + if (ret.code = new_server_handle(arg->api_version, rqstp, &handle)) + return &ret; + + if (ret.code = check_handle((void *)handle)) { + free_server_handle(handle); + return &ret; + } + + if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { + ret.code = KADM5_FAILURE; + return &ret; + } + krb5_unparse_name(handle->context, arg->src, &prime_arg1); + krb5_unparse_name(handle->context, arg->dest, &prime_arg2); + sprintf(prime_arg, "%s to %s", prime_arg1, prime_arg2); + + ret.code = KADM5_OK; + if (! CHANGEPW_SERVICE(rqstp)) { + if (!acl_check(handle->context, rqstp->rq_clntcred, + ACL_DELETE, arg->src)) + ret.code = KADM5_AUTH_DELETE; + if (!acl_check(handle->context, rqstp->rq_clntcred, + ACL_ADD, arg->dest)) { + if (ret.code == KADM5_AUTH_DELETE) + ret.code = KADM5_AUTH_INSUFFICIENT; + else + ret.code = KADM5_AUTH_ADD; + } + } else + ret.code = KADM5_AUTH_INSUFFICIENT; + if (ret.code != KADM5_OK) { + krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_rename_principal", + prime_arg, client_name.value, service_name.value, + inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr)); + } else { + ret.code = kadm5_rename_principal((void *)handle, arg->src, + arg->dest); + krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_rename_principal", + prime_arg, ((ret.code == 0) ? "success" : + error_message(ret.code)), + client_name.value, service_name.value, + inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr)); + } + free_server_handle(handle); + free(prime_arg1); + free(prime_arg2); + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); + return &ret; +} + +gprinc_ret * +get_principal_1(gprinc_arg *arg, struct svc_req *rqstp) +{ + static gprinc_ret ret; + kadm5_principal_ent_t_v1 e; + char *prime_arg, *funcname; + gss_buffer_desc client_name, + service_name; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + + xdr_free(xdr_gprinc_ret, &ret); + + if (ret.code = new_server_handle(arg->api_version, rqstp, &handle)) + return &ret; + + if (ret.code = check_handle((void *)handle)) { + free_server_handle(handle); + return &ret; + } + + ret.api_version = handle->api_version; + + funcname = handle->api_version == KADM5_API_VERSION_1 ? + "kadm5_get_principal (V1)" : "kadm5_get_principal"; + + if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { + ret.code = KADM5_FAILURE; + return &ret; + } + krb5_unparse_name(handle->context, arg->princ, &prime_arg); + + if (! cmp_gss_krb5_name(handle, rqstp->rq_clntcred, arg->princ) && + (CHANGEPW_SERVICE(rqstp) || !acl_check(handle->context, + rqstp->rq_clntcred, + ACL_INQUIRE, + arg->princ))) { + ret.code = KADM5_AUTH_GET; + krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, funcname, + prime_arg, client_name.value, service_name.value, + inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr)); + } else { + if (handle->api_version == KADM5_API_VERSION_1) { + ret.code = kadm5_get_principal_v1((void *)handle, + arg->princ, &e); + if(ret.code == KADM5_OK) { + memcpy(&ret.rec, e, sizeof(kadm5_principal_ent_rec_v1)); + free(e); + } + } else { + ret.code = kadm5_get_principal((void *)handle, + arg->princ, &ret.rec, + arg->mask); + } + + krb5_klog_syslog(LOG_NOTICE, LOG_DONE, funcname, + prime_arg, + ((ret.code == 0) ? "success" : error_message(ret.code)), + client_name.value, service_name.value, + inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr)); + } + free_server_handle(handle); + free(prime_arg); + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); + return &ret; +} + +gprincs_ret * +get_princs_1(gprincs_arg *arg, struct svc_req *rqstp) +{ + static gprincs_ret ret; + char *prime_arg; + gss_buffer_desc client_name, + service_name; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + + xdr_free(xdr_gprincs_ret, &ret); + + if (ret.code = new_server_handle(arg->api_version, rqstp, &handle)) + return &ret; + + if (ret.code = check_handle((void *)handle)) { + free_server_handle(handle); + return &ret; + } + + ret.api_version = handle->api_version; + + if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { + ret.code = KADM5_FAILURE; + return &ret; + } + prime_arg = arg->exp; + if (prime_arg == NULL) + prime_arg = "*"; + + if (CHANGEPW_SERVICE(rqstp) || !acl_check(handle->context, + rqstp->rq_clntcred, + ACL_LIST, + NULL)) { + ret.code = KADM5_AUTH_LIST; + krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_get_principals", + prime_arg, client_name.value, service_name.value, + inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr)); + } else { + ret.code = kadm5_get_principals((void *)handle, + arg->exp, &ret.princs, + &ret.count); + krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_get_principals", + prime_arg, + ((ret.code == 0) ? "success" : error_message(ret.code)), + client_name.value, service_name.value, + inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr)); + } + free_server_handle(handle); + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); + return &ret; +} + +generic_ret * +chpass_principal_1(chpass_arg *arg, struct svc_req *rqstp) +{ + static generic_ret ret; + char *prime_arg; + gss_buffer_desc client_name, + service_name; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + + xdr_free(xdr_generic_ret, &ret); + + if (ret.code = new_server_handle(arg->api_version, rqstp, &handle)) + return &ret; + + if (ret.code = check_handle((void *)handle)) { + free_server_handle(handle); + return &ret; + } + + ret.api_version = handle->api_version; + + if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { + ret.code = KADM5_FAILURE; + return &ret; + } + krb5_unparse_name(handle->context, arg->princ, &prime_arg); + + if (cmp_gss_krb5_name(handle, rqstp->rq_clntcred, arg->princ)) { + ret.code = chpass_principal_wrapper((void *)handle, arg->princ, + arg->pass); + } else if (!(CHANGEPW_SERVICE(rqstp)) && + acl_check(handle->context, rqstp->rq_clntcred, + ACL_CHANGEPW, arg->princ)) { + ret.code = kadm5_chpass_principal((void *)handle, arg->princ, + arg->pass); + } else { + krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_chpass_principal", + prime_arg, client_name.value, service_name.value, + inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr)); + ret.code = KADM5_AUTH_CHANGEPW; + } + + if(ret.code != KADM5_AUTH_CHANGEPW) { + krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_chpass_principal", + prime_arg, ((ret.code == 0) ? "success" : + error_message(ret.code)), + client_name.value, service_name.value, + inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr)); + } + + free_server_handle(handle); + free(prime_arg); + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); + return &ret; +} + +chrand_ret * +chrand_principal_1(chrand_arg *arg, struct svc_req *rqstp) +{ + static chrand_ret ret; + krb5_keyblock *k; + int nkeys; + char *prime_arg, *funcname; + gss_buffer_desc client_name, + service_name; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + + xdr_free(xdr_chrand_ret, &ret); + + if (ret.code = new_server_handle(arg->api_version, rqstp, &handle)) + return &ret; + + if (ret.code = check_handle((void *)handle)) { + free_server_handle(handle); + return &ret; + } + + ret.api_version = handle->api_version; + + funcname = handle->api_version == KADM5_API_VERSION_1 ? + "kadm5_randkey_principal (V1)" : "kadm5_randkey_principal"; + + if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { + ret.code = KADM5_FAILURE; + return &ret; + } + krb5_unparse_name(handle->context, arg->princ, &prime_arg); + + if (cmp_gss_krb5_name(handle, rqstp->rq_clntcred, arg->princ)) { + ret.code = randkey_principal_wrapper((void *)handle, + arg->princ, &k, &nkeys); + } else if (!(CHANGEPW_SERVICE(rqstp)) && + acl_check(handle->context, rqstp->rq_clntcred, + ACL_CHANGEPW, arg->princ)) { + ret.code = kadm5_randkey_principal((void *)handle, arg->princ, + &k, &nkeys); + } else { + krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, funcname, + prime_arg, client_name.value, service_name.value, + inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr)); + ret.code = KADM5_AUTH_CHANGEPW; + } + + if(ret.code == KADM5_OK) { + if (handle->api_version == KADM5_API_VERSION_1) { + krb5_copy_keyblock_contents(handle->context, k, &ret.key); + krb5_free_keyblock(handle->context, k); + } else { + ret.keys = k; + ret.n_keys = nkeys; + } + } + + if(ret.code != KADM5_AUTH_CHANGEPW) { + krb5_klog_syslog(LOG_NOTICE, LOG_DONE, funcname, + prime_arg, ((ret.code == 0) ? "success" : + error_message(ret.code)), + client_name.value, service_name.value, + inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr)); + } + free_server_handle(handle); + free(prime_arg); + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); + return &ret; +} + +generic_ret * +create_policy_1(cpol_arg *arg, struct svc_req *rqstp) +{ + static generic_ret ret; + char *prime_arg; + gss_buffer_desc client_name, + service_name; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + + xdr_free(xdr_generic_ret, &ret); + + if (ret.code = new_server_handle(arg->api_version, rqstp, &handle)) + return &ret; + + if (ret.code = check_handle((void *)handle)) { + free_server_handle(handle); + return &ret; + } + + ret.api_version = handle->api_version; + + if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { + ret.code = KADM5_FAILURE; + return &ret; + } + prime_arg = arg->rec.policy; + + if (CHANGEPW_SERVICE(rqstp) || !acl_check(handle->context, + rqstp->rq_clntcred, + ACL_ADD, NULL)) { + ret.code = KADM5_AUTH_ADD; + krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_create_policy", + prime_arg, client_name.value, service_name.value, + inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr)); + + } else { + ret.code = kadm5_create_policy((void *)handle, &arg->rec, + arg->mask); + krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_create_policy", + ((prime_arg == NULL) ? "(null)" : prime_arg), + ((ret.code == 0) ? "success" : error_message(ret.code)), + client_name.value, service_name.value, + inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr)); + } + free_server_handle(handle); + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); + return &ret; +} + +generic_ret * +delete_policy_1(dpol_arg *arg, struct svc_req *rqstp) +{ + static generic_ret ret; + char *prime_arg; + gss_buffer_desc client_name, + service_name; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + + xdr_free(xdr_generic_ret, &ret); + + if (ret.code = new_server_handle(arg->api_version, rqstp, &handle)) + return &ret; + + if (ret.code = check_handle((void *)handle)) { + free_server_handle(handle); + return &ret; + } + + ret.api_version = handle->api_version; + + if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { + ret.code = KADM5_FAILURE; + return &ret; + } + prime_arg = arg->name; + + if (CHANGEPW_SERVICE(rqstp) || !acl_check(handle->context, + rqstp->rq_clntcred, + ACL_DELETE, NULL)) { + krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_delete_policy", + prime_arg, client_name.value, service_name.value, + inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr)); + ret.code = KADM5_AUTH_DELETE; + } else { + ret.code = kadm5_delete_policy((void *)handle, arg->name); + krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_delete_policy", + ((prime_arg == NULL) ? "(null)" : prime_arg), + ((ret.code == 0) ? "success" : error_message(ret.code)), + client_name.value, service_name.value, + inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr)); + } + free_server_handle(handle); + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); + return &ret; +} + +generic_ret * +modify_policy_1(mpol_arg *arg, struct svc_req *rqstp) +{ + static generic_ret ret; + char *prime_arg; + gss_buffer_desc client_name, + service_name; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + + xdr_free(xdr_generic_ret, &ret); + + if (ret.code = new_server_handle(arg->api_version, rqstp, &handle)) + return &ret; + + if (ret.code = check_handle((void *)handle)) { + free_server_handle(handle); + return &ret; + } + + ret.api_version = handle->api_version; + + if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { + ret.code = KADM5_FAILURE; + return &ret; + } + prime_arg = arg->rec.policy; + + if (CHANGEPW_SERVICE(rqstp) || !acl_check(handle->context, + rqstp->rq_clntcred, + ACL_MODIFY, NULL)) { + krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_modify_policy", + prime_arg, client_name.value, service_name.value, + inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr)); + ret.code = KADM5_AUTH_MODIFY; + } else { + ret.code = kadm5_modify_policy((void *)handle, &arg->rec, + arg->mask); + krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_modify_policy", + ((prime_arg == NULL) ? "(null)" : prime_arg), + ((ret.code == 0) ? "success" : error_message(ret.code)), + client_name.value, service_name.value, + inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr)); + } + free_server_handle(handle); + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); + return &ret; +} + +gpol_ret * +get_policy_1(gpol_arg *arg, struct svc_req *rqstp) +{ + static gpol_ret ret; + kadm5_ret_t ret2; + char *prime_arg, *funcname; + gss_buffer_desc client_name, + service_name; + OM_uint32 minor_stat; + kadm5_policy_ent_t e; + kadm5_principal_ent_rec caller_ent; + krb5_principal caller; + kadm5_server_handle_t handle; + + xdr_free(xdr_gpol_ret, &ret); + + if (ret.code = new_server_handle(arg->api_version, rqstp, &handle)) + return &ret; + + if (ret.code = check_handle((void *)handle)) { + free_server_handle(handle); + return &ret; + } + + ret.api_version = handle->api_version; + + funcname = handle->api_version == KADM5_API_VERSION_1 ? + "kadm5_get_policy (V1)" : "kadm5_get_policy"; + + if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { + ret.code = KADM5_FAILURE; + return &ret; + } + prime_arg = arg->name; + + ret.code = KADM5_AUTH_GET; + if (!CHANGEPW_SERVICE(rqstp) && acl_check(handle->context, + rqstp->rq_clntcred, + ACL_INQUIRE, 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) { + if (handle->api_version == KADM5_API_VERSION_1) { + ret.code = kadm5_get_policy_v1((void *)handle, arg->name, &e); + if(ret.code == KADM5_OK) { + memcpy(&ret.rec, e, sizeof(kadm5_policy_ent_rec)); + free(e); + } + } else { + ret.code = kadm5_get_policy((void *)handle, arg->name, + &ret.rec); + } + + krb5_klog_syslog(LOG_NOTICE, LOG_DONE, funcname, + ((prime_arg == NULL) ? "(null)" : prime_arg), + ((ret.code == 0) ? "success" : error_message(ret.code)), + client_name.value, service_name.value, + inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr)); + } else { + krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, funcname, + prime_arg, client_name.value, service_name.value, + inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr)); + } + free_server_handle(handle); + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); + return &ret; + +} + +gpols_ret * +get_pols_1(gpols_arg *arg, struct svc_req *rqstp) +{ + static gpols_ret ret; + char *prime_arg; + gss_buffer_desc client_name, + service_name; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + + xdr_free(xdr_gpols_ret, &ret); + + if (ret.code = new_server_handle(arg->api_version, rqstp, &handle)) + return &ret; + + if (ret.code = check_handle((void *)handle)) { + free_server_handle(handle); + return &ret; + } + + ret.api_version = handle->api_version; + + if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { + ret.code = KADM5_FAILURE; + return &ret; + } + prime_arg = arg->exp; + if (prime_arg == NULL) + prime_arg = "*"; + + if (CHANGEPW_SERVICE(rqstp) || !acl_check(handle->context, + rqstp->rq_clntcred, + ACL_LIST, NULL)) { + ret.code = KADM5_AUTH_LIST; + krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_get_policies", + prime_arg, client_name.value, service_name.value, + inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr)); + } else { + ret.code = kadm5_get_policies((void *)handle, + arg->exp, &ret.pols, + &ret.count); + krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_get_policies", + prime_arg, + ((ret.code == 0) ? "success" : error_message(ret.code)), + client_name.value, service_name.value, + inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr)); + } + free_server_handle(handle); + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); + return &ret; +} + +getprivs_ret * get_privs_1(krb5_ui_4 *arg, struct svc_req *rqstp) +{ + static getprivs_ret ret; + char *prime_arg; + gss_buffer_desc client_name, service_name; + OM_uint32 minor_stat; + kadm5_server_handle_t handle; + + xdr_free(xdr_getprivs_ret, &ret); + + if (ret.code = new_server_handle(*arg, rqstp, &handle)) + return &ret; + + if (ret.code = check_handle((void *)handle)) { + free_server_handle(handle); + return &ret; + } + + ret.api_version = handle->api_version; + + if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { + ret.code = KADM5_FAILURE; + return &ret; + } + + ret.code = kadm5_get_privs((void *)handle, &ret.privs); + krb5_klog_syslog(LOG_NOTICE, LOG_DONE, "kadm5_get_privs", + client_name.value, + ((ret.code == 0) ? "success" : error_message(ret.code)), + client_name.value, service_name.value, + inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr)); + free_server_handle(handle); + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); + return &ret; +} + +generic_ret *init_1(krb5_ui_4 *arg, struct svc_req *rqstp) +{ + static generic_ret ret; + gss_buffer_desc client_name, + service_name; + kadm5_server_handle_t handle; + OM_uint32 minor_stat; + + xdr_free(xdr_generic_ret, &ret); + + if (ret.code = new_server_handle(*arg, rqstp, &handle)) + return &ret; + if (! (ret.code = check_handle((void *)handle))) { + ret.api_version = handle->api_version; + } + + free_server_handle(handle); + + if (setup_gss_names(rqstp, &client_name, &service_name) < 0) { + ret.code = KADM5_FAILURE; + return &ret; + } + + krb5_klog_syslog(LOG_NOTICE, LOG_DONE, + (ret.api_version == KADM5_API_VERSION_1 ? + "kadm5_init (V1)" : "kadm5_init"), + client_name.value, + (ret.code == 0) ? "success" : error_message(ret.code), + client_name.value, service_name.value, + inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr)); + gss_release_buffer(&minor_stat, &client_name); + gss_release_buffer(&minor_stat, &service_name); + + return(&ret); +} |
