summaryrefslogtreecommitdiffstats
path: root/src/kadmin/server
diff options
context:
space:
mode:
authorMarc Horowitz <marc@mit.edu>1996-07-22 20:49:46 +0000
committerMarc Horowitz <marc@mit.edu>1996-07-22 20:49:46 +0000
commitedf8b4d8a6a665c2aa150993cd813ea6c5cf12e1 (patch)
tree6c2974a97b448c040fa4a31708ec5e02f187526c /src/kadmin/server
parent013bb1391582ed9e653ae706e398ddb8d08cfcc9 (diff)
downloadkrb5-edf8b4d8a6a665c2aa150993cd813ea6c5cf12e1.tar.gz
krb5-edf8b4d8a6a665c2aa150993cd813ea6c5cf12e1.tar.xz
krb5-edf8b4d8a6a665c2aa150993cd813ea6c5cf12e1.zip
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. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@8774 dc483132-0cff-0310-8789-dd5450dbe970
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 000000000..41bea4f45
--- /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 000000000..4f8e489fb
--- /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 000000000..aee4801e9
--- /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 000000000..98492f909
--- /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 000000000..9128821d5
--- /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 000000000..9dc3d9d28
--- /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 000000000..c92f5fe32
--- /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 000000000..34f233893
--- /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 000000000..c0bec26e6
--- /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 000000000..8107160af
--- /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);
+}