From: Greg Hudson Date: Wed, 21 Jun 2017 14:38:41 +0000 (-0400) Subject: Modernize auth_acl.c X-Git-Tag: krb5-1.16-beta1~41 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0def80f767b9a2cdfbc19d3a61433d1edd7a7998;p=thirdparty%2Fkrb5.git Modernize auth_acl.c Change auth_acl.c to match current coding conventions. Use more consistent identifier names, and drop the kadm5int_ prefix as the code is now part of kadmind. Remove the acl_inited, acl_debug_level, and acl_catchall_entry variables. Move global state into a structure, to make it easier to migrate to a module handle later. Move parse_restrictions() above parse_line() so it can later be used from parse_line() without a forward declaration. Rewrite get_line() and parse_line() to avoid the use of fixed-sized static buffers and sscanf(). Add a parse_entry() helper to make memory management in parse_line() easier. Add a free_acl_entry() helper (split out from free_acl_entries()) to make error handling in parse_entry() easier. Add a match_princ() helper to simplify find_entry(). Remove the GSS name translation wrapper in auth_acl.c. In the server stubs, use handle->current_caller for the client principal. In the iprop RPCs(), add a wrapper to parse the client display name before calling acl_check(). --- diff --git a/src/kadmin/server/auth_acl.c b/src/kadmin/server/auth_acl.c index ea89af0fcc..e0c18f6dd5 100644 --- a/src/kadmin/server/auth_acl.c +++ b/src/kadmin/server/auth_acl.c @@ -1,8 +1,8 @@ /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /* kadmin/server/auth_acl.c */ /* - * Copyright 1995-2004, 2007, 2008 by the Massachusetts Institute of Technology. - * All Rights Reserved. + * 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. @@ -26,243 +26,119 @@ #include "k5-int.h" #include -#include -#include -#include #include #include "adm_proto.h" #include "auth_acl.h" #include -typedef struct _acl_op_table { - char ao_op; - krb5_int32 ao_mask; -} aop_t; - -typedef struct _acl_entry { - struct _acl_entry *ae_next; - char *ae_name; - krb5_boolean ae_name_bad; - krb5_principal ae_principal; - krb5_int32 ae_op_allowed; - 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[] = { - { '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 acl_op_table { + char op; + uint32_t mask; }; -typedef struct _wildstate { +struct acl_entry { + struct acl_entry *next; + char *client_string; + krb5_boolean client_bad; + krb5_principal client; + uint32_t op_allowed; + char *target_string; + krb5_boolean target_bad; + krb5_principal target; + char *rs_string; + krb5_boolean rs_bad; + 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]; -} wildstate_t; - -static aent_t *acl_list_head = (aent_t *) NULL; -static aent_t *acl_list_tail = (aent_t *) NULL; +}; -static const char *acl_acl_file = (char *) NULL; -static int acl_inited = 0; -static int acl_debug_level = 0; -/* - * This is the catchall entry. If nothing else appropriate is found, or in - * the case where the ACL file is not present, this entry controls what can - * be done. - */ -static const char *acl_catchall_entry = NULL; +struct acl_state { + struct acl_entry *list; + const char *fname; +}; -static const char *acl_line2long_msg = N_("%s: line %d too long, truncated"); -static const char *acl_op_bad_msg = N_("Unrecognized ACL operation '%c' in " - "%s"); -static const char *acl_syn_err_msg = N_("%s: syntax error at line %d " - "<%.10s...>"); -static const char *acl_cantopen_msg = N_("%s while opening ACL file %s"); +static struct acl_state aclstate; /* - * kadm5int_acl_get_line() - Get a line from the ACL file. - * Lines ending with \ are continued on the next line + * 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 * -kadm5int_acl_get_line(fp, lnp) - FILE *fp; - int *lnp; /* caller should set to 1 before first call */ +get_line(FILE *fp, const char *fname, int *lineno, int *incr) { - int i, domore; - static int line_incr = 0; - static char acl_buf[BUFSIZ]; - - for (domore = 1; domore && !feof(fp); ) { - *lnp += line_incr; - line_incr = 0; - /* Copy in the line, with continuations */ - for (i = 0; ((i < BUFSIZ) && !feof(fp)); i++) { - int byte; - byte = fgetc(fp); - acl_buf[i] = byte; - if (byte == EOF) { - if (i > 0 && acl_buf[i-1] == '\\') - i--; - break; /* it gets nulled-out below */ - } - else if (acl_buf[i] == '\n') { - if (i == 0 || acl_buf[i-1] != '\\') - break; /* empty line or normal end of line */ - else { - i -= 2; /* back up over "\\\n" and continue */ - line_incr++; - } - } - } - /* Check if we exceeded our buffer size */ - if (i == sizeof acl_buf && (i--, !feof(fp))) { - int c1 = acl_buf[i], c2; - - krb5_klog_syslog(LOG_ERR, _(acl_line2long_msg), acl_acl_file, - *lnp); - while ((c2 = fgetc(fp)) != EOF) { - if (c2 == '\n') { - if (c1 != '\\') - break; - line_incr++; - } - c1 = c2; - } + 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; } - acl_buf[i] = '\0'; - if (acl_buf[0] == (char) EOF) /* ptooey */ - acl_buf[0] = '\0'; - else - line_incr++; - if ((acl_buf[0] != '#') && (acl_buf[0] != '\0')) - domore = 0; - } - if (domore || (strlen(acl_buf) == 0)) - return((char *) NULL); - else - return(acl_buf); -} - -/* - * kadm5int_acl_parse_line() - Parse the contents of an ACL line. - */ -static aent_t * -kadm5int_acl_parse_line(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; - - DPRINT(DEBUG_CALLS, acl_debug_level, - ("* kadm5int_acl_parse_line(line=%20s)\n", lp)); - /* - * Format is still simple: - * entry ::= [] - * [ [ - * []]] - */ - acle = (aent_t *) NULL; - acle_object[0] = '\0'; - 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) { - acle->ae_next = (aent_t *) NULL; - acle->ae_op_allowed = (krb5_int32) 0; - acle->ae_target = - (nmatch >= 3) ? strdup(acle_object) : (char *) NULL; - acle->ae_target_bad = 0; - acle->ae_target_princ = (krb5_principal) NULL; - opok = 1; - for (op=acle_ops; *op; op++) { - char rop; - - rop = (isupper((unsigned char) *op)) ? tolower((unsigned char) *op) : *op; - found = 0; - for (t=0; acl_op_table[t].ao_op; t++) { - if (rop == acl_op_table[t].ao_op) { - found = 1; - if (rop == *op) - acle->ae_op_allowed |= acl_op_table[t].ao_mask; - else - acle->ae_op_allowed &= ~acl_op_table[t].ao_mask; - } - } - if (!found) { - krb5_klog_syslog(LOG_ERR, _(acl_op_bad_msg), *op, lp); - opok = 0; - } - } - if (opok) { - acle->ae_name = strdup(acle_principal); - if (acle->ae_name) { - acle->ae_principal = (krb5_principal) NULL; - acle->ae_name_bad = 0; - DPRINT(DEBUG_ACL, acl_debug_level, - ("A ACL entry %s -> opmask %x\n", - acle->ae_name, acle->ae_op_allowed)); - } - else { - if (acle->ae_target) - free(acle->ae_target); - free(acle); - acle = (aent_t *) NULL; - } - } - else { - if (acle->ae_target) - free(acle->ae_target); - free(acle); - acle = (aent_t *) NULL; - } - if (acle) { - if ( nmatch >= 4 ) { - char *trailing; - - trailing = &acle_restrictions[strlen(acle_restrictions)-1]; - while ( isspace((int) *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; + /* 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; } } } - DPRINT(DEBUG_CALLS, acl_debug_level, - ("X kadm5int_acl_parse_line() = %x\n", (long) acle)); - return(acle); } /* - * kadm5int_acl_parse_restrictions() - Parse optional restrictions field + * Parse a restrictions field. Return NULL on failure. * * Allowed restrictions are: * [+-]flagname (recognized by krb5_flagspec_to_mask) @@ -272,539 +148,477 @@ kadm5int_acl_parse_line(lp) * -{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 -kadm5int_acl_parse_restrictions(s, rpp) - char *s; - restriction_t **rpp; +static struct kadm5_auth_restrictions * +parse_restrictions(const char *str, const char *fname) { - char *sp = NULL, *tp, *ap, *save; - static const char *delims = "\t\n\f\v\r ,"; - krb5_deltat dt; - krb5_error_code code; - - DPRINT(DEBUG_CALLS, acl_debug_level, - ("* kadm5int_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; + 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 { - memset(*rpp, 0, sizeof(**rpp)); - (*rpp)->forbid_attrs = ~(krb5_flags)0; - for (tp = strtok_r(sp, delims, &save); tp; - tp = strtok_r(NULL, delims, &save)) { - if (!krb5_flagspec_to_mask(tp, &(*rpp)->require_attrs, - &(*rpp)->forbid_attrs)) { - (*rpp)->mask |= KADM5_ATTRIBUTES; - } else if (!strcmp(tp, "-clearpolicy")) { - (*rpp)->mask |= KADM5_POLICY_CLR; - } else { - /* everything else needs an argument ... */ - if (!(ap = strtok_r(NULL, delims, &save))) { - 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 (code) { - krb5_klog_syslog(LOG_ERR, _("%s: invalid restrictions: %s"), - acl_acl_file, s); + 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) +{ + free(entry->client_string); + krb5_free_principal(NULL, entry->client); + free(entry->target_string); + krb5_free_principal(NULL, entry->target); + free(entry->rs_string); + 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(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; + } + } + + entry->client_string = strdup(client); + if (entry->client_string == NULL) + goto error; + if (target != NULL) { + entry->target_string = strdup(target); + if (entry->target_string == NULL) + goto error; } - if (sp) - free(sp); - if (*rpp && code) { - if ((*rpp)->policy) - free((*rpp)->policy); - free(*rpp); - *rpp = (restriction_t *) NULL; + if (rs != NULL) { + entry->rs_string = strdup(rs); + if (entry->rs_string == NULL) + goto error; } - DPRINT(DEBUG_CALLS, acl_debug_level, - ("X kadm5int_acl_parse_restrictions() = %d, mask=0x%08x\n", - code, (*rpp) ? (*rpp)->mask : 0)); - return code; + + return entry; + +error: + free_acl_entry(entry); + return NULL; } -/* - * kadm5int_acl_impose_restrictions() - impose restrictions, modifying *recp, *maskp - * - * Returns: 0 on success; - * malloc or timeofday errors - */ +/* Parse the contents of an ACL line. */ +static struct acl_entry * +parse_line(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 ::= [] + * [ [ + * []]] + */ + + /* 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(client, ops, target, rs, line, fname); + free(copy); + return entry; +} + +/* Impose restrictions, modifying *rec and *mask. */ krb5_error_code -kadm5int_acl_impose_restrictions(kcontext, recp, maskp, rp) - krb5_context kcontext; - kadm5_principal_ent_rec *recp; - long *maskp; - restriction_t *rp; +acl_impose_restrictions(krb5_context context, kadm5_principal_ent_rec *rec, + long *mask, struct kadm5_auth_restrictions *rs) { - krb5_error_code code; - krb5_timestamp now; + krb5_error_code ret; + krb5_timestamp now; - DPRINT(DEBUG_CALLS, acl_debug_level, - ("* kadm5int_acl_impose_restrictions(..., *maskp=0x%08x, rp=0x%08x)\n", - *maskp, (long)rp)); - if (!rp) + if (rs == NULL) 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 (rs->mask & (KADM5_PRINC_EXPIRE_TIME | KADM5_PW_EXPIRATION)) { + ret = krb5_timeofday(context, &now); + if (ret) + return ret; + } + + if (rs->mask & KADM5_ATTRIBUTES) { + rec->attributes |= rs->require_attrs; + rec->attributes &= rs->forbid_attrs; + *mask |= KADM5_ATTRIBUTES; } - if (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 (rs->mask & KADM5_POLICY_CLR) { + *mask &= ~KADM5_POLICY; + *mask |= KADM5_POLICY_CLR; + } else if (rs->mask & KADM5_POLICY) { + if (rec->policy != NULL && strcmp(rec->policy, rs->policy) != 0) { + free(rec->policy); + rec->policy = NULL; } - if (!recp->policy) { - recp->policy = strdup(rp->policy); /* XDR will free it */ - if (!recp->policy) + if (rec->policy == NULL) { + rec->policy = strdup(rs->policy); /* XDR will free it */ + if (!rec->policy) return ENOMEM; } - *maskp |= KADM5_POLICY; + *mask |= KADM5_POLICY; } - if (rp->mask & KADM5_PRINC_EXPIRE_TIME) { - if (!(*maskp & KADM5_PRINC_EXPIRE_TIME) - || ts_after(recp->princ_expire_time, - ts_incr(now, rp->princ_lifetime))) - recp->princ_expire_time = now + rp->princ_lifetime; - *maskp |= KADM5_PRINC_EXPIRE_TIME; + if (rs->mask & KADM5_PRINC_EXPIRE_TIME) { + if (!(*mask & KADM5_PRINC_EXPIRE_TIME) || + ts_after(rec->princ_expire_time, ts_incr(now, rs->princ_lifetime))) + rec->princ_expire_time = now + rs->princ_lifetime; + *mask |= KADM5_PRINC_EXPIRE_TIME; } - if (rp->mask & KADM5_PW_EXPIRATION) { - if (!(*maskp & KADM5_PW_EXPIRATION) - || ts_after(recp->pw_expiration, ts_incr(now, rp->pw_lifetime))) - recp->pw_expiration = now + rp->pw_lifetime; - *maskp |= KADM5_PW_EXPIRATION; + if (rs->mask & KADM5_PW_EXPIRATION) { + if (!(*mask & KADM5_PW_EXPIRATION) || + ts_after(rec->pw_expiration, ts_incr(now, rs->pw_lifetime))) + rec->pw_expiration = now + rs->pw_lifetime; + *mask |= KADM5_PW_EXPIRATION; } - if (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 (rs->mask & KADM5_MAX_LIFE) { + if (!(*mask & KADM5_MAX_LIFE) || rec->max_life > rs->max_life) + rec->max_life = rs->max_life; + *mask |= KADM5_MAX_LIFE; } - if (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; + if (rs->mask & KADM5_MAX_RLIFE) { + if (!(*mask & KADM5_MAX_RLIFE) || + rec->max_renewable_life > rs->max_renewable_life) + rec->max_renewable_life = rs->max_renewable_life; + *mask |= KADM5_MAX_RLIFE; } - DPRINT(DEBUG_CALLS, acl_debug_level, - ("X kadm5int_acl_impose_restrictions() = 0, *maskp=0x%08x\n", *maskp)); return 0; } -/* - * kadm5int_acl_free_entries() - Free all ACL entries. - */ +/* Free all ACL entries. */ static void -kadm5int_acl_free_entries() +free_acl_entries(struct acl_state *state) { - aent_t *ap; - aent_t *np; - - DPRINT(DEBUG_CALLS, acl_debug_level, ("* kadm5int_acl_free_entries()\n")); - for (ap=acl_list_head; ap; ap = np) { - if (ap->ae_name) - free(ap->ae_name); - if (ap->ae_principal) - krb5_free_principal((krb5_context) NULL, ap->ae_principal); - if (ap->ae_target) - 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); + struct acl_entry *entry, *next; + + for (entry = state->list; entry != NULL; entry = next) { + next = entry->next; + free_acl_entry(entry); } - acl_list_head = acl_list_tail = (aent_t *) NULL; - acl_inited = 0; - DPRINT(DEBUG_CALLS, acl_debug_level, ("X kadm5int_acl_free_entries()\n")); + state->list = NULL; } -/* - * kadm5int_acl_load_acl_file() - Open and parse the ACL file. - */ -static int -kadm5int_acl_load_acl_file() +/* Open and parse the ACL file. */ +static void +load_acl_file(const char *fname, struct acl_state *state) { - FILE *afp; - char *alinep; - aent_t **aentpp; - int alineno; - int retval = 1; - - DPRINT(DEBUG_CALLS, acl_debug_level, ("* kadm5int_acl_load_acl_file()\n")); - /* Open the ACL file for read */ - afp = fopen(acl_acl_file, "r"); - if (afp) { - set_cloexec_file(afp); - alineno = 1; - aentpp = &acl_list_head; - - /* Get a non-comment line */ - while ((alinep = kadm5int_acl_get_line(afp, &alineno))) { - /* Parse it */ - *aentpp = kadm5int_acl_parse_line(alinep); - /* If syntax error, then fall out */ - if (!*aentpp) { - krb5_klog_syslog(LOG_ERR, _(acl_syn_err_msg), - acl_acl_file, alineno, alinep); - retval = 0; - break; - } - acl_list_tail = *aentpp; - aentpp = &(*aentpp)->ae_next; - } - - fclose(afp); - - if (acl_catchall_entry) { - *aentpp = kadm5int_acl_parse_line(acl_catchall_entry); - if (*aentpp) { - acl_list_tail = *aentpp; - } - else { - retval = 0; - DPRINT(DEBUG_OPERATION, acl_debug_level, - ("> catchall acl entry (%s) load failed\n", - acl_catchall_entry)); - } - } + 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); + return; } - else { - krb5_klog_syslog(LOG_ERR, _(acl_cantopen_msg), - error_message(errno), acl_acl_file); - if (acl_catchall_entry && - (acl_list_head = kadm5int_acl_parse_line(acl_catchall_entry))) { - acl_list_tail = acl_list_head; - } - else { - retval = 0; - DPRINT(DEBUG_OPERATION, acl_debug_level, - ("> catchall acl entry (%s) load failed\n", - acl_catchall_entry)); + + 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(line, fname); + if (*entry_slot == NULL) { + krb5_klog_syslog(LOG_ERR, + _("%s: syntax error at line %d <%.10s...>"), + fname, lineno, line); + free_acl_entries(state); + free(line); + fclose(fp); + return; } + entry_slot = &(*entry_slot)->next; + free(line); } - if (!retval) { - kadm5int_acl_free_entries(); - } - DPRINT(DEBUG_CALLS, acl_debug_level, - ("X kadm5int_acl_load_acl_file() = %d\n", retval)); - return(retval); + fclose(fp); + state->fname = fname; } /* - * kadm5int_acl_match_data() - See if two data entries match. - * - * Wildcarding is only supported for a whole component. + * 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 -kadm5int_acl_match_data(const krb5_data *e1, const krb5_data *e2, - int targetflag, wildstate_t *ws) +match_data(const krb5_data *e1, const krb5_data *e2, krb5_boolean targetflag, + struct wildstate *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)) { - retval = 1; - if (ws && !targetflag) { - if (ws->nwild >= 9) { - DPRINT(DEBUG_ACL, acl_debug_level, - ("Too many wildcards in ACL entry.\n")); - } - else + int n; + + if (data_eq_string(*e1, "*")) { + if (ws != NULL && !targetflag) { + if (ws->nwild < 9) ws->backref[ws->nwild++] = e2; } + return TRUE; } - 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.\n")); - } - else if ((ws->backref[n]->length == e2->length) && - (!strncmp(ws->backref[n]->data, e2->data, e2->length))) - retval = 1; + 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); } - else { - if ((e1->length == e2->length) && - (!strncmp(e1->data, e2->data, e1->length))) - retval = 1; +} + +/* 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; } - DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_match_entry()=%d\n",retval)); - return(retval); + + return TRUE; } -/* - * kadm5int_acl_find_entry() - Find a matching entry. - */ -static aent_t * -kadm5int_acl_find_entry(krb5_context kcontext, krb5_const_principal principal, - krb5_const_principal dest_princ) +/* Find an ACL entry matching principal and target_principal. Return NULL if + * none is found. */ +static struct acl_entry * +find_entry(krb5_context context, struct acl_state *state, + krb5_const_principal client, krb5_const_principal target) { - aent_t *entry; - krb5_error_code kret; - int i; - int matchgood; - wildstate_t state; - - DPRINT(DEBUG_CALLS, acl_debug_level, ("* kadm5int_acl_find_entry()\n")); - for (entry=acl_list_head; entry; entry = entry->ae_next) { - memset(&state, 0, sizeof(state)); - if (entry->ae_name_bad) + struct acl_entry *entry; + krb5_error_code ret; + struct wildstate ws; + + for (entry = state->list; entry != NULL; entry = entry->next) { + memset(&ws, 0, sizeof(ws)); + if (entry->client_bad || entry->target_bad || entry->rs_bad) continue; - if (!strcmp(entry->ae_name, "*")) { - DPRINT(DEBUG_ACL, acl_debug_level, ("A wildcard ACL match\n")); - matchgood = 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; + + /* The client principal must match or be "*" in the entry. */ + if (strcmp(entry->client_string, "*") != 0) { + if (entry->client == NULL) { + ret = krb5_parse_name(context, entry->client_string, + &entry->client); + if (ret) { + entry->client_bad = TRUE; + continue; + } } - if (entry->ae_name_bad) { - DPRINT(DEBUG_ACL, acl_debug_level, - ("Bad ACL entry %s\n", entry->ae_name)); + if (!match_princ(entry->client, client, FALSE, &ws)) continue; - } - matchgood = 0; - if (kadm5int_acl_match_data(&entry->ae_principal->realm, - &principal->realm, 0, (wildstate_t *)0) && - (entry->ae_principal->length == principal->length)) { - matchgood = 1; - for (i=0; ilength; i++) { - if (!kadm5int_acl_match_data(&entry->ae_principal->data[i], - &principal->data[i], 0, &state)) { - matchgood = 0; - break; - } + } + + /* The target principal must match if one is specified. */ + if (entry->target_string != NULL && + strcmp(entry->target_string, "*") != 0) { + if (entry->target == NULL) { + ret = krb5_parse_name(context, entry->target_string, + &entry->target); + if (ret) { + entry->target_bad = TRUE; + continue; } } + if (target == NULL) + continue; + if (!match_princ(entry->target, target, TRUE, &ws)) + continue; } - if (!matchgood) - continue; - /* We've matched the principal. If we have a target, then try it */ - if (entry->ae_target && strcmp(entry->ae_target, "*")) { - 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, - ("Bad target in ACL entry for %s\n", entry->ae_name)); - entry->ae_name_bad = 1; + if (entry->rs_string != NULL && entry->rs == NULL) { + entry->rs = parse_restrictions(entry->rs_string, aclstate.fname); + if (entry->rs == NULL) { + entry->rs_bad = TRUE; continue; } - if (!dest_princ) - matchgood = 0; - else if (entry->ae_target_princ && dest_princ) { - if (kadm5int_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; ilength; i++) { - if (!kadm5int_acl_match_data(&entry->ae_target_princ->data[i], - &dest_princ->data[i], 1, &state)) { - matchgood = 0; - break; - } - } - } - else - matchgood = 0; - } } - if (!matchgood) - continue; - if (entry->ae_restriction_string - && !entry->ae_restriction_bad - && !entry->ae_restrictions - && kadm5int_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 (entry->ae_restriction_bad) { - entry->ae_name_bad = 1; - continue; - } - break; + return entry; } - DPRINT(DEBUG_CALLS, acl_debug_level, ("X kadm5int_acl_find_entry()=%x\n",entry)); - return(entry); + + return NULL; } -/* - * kadm5int_acl_init() - Initialize ACL context. - */ +/* Initialize the ACL context. */ krb5_error_code -kadm5int_acl_init(kcontext, debug_level, acl_file) - krb5_context kcontext; - int debug_level; - char *acl_file; +acl_init(krb5_context context, const char *acl_file) { - krb5_error_code kret; - - kret = 0; - acl_debug_level = debug_level; - DPRINT(DEBUG_CALLS, acl_debug_level, - ("* kadm5int_acl_init(afile=%s)\n", - ((acl_file) ? acl_file : "(null)"))); - acl_acl_file = (acl_file) ? acl_file : (char *) KRB5_DEFAULT_ADMIN_ACL; - acl_inited = kadm5int_acl_load_acl_file(); - - DPRINT(DEBUG_CALLS, acl_debug_level, ("X kadm5int_acl_init() = %d\n", kret)); - return(kret); + load_acl_file(acl_file, &aclstate); + return 0; } -/* - * kadm5int_acl_finish - Terminate ACL context. - */ +/* Terminate the ACL context. */ void -kadm5int_acl_finish(kcontext, debug_level) - krb5_context kcontext; - int debug_level; +acl_finish(krb5_context context) { - DPRINT(DEBUG_CALLS, acl_debug_level, ("* kadm5int_acl_finish()\n")); - kadm5int_acl_free_entries(); - DPRINT(DEBUG_CALLS, acl_debug_level, ("X kadm5int_acl_finish()\n")); + free_acl_entries(&aclstate); } -/* - * kadm5int_acl_check_krb() - Is this operation permitted for this principal? - */ +/* Return true if op is permitted for this principal. Set *rs_out (if not + * NULL) according to any restrictions in the ACL entry. */ krb5_boolean -kadm5int_acl_check_krb(kcontext, caller_princ, opmask, principal, restrictions) - krb5_context kcontext; - krb5_const_principal caller_princ; - krb5_int32 opmask; - krb5_const_principal principal; - restriction_t **restrictions; +acl_check(krb5_context context, krb5_const_principal client, uint32_t op, + krb5_const_principal target, struct kadm5_auth_restrictions **rs_out) { - krb5_boolean retval; - aent_t *aentry; - - DPRINT(DEBUG_CALLS, acl_debug_level, ("* acl_op_permitted()\n")); - - retval = FALSE; - - aentry = kadm5int_acl_find_entry(kcontext, caller_princ, principal); - if (aentry) { - if ((aentry->ae_op_allowed & opmask) == opmask) { - retval = TRUE; - if (restrictions) { - *restrictions = - (aentry->ae_restrictions && aentry->ae_restrictions->mask) - ? aentry->ae_restrictions - : (restriction_t *) NULL; - } - } - } + struct acl_entry *entry; - DPRINT(DEBUG_CALLS, acl_debug_level, ("X acl_op_permitted()=%d\n", - retval)); - return retval; -} + if (rs_out != NULL) + *rs_out = NULL; -/* - * kadm5int_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 - * the best medium-term solution. (The best long-term - * solution is, of course, a real authorization service.) - */ -krb5_boolean -kadm5int_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; - gss_buffer_desc caller_buf; - gss_OID caller_oid; - OM_uint32 emin; - krb5_error_code code; - krb5_principal caller_princ; - - if (GSS_ERROR(gss_display_name(&emin, caller, &caller_buf, &caller_oid))) + entry = find_entry(context, &aclstate, client, target); + if (entry == NULL) return FALSE; - - code = krb5_parse_name(kcontext, (char *) caller_buf.value, - &caller_princ); - - gss_release_buffer(&emin, &caller_buf); - - if (code != 0) + if (!(entry->op_allowed & op)) return FALSE; - retval = kadm5int_acl_check_krb(kcontext, caller_princ, - opmask, principal, restrictions); - - krb5_free_principal(kcontext, caller_princ); + if (rs_out != NULL && entry->rs != NULL && entry->rs->mask) + *rs_out = entry->rs; - return retval; + return TRUE; } diff --git a/src/kadmin/server/auth_acl.h b/src/kadmin/server/auth_acl.h index c1a45dbbbf..55a8662b44 100644 --- a/src/kadmin/server/auth_acl.h +++ b/src/kadmin/server/auth_acl.h @@ -27,24 +27,6 @@ #ifndef SERVER_ACL_H__ #define SERVER_ACL_H__ -/* - * Debug definitions. - */ -#define DEBUG_SPROC 1 -#define DEBUG_OPERATION 2 -#define DEBUG_HOST 4 -#define DEBUG_REALM 8 -#define DEBUG_REQUESTS 16 -#define DEBUG_ACL 32 -#define DEBUG_PROTO 64 -#define DEBUG_CALLS 128 -#define DEBUG_NOSLAVES 256 -#ifdef DEBUG -#define DPRINT(l1, cl, al) if ((cl & l1) != 0) printf al -#else /* DEBUG */ -#define DPRINT(l1, cl, al) -#endif /* DEBUG */ - /* * Access control bits. */ @@ -58,7 +40,6 @@ #define ACL_LIST 128 #define ACL_SETKEY 256 #define ACL_IPROP 512 -#define ACL_RENAME (ACL_ADD+ACL_DELETE) #define ACL_ALL_MASK (ACL_ADD | \ ACL_DELETE | \ @@ -69,32 +50,25 @@ ACL_IPROP | \ 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; +struct kadm5_auth_restrictions { + long mask; + krb5_flags require_attrs; + krb5_flags forbid_attrs; + krb5_deltat princ_lifetime; + krb5_deltat pw_lifetime; + krb5_deltat max_life; + krb5_deltat max_renewable_life; + char *policy; +}; + +krb5_error_code acl_init(krb5_context context, const char *acl_file); +void acl_finish(krb5_context); +krb5_boolean acl_check(krb5_context context, krb5_const_principal client, + uint32_t op, krb5_const_principal target, + struct kadm5_auth_restrictions **rs_out); +krb5_error_code acl_impose_restrictions(krb5_context context, + kadm5_principal_ent_rec *rec, + long *mask, + struct kadm5_auth_restrictions *rs); -krb5_error_code kadm5int_acl_init(krb5_context, int, char *); -void kadm5int_acl_finish(krb5_context, int); -krb5_boolean kadm5int_acl_check(krb5_context, - gss_name_t, - krb5_int32, - krb5_principal, - restriction_t **); -krb5_boolean kadm5int_acl_check_krb(krb5_context, - krb5_const_principal, - krb5_int32, - krb5_const_principal, - restriction_t **); -krb5_error_code kadm5int_acl_impose_restrictions(krb5_context, - kadm5_principal_ent_rec *, - long *, - restriction_t *); #endif /* SERVER_ACL_H__ */ diff --git a/src/kadmin/server/deps b/src/kadmin/server/deps index fce7ed39c2..e7cd3e6066 100644 --- a/src/kadmin/server/deps +++ b/src/kadmin/server/deps @@ -2,25 +2,24 @@ # Generated makefile dependencies follow. # $(OUTPRE)auth_acl.$(OBJEXT): $(BUILDTOP)/include/autoconf.h \ - $(BUILDTOP)/include/gssapi/gssapi.h $(BUILDTOP)/include/gssapi/gssapi_generic.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_internal.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/plugin.h $(top_srcdir)/include/port-sockets.h \ - $(top_srcdir)/include/socket-utils.h auth_acl.c auth_acl.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/plugin.h \ + $(top_srcdir)/include/port-sockets.h $(top_srcdir)/include/socket-utils.h \ + auth_acl.c auth_acl.h $(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 \ diff --git a/src/kadmin/server/ipropd_svc.c b/src/kadmin/server/ipropd_svc.c index 503b797472..c552ed08c2 100644 --- a/src/kadmin/server/ipropd_svc.c +++ b/src/kadmin/server/ipropd_svc.c @@ -129,6 +129,19 @@ 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 = acl_check(context, client_princ, ACL_IPROP, NULL, NULL); + 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 +187,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 +310,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); diff --git a/src/kadmin/server/misc.c b/src/kadmin/server/misc.c index 685a0bb5c0..1975af0a6a 100644 --- a/src/kadmin/server/misc.c +++ b/src/kadmin/server/misc.c @@ -133,8 +133,7 @@ schpw_util_wrapper(void *server_handle, access_granted = FALSE; if (!access_granted && - kadm5int_acl_check_krb(handle->context, client, - ACL_CHANGEPW, target, NULL)) { + acl_check(handle->context, client, ACL_CHANGEPW, target, NULL)) { /* * Otherwise, principals with appropriate privileges can change * any password diff --git a/src/kadmin/server/ovsec_kadmd.c b/src/kadmin/server/ovsec_kadmd.c index b9876b9794..498c7cdff6 100644 --- a/src/kadmin/server/ovsec_kadmd.c +++ b/src/kadmin/server/ovsec_kadmd.c @@ -505,7 +505,7 @@ 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); + ret = acl_init(context, params.acl_file); if (ret) fail_to_start(ret, _("initializing ACL file")); @@ -550,7 +550,7 @@ main(int argc, char *argv[]) svcauth_gssapi_unset_names(); kadm5_destroy(global_server_handle); loop_free(vctx); - kadm5int_acl_finish(context, 0); + acl_finish(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/server_stubs.c b/src/kadmin/server/server_stubs.c index be50efcbf2..84b877a749 100644 --- a/src/kadmin/server/server_stubs.c +++ b/src/kadmin/server/server_stubs.c @@ -320,6 +320,15 @@ stub_cleanup(kadm5_server_handle_t handle, char *princ_str, gss_release_buffer(&minor_stat, service_name); } +static krb5_boolean +stub_acl_check(kadm5_server_handle_t handle, uint32_t op, + krb5_const_principal target, + struct kadm5_auth_restrictions **rs_out) +{ + return acl_check(handle->context, handle->current_caller, op, target, + rs_out); +} + static int log_unauth( char *op, @@ -387,7 +396,7 @@ 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; + struct kadm5_auth_restrictions *rp; const char *errmsg = NULL; ret->code = stub_setup(arg->api_version, rqstp, arg->rec.principal, @@ -396,11 +405,9 @@ 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_acl_check(handle, ACL_ADD, arg->rec.principal, &rp) || + acl_impose_restrictions(handle->context, &arg->rec, &arg->mask, rp)) { ret->code = KADM5_AUTH_ADD; log_unauth("kadm5_create_principal", prime_arg, &client_name, &service_name, rqstp); @@ -431,7 +438,7 @@ 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; + struct kadm5_auth_restrictions *rp; const char *errmsg = NULL; ret->code = stub_setup(arg->api_version, rqstp, arg->rec.principal, @@ -440,11 +447,9 @@ 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_acl_check(handle, ACL_ADD, arg->rec.principal, &rp) || + acl_impose_restrictions(handle->context, &arg->rec, &arg->mask, rp)) { ret->code = KADM5_AUTH_ADD; log_unauth("kadm5_create_principal", prime_arg, &client_name, &service_name, rqstp); @@ -498,9 +503,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_acl_check(handle, ACL_DELETE, arg->princ, NULL)) { ret->code = KADM5_AUTH_DELETE; log_unauth("kadm5_delete_principal", prime_arg, &client_name, &service_name, rqstp); @@ -540,7 +544,7 @@ 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; + struct kadm5_auth_restrictions *rp; const char *errmsg = NULL; ret->code = stub_setup(arg->api_version, rqstp, arg->rec.principal, @@ -549,11 +553,9 @@ 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_acl_check(handle, ACL_MODIFY, arg->rec.principal, &rp) || + acl_impose_restrictions(handle->context, &arg->rec, &arg->mask, rp)) { ret->code = KADM5_AUTH_MODIFY; log_unauth("kadm5_modify_principal", prime_arg, &client_name, &service_name, rqstp); @@ -592,7 +594,7 @@ 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; + struct kadm5_auth_restrictions *rp; const char *errmsg = NULL; size_t tlen1, tlen2, clen, slen; char *tdots1, *tdots2, *cdots, *sdots; @@ -619,12 +621,10 @@ rename_principal_2_svc(rprinc_arg *arg, generic_ret *ret, ret->code = KADM5_OK; if (! CHANGEPW_SERVICE(rqstp)) { - if (!kadm5int_acl_check(handle->context, rqst2name(rqstp), - ACL_DELETE, arg->src, NULL)) + if (!stub_acl_check(handle, ACL_DELETE, arg->src, NULL)) 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 (!stub_acl_check(handle, ACL_ADD, arg->dest, &rp) || rp != NULL) { if (ret->code == KADM5_AUTH_DELETE) ret->code = KADM5_AUTH_INSUFFICIENT; else @@ -697,11 +697,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))) { + (CHANGEPW_SERVICE(rqstp) || + !stub_acl_check(handle, ACL_INQUIRE, arg->princ, NULL))) { ret->code = KADM5_AUTH_GET; log_unauth(funcname, prime_arg, &client_name, &service_name, rqstp); @@ -743,11 +740,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_acl_check(handle, ACL_LIST, NULL, NULL)) { ret->code = KADM5_AUTH_LIST; log_unauth("kadm5_get_principals", prime_arg, &client_name, &service_name, rqstp); @@ -797,8 +791,7 @@ chpass_principal_2_svc(chpass_arg *arg, generic_ret *ret, 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)) { + stub_acl_check(handle, ACL_CHANGEPW, arg->princ, NULL)) { ret->code = kadm5_chpass_principal(handle, arg->princ, arg->pass); } else { log_unauth("kadm5_chpass_principal", prime_arg, @@ -850,8 +843,7 @@ chpass_principal3_2_svc(chpass3_arg *arg, generic_ret *ret, 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)) { + stub_acl_check(handle, ACL_CHANGEPW, arg->princ, NULL)) { ret->code = kadm5_chpass_principal_3(handle, arg->princ, arg->keepold, arg->n_ks_tuple, arg->ks_tuple, arg->pass); @@ -901,8 +893,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_acl_check(handle, ACL_SETKEY, arg->princ, NULL)) { ret->code = kadm5_setv4key_principal(handle, arg->princ, arg->keyblock); } else { @@ -952,8 +943,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_acl_check(handle, ACL_SETKEY, arg->princ, NULL)) { ret->code = kadm5_setkey_principal(handle, arg->princ, arg->keyblocks, arg->n_keys); } else { @@ -1002,8 +992,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_acl_check(handle, ACL_SETKEY, arg->princ, 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 +1042,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_acl_check(handle, ACL_SETKEY, arg->princ, NULL)) { ret->code = kadm5_setkey_principal_4(handle, arg->princ, arg->keepold, arg->key_data, arg->n_key_data); } else { @@ -1123,8 +1111,7 @@ chrand_principal_2_svc(chrand_arg *arg, chrand_ret *ret, struct svc_req *rqstp) 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)) { + stub_acl_check(handle, ACL_CHANGEPW, arg->princ, NULL)) { ret->code = kadm5_randkey_principal(handle, arg->princ, &k, &nkeys); } else { log_unauth(funcname, prime_arg, @@ -1181,8 +1168,7 @@ chrand_principal3_2_svc(chrand3_arg *arg, chrand_ret *ret, 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)) { + stub_acl_check(handle, ACL_CHANGEPW, arg->princ, NULL)) { ret->code = kadm5_randkey_principal_3(handle, arg->princ, arg->keepold, arg->n_ks_tuple, arg->ks_tuple, &k, &nkeys); @@ -1233,9 +1219,8 @@ 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_acl_check(handle, ACL_ADD, NULL, NULL)) { ret->code = KADM5_AUTH_ADD; log_unauth("kadm5_create_policy", prime_arg, &client_name, &service_name, rqstp); @@ -1275,9 +1260,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_acl_check(handle, ACL_DELETE, NULL, NULL)) { log_unauth("kadm5_delete_policy", prime_arg, &client_name, &service_name, rqstp); ret->code = KADM5_AUTH_DELETE; @@ -1316,9 +1300,8 @@ 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_acl_check(handle, ACL_MODIFY, NULL, NULL)) { log_unauth("kadm5_modify_policy", prime_arg, &client_name, &service_name, rqstp); ret->code = KADM5_AUTH_MODIFY; @@ -1362,11 +1345,10 @@ 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)) + if (!CHANGEPW_SERVICE(rqstp) && + stub_acl_check(handle, ACL_INQUIRE, NULL, NULL)) { ret->code = KADM5_OK; - else { + } else { ret->code = kadm5_get_principal(handle->lhandle, handle->current_caller, &caller_ent, KADM5_PRINCIPAL_NORMAL_MASK); @@ -1424,9 +1406,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_acl_check(handle, ACL_LIST, NULL, NULL)) { ret->code = KADM5_AUTH_LIST; log_unauth("kadm5_get_policies", prime_arg, &client_name, &service_name, rqstp); @@ -1495,9 +1476,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))) { + (CHANGEPW_SERVICE(rqstp) || + !stub_acl_check(handle, ACL_MODIFY, arg->princ, NULL))) { ret->code = KADM5_AUTH_MODIFY; log_unauth(funcname, prime_arg, &client_name, &service_name, rqstp); } else { @@ -1533,11 +1513,8 @@ get_strings_2_svc(gstrings_arg *arg, gstrings_ret *ret, struct svc_req *rqstp) 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))) { + (CHANGEPW_SERVICE(rqstp) || + !stub_acl_check(handle, ACL_INQUIRE, arg->princ, NULL))) { ret->code = KADM5_AUTH_GET; log_unauth("kadm5_get_strings", prime_arg, &client_name, &service_name, rqstp); @@ -1574,9 +1551,8 @@ 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_acl_check(handle, ACL_MODIFY, arg->princ, NULL)) { ret->code = KADM5_AUTH_MODIFY; log_unauth("kadm5_mod_strings", prime_arg, &client_name, &service_name, rqstp); @@ -1665,8 +1641,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_acl_check(handle, ACL_EXTRACT, arg->princ, NULL)) { ret->code = kadm5_get_principal_keys(handle, arg->princ, arg->kvno, &ret->key_data, &ret->n_key_data); } else {