aclcache.cpp 15 KB

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