aclcache.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503
  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. void
  218. ACL_Destroy(void)
  219. {
  220. ACL_ListHashDestroy();
  221. ACL_UriHashDestroy();
  222. ACL_LasHashDestroy();
  223. }
  224. /* Only used in ASSERT statements to verify that we have the lock */
  225. int
  226. ACL_CritHeld(void)
  227. {
  228. return (crit_owner_is_me(acl_hash_crit));
  229. }
  230. NSAPI_PUBLIC void
  231. ACL_CritEnter(void)
  232. {
  233. crit_enter(acl_hash_crit);
  234. }
  235. NSAPI_PUBLIC void
  236. ACL_CritExit(void)
  237. {
  238. crit_exit(acl_hash_crit);
  239. }
  240. void
  241. ACL_CritInit(void)
  242. {
  243. acl_hash_crit = crit_init();
  244. }
  245. void
  246. ACL_UriHashInit(void)
  247. {
  248. acl_uri_hash = PR_NewHashTable(200,
  249. PR_HashString,
  250. PR_CompareStrings,
  251. PR_CompareValues,
  252. &ACLPermAllocOps,
  253. NULL);
  254. acl_uri_get_hash = PR_NewHashTable(200,
  255. PR_HashString,
  256. PR_CompareStrings,
  257. PR_CompareValues,
  258. &ACLPermAllocOps,
  259. NULL);
  260. acl_uri_hash_pool = pool_create();
  261. }
  262. /* ACL_CacheCheck
  263. * INPUT
  264. * uri A URI string pointer
  265. * acllistp A pointer to an acllist placeholder. E.g. &rq->acllist
  266. * OUTPUT
  267. * return 1 if cached. 0 if not. The reference count on the ACL List
  268. * is INCREMENTED, and will be decremented when ACL_EvalDestroy or
  269. * ACL_ListDecrement is
  270. * called.
  271. */
  272. int
  273. ACL_INTCacheCheck(int which, char *uri, ACLListHandle_t **acllistp)
  274. {
  275. PLHashTable *hash;
  276. PR_ASSERT(uri && acl_uri_hash && acl_uri_get_hash);
  277. /* ACL cache: If the ACL List is already in the cache, there's no need
  278. * to go through the pathcheck directives.
  279. * NULL means that the URI hasn't been accessed before.
  280. * ACL_LIST_NO_ACLS
  281. * means that the URI has no ACLs.
  282. * Anything else is a pointer to the acllist.
  283. */
  284. ACL_CritEnter();
  285. /* Get the pointer to the hash table after acquiring the lock */
  286. if (which == ACL_URI_HASH)
  287. hash = acl_uri_hash;
  288. else
  289. hash = acl_uri_get_hash;
  290. *acllistp = (ACLListHandle_t *)PR_HashTableLookup(hash, uri);
  291. if (*acllistp != NULL) {
  292. if (*acllistp != ACL_LIST_NO_ACLS) {
  293. PR_ASSERT((*acllistp)->ref_count >= 0);
  294. PR_ASSERT(ACL_CritHeld());
  295. (*acllistp)->ref_count++;
  296. }
  297. ACL_CritExit();
  298. PR_ASSERT(ACL_AssertAcllist(*acllistp));
  299. return 1; /* Normal path */
  300. }
  301. ACL_CritExit();
  302. return 0;
  303. }
  304. int
  305. ACL_CacheCheckGet(char *uri, ACLListHandle_t **acllistp)
  306. {
  307. return (ACL_INTCacheCheck(ACL_URI_GET_HASH, uri, acllistp));
  308. }
  309. int
  310. ACL_CacheCheck(char *uri, ACLListHandle_t **acllistp)
  311. {
  312. return (ACL_INTCacheCheck(ACL_URI_HASH, uri, acllistp));
  313. }
  314. /* ACL_CacheEnter
  315. * INPUT
  316. * acllist or 0 if there were no ACLs that applied.
  317. * OUTPUT
  318. * The acllist address may be changed if it matches an existing one.
  319. */
  320. static void
  321. ACL_INTCacheEnter(int which, char *uri, ACLListHandle_t **acllistp)
  322. {
  323. ACLListHandle_t *tmpacllist;
  324. NSErr_t *errp = 0;
  325. PLHashTable *hash;
  326. PR_ASSERT(uri);
  327. ACL_CritEnter();
  328. /* Get the pointer to the hash table after acquiring the lock */
  329. if (which == ACL_URI_HASH)
  330. hash = acl_uri_hash;
  331. else
  332. hash = acl_uri_get_hash;
  333. /* Check again (now that we're in the critical section) to see if
  334. * someone else created an ACL List for this URI. If so, discard the
  335. * list that we made and replace it with the one just found.
  336. */
  337. tmpacllist = (ACLListHandle_t *)PR_HashTableLookup(hash, uri);
  338. if (tmpacllist != NULL) {
  339. if (tmpacllist != ACL_LIST_NO_ACLS) {
  340. PR_ASSERT(ACL_CritHeld());
  341. tmpacllist->ref_count++; /* we're going to use it */
  342. }
  343. ACL_CritExit();
  344. if (*acllistp && *acllistp != ACL_LIST_NO_ACLS) {
  345. ACL_ListDestroy(errp, *acllistp);
  346. }
  347. *acllistp = tmpacllist;
  348. PR_ASSERT(ACL_AssertAcllist(*acllistp));
  349. return;
  350. }
  351. /* Didn't find another list, so put ours in. */
  352. /* Look for a matching ACL List and use it if we find one. */
  353. if (*acllistp) {
  354. PR_ASSERT(*acllistp != ACL_LIST_NO_ACLS);
  355. PR_ASSERT(ACL_AssertAcllist(*acllistp));
  356. ACL_ListHashUpdate(acllistp);
  357. } else {
  358. *acllistp = ACL_LIST_NO_ACLS;
  359. }
  360. PR_HashTableAdd(hash, pool_strdup((void **)acl_uri_hash_pool, uri), (void *)*acllistp);
  361. ACL_CritExit();
  362. PR_ASSERT(ACL_AssertAcllist(*acllistp));
  363. return;
  364. }
  365. void
  366. ACL_CacheEnter(char *uri, ACLListHandle_t **acllistp)
  367. {
  368. ACL_INTCacheEnter(ACL_URI_HASH, uri, acllistp);
  369. return;
  370. }
  371. void
  372. ACL_CacheEnterGet(char *uri, ACLListHandle_t **acllistp)
  373. {
  374. ACL_INTCacheEnter(ACL_URI_GET_HASH, uri, acllistp);
  375. return;
  376. }
  377. static int get_is_owner_default (NSErr_t *errp, PList_t subject,
  378. PList_t resource, PList_t auth_info,
  379. PList_t global_auth, void *unused)
  380. {
  381. /* Make sure we don't generate error "all getters declined" message from
  382. * ACL_GetAttribute.
  383. */
  384. PListInitProp(subject, ACL_ATTR_IS_OWNER_INDEX, ACL_ATTR_IS_OWNER,
  385. "true", 0);
  386. return LAS_EVAL_TRUE;
  387. }
  388. NSAPI_PUBLIC int
  389. ACL_Init(void)
  390. {
  391. ACL_InitAttr2Index();
  392. ACLGlobal = (ACLGlobal_p)PERM_CALLOC(sizeof(ACLGlobal_s));
  393. oldACLGlobal = (ACLGlobal_p)PERM_CALLOC(sizeof(ACLGlobal_s));
  394. PR_ASSERT(ACLGlobal && oldACLGlobal);
  395. ACL_DATABASE_POOL = pool_create();
  396. ACL_METHOD_POOL = pool_create();
  397. ACL_CritInit();
  398. ACL_UriHashInit();
  399. ACL_ListHashInit();
  400. ACL_LasHashInit();
  401. ACL_Init2();
  402. return 0;
  403. }
  404. /* This one gets called at startup AND at cache flush time. */
  405. void
  406. ACL_Init2(void)
  407. {
  408. /* Register the ACL functions */
  409. ACL_LasRegister(NULL, "timeofday", LASTimeOfDayEval, LASTimeOfDayFlush);
  410. ACL_LasRegister(NULL, "dayofweek", LASDayOfWeekEval, LASDayOfWeekFlush);
  411. ACL_LasRegister(NULL, "ip", LASIpEval, LASIpFlush);
  412. ACL_LasRegister(NULL, "dns", LASDnsEval, LASDnsFlush);
  413. ACL_LasRegister(NULL, "dnsalias", LASDnsEval, LASDnsFlush);
  414. ACL_LasRegister(NULL, "group", LASGroupEval, (LASFlushFunc_t)NULL);
  415. ACL_LasRegister(NULL, "user", LASUserEval, (LASFlushFunc_t)NULL);
  416. #ifdef MCC_ADMSERV
  417. ACL_LasRegister(NULL, "program", LASProgramEval, (LASFlushFunc_t)NULL);
  418. #endif
  419. return;
  420. }
  421. NSAPI_PUBLIC int
  422. ACL_InitPostMagnus(void)
  423. {
  424. int rv;
  425. rv = ACL_AttrGetterRegister(NULL, ACL_ATTR_IS_OWNER,
  426. get_is_owner_default,
  427. ACL_METHOD_ANY, ACL_DBTYPE_ANY,
  428. ACL_AT_END, NULL);
  429. return rv;
  430. }
  431. NSAPI_PUBLIC int
  432. ACL_LateInitPostMagnus(void)
  433. {
  434. return acl_usr_cache_init();
  435. }