aclcache.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521
  1. /** BEGIN COPYRIGHT BLOCK
  2. * This Program is free software; you can redistribute it and/or modify it under
  3. * the terms of the GNU General Public License as published by the Free Software
  4. * Foundation; version 2 of the License.
  5. *
  6. * This Program is distributed in the hope that it will be useful, but WITHOUT
  7. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  8. * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  9. *
  10. * You should have received a copy of the GNU General Public License along with
  11. * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple
  12. * Place, Suite 330, Boston, MA 02111-1307 USA.
  13. *
  14. * In addition, as a special exception, Red Hat, Inc. gives You the additional
  15. * right to link the code of this Program with code not covered under the GNU
  16. * General Public License ("Non-GPL Code") and to distribute linked combinations
  17. * including the two, subject to the limitations in this paragraph. Non-GPL Code
  18. * permitted under this exception must only link to the code of this Program
  19. * through those well defined interfaces identified in the file named EXCEPTION
  20. * found in the source code files (the "Approved Interfaces"). The files of
  21. * Non-GPL Code may instantiate templates or use macros or inline functions from
  22. * the Approved Interfaces without causing the resulting work to be covered by
  23. * the GNU General Public License. Only Red Hat, Inc. may make changes or
  24. * additions to the list of Approved Interfaces. You must obey the GNU General
  25. * Public License in all respects for all of the Program code and other code used
  26. * in conjunction with the Program except the Non-GPL Code covered by this
  27. * exception. If you modify this file, you may extend this exception to your
  28. * version of the file, but you are not obligated to do so. If you do not wish to
  29. * provide this exception without modification, you must delete this exception
  30. * statement from your version and license this file solely under the GPL without
  31. * exception.
  32. *
  33. *
  34. * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
  35. * Copyright (C) 2005 Red Hat, Inc.
  36. * All rights reserved.
  37. * END COPYRIGHT BLOCK **/
  38. #ifdef HAVE_CONFIG_H
  39. # include <config.h>
  40. #endif
  41. #include <prlog.h>
  42. #include <base/crit.h>
  43. #include <base/ereport.h>
  44. #include <plhash.h>
  45. #include <libaccess/acl.h>
  46. #include "aclpriv.h"
  47. #include <libaccess/aclproto.h>
  48. #include <libaccess/aclglobal.h>
  49. #include <libaccess/usrcache.h>
  50. #include <libaccess/las.h>
  51. #include "aclutil.h"
  52. #define NO_ACL_HASH_FUNCS
  53. #include "permhash.h"
  54. #include "aclcache.h"
  55. static CRITICAL acl_hash_crit = NULL; /* Controls Global Hash */
  56. enum {
  57. ACL_URI_HASH,
  58. ACL_URI_GET_HASH
  59. };
  60. /* ACL_ListHashKeyHash
  61. * Given an ACL List address, computes a randomized hash value of the
  62. * ACL structure pointer addresses by simply adding them up. Returns
  63. * the resultant hash value.
  64. */
  65. static PLHashNumber
  66. ACL_ListHashKeyHash(const void *Iacllist)
  67. {
  68. PLHashNumber hash=0;
  69. ACLWrapper_t *wrap;
  70. ACLListHandle_t *acllist=(ACLListHandle_t *)Iacllist;
  71. for (wrap=acllist->acl_list_head; wrap; wrap=wrap->wrap_next) {
  72. hash += (PLHashNumber)(PRSize)wrap->acl;
  73. }
  74. return (hash);
  75. }
  76. /* ACL_ListHashKeyCompare
  77. * Given two acl lists, compares the addresses of the acl pointers within
  78. * them to see if theyre identical. Returns 1 if equal, 0 otherwise.
  79. */
  80. static int
  81. ACL_ListHashKeyCompare(const void *Iacllist1, const void *Iacllist2)
  82. {
  83. ACLWrapper_t *wrap1, *wrap2;
  84. ACLListHandle_t *acllist1=(ACLListHandle_t *)Iacllist1;
  85. ACLListHandle_t *acllist2=(ACLListHandle_t *)Iacllist2;
  86. if (acllist1->acl_count != acllist2->acl_count)
  87. return 0;
  88. wrap1 = acllist1->acl_list_head;
  89. wrap2 = acllist2->acl_list_head;
  90. while ((wrap1 != NULL) && (wrap2 != NULL)) {
  91. if (wrap1->acl != wrap2->acl)
  92. return 0;
  93. wrap1 = wrap1->wrap_next;
  94. wrap2 = wrap2->wrap_next;
  95. }
  96. if ((wrap1 != NULL) || (wrap2 != NULL))
  97. return 0;
  98. else
  99. return 1;
  100. }
  101. /* ACL_ListHashValueCompare
  102. * Returns 1 if equal, 0 otherwise
  103. */
  104. static int
  105. ACL_ListHashValueCompare(const void *acllist1, const void *acllist2)
  106. {
  107. return (acllist1 == acllist2);
  108. }
  109. void
  110. ACL_ListHashInit()
  111. {
  112. ACLListHash = PR_NewHashTable(200,
  113. ACL_ListHashKeyHash,
  114. ACL_ListHashKeyCompare,
  115. ACL_ListHashValueCompare,
  116. &ACLPermAllocOps,
  117. NULL);
  118. if (ACLListHash == NULL) {
  119. ereport(LOG_SECURITY, "Unable to allocate ACL List Hash\n");
  120. return;
  121. }
  122. return;
  123. }
  124. static void
  125. ACL_ListHashDestroy()
  126. {
  127. if (ACLListHash) {
  128. PR_HashTableDestroy(ACLListHash);
  129. ACLListHash = NULL;
  130. }
  131. return;
  132. }
  133. /* ACL_ListHashUpdate
  134. * Typically called with the &rq->acllist. Checks if the newly generated
  135. * acllist matches one that's already been created. If so, toss the new
  136. * list and set the pointer to the old list in its place.
  137. */
  138. void
  139. ACL_ListHashUpdate(ACLListHandle_t **acllistp)
  140. {
  141. NSErr_t *errp = 0;
  142. ACLListHandle_t *tmp_acllist;
  143. PR_ASSERT(ACL_AssertAcllist(*acllistp));
  144. tmp_acllist = (ACLListHandle_t *)PR_HashTableLookup(ACLListHash, *acllistp);
  145. if (tmp_acllist && tmp_acllist != *acllistp) {
  146. PR_ASSERT(*acllistp && *acllistp != ACL_LIST_NO_ACLS);
  147. ACL_ListDestroy(errp, *acllistp);
  148. *acllistp = tmp_acllist;
  149. PR_ASSERT(ACL_CritHeld());
  150. tmp_acllist->ref_count++; /* we're gonna use it */
  151. } else { /* Wasn't in the list */
  152. PR_HashTableAdd(ACLListHash, *acllistp, *acllistp);
  153. }
  154. PR_ASSERT(ACL_AssertAcllist(*acllistp));
  155. return;
  156. }
  157. /* ACL_ListCacheEnter
  158. * In some cases, the URI cache is useless. E.g. when virtual servers are used.
  159. * When that happens, the List Cache is still useful, because the cached ACL
  160. * List has the Eval cache in it, plus any LAS caches.
  161. */
  162. NSAPI_PUBLIC void
  163. ACL_ListHashEnter(ACLListHandle_t **acllistp)
  164. {
  165. ACL_CritEnter();
  166. /* Look for a matching ACL List and use it if we find one. */
  167. if (*acllistp) {
  168. PR_ASSERT(*acllistp != ACL_LIST_NO_ACLS);
  169. PR_ASSERT(ACL_AssertAcllist(*acllistp));
  170. ACL_ListHashUpdate(acllistp);
  171. } else {
  172. *acllistp = ACL_LIST_NO_ACLS;
  173. }
  174. ACL_CritExit();
  175. PR_ASSERT(ACL_AssertAcllist(*acllistp));
  176. return;
  177. }
  178. /* ACL_ListHashCheck
  179. * When Virtual Servers are active, and the ACL URI cache is inactive, someone
  180. * with an old ACL List pointer can check to see if it's still valid. This will
  181. * also increment the reference count on it.
  182. */
  183. NSAPI_PUBLIC int
  184. ACL_ListHashCheck(ACLListHandle_t **acllistp)
  185. {
  186. ACLListHandle_t *tmp_acllist;
  187. if (*acllistp == ACL_LIST_NO_ACLS) return 1;
  188. ACL_CritEnter();
  189. tmp_acllist = (ACLListHandle_t *)PR_HashTableLookup(ACLListHash, *acllistp);
  190. if (tmp_acllist) {
  191. PR_ASSERT(*acllistp && *acllistp != ACL_LIST_NO_ACLS);
  192. *acllistp = tmp_acllist;
  193. PR_ASSERT(ACL_CritHeld());
  194. tmp_acllist->ref_count++; /* we're gonna use it */
  195. ACL_CritExit();
  196. PR_ASSERT(ACL_AssertAcllist(*acllistp));
  197. return 1; /* Normal path */
  198. } else { /* Wasn't in the list */
  199. ACL_CritExit();
  200. return 0;
  201. }
  202. }
  203. void
  204. ACL_UriHashDestroy(void)
  205. {
  206. if (acl_uri_hash) {
  207. PR_HashTableDestroy(acl_uri_hash);
  208. acl_uri_hash = NULL;
  209. }
  210. if (acl_uri_get_hash) {
  211. PR_HashTableDestroy(acl_uri_get_hash);
  212. acl_uri_get_hash = NULL;
  213. }
  214. pool_destroy((void **)acl_uri_hash_pool);
  215. acl_uri_hash_pool = NULL;
  216. }
  217. NSAPI_PUBLIC void
  218. ACL_Destroy(void)
  219. {
  220. ACL_ListHashDestroy();
  221. ACL_UriHashDestroy();
  222. ACL_LasHashDestroy();
  223. }
  224. NSAPI_PUBLIC void
  225. ACL_DestroyPools(void)
  226. {
  227. pool_destroy(ACL_DATABASE_POOL);
  228. ACLGlobal->databasepool = NULL;
  229. pool_destroy(ACL_METHOD_POOL);
  230. ACLGlobal->methodpool = NULL;
  231. PERM_FREE(ACLGlobal);
  232. ACLGlobal = NULL;
  233. PERM_FREE(oldACLGlobal);
  234. oldACLGlobal = NULL;
  235. ACL_Attr2IndexListDestroy();
  236. if(acl_hash_crit)
  237. crit_terminate(acl_hash_crit);
  238. acl_hash_crit = NULL;
  239. pool_terminate();
  240. }
  241. /* Only used in ASSERT statements to verify that we have the lock */
  242. int
  243. ACL_CritHeld(void)
  244. {
  245. return (crit_owner_is_me(acl_hash_crit));
  246. }
  247. NSAPI_PUBLIC void
  248. ACL_CritEnter(void)
  249. {
  250. crit_enter(acl_hash_crit);
  251. }
  252. NSAPI_PUBLIC void
  253. ACL_CritExit(void)
  254. {
  255. crit_exit(acl_hash_crit);
  256. }
  257. void
  258. ACL_CritInit(void)
  259. {
  260. acl_hash_crit = crit_init();
  261. }
  262. void
  263. ACL_UriHashInit(void)
  264. {
  265. acl_uri_hash = PR_NewHashTable(200,
  266. PR_HashString,
  267. PR_CompareStrings,
  268. PR_CompareValues,
  269. &ACLPermAllocOps,
  270. NULL);
  271. acl_uri_get_hash = PR_NewHashTable(200,
  272. PR_HashString,
  273. PR_CompareStrings,
  274. PR_CompareValues,
  275. &ACLPermAllocOps,
  276. NULL);
  277. acl_uri_hash_pool = pool_create();
  278. }
  279. /* ACL_CacheCheck
  280. * INPUT
  281. * uri A URI string pointer
  282. * acllistp A pointer to an acllist placeholder. E.g. &rq->acllist
  283. * OUTPUT
  284. * return 1 if cached. 0 if not. The reference count on the ACL List
  285. * is INCREMENTED, and will be decremented when ACL_EvalDestroy or
  286. * ACL_ListDecrement is
  287. * called.
  288. */
  289. int
  290. ACL_INTCacheCheck(int which, char *uri, ACLListHandle_t **acllistp)
  291. {
  292. PLHashTable *hash;
  293. PR_ASSERT(uri && acl_uri_hash && acl_uri_get_hash);
  294. /* ACL cache: If the ACL List is already in the cache, there's no need
  295. * to go through the pathcheck directives.
  296. * NULL means that the URI hasn't been accessed before.
  297. * ACL_LIST_NO_ACLS
  298. * means that the URI has no ACLs.
  299. * Anything else is a pointer to the acllist.
  300. */
  301. ACL_CritEnter();
  302. /* Get the pointer to the hash table after acquiring the lock */
  303. if (which == ACL_URI_HASH)
  304. hash = acl_uri_hash;
  305. else
  306. hash = acl_uri_get_hash;
  307. *acllistp = (ACLListHandle_t *)PR_HashTableLookup(hash, uri);
  308. if (*acllistp != NULL) {
  309. if (*acllistp != ACL_LIST_NO_ACLS) {
  310. PR_ASSERT((*acllistp)->ref_count >= 0);
  311. PR_ASSERT(ACL_CritHeld());
  312. (*acllistp)->ref_count++;
  313. }
  314. ACL_CritExit();
  315. PR_ASSERT(ACL_AssertAcllist(*acllistp));
  316. return 1; /* Normal path */
  317. }
  318. ACL_CritExit();
  319. return 0;
  320. }
  321. int
  322. ACL_CacheCheckGet(char *uri, ACLListHandle_t **acllistp)
  323. {
  324. return (ACL_INTCacheCheck(ACL_URI_GET_HASH, uri, acllistp));
  325. }
  326. int
  327. ACL_CacheCheck(char *uri, ACLListHandle_t **acllistp)
  328. {
  329. return (ACL_INTCacheCheck(ACL_URI_HASH, uri, acllistp));
  330. }
  331. /* ACL_CacheEnter
  332. * INPUT
  333. * acllist or 0 if there were no ACLs that applied.
  334. * OUTPUT
  335. * The acllist address may be changed if it matches an existing one.
  336. */
  337. static void
  338. ACL_INTCacheEnter(int which, char *uri, ACLListHandle_t **acllistp)
  339. {
  340. ACLListHandle_t *tmpacllist;
  341. NSErr_t *errp = 0;
  342. PLHashTable *hash;
  343. PR_ASSERT(uri);
  344. ACL_CritEnter();
  345. /* Get the pointer to the hash table after acquiring the lock */
  346. if (which == ACL_URI_HASH)
  347. hash = acl_uri_hash;
  348. else
  349. hash = acl_uri_get_hash;
  350. /* Check again (now that we're in the critical section) to see if
  351. * someone else created an ACL List for this URI. If so, discard the
  352. * list that we made and replace it with the one just found.
  353. */
  354. tmpacllist = (ACLListHandle_t *)PR_HashTableLookup(hash, uri);
  355. if (tmpacllist != NULL) {
  356. if (tmpacllist != ACL_LIST_NO_ACLS) {
  357. PR_ASSERT(ACL_CritHeld());
  358. tmpacllist->ref_count++; /* we're going to use it */
  359. }
  360. ACL_CritExit();
  361. if (*acllistp && *acllistp != ACL_LIST_NO_ACLS) {
  362. ACL_ListDestroy(errp, *acllistp);
  363. }
  364. *acllistp = tmpacllist;
  365. PR_ASSERT(ACL_AssertAcllist(*acllistp));
  366. return;
  367. }
  368. /* Didn't find another list, so put ours in. */
  369. /* Look for a matching ACL List and use it if we find one. */
  370. if (*acllistp) {
  371. PR_ASSERT(*acllistp != ACL_LIST_NO_ACLS);
  372. PR_ASSERT(ACL_AssertAcllist(*acllistp));
  373. ACL_ListHashUpdate(acllistp);
  374. } else {
  375. *acllistp = ACL_LIST_NO_ACLS;
  376. }
  377. PR_HashTableAdd(hash, pool_strdup((void **)acl_uri_hash_pool, uri), (void *)*acllistp);
  378. ACL_CritExit();
  379. PR_ASSERT(ACL_AssertAcllist(*acllistp));
  380. return;
  381. }
  382. void
  383. ACL_CacheEnter(char *uri, ACLListHandle_t **acllistp)
  384. {
  385. ACL_INTCacheEnter(ACL_URI_HASH, uri, acllistp);
  386. return;
  387. }
  388. void
  389. ACL_CacheEnterGet(char *uri, ACLListHandle_t **acllistp)
  390. {
  391. ACL_INTCacheEnter(ACL_URI_GET_HASH, uri, acllistp);
  392. return;
  393. }
  394. static int get_is_owner_default (NSErr_t *errp, PList_t subject,
  395. PList_t resource, PList_t auth_info,
  396. PList_t global_auth, void *unused)
  397. {
  398. /* Make sure we don't generate error "all getters declined" message from
  399. * ACL_GetAttribute.
  400. */
  401. PListInitProp(subject, ACL_ATTR_IS_OWNER_INDEX, ACL_ATTR_IS_OWNER,
  402. "true", 0);
  403. return LAS_EVAL_TRUE;
  404. }
  405. NSAPI_PUBLIC int
  406. ACL_Init(void)
  407. {
  408. ACL_InitAttr2Index();
  409. ACLGlobal = (ACLGlobal_p)PERM_CALLOC(sizeof(ACLGlobal_s));
  410. oldACLGlobal = (ACLGlobal_p)PERM_CALLOC(sizeof(ACLGlobal_s));
  411. PR_ASSERT(ACLGlobal && oldACLGlobal);
  412. ACL_DATABASE_POOL = pool_create();
  413. ACL_METHOD_POOL = pool_create();
  414. ACL_CritInit();
  415. ACL_UriHashInit();
  416. ACL_ListHashInit();
  417. ACL_LasHashInit();
  418. ACL_Init2();
  419. return 0;
  420. }
  421. /* This one gets called at startup AND at cache flush time. */
  422. void
  423. ACL_Init2(void)
  424. {
  425. /* Register the ACL functions */
  426. ACL_LasRegister(NULL, "timeofday", LASTimeOfDayEval, LASTimeOfDayFlush);
  427. ACL_LasRegister(NULL, "dayofweek", LASDayOfWeekEval, LASDayOfWeekFlush);
  428. ACL_LasRegister(NULL, "ip", LASIpEval, LASIpFlush);
  429. ACL_LasRegister(NULL, "dns", LASDnsEval, LASDnsFlush);
  430. ACL_LasRegister(NULL, "dnsalias", LASDnsEval, LASDnsFlush);
  431. ACL_LasRegister(NULL, "group", LASGroupEval, (LASFlushFunc_t)NULL);
  432. ACL_LasRegister(NULL, "user", LASUserEval, (LASFlushFunc_t)NULL);
  433. #ifdef MCC_ADMSERV
  434. ACL_LasRegister(NULL, "program", LASProgramEval, (LASFlushFunc_t)NULL);
  435. #endif
  436. return;
  437. }
  438. NSAPI_PUBLIC int
  439. ACL_InitPostMagnus(void)
  440. {
  441. int rv;
  442. rv = ACL_AttrGetterRegister(NULL, ACL_ATTR_IS_OWNER,
  443. get_is_owner_default,
  444. ACL_METHOD_ANY, ACL_DBTYPE_ANY,
  445. ACL_AT_END, NULL);
  446. return rv;
  447. }
  448. NSAPI_PUBLIC int
  449. ACL_LateInitPostMagnus(void)
  450. {
  451. return acl_usr_cache_init();
  452. }