123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089 |
- /** BEGIN COPYRIGHT BLOCK
- * This Program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License as published by the Free Software
- * Foundation; version 2 of the License.
- *
- * This Program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * In addition, as a special exception, Red Hat, Inc. gives You the additional
- * right to link the code of this Program with code not covered under the GNU
- * General Public License ("Non-GPL Code") and to distribute linked combinations
- * including the two, subject to the limitations in this paragraph. Non-GPL Code
- * permitted under this exception must only link to the code of this Program
- * through those well defined interfaces identified in the file named EXCEPTION
- * found in the source code files (the "Approved Interfaces"). The files of
- * Non-GPL Code may instantiate templates or use macros or inline functions from
- * the Approved Interfaces without causing the resulting work to be covered by
- * the GNU General Public License. Only Red Hat, Inc. may make changes or
- * additions to the list of Approved Interfaces. You must obey the GNU General
- * Public License in all respects for all of the Program code and other code used
- * in conjunction with the Program except the Non-GPL Code covered by this
- * exception. If you modify this file, you may extend this exception to your
- * version of the file, but you are not obligated to do so. If you do not wish to
- * provide this exception without modification, you must delete this exception
- * statement from your version and license this file solely under the GPL without
- * exception.
- *
- *
- * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
- * Copyright (C) 2005 Red Hat, Inc.
- * All rights reserved.
- * END COPYRIGHT BLOCK **/
- #ifdef HAVE_CONFIG_H
- # include <config.h>
- #endif
- /*
- * Description (acleval.c)
- *
- * This module provides functions for evaluating Access Control List
- * (ACL) structures in memory.
- *
- */
- #include <string.h>
- #include <sys/types.h>
- #include <assert.h>
- #include <netsite.h>
- #include <base/systems.h>
- #include <base/crit.h>
- #include <libaccess/nserror.h>
- #include <libaccess/acl.h>
- #include "aclpriv.h"
- #include <libaccess/aclproto.h>
- #include <libaccess/las.h>
- #include <libaccess/symbols.h>
- #include <libaccess/aclerror.h>
- #include <libaccess/aclglobal.h>
- #include <libaccess/dbtlibaccess.h>
- #include <libaccess/aclerror.h>
- #include "access_plhash.h"
- #include "aclutil.h"
- #include "aclcache.h"
- #include "oneeval.h"
- #define NO_ACL_HASH_FUNCS
- #include "permhash.h"
- static ACLDispatchVector_t __nsacl_vector = {
- /* Error frame stack support */
- nserrDispose,
- nserrFAlloc,
- nserrFFree,
- nserrGenerate,
- /* Property list support */
- PListAssignValue,
- PListCreate,
- PListDefProp,
- PListDeleteProp,
- PListFindValue,
- PListInitProp,
- PListNew,
- PListDestroy,
- PListGetValue,
- PListNameProp,
- PListSetType,
- PListSetValue,
- PListEnumerate,
- PListDuplicate,
- PListGetPool,
- /* ACL attribute handling */
- ACL_LasRegister,
- /* method/dbtype registration routines */
- ACL_MethodRegister,
- ACL_MethodIsEqual,
- ACL_MethodNameIsEqual,
- ACL_MethodFind,
- ACL_MethodGetDefault,
- ACL_MethodSetDefault,
- ACL_AuthInfoGetMethod,
- ACL_DbTypeRegister,
- ACL_DbTypeIsEqual,
- ACL_DbTypeNameIsEqual,
- ACL_DbTypeFind,
- ACL_DbTypeGetDefault,
- ACL_AuthInfoGetDbType,
- ACL_DbTypeIsRegistered,
- ACL_DbTypeParseFn,
- ACL_AttrGetterRegister,
- ACL_ModuleRegister,
- ACL_GetAttribute,
- ACL_DatabaseRegister,
- ACL_DatabaseFind,
- ACL_DatabaseSetDefault,
- NULL,
- ACL_AuthInfoGetDbname,
- ACL_CacheFlushRegister,
- ACL_CacheFlush,
- /* ACL language and file interfaces */
- NULL /* ex ACL_ParseFile*/,
- ACL_ParseString,
- NULL /* ex ACL_WriteString*/,
- NULL /* ex ACL_WriteFile */,
- NULL /* ex ACL_FileRenameAcl */,
- NULL /* ex ACL_FileDeleteAcl */,
- NULL /* ex ACL_FileGetAcl */,
- NULL /* ex ACL_FileSetAcl */,
- /* ACL Expression construction interfaces */
- ACL_ExprNew,
- ACL_ExprDestroy,
- ACL_ExprSetPFlags,
- ACL_ExprClearPFlags,
- ACL_ExprTerm,
- ACL_ExprNot,
- ACL_ExprAnd,
- ACL_ExprOr,
- ACL_ExprAddAuthInfo,
- ACL_ExprAddArg,
- ACL_ExprSetDenyWith,
- ACL_ExprGetDenyWith,
- ACL_ExprAppend,
- /* ACL manipulation */
- ACL_AclNew,
- ACL_AclDestroy,
- /* ACL list manipulation */
- ACL_ListNew,
- ACL_ListConcat,
- ACL_ListAppend,
- ACL_ListDestroy,
- ACL_ListFind,
- ACL_ListAclDelete,
- ACL_ListGetNameList,
- ACL_NameListDestroy,
- /* ACL evaluation */
- ACL_EvalTestRights,
- ACL_EvalNew,
- ACL_EvalDestroy,
- ACL_EvalSetACL,
- ACL_EvalGetSubject,
- ACL_EvalSetSubject,
- ACL_EvalGetResource,
- ACL_EvalSetResource,
- /* Access to critical section for ACL cache */
- ACL_CritEnter,
- ACL_CritExit,
- /* Miscellaneous functions */
- ACL_AclGetTag,
- ACL_ListGetFirst,
- ACL_ListGetNext,
- /* Functions added after ES 3.0 release */
- ACL_DatabaseGetDefault,
- ACL_SetDefaultResult,
- ACL_GetDefaultResult
- };
- NSAPI_PUBLIC ACLDispatchVector_t *__nsacl_table = &__nsacl_vector;
- int ACLEvalAce(
- NSErr_t *errp,
- ACLEvalHandle_t *acleval,
- ACLExprHandle_t *ace,
- ACLCachable_t *cachable,
- PList_t autharray[],
- PList_t global_auth
- )
- {
- ACLCachable_t local_cachable;
- int result;
- ACLExprEntry_t *expr;
- int expr_index = 0;
- expr = &ace->expr_arry[0];
- *cachable = ACL_INDEF_CACHABLE;
- while (TRUE)
- {
- local_cachable = ACL_NOT_CACHABLE;
- /* Call the LAS driver */
- if (!expr->las_eval_func) {
- ACL_CritEnter();
- if (!expr->las_eval_func) { /* Must check again after locking */
- ACL_LasFindEval(errp, expr->attr_name, &expr->las_eval_func);
- if (!expr->las_eval_func) { /* Couldn't find it */
- ACL_CritExit();
- return LAS_EVAL_INVALID;
- }
- }
- ACL_CritExit();
- }
- result = (*expr->las_eval_func)(
- errp,
- expr->attr_name,
- expr->comparator,
- expr->attr_pattern,
- &local_cachable,
- &expr->las_cookie,
- acleval->subject,
- acleval->resource,
- autharray ? autharray[expr_index] : NULL,
- global_auth);
- /* Evaluate the cachable value */
- if (local_cachable < *cachable) {
- /* Take the minimum value */
- *cachable = local_cachable;
- }
- /* Evaluate the return code */
- switch (result) {
- case LAS_EVAL_TRUE:
- if (expr->true_idx < 0)
- return (expr->true_idx);
- else {
- expr_index = expr->true_idx;
- expr = &ace->expr_arry[expr->true_idx];
- }
- break;
- case LAS_EVAL_FALSE:
- if (expr->false_idx < 0)
- return (expr->false_idx);
- else {
- expr_index = expr->false_idx;
- expr = &ace->expr_arry[expr->false_idx];
- }
- break;
- default:
- return (result);
- }
- }
- }
- int
- ACL_EvalDestroyContext(ACLListCache_t *cache)
- {
- ACLAceEntry_t *cur_ace, *next_ace;
- ACLAceNumEntry_t *cur_num_p, *next_num_p;
- if (!cache)
- return 0;
- PR_HashTableDestroy(cache->Table);
- cache->Table = NULL;
- cur_ace = cache->acelist;
- cache->acelist = NULL;
- while (cur_ace) {
- if (cur_ace->autharray)
- PERM_FREE(cur_ace->autharray);
- if ((cur_ace->global_auth) &&
- (cur_ace->acep->expr_type == ACL_EXPR_TYPE_AUTH))
- PListDestroy(cur_ace->global_auth);
- next_ace = cur_ace->next;
- PERM_FREE(cur_ace);
- cur_ace = next_ace;
- }
- cur_num_p = cache->chain_head;
- cache->chain_head = NULL;
- while (cur_num_p) {
- next_num_p = cur_num_p->chain;
- PERM_FREE(cur_num_p);
- cur_num_p = next_num_p;
- }
- PERM_FREE(cache);
- return 0;
- }
- /* ACLEvalBuildContext
- * Builds three structures:
- * Table - A hash table of all access rights referenced by any ACE in any
- * of the ACLs in this list. Each hash entry then has a list of
- * the relevant ACEs, in the form of indexes to the ACE linked
- * list.
- * ACE List - A linked list of all the ACEs in the proper evaluation order.
- *
- * For concurrency control, the caller must call ACL_CritEnter()
- */
- int
- ACLEvalBuildContext(
- NSErr_t *errp,
- ACLEvalHandle_t *acleval)
- {
- ACLHandle_t *acl;
- ACLExprHandle_t *ace;
- int ace_cnt = -1;
- ACLAceEntry_t *acelast = NULL, *new_ace;
- ACLAceNumEntry_t *entry, *temp_entry;
- char **argp;
- ACLListCache_t *cache;
- ACLWrapper_t *wrapper;
- PList_t curauthplist=NULL, absauthplist=NULL;
- int i, rv;
- ACLExprEntry_t *expr;
- PList_t authplist;
- /* Allocate the cache context and link it into the ACLListHandle */
- cache = (ACLListCache_t *)PERM_CALLOC(sizeof(ACLListCache_t));
- if (cache == NULL) {
- nserrGenerate(errp, ACLERRNOMEM, ACLERR4010, ACL_Program, 0);
- goto error;
- }
- /* Allocate the access rights hash table */
- cache->Table = PR_NewHashTable(0,
- PR_HashString,
- PR_CompareStrings,
- PR_CompareValues,
- &ACLPermAllocOps,
- NULL);
- if (cache->Table == NULL) {
- nserrGenerate(errp, ACLERRNOMEM, ACLERR4000, ACL_Program, 1,
- XP_GetAdminStr(DBT_EvalBuildContextUnableToCreateHash));
- goto error;
- }
- wrapper = acleval->acllist->acl_list_head;
- /* Loop through all the ACLs in the list */
- while (wrapper)
- {
- acl = wrapper->acl;
- ace = acl->expr_list_head;
- while (ace) /* Loop through all the ACEs in this ACL */
- {
- /* allocate a new ace list entry and link it in to the ordered
- * list.
- */
- new_ace = (ACLAceEntry_t *)PERM_CALLOC(sizeof(ACLAceEntry_t));
- if (new_ace == (ACLAceEntry_t *)NULL) {
- nserrGenerate(errp, ACLERRNOMEM, ACLERR4020, ACL_Program, 1,
- XP_GetAdminStr(DBT_EvalBuildContextUnableToAllocAceEntry));
- goto error;
- }
- new_ace->acep = ace;
- ace_cnt++;
- if (cache->acelist == NULL)
- cache->acelist = acelast = new_ace;
- else {
- if(acelast)
- acelast->next = new_ace;
- acelast = new_ace;
- new_ace->acep = ace;
- }
- new_ace->next = NULL;
- argp = ace->expr_argv;
- switch (ace->expr_type)
- {
- case ACL_EXPR_TYPE_ALLOW:
- case ACL_EXPR_TYPE_DENY:
- /* Add this ACE to the appropriate entries in the access rights
- * hash table
- */
- while (*argp)
- {
- entry =
- (ACLAceNumEntry_t *)PERM_CALLOC(sizeof(ACLAceNumEntry_t));
- if (entry == (ACLAceNumEntry_t *)NULL) {
- nserrGenerate(errp, ACLERRNOMEM, ACLERR4030, ACL_Program, 1,
- XP_GetAdminStr(DBT_EvalBuildContextUnableToAllocAceEntry));
- goto error;
- }
- if (cache->chain_head == NULL)
- cache->chain_head = cache->chain_tail = entry;
- else {
- cache->chain_tail->chain = entry;
- cache->chain_tail = entry;
- }
- entry->acenum = ace_cnt;
-
- /*
- * OK to call PL_HasTableLookup() even though it mods
- * the Table as this routine is called in critical section.
- */
- temp_entry = (ACLAceNumEntry_t *)PL_HashTableLookup(cache->Table, *argp);
- /* the first ACE for this right? */
- if (temp_entry) {
- /* Link it in at the end */
- while (temp_entry->next) {
- temp_entry = temp_entry->next;
- }
- temp_entry->next = entry;
- } else /* just link it in */
- PR_HashTableAdd(cache->Table, *argp, entry);
- argp++;
- }
- /* See if any of the clauses require authentication. */
- if (curauthplist) {
- for (i = 0; i < ace->expr_term_index; i++) {
- expr = &ace->expr_arry[i];
- rv = PListFindValue(curauthplist, expr->attr_name,
- NULL, &authplist);
- if (rv > 0) {
- /* First one for this ACE? */
- if (!new_ace->autharray) {
- new_ace->autharray = (PList_t *)PERM_CALLOC(sizeof(PList_t) * ace->expr_term_index);
- if (!new_ace->autharray) {
- nserrGenerate(errp, ACLERRNOMEM, ACLERR4040, ACL_Program, 1, XP_GetAdminStr(DBT_EvalBuildContextUnableToAllocAuthPointerArray));
- goto error;
- }
- }
- new_ace->autharray[i] = authplist;
- }
- }
- }
- break;
- case ACL_EXPR_TYPE_AUTH:
- /* Allocate the running auth tables if none yet */
- if (!curauthplist) {
- curauthplist = PListNew(NULL);
- if (!curauthplist) {
- nserrGenerate(errp, ACLERRNOMEM, ACLERR4050, ACL_Program, 1, XP_GetAdminStr(DBT_EvalBuildContextUnableToAllocAuthPlist));
- goto error;
- }
- absauthplist = PListNew(NULL);
- if (!absauthplist) {
- nserrGenerate(errp, ACLERRNOMEM, ACLERR4050, ACL_Program, 1, XP_GetAdminStr(DBT_EvalBuildContextUnableToAllocAuthPlist));
- goto error;
- }
- } else { /* duplicate the existing auth table */
- curauthplist = PListDuplicate(curauthplist, NULL, 0);
- if (!curauthplist) {
- nserrGenerate(errp, ACLERRNOMEM, ACLERR4050, ACL_Program, 1, XP_GetAdminStr(DBT_EvalBuildContextUnableToAllocAuthPlist));
- goto error;
- }
- }
- /* For each listed attribute */
- while (*argp)
- {
- /* skip any attributes that were absoluted */
- if (PListFindValue(absauthplist, *argp, NULL, NULL) < 0)
- {
- /* Save pointer to the property list */
- PListInitProp(curauthplist, 0, *argp, ace->expr_auth,
- ace->expr_auth);
- if (IS_ABSOLUTE(ace->expr_flags))
- PListInitProp(absauthplist, 0, *argp, NULL,
- NULL);
- }
- argp++;
- }
- break;
- case ACL_EXPR_TYPE_RESPONSE:
- (void) ACL_ExprGetDenyWith(NULL, ace, &cache->deny_type,
- &cache->deny_response);
- break;
- default:
- PR_ASSERT(0);
-
- } /* switch expr_type */
- new_ace->global_auth = curauthplist;
- ace = ace->expr_next;
- }
- /* Next ACL please */
- wrapper = wrapper->wrap_next;
- }
- if (absauthplist)
- PListDestroy(absauthplist);
- /* This must be done last to avoid a race in initialization */
- acleval->acllist->cache = (void *)cache;
- return 0;
- error:
- if (curauthplist)
- PListDestroy(curauthplist);
- if (absauthplist)
- PListDestroy(absauthplist);
- if (cache) {
- ACL_EvalDestroyContext(cache);
- }
- acleval->acllist->cache = NULL;
- return ACL_RES_ERROR;
- }
- /* ACL_InvalidateSubjectPList
- * Given a new authentication plist, enumerate the plist and for each
- * key in the plist, search for the matching key in the subject plist
- * and delete any matches. E.g. "user", "group".
- */
- void
- ACL_InvalidateSubjectPList(char *attr, const void *value, void *user_data)
- {
- PList_t subject = (PList_t)user_data;
- PListDeleteProp(subject, 0, attr);
- return;
- }
- NSAPI_PUBLIC int ACL_SetDefaultResult (NSErr_t *errp,
- ACLEvalHandle_t *acleval,
- int result)
- {
- int rv;
- switch(result) {
- case ACL_RES_ALLOW:
- case ACL_RES_DENY:
- case ACL_RES_FAIL:
- case ACL_RES_INVALID:
- acleval->default_result = result;
- rv = 0;
- break;
- default:
- rv = -1;
- }
- return rv;
- }
- NSAPI_PUBLIC int ACL_GetDefaultResult (ACLEvalHandle_t *acleval)
- {
- return acleval->default_result;
- }
- /* ACL_INTEvalTestRights
- * INPUT
- * *errp The usual error context stack
- * *acleval A list of ACLs
- * **rights An array of strings listing the requested rights
- * **map_generic An array of strings listing the specific rights
- * that map from the generic rights.
- * OUTPUT
- * **deny_type bong file type passed on the way back out
- * **deny_response bong file pathname passed on the way back out
- * **acl_tag Name of the ACL that denies access
- * *expr_num ACE number within the denying ACL
- * *cachable Is the result cachable?
- */
- static int
- ACL_INTEvalTestRights(
- NSErr_t *errp,
- ACLEvalHandle_t *acleval,
- char **rights,
- char **map_generic,
- char **deny_type,
- char **deny_response,
- char **acl_tag,
- int *expr_num,
- ACLCachable_t *cachable)
- {
- struct rights_ent {
- char right[64]; /* lowercase-ed rights string */
- int result; /* Interim result value */
- int absolute; /* ACE with absolute keyword */
- int count; /* # specific + generic rights */
- ACLAceNumEntry_t *acelist[ACL_MAX_GENERIC+1];
- /* List of relevant ACEs */
- };
- struct rights_ent *rarray_p;
- struct rights_ent rights_arry[ACL_MAX_TEST_RIGHTS];
- ACLAceNumEntry_t *alllist; /* List of ACEs for "all" rights */
- ACLAceEntry_t *cur_ace;
- ACLListCache_t *cache;
- int rights_cnt = 0;
- int prev_acenum, cur_acenum;
- int i, j, right_num, delta;
- ACLCachable_t ace_cachable;
- int result;
- int absolute = 0;
- int skipflag;
- int g_num; /* index into the generic rights array. */
- char **g_rights;
- PList_t global_auth=NULL;
- int allow_error = 0;
- int allow_absolute = 0;
- char *allow_tag = NULL;
- int allow_num = 0;
- int default_result = ACL_GetDefaultResult(acleval);
- *acl_tag = NULL;
- *expr_num = 0;
- *cachable = ACL_INDEF_CACHABLE;
- /*
- * The acleval contains the list of acis we are asking about.
- * In our case it's always of length 1.
- * The acleval is a per aclpb structure but
- * the acllist is a global structure derived from the global
- * aci cache--so access to acllist is multi-threaded.
- * Hence, for example the use of the "read-only" hash
- * lookup routines in this function--ACL_EvalTestRights()
- * is called in a "reader only context" so this code is therefore
- * thread-safe.
- */
- if (acleval->acllist == ACL_LIST_NO_ACLS) return ACL_RES_ALLOW;
- /* Build up the access right - indexed structures */
- if (acleval->acllist->cache == NULL) {
- ACL_CritEnter();
- if (acleval->acllist->cache == NULL) { /* Check again */
- if (ACLEvalBuildContext(errp, acleval) == ACL_RES_ERROR) {
- nserrGenerate(errp, ACLERRINTERNAL, ACLERR4110, ACL_Program,
- 1, XP_GetAdminStr(DBT_EvalTestRightsEvalBuildContextFailed));
- ACL_CritExit();
- return ACL_RES_ERROR;
- }
- }
- ACL_CritExit();
- }
- cache = (ACLListCache_t *)acleval->acllist->cache;
- *deny_response = cache->deny_response;
- *deny_type = cache->deny_type;
- /* For the list of rights requested, get back the list of relevant
- * ACEs. If we want
- * to alter the precedence of allow/deny, this would be a good
- * place to do it.
- */
- while (*rights)
- {
- rarray_p = &rights_arry[rights_cnt];
- /* Initialize the rights array entry */
- strcpy(&rarray_p->right[0], *rights);
- makelower(&rarray_p->right[0]);
- rarray_p->result = default_result;
- rarray_p->absolute = 0;
- rarray_p->count = 1; // There's always the specific right
- /* Locate the list of ACEs that apply to the right */
- rarray_p->acelist[0] =
- (ACLAceNumEntry_t *)ACL_HashTableLookup_const(cache->Table, rarray_p->right);
- /* See if the requested right also maps back to a generic right and
- * if so, locate the acelist for it as well.
- */
- if (map_generic)
- {
- for (g_rights=map_generic, g_num=0; *g_rights; g_rights++, g_num++)
- {
- if (strstr(*g_rights, rarray_p->right)) {
- // Add it to our acelist, but skip 0 'cause that's the
- // specific right.
- rarray_p->acelist[rarray_p->count++] =
- (ACLAceNumEntry_t *)ACL_HashTableLookup_const(cache->Table,
- (char *)generic_rights[g_num]);
- PR_ASSERT (rarray_p->count < ACL_MAX_GENERIC);
- }
- }
- }
- rights_cnt++;
- rights++;
- PR_ASSERT (rights_cnt < ACL_MAX_TEST_RIGHTS);
- }
- /* Special case - look for an entry that applies to "all" rights */
- alllist = (ACLAceNumEntry_t *)ACL_HashTableLookup_const(cache->Table, "all");
- /* Ok, we've now got a list of relevant ACEs. Now evaluate things. */
- prev_acenum = -1;
- cur_ace = cache->acelist;
- /* Loop through the relevant ACEs for the requested rights */
- while (TRUE)
- {
- cur_acenum = 10000; /* Pick a really high num so we lose */
- /* Find the lowest ACE among the rights lists */
- for (i=0; i<rights_cnt; i++) {
- rarray_p = &rights_arry[i];
- if (rarray_p->absolute) continue; // This right doesn't matter
- for (j=0; j<rarray_p->count; j++) {
- if ((rarray_p->acelist[j] != NULL) &&
- (rarray_p->acelist[j]->acenum < cur_acenum)) {
- cur_acenum = rarray_p->acelist[j]->acenum;
- }
- }
- }
- /* Special case - look for the "all" rights ace list and see if its
- * the lowest of all.
- */
- if (alllist && (alllist->acenum < cur_acenum))
- cur_acenum = alllist->acenum;
- /* If no new ACEs then we're done - evaluate the rights list */
- if (cur_acenum == 10000)
- break;
- /* Locate that ACE and evaluate it. We have to step through the
- * linked list of ACEs to find it.
- */
- if (prev_acenum == -1)
- delta = cur_acenum;
- else
- delta = cur_acenum - prev_acenum;
- for (i=0; i<delta; i++)
- cur_ace = cur_ace->next;
- if (global_auth && global_auth != cur_ace->global_auth) {
- /* We must enumerate the auth_info plist and remove entries for
- * each attribute from the subject property list.
- */
- PListEnumerate(cur_ace->global_auth, ACL_InvalidateSubjectPList,
- acleval->subject);
- }
- global_auth = cur_ace->global_auth;
- result = ACLEvalAce(errp, acleval, cur_ace->acep, &ace_cachable,
- cur_ace->autharray, cur_ace->global_auth);
- /* Evaluate the cachable value */
- if (ace_cachable < *cachable) {
- /* Take the minimum value */
- *cachable = ace_cachable;
- }
- /* Under certain circumstances, no matter what happens later,
- * the current result is not gonna change.
- */
- if ((result != LAS_EVAL_TRUE) && (result != LAS_EVAL_FALSE)) {
- if (cur_ace->acep->expr_type != ACL_EXPR_TYPE_ALLOW) {
- if (allow_error) {
- *acl_tag = allow_tag;
- *expr_num = allow_num;
- return (allow_error);
- } else {
- *acl_tag = cur_ace->acep->acl_tag;
- *expr_num = cur_ace->acep->expr_number;
- return (EvalToRes(result));
- }
- } else {
- /* If the error is on an allow statement, continue processing
- * and see if a subsequent allow works. If not, remember the
- * error and return it.
- */
- if (!allow_error) {
- allow_error = EvalToRes(result);
- allow_tag = cur_ace->acep->acl_tag;
- allow_num = cur_ace->acep->expr_number;
- }
- if (IS_ABSOLUTE(cur_ace->acep->expr_flags)) {
- allow_absolute = 1;
- }
- }
- }
- /* Now apply the result to the rights array. Look to see which rights'
- * acelist include the current one, or if the current one is on the
- * "all" rights ace list.
- */
- for (right_num=0; right_num<rights_cnt; right_num++)
- {
- rarray_p = &rights_arry[right_num];
- /* Have we fixated on a prior result? */
- if (rarray_p->absolute)
- continue;
- skipflag = 1;
- // Did this ace apply to this right?
- for (i=0; i<rarray_p->count; i++) {
- if ((rarray_p->acelist[i]) &&
- (rarray_p->acelist[i]->acenum == cur_acenum)) {
- rarray_p->acelist[i] = rarray_p->acelist[i]->next;
- skipflag = 0;
- }
- }
- /* This ace was on the "all" rights queue */
- if ((alllist) && (alllist->acenum == cur_acenum)) {
- skipflag = 0;
- }
- if (skipflag)
- continue; /* doesn't apply to this right */
- if (IS_ABSOLUTE(cur_ace->acep->expr_flags) && (result ==
- LAS_EVAL_TRUE)) {
- rarray_p->absolute = 1;
- absolute = 1;
- } else
- absolute = 0;
- switch (cur_ace->acep->expr_type) {
- case ACL_EXPR_TYPE_ALLOW:
- if (result == LAS_EVAL_TRUE) {
- rarray_p->result = ACL_RES_ALLOW;
- if (!allow_absolute) {
- /* A previous ALLOW error was superceded */
- allow_error = 0;
- }
- }
- else if (!*acl_tag) {
- *acl_tag = cur_ace->acep->acl_tag;
- *expr_num = cur_ace->acep->expr_number;
- }
- break;
- case ACL_EXPR_TYPE_DENY:
- if (result == LAS_EVAL_TRUE) {
- *acl_tag = cur_ace->acep->acl_tag;
- *expr_num = cur_ace->acep->expr_number;
- if (absolute) {
- if (allow_error) {
- *acl_tag = allow_tag;
- *expr_num = allow_num;
- return (allow_error);
- }
- return (ACL_RES_DENY);
- }
- rarray_p->result = ACL_RES_DENY;
- }
- break;
- default:
- /* a non-authorization ACE, just ignore */
- break;
- }
- }
- /* This ace was on the "all" rights queue */
- if ((alllist) && (alllist->acenum == cur_acenum)) {
- alllist = alllist->next;
- }
- /* If this is an absolute, check to see if all the rights
- * have already been fixed by this or previous absolute
- * statements. If so, we can compute the response without
- * evaluating any more of the ACL list.
- */
- if (absolute) {
- for (i=0; i<rights_cnt; i++) {
- /* Non absolute right, so skip this section */
- if (rights_arry[i].absolute == 0)
- break;
- /* This shouldn't be possible, but check anyway.
- * Any absolute non-allow result should already
- * have been returned earlier.
- */
- if (rights_arry[i].result != ACL_RES_ALLOW) {
- char result_str[16];
- sprintf(result_str, "%d", rights_arry[i].result);
- nserrGenerate(errp, ACLERRINTERNAL, ACLERR4100, ACL_Program, 3, XP_GetAdminStr(DBT_EvalTestRightsInterimAbsoluteNonAllowValue), rights[i], result_str);
- break;
- }
- if (i == (rights_cnt - 1))
- return ACL_RES_ALLOW;
- }
- }
- prev_acenum = cur_acenum;
- } /* Next ACE */
- /* Do an AND on the results for the individual rights */
- for (right_num=0; right_num<rights_cnt; right_num++)
- if (rights_arry[right_num].result != ACL_RES_ALLOW) {
- if (allow_error) {
- *acl_tag = allow_tag;
- *expr_num = allow_num;
- return (allow_error);
- }
- return (rights_arry[right_num].result);
- }
- return (ACL_RES_ALLOW);
- }
- /* ACL_CachableAclList
- * Returns 1 if the ACL list will always evaluate to ALLOW for http_get.
- */
- NSAPI_PUBLIC int
- ACL_CachableAclList(ACLListHandle_t *acllist)
- {
- ACLEvalHandle_t *acleval;
- char *bong;
- char *bong_type;
- char *acl_tag;
- int expr_num;
- int rv;
- static char *rights[] = { "http_get", NULL };
- ACLCachable_t cachable=ACL_INDEF_CACHABLE;
- if (!acllist || acllist == ACL_LIST_NO_ACLS) {
- return 1;
- }
- acleval = ACL_EvalNew(NULL, NULL);
- ACL_EvalSetACL(NULL, acleval, acllist);
- rv = ACL_INTEvalTestRights(NULL, acleval, rights, http_generic,
- &bong_type, &bong, &acl_tag, &expr_num,
- &cachable);
- ACL_EvalDestroyNoDecrement(NULL, NULL, acleval);
- if (rv == ACL_RES_ALLOW && cachable == ACL_INDEF_CACHABLE) {
- return 1;
- }
- return 0;
- }
-
- NSAPI_PUBLIC int
- ACL_EvalTestRights(
- NSErr_t *errp,
- ACLEvalHandle_t *acleval,
- char **rights,
- char **map_generic,
- char **deny_type,
- char **deny_response,
- char **acl_tag,
- int *expr_num)
- {
- ACLCachable_t cachable;
- return (ACL_INTEvalTestRights(errp, acleval, rights, map_generic,
- deny_type, deny_response,
- acl_tag, expr_num, &cachable));
- }
- NSAPI_PUBLIC ACLEvalHandle_t *
- ACL_EvalNew(NSErr_t *errp, pool_handle_t *pool)
- {
- ACLEvalHandle_t *rv = ((ACLEvalHandle_t *)pool_calloc(pool, sizeof(ACLEvalHandle_t), 1));
- rv->default_result = ACL_RES_DENY;
- return rv;
- }
- NSAPI_PUBLIC void
- ACL_EvalDestroy(NSErr_t *errp, pool_handle_t *pool, ACLEvalHandle_t *acleval)
- {
- if (!acleval->acllist || acleval->acllist == ACL_LIST_NO_ACLS)
- return;
- PR_ASSERT(acleval->acllist->ref_count > 0);
- ACL_CritEnter();
- PR_ASSERT(ACL_CritHeld());
- if (--acleval->acllist->ref_count == 0) {
- if (ACL_LIST_IS_STALE(acleval->acllist)) {
- ACL_ListDestroy(errp, acleval->acllist);
- }
- }
- ACL_CritExit();
- pool_free(pool, acleval);
- }
- NSAPI_PUBLIC void
- ACL_EvalDestroyNoDecrement(NSErr_t *errp, pool_handle_t *pool, ACLEvalHandle_t *acleval)
- {
- /*if (!acleval->acllist || acleval->acllist == ACL_LIST_NO_ACLS)
- return; */
- /* olga: we need to free acleval unconditionally to avoid memory leaks */
- if (acleval)
- pool_free(pool, acleval);
- }
- NSAPI_PUBLIC int
- ACL_ListDecrement(NSErr_t *errp, ACLListHandle_t *acllist)
- {
- if (!acllist || acllist == ACL_LIST_NO_ACLS)
- return 0;
- PR_ASSERT(ACL_AssertAcllist(acllist));
- ACL_CritEnter();
- PR_ASSERT(ACL_CritHeld());
- if (--acllist->ref_count == 0) {
- if (ACL_LIST_IS_STALE(acllist)) {
- ACL_ListDestroy(errp, acllist);
- }
- }
- ACL_CritExit();
- return 0;
- }
- NSAPI_PUBLIC int
- ACL_EvalSetACL(NSErr_t *errp, ACLEvalHandle_t *acleval, ACLListHandle_t *acllist)
- {
- PR_ASSERT(ACL_AssertAcllist(acllist));
- acleval->acllist = acllist;
- return(0);
- }
- NSAPI_PUBLIC int
- ACL_EvalSetSubject(NSErr_t *errp, ACLEvalHandle_t *acleval, PList_t subject)
- {
- acleval->subject = subject;
- return 0;
- }
- NSAPI_PUBLIC PList_t
- ACL_EvalGetSubject(NSErr_t *errp, ACLEvalHandle_t *acleval)
- {
- return (acleval->subject);
- }
- NSAPI_PUBLIC int
- ACL_EvalSetResource(NSErr_t *errp, ACLEvalHandle_t *acleval, PList_t resource)
- {
- acleval->resource = resource;
- return 0;
- }
- NSAPI_PUBLIC PList_t
- ACL_EvalGetResource(NSErr_t *errp, ACLEvalHandle_t *acleval)
- {
- return (acleval->resource);
- }
|