]> git.ipfire.org Git - thirdparty/krb5.git/commitdiff
Use kadm5_auth interface in kadmind
authorGreg Hudson <ghudson@mit.edu>
Fri, 30 Jun 2017 15:54:09 +0000 (11:54 -0400)
committerGreg Hudson <ghudson@mit.edu>
Thu, 17 Aug 2017 15:51:14 +0000 (11:51 -0400)
Convert the ACL code to a kadm5_auth module, and create a new module
for self-service authorization.  Use the kadm5_auth consumer code
instead of directly using the ACL code to authorize requests.

Do not assume self-service authorization in the RPC stubs or in
schpw_util_wrapper().  For key change requests, enforce the initial
ticket requirement whenever a client changes its own keys, regardless
of how it is authorized or which protocol it uses.  The initial ticket
check for protocol version 1 in process_chpw_request() is redundant
after this change, so remove it.

The old kadmin-based password change client authenticates to
kadmin/changepw and performs self-service get_principal, get_policy,
and chpass requests.  Continue to allow these operations, enforcing
the self-service requirement in addition to checking through the
kadm5_auth interface.  For get_policy requests, always look up the
client principal's policy name, for this check and for the
authorization layer's use.

The error messages for rename authorization failures are now more
vague (because there is a specific rename operation check in the
kadm5_auth interface, and we do not find out whether it failed due to
missing add or delete privileges).  Adjust t_kadmin_acl.py
accordingly.

ticket: 8595

19 files changed:
doc/admin/conf_files/kadm5_acl.rst
doc/admin/conf_files/kdc_conf.rst
doc/admin/conf_files/krb5_conf.rst
src/kadmin/server/Makefile.in
src/kadmin/server/auth.c
src/kadmin/server/auth.h
src/kadmin/server/auth_acl.c
src/kadmin/server/auth_acl.h [deleted file]
src/kadmin/server/auth_self.c [new file with mode: 0644]
src/kadmin/server/deps
src/kadmin/server/ipropd_svc.c
src/kadmin/server/misc.c
src/kadmin/server/misc.h
src/kadmin/server/ovsec_kadmd.c
src/kadmin/server/schpw.c
src/kadmin/server/server_stubs.c
src/lib/kadm5/kadm_err.et
src/lib/krb5/krb/plugin.c
src/tests/t_kadmin_acl.py

index 138a2d76e861c1ec8848e81924c20dbfe3c735ac..290bf0e037a7ac197bf598c42f393d0d8aeb1cc9 100644 (file)
@@ -144,6 +144,19 @@ principals.
 any principal that it creates or modifies will not be able to get
 postdateable tickets or tickets with a life of longer than 9 hours.
 
+MODULE BEHAVIOR
+---------------
+
+The ACL file can coexist with other authorization modules in release
+1.16 and later, as configured in the :ref:`kadm5_auth` section of
+:ref:`krb5.conf(5)`.  The ACL file will positively authorize
+operations according to the rules above, but will never
+authoritatively deny an operation, so other modules can authorize
+operations in addition to those authorized by the ACL file.
+
+To operate without an ACL file, set the *acl_file* variable in
+:ref:`kdc.conf(5)` to the empty string with ``acl_file = ""``.
+
 SEE ALSO
 --------
 
index 3c11e45be56937ab9902fbcd1ace0d93ba7a63ca..3af1c3796e6b54177ae10616f1a8b788f47f6b92 100644 (file)
@@ -86,9 +86,10 @@ The following tags may be specified in a [realms] subsection:
 **acl_file**
     (String.)  Location of the access control list file that
     :ref:`kadmind(8)` uses to determine which principals are allowed
-    which permissions on the Kerberos database.  The default value is
-    |kdcdir|\ ``/kadm5.acl``.  For more information on Kerberos ACL
-    file see :ref:`kadm5.acl(5)`.
+    which permissions on the Kerberos database.  To operate without an
+    ACL file, set this relation to the empty string with ``acl_file =
+    ""``.  The default value is |kdcdir|\ ``/kadm5.acl``.  For more
+    information on Kerberos ACL file see :ref:`kadm5.acl(5)`.
 
 **database_module**
     (String.)  This relation indicates the name of the configuration
