| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579 |
- /** BEGIN COPYRIGHT BLOCK
- * Copyright 2001 Sun Microsystems, Inc.
- * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
- * All rights reserved.
- * END COPYRIGHT BLOCK **/
- #include <prlog.h>
- #include <base/crit.h>
- #include <base/ereport.h>
- #include <plhash.h>
- #include <libaccess/acl.h>
- #include "aclpriv.h"
- #include <libaccess/aclproto.h>
- #include <libaccess/aclglobal.h>
- #include <libaccess/usrcache.h>
- #include <libaccess/las.h>
- #include <libaccess/ldapacl.h>
- #include "aclutil.h"
- #include "permhash.h"
- #include "aclcache.h"
- static CRITICAL acl_hash_crit = NULL; /* Controls Global Hash */
- enum {
- ACL_URI_HASH,
- ACL_URI_GET_HASH
- };
- /* ACL_ListHashKeyHash
- * Given an ACL List address, computes a randomized hash value of the
- * ACL structure pointer addresses by simply adding them up. Returns
- * the resultant hash value.
- */
- static PLHashNumber
- ACL_ListHashKeyHash(const void *Iacllist)
- {
- PLHashNumber hash=0;
- ACLWrapper_t *wrap;
- ACLListHandle_t *acllist=(ACLListHandle_t *)Iacllist;
- for (wrap=acllist->acl_list_head; wrap; wrap=wrap->wrap_next) {
- hash += (PLHashNumber)(PRSize)wrap->acl;
- }
- return (hash);
- }
- /* ACL_ListHashKeyCompare
- * Given two acl lists, compares the addresses of the acl pointers within
- * them to see if theyre identical. Returns 1 if equal, 0 otherwise.
- */
- static int
- ACL_ListHashKeyCompare(const void *Iacllist1, const void *Iacllist2)
- {
- ACLWrapper_t *wrap1, *wrap2;
- ACLListHandle_t *acllist1=(ACLListHandle_t *)Iacllist1;
- ACLListHandle_t *acllist2=(ACLListHandle_t *)Iacllist2;
- if (acllist1->acl_count != acllist2->acl_count)
- return 0;
- wrap1 = acllist1->acl_list_head;
- wrap2 = acllist2->acl_list_head;
- while ((wrap1 != NULL) && (wrap2 != NULL)) {
- if (wrap1->acl != wrap2->acl)
- return 0;
- wrap1 = wrap1->wrap_next;
- wrap2 = wrap2->wrap_next;
- }
- if ((wrap1 != NULL) || (wrap2 != NULL))
- return 0;
- else
- return 1;
- }
- /* ACL_ListHashValueCompare
- * Returns 1 if equal, 0 otherwise
- */
- static int
- ACL_ListHashValueCompare(const void *acllist1, const void *acllist2)
- {
- return (acllist1 == acllist2);
- }
- void
- ACL_ListHashInit()
- {
- ACLListHash = PR_NewHashTable(200,
- ACL_ListHashKeyHash,
- ACL_ListHashKeyCompare,
- ACL_ListHashValueCompare,
- &ACLPermAllocOps,
- NULL);
- if (ACLListHash == NULL) {
- ereport(LOG_SECURITY, "Unable to allocate ACL List Hash\n");
- return;
- }
- return;
- }
- static void
- ACL_ListHashDestroy()
- {
- if (ACLListHash) {
- PR_HashTableDestroy(ACLListHash);
- ACLListHash = NULL;
- }
- return;
- }
- /* ACL_ListHashUpdate
- * Typically called with the &rq->acllist. Checks if the newly generated
- * acllist matches one that's already been created. If so, toss the new
- * list and set the pointer to the old list in its place.
- */
- void
- ACL_ListHashUpdate(ACLListHandle_t **acllistp)
- {
- NSErr_t *errp = 0;
- ACLListHandle_t *tmp_acllist;
- PR_ASSERT(ACL_AssertAcllist(*acllistp));
- tmp_acllist = (ACLListHandle_t *)PR_HashTableLookup(ACLListHash, *acllistp);
- if (tmp_acllist && tmp_acllist != *acllistp) {
- PR_ASSERT(*acllistp && *acllistp != ACL_LIST_NO_ACLS);
- ACL_ListDestroy(errp, *acllistp);
- *acllistp = tmp_acllist;
- PR_ASSERT(ACL_CritHeld());
- tmp_acllist->ref_count++; /* we're gonna use it */
- } else { /* Wasn't in the list */
- PR_HashTableAdd(ACLListHash, *acllistp, *acllistp);
- }
- PR_ASSERT(ACL_AssertAcllist(*acllistp));
- return;
- }
- /* ACL_ListCacheEnter
- * In some cases, the URI cache is useless. E.g. when virtual servers are used.
- * When that happens, the List Cache is still useful, because the cached ACL
- * List has the Eval cache in it, plus any LAS caches.
- */
- NSAPI_PUBLIC void
- ACL_ListHashEnter(ACLListHandle_t **acllistp)
- {
- NSErr_t *errp = 0;
- ACL_CritEnter();
- /* Look for a matching ACL List and use it if we find one. */
- if (*acllistp) {
- PR_ASSERT(*acllistp != ACL_LIST_NO_ACLS);
- PR_ASSERT(ACL_AssertAcllist(*acllistp));
- ACL_ListHashUpdate(acllistp);
- } else {
- *acllistp = ACL_LIST_NO_ACLS;
- }
- ACL_CritExit();
- PR_ASSERT(ACL_AssertAcllist(*acllistp));
- return;
- }
- /* ACL_ListHashCheck
- * When Virtual Servers are active, and the ACL URI cache is inactive, someone
- * with an old ACL List pointer can check to see if it's still valid. This will
- * also increment the reference count on it.
- */
- NSAPI_PUBLIC int
- ACL_ListHashCheck(ACLListHandle_t **acllistp)
- {
- ACLListHandle_t *tmp_acllist;
- if (*acllistp == ACL_LIST_NO_ACLS) return 1;
- ACL_CritEnter();
- tmp_acllist = (ACLListHandle_t *)PR_HashTableLookup(ACLListHash, *acllistp);
- if (tmp_acllist) {
- PR_ASSERT(*acllistp && *acllistp != ACL_LIST_NO_ACLS);
- *acllistp = tmp_acllist;
- PR_ASSERT(ACL_CritHeld());
- tmp_acllist->ref_count++; /* we're gonna use it */
- ACL_CritExit();
- PR_ASSERT(ACL_AssertAcllist(*acllistp));
- return 1; /* Normal path */
- } else { /* Wasn't in the list */
- ACL_CritExit();
- return 0;
- }
- }
-
- void
- ACL_UriHashDestroy(void)
- {
- if (acl_uri_hash) {
- PR_HashTableDestroy(acl_uri_hash);
- acl_uri_hash = NULL;
- }
- if (acl_uri_get_hash) {
- PR_HashTableDestroy(acl_uri_get_hash);
- acl_uri_get_hash = NULL;
- }
- pool_destroy((void **)acl_uri_hash_pool);
- acl_uri_hash_pool = NULL;
- }
- void
- ACL_Destroy(void)
- {
- ACL_ListHashDestroy();
- ACL_UriHashDestroy();
- ACL_LasHashDestroy();
- }
- /* Only used in ASSERT statements to verify that we have the lock */
- int
- ACL_CritHeld(void)
- {
- return (crit_owner_is_me(acl_hash_crit));
- }
- NSAPI_PUBLIC void
- ACL_CritEnter(void)
- {
- crit_enter(acl_hash_crit);
- }
- NSAPI_PUBLIC void
- ACL_CritExit(void)
- {
- crit_exit(acl_hash_crit);
- }
- void
- ACL_CritInit(void)
- {
- acl_hash_crit = crit_init();
- }
- void
- ACL_UriHashInit(void)
- {
- acl_uri_hash = PR_NewHashTable(200,
- PR_HashString,
- PR_CompareStrings,
- PR_CompareValues,
- &ACLPermAllocOps,
- NULL);
- acl_uri_get_hash = PR_NewHashTable(200,
- PR_HashString,
- PR_CompareStrings,
- PR_CompareValues,
- &ACLPermAllocOps,
- NULL);
- acl_uri_hash_pool = pool_create();
- }
- /* ACL_CacheCheck
- * INPUT
- * uri A URI string pointer
- * acllistp A pointer to an acllist placeholder. E.g. &rq->acllist
- * OUTPUT
- * return 1 if cached. 0 if not. The reference count on the ACL List
- * is INCREMENTED, and will be decremented when ACL_EvalDestroy or
- * ACL_ListDecrement is
- * called.
- */
- int
- ACL_INTCacheCheck(int which, char *uri, ACLListHandle_t **acllistp)
- {
- PLHashTable *hash;
- PR_ASSERT(uri && acl_uri_hash && acl_uri_get_hash);
- /* ACL cache: If the ACL List is already in the cache, there's no need
- * to go through the pathcheck directives.
- * NULL means that the URI hasn't been accessed before.
- * ACL_LIST_NO_ACLS
- * means that the URI has no ACLs.
- * Anything else is a pointer to the acllist.
- */
- ACL_CritEnter();
- /* Get the pointer to the hash table after acquiring the lock */
- if (which == ACL_URI_HASH)
- hash = acl_uri_hash;
- else
- hash = acl_uri_get_hash;
- *acllistp = (ACLListHandle_t *)PR_HashTableLookup(hash, uri);
- if (*acllistp != NULL) {
- if (*acllistp != ACL_LIST_NO_ACLS) {
- PR_ASSERT((*acllistp)->ref_count >= 0);
- PR_ASSERT(ACL_CritHeld());
- (*acllistp)->ref_count++;
- }
- ACL_CritExit();
- PR_ASSERT(ACL_AssertAcllist(*acllistp));
- return 1; /* Normal path */
- }
- ACL_CritExit();
- return 0;
- }
- int
- ACL_CacheCheckGet(char *uri, ACLListHandle_t **acllistp)
- {
- return (ACL_INTCacheCheck(ACL_URI_GET_HASH, uri, acllistp));
- }
- int
- ACL_CacheCheck(char *uri, ACLListHandle_t **acllistp)
- {
- return (ACL_INTCacheCheck(ACL_URI_HASH, uri, acllistp));
- }
-
- /* ACL_CacheEnter
- * INPUT
- * acllist or 0 if there were no ACLs that applied.
- * OUTPUT
- * The acllist address may be changed if it matches an existing one.
- */
- static void
- ACL_INTCacheEnter(int which, char *uri, ACLListHandle_t **acllistp)
- {
- ACLListHandle_t *tmpacllist;
- NSErr_t *errp = 0;
- PLHashTable *hash;
- PR_ASSERT(uri);
- ACL_CritEnter();
- /* Get the pointer to the hash table after acquiring the lock */
- if (which == ACL_URI_HASH)
- hash = acl_uri_hash;
- else
- hash = acl_uri_get_hash;
- /* Check again (now that we're in the critical section) to see if
- * someone else created an ACL List for this URI. If so, discard the
- * list that we made and replace it with the one just found.
- */
- tmpacllist = (ACLListHandle_t *)PR_HashTableLookup(hash, uri);
- if (tmpacllist != NULL) {
- if (tmpacllist != ACL_LIST_NO_ACLS) {
- PR_ASSERT(ACL_CritHeld());
- tmpacllist->ref_count++; /* we're going to use it */
- }
- ACL_CritExit();
- if (*acllistp && *acllistp != ACL_LIST_NO_ACLS) {
- ACL_ListDestroy(errp, *acllistp);
- }
- *acllistp = tmpacllist;
- PR_ASSERT(ACL_AssertAcllist(*acllistp));
- return;
- }
- /* Didn't find another list, so put ours in. */
- /* Look for a matching ACL List and use it if we find one. */
- if (*acllistp) {
- PR_ASSERT(*acllistp != ACL_LIST_NO_ACLS);
- PR_ASSERT(ACL_AssertAcllist(*acllistp));
- ACL_ListHashUpdate(acllistp);
- } else {
- *acllistp = ACL_LIST_NO_ACLS;
- }
- PR_HashTableAdd(hash, pool_strdup((void **)acl_uri_hash_pool, uri), (void *)*acllistp);
- ACL_CritExit();
- PR_ASSERT(ACL_AssertAcllist(*acllistp));
- return;
- }
- void
- ACL_CacheEnter(char *uri, ACLListHandle_t **acllistp)
- {
- ACL_INTCacheEnter(ACL_URI_HASH, uri, acllistp);
- return;
- }
- void
- ACL_CacheEnterGet(char *uri, ACLListHandle_t **acllistp)
- {
- ACL_INTCacheEnter(ACL_URI_GET_HASH, uri, acllistp);
- return;
- }
- /* ACL_AddAclName
- * Adds the ACLs for just the terminal object specified in a pathname.
- * INPUT
- * path The filesystem pathname of the terminal object.
- * acllistp The address of the list of ACLs found thus far.
- * Could be NULL. If so, a new acllist will be allocated (if any
- * acls are found). Otherwise the existing list will be added to.
- * masterlist Usually acl_root_30.
- */
- void
- ACL_AddAclName(char *path, ACLListHandle_t **acllistp, ACLListHandle_t
- *masterlist)
- {
- ACLHandle_t *acl;
- NSErr_t *errp = 0;
- #ifdef XP_WIN32
- acl = ACL_ListFind(errp, masterlist, path, ACL_CASE_INSENSITIVE);
- #else
- acl = ACL_ListFind(errp, masterlist, path, ACL_CASE_SENSITIVE);
- #endif
- if (!acl)
- return;
- PR_ASSERT(ACL_AssertAcl(acl));
- if (!*acllistp)
- *acllistp = ACL_ListNew(errp);
- ACL_ListAppend(NULL, *acllistp, acl, 0);
- PR_ASSERT(ACL_AssertAcllist(*acllistp));
- return;
- }
- /* ACL_GetPathAcls
- * Adds the ACLs for all directories plus the terminal object along a given
- * filesystem pathname. For each pathname component, look for the name, the
- * name + "/", and the name + "/*". The last one is because the resource
- * picker likes to postpend "/*" for directories.
- * INPUT
- * path The filesystem pathname of the terminal object.
- * acllistp The address of the list of ACLs found thus far.
- * Could be NULL. If so, a new acllist will be allocated (if any
- * acls are found). Otherwise the existing list will be added to.
- * prefix A string to be prepended to the path component when looking
- * for a matching ACL tag.
- */
- void
- ACL_GetPathAcls(char *path, ACLListHandle_t **acllistp, char *prefix,
- ACLListHandle_t *masterlist)
- {
- char *slashp=path;
- int slashidx;
- char ppath[ACL_PATH_MAX];
- int prefixlen;
- char *dst;
- PR_ASSERT(path);
- PR_ASSERT(prefix);
- dst = strncpy(ppath, prefix, ACL_PATH_MAX);
- if (dst >= (ppath+ACL_PATH_MAX-1)) {
- ereport(LOG_SECURITY, "Abort - the path is too long for ACL_GetPathAcls to handle\n");
- abort();
- }
- prefixlen = strlen(ppath);
- /* Handle the first "/". i.e. the root directory */
- if (*path == '/') {
- ppath[prefixlen]='/';
- ppath[prefixlen+1]='\0';
- ACL_AddAclName(ppath, acllistp, masterlist);
- strcat(ppath, "*");
- ACL_AddAclName(ppath, acllistp, masterlist);
- slashp = path;
- }
- do {
- slashp = strchr(++slashp, '/');
- if (slashp) {
- slashidx = slashp - path;
- strncpy(&ppath[prefixlen], path, slashidx);
- ppath[slashidx+prefixlen] = '\0';
- ACL_AddAclName(ppath, acllistp, masterlist);
- /* Must also handle "/a/b/" in addition to "/a/b" */
- strcat(ppath, "/");
- ACL_AddAclName(ppath, acllistp, masterlist);
- strcat(ppath, "*");
- ACL_AddAclName(ppath, acllistp, masterlist);
- continue;
- }
- strcpy(&ppath[prefixlen], path);
- ACL_AddAclName(ppath, acllistp, masterlist);
- strcat(ppath, "/");
- ACL_AddAclName(ppath, acllistp, masterlist);
- strcat(ppath, "*");
- ACL_AddAclName(ppath, acllistp, masterlist);
- break;
- } while (slashp);
- }
- static int get_is_owner_default (NSErr_t *errp, PList_t subject,
- PList_t resource, PList_t auth_info,
- PList_t global_auth, void *unused)
- {
- /* Make sure we don't generate error "all getters declined" message from
- * ACL_GetAttribute.
- */
- PListInitProp(subject, ACL_ATTR_IS_OWNER_INDEX, ACL_ATTR_IS_OWNER,
- "true", 0);
- return LAS_EVAL_TRUE;
- }
- NSAPI_PUBLIC int
- ACL_Init(void)
- {
- ACL_InitAttr2Index();
- ACLGlobal = (ACLGlobal_p)PERM_CALLOC(sizeof(ACLGlobal_s));
- oldACLGlobal = (ACLGlobal_p)PERM_CALLOC(sizeof(ACLGlobal_s));
- PR_ASSERT(ACLGlobal && oldACLGlobal);
- ACL_DATABASE_POOL = pool_create();
- ACL_METHOD_POOL = pool_create();
- ACL_CritInit();
- ACL_UriHashInit();
- ACL_ListHashInit();
- ACL_LasHashInit();
- ACL_Init2();
- init_ldb_rwlock();
- ACL_RegisterInit();
- return 0;
- }
- /* This one gets called at startup AND at cache flush time. */
- void
- ACL_Init2(void)
- {
- /* Register the ACL functions */
- ACL_LasRegister(NULL, "timeofday", LASTimeOfDayEval, LASTimeOfDayFlush);
- ACL_LasRegister(NULL, "dayofweek", LASDayOfWeekEval, LASDayOfWeekFlush);
- ACL_LasRegister(NULL, "ip", LASIpEval, LASIpFlush);
- ACL_LasRegister(NULL, "dns", LASDnsEval, LASDnsFlush);
- ACL_LasRegister(NULL, "dnsalias", LASDnsEval, LASDnsFlush);
- ACL_LasRegister(NULL, "group", LASGroupEval, (LASFlushFunc_t)NULL);
- ACL_LasRegister(NULL, "user", LASUserEval, (LASFlushFunc_t)NULL);
- #ifdef MCC_ADMSERV
- ACL_LasRegister(NULL, "program", LASProgramEval, (LASFlushFunc_t)NULL);
- #endif
- ACL_AttrGetterRegister(NULL, ACL_ATTR_USERDN,
- get_userdn_ldap,
- ACL_METHOD_ANY, ACL_DBTYPE_ANY,
- ACL_AT_END, NULL);
- return;
- }
- NSAPI_PUBLIC int
- ACL_InitPostMagnus(void)
- {
- int rv;
- rv = ACL_AttrGetterRegister(NULL, ACL_ATTR_IS_OWNER,
- get_is_owner_default,
- ACL_METHOD_ANY, ACL_DBTYPE_ANY,
- ACL_AT_END, NULL);
- return rv;
- }
- NSAPI_PUBLIC int
- ACL_LateInitPostMagnus(void)
- {
- return acl_usr_cache_init();
- }
|