aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/kadmin/server/ChangeLog8
-rw-r--r--src/kadmin/server/server_stubs.c71
-rw-r--r--src/lib/kadm5/srv/ChangeLog19
-rw-r--r--src/lib/kadm5/srv/server_acl.c390
-rw-r--r--src/lib/kadm5/srv/server_acl.h21
5 files changed, 412 insertions, 97 deletions
diff --git a/src/kadmin/server/ChangeLog b/src/kadmin/server/ChangeLog
index f1a14b4..d5f932e 100644
--- a/src/kadmin/server/ChangeLog
+++ b/src/kadmin/server/ChangeLog
@@ -1,3 +1,11 @@
+2000-03-16 Ken Raeburn <raeburn@mit.edu>
+ Matt Crawford <crawdad@fnal.gov>
+
+ * server_stubs.c: All callers of acl_check updated to add new
+ restriction argument. Impose any provided restrictions on add- or
+ modify-principal operations; pass NULL pointer for all other
+ operations including rename-principal.
+
2000-02-27 Tom Yu <tlyu@mit.edu>
* server_stubs.c (create_principal3_1): Remove keepold argument.
diff --git a/src/kadmin/server/server_stubs.c b/src/kadmin/server/server_stubs.c
index c90365a..2eef601 100644
--- a/src/kadmin/server/server_stubs.c
+++ b/src/kadmin/server/server_stubs.c
@@ -237,6 +237,7 @@ create_principal_1(cprinc_arg *arg, struct svc_req *rqstp)
gss_buffer_desc client_name, service_name;
OM_uint32 minor_stat;
kadm5_server_handle_t handle;
+ restriction_t *rp;
xdr_free(xdr_generic_ret, &ret);
@@ -256,10 +257,11 @@ create_principal_1(cprinc_arg *arg, struct svc_req *rqstp)
}
krb5_unparse_name(handle->context, arg->rec.principal, &prime_arg);
- if (CHANGEPW_SERVICE(rqstp) || !acl_check(handle->context,
- rqstp->rq_clntcred,
- ACL_ADD,
- arg->rec.principal)) {
+ if (CHANGEPW_SERVICE(rqstp)
+ || !acl_check(handle->context, rqstp->rq_clntcred, ACL_ADD,
+ arg->rec.principal, &rp)
+ || acl_impose_restrictions(handle->context,
+ &arg->rec, &arg->mask, rp)) {
ret.code = KADM5_AUTH_ADD;
krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_create_principal",
prime_arg, client_name.value, service_name.value,
@@ -289,6 +291,7 @@ create_principal3_1(cprinc3_arg *arg, struct svc_req *rqstp)
gss_buffer_desc client_name, service_name;
OM_uint32 minor_stat;
kadm5_server_handle_t handle;
+ restriction_t *rp;
xdr_free(xdr_generic_ret, &ret);
@@ -308,10 +311,11 @@ create_principal3_1(cprinc3_arg *arg, struct svc_req *rqstp)
}
krb5_unparse_name(handle->context, arg->rec.principal, &prime_arg);
- if (CHANGEPW_SERVICE(rqstp) || !acl_check(handle->context,
- rqstp->rq_clntcred,
- ACL_ADD,
- arg->rec.principal)) {
+ if (CHANGEPW_SERVICE(rqstp)
+ || !acl_check(handle->context, rqstp->rq_clntcred, ACL_ADD,
+ arg->rec.principal, &rp)
+ || acl_impose_restrictions(handle->context,
+ &arg->rec, &arg->mask, rp)) {
ret.code = KADM5_AUTH_ADD;
krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_create_principal",
prime_arg, client_name.value, service_name.value,
@@ -363,10 +367,9 @@ delete_principal_1(dprinc_arg *arg, struct svc_req *rqstp)
}
krb5_unparse_name(handle->context, arg->princ, &prime_arg);
- if (CHANGEPW_SERVICE(rqstp) || !acl_check(handle->context,
- rqstp->rq_clntcred,
- ACL_DELETE,
- arg->princ)) {
+ if (CHANGEPW_SERVICE(rqstp)
+ || !acl_check(handle->context, rqstp->rq_clntcred, ACL_DELETE,
+ arg->princ, NULL)) {
ret.code = KADM5_AUTH_DELETE;
krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_delete_principal",
prime_arg, client_name.value, service_name.value,
@@ -394,6 +397,7 @@ modify_principal_1(mprinc_arg *arg, struct svc_req *rqstp)
service_name;
OM_uint32 minor_stat;
kadm5_server_handle_t handle;
+ restriction_t *rp;
xdr_free(xdr_generic_ret, &ret);
@@ -411,10 +415,11 @@ modify_principal_1(mprinc_arg *arg, struct svc_req *rqstp)
}
krb5_unparse_name(handle->context, arg->rec.principal, &prime_arg);
- if (CHANGEPW_SERVICE(rqstp) || !acl_check(handle->context,
- rqstp->rq_clntcred,
- ACL_MODIFY,
- arg->rec.principal)) {
+ if (CHANGEPW_SERVICE(rqstp)
+ || !acl_check(handle->context, rqstp->rq_clntcred, ACL_MODIFY,
+ arg->rec.principal, &rp)
+ || acl_impose_restrictions(handle->context,
+ &arg->rec, &arg->mask, rp)) {
ret.code = KADM5_AUTH_MODIFY;
krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_modify_principal",
prime_arg, client_name.value, service_name.value,
@@ -446,6 +451,7 @@ rename_principal_1(rprinc_arg *arg, struct svc_req *rqstp)
service_name;
OM_uint32 minor_stat;
kadm5_server_handle_t handle;
+ restriction_t *rp;
xdr_free(xdr_generic_ret, &ret);
@@ -468,10 +474,11 @@ rename_principal_1(rprinc_arg *arg, struct svc_req *rqstp)
ret.code = KADM5_OK;
if (! CHANGEPW_SERVICE(rqstp)) {
if (!acl_check(handle->context, rqstp->rq_clntcred,
- ACL_DELETE, arg->src))
+ ACL_DELETE, arg->src, NULL))
ret.code = KADM5_AUTH_DELETE;
+ /* any restrictions at all on the ADD kills the RENAME */
if (!acl_check(handle->context, rqstp->rq_clntcred,
- ACL_ADD, arg->dest)) {
+ ACL_ADD, arg->dest, &rp) || rp) {
if (ret.code == KADM5_AUTH_DELETE)
ret.code = KADM5_AUTH_INSUFFICIENT;
else
@@ -536,7 +543,8 @@ get_principal_1(gprinc_arg *arg, struct svc_req *rqstp)
(CHANGEPW_SERVICE(rqstp) || !acl_check(handle->context,
rqstp->rq_clntcred,
ACL_INQUIRE,
- arg->princ))) {
+ arg->princ,
+ NULL))) {
ret.code = KADM5_AUTH_GET;
krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, funcname,
prime_arg, client_name.value, service_name.value,
@@ -601,6 +609,7 @@ get_princs_1(gprincs_arg *arg, struct svc_req *rqstp)
if (CHANGEPW_SERVICE(rqstp) || !acl_check(handle->context,
rqstp->rq_clntcred,
ACL_LIST,
+ NULL,
NULL)) {
ret.code = KADM5_AUTH_LIST;
krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_get_principals",
@@ -655,7 +664,7 @@ chpass_principal_1(chpass_arg *arg, struct svc_req *rqstp)
arg->pass);
} else if (!(CHANGEPW_SERVICE(rqstp)) &&
acl_check(handle->context, rqstp->rq_clntcred,
- ACL_CHANGEPW, arg->princ)) {
+ ACL_CHANGEPW, arg->princ, NULL)) {
ret.code = kadm5_chpass_principal((void *)handle, arg->princ,
arg->pass);
} else {
@@ -713,7 +722,7 @@ chpass_principal3_1(chpass3_arg *arg, struct svc_req *rqstp)
arg->pass);
} else if (!(CHANGEPW_SERVICE(rqstp)) &&
acl_check(handle->context, rqstp->rq_clntcred,
- ACL_CHANGEPW, arg->princ)) {
+ ACL_CHANGEPW, arg->princ, NULL)) {
ret.code = kadm5_chpass_principal_3((void *)handle, arg->princ,
arg->keepold,
arg->n_ks_tuple,
@@ -771,7 +780,7 @@ setv4key_principal_1(setv4key_arg *arg, struct svc_req *rqstp)
if (!(CHANGEPW_SERVICE(rqstp)) &&
acl_check(handle->context, rqstp->rq_clntcred,
- ACL_SETKEY, arg->princ)) {
+ ACL_SETKEY, arg->princ, NULL)) {
ret.code = kadm5_setv4key_principal((void *)handle, arg->princ,
arg->keyblock);
} else {
@@ -826,7 +835,7 @@ setkey_principal_1(setkey_arg *arg, struct svc_req *rqstp)
if (!(CHANGEPW_SERVICE(rqstp)) &&
acl_check(handle->context, rqstp->rq_clntcred,
- ACL_SETKEY, arg->princ)) {
+ ACL_SETKEY, arg->princ, NULL)) {
ret.code = kadm5_setkey_principal((void *)handle, arg->princ,
arg->keyblocks, arg->n_keys);
} else {
@@ -881,7 +890,7 @@ setkey_principal3_1(setkey3_arg *arg, struct svc_req *rqstp)
if (!(CHANGEPW_SERVICE(rqstp)) &&
acl_check(handle->context, rqstp->rq_clntcred,
- ACL_SETKEY, arg->princ)) {
+ ACL_SETKEY, arg->princ, NULL)) {
ret.code = kadm5_setkey_principal_3((void *)handle, arg->princ,
arg->keepold,
arg->n_ks_tuple,
@@ -948,7 +957,7 @@ chrand_principal_1(chrand_arg *arg, struct svc_req *rqstp)
arg->princ, &k, &nkeys);
} else if (!(CHANGEPW_SERVICE(rqstp)) &&
acl_check(handle->context, rqstp->rq_clntcred,
- ACL_CHANGEPW, arg->princ)) {
+ ACL_CHANGEPW, arg->princ, NULL)) {
ret.code = kadm5_randkey_principal((void *)handle, arg->princ,
&k, &nkeys);
} else {
@@ -1021,7 +1030,7 @@ chrand_principal3_1(chrand3_arg *arg, struct svc_req *rqstp)
arg->princ, &k, &nkeys);
} else if (!(CHANGEPW_SERVICE(rqstp)) &&
acl_check(handle->context, rqstp->rq_clntcred,
- ACL_CHANGEPW, arg->princ)) {
+ ACL_CHANGEPW, arg->princ, NULL)) {
ret.code = kadm5_randkey_principal_3((void *)handle, arg->princ,
arg->keepold,
arg->n_ks_tuple,
@@ -1088,7 +1097,7 @@ create_policy_1(cpol_arg *arg, struct svc_req *rqstp)
if (CHANGEPW_SERVICE(rqstp) || !acl_check(handle->context,
rqstp->rq_clntcred,
- ACL_ADD, NULL)) {
+ ACL_ADD, NULL, NULL)) {
ret.code = KADM5_AUTH_ADD;
krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_create_policy",
prime_arg, client_name.value, service_name.value,
@@ -1139,7 +1148,7 @@ delete_policy_1(dpol_arg *arg, struct svc_req *rqstp)
if (CHANGEPW_SERVICE(rqstp) || !acl_check(handle->context,
rqstp->rq_clntcred,
- ACL_DELETE, NULL)) {
+ ACL_DELETE, NULL, NULL)) {
krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_delete_policy",
prime_arg, client_name.value, service_name.value,
inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
@@ -1188,7 +1197,7 @@ modify_policy_1(mpol_arg *arg, struct svc_req *rqstp)
if (CHANGEPW_SERVICE(rqstp) || !acl_check(handle->context,
rqstp->rq_clntcred,
- ACL_MODIFY, NULL)) {
+ ACL_MODIFY, NULL, NULL)) {
krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_modify_policy",
prime_arg, client_name.value, service_name.value,
inet_ntoa(rqstp->rq_xprt->xp_raddr.sin_addr));
@@ -1246,7 +1255,7 @@ get_policy_1(gpol_arg *arg, struct svc_req *rqstp)
ret.code = KADM5_AUTH_GET;
if (!CHANGEPW_SERVICE(rqstp) && acl_check(handle->context,
rqstp->rq_clntcred,
- ACL_INQUIRE, NULL))
+ ACL_INQUIRE, NULL, NULL))
ret.code = KADM5_OK;
else {
ret.code = kadm5_get_principal(handle->lhandle,
@@ -1325,7 +1334,7 @@ get_pols_1(gpols_arg *arg, struct svc_req *rqstp)
if (CHANGEPW_SERVICE(rqstp) || !acl_check(handle->context,
rqstp->rq_clntcred,
- ACL_LIST, NULL)) {
+ ACL_LIST, NULL, NULL)) {
ret.code = KADM5_AUTH_LIST;
krb5_klog_syslog(LOG_NOTICE, LOG_UNAUTH, "kadm5_get_policies",
prime_arg, client_name.value, service_name.value,
diff --git a/src/lib/kadm5/srv/ChangeLog b/src/lib/kadm5/srv/ChangeLog
index 3ada002..792936d 100644
--- a/src/lib/kadm5/srv/ChangeLog
+++ b/src/lib/kadm5/srv/ChangeLog
@@ -1,3 +1,22 @@
+2000-03-16 Ken Raeburn <raeburn@mit.edu>
+ Matt Crawford <crawdad@fnal.gov>
+
+ * server_acl.c: Include kadm5/admin.h.
+ (struct _acl_entry): Add new fields for restrictions.
+ (struct _wildstate): New type.
+ (acl_parse_line): Input is const. Parse and save restrictions.
+ Allow backslash at end of line to indicate continuation.
+ (acl_parse_restrictions, acl_impose_restrictions): New functions.
+ (acl_free_entries): Free up restriction data if any.
+ (acl_load_acl_file): Don't use tmpbuf for catch-all entry.
+ (acl_match_data): Add new arguments for wildcard state.
+ (acl_find_entry): Support wildcard component matching.
+ Reorganized checks for bad ACL entries.
+ (acl_check): Add restrictions parameter.
+ * server_acl.h (struct _restriction): New type.
+ (acl_check): Update prototype.
+ (acl_impose_restrictions): Declare.
+
2000-02-26 Tom Yu <tlyu@mit.edu>
* svr_principal.c (kadm5_create_principal_3): Remove keepold
diff --git a/src/lib/kadm5/srv/server_acl.c b/src/lib/kadm5/srv/server_acl.c
index 8d330ec..04b2ce7 100644
--- a/src/lib/kadm5/srv/server_acl.c
+++ b/src/lib/kadm5/srv/server_acl.c
@@ -33,8 +33,9 @@
#include <sys/param.h>
#include <gssapi/gssapi_generic.h>
#include "k5-int.h"
-#include "server_acl.h"
#include <kadm5/server_internal.h>
+#include <kadm5/admin.h>
+#include "server_acl.h"
#include <ctype.h>
typedef struct _acl_op_table {
@@ -51,6 +52,10 @@ typedef struct _acl_entry {
char *ae_target;
krb5_boolean ae_target_bad;
krb5_principal ae_target_princ;
+ char *ae_restriction_string;
+ /* eg: "-maxlife 3h -service +proxiable" */
+ krb5_boolean ae_restriction_bad;
+ restriction_t *ae_restrictions;
} aent_t;
static const aop_t acl_op_table[] = {
@@ -66,6 +71,11 @@ static const aop_t acl_op_table[] = {
{ '\0', 0 }
};
+typedef struct _wildstate {
+ int nwild;
+ krb5_data *backref[9];
+} wildstate_t;
+
static aent_t *acl_list_head = (aent_t *) NULL;
static aent_t *acl_list_tail = (aent_t *) NULL;
@@ -151,11 +161,12 @@ acl_get_line(fp, lnp)
*/
static aent_t *
acl_parse_line(lp)
- char *lp;
+ const char *lp;
{
static char acle_principal[BUFSIZ];
static char acle_ops[BUFSIZ];
static char acle_object[BUFSIZ];
+ static char acle_restrictions[BUFSIZ];
aent_t *acle;
char *op;
int t, found, opok, nmatch;
@@ -163,13 +174,15 @@ acl_parse_line(lp)
DPRINT(DEBUG_CALLS, acl_debug_level,
("* acl_parse_line(line=%20s)\n", lp));
/*
- * Format is very simple:
- * entry ::= <whitespace> <principal> <whitespace> <opstring> <whitespace>
- * [<target> <whitespace>]
+ * Format is still simple:
+ * entry ::= [<whitespace>] <principal> <whitespace> <opstring>
+ * [<whitespace> <target> [<whitespace> <restrictions>
+ * [<whitespace>]]]
*/
acle = (aent_t *) NULL;
acle_object[0] = '\0';
- nmatch = sscanf(lp, "%s %s %s", acle_principal, acle_ops, acle_object);
+ nmatch = sscanf(lp, "%s %s %s %[^\n]", acle_principal, acle_ops,
+ acle_object, acle_restrictions);
if (nmatch >= 2) {
acle = (aent_t *) malloc(sizeof(aent_t));
if (acle) {
@@ -222,6 +235,20 @@ acl_parse_line(lp)
free(acle);
acle = (aent_t *) NULL;
}
+ if ( nmatch >= 4 ) {
+ char *trailing;
+
+ trailing = &acle_restrictions[strlen(acle_restrictions)-1];
+ while ( isspace(*trailing) )
+ trailing--;
+ trailing[1] = '\0';
+ acle->ae_restriction_string = strdup(acle_restrictions);
+ }
+ else {
+ acle->ae_restriction_string = (char *) NULL;
+ }
+ acle->ae_restriction_bad = 0;
+ acle->ae_restrictions = (restriction_t *) NULL;
}
}
DPRINT(DEBUG_CALLS, acl_debug_level,
@@ -230,6 +257,183 @@ acl_parse_line(lp)
}
/*
+ * acl_parse_restrictions() - Parse optional restrictions field
+ *
+ * Allowed restrictions are:
+ * [+-]flagname (recognized by krb5_string_to_flags)
+ * 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)
+ *
+ * Returns: 0 on success, or system errors
+ */
+static krb5_error_code
+acl_parse_restrictions(s, rpp)
+ char *s;
+ restriction_t **rpp;
+{
+ char *sp, *tp, *ap;
+ static const char *delims = "\t\n\f\v\r ,";
+ krb5_error_code ret;
+ krb5_deltat dt;
+ krb5_flags flag;
+ krb5_error_code code;
+
+ DPRINT(DEBUG_CALLS, acl_debug_level,
+ ("* acl_parse_restrictions(s=%20s, rpp=0x%08x)\n", s, (long)rpp));
+
+ *rpp = (restriction_t *) NULL;
+ code = 0;
+ if (s)
+ if (!(sp = strdup(s)) /* Don't munge the original */
+ || !(*rpp = (restriction_t *) malloc(sizeof(restriction_t)))) {
+ code = ENOMEM;
+ } else {
+ memset(*rpp, 0, sizeof(**rpp));
+ for (tp=strtok(sp, delims); tp; tp=strtok((char *)NULL, delims)) {
+ flag = 0;
+ if (!krb5_string_to_flags(tp, "+", "-", &flag)) {
+ /* OK, but was it in the positive or negative sense? */
+ if (flag) {
+ (*rpp)->require_attrs |= flag;
+ } else {
+ flag = ~0;
+ (void) krb5_string_to_flags(tp, "+", "-", &flag);
+ (*rpp)->forbid_attrs |= ~flag;
+ }
+ (*rpp)->mask |= KADM5_ATTRIBUTES;
+ } else if (!strcmp(tp, "-clearpolicy")) {
+ (*rpp)->mask |= KADM5_POLICY_CLR;
+ } else {
+ /* everything else needs an argument ... */
+ if (!(ap = strtok((char *)NULL, delims))) {
+ code = EINVAL;
+ break;
+ }
+ if (!strcmp(tp, "-policy")) {
+ if (!((*rpp)->policy = strdup(ap))) {
+ code = ENOMEM;
+ break;
+ }
+ (*rpp)->mask |= KADM5_POLICY;
+ } else {
+ /* all other arguments must be a deltat ... */
+ if (krb5_string_to_deltat(ap, &dt)) {
+ code = EINVAL;
+ break;
+ }
+ if (!strcmp(tp, "-expire")) {
+ (*rpp)->princ_lifetime = dt;
+ (*rpp)->mask |= KADM5_PRINC_EXPIRE_TIME;
+ } else if (!strcmp(tp, "-pwexpire")) {
+ (*rpp)->pw_lifetime = dt;
+ (*rpp)->mask |= KADM5_PW_EXPIRATION;
+ } else if (!strcmp(tp, "-maxlife")) {
+ (*rpp)->max_life = dt;
+ (*rpp)->mask |= KADM5_MAX_LIFE;
+ } else if (!strcmp(tp, "-maxrenewlife")) {
+ (*rpp)->max_renewable_life = dt;
+ (*rpp)->mask |= KADM5_MAX_RLIFE;
+ } else {
+ code = EINVAL;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (sp)
+ free(sp);
+ if (*rpp && code) {
+ if ((*rpp)->policy)
+ free((*rpp)->policy);
+ free(*rpp);
+ *rpp = (restriction_t *) NULL;
+ }
+ DPRINT(DEBUG_CALLS, acl_debug_level,
+ ("X acl_parse_restrictions() = %d, mask=0x%08x\n",
+ code, (*rpp) ? (*rpp)->mask : 0));
+ return code;
+}
+
+/*
+ * acl_impose_restrictions() - impose restrictions, modifying *recp, *maskp
+ *
+ * Returns: 0 on success;
+ * malloc or timeofday errors
+ */
+krb5_error_code
+acl_impose_restrictions(kcontext, recp, maskp, rp)
+ krb5_context kcontext;
+ kadm5_principal_ent_rec *recp;
+ long *maskp;
+ restriction_t *rp;
+{
+ krb5_error_code code;
+ krb5_int32 now;
+
+ DPRINT(DEBUG_CALLS, acl_debug_level,
+ ("* acl_impose_restrictions(..., *maskp=0x%08x, rp=0x%08x)\n",
+ *maskp, (long)rp));
+ if (!rp)
+ return 0;
+ if (rp->mask & (KADM5_PRINC_EXPIRE_TIME|KADM5_PW_EXPIRATION))
+ if ((code = krb5_timeofday(kcontext, &now)))
+ return code;
+
+ if (rp->mask & KADM5_ATTRIBUTES) {
+ recp->attributes |= rp->require_attrs;
+ recp->attributes &= ~(rp->forbid_attrs);
+ *maskp |= KADM5_ATTRIBUTES;
+ }
+ if (rp->mask & KADM5_POLICY_CLR) {
+ *maskp &= ~KADM5_POLICY;
+ *maskp |= KADM5_POLICY_CLR;
+ } else if (rp->mask & KADM5_POLICY) {
+ if (recp->policy && strcmp(recp->policy, rp->policy)) {
+ free(recp->policy);
+ recp->policy = (char *) NULL;
+ }
+ if (!recp->policy) {
+ recp->policy = strdup(rp->policy); /* XDR will free it */
+ if (!recp->policy)
+ return ENOMEM;
+ }
+ *maskp |= KADM5_POLICY;
+ }
+ if (rp->mask & KADM5_PRINC_EXPIRE_TIME) {
+ if (!(*maskp & KADM5_PRINC_EXPIRE_TIME)
+ || (recp->princ_expire_time > (now + rp->princ_lifetime)))
+ recp->princ_expire_time = now + rp->princ_lifetime;
+ *maskp |= KADM5_PRINC_EXPIRE_TIME;
+ }
+ if (rp->mask & KADM5_PW_EXPIRATION) {
+ if (!(*maskp & KADM5_PW_EXPIRATION)
+ || (recp->pw_expiration > (now + rp->pw_lifetime)))
+ recp->pw_expiration = now + rp->pw_lifetime;
+ *maskp |= KADM5_PW_EXPIRATION;
+ }
+ if (rp->mask & KADM5_MAX_LIFE) {
+ if (!(*maskp & KADM5_MAX_LIFE)
+ || (recp->max_life > rp->max_life))
+ recp->max_life = rp->max_life;
+ *maskp |= KADM5_MAX_LIFE;
+ }
+ if (rp->mask & KADM5_MAX_RLIFE) {
+ if (!(*maskp & KADM5_MAX_RLIFE)
+ || (recp->max_renewable_life > rp->max_renewable_life))
+ recp->max_renewable_life = rp->max_renewable_life;
+ *maskp |= KADM5_MAX_RLIFE;
+ }
+ DPRINT(DEBUG_CALLS, acl_debug_level,
+ ("X acl_impose_restrictions() = 0, *maskp=0x%08x\n", *maskp));
+ return 0;
+}
+
+/*
* acl_free_entries() - Free all ACL entries.
*/
static void
@@ -248,6 +452,13 @@ acl_free_entries()
free(ap->ae_target);
if (ap->ae_target_princ)
krb5_free_principal((krb5_context) NULL, ap->ae_target_princ);
+ if (ap->ae_restriction_string)
+ free(ap->ae_restriction_string);
+ if (ap->ae_restrictions) {
+ if (ap->ae_restrictions->policy)
+ free(ap->ae_restrictions->policy);
+ free(ap->ae_restrictions);
+ }
np = ap->ae_next;
free(ap);
}
@@ -262,7 +473,6 @@ acl_free_entries()
static int
acl_load_acl_file()
{
-char tmpbuf[10];
FILE *afp;
char *alinep;
aent_t **aentpp;
@@ -293,8 +503,7 @@ char tmpbuf[10];
fclose(afp);
if (acl_catchall_entry) {
- strcpy(tmpbuf, acl_catchall_entry);
- if (*aentpp = acl_parse_line(tmpbuf)) {
+ if (*aentpp = acl_parse_line(acl_catchall_entry)) {
acl_list_tail = *aentpp;
}
else {
@@ -334,17 +543,38 @@ char tmpbuf[10];
* Wildcarding is only supported for a whole component.
*/
static krb5_boolean
-acl_match_data(e1, e2)
+acl_match_data(e1, e2, targetflag, ws)
krb5_data *e1, *e2;
+ int targetflag;
+ wildstate_t *ws;
{
krb5_boolean retval;
DPRINT(DEBUG_CALLS, acl_debug_level,
("* acl_match_entry(%s, %s)\n", e1->data, e2->data));
retval = 0;
- if (!strncmp(e1->data, "*", e1->length) ||
- !strncmp(e2->data, "*", e2->length)) {
+ if (!strncmp(e1->data, "*", e1->length)) {
retval = 1;
+ if (ws && !targetflag) {
+ if (ws->nwild >= 9) {
+ DPRINT(DEBUG_ACL, acl_debug_level,
+ ("Too many wildcards in ACL entry %s\n", entry->ae_name));
+ }
+ else
+ ws->backref[ws->nwild++] = e2;
+ }
+ }
+ else if (ws && targetflag && (e1->length == 2) && (e1->data[0] == '*') &&
+ (e1->data[1] >= '1') && (e1->data[1] <= '9')) {
+ int n = e1->data[1] - '1';
+ if (n >= ws->nwild) {
+ DPRINT(DEBUG_ACL, acl_debug_level,
+ ("Too many backrefs in ACL entry %s\n", entry->ae_name));
+ }
+ else if ((ws->backref[n]->length == e2->length) &&
+ (!strncmp(ws->backref[n]->data, e2->data, e2->length)))
+ retval = 1;
+
}
else {
if ((e1->length == e2->length) &&
@@ -368,75 +598,98 @@ acl_find_entry(kcontext, principal, dest_princ)
krb5_error_code kret;
int i;
int matchgood;
+ wildstate_t state;
DPRINT(DEBUG_CALLS, acl_debug_level, ("* acl_find_entry()\n"));
+ memset((char *)&state, 0, sizeof state);
for (entry=acl_list_head; entry; entry = entry->ae_next) {
+ if (entry->ae_name_bad)
+ continue;
if (!strcmp(entry->ae_name, "*")) {
DPRINT(DEBUG_ACL, acl_debug_level, ("A wildcard ACL match\n"));
- break;
+ matchgood = 1;
}
- if (!entry->ae_principal && !entry->ae_name_bad) {
- kret = krb5_parse_name(kcontext,
- entry->ae_name,
- &entry->ae_principal);
- if (kret)
- entry->ae_name_bad = 1;
+ else {
+ if (!entry->ae_principal && !entry->ae_name_bad) {
+ kret = krb5_parse_name(kcontext,
+ entry->ae_name,
+ &entry->ae_principal);
+ if (kret)
+ entry->ae_name_bad = 1;
+ }
+ if (entry->ae_name_bad) {
+ DPRINT(DEBUG_ACL, acl_debug_level,
+ ("Bad ACL entry %s\n", entry->ae_name));
+ continue;
+ }
+ matchgood = 0;
+ if (acl_match_data(&entry->ae_principal->realm,
+ &principal->realm, 0, (wildstate_t *)0) &&
+ (entry->ae_principal->length == principal->length)) {
+ matchgood = 1;
+ for (i=0; i<principal->length; i++) {
+ if (!acl_match_data(&entry->ae_principal->data[i],
+ &principal->data[i], 0, &state)) {
+ matchgood = 0;
+ break;
+ }
+ }
+ }
}
- if (entry->ae_name_bad) {
- DPRINT(DEBUG_ACL, acl_debug_level,
- ("A Bad ACL entry %s\n", entry->ae_name));
+ if (!matchgood)
continue;
- }
- if (entry->ae_target &&
- !entry->ae_target_princ &&
- !entry->ae_target_bad) {
- kret = krb5_parse_name(kcontext,
- entry->ae_target,
- &entry->ae_target_princ);
- if (kret)
- entry->ae_target_bad = 1;
+
+ /* We've matched the principal. If we have a target, then try it */
+ if (entry->ae_target) {
+ if (!strcmp(entry->ae_target, "*"))
+ break;
+ if (!entry->ae_target_princ && !entry->ae_target_bad) {
+ kret = krb5_parse_name(kcontext, entry->ae_target,
+ &entry->ae_target_princ);
+ if (kret)
+ entry->ae_target_bad = 1;
+ }
}
if (entry->ae_target_bad) {
DPRINT(DEBUG_ACL, acl_debug_level,
- ("A Bad target in an ACL entry for %s\n", entry->ae_name));
+ ("Bad target in ACL entry for %s\n", entry->ae_name));
entry->ae_name_bad = 1;
continue;
}
- matchgood = 0;
- if (acl_match_data(&entry->ae_principal->realm,
- &principal->realm) &&
- (entry->ae_principal->length == principal->length)) {
- matchgood = 1;
- for (i=0; i<principal->length; i++) {
- if (!acl_match_data(&entry->ae_principal->data[i],
- &principal->data[i])) {
- matchgood = 0;
- break;
+ if (entry->ae_target && !dest_princ)
+ matchgood = 0;
+ else if (entry->ae_target && entry->ae_target_princ && dest_princ) {
+ if (acl_match_data(&entry->ae_target_princ->realm,
+ &dest_princ->realm, 1, (wildstate_t *)0) &&
+ (entry->ae_target_princ->length == dest_princ->length)) {
+ for (i=0; i<dest_princ->length; i++) {
+ if (!acl_match_data(&entry->ae_target_princ->data[i],
+ &dest_princ->data[i], 1, &state)) {
+ matchgood = 0;
+ break;
+ }
}
}
+ else
+ matchgood = 0;
}
if (!matchgood)
continue;
- /* We've matched the principal. If we have a target, then try it */
- if (entry->ae_target && entry->ae_target_princ && dest_princ) {
- if (acl_match_data(&entry->ae_target_princ->realm,
- &dest_princ->realm) &&
- (entry->ae_target_princ->length == dest_princ->length)) {
- for (i=0; i<dest_princ->length; i++) {
- if (!acl_match_data(&entry->ae_target_princ->data[i],
- &dest_princ->data[i])) {
- matchgood = 0;
- break;
- }
- }
- }
- else
- matchgood = 0;
+ if (entry->ae_restriction_string
+ && !entry->ae_restriction_bad
+ && !entry->ae_restrictions
+ && acl_parse_restrictions(entry->ae_restriction_string,
+ &entry->ae_restrictions)) {
+ DPRINT(DEBUG_ACL, acl_debug_level,
+ ("Bad restrictions in ACL entry for %s\n", entry->ae_name));
+ entry->ae_restriction_bad = 1;
}
-
- if (matchgood)
- break;
+ if (entry->ae_restriction_bad) {
+ entry->ae_name_bad = 1;
+ continue;
+ }
+ break;
}
DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_find_entry()=%x\n",entry));
return(entry);
@@ -479,7 +732,7 @@ acl_finish(kcontext, debug_level)
}
/*
- * acl_op_permitted() - Is this operation permitted for this principal?
+ * acl_check() - Is this operation permitted for this principal?
* this code used not to be based on gssapi. In order
* to minimize porting hassles, I've put all the
* gssapi hair in this function. This might not be
@@ -487,11 +740,12 @@ acl_finish(kcontext, debug_level)
* solution is, of course, a real authorization service.)
*/
krb5_boolean
-acl_check(kcontext, caller, opmask, principal)
+acl_check(kcontext, caller, opmask, principal, restrictions)
krb5_context kcontext;
gss_name_t caller;
krb5_int32 opmask;
krb5_principal principal;
+ restriction_t **restrictions;
{
krb5_boolean retval;
aent_t *aentry;
@@ -517,8 +771,15 @@ acl_check(kcontext, caller, opmask, principal)
retval = 0;
if (aentry = acl_find_entry(kcontext, caller_princ, principal)) {
- if ((aentry->ae_op_allowed & opmask) == opmask)
+ if ((aentry->ae_op_allowed & opmask) == opmask) {
retval = 1;
+ if (restrictions) {
+ *restrictions =
+ (aentry->ae_restrictions && aentry->ae_restrictions->mask)
+ ? aentry->ae_restrictions
+ : (restriction_t *) NULL;
+ }
+ }
}
krb5_free_principal(kcontext, caller_princ);
@@ -528,7 +789,8 @@ acl_check(kcontext, caller, opmask, principal)
return(retval);
}
-kadm5_ret_t kadm5_get_privs(void *server_handle, long *privs)
+kadm5_ret_t
+kadm5_get_privs(void *server_handle, long *privs)
{
kadm5_server_handle_t handle = server_handle;
diff --git a/src/lib/kadm5/srv/server_acl.h b/src/lib/kadm5/srv/server_acl.h
index e2aa8bd..226a4d9 100644
--- a/src/lib/kadm5/srv/server_acl.h
+++ b/src/lib/kadm5/srv/server_acl.h
@@ -70,6 +70,18 @@
ACL_LIST | \
ACL_SETKEY)
+typedef struct _restriction {
+ 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;
+ long aux_attributes;
+ char *policy;
+} restriction_t;
+
krb5_error_code acl_init
KRB5_PROTOTYPE((krb5_context,
int,
@@ -81,6 +93,11 @@ krb5_boolean acl_check
KRB5_PROTOTYPE((krb5_context,
gss_name_t,
krb5_int32,
- krb5_principal));
-
+ krb5_principal,
+ restriction_t **));
+krb5_error_code acl_impose_restrictions
+ KRB5_PROTOTYPE((krb5_context,
+ kadm5_principal_ent_rec *,
+ long *,
+ restriction_t *));
#endif /* SERVER_ACL_H__ */