aclcache.cpp 14 KB

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