diff options
Diffstat (limited to 'src/kadmin/server')
-rw-r--r-- | src/kadmin/server/Makefile.in | 6 | ||||
-rw-r--r-- | src/kadmin/server/auth.c | 314 | ||||
-rw-r--r-- | src/kadmin/server/auth.h | 85 | ||||
-rw-r--r-- | src/kadmin/server/auth_acl.c | 755 | ||||
-rw-r--r-- | src/kadmin/server/auth_self.c | 77 | ||||
-rw-r--r-- | src/kadmin/server/deps | 109 | ||||
-rw-r--r-- | src/kadmin/server/ipropd_svc.c | 38 | ||||
-rw-r--r-- | src/kadmin/server/misc.c | 127 | ||||
-rw-r--r-- | src/kadmin/server/misc.h | 17 | ||||
-rw-r--r-- | src/kadmin/server/ovsec_kadmd.c | 8 | ||||
-rw-r--r-- | src/kadmin/server/schpw.c | 49 | ||||
-rw-r--r-- | src/kadmin/server/server_stubs.c | 340 |
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 { |