diff options
author | Ken Raeburn <raeburn@mit.edu> | 2000-03-16 13:05:17 +0000 |
---|---|---|
committer | Ken Raeburn <raeburn@mit.edu> | 2000-03-16 13:05:17 +0000 |
commit | d88c5a0fb51d749d64a8e7ddfd36b049c4f0ae5f (patch) | |
tree | 0b19f76d9ad00cad8ed2266e49176a82b9cbe937 | |
parent | 49bbd71f54fe95cd53f0cb7a7ef075ba04c7b802 (diff) | |
download | krb5-d88c5a0fb51d749d64a8e7ddfd36b049c4f0ae5f.tar.gz krb5-d88c5a0fb51d749d64a8e7ddfd36b049c4f0ae5f.tar.xz krb5-d88c5a0fb51d749d64a8e7ddfd36b049c4f0ae5f.zip |
Matt Crawford's kadm acl fixes & enhancements
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@12121 dc483132-0cff-0310-8789-dd5450dbe970
-rw-r--r-- | src/kadmin/server/ChangeLog | 8 | ||||
-rw-r--r-- | src/kadmin/server/server_stubs.c | 71 | ||||
-rw-r--r-- | src/lib/kadm5/srv/ChangeLog | 19 | ||||
-rw-r--r-- | src/lib/kadm5/srv/server_acl.c | 390 | ||||
-rw-r--r-- | src/lib/kadm5/srv/server_acl.h | 21 |
5 files changed, 412 insertions, 97 deletions
diff --git a/src/kadmin/server/ChangeLog b/src/kadmin/server/ChangeLog index f1a14b4e7b..d5f932eb25 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 c90365a50a..2eef601b22 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 3ada002ce2..792936dace 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 8d330ec7cc..04b2ce707a 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 e2aa8bddcc..226a4d925b 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__ */ |