summaryrefslogtreecommitdiff
path: root/src/kadmin/server
diff options
context:
space:
mode:
Diffstat (limited to 'src/kadmin/server')
-rw-r--r--src/kadmin/server/Makefile.in6
-rw-r--r--src/kadmin/server/auth.c314
-rw-r--r--src/kadmin/server/auth.h85
-rw-r--r--src/kadmin/server/auth_acl.c755
-rw-r--r--src/kadmin/server/auth_self.c77
-rw-r--r--src/kadmin/server/deps109
-rw-r--r--src/kadmin/server/ipropd_svc.c38
-rw-r--r--src/kadmin/server/misc.c127
-rw-r--r--src/kadmin/server/misc.h17
-rw-r--r--src/kadmin/server/ovsec_kadmd.c8
-rw-r--r--src/kadmin/server/schpw.c49
-rw-r--r--src/kadmin/server/server_stubs.c340
12 files changed, 1528 insertions, 397 deletions
diff --git a/src/kadmin/server/Makefile.in b/src/kadmin/server/Makefile.in
index 3a013a4d4e15..16d5cc54aa4c 100644
--- a/src/kadmin/server/Makefile.in
+++ b/src/kadmin/server/Makefile.in
@@ -7,8 +7,10 @@ LOCALINCLUDES = -I$(top_srcdir)/lib/gssapi/generic \
-I$(BUILDTOP)/lib/gssapi/krb5 -I$(top_srcdir)/lib/kadm5/srv
PROG = kadmind
-OBJS = kadm_rpc_svc.o server_stubs.o ovsec_kadmd.o schpw.o misc.o ipropd_svc.o
-SRCS = kadm_rpc_svc.c server_stubs.c ovsec_kadmd.c schpw.c misc.c ipropd_svc.c
+OBJS = auth.o auth_acl.o auth_self.o kadm_rpc_svc.o server_stubs.o \
+ ovsec_kadmd.o schpw.o misc.o ipropd_svc.o
+SRCS = auth.o auth_acl.c auth_self.c kadm_rpc_svc.c server_stubs.c \
+ ovsec_kadmd.c schpw.c misc.c ipropd_svc.c
all: $(PROG)
diff --git a/src/kadmin/server/auth.c b/src/kadmin/server/auth.c
new file mode 100644
index 000000000000..081b20a8b678
--- /dev/null
+++ b/src/kadmin/server/auth.c
@@ -0,0 +1,314 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* kadmin/server/auth.c - kadm5_auth pluggable interface consumer */
+/*
+ * Copyright (C) 2017 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "k5-int.h"
+#include <kadm5/admin.h>
+#include <krb5/kadm5_auth_plugin.h>
+#include "auth.h"
+
+typedef struct {
+ struct kadm5_auth_vtable_st vt;
+ kadm5_auth_moddata data;
+} *auth_handle;
+
+static auth_handle *handles;
+
+void
+auth_fini(krb5_context context)
+{
+ auth_handle *hp, h;
+
+ if (handles == NULL)
+ return;
+ for (hp = handles; *hp != NULL; hp++) {
+ h = *hp;
+ if (h->vt.fini != NULL)
+ h->vt.fini(context, h->data);
+ free(h);
+ }
+ free(handles);
+ handles = NULL;
+}
+
+krb5_error_code
+auth_init(krb5_context context, const char *acl_file)
+{
+ krb5_error_code ret;
+ krb5_plugin_initvt_fn *modules = NULL, *mod;
+ size_t count;
+ auth_handle h = NULL;
+ const int intf = PLUGIN_INTERFACE_KADM5_AUTH;
+
+ ret = k5_plugin_register(context, intf, "acl", kadm5_auth_acl_initvt);
+ if (ret)
+ goto cleanup;
+ ret = k5_plugin_register(context, intf, "self", kadm5_auth_self_initvt);
+ if (ret)
+ goto cleanup;
+ ret = k5_plugin_load_all(context, PLUGIN_INTERFACE_KADM5_AUTH, &modules);
+ if (ret)
+ goto cleanup;
+
+ /* Allocate a large enough list of handles. */
+ for (count = 0; modules[count] != NULL; count++);
+ handles = k5calloc(count + 1, sizeof(*handles), &ret);
+ if (handles == NULL)
+ goto cleanup;
+
+ /* For each module, allocate a handle, initialize its vtable, and
+ * initialize its module data. */
+ count = 0;
+ for (mod = modules; *mod != NULL; mod++) {
+ h = k5alloc(sizeof(*h), &ret);
+ if (h == NULL)
+ goto cleanup;
+ ret = (*mod)(context, 1, 1, (krb5_plugin_vtable)&h->vt);
+ if (ret) { /* Failed vtable init is non-fatal. */
+ TRACE_KADM5_AUTH_VTINIT_FAIL(context, ret);
+ free(h);
+ h = NULL;
+ continue;
+ }
+ h->data = NULL;
+ if (h->vt.init != NULL) {
+ ret = h->vt.init(context, acl_file, &h->data);
+ if (ret == KRB5_PLUGIN_NO_HANDLE) {
+ TRACE_KADM5_AUTH_INIT_SKIP(context, h->vt.name);
+ free(h);
+ h = NULL;
+ continue;
+ }
+ if (ret) {
+ TRACE_KADM5_AUTH_INIT_FAIL(context, h->vt.name, ret);
+ goto cleanup;
+ }
+ }
+ handles[count++] = h;
+ handles[count] = NULL;
+ h = NULL;
+ }
+
+ ret = 0;
+
+cleanup:
+ if (ret)
+ auth_fini(context);
+ free(h);
+ k5_plugin_free_modules(context, modules);
+ return ret;
+}
+
+/* Invoke the appropriate method from h->vt for opcode, passing client and the
+ * correct subset of p1, p2, s1, s2, polent, and mask for the method. */
+static krb5_error_code
+call_module(krb5_context context, auth_handle h, int opcode,
+ krb5_const_principal client, krb5_const_principal p1,
+ krb5_const_principal p2, const char *s1, const char *s2,
+ const kadm5_policy_ent_rec *polent, long mask)
+{
+ /* addprinc and modprinc are handled through auth_restrict(). */
+ assert(opcode != OP_ADDPRINC && opcode != OP_MODPRINC);
+
+ if (opcode == OP_SETSTR && h->vt.setstr != NULL)
+ return h->vt.setstr(context, h->data, client, p1, s1, s2);
+ else if (opcode == OP_CPW && h->vt.cpw != NULL)
+ return h->vt.cpw(context, h->data, client, p1);
+ else if (opcode == OP_CHRAND && h->vt.chrand != NULL)
+ return h->vt.chrand(context, h->data, client, p1);
+ else if (opcode == OP_SETKEY && h->vt.setkey != NULL)
+ return h->vt.setkey(context, h->data, client, p1);
+ else if (opcode == OP_PURGEKEYS && h->vt.purgekeys != NULL)
+ return h->vt.purgekeys(context, h->data, client, p1);
+ else if (opcode == OP_DELPRINC && h->vt.delprinc != NULL)
+ return h->vt.delprinc(context, h->data, client, p1);
+ else if (opcode == OP_RENPRINC && h->vt.renprinc != NULL)
+ return h->vt.renprinc(context, h->data, client, p1, p2);
+ else if (opcode == OP_GETPRINC && h->vt.getprinc != NULL)
+ return h->vt.getprinc(context, h->data, client, p1);
+ else if (opcode == OP_GETSTRS && h->vt.getstrs != NULL)
+ return h->vt.getstrs(context, h->data, client, p1);
+ else if (opcode == OP_EXTRACT && h->vt.extract != NULL)
+ return h->vt.extract(context, h->data, client, p1);
+ else if (opcode == OP_LISTPRINCS && h->vt.listprincs != NULL)
+ return h->vt.listprincs(context, h->data, client);
+ else if (opcode == OP_ADDPOL && h->vt.addpol != NULL)
+ return h->vt.addpol(context, h->data, client, s1, polent, mask);
+ else if (opcode == OP_MODPOL && h->vt.modpol != NULL)
+ return h->vt.modpol(context, h->data, client, s1, polent, mask);
+ else if (opcode == OP_DELPOL && h->vt.delpol != NULL)
+ return h->vt.delpol(context, h->data, client, s1);
+ else if (opcode == OP_GETPOL && h->vt.getpol != NULL)
+ return h->vt.getpol(context, h->data, client, s1, s2);
+ else if (opcode == OP_LISTPOLS && h->vt.listpols != NULL)
+ return h->vt.listpols(context, h->data, client);
+ else if (opcode == OP_IPROP && h->vt.iprop != NULL)
+ return h->vt.iprop(context, h->data, client);
+
+ return KRB5_PLUGIN_NO_HANDLE;
+}
+
+krb5_boolean
+auth(krb5_context context, int opcode, krb5_const_principal client,
+ krb5_const_principal p1, krb5_const_principal p2, const char *s1,
+ const char *s2, const kadm5_policy_ent_rec *polent, long mask)
+{
+ krb5_error_code ret;
+ krb5_boolean authorized = FALSE;
+ auth_handle *hp, h;
+
+ for (hp = handles; *hp != NULL; hp++) {
+ h = *hp;
+
+ ret = call_module(context, h, opcode, client, p1, p2, s1, s2,
+ polent, mask);
+ if (!ret)
+ authorized = TRUE;
+ else if (ret != KRB5_PLUGIN_NO_HANDLE)
+ return FALSE;
+ }
+
+ return authorized;
+}
+
+/* Impose restrictions, modifying *ent and *mask. */
+static krb5_error_code
+impose_restrictions(krb5_context context,
+ const struct kadm5_auth_restrictions *rs,
+ kadm5_principal_ent_t ent, long *mask)
+{
+ krb5_error_code ret;
+ krb5_timestamp now;
+
+ if (rs == NULL)
+ return 0;
+ if (rs->mask & (KADM5_PRINC_EXPIRE_TIME | KADM5_PW_EXPIRATION)) {
+ ret = krb5_timeofday(context, &now);
+ if (ret)
+ return ret;
+ }
+
+ if (rs->mask & KADM5_ATTRIBUTES) {
+ ent->attributes |= rs->require_attrs;
+ ent->attributes &= rs->forbid_attrs;
+ *mask |= KADM5_ATTRIBUTES;
+ }
+ if (rs->mask & KADM5_POLICY_CLR) {
+ *mask &= ~KADM5_POLICY;
+ *mask |= KADM5_POLICY_CLR;
+ } else if (rs->mask & KADM5_POLICY) {
+ if (ent->policy != NULL && strcmp(ent->policy, rs->policy) != 0) {
+ free(ent->policy);
+ ent->policy = NULL;
+ }
+ if (ent->policy == NULL) {
+ ent->policy = strdup(rs->policy);
+ if (ent->policy == NULL)
+ return ENOMEM;
+ }
+ *mask |= KADM5_POLICY;
+ }
+ if (rs->mask & KADM5_PRINC_EXPIRE_TIME) {
+ if (!(*mask & KADM5_PRINC_EXPIRE_TIME) ||
+ ts_after(ent->princ_expire_time, ts_incr(now, rs->princ_lifetime)))
+ ent->princ_expire_time = now + rs->princ_lifetime;
+ *mask |= KADM5_PRINC_EXPIRE_TIME;
+ }
+ if (rs->mask & KADM5_PW_EXPIRATION) {
+ if (!(*mask & KADM5_PW_EXPIRATION) ||
+ ts_after(ent->pw_expiration, ts_incr(now, rs->pw_lifetime)))
+ ent->pw_expiration = now + rs->pw_lifetime;
+ *mask |= KADM5_PW_EXPIRATION;
+ }
+ if (rs->mask & KADM5_MAX_LIFE) {
+ if (!(*mask & KADM5_MAX_LIFE) || ent->max_life > rs->max_life)
+ ent->max_life = rs->max_life;
+ *mask |= KADM5_MAX_LIFE;
+ }
+ if (rs->mask & KADM5_MAX_RLIFE) {
+ if (!(*mask & KADM5_MAX_RLIFE) ||
+ ent->max_renewable_life > rs->max_renewable_life)
+ ent->max_renewable_life = rs->max_renewable_life;
+ *mask |= KADM5_MAX_RLIFE;
+ }
+ return 0;
+}
+
+krb5_boolean
+auth_restrict(krb5_context context, int opcode, krb5_const_principal client,
+ kadm5_principal_ent_t ent, long *mask)
+{
+ auth_handle *hp, h;
+ krb5_boolean authorized = FALSE;
+ krb5_error_code ret, rs_ret;
+ krb5_const_principal target = ent->principal;
+ struct kadm5_auth_restrictions *rs;
+
+ assert(opcode == OP_ADDPRINC || opcode == OP_MODPRINC);
+ for (hp = handles; *hp != NULL; hp++) {
+ h = *hp;
+
+ ret = KRB5_PLUGIN_NO_HANDLE;
+ rs = NULL;
+ if (opcode == OP_ADDPRINC && h->vt.addprinc != NULL) {
+ ret = h->vt.addprinc(context, h->data, client, target, ent, *mask,
+ &rs);
+ } else if (opcode == OP_MODPRINC && h->vt.modprinc != NULL) {
+ ret = h->vt.modprinc(context, h->data, client, target, ent, *mask,
+ &rs);
+ }
+ if (rs != NULL) {
+ rs_ret = impose_restrictions(context, rs, ent, mask);
+ if (h->vt.free_restrictions != NULL)
+ h->vt.free_restrictions(context, h->data, rs);
+ if (rs_ret)
+ return FALSE;
+ }
+ if (!ret)
+ authorized = TRUE;
+ else if (ret != KRB5_PLUGIN_NO_HANDLE)
+ return FALSE;
+ }
+
+ return authorized;
+}
+
+void
+auth_end(krb5_context context)
+{
+ auth_handle *hp, h;
+
+ for (hp = handles; *hp != NULL; hp++) {
+ h = *hp;
+ if (h->vt.end != NULL)
+ h->vt.end(context, h->data);
+ }
+}
diff --git a/src/kadmin/server/auth.h b/src/kadmin/server/auth.h
new file mode 100644
index 000000000000..4d265add7c0d
--- /dev/null
+++ b/src/kadmin/server/auth.h
@@ -0,0 +1,85 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* kadmin/server/auth.h - kadmin authorization declarations */
+/*
+ * Copyright (C) 2017 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef AUTH_H
+#define AUTH_H
+
+#define OP_ADDPRINC 1
+#define OP_MODPRINC 2
+#define OP_SETSTR 3
+#define OP_CPW 4
+#define OP_CHRAND 5
+#define OP_SETKEY 6
+#define OP_PURGEKEYS 7
+#define OP_DELPRINC 8
+#define OP_RENPRINC 9
+#define OP_GETPRINC 10
+#define OP_GETSTRS 11
+#define OP_EXTRACT 12
+#define OP_LISTPRINCS 13
+#define OP_ADDPOL 14
+#define OP_MODPOL 15
+#define OP_DELPOL 16
+#define OP_GETPOL 17
+#define OP_LISTPOLS 18
+#define OP_IPROP 19
+
+/* Initialize all authorization modules. */
+krb5_error_code auth_init(krb5_context context, const char *acl_file);
+
+/* Release authorization module state. */
+void auth_fini(krb5_context context);
+
+/* Authorize the operation given by opcode, using the appropriate subset of p1,
+ * p2, s1, s2, polent, and mask. */
+krb5_boolean auth(krb5_context context, int opcode,
+ krb5_const_principal client, krb5_const_principal p1,
+ krb5_const_principal p2, const char *s1, const char *s2,
+ const kadm5_policy_ent_rec *polent, long mask);
+
+/* Authorize an add-principal or modify-principal operation, and apply
+ * restrictions to ent and mask if any modules supply them. */
+krb5_boolean auth_restrict(krb5_context context, int opcode,
+ krb5_const_principal client,
+ kadm5_principal_ent_t ent, long *mask);
+
+/* Notify modules that the most recent authorized operation has ended. */
+void auth_end(krb5_context context);
+
+/* initvt declarations for built-in modules */
+
+krb5_error_code kadm5_auth_acl_initvt(krb5_context context, int maj_ver,
+ int min_ver, krb5_plugin_vtable vtable);
+krb5_error_code kadm5_auth_self_initvt(krb5_context context, int maj_ver,
+ int min_ver, krb5_plugin_vtable vtable);
+
+#endif /* AUTH_H */
diff --git a/src/kadmin/server/auth_acl.c b/src/kadmin/server/auth_acl.c
new file mode 100644
index 000000000000..efe9c6961bbb
--- /dev/null
+++ b/src/kadmin/server/auth_acl.c
@@ -0,0 +1,755 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* kadmin/server/auth_acl.c - ACL kadm5_auth module */
+/*
+ * Copyright 1995-2004, 2007, 2008, 2017 by the Massachusetts Institute of
+ * Technology. All Rights Reserved.
+ *
+ * Export of this software from the United States of America may
+ * require a specific license from the United States Government.
+ * It is the responsibility of any person or organization contemplating
+ * export to obtain such a license before exporting.
+ *
+ * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
+ * distribute this software and its documentation for any purpose and
+ * without fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright notice and
+ * this permission notice appear in supporting documentation, and that
+ * the name of M.I.T. not be used in advertising or publicity pertaining
+ * to distribution of the software without specific, written prior
+ * permission. Furthermore if you modify this software you must label
+ * your software as modified software and not distribute it in such a
+ * fashion that it might be confused with the original M.I.T. software.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is" without express
+ * or implied warranty.
+ */
+
+#include "k5-int.h"
+#include <syslog.h>
+#include <kadm5/admin.h>
+#include <krb5/kadm5_auth_plugin.h>
+#include "adm_proto.h"
+#include <ctype.h>
+#include "auth.h"
+
+/*
+ * Access control bits.
+ */
+#define ACL_ADD 1
+#define ACL_DELETE 2
+#define ACL_MODIFY 4
+#define ACL_CHANGEPW 8
+/* #define ACL_CHANGE_OWN_PW 16 */
+#define ACL_INQUIRE 32
+#define ACL_EXTRACT 64
+#define ACL_LIST 128
+#define ACL_SETKEY 256
+#define ACL_IPROP 512
+
+#define ACL_ALL_MASK (ACL_ADD | \
+ ACL_DELETE | \
+ ACL_MODIFY | \
+ ACL_CHANGEPW | \
+ ACL_INQUIRE | \
+ ACL_LIST | \
+ ACL_IPROP | \
+ ACL_SETKEY)
+
+struct acl_op_table {
+ char op;
+ uint32_t mask;
+};
+
+struct acl_entry {
+ struct acl_entry *next;
+ krb5_principal client;
+ uint32_t op_allowed;
+ krb5_principal target;
+ struct kadm5_auth_restrictions *rs;
+};
+
+static const struct acl_op_table acl_op_table[] = {
+ { 'a', ACL_ADD },
+ { 'd', ACL_DELETE },
+ { 'm', ACL_MODIFY },
+ { 'c', ACL_CHANGEPW },
+ { 'i', ACL_INQUIRE },
+ { 'l', ACL_LIST },
+ { 'p', ACL_IPROP },
+ { 's', ACL_SETKEY },
+ { 'x', ACL_ALL_MASK },
+ { '*', ACL_ALL_MASK },
+ { 'e', ACL_EXTRACT },
+ { '\0', 0 }
+};
+
+struct wildstate {
+ int nwild;
+ const krb5_data *backref[9];
+};
+
+struct acl_state {
+ struct acl_entry *list;
+};
+
+/*
+ * Get a line from the ACL file. Lines ending with \ are continued on the next
+ * line. The caller should set *lineno to 1 and *incr to 0 before the first
+ * call. On successful return, *lineno will be the line number of the line
+ * read. Return a pointer to the line on success, or NULL on end of file or
+ * read failure.
+ */
+static char *
+get_line(FILE *fp, const char *fname, int *lineno, int *incr)
+{
+ const int chunksize = 128;
+ struct k5buf buf;
+ size_t old_len;
+ char *p;
+
+ /* Increment *lineno by the number of newlines from the last line. */
+ *lineno += *incr;
+ *incr = 0;
+
+ k5_buf_init_dynamic(&buf);
+ for (;;) {
+ /* Read at least part of a line into the buffer. */
+ old_len = buf.len;
+ p = k5_buf_get_space(&buf, chunksize);
+ if (p == NULL)
+ return NULL;
+
+ if (fgets(p, chunksize, fp) == NULL) {
+ /* We reached the end. Return a final unterminated line, if there
+ * is one and it's not a comment. */
+ k5_buf_truncate(&buf, old_len);
+ if (buf.len > 0 && *(char *)buf.data != '#')
+ return buf.data;
+ k5_buf_free(&buf);
+ return NULL;
+ }
+
+ /* Set the buffer length based on the actual amount read. */
+ k5_buf_truncate(&buf, old_len + strlen(p));
+
+ p = buf.data;
+ if (buf.len > 0 && p[buf.len - 1] == '\n') {
+ /* We have a complete raw line in the buffer. */
+ (*incr)++;
+ k5_buf_truncate(&buf, buf.len - 1);
+ if (buf.len > 0 && p[buf.len - 1] == '\\') {
+ /* This line has a continuation marker; keep reading. */
+ k5_buf_truncate(&buf, buf.len - 1);
+ } else if (buf.len == 0 || *p == '#') {
+ /* This line is empty or a comment. Start over. */
+ *lineno += *incr;
+ *incr = 0;
+ k5_buf_truncate(&buf, 0);
+ } else {
+ return buf.data;
+ }
+ }
+ }
+}
+
+/*
+ * Parse a restrictions field. Return NULL on failure.
+ *
+ * Allowed restrictions are:
+ * [+-]flagname (recognized by krb5_flagspec_to_mask)
+ * flag is forced to indicated value
+ * -clearpolicy policy is forced clear
+ * -policy pol policy is forced to be "pol"
+ * -{expire,pwexpire,maxlife,maxrenewlife} deltat
+ * associated value will be forced to
+ * MIN(deltat, requested value)
+ */
+static struct kadm5_auth_restrictions *
+parse_restrictions(const char *str, const char *fname)
+{
+ char *copy = NULL, *token, *arg, *save;
+ const char *delims = "\t\n\f\v\r ,";
+ krb5_deltat delta;
+ struct kadm5_auth_restrictions *rs;
+
+ copy = strdup(str);
+ if (copy == NULL)
+ return NULL;
+
+ rs = calloc(1, sizeof(*rs));
+ if (rs == NULL) {
+ free(copy);
+ return NULL;
+ }
+
+ rs->forbid_attrs = ~(krb5_flags)0;
+ for (token = strtok_r(copy, delims, &save); token != NULL;
+ token = strtok_r(NULL, delims, &save)) {
+
+ if (krb5_flagspec_to_mask(token, &rs->require_attrs,
+ &rs->forbid_attrs) == 0) {
+ rs->mask |= KADM5_ATTRIBUTES;
+ continue;
+ }
+
+ if (strcmp(token, "-clearpolicy") == 0) {
+ rs->mask |= KADM5_POLICY_CLR;
+ continue;
+ }
+
+ /* Everything else needs an argument. */
+ arg = strtok_r(NULL, delims, &save);
+ if (arg == NULL)
+ goto error;
+
+ if (strcmp(token, "-policy") == 0) {
+ if (rs->policy != NULL)
+ goto error;
+ rs->policy = strdup(arg);
+ if (rs->policy == NULL)
+ goto error;
+ rs->mask |= KADM5_POLICY;
+ continue;
+ }
+
+ /* All other arguments must be a deltat. */
+ if (krb5_string_to_deltat(arg, &delta) != 0)
+ goto error;
+
+ if (strcmp(token, "-expire") == 0) {
+ rs->princ_lifetime = delta;
+ rs->mask |= KADM5_PRINC_EXPIRE_TIME;
+ } else if (strcmp(token, "-pwexpire") == 0) {
+ rs->pw_lifetime = delta;
+ rs->mask |= KADM5_PW_EXPIRATION;
+ } else if (strcmp(token, "-maxlife") == 0) {
+ rs->max_life = delta;
+ rs->mask |= KADM5_MAX_LIFE;
+ } else if (strcmp(token, "-maxrenewlife") == 0) {
+ rs->max_renewable_life = delta;
+ rs->mask |= KADM5_MAX_RLIFE;
+ } else {
+ goto error;
+ }
+ }
+
+ free(copy);
+ return rs;
+
+error:
+ krb5_klog_syslog(LOG_ERR, _("%s: invalid restrictions: %s"), fname, str);
+ free(copy);
+ free(rs->policy);
+ free(rs);
+ return NULL;
+}
+
+static void
+free_acl_entry(struct acl_entry *entry)
+{
+ krb5_free_principal(NULL, entry->client);
+ krb5_free_principal(NULL, entry->target);
+ if (entry->rs != NULL) {
+ free(entry->rs->policy);
+ free(entry->rs);
+ }
+ free(entry);
+}
+
+/* Parse the four fields of an ACL entry and return a structure representing
+ * it. Log a message and return NULL on error. */
+static struct acl_entry *
+parse_entry(krb5_context context, const char *client, const char *ops,
+ const char *target, const char *rs, const char *line,
+ const char *fname)
+{
+ struct acl_entry *entry;
+ const char *op;
+ char rop;
+ int t;
+
+ entry = calloc(1, sizeof(*entry));
+ if (entry == NULL)
+ return NULL;
+
+ for (op = ops; *op; op++) {
+ rop = isupper((unsigned char)*op) ? tolower((unsigned char)*op) : *op;
+ for (t = 0; acl_op_table[t].op; t++) {
+ if (rop == acl_op_table[t].op) {
+ if (rop == *op)
+ entry->op_allowed |= acl_op_table[t].mask;
+ else
+ entry->op_allowed &= ~acl_op_table[t].mask;
+ break;
+ }
+ }
+ if (!acl_op_table[t].op) {
+ krb5_klog_syslog(LOG_ERR,
+ _("Unrecognized ACL operation '%c' in %s"),
+ *op, line);
+ goto error;
+ }
+ }
+
+ if (strcmp(client, "*") != 0) {
+ if (krb5_parse_name(context, client, &entry->client) != 0) {
+ krb5_klog_syslog(LOG_ERR, _("Cannot parse client principal '%s'"),
+ client);
+ goto error;
+ }
+ }
+
+ if (target != NULL && strcmp(target, "*") != 0) {
+ if (krb5_parse_name(context, target, &entry->target) != 0) {
+ krb5_klog_syslog(LOG_ERR, _("Cannot parse target principal '%s'"),
+ target);
+ goto error;
+ }
+ }
+
+ if (rs != NULL) {
+ entry->rs = parse_restrictions(rs, fname);
+ if (entry->rs == NULL)
+ goto error;
+ }
+
+ return entry;
+
+error:
+ free_acl_entry(entry);
+ return NULL;
+}
+
+/* Parse the contents of an ACL line. */
+static struct acl_entry *
+parse_line(krb5_context context, const char *line, const char *fname)
+{
+ struct acl_entry *entry = NULL;
+ char *copy;
+ char *client, *client_end, *ops, *ops_end, *target, *target_end, *rs, *end;
+ const char *ws = "\t\n\f\v\r ,";
+
+ /*
+ * Format:
+ * entry ::= [<whitespace>] <principal> <whitespace> <opstring>
+ * [<whitespace> <target> [<whitespace> <restrictions>
+ * [<whitespace>]]]
+ */
+
+ /* Make a copy and remove any trailing whitespace. */
+ copy = strdup(line);
+ if (copy == NULL)
+ return NULL;
+ end = copy + strlen(copy);
+ while (end > copy && isspace(end[-1]))
+ *--end = '\0';
+
+ /* Find the beginning and end of each field. The end of restrictions is
+ * the end of copy. */
+ client = copy + strspn(copy, ws);
+ client_end = client + strcspn(client, ws);
+ ops = client_end + strspn(client_end, ws);
+ ops_end = ops + strcspn(ops, ws);
+ target = ops_end + strspn(ops_end, ws);
+ target_end = target + strcspn(target, ws);
+ rs = target_end + strspn(target_end, ws);
+
+ /* Terminate the first three fields. */
+ *client_end = *ops_end = *target_end = '\0';
+
+ /* The last two fields are optional; represent them as NULL if not present.
+ * The first two fields are required. */
+ if (*target == '\0')
+ target = NULL;
+ if (*rs == '\0')
+ rs = NULL;
+ if (*client != '\0' && *ops != '\0')
+ entry = parse_entry(context, client, ops, target, rs, line, fname);
+ free(copy);
+ return entry;
+}
+
+/* Free all ACL entries. */
+static void
+free_acl_entries(struct acl_state *state)
+{
+ struct acl_entry *entry, *next;
+
+ for (entry = state->list; entry != NULL; entry = next) {
+ next = entry->next;
+ free_acl_entry(entry);
+ }
+ state->list = NULL;
+}
+
+/* Open and parse the ACL file. */
+static krb5_error_code
+load_acl_file(krb5_context context, const char *fname, struct acl_state *state)
+{
+ krb5_error_code ret;
+ FILE *fp;
+ char *line;
+ struct acl_entry **entry_slot;
+ int lineno, incr;
+
+ state->list = NULL;
+
+ /* Open the ACL file for reading. */
+ fp = fopen(fname, "r");
+ if (fp == NULL) {
+ krb5_klog_syslog(LOG_ERR, _("%s while opening ACL file %s"),
+ error_message(errno), fname);
+ ret = errno;
+ k5_setmsg(context, errno, _("Cannot open %s: %s"), fname,
+ error_message(ret));
+ return ret;
+ }
+
+ set_cloexec_file(fp);
+ lineno = 1;
+ incr = 0;
+ entry_slot = &state->list;
+
+ /* Get a non-comment line. */
+ while ((line = get_line(fp, fname, &lineno, &incr)) != NULL) {
+ /* Parse it. Fail out on syntax error. */
+ *entry_slot = parse_line(context, line, fname);
+ if (*entry_slot == NULL) {
+ krb5_klog_syslog(LOG_ERR,
+ _("%s: syntax error at line %d <%.10s...>"),
+ fname, lineno, line);
+ k5_setmsg(context, EINVAL,
+ _("%s: syntax error at line %d <%.10s...>"),
+ fname, lineno, line);
+ free_acl_entries(state);
+ free(line);
+ fclose(fp);
+ return EINVAL;
+ }
+ entry_slot = &(*entry_slot)->next;
+ free(line);
+ }
+
+ fclose(fp);
+ return 0;
+}
+
+/*
+ * See if two data entries match. If e1 is a wildcard (matching a whole
+ * component only) and targetflag is false, save an alias to e2 into
+ * ws->backref. If e1 is a back-reference and targetflag is true, compare the
+ * appropriate entry in ws->backref to e2. If ws is NULL, do not store or
+ * match back-references.
+ */
+static krb5_boolean
+match_data(const krb5_data *e1, const krb5_data *e2, krb5_boolean targetflag,
+ struct wildstate *ws)
+{
+ int n;
+
+ if (data_eq_string(*e1, "*")) {
+ if (ws != NULL && !targetflag) {
+ if (ws->nwild < 9)
+ ws->backref[ws->nwild++] = e2;
+ }
+ return TRUE;
+ }
+
+ if (ws != NULL && targetflag && e1->length == 2 && e1->data[0] == '*' &&
+ e1->data[1] >= '1' && e1->data[1] <= '9') {
+ n = e1->data[1] - '1';
+ if (n >= ws->nwild)
+ return FALSE;
+ return data_eq(*e2, *ws->backref[n]);
+ } else {
+ return data_eq(*e2, *e1);
+ }
+}
+
+/* Return true if p1 matches p2. p1 may contain wildcards if targetflag is
+ * false, or backreferences if it is true. */
+static krb5_boolean
+match_princ(krb5_const_principal p1, krb5_const_principal p2,
+ krb5_boolean targetflag, struct wildstate *ws)
+{
+ int i;
+
+ /* The principals must be of the same length. */
+ if (p1->length != p2->length)
+ return FALSE;
+
+ /* The realm must match, and does not interact with wildcard state. */
+ if (!match_data(&p1->realm, &p2->realm, targetflag, NULL))
+ return FALSE;
+
+ /* All components of the principals must match. */
+ for (i = 0; i < p1->length; i++) {
+ if (!match_data(&p1->data[i], &p2->data[i], targetflag, ws))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Find an ACL entry matching principal and target_principal. Return NULL if
+ * none is found. */
+static struct acl_entry *
+find_entry(struct acl_state *state, krb5_const_principal client,
+ krb5_const_principal target)
+{
+ struct acl_entry *entry;
+ struct wildstate ws;
+
+ for (entry = state->list; entry != NULL; entry = entry->next) {
+ memset(&ws, 0, sizeof(ws));
+ if (entry->client != NULL) {
+ if (!match_princ(entry->client, client, FALSE, &ws))
+ continue;
+ }
+
+ if (entry->target != NULL) {
+ if (target == NULL)
+ continue;
+ if (!match_princ(entry->target, target, TRUE, &ws))
+ continue;
+ }
+
+ return entry;
+ }
+
+ return NULL;
+}
+
+/* Return true if op is permitted for this principal. Set *rs_out (if not
+ * NULL) according to any restrictions in the ACL entry. */
+static krb5_error_code
+acl_check(kadm5_auth_moddata data, uint32_t op, krb5_const_principal client,
+ krb5_const_principal target, struct kadm5_auth_restrictions **rs_out)
+{
+ struct acl_entry *entry;
+
+ if (rs_out != NULL)
+ *rs_out = NULL;
+
+ entry = find_entry((struct acl_state *)data, client, target);
+ if (entry == NULL)
+ return KRB5_PLUGIN_NO_HANDLE;
+ if (!(entry->op_allowed & op))
+ return KRB5_PLUGIN_NO_HANDLE;
+
+ if (rs_out != NULL && entry->rs != NULL && entry->rs->mask)
+ *rs_out = entry->rs;
+
+ return 0;
+}
+
+static krb5_error_code
+acl_init(krb5_context context, const char *acl_file,
+ kadm5_auth_moddata *data_out)
+{
+ krb5_error_code ret;
+ struct acl_state *state;
+
+ *data_out = NULL;
+ if (acl_file == NULL)
+ return KRB5_PLUGIN_NO_HANDLE;
+ state = malloc(sizeof(*state));
+ state->list = NULL;
+ ret = load_acl_file(context, acl_file, state);
+ if (ret) {
+ free(state);
+ return ret;
+ }
+ *data_out = (kadm5_auth_moddata)state;
+ return 0;
+}
+
+static void
+acl_fini(krb5_context context, kadm5_auth_moddata data)
+{
+ if (data == NULL)
+ return;
+ free_acl_entries((struct acl_state *)data);
+ free(data);
+}
+
+static krb5_error_code
+acl_addprinc(krb5_context context, kadm5_auth_moddata data,
+ krb5_const_principal client, krb5_const_principal target,
+ const struct _kadm5_principal_ent_t *ent, long mask,
+ struct kadm5_auth_restrictions **rs_out)
+{
+ return acl_check(data, ACL_ADD, client, target, rs_out);
+}
+
+static krb5_error_code
+acl_modprinc(krb5_context context, kadm5_auth_moddata data,
+ krb5_const_principal client, krb5_const_principal target,
+ const struct _kadm5_principal_ent_t *ent, long mask,
+ struct kadm5_auth_restrictions **rs_out)
+{
+ return acl_check(data, ACL_MODIFY, client, target, rs_out);
+}
+
+static krb5_error_code
+acl_setstr(krb5_context context, kadm5_auth_moddata data,
+ krb5_const_principal client, krb5_const_principal target,
+ const char *key, const char *value)
+{
+ return acl_check(data, ACL_MODIFY, client, target, NULL);
+}
+
+static krb5_error_code
+acl_cpw(krb5_context context, kadm5_auth_moddata data,
+ krb5_const_principal client, krb5_const_principal target)
+{
+ return acl_check(data, ACL_CHANGEPW, client, target, NULL);
+}
+
+static krb5_error_code
+acl_chrand(krb5_context context, kadm5_auth_moddata data,
+ krb5_const_principal client, krb5_const_principal target)
+{
+ return acl_check(data, ACL_CHANGEPW, client, target, NULL);
+}
+
+static krb5_error_code
+acl_setkey(krb5_context context, kadm5_auth_moddata data,
+ krb5_const_principal client, krb5_const_principal target)
+{
+ return acl_check(data, ACL_SETKEY, client, target, NULL);
+}
+
+static krb5_error_code
+acl_purgekeys(krb5_context context, kadm5_auth_moddata data,
+ krb5_const_principal client, krb5_const_principal target)
+{
+ return acl_check(data, ACL_MODIFY, client, target, NULL);
+}
+
+static krb5_error_code
+acl_delprinc(krb5_context context, kadm5_auth_moddata data,
+ krb5_const_principal client, krb5_const_principal target)
+{
+ return acl_check(data, ACL_DELETE, client, target, NULL);
+}
+
+static krb5_error_code
+acl_renprinc(krb5_context context, kadm5_auth_moddata data,
+ krb5_const_principal client, krb5_const_principal src,
+ krb5_const_principal dest)
+{
+ struct kadm5_auth_restrictions *rs;
+
+ if (acl_check(data, ACL_DELETE, client, src, NULL) == 0 &&
+ acl_check(data, ACL_ADD, client, dest, &rs) == 0 && rs == NULL)
+ return 0;
+ return KRB5_PLUGIN_NO_HANDLE;
+}
+
+static krb5_error_code
+acl_getprinc(krb5_context context, kadm5_auth_moddata data,
+ krb5_const_principal client, krb5_const_principal target)
+{
+ return acl_check(data, ACL_INQUIRE, client, target, NULL);
+}
+
+static krb5_error_code
+acl_getstrs(krb5_context context, kadm5_auth_moddata data,
+ krb5_const_principal client, krb5_const_principal target)
+{
+ return acl_check(data, ACL_INQUIRE, client, target, NULL);
+}
+
+static krb5_error_code
+acl_extract(krb5_context context, kadm5_auth_moddata data,
+ krb5_const_principal client, krb5_const_principal target)
+{
+ return acl_check(data, ACL_EXTRACT, client, target, NULL);
+}
+
+static krb5_error_code
+acl_listprincs(krb5_context context, kadm5_auth_moddata data,
+ krb5_const_principal client)
+{
+ return acl_check(data, ACL_LIST, client, NULL, NULL);
+}
+
+static krb5_error_code
+acl_addpol(krb5_context context, kadm5_auth_moddata data,
+ krb5_const_principal client, const char *policy,
+ const struct _kadm5_policy_ent_t *ent, long mask)
+{
+ return acl_check(data, ACL_ADD, client, NULL, NULL);
+}
+
+static krb5_error_code
+acl_modpol(krb5_context context, kadm5_auth_moddata data,
+ krb5_const_principal client, const char *policy,
+ const struct _kadm5_policy_ent_t *ent, long mask)
+{
+ return acl_check(data, ACL_MODIFY, client, NULL, NULL);
+}
+
+static krb5_error_code
+acl_delpol(krb5_context context, kadm5_auth_moddata data,
+ krb5_const_principal client, const char *policy)
+{
+ return acl_check(data, ACL_DELETE, client, NULL, NULL);
+}
+
+static krb5_error_code
+acl_getpol(krb5_context context, kadm5_auth_moddata data,
+ krb5_const_principal client, const char *policy,
+ const char *client_policy)
+{
+ return acl_check(data, ACL_INQUIRE, client, NULL, NULL);
+}
+
+static krb5_error_code
+acl_listpols(krb5_context context, kadm5_auth_moddata data,
+ krb5_const_principal client)
+{
+ return acl_check(data, ACL_LIST, client, NULL, NULL);
+}
+
+static krb5_error_code
+acl_iprop(krb5_context context, kadm5_auth_moddata data,
+ krb5_const_principal client)
+{
+ return acl_check(data, ACL_IPROP, client, NULL, NULL);
+}
+
+krb5_error_code
+kadm5_auth_acl_initvt(krb5_context context, int maj_ver, int min_ver,
+ krb5_plugin_vtable vtable)
+{
+ kadm5_auth_vtable vt;
+
+ if (maj_ver != 1)
+ return KRB5_PLUGIN_VER_NOTSUPP;
+ vt = (kadm5_auth_vtable)vtable;
+ vt->name = "acl";
+ vt->init = acl_init;
+ vt->fini = acl_fini;
+ vt->addprinc = acl_addprinc;
+ vt->modprinc = acl_modprinc;
+ vt->setstr = acl_setstr;
+ vt->cpw = acl_cpw;
+ vt->chrand = acl_chrand;
+ vt->setkey = acl_setkey;
+ vt->purgekeys = acl_purgekeys;
+ vt->delprinc = acl_delprinc;
+ vt->renprinc = acl_renprinc;
+ vt->getprinc = acl_getprinc;
+ vt->getstrs = acl_getstrs;
+ vt->extract = acl_extract;
+ vt->listprincs = acl_listprincs;
+ vt->addpol = acl_addpol;
+ vt->modpol = acl_modpol;
+ vt->delpol = acl_delpol;
+ vt->getpol = acl_getpol;
+ vt->listpols = acl_listpols;
+ vt->iprop = acl_iprop;
+ return 0;
+}
diff --git a/src/kadmin/server/auth_self.c b/src/kadmin/server/auth_self.c
new file mode 100644
index 000000000000..253d4bc596ae
--- /dev/null
+++ b/src/kadmin/server/auth_self.c
@@ -0,0 +1,77 @@
+/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/* kadmin/server/auth_self.c - self-service kadm5_auth module */
+/*
+ * Copyright (C) 2017 by the Massachusetts Institute of Technology.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "k5-int.h"
+#include <kadm5/admin.h>
+#include <krb5/kadm5_auth_plugin.h>
+#include "auth.h"
+
+/* Authorize a principal to operate on itself. Applies to cpw, chrand,
+ * purgekeys, getprinc, and getstrs. */
+static krb5_error_code
+self_compare(krb5_context context, kadm5_auth_moddata data,
+ krb5_const_principal client, krb5_const_principal target)
+{
+ if (krb5_principal_compare(context, client, target))
+ return 0;
+ return KRB5_PLUGIN_NO_HANDLE;
+}
+
+/* Authorize a principal to get the policy record for its own policy. */
+static krb5_error_code
+self_getpol(krb5_context context, kadm5_auth_moddata data,
+ krb5_const_principal client, const char *policy,
+ const char *client_policy)
+{
+ if (client_policy != NULL && strcmp(policy, client_policy) == 0)
+ return 0;
+ return KRB5_PLUGIN_NO_HANDLE;
+}
+
+krb5_error_code
+kadm5_auth_self_initvt(krb5_context context, int maj_ver, int min_ver,
+ krb5_plugin_vtable vtable)
+{
+ kadm5_auth_vtable vt;
+
+ if (maj_ver != 1)
+ return KRB5_PLUGIN_VER_NOTSUPP;
+ vt = (kadm5_auth_vtable)vtable;
+ vt->name = "self";
+ vt->cpw = self_compare;
+ vt->chrand = self_compare;
+ vt->purgekeys = self_compare;
+ vt->getprinc = self_compare;
+ vt->getstrs = self_compare;
+ vt->getpol = self_getpol;
+ return 0;
+}
diff --git a/src/kadmin/server/deps b/src/kadmin/server/deps
index 44311af19af7..99aef7500e00 100644
--- a/src/kadmin/server/deps
+++ b/src/kadmin/server/deps
@@ -1,6 +1,44 @@
#
# Generated makefile dependencies follow.
#
+$(OUTPRE)auth_acl.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/types.h \
+ $(BUILDTOP)/include/kadm5/admin.h $(BUILDTOP)/include/kadm5/chpass_util_strings.h \
+ $(BUILDTOP)/include/kadm5/kadm_err.h $(BUILDTOP)/include/krb5/krb5.h \
+ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+ $(COM_ERR_DEPS) $(top_srcdir)/include/adm_proto.h $(top_srcdir)/include/gssrpc/auth.h \
+ $(top_srcdir)/include/gssrpc/auth_gss.h $(top_srcdir)/include/gssrpc/auth_unix.h \
+ $(top_srcdir)/include/gssrpc/clnt.h $(top_srcdir)/include/gssrpc/rename.h \
+ $(top_srcdir)/include/gssrpc/rpc.h $(top_srcdir)/include/gssrpc/rpc_msg.h \
+ $(top_srcdir)/include/gssrpc/svc.h $(top_srcdir)/include/gssrpc/svc_auth.h \
+ $(top_srcdir)/include/gssrpc/xdr.h $(top_srcdir)/include/k5-buf.h \
+ $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \
+ $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \
+ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \
+ $(top_srcdir)/include/kdb.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/kadm5_auth_plugin.h \
+ $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
+ $(top_srcdir)/include/socket-utils.h auth.h auth_acl.c
+$(OUTPRE)auth_self.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
+ $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/types.h \
+ $(BUILDTOP)/include/kadm5/admin.h $(BUILDTOP)/include/kadm5/chpass_util_strings.h \
+ $(BUILDTOP)/include/kadm5/kadm_err.h $(BUILDTOP)/include/krb5/krb5.h \
+ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+ $(COM_ERR_DEPS) $(top_srcdir)/include/gssrpc/auth.h \
+ $(top_srcdir)/include/gssrpc/auth_gss.h $(top_srcdir)/include/gssrpc/auth_unix.h \
+ $(top_srcdir)/include/gssrpc/clnt.h $(top_srcdir)/include/gssrpc/rename.h \
+ $(top_srcdir)/include/gssrpc/rpc.h $(top_srcdir)/include/gssrpc/rpc_msg.h \
+ $(top_srcdir)/include/gssrpc/svc.h $(top_srcdir)/include/gssrpc/svc_auth.h \
+ $(top_srcdir)/include/gssrpc/xdr.h $(top_srcdir)/include/k5-buf.h \
+ $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \
+ $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \
+ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \
+ $(top_srcdir)/include/kdb.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/kadm5_auth_plugin.h \
+ $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/port-sockets.h \
+ $(top_srcdir)/include/socket-utils.h auth.h auth_self.c
$(OUTPRE)kadm_rpc_svc.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
$(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
$(BUILDTOP)/include/gssapi/gssapi_krb5.h $(BUILDTOP)/include/gssrpc/types.h \
@@ -29,28 +67,27 @@ $(OUTPRE)server_stubs.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
$(BUILDTOP)/include/gssapi/gssapi_krb5.h $(BUILDTOP)/include/gssrpc/types.h \
$(BUILDTOP)/include/kadm5/admin.h $(BUILDTOP)/include/kadm5/admin_internal.h \
$(BUILDTOP)/include/kadm5/chpass_util_strings.h $(BUILDTOP)/include/kadm5/kadm_err.h \
- $(BUILDTOP)/include/kadm5/kadm_rpc.h $(BUILDTOP)/include/kadm5/server_acl.h \
- $(BUILDTOP)/include/kadm5/server_internal.h $(BUILDTOP)/include/krb5/krb5.h \
- $(COM_ERR_DEPS) $(VERTO_DEPS) $(top_srcdir)/include/adm_proto.h \
- $(top_srcdir)/include/gssrpc/auth.h $(top_srcdir)/include/gssrpc/auth_gss.h \
- $(top_srcdir)/include/gssrpc/auth_unix.h $(top_srcdir)/include/gssrpc/clnt.h \
- $(top_srcdir)/include/gssrpc/rename.h $(top_srcdir)/include/gssrpc/rpc.h \
- $(top_srcdir)/include/gssrpc/rpc_msg.h $(top_srcdir)/include/gssrpc/svc.h \
- $(top_srcdir)/include/gssrpc/svc_auth.h $(top_srcdir)/include/gssrpc/xdr.h \
- $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-thread.h \
- $(top_srcdir)/include/kdb.h $(top_srcdir)/include/krb5.h \
- $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/net-server.h \
- $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
- misc.h server_stubs.c
+ $(BUILDTOP)/include/kadm5/kadm_rpc.h $(BUILDTOP)/include/kadm5/server_internal.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(COM_ERR_DEPS) $(VERTO_DEPS) \
+ $(top_srcdir)/include/adm_proto.h $(top_srcdir)/include/gssrpc/auth.h \
+ $(top_srcdir)/include/gssrpc/auth_gss.h $(top_srcdir)/include/gssrpc/auth_unix.h \
+ $(top_srcdir)/include/gssrpc/clnt.h $(top_srcdir)/include/gssrpc/rename.h \
+ $(top_srcdir)/include/gssrpc/rpc.h $(top_srcdir)/include/gssrpc/rpc_msg.h \
+ $(top_srcdir)/include/gssrpc/svc.h $(top_srcdir)/include/gssrpc/svc_auth.h \
+ $(top_srcdir)/include/gssrpc/xdr.h $(top_srcdir)/include/k5-platform.h \
+ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/kdb.h \
+ $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/net-server.h $(top_srcdir)/include/port-sockets.h \
+ $(top_srcdir)/include/socket-utils.h auth.h misc.h \
+ server_stubs.c
$(OUTPRE)ovsec_kadmd.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
$(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_alloc.h \
$(BUILDTOP)/include/gssapi/gssapi_ext.h $(BUILDTOP)/include/gssrpc/types.h \
$(BUILDTOP)/include/kadm5/admin.h $(BUILDTOP)/include/kadm5/admin_internal.h \
$(BUILDTOP)/include/kadm5/chpass_util_strings.h $(BUILDTOP)/include/kadm5/kadm_err.h \
- $(BUILDTOP)/include/kadm5/kadm_rpc.h $(BUILDTOP)/include/kadm5/server_acl.h \
- $(BUILDTOP)/include/kadm5/server_internal.h $(BUILDTOP)/include/krb5/krb5.h \
- $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
- $(BUILDTOP)/lib/gssapi/generic/gssapi_err_generic.h \
+ $(BUILDTOP)/include/kadm5/kadm_rpc.h $(BUILDTOP)/include/kadm5/server_internal.h \
+ $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
+ $(BUILDTOP)/include/profile.h $(BUILDTOP)/lib/gssapi/generic/gssapi_err_generic.h \
$(BUILDTOP)/lib/gssapi/krb5/gssapi_err_krb5.h $(COM_ERR_DEPS) \
$(VERTO_DEPS) $(top_srcdir)/include/adm_proto.h $(top_srcdir)/include/gssrpc/auth.h \
$(top_srcdir)/include/gssrpc/auth_gss.h $(top_srcdir)/include/gssrpc/auth_gssapi.h \
@@ -71,7 +108,7 @@ $(OUTPRE)ovsec_kadmd.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
$(top_srcdir)/lib/gssapi/generic/gssapiP_generic.h \
$(top_srcdir)/lib/gssapi/generic/gssapi_ext.h $(top_srcdir)/lib/gssapi/generic/gssapi_generic.h \
$(top_srcdir)/lib/gssapi/krb5/gssapiP_krb5.h $(top_srcdir)/lib/gssapi/krb5/gssapi_krb5.h \
- misc.h ovsec_kadmd.c
+ auth.h misc.h ovsec_kadmd.c
$(OUTPRE)schpw.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
$(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/types.h \
$(BUILDTOP)/include/kadm5/admin.h $(BUILDTOP)/include/kadm5/admin_internal.h \
@@ -97,23 +134,23 @@ $(OUTPRE)misc.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
$(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssrpc/types.h \
$(BUILDTOP)/include/kadm5/admin.h $(BUILDTOP)/include/kadm5/admin_internal.h \
$(BUILDTOP)/include/kadm5/chpass_util_strings.h $(BUILDTOP)/include/kadm5/kadm_err.h \
- $(BUILDTOP)/include/kadm5/server_acl.h $(BUILDTOP)/include/kadm5/server_internal.h \
- $(BUILDTOP)/include/krb5/krb5.h $(BUILDTOP)/include/osconf.h \
- $(BUILDTOP)/include/profile.h $(COM_ERR_DEPS) $(VERTO_DEPS) \
- $(top_srcdir)/include/gssrpc/auth.h $(top_srcdir)/include/gssrpc/auth_gss.h \
- $(top_srcdir)/include/gssrpc/auth_unix.h $(top_srcdir)/include/gssrpc/clnt.h \
- $(top_srcdir)/include/gssrpc/rename.h $(top_srcdir)/include/gssrpc/rpc.h \
- $(top_srcdir)/include/gssrpc/rpc_msg.h $(top_srcdir)/include/gssrpc/svc.h \
- $(top_srcdir)/include/gssrpc/svc_auth.h $(top_srcdir)/include/gssrpc/xdr.h \
- $(top_srcdir)/include/k5-buf.h $(top_srcdir)/include/k5-err.h \
- $(top_srcdir)/include/k5-gmt_mktime.h $(top_srcdir)/include/k5-int-pkinit.h \
- $(top_srcdir)/include/k5-int.h $(top_srcdir)/include/k5-platform.h \
- $(top_srcdir)/include/k5-plugin.h $(top_srcdir)/include/k5-thread.h \
- $(top_srcdir)/include/k5-trace.h $(top_srcdir)/include/kdb.h \
- $(top_srcdir)/include/krb5.h $(top_srcdir)/include/krb5/authdata_plugin.h \
- $(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/net-server.h \
- $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \
- misc.c misc.h
+ $(BUILDTOP)/include/kadm5/server_internal.h $(BUILDTOP)/include/krb5/krb5.h \
+ $(BUILDTOP)/include/osconf.h $(BUILDTOP)/include/profile.h \
+ $(COM_ERR_DEPS) $(VERTO_DEPS) $(top_srcdir)/include/gssrpc/auth.h \
+ $(top_srcdir)/include/gssrpc/auth_gss.h $(top_srcdir)/include/gssrpc/auth_unix.h \
+ $(top_srcdir)/include/gssrpc/clnt.h $(top_srcdir)/include/gssrpc/rename.h \
+ $(top_srcdir)/include/gssrpc/rpc.h $(top_srcdir)/include/gssrpc/rpc_msg.h \
+ $(top_srcdir)/include/gssrpc/svc.h $(top_srcdir)/include/gssrpc/svc_auth.h \
+ $(top_srcdir)/include/gssrpc/xdr.h $(top_srcdir)/include/k5-buf.h \
+ $(top_srcdir)/include/k5-err.h $(top_srcdir)/include/k5-gmt_mktime.h \
+ $(top_srcdir)/include/k5-int-pkinit.h $(top_srcdir)/include/k5-int.h \
+ $(top_srcdir)/include/k5-platform.h $(top_srcdir)/include/k5-plugin.h \
+ $(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/k5-trace.h \
+ $(top_srcdir)/include/kdb.h $(top_srcdir)/include/krb5.h \
+ $(top_srcdir)/include/krb5/authdata_plugin.h $(top_srcdir)/include/krb5/plugin.h \
+ $(top_srcdir)/include/net-server.h $(top_srcdir)/include/port-sockets.h \
+ $(top_srcdir)/include/socket-utils.h auth.h misc.c \
+ misc.h
$(OUTPRE)ipropd_svc.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
$(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_ext.h \
$(BUILDTOP)/include/gssrpc/types.h $(BUILDTOP)/include/kadm5/admin.h \
@@ -131,5 +168,5 @@ $(OUTPRE)ipropd_svc.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \
$(top_srcdir)/include/k5-thread.h $(top_srcdir)/include/kdb.h \
$(top_srcdir)/include/kdb_log.h $(top_srcdir)/include/krb5.h \
$(top_srcdir)/include/krb5/plugin.h $(top_srcdir)/include/net-server.h \
- $(top_srcdir)/lib/gssapi/krb5/gssapi_krb5.h $(top_srcdir)/lib/kadm5/srv/server_acl.h \
+ $(top_srcdir)/lib/gssapi/krb5/gssapi_krb5.h auth.h \
ipropd_svc.c misc.h
diff --git a/src/kadmin/server/ipropd_svc.c b/src/kadmin/server/ipropd_svc.c
index bce668f4221a..e6e190136f88 100644
--- a/src/kadmin/server/ipropd_svc.c
+++ b/src/kadmin/server/ipropd_svc.c
@@ -16,7 +16,6 @@
#include <kadm5/admin.h>
#include <kadm5/kadm_rpc.h>
#include <kadm5/server_internal.h>
-#include <server_acl.h>
#include <adm_proto.h>
#include <string.h>
#include <gssapi_krb5.h>
@@ -25,6 +24,7 @@
#include <arpa/inet.h>
#include <netdb.h>
#include <kdb_log.h>
+#include "auth.h"
#include "misc.h"
#include "osconf.h"
@@ -129,6 +129,20 @@ buf_to_string(gss_buffer_desc *b)
return s;
}
+static krb5_boolean
+iprop_acl_check(krb5_context context, const char *client_name)
+{
+ krb5_principal client_princ;
+ krb5_boolean result;
+
+ if (krb5_parse_name(context, client_name, &client_princ) != 0)
+ return FALSE;
+ result = auth(context, OP_IPROP, client_princ,
+ NULL, NULL, NULL, NULL, NULL, 0);
+ krb5_free_principal(context, client_princ);
+ return result;
+}
+
kdb_incr_result_t *
iprop_get_updates_1_svc(kdb_last_t *arg, struct svc_req *rqstp)
{
@@ -174,11 +188,7 @@ iprop_get_updates_1_svc(kdb_last_t *arg, struct svc_req *rqstp)
DPRINT("%s: clprinc=`%s'\n\tsvcprinc=`%s'\n", whoami, client_name,
service_name);
- if (!kadm5int_acl_check(handle->context,
- rqst2name(rqstp),
- ACL_IPROP,
- NULL,
- NULL)) {
+ if (!iprop_acl_check(handle->context, client_name)) {
ret.ret = UPDATE_PERM_DENIED;
DPRINT("%s: PERMISSION DENIED: clprinc=`%s'\n\tsvcprinc=`%s'\n",
@@ -301,11 +311,7 @@ ipropx_resync(uint32_t vers, struct svc_req *rqstp)
DPRINT("%s: clprinc=`%s'\n\tsvcprinc=`%s'\n",
whoami, client_name, service_name);
- if (!kadm5int_acl_check(handle->context,
- rqst2name(rqstp),
- ACL_IPROP,
- NULL,
- NULL)) {
+ if (!iprop_acl_check(handle->context, client_name)) {
ret.ret = UPDATE_PERM_DENIED;
DPRINT("%s: Permission denied\n", whoami);
@@ -532,9 +538,9 @@ krb5_iprop_prog_1(struct svc_req *rqstp,
union {
kdb_last_t iprop_get_updates_1_arg;
} argument;
- char *result;
+ void *result;
bool_t (*_xdr_argument)(), (*_xdr_result)();
- char *(*local)(/* union XXX *, struct svc_req * */);
+ void *(*local)(/* union XXX *, struct svc_req * */);
char *whoami = "krb5_iprop_prog_1";
if (!check_iprop_rpcsec_auth(rqstp)) {
@@ -555,19 +561,19 @@ krb5_iprop_prog_1(struct svc_req *rqstp,
case IPROP_GET_UPDATES:
_xdr_argument = xdr_kdb_last_t;
_xdr_result = xdr_kdb_incr_result_t;
- local = (char *(*)()) iprop_get_updates_1_svc;
+ local = (void *(*)()) iprop_get_updates_1_svc;
break;
case IPROP_FULL_RESYNC:
_xdr_argument = xdr_void;
_xdr_result = xdr_kdb_fullresync_result_t;
- local = (char *(*)()) iprop_full_resync_1_svc;
+ local = (void *(*)()) iprop_full_resync_1_svc;
break;
case IPROP_FULL_RESYNC_EXT:
_xdr_argument = xdr_u_int32;
_xdr_result = xdr_kdb_fullresync_result_t;
- local = (char *(*)()) iprop_full_resync_ext_1_svc;
+ local = (void *(*)()) iprop_full_resync_ext_1_svc;
break;
default:
diff --git a/src/kadmin/server/misc.c b/src/kadmin/server/misc.c
index 27a6376af6b1..6b258a6a056e 100644
--- a/src/kadmin/server/misc.c
+++ b/src/kadmin/server/misc.c
@@ -7,96 +7,9 @@
#include <k5-int.h>
#include <kdb.h>
#include <kadm5/server_internal.h>
-#include <kadm5/server_acl.h>
#include "misc.h"
+#include "auth.h"
#include "net-server.h"
-
-/*
- * Function: chpass_principal_wrapper_3
- *
- * 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
- * keepold (input) whether to preserve old keys
- * n_ks_tuple (input) the number of key-salt tuples in ks_tuple
- * ks_tuple (input) array of tuples indicating the caller's
- * requested enctypes/salttypes
- * password (input) password we are going to change to.
- * <return value> 0 on success 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_3(void *server_handle,
- krb5_principal principal,
- krb5_boolean keepold,
- int n_ks_tuple,
- krb5_key_salt_tuple *ks_tuple,
- char *password)
-{
- kadm5_ret_t ret;
-
- ret = check_min_life(server_handle, principal, NULL, 0);
- if (ret)
- return ret;
-
- return kadm5_chpass_principal_3(server_handle, principal,
- keepold, n_ks_tuple, ks_tuple,
- password);
-}
-
-
-/*
- * Function: randkey_principal_wrapper_3
- *
- * Purpose: wrapper to kadm5_randkey_principal which checks the
- * password's min. life.
- *
- * Arguments:
- * principal (input) krb5_principal whose password we are
- * changing
- * keepold (input) whether to preserve old keys
- * n_ks_tuple (input) the number of key-salt tuples in ks_tuple
- * ks_tuple (input) array of tuples indicating the caller's
- * requested enctypes/salttypes
- * 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_3(void *server_handle,
- krb5_principal principal,
- krb5_boolean keepold,
- int n_ks_tuple,
- krb5_key_salt_tuple *ks_tuple,
- krb5_keyblock **keys, int *n_keys)
-{
- kadm5_ret_t ret;
-
- ret = check_min_life(server_handle, principal, NULL, 0);
- if (ret)
- return ret;
- return kadm5_randkey_principal_3(server_handle, principal,
- keepold, n_ks_tuple, ks_tuple,
- keys, n_keys);
-}
-
kadm5_ret_t
schpw_util_wrapper(void *server_handle,
krb5_principal client,
@@ -107,8 +20,6 @@ schpw_util_wrapper(void *server_handle,
{
kadm5_ret_t ret;
kadm5_server_handle_t handle = server_handle;
- krb5_boolean access_granted;
- krb5_boolean self;
/*
* If no target is explicitly provided, then the target principal
@@ -117,32 +28,22 @@ schpw_util_wrapper(void *server_handle,
if (target == NULL)
target = client;
- /*
- * A principal can always change its own password, as long as it
- * has an initial ticket and meets the minimum password lifetime
- * requirement.
- */
- self = krb5_principal_compare(handle->context, client, target);
- if (self) {
+ /* If the client is changing its own password, require it to use an initial
+ * ticket, and enforce the policy min_life. */
+ if (krb5_principal_compare(handle->context, client, target)) {
+ if (!initial_flag) {
+ strlcpy(msg_ret, "Ticket must be derived from a password",
+ msg_len);
+ return KADM5_AUTH_INITIAL;
+ }
+
ret = check_min_life(server_handle, target, msg_ret, msg_len);
if (ret != 0)
return ret;
-
- access_granted = initial_flag;
- } else
- access_granted = FALSE;
-
- if (!access_granted &&
- kadm5int_acl_check_krb(handle->context, client,
- ACL_CHANGEPW, target, NULL)) {
- /*
- * Otherwise, principals with appropriate privileges can change
- * any password
- */
- access_granted = TRUE;
}
- if (access_granted) {
+ if (auth(handle->context, OP_CPW, client, target,
+ NULL, NULL, NULL, NULL, 0)) {
ret = kadm5_chpass_principal_util(server_handle,
target,
new_pw, ret_pw,
@@ -159,7 +60,7 @@ kadm5_ret_t
check_min_life(void *server_handle, krb5_principal principal,
char *msg_ret, unsigned int msg_len)
{
- krb5_int32 now;
+ krb5_timestamp now;
kadm5_ret_t ret;
kadm5_policy_ent_rec pol;
kadm5_principal_ent_rec princ;
@@ -184,7 +85,7 @@ check_min_life(void *server_handle, krb5_principal principal,
(void) kadm5_free_principal_ent(handle->lhandle, &princ);
return (ret == KADM5_UNK_POLICY) ? 0 : ret;
}
- if((now - princ.last_pwd_change) < pol.pw_min_life &&
+ if(ts_delta(now, princ.last_pwd_change) < pol.pw_min_life &&
!(princ.attributes & KRB5_KDB_REQUIRES_PWCHANGE)) {
if (msg_ret != NULL) {
time_t until;
diff --git a/src/kadmin/server/misc.h b/src/kadmin/server/misc.h
index ea0fc7d2217a..3a112a0b7b2e 100644
--- a/src/kadmin/server/misc.h
+++ b/src/kadmin/server/misc.h
@@ -13,23 +13,6 @@ int
setup_gss_names(struct svc_req *, gss_buffer_desc *,
gss_buffer_desc *);
-
-kadm5_ret_t
-chpass_principal_wrapper_3(void *server_handle,
- krb5_principal principal,
- krb5_boolean keepold,
- int n_ks_tuple,
- krb5_key_salt_tuple *ks_tuple,
- char *password);
-
-kadm5_ret_t
-randkey_principal_wrapper_3(void *server_handle,
- krb5_principal principal,
- krb5_boolean keepold,
- int n_ks_tuple,
- krb5_key_salt_tuple *ks_tuple,
- krb5_keyblock **keys, int *n_keys);
-
kadm5_ret_t
schpw_util_wrapper(void *server_handle, krb5_principal client,
krb5_principal target, krb5_boolean initial_flag,
diff --git a/src/kadmin/server/ovsec_kadmd.c b/src/kadmin/server/ovsec_kadmd.c
index a3edd3b00169..6c875901a976 100644
--- a/src/kadmin/server/ovsec_kadmd.c
+++ b/src/kadmin/server/ovsec_kadmd.c
@@ -51,7 +51,6 @@
#include <gssrpc/auth_gssapi.h>
#include <kadm5/admin.h>
#include <kadm5/kadm_rpc.h>
-#include <kadm5/server_acl.h>
#include <adm_proto.h>
#include "kdb_kt.h" /* for krb5_ktkdb_set_context */
#include <string.h>
@@ -59,6 +58,7 @@
#include <kdb_log.h>
#include "misc.h"
+#include "auth.h"
#if defined(NEED_DAEMON_PROTO)
int daemon(int, int);
@@ -356,6 +356,7 @@ main(int argc, char *argv[])
verto_ctx *vctx;
const char *pid_file = NULL;
char **db_args = NULL, **tmpargs;
+ const char *acl_file;
int ret, i, db_args_size = 0, strong_random = 1, proponly = 0;
setlocale(LC_ALL, "");
@@ -505,7 +506,8 @@ main(int argc, char *argv[])
if (svcauth_gss_set_svc_name(GSS_C_NO_NAME) != TRUE)
fail_to_start(0, _("Cannot initialize GSSAPI service name"));
- ret = kadm5int_acl_init(context, 0, params.acl_file);
+ acl_file = (*params.acl_file != '\0') ? params.acl_file : NULL;
+ ret = auth_init(context, acl_file);
if (ret)
fail_to_start(ret, _("initializing ACL file"));
@@ -550,7 +552,7 @@ main(int argc, char *argv[])
svcauth_gssapi_unset_names();
kadm5_destroy(global_server_handle);
loop_free(vctx);
- kadm5int_acl_finish(context, 0);
+ auth_fini(context);
(void)gss_release_name(&minor_status, &gss_changepw_name);
(void)gss_release_name(&minor_status, &gss_oldchangepw_name);
for (i = 0; i < 4; i++)
diff --git a/src/kadmin/server/schpw.c b/src/kadmin/server/schpw.c
index 900adf7a0997..491cba91aa1a 100644
--- a/src/kadmin/server/schpw.c
+++ b/src/kadmin/server/schpw.c
@@ -18,8 +18,8 @@
static krb5_error_code
process_chpw_request(krb5_context context, void *server_handle, char *realm,
- krb5_keytab keytab, const krb5_fulladdr *local_faddr,
- const krb5_fulladdr *remote_faddr, krb5_data *req,
+ krb5_keytab keytab, const krb5_fulladdr *local_addr,
+ const krb5_fulladdr *remote_addr, krb5_data *req,
krb5_data *rep)
{
krb5_error_code ret;
@@ -42,7 +42,7 @@ process_chpw_request(krb5_context context, void *server_handle, char *realm,
struct sockaddr_storage ss;
socklen_t salen;
char addrbuf[100];
- krb5_address *addr = remote_faddr->address;
+ krb5_address *addr = remote_addr->address;
*rep = empty_data();
@@ -205,15 +205,6 @@ process_chpw_request(krb5_context context, void *server_handle, char *realm,
goto chpwfail;
}
- /* for cpw, verify that this is an AS_REQ ticket */
- if (vno == 1 &&
- (ticket->enc_part2->flags & TKT_FLG_INITIAL) == 0) {
- numresult = KRB5_KPASSWD_INITIAL_FLAG_NEEDED;
- strlcpy(strresult, "Ticket must be derived from a password",
- sizeof(strresult));
- goto chpwfail;
- }
-
/* change the password */
ptr = k5memdup0(clear.data, clear.length, &ret);
@@ -237,7 +228,7 @@ process_chpw_request(krb5_context context, void *server_handle, char *realm,
sin->sin_family = AF_INET;
memcpy(&sin->sin_addr, addr->contents, addr->length);
- sin->sin_port = htons(remote_faddr->port);
+ sin->sin_port = htons(remote_addr->port);
salen = sizeof(*sin);
break;
}
@@ -246,7 +237,7 @@ process_chpw_request(krb5_context context, void *server_handle, char *realm,
sin6->sin6_family = AF_INET6;
memcpy(&sin6->sin6_addr, addr->contents, addr->length);
- sin6->sin6_port = htons(remote_faddr->port);
+ sin6->sin6_port = htons(remote_addr->port);
salen = sizeof(*sin6);
break;
}
@@ -292,6 +283,9 @@ process_chpw_request(krb5_context context, void *server_handle, char *realm,
case KADM5_AUTH_CHANGEPW:
numresult = KRB5_KPASSWD_ACCESSDENIED;
break;
+ case KADM5_AUTH_INITIAL:
+ numresult = KRB5_KPASSWD_INITIAL_FLAG_NEEDED;
+ break;
case KADM5_PASS_Q_TOOSHORT:
case KADM5_PASS_REUSE:
case KADM5_PASS_Q_CLASS:
@@ -326,7 +320,7 @@ chpwfail:
if (ap_rep.length) {
ret = krb5_auth_con_setaddrs(context, auth_context,
- local_faddr->address, NULL);
+ local_addr->address, NULL);
if (ret) {
numresult = KRB5_KPASSWD_HARDERROR;
strlcpy(strresult,
@@ -366,7 +360,7 @@ chpwfail:
to mk_error do. */
krberror.error = ret;
krberror.error -= ERROR_TABLE_BASE_krb5;
- if (krberror.error < 0 || krberror.error > KRB_ERR_MAX)
+ if (krberror.error > KRB_ERR_MAX)
krberror.error = KRB_ERR_GENERIC;
krberror.client = NULL;
@@ -436,29 +430,15 @@ bailout:
/* Dispatch routine for set/change password */
void
-dispatch(void *handle, struct sockaddr *local_saddr,
- const krb5_fulladdr *remote_faddr, krb5_data *request, int is_tcp,
+dispatch(void *handle, const krb5_fulladdr *local_addr,
+ const krb5_fulladdr *remote_addr, krb5_data *request, int is_tcp,
verto_ctx *vctx, loop_respond_fn respond, void *arg)
{
krb5_error_code ret;
krb5_keytab kt = NULL;
kadm5_server_handle_t server_handle = (kadm5_server_handle_t)handle;
- krb5_fulladdr local_faddr;
- krb5_address **local_kaddrs = NULL, local_kaddr_buf;
krb5_data *response = NULL;
- if (local_saddr == NULL) {
- ret = krb5_os_localaddr(server_handle->context, &local_kaddrs);
- if (ret != 0)
- goto egress;
-
- local_faddr.address = local_kaddrs[0];
- local_faddr.port = 0;
- } else {
- local_faddr.address = &local_kaddr_buf;
- init_addr(&local_faddr, local_saddr);
- }
-
ret = krb5_kt_resolve(server_handle->context, "KDB:", &kt);
if (ret != 0) {
krb5_klog_syslog(LOG_ERR, _("chpw: Couldn't open admin keytab %s"),
@@ -474,14 +454,13 @@ dispatch(void *handle, struct sockaddr *local_saddr,
handle,
server_handle->params.realm,
kt,
- &local_faddr,
- remote_faddr,
+ local_addr,
+ remote_addr,
request,
response);
egress:
if (ret)
krb5_free_data(server_handle->context, response);
- krb5_free_addresses(server_handle->context, local_kaddrs);
krb5_kt_close(server_handle->context, kt);
(*respond)(arg, ret, ret == 0 ? response : NULL);
}
diff --git a/src/kadmin/server/server_stubs.c b/src/kadmin/server/server_stubs.c
index 86c162590e4b..cfef97fec147 100644
--- a/src/kadmin/server/server_stubs.c
+++ b/src/kadmin/server/server_stubs.c
@@ -12,10 +12,10 @@
#include <kadm5/admin.h>
#include <kadm5/kadm_rpc.h>
#include <kadm5/server_internal.h>
-#include <kadm5/server_acl.h>
#include <syslog.h>
#include <adm_proto.h> /* krb5_klog_syslog */
#include "misc.h"
+#include "auth.h"
extern gss_name_t gss_changepw_name;
extern gss_name_t gss_oldchangepw_name;
@@ -216,19 +216,6 @@ static gss_name_t acceptor_name(gss_ctx_id_t context)
return name;
}
-static int cmp_gss_krb5_name(kadm5_server_handle_t handle,
- gss_name_t gss_name, krb5_principal princ)
-{
- krb5_principal princ2;
- int status;
-
- if (! gss_to_krb5_name(handle, gss_name, &princ2))
- return 0;
- status = krb5_principal_compare(handle->context, princ, princ2);
- krb5_free_principal(handle->context, princ2);
- return status;
-}
-
static int gss_to_krb5_name(kadm5_server_handle_t handle,
gss_name_t gss_name, krb5_principal *princ)
{
@@ -314,12 +301,76 @@ stub_cleanup(kadm5_server_handle_t handle, char *princ_str,
{
OM_uint32 minor_stat;
+ auth_end(handle->context);
free_server_handle(handle);
free(princ_str);
gss_release_buffer(&minor_stat, client_name);
gss_release_buffer(&minor_stat, service_name);
}
+static krb5_boolean
+stub_auth(kadm5_server_handle_t handle, int opcode, krb5_const_principal p1,
+ krb5_const_principal p2, const char *s1, const char *s2)
+{
+ return auth(handle->context, opcode, handle->current_caller, p1, p2,
+ s1, s2, NULL, 0);
+}
+
+static krb5_boolean
+stub_auth_pol(kadm5_server_handle_t handle, int opcode, const char *policy,
+ const kadm5_policy_ent_rec *polent, long mask)
+{
+ return auth(handle->context, opcode, handle->current_caller, NULL, NULL,
+ policy, NULL, polent, mask);
+}
+
+static krb5_boolean
+stub_auth_restrict(kadm5_server_handle_t handle, int opcode,
+ kadm5_principal_ent_t ent, long *mask)
+{
+ return auth_restrict(handle->context, opcode, handle->current_caller,
+ ent, mask);
+}
+
+/* Return true if the client authenticated to kadmin/changepw and princ is not
+ * the client principal. */
+static krb5_boolean
+changepw_not_self(kadm5_server_handle_t handle, struct svc_req *rqstp,
+ krb5_const_principal princ)
+{
+ return CHANGEPW_SERVICE(rqstp) &&
+ !krb5_principal_compare(handle->context, handle->current_caller,
+ princ);
+}
+
+static krb5_boolean
+ticket_is_initial(struct svc_req *rqstp)
+{
+ OM_uint32 status, minor_stat;
+ krb5_flags flags;
+
+ status = gss_krb5_get_tkt_flags(&minor_stat, rqstp->rq_svccred, &flags);
+ if (status != GSS_S_COMPLETE)
+ return 0;
+ return (flags & TKT_FLG_INITIAL) != 0;
+}
+
+/* If a key change request is for the client's own principal, verify that the
+ * client used an initial ticket and enforce the policy min_life. */
+static kadm5_ret_t
+check_self_keychange(kadm5_server_handle_t handle, struct svc_req *rqstp,
+ krb5_principal princ)
+{
+ if (!krb5_principal_compare(handle->context, handle->current_caller,
+ princ))
+ return 0;
+
+ if (!ticket_is_initial(rqstp))
+ return KADM5_AUTH_INITIAL;
+
+ return check_min_life(handle, princ, NULL, 0);
+}
+
static int
log_unauth(
char *op,
@@ -387,7 +438,6 @@ create_principal_2_svc(cprinc_arg *arg, generic_ret *ret,
gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
kadm5_server_handle_t handle;
- restriction_t *rp;
const char *errmsg = NULL;
ret->code = stub_setup(arg->api_version, rqstp, arg->rec.principal,
@@ -396,11 +446,8 @@ create_principal_2_svc(cprinc_arg *arg, generic_ret *ret,
if (ret->code)
goto exit_func;
- if (CHANGEPW_SERVICE(rqstp)
- || !kadm5int_acl_check(handle->context, rqst2name(rqstp), ACL_ADD,
- arg->rec.principal, &rp)
- || kadm5int_acl_impose_restrictions(handle->context,
- &arg->rec, &arg->mask, rp)) {
+ if (CHANGEPW_SERVICE(rqstp) ||
+ !stub_auth_restrict(handle, OP_ADDPRINC, &arg->rec, &arg->mask)) {
ret->code = KADM5_AUTH_ADD;
log_unauth("kadm5_create_principal", prime_arg,
&client_name, &service_name, rqstp);
@@ -431,7 +478,6 @@ create_principal3_2_svc(cprinc3_arg *arg, generic_ret *ret,
gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
kadm5_server_handle_t handle;
- restriction_t *rp;
const char *errmsg = NULL;
ret->code = stub_setup(arg->api_version, rqstp, arg->rec.principal,
@@ -440,11 +486,8 @@ create_principal3_2_svc(cprinc3_arg *arg, generic_ret *ret,
if (ret->code)
goto exit_func;
- if (CHANGEPW_SERVICE(rqstp)
- || !kadm5int_acl_check(handle->context, rqst2name(rqstp), ACL_ADD,
- arg->rec.principal, &rp)
- || kadm5int_acl_impose_restrictions(handle->context,
- &arg->rec, &arg->mask, rp)) {
+ if (CHANGEPW_SERVICE(rqstp) ||
+ !stub_auth_restrict(handle, OP_ADDPRINC, &arg->rec, &arg->mask)) {
ret->code = KADM5_AUTH_ADD;
log_unauth("kadm5_create_principal", prime_arg,
&client_name, &service_name, rqstp);
@@ -498,9 +541,8 @@ delete_principal_2_svc(dprinc_arg *arg, generic_ret *ret,
if (ret->code)
goto exit_func;
- if (CHANGEPW_SERVICE(rqstp)
- || !kadm5int_acl_check(handle->context, rqst2name(rqstp), ACL_DELETE,
- arg->princ, NULL)) {
+ if (CHANGEPW_SERVICE(rqstp) ||
+ !stub_auth(handle, OP_DELPRINC, arg->princ, NULL, NULL, NULL)) {
ret->code = KADM5_AUTH_DELETE;
log_unauth("kadm5_delete_principal", prime_arg,
&client_name, &service_name, rqstp);
@@ -540,7 +582,6 @@ modify_principal_2_svc(mprinc_arg *arg, generic_ret *ret,
gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
kadm5_server_handle_t handle;
- restriction_t *rp;
const char *errmsg = NULL;
ret->code = stub_setup(arg->api_version, rqstp, arg->rec.principal,
@@ -549,11 +590,8 @@ modify_principal_2_svc(mprinc_arg *arg, generic_ret *ret,
if (ret->code)
goto exit_func;
- if (CHANGEPW_SERVICE(rqstp)
- || !kadm5int_acl_check(handle->context, rqst2name(rqstp), ACL_MODIFY,
- arg->rec.principal, &rp)
- || kadm5int_acl_impose_restrictions(handle->context,
- &arg->rec, &arg->mask, rp)) {
+ if (CHANGEPW_SERVICE(rqstp) ||
+ !stub_auth_restrict(handle, OP_MODPRINC, &arg->rec, &arg->mask)) {
ret->code = KADM5_AUTH_MODIFY;
log_unauth("kadm5_modify_principal", prime_arg,
&client_name, &service_name, rqstp);
@@ -592,7 +630,6 @@ rename_principal_2_svc(rprinc_arg *arg, generic_ret *ret,
gss_buffer_desc client_name = GSS_C_EMPTY_BUFFER;
gss_buffer_desc service_name = GSS_C_EMPTY_BUFFER;
kadm5_server_handle_t handle;
- restriction_t *rp;
const char *errmsg = NULL;
size_t tlen1, tlen2, clen, slen;
char *tdots1, *tdots2, *cdots, *sdots;
@@ -617,29 +654,19 @@ rename_principal_2_svc(rprinc_arg *arg, generic_ret *ret,
slen = service_name.length;
trunc_name(&slen, &sdots);
- ret->code = KADM5_OK;
- if (! CHANGEPW_SERVICE(rqstp)) {
- if (!kadm5int_acl_check(handle->context, rqst2name(rqstp),
- ACL_DELETE, arg->src, NULL))
+ if (CHANGEPW_SERVICE(rqstp) ||
+ !stub_auth(handle, OP_RENPRINC, arg->src, arg->dest, NULL, NULL)) {
+ ret->code = KADM5_AUTH_INSUFFICIENT;
+ log_unauth("kadm5_rename_principal", prime_arg1, &client_name,
+ &service_name, rqstp);
+ } else {
+ ret->code = check_lockdown_keys(handle, arg->src);
+ if (ret->code == KADM5_PROTECT_KEYS) {
+ log_unauth("kadm5_rename_principal", prime_arg1, &client_name,
+ &service_name, rqstp);
ret->code = KADM5_AUTH_DELETE;
- /* any restrictions at all on the ADD kills the RENAME */
- if (!kadm5int_acl_check(handle->context, rqst2name(rqstp),
- ACL_ADD, arg->dest, &rp) || rp) {
- if (ret->code == KADM5_AUTH_DELETE)
- ret->code = KADM5_AUTH_INSUFFICIENT;
- else
- ret->code = KADM5_AUTH_ADD;
- }
- if (ret->code == KADM5_OK) {
- ret->code = check_lockdown_keys(handle, arg->src);
- if (ret->code == KADM5_PROTECT_KEYS) {
- log_unauth("kadm5_rename_principal", prime_arg1, &client_name,
- &service_name, rqstp);
- ret->code = KADM5_AUTH_DELETE;
- }
}
- } else
- ret->code = KADM5_AUTH_INSUFFICIENT;
+ }
if (ret->code != KADM5_OK) {
/* okay to cast lengths to int because trunc_name limits max value */
krb5_klog_syslog(LOG_NOTICE,
@@ -696,12 +723,8 @@ get_principal_2_svc(gprinc_arg *arg, gprinc_ret *ret, struct svc_req *rqstp)
funcname = "kadm5_get_principal";
- if (! cmp_gss_krb5_name(handle, rqst2name(rqstp), arg->princ) &&
- (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context,
- rqst2name(rqstp),
- ACL_INQUIRE,
- arg->princ,
- NULL))) {
+ if (changepw_not_self(handle, rqstp, arg->princ) ||
+ !stub_auth(handle, OP_GETPRINC, arg->princ, NULL, NULL, NULL)) {
ret->code = KADM5_AUTH_GET;
log_unauth(funcname, prime_arg,
&client_name, &service_name, rqstp);
@@ -743,11 +766,8 @@ get_princs_2_svc(gprincs_arg *arg, gprincs_ret *ret, struct svc_req *rqstp)
if (prime_arg == NULL)
prime_arg = "*";
- if (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context,
- rqst2name(rqstp),
- ACL_LIST,
- NULL,
- NULL)) {
+ if (CHANGEPW_SERVICE(rqstp) ||
+ !stub_auth(handle, OP_LISTPRINCS, NULL, NULL, NULL, NULL)) {
ret->code = KADM5_AUTH_LIST;
log_unauth("kadm5_get_principals", prime_arg,
&client_name, &service_name, rqstp);
@@ -793,17 +813,15 @@ chpass_principal_2_svc(chpass_arg *arg, generic_ret *ret,
&service_name, rqstp);
ret->code = KADM5_AUTH_CHANGEPW;
}
- } else if (cmp_gss_krb5_name(handle, rqst2name(rqstp), arg->princ)) {
- ret->code = chpass_principal_wrapper_3(handle, arg->princ, FALSE, 0,
- NULL, arg->pass);
- } else if (!(CHANGEPW_SERVICE(rqstp)) &&
- kadm5int_acl_check(handle->context, rqst2name(rqstp),
- ACL_CHANGEPW, arg->princ, NULL)) {
- ret->code = kadm5_chpass_principal(handle, arg->princ, arg->pass);
- } else {
+ } else if (changepw_not_self(handle, rqstp, arg->princ) ||
+ !stub_auth(handle, OP_CPW, arg->princ, NULL, NULL, NULL)) {
+ ret->code = KADM5_AUTH_CHANGEPW;
log_unauth("kadm5_chpass_principal", prime_arg,
&client_name, &service_name, rqstp);
- ret->code = KADM5_AUTH_CHANGEPW;
+ } else {
+ ret->code = check_self_keychange(handle, rqstp, arg->princ);
+ if (!ret->code)
+ ret->code = kadm5_chpass_principal(handle, arg->princ, arg->pass);
}
if (ret->code != KADM5_AUTH_CHANGEPW) {
@@ -845,20 +863,18 @@ chpass_principal3_2_svc(chpass3_arg *arg, generic_ret *ret,
&service_name, rqstp);
ret->code = KADM5_AUTH_CHANGEPW;
}
- } else if (cmp_gss_krb5_name(handle, rqst2name(rqstp), arg->princ)) {
- ret->code = chpass_principal_wrapper_3(handle, arg->princ,
- arg->keepold, arg->n_ks_tuple,
- arg->ks_tuple, arg->pass);
- } else if (!(CHANGEPW_SERVICE(rqstp)) &&
- kadm5int_acl_check(handle->context, rqst2name(rqstp),
- ACL_CHANGEPW, arg->princ, NULL)) {
- ret->code = kadm5_chpass_principal_3(handle, arg->princ, arg->keepold,
- arg->n_ks_tuple, arg->ks_tuple,
- arg->pass);
- } else {
+ } else if (changepw_not_self(handle, rqstp, arg->princ) ||
+ !stub_auth(handle, OP_CPW, arg->princ, NULL, NULL, NULL)) {
+ ret->code = KADM5_AUTH_CHANGEPW;
log_unauth("kadm5_chpass_principal", prime_arg,
&client_name, &service_name, rqstp);
- ret->code = KADM5_AUTH_CHANGEPW;
+ } else {
+ ret->code = check_self_keychange(handle, rqstp, arg->princ);
+ if (!ret->code) {
+ ret->code = kadm5_chpass_principal_3(handle, arg->princ,
+ arg->keepold, arg->n_ks_tuple,
+ arg->ks_tuple, arg->pass);
+ }
}
if (ret->code != KADM5_AUTH_CHANGEPW) {
@@ -901,8 +917,7 @@ setv4key_principal_2_svc(setv4key_arg *arg, generic_ret *ret,
ret->code = KADM5_AUTH_SETKEY;
}
} else if (!(CHANGEPW_SERVICE(rqstp)) &&
- kadm5int_acl_check(handle->context, rqst2name(rqstp),
- ACL_SETKEY, arg->princ, NULL)) {
+ stub_auth(handle, OP_SETKEY, arg->princ, NULL, NULL, NULL)) {
ret->code = kadm5_setv4key_principal(handle, arg->princ,
arg->keyblock);
} else {
@@ -952,8 +967,7 @@ setkey_principal_2_svc(setkey_arg *arg, generic_ret *ret,
ret->code = KADM5_AUTH_SETKEY;
}
} else if (!(CHANGEPW_SERVICE(rqstp)) &&
- kadm5int_acl_check(handle->context, rqst2name(rqstp),
- ACL_SETKEY, arg->princ, NULL)) {
+ stub_auth(handle, OP_SETKEY, arg->princ, NULL, NULL, NULL)) {
ret->code = kadm5_setkey_principal(handle, arg->princ, arg->keyblocks,
arg->n_keys);
} else {
@@ -1002,8 +1016,7 @@ setkey_principal3_2_svc(setkey3_arg *arg, generic_ret *ret,
ret->code = KADM5_AUTH_SETKEY;
}
} else if (!(CHANGEPW_SERVICE(rqstp)) &&
- kadm5int_acl_check(handle->context, rqst2name(rqstp),
- ACL_SETKEY, arg->princ, NULL)) {
+ stub_auth(handle, OP_SETKEY, arg->princ, NULL, NULL, NULL)) {
ret->code = kadm5_setkey_principal_3(handle, arg->princ, arg->keepold,
arg->n_ks_tuple, arg->ks_tuple,
arg->keyblocks, arg->n_keys);
@@ -1053,8 +1066,7 @@ setkey_principal4_2_svc(setkey4_arg *arg, generic_ret *ret,
ret->code = KADM5_AUTH_SETKEY;
}
} else if (!(CHANGEPW_SERVICE(rqstp)) &&
- kadm5int_acl_check(handle->context, rqst2name(rqstp),
- ACL_SETKEY, arg->princ, NULL)) {
+ stub_auth(handle, OP_SETKEY, arg->princ, NULL, NULL, NULL)) {
ret->code = kadm5_setkey_principal_4(handle, arg->princ, arg->keepold,
arg->key_data, arg->n_key_data);
} else {
@@ -1079,8 +1091,8 @@ exit_func:
return TRUE;
}
-/* Empty out *keys/*nkeys if princ is protected with the lockdown attribute, or
- * if we fail to check. */
+/* Empty out *keys / *nkeys if princ is protected with the lockdown
+ * attribute, or if we fail to check. */
static kadm5_ret_t
chrand_check_lockdown(kadm5_server_handle_t handle, krb5_principal princ,
krb5_keyblock **keys, int *nkeys)
@@ -1119,17 +1131,17 @@ chrand_principal_2_svc(chrand_arg *arg, chrand_ret *ret, struct svc_req *rqstp)
funcname = "kadm5_randkey_principal";
- if (cmp_gss_krb5_name(handle, rqst2name(rqstp), arg->princ)) {
- ret->code = randkey_principal_wrapper_3(handle, arg->princ, FALSE, 0,
- NULL, &k, &nkeys);
- } else if (!(CHANGEPW_SERVICE(rqstp)) &&
- kadm5int_acl_check(handle->context, rqst2name(rqstp),
- ACL_CHANGEPW, arg->princ, NULL)) {
- ret->code = kadm5_randkey_principal(handle, arg->princ, &k, &nkeys);
- } else {
+ if (changepw_not_self(handle, rqstp, arg->princ) ||
+ !stub_auth(handle, OP_CHRAND, arg->princ, NULL, NULL, NULL)) {
+ ret->code = KADM5_AUTH_CHANGEPW;
log_unauth(funcname, prime_arg,
&client_name, &service_name, rqstp);
- ret->code = KADM5_AUTH_CHANGEPW;
+ } else {
+ ret->code = check_self_keychange(handle, rqstp, arg->princ);
+ if (!ret->code) {
+ ret->code = kadm5_randkey_principal(handle, arg->princ,
+ &k, &nkeys);
+ }
}
if (ret->code == KADM5_OK) {
@@ -1176,20 +1188,19 @@ chrand_principal3_2_svc(chrand3_arg *arg, chrand_ret *ret,
funcname = "kadm5_randkey_principal";
- if (cmp_gss_krb5_name(handle, rqst2name(rqstp), arg->princ)) {
- ret->code = randkey_principal_wrapper_3(handle, arg->princ,
- arg->keepold, arg->n_ks_tuple,
- arg->ks_tuple, &k, &nkeys);
- } else if (!(CHANGEPW_SERVICE(rqstp)) &&
- kadm5int_acl_check(handle->context, rqst2name(rqstp),
- ACL_CHANGEPW, arg->princ, NULL)) {
- ret->code = kadm5_randkey_principal_3(handle, arg->princ, arg->keepold,
- arg->n_ks_tuple, arg->ks_tuple,
- &k, &nkeys);
- } else {
+ if (changepw_not_self(handle, rqstp, arg->princ) ||
+ !stub_auth(handle, OP_CHRAND, arg->princ, NULL, NULL, NULL)) {
+ ret->code = KADM5_AUTH_CHANGEPW;
log_unauth(funcname, prime_arg,
&client_name, &service_name, rqstp);
- ret->code = KADM5_AUTH_CHANGEPW;
+ } else {
+ ret->code = check_self_keychange(handle, rqstp, arg->princ);
+ if (!ret->code) {
+ ret->code = kadm5_randkey_principal_3(handle, arg->princ,
+ arg->keepold,
+ arg->n_ks_tuple,
+ arg->ks_tuple, &k, &nkeys);
+ }
}
if (ret->code == KADM5_OK) {
@@ -1233,9 +1244,9 @@ create_policy_2_svc(cpol_arg *arg, generic_ret *ret, struct svc_req *rqstp)
prime_arg = arg->rec.policy;
- if (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context,
- rqst2name(rqstp),
- ACL_ADD, NULL, NULL)) {
+ if (CHANGEPW_SERVICE(rqstp) ||
+ !stub_auth_pol(handle, OP_ADDPOL, arg->rec.policy,
+ &arg->rec, arg->mask)) {
ret->code = KADM5_AUTH_ADD;
log_unauth("kadm5_create_policy", prime_arg,
&client_name, &service_name, rqstp);
@@ -1275,9 +1286,8 @@ delete_policy_2_svc(dpol_arg *arg, generic_ret *ret, struct svc_req *rqstp)
prime_arg = arg->name;
- if (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context,
- rqst2name(rqstp),
- ACL_DELETE, NULL, NULL)) {
+ if (CHANGEPW_SERVICE(rqstp) ||
+ !stub_auth(handle, OP_DELPOL, NULL, NULL, arg->name, NULL)) {
log_unauth("kadm5_delete_policy", prime_arg,
&client_name, &service_name, rqstp);
ret->code = KADM5_AUTH_DELETE;
@@ -1316,9 +1326,9 @@ modify_policy_2_svc(mpol_arg *arg, generic_ret *ret, struct svc_req *rqstp)
prime_arg = arg->rec.policy;
- if (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context,
- rqst2name(rqstp),
- ACL_MODIFY, NULL, NULL)) {
+ if (CHANGEPW_SERVICE(rqstp) ||
+ !stub_auth_pol(handle, OP_MODPOL, arg->rec.policy,
+ &arg->rec, arg->mask)) {
log_unauth("kadm5_modify_policy", prime_arg,
&client_name, &service_name, rqstp);
ret->code = KADM5_AUTH_MODIFY;
@@ -1349,7 +1359,9 @@ get_policy_2_svc(gpol_arg *arg, gpol_ret *ret, struct svc_req *rqstp)
kadm5_ret_t ret2;
kadm5_principal_ent_rec caller_ent;
kadm5_server_handle_t handle;
- const char *errmsg = NULL;
+ const char *errmsg = NULL, *cpolicy = NULL;
+
+ memset(&caller_ent, 0, sizeof(caller_ent));
ret->code = stub_setup(arg->api_version, rqstp, NULL, &handle,
&ret->api_version, &client_name, &service_name,
@@ -1361,31 +1373,20 @@ get_policy_2_svc(gpol_arg *arg, gpol_ret *ret, struct svc_req *rqstp)
prime_arg = arg->name;
- ret->code = KADM5_AUTH_GET;
- if (!CHANGEPW_SERVICE(rqstp) && kadm5int_acl_check(handle->context,
- rqst2name(rqstp),
- ACL_INQUIRE, NULL, NULL))
- ret->code = KADM5_OK;
- else {
- ret->code = kadm5_get_principal(handle->lhandle,
- handle->current_caller, &caller_ent,
- KADM5_PRINCIPAL_NORMAL_MASK);
- if (ret->code == KADM5_OK) {
- if (caller_ent.aux_attributes & KADM5_POLICY &&
- strcmp(caller_ent.policy, arg->name) == 0) {
- ret->code = KADM5_OK;
- } else {
- ret->code = KADM5_AUTH_GET;
- }
- ret2 = kadm5_free_principal_ent(handle->lhandle,
- &caller_ent);
- ret->code = ret->code ? ret->code : ret2;
- }
- }
+ /* Look up the client principal's policy value. */
+ ret2 = kadm5_get_principal(handle->lhandle, handle->current_caller,
+ &caller_ent, KADM5_PRINCIPAL_NORMAL_MASK);
+ if (ret2 == KADM5_OK && (caller_ent.aux_attributes & KADM5_POLICY))
+ cpolicy = caller_ent.policy;
- if (ret->code == KADM5_OK) {
+ ret->code = KADM5_AUTH_GET;
+ if ((CHANGEPW_SERVICE(rqstp) &&
+ (cpolicy == NULL || strcmp(cpolicy, arg->name) != 0)) ||
+ !stub_auth(handle, OP_GETPOL, NULL, NULL, arg->name, cpolicy)) {
+ ret->code = KADM5_AUTH_GET;
+ log_unauth(funcname, prime_arg, &client_name, &service_name, rqstp);
+ } else {
ret->code = kadm5_get_policy(handle, arg->name, &ret->rec);
-
if (ret->code != 0)
errmsg = krb5_get_error_message(handle->context, ret->code);
@@ -1394,13 +1395,10 @@ get_policy_2_svc(gpol_arg *arg, gpol_ret *ret, struct svc_req *rqstp)
&client_name, &service_name, rqstp);
if (errmsg != NULL)
krb5_free_error_message(handle->context, errmsg);
-
- } else {
- log_unauth(funcname, prime_arg,
- &client_name, &service_name, rqstp);
}
exit_func:
+ (void)kadm5_free_principal_ent(handle->lhandle, &caller_ent);
stub_cleanup(handle, NULL, &client_name, &service_name);
return TRUE;
}
@@ -1424,9 +1422,8 @@ get_pols_2_svc(gpols_arg *arg, gpols_ret *ret, struct svc_req *rqstp)
if (prime_arg == NULL)
prime_arg = "*";
- if (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context,
- rqst2name(rqstp),
- ACL_LIST, NULL, NULL)) {
+ if (CHANGEPW_SERVICE(rqstp) ||
+ !stub_auth(handle, OP_LISTPOLS, NULL, NULL, NULL, NULL)) {
ret->code = KADM5_AUTH_LIST;
log_unauth("kadm5_get_policies", prime_arg,
&client_name, &service_name, rqstp);
@@ -1494,10 +1491,8 @@ purgekeys_2_svc(purgekeys_arg *arg, generic_ret *ret, struct svc_req *rqstp)
funcname = "kadm5_purgekeys";
- if (!cmp_gss_krb5_name(handle, rqst2name(rqstp), arg->princ) &&
- (CHANGEPW_SERVICE(rqstp)
- || !kadm5int_acl_check(handle->context, rqst2name(rqstp), ACL_MODIFY,
- arg->princ, NULL))) {
+ if (CHANGEPW_SERVICE(rqstp) ||
+ !stub_auth(handle, OP_PURGEKEYS, arg->princ, NULL, NULL, NULL)) {
ret->code = KADM5_AUTH_MODIFY;
log_unauth(funcname, prime_arg, &client_name, &service_name, rqstp);
} else {
@@ -1532,12 +1527,8 @@ get_strings_2_svc(gstrings_arg *arg, gstrings_ret *ret, struct svc_req *rqstp)
if (ret->code)
goto exit_func;
- if (! cmp_gss_krb5_name(handle, rqst2name(rqstp), arg->princ) &&
- (CHANGEPW_SERVICE(rqstp) || !kadm5int_acl_check(handle->context,
- rqst2name(rqstp),
- ACL_INQUIRE,
- arg->princ,
- NULL))) {
+ if (CHANGEPW_SERVICE(rqstp) ||
+ !stub_auth(handle, OP_GETSTRS, arg->princ, NULL, NULL, NULL)) {
ret->code = KADM5_AUTH_GET;
log_unauth("kadm5_get_strings", prime_arg,
&client_name, &service_name, rqstp);
@@ -1574,9 +1565,9 @@ set_string_2_svc(sstring_arg *arg, generic_ret *ret, struct svc_req *rqstp)
if (ret->code)
goto exit_func;
- if (CHANGEPW_SERVICE(rqstp)
- || !kadm5int_acl_check(handle->context, rqst2name(rqstp), ACL_MODIFY,
- arg->princ, NULL)) {
+ if (CHANGEPW_SERVICE(rqstp) ||
+ !stub_auth(handle, OP_SETSTR, arg->princ, NULL,
+ arg->key, arg->value)) {
ret->code = KADM5_AUTH_MODIFY;
log_unauth("kadm5_mod_strings", prime_arg,
&client_name, &service_name, rqstp);
@@ -1665,8 +1656,7 @@ get_principal_keys_2_svc(getpkeys_arg *arg, getpkeys_ret *ret,
goto exit_func;
if (!(CHANGEPW_SERVICE(rqstp)) &&
- kadm5int_acl_check(handle->context, rqst2name(rqstp),
- ACL_EXTRACT, arg->princ, NULL)) {
+ stub_auth(handle, OP_EXTRACT, arg->princ, NULL, NULL, NULL)) {
ret->code = kadm5_get_principal_keys(handle, arg->princ, arg->kvno,
&ret->key_data, &ret->n_key_data);
} else {