index 3a09279020025c9fd8585416232506793afeb6c0..7951149132928ebc83eff8000aeb456bf15c1541 100644 (file)
@@ -778,6 +778,26 @@ interface can be used to write a plugin to synchronize MIT Kerberos
 with another database such as Active Directory.  No plugins are built
 in for this interface.
 
+.. _kadm5_auth:
+
+kadm5_auth interface
+====================
+
+The kadm5_auth section (introduced in release 1.16) controls modules
+for the kadmin authorization interface, which determines whether a
+client principal is allowed to perform a kadmin operation.  The
+following built-in modules exist for this interface:
+
+**acl**
+    This module reads the :ref:`kadm5.acl(5)` file, and authorizes
+    operations which are allowed according to the rules in the file.
+
+**self**
+    This module authorizes self-service operations including password
+    changes, creation of new random keys, fetching the client's
+    principal record or string attributes, and fetching the policy
+    record associated with the client principal.
+
 .. _clpreauth:
 
 .. _kdcpreauth:
index 2f97ab9e31b1e794aeaf5d770ccaa90f3062fa74..16d5cc54aa4c37423d7f72af3b8e8878eac225ef 100644 (file)
@@ -7,10 +7,10 @@ LOCALINCLUDES = -I$(top_srcdir)/lib/gssapi/generic \
        -I$(BUILDTOP)/lib/gssapi/krb5 -I$(top_srcdir)/lib/kadm5/srv
 
 PROG = kadmind
-OBJS = auth.o auth_acl.o kadm_rpc_svc.o server_stubs.o ovsec_kadmd.o schpw.o \
-       misc.o ipropd_svc.o
-SRCS = auth.o auth_acl.c 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)
 
index ccff0eb3d5ceed9767aee1a9569095675c416478..081b20a8b678a8c027e7f389245b2c8feb65c4e7 100644 (file)
@@ -66,7 +66,14 @@ auth_init(krb5_context context, const char *acl_file)
     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;
index 01e78ccf961919f4c1751e3a0948dd140635bd2b..4d265add7c0d0df5f505204008542ce547c902cd 100644 (file)
@@ -75,4 +75,11 @@ krb5_boolean auth_restrict(krb5_context context, int opcode,
 /* 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 */
index 389ff0bdc077185bd4a806ba2688e17f8975f955..1f804badf11e322da6ddaabee02f8dc8014f812b 100644 (file)
@@ -1,5 +1,5 @@
 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* kadmin/server/auth_acl.c */
+/* kadmin/server/auth_acl.c - ACL kadm5_auth module */
 /*
  * Copyright 1995-2004, 2007, 2008, 2017 by the Massachusetts Institute of
  * Technology.  All Rights Reserved.
 #include "k5-int.h"
 #include <syslog.h>
 #include <kadm5/admin.h>
+#include <krb5/kadm5_auth_plugin.h>
 #include "adm_proto.h"
-#include "auth_acl.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;
@@ -68,8 +92,6 @@ struct acl_state {
     struct acl_entry *list;
 };
 
-static struct acl_state aclstate;
-
 /*
  * 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
@@ -347,68 +369,6 @@ parse_line(krb5_context context, const char *line, const char *fname)
     return entry;
 }
 
-/* Impose restrictions, modifying *rec and *mask. */
-krb5_error_code
-acl_impose_restrictions(krb5_context context, kadm5_principal_ent_rec *rec,
-                        long *mask, struct kadm5_auth_restrictions *rs)
-{
-    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) {
-        rec->attributes |= rs->require_attrs;
-        rec->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 (rec->policy != NULL && strcmp(rec->policy, rs->policy) != 0) {
-            free(rec->policy);
-            rec->policy = NULL;
-        }
-        if (rec->policy == NULL) {
-            rec->policy = strdup(rs->policy);  /* XDR will free it */
-            if (!rec->policy)
-                return ENOMEM;
-        }
-        *mask |= KADM5_POLICY;
-    }
-    if (rs->mask & KADM5_PRINC_EXPIRE_TIME) {
-        if (!(*mask & KADM5_PRINC_EXPIRE_TIME) ||
-            ts_after(rec->princ_expire_time, ts_incr(now, rs->princ_lifetime)))
-            rec->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(rec->pw_expiration, ts_incr(now, rs->pw_lifetime)))
-            rec->pw_expiration = now + rs->pw_lifetime;
-        *mask |= KADM5_PW_EXPIRATION;
-    }
-    if (rs->mask & KADM5_MAX_LIFE) {
-        if (!(*mask & KADM5_MAX_LIFE) || rec->max_life > rs->max_life)
-            rec->max_life = rs->max_life;
-        *mask |= KADM5_MAX_LIFE;
-    }
-    if (rs->mask & KADM5_MAX_RLIFE) {
-        if (!(*mask & KADM5_MAX_RLIFE) ||
-            rec->max_renewable_life > rs->max_renewable_life)
-            rec->max_renewable_life = rs->max_renewable_life;
-        *mask |= KADM5_MAX_RLIFE;
-    }
-    return 0;
-}
-
 /* Free all ACL entries. */
 static void
 free_acl_entries(struct acl_state *state)
@@ -423,9 +383,10 @@ free_acl_entries(struct acl_state *state)
 }
 
 /* Open and parse the ACL file. */
-static void
+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;
@@ -438,7 +399,10 @@ load_acl_file(krb5_context context, const char *fname, struct acl_state *state)
     if (fp == NULL) {
         krb5_klog_syslog(LOG_ERR, _("%s while opening ACL file %s"),
                          error_message(errno), fname);
-        return;
+        ret = errno;
+        k5_setmsg(context, errno, _("Cannot open %s: %s"), fname,
+                  error_message(ret));
+        return ret;
     }
 
     set_cloexec_file(fp);
@@ -457,13 +421,17 @@ load_acl_file(krb5_context context, const char *fname, struct acl_state *state)
             free_acl_entries(state);
             free(line);
             fclose(fp);
-            return;
+            k5_setmsg(context, EINVAL,
+                      _("%s: syntax error at line %d <%.10s...>"),
+                      fname, lineno, line);
+            return EINVAL;
         }
         entry_slot = &(*entry_slot)->next;
         free(line);
     }
 
     fclose(fp);
+    return 0;
 }
 
 /*
@@ -552,25 +520,10 @@ find_entry(struct acl_state *state, krb5_const_principal client,
     return NULL;
 }
 
-/* Initialize the ACL context. */
-krb5_error_code
-acl_init(krb5_context context, const char *acl_file)
-{
-    load_acl_file(context, acl_file, &aclstate);
-    return 0;
-}
-
-/* Terminate the ACL context. */
-void
-acl_finish(krb5_context context)
-{
-    free_acl_entries(&aclstate);
-}
-
 /* Return true if op is permitted for this principal.  Set *rs_out (if not
  * NULL) according to any restrictions in the ACL entry. */
-krb5_boolean
-acl_check(krb5_context context, krb5_const_principal client, uint32_t op,
+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;
@@ -578,14 +531,225 @@ acl_check(krb5_context context, krb5_const_principal client, uint32_t op,
     if (rs_out != NULL)
         *rs_out = NULL;
 
-    entry = find_entry(&aclstate, client, target);
+    entry = find_entry((struct acl_state *)data, client, target);
     if (entry == NULL)
-        return FALSE;
+        return KRB5_PLUGIN_NO_HANDLE;
     if (!(entry->op_allowed & op))
-        return FALSE;
+        return KRB5_PLUGIN_NO_HANDLE;
 
     if (rs_out != NULL && entry->rs != NULL && entry->rs->mask)
         *rs_out = entry->rs;
 
-    return TRUE;
+    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_acl.h b/src/kadmin/server/auth_acl.h
deleted file mode 100644 (file)
index 55a8662..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/* kadmin/server/auth_acl.h */
-/*
- * Copyright 1995-2004, 2007, 2008 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.
- */
-
-#ifndef SERVER_ACL_H__
-#define SERVER_ACL_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 kadm5_auth_restrictions {
-    long mask;
-    krb5_flags require_attrs;
-    krb5_flags forbid_attrs;
-    krb5_deltat princ_lifetime;
-    krb5_deltat pw_lifetime;
-    krb5_deltat max_life;
-    krb5_deltat max_renewable_life;
-    char *policy;
-};
-
-krb5_error_code acl_init(krb5_context context, const char *acl_file);
-void acl_finish(krb5_context);
-krb5_boolean acl_check(krb5_context context, krb5_const_principal client,
-                       uint32_t op, krb5_const_principal target,
-                       struct kadm5_auth_restrictions **rs_out);
-krb5_error_code acl_impose_restrictions(krb5_context context,
-                                        kadm5_principal_ent_rec *rec,
-                                        long *mask,
-                                        struct kadm5_auth_restrictions *rs);
-
-#endif  /* SERVER_ACL_H__ */
diff --git a/src/kadmin/server/auth_self.c b/src/kadmin/server/auth_self.c
new file mode 100644 (file)
index 0000000..253d4bc
--- /dev/null
@@ -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;
+}
index e7cd3e6066eb3fe6e53fa46d9199bf449782423f..99aef7500e00959df3a0ae8934aea61b3808977a 100644 (file)
@@ -17,9 +17,28 @@ $(OUTPRE)auth_acl.$(OBJEXT): $(BUILDTOP)/include/autoconf.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/port-sockets.h $(top_srcdir)/include/socket-utils.h \
-  auth_acl.c auth_acl.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 \
@@ -59,7 +78,7 @@ $(OUTPRE)server_stubs.$(OBJEXT): $(BUILDTOP)/include/autoconf.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_acl.h misc.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 \
@@ -89,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 \
-  auth_acl.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 \
@@ -130,7 +149,7 @@ $(OUTPRE)misc.$(OBJEXT): $(BUILDTOP)/include/autoconf.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_acl.h misc.c \
+  $(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 \
@@ -149,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 auth_acl.h \
+  $(top_srcdir)/lib/gssapi/krb5/gssapi_krb5.h auth.h \
   ipropd_svc.c misc.h
index c552ed08c2d623120e679db591d96ffbb99918c8..e6e190136f881fc7050579978ad7157b8e38f429 100644 (file)
@@ -24,7 +24,7 @@
 #include <arpa/inet.h>
 #include <netdb.h>
 #include <kdb_log.h>
-#include "auth_acl.h"
+#include "auth.h"
 #include "misc.h"
 #include "osconf.h"
 
@@ -137,7 +137,8 @@ iprop_acl_check(krb5_context context, const char *client_name)
 
     if (krb5_parse_name(context, client_name, &client_princ) != 0)
        return FALSE;
-    result = acl_check(context, client_princ, ACL_IPROP, NULL, NULL);
+    result = auth(context, OP_IPROP, client_princ,
+                 NULL, NULL, NULL, NULL, NULL, 0);
     krb5_free_principal(context, client_princ);
     return result;
 }
index 1975af0a6a26a8bcd29ac2fee7d9916ca4150811..6b258a6a056e4ebb557d46089a2ef221dafaddfb 100644 (file)
@@ -8,95 +8,8 @@
 #include    <kdb.h>
 #include    <kadm5/server_internal.h>
 #include    "misc.h"
-#include    "auth_acl.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,31 +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 &&
-        acl_check(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,
index ea0fc7d2217a0a4fe65c5f2208d4bff61a1ee009..3a112a0b7b2ef6b393fa98534304c76400164d0a 100644 (file)
@@ -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,
index 498c7cdff66114d28ddb1e14a4456b4ecd50e2cf..6c875901a976063aebcd3d36582215e9ac03ffe5 100644 (file)
@@ -58,7 +58,7 @@
 #include <kdb_log.h>
 
 #include "misc.h"
-#include "auth_acl.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 = acl_init(context, 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);
-    acl_finish(context);
+    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++)
index d46261620acbe169b747da60390c90047dc56d2a..491cba91aa1aa7b37a5eaf66a7130970f6b1e7d5 100644 (file)
@@ -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);
@@ -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:
index 84b877a749440f1383e10239771caa059cb985bd..cfef97fec14751ee1f303f9c88cac4192e7d3b4a 100644 (file)
@@ -15,7 +15,7 @@
 #include <syslog.h>
 #include <adm_proto.h>  /* krb5_klog_syslog */
 #include "misc.h"
-#include "auth_acl.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,6 +301,7 @@ 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);
@@ -321,12 +309,66 @@ stub_cleanup(kadm5_server_handle_t handle, char *princ_str,
 }
 
 static krb5_boolean
-stub_acl_check(kadm5_server_handle_t handle, uint32_t op,
-               krb5_const_principal target,
-               struct kadm5_auth_restrictions **rs_out)
+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)
 {
-    return acl_check(handle->context, handle->current_caller, op, target,
-                     rs_out);
+    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
@@ -396,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;
-    struct kadm5_auth_restrictions *rp;
     const char                  *errmsg = NULL;
 
     ret->code = stub_setup(arg->api_version, rqstp, arg->rec.principal,
@@ -406,8 +447,7 @@ create_principal_2_svc(cprinc_arg *arg, generic_ret *ret,
         goto exit_func;
 
     if (CHANGEPW_SERVICE(rqstp) ||
-        !stub_acl_check(handle, ACL_ADD, arg->rec.principal, &rp) ||
-        acl_impose_restrictions(handle->context, &arg->rec, &arg->mask, rp)) {
+        !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);
@@ -438,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;
-    struct kadm5_auth_restrictions *rp;
     const char                  *errmsg = NULL;
 
     ret->code = stub_setup(arg->api_version, rqstp, arg->rec.principal,
@@ -448,8 +487,7 @@ create_principal3_2_svc(cprinc3_arg *arg, generic_ret *ret,
         goto exit_func;
 
     if (CHANGEPW_SERVICE(rqstp) ||
-        !stub_acl_check(handle, ACL_ADD, arg->rec.principal, &rp) ||
-        acl_impose_restrictions(handle->context, &arg->rec, &arg->mask, rp)) {
+        !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);
@@ -504,7 +542,7 @@ delete_principal_2_svc(dprinc_arg *arg, generic_ret *ret,
         goto exit_func;
 
     if (CHANGEPW_SERVICE(rqstp) ||
-        !stub_acl_check(handle, ACL_DELETE, arg->princ, NULL)) {
+        !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);
@@ -544,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;
-    struct kadm5_auth_restrictions *rp;
     const char                      *errmsg = NULL;
 
     ret->code = stub_setup(arg->api_version, rqstp, arg->rec.principal,
@@ -554,8 +591,7 @@ modify_principal_2_svc(mprinc_arg *arg, generic_ret *ret,
         goto exit_func;
 
     if (CHANGEPW_SERVICE(rqstp) ||
-        !stub_acl_check(handle, ACL_MODIFY, arg->rec.principal, &rp) ||
-        acl_impose_restrictions(handle->context, &arg->rec, &arg->mask, rp)) {
+        !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);
@@ -594,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;
-    struct kadm5_auth_restrictions *rp;
     const char                  *errmsg = NULL;
     size_t                      tlen1, tlen2, clen, slen;
     char                        *tdots1, *tdots2, *cdots, *sdots;
@@ -619,27 +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 (!stub_acl_check(handle, 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 (!stub_acl_check(handle, ACL_ADD, arg->dest, &rp) || rp != NULL) {
-            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,9 +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) ||
-         !stub_acl_check(handle, 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);
@@ -741,7 +767,7 @@ get_princs_2_svc(gprincs_arg *arg, gprincs_ret *ret, struct svc_req *rqstp)
         prime_arg = "*";
 
     if (CHANGEPW_SERVICE(rqstp) ||
-        !stub_acl_check(handle, ACL_LIST, NULL, NULL)) {
+        !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);
@@ -787,16 +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)) &&
-               stub_acl_check(handle, 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) {
@@ -838,19 +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)) &&
-               stub_acl_check(handle, 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) {
@@ -893,7 +917,7 @@ setv4key_principal_2_svc(setv4key_arg *arg, generic_ret *ret,
             ret->code = KADM5_AUTH_SETKEY;
         }
     } else if (!(CHANGEPW_SERVICE(rqstp)) &&
-               stub_acl_check(handle, 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 {
@@ -943,7 +967,7 @@ setkey_principal_2_svc(setkey_arg *arg, generic_ret *ret,
             ret->code = KADM5_AUTH_SETKEY;
         }
     } else if (!(CHANGEPW_SERVICE(rqstp)) &&
-               stub_acl_check(handle, 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 {
@@ -992,7 +1016,7 @@ setkey_principal3_2_svc(setkey3_arg *arg, generic_ret *ret,
             ret->code = KADM5_AUTH_SETKEY;
         }
     } else if (!(CHANGEPW_SERVICE(rqstp)) &&
-               stub_acl_check(handle, 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);
@@ -1042,7 +1066,7 @@ setkey_principal4_2_svc(setkey4_arg *arg, generic_ret *ret,
             ret->code = KADM5_AUTH_SETKEY;
         }
     } else if (!(CHANGEPW_SERVICE(rqstp)) &&
-               stub_acl_check(handle, 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 {
@@ -1107,16 +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)) &&
-               stub_acl_check(handle, 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) {
@@ -1163,19 +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)) &&
-               stub_acl_check(handle, 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) {
@@ -1220,7 +1245,8 @@ create_policy_2_svc(cpol_arg *arg, generic_ret *ret, struct svc_req *rqstp)
     prime_arg = arg->rec.policy;
 
     if (CHANGEPW_SERVICE(rqstp) ||
-        !stub_acl_check(handle, ACL_ADD, NULL, NULL)) {
+        !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);
@@ -1261,7 +1287,7 @@ delete_policy_2_svc(dpol_arg *arg, generic_ret *ret, struct svc_req *rqstp)
     prime_arg = arg->name;
 
     if (CHANGEPW_SERVICE(rqstp) ||
-        !stub_acl_check(handle, ACL_DELETE, NULL, NULL)) {
+        !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;
@@ -1301,7 +1327,8 @@ modify_policy_2_svc(mpol_arg *arg, generic_ret *ret, struct svc_req *rqstp)
     prime_arg = arg->rec.policy;
 
     if (CHANGEPW_SERVICE(rqstp) ||
-        !stub_acl_check(handle, ACL_MODIFY, NULL, NULL)) {
+        !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;
@@ -1332,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,
@@ -1344,30 +1373,20 @@ get_policy_2_svc(gpol_arg *arg, gpol_ret *ret, struct svc_req *rqstp)
 
     prime_arg = arg->name;
 
+    /* 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;
+
     ret->code = KADM5_AUTH_GET;
-    if (!CHANGEPW_SERVICE(rqstp) &&
-        stub_acl_check(handle, ACL_INQUIRE, NULL, NULL)) {
-        ret->code = KADM5_OK;
+    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_principal(handle->lhandle,
-                                        handle->current_caller, &caller_ent,
-                                        KADM5_PRINCIPAL_NORMAL_MASK);
-        if (ret->code == KADM5_OK) {
-            if (caller_ent.aux_attributes & KADM5_POLICY &&
-                strcmp(caller_ent.policy, arg->name) == 0) {
-                ret->code = KADM5_OK;
-            } else {
-                ret->code = KADM5_AUTH_GET;
-            }
-            ret2 = kadm5_free_principal_ent(handle->lhandle,
-                                            &caller_ent);
-            ret->code = ret->code ? ret->code : ret2;
-        }
-    }
-
-    if (ret->code == KADM5_OK) {
         ret->code = kadm5_get_policy(handle, arg->name, &ret->rec);
-
         if (ret->code != 0)
             errmsg = krb5_get_error_message(handle->context, ret->code);
 
@@ -1376,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;
 }
@@ -1407,7 +1423,7 @@ get_pols_2_svc(gpols_arg *arg, gpols_ret *ret, struct svc_req *rqstp)
         prime_arg = "*";
 
     if (CHANGEPW_SERVICE(rqstp) ||
-        !stub_acl_check(handle, ACL_LIST, NULL, NULL)) {
+        !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);
@@ -1475,9 +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) ||
-         !stub_acl_check(handle, 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 {
@@ -1512,9 +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) ||
-         !stub_acl_check(handle, 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);
@@ -1552,7 +1566,8 @@ set_string_2_svc(sstring_arg *arg, generic_ret *ret, struct svc_req *rqstp)
         goto exit_func;
 
     if (CHANGEPW_SERVICE(rqstp) ||
-        !stub_acl_check(handle, ACL_MODIFY, arg->princ, NULL)) {
+        !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);
@@ -1641,7 +1656,7 @@ get_principal_keys_2_svc(getpkeys_arg *arg, getpkeys_ret *ret,
         goto exit_func;
 
     if (!(CHANGEPW_SERVICE(rqstp)) &&
-        stub_acl_check(handle, 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 {
index 71b053460117beda88c5c54d5a367b9637d25ef6..892a6fac1053b77cbe222b32396cf4d8a0499259 100644 (file)
@@ -66,4 +66,5 @@ error_code KADM5_BAD_KEYSALTS, "Invalid key/salt tuples"
 error_code KADM5_SETKEY_BAD_KVNO, "Invalid multiple or duplicate kvnos in setkey operation"
 error_code KADM5_AUTH_EXTRACT, "Operation requires ``extract-keys'' privilege"
 error_code KADM5_PROTECT_KEYS, "Principal keys are locked down"
+error_code KADM5_AUTH_INITIAL, "Operation requires initial ticket"
 end
index 17dd6bd30b6b1e3c0db5d2c60887658cd5fe1988..ea4c06943c20ec65d093b97ec049cde7dbc42036 100644 (file)
@@ -58,7 +58,8 @@ const char *interface_names[] = {
     "audit",
     "tls",
     "kdcauthdata",
-    "certauth"
+    "certauth",
+    "kadm5_auth"
 };
 
 /* Return the context's interface structure for id, or NULL if invalid. */
index bbbbae99e4dad54f53e8eb463500151a13e5d3d8..f7c04cf4ff34697434d7f9937ba7577140135849 100755 (executable)
@@ -213,16 +213,16 @@ realm.run([kadminl, 'renprinc', 'to', 'from'])
 kadmin_as(some_rename, ['renprinc', 'from', 'to'])
 realm.run([kadminl, 'renprinc', 'to', 'from'])
 kadmin_as(all_add, ['renprinc', 'from', 'to'], expected_code=1,
-          expected_msg="Operation requires ``delete'' privilege")
+          expected_msg="Insufficient authorization for operation")
 kadmin_as(all_delete, ['renprinc', 'from', 'to'], expected_code=1,
-          expected_msg="Operation requires ``add'' privilege")
+          expected_msg="Insufficient authorization for operation")
 kadmin_as(some_rename, ['renprinc', 'from', 'notto'], expected_code=1,
-          expected_msg="Operation requires ``add'' privilege")
+          expected_msg="Insufficient authorization for operation")
 realm.run([kadminl, 'renprinc', 'from', 'notfrom'])
 kadmin_as(some_rename, ['renprinc', 'notfrom', 'to'], expected_code=1,
-          expected_msg="Operation requires ``delete'' privilege")
+          expected_msg="Insufficient authorization for operation")
 kadmin_as(restricted_rename, ['renprinc', 'notfrom', 'to'], expected_code=1,
-          expected_msg="Operation requires ``add'' privilege")
+          expected_msg="Insufficient authorization for operation")
 realm.run([kadminl, 'delprinc', 'notfrom'])
 
 realm.addprinc('selected', 'pw')