aclcache.cpp 12 KB

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