summaryrefslogtreecommitdiffstats
path: root/src/kadmin/server
diff options
context:
space:
mode:
Diffstat (limited to 'src/kadmin/server')
-rw-r--r--src/kadmin/server/Makefile.in15
-rw-r--r--src/kadmin/server/Makefile.ov39
-rw-r--r--src/kadmin/server/acls.l190
-rw-r--r--src/kadmin/server/configure.in17
-rw-r--r--src/kadmin/server/kadm_rpc_svc.c248
-rw-r--r--src/kadmin/server/misc.c138
-rw-r--r--src/kadmin/server/misc.h53
-rw-r--r--src/kadmin/server/ovsec_kadmd.c762
-rw-r--r--src/kadmin/server/server_glue_v1.c31
-rw-r--r--src/kadmin/server/server_stubs.c1045
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 *) &params, 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, &params,
+ 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, &params,
+ &params)) {
+ 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);
+}