aclcache.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577
  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. * 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. ACL_CritEnter();
  131. /* Look for a matching ACL List and use it if we find one. */
  132. if (*acllistp) {
  133. PR_ASSERT(*acllistp != ACL_LIST_NO_ACLS);
  134. PR_ASSERT(ACL_AssertAcllist(*acllistp));
  135. ACL_ListHashUpdate(acllistp);
  136. } else {
  137. *acllistp = ACL_LIST_NO_ACLS;
  138. }
  139. ACL_CritExit();
  140. PR_ASSERT(ACL_AssertAcllist(*acllistp));
  141. return;
  142. }
  143. /* ACL_ListHashCheck
  144. * When Virtual Servers are active, and the ACL URI cache is inactive, someone
  145. * with an old ACL List pointer can check to see if it's still valid. This will
  146. * also increment the reference count on it.
  147. */
  148. NSAPI_PUBLIC int
  149. ACL_ListHashCheck(ACLListHandle_t **acllistp)
  150. {
  151. ACLListHandle_t *tmp_acllist;
  152. if (*acllistp == ACL_LIST_NO_ACLS) return 1;
  153. ACL_CritEnter();
  154. tmp_acllist = (ACLListHandle_t *)PR_HashTableLookup(ACLListHash, *acllistp);
  155. if (tmp_acllist) {
  156. PR_ASSERT(*acllistp && *acllistp != ACL_LIST_NO_ACLS);
  157. *acllistp = tmp_acllist;
  158. PR_ASSERT(ACL_CritHeld());
  159. tmp_acllist->ref_count++; /* we're gonna use it */
  160. ACL_CritExit();
  161. PR_ASSERT(ACL_AssertAcllist(*acllistp));
  162. return 1; /* Normal path */
  163. } else { /* Wasn't in the list */
  164. ACL_CritExit();
  165. return 0;
  166. }
  167. }
  168. void
  169. ACL_UriHashDestroy(void)
  170. {
  171. if (acl_uri_hash) {
  172. PR_HashTableDestroy(acl_uri_hash);
  173. acl_uri_hash = NULL;
  174. }
  175. if (acl_uri_get_hash) {
  176. PR_HashTableDestroy(acl_uri_get_hash);
  177. acl_uri_get_hash = NULL;
  178. }
  179. pool_destroy((void **)acl_uri_hash_pool);
  180. acl_uri_hash_pool = NULL;
  181. }
  182. void
  183. ACL_Destroy(void)
  184. {
  185. ACL_ListHashDestroy();
  186. ACL_UriHashDestroy();
  187. ACL_LasHashDestroy();
  188. }
  189. /* Only used in ASSERT statements to verify that we have the lock */
  190. int
  191. ACL_CritHeld(void)
  192. {
  193. return (crit_owner_is_me(acl_hash_crit));
  194. }
  195. NSAPI_PUBLIC void
  196. ACL_CritEnter(void)
  197. {
  198. crit_enter(acl_hash_crit);
  199. }
  200. NSAPI_PUBLIC void
  201. ACL_CritExit(void)
  202. {
  203. crit_exit(acl_hash_crit);
  204. }
  205. void
  206. ACL_CritInit(void)
  207. {
  208. acl_hash_crit = crit_init();
  209. }
  210. void
  211. ACL_UriHashInit(void)
  212. {
  213. acl_uri_hash = PR_NewHashTable(200,
  214. PR_HashString,
  215. PR_CompareStrings,
  216. PR_CompareValues,
  217. &ACLPermAllocOps,
  218. NULL);
  219. acl_uri_get_hash = PR_NewHashTable(200,
  220. PR_HashString,
  221. PR_CompareStrings,
  222. PR_CompareValues,
  223. &ACLPermAllocOps,
  224. NULL);
  225. acl_uri_hash_pool = pool_create();
  226. }
  227. /* ACL_CacheCheck
  228. * INPUT
  229. * uri A URI string pointer
  230. * acllistp A pointer to an acllist placeholder. E.g. &rq->acllist
  231. * OUTPUT
  232. * return 1 if cached. 0 if not. The reference count on the ACL List
  233. * is INCREMENTED, and will be decremented when ACL_EvalDestroy or
  234. * ACL_ListDecrement is
  235. * called.
  236. */
  237. int
  238. ACL_INTCacheCheck(int which, char *uri, ACLListHandle_t **acllistp)
  239. {
  240. PLHashTable *hash;
  241. PR_ASSERT(uri && acl_uri_hash && acl_uri_get_hash);
  242. /* ACL cache: If the ACL List is already in the cache, there's no need
  243. * to go through the pathcheck directives.
  244. * NULL means that the URI hasn't been accessed before.
  245. * ACL_LIST_NO_ACLS
  246. * means that the URI has no ACLs.
  247. * Anything else is a pointer to the acllist.
  248. */
  249. ACL_CritEnter();
  250. /* Get the pointer to the hash table after acquiring the lock */
  251. if (which == ACL_URI_HASH)
  252. hash = acl_uri_hash;
  253. else
  254. hash = acl_uri_get_hash;
  255. *acllistp = (ACLListHandle_t *)PR_HashTableLookup(hash, uri);
  256. if (*acllistp != NULL) {
  257. if (*acllistp != ACL_LIST_NO_ACLS) {
  258. PR_ASSERT((*acllistp)->ref_count >= 0);
  259. PR_ASSERT(ACL_CritHeld());
  260. (*acllistp)->ref_count++;
  261. }
  262. ACL_CritExit();
  263. PR_ASSERT(ACL_AssertAcllist(*acllistp));
  264. return 1; /* Normal path */
  265. }
  266. ACL_CritExit();
  267. return 0;
  268. }
  269. int
  270. ACL_CacheCheckGet(char *uri, ACLListHandle_t **acllistp)
  271. {
  272. return (ACL_INTCacheCheck(ACL_URI_GET_HASH, uri, acllistp));
  273. }
  274. int
  275. ACL_CacheCheck(char *uri, ACLListHandle_t **acllistp)
  276. {
  277. return (ACL_INTCacheCheck(ACL_URI_HASH, uri, acllistp));
  278. }
  279. /* ACL_CacheEnter
  280. * INPUT
  281. * acllist or 0 if there were no ACLs that applied.
  282. * OUTPUT
  283. * The acllist address may be changed if it matches an existing one.
  284. */
  285. static void
  286. ACL_INTCacheEnter(int which, char *uri, ACLListHandle_t **acllistp)
  287. {
  288. ACLListHandle_t *tmpacllist;
  289. NSErr_t *errp = 0;
  290. PLHashTable *hash;
  291. PR_ASSERT(uri);
  292. ACL_CritEnter();
  293. /* Get the pointer to the hash table after acquiring the lock */
  294. if (which == ACL_URI_HASH)
  295. hash = acl_uri_hash;
  296. else
  297. hash = acl_uri_get_hash;
  298. /* Check again (now that we're in the critical section) to see if
  299. * someone else created an ACL List for this URI. If so, discard the
  300. * list that we made and replace it with the one just found.
  301. */
  302. tmpacllist = (ACLListHandle_t *)PR_HashTableLookup(hash, uri);
  303. if (tmpacllist != NULL) {
  304. if (tmpacllist != ACL_LIST_NO_ACLS) {
  305. PR_ASSERT(ACL_CritHeld());
  306. tmpacllist->ref_count++; /* we're going to use it */
  307. }
  308. ACL_CritExit();
  309. if (*acllistp && *acllistp != ACL_LIST_NO_ACLS) {
  310. ACL_ListDestroy(errp, *acllistp);
  311. }
  312. *acllistp = tmpacllist;
  313. PR_ASSERT(ACL_AssertAcllist(*acllistp));
  314. return;
  315. }
  316. /* Didn't find another list, so put ours in. */
  317. /* Look for a matching ACL List and use it if we find one. */
  318. if (*acllistp) {
  319. PR_ASSERT(*acllistp != ACL_LIST_NO_ACLS);
  320. PR_ASSERT(ACL_AssertAcllist(*acllistp));
  321. ACL_ListHashUpdate(acllistp);
  322. } else {
  323. *acllistp = ACL_LIST_NO_ACLS;
  324. }
  325. PR_HashTableAdd(hash, pool_strdup((void **)acl_uri_hash_pool, uri), (void *)*acllistp);
  326. ACL_CritExit();
  327. PR_ASSERT(ACL_AssertAcllist(*acllistp));
  328. return;
  329. }
  330. void
  331. ACL_CacheEnter(char *uri, ACLListHandle_t **acllistp)
  332. {
  333. ACL_INTCacheEnter(ACL_URI_HASH, uri, acllistp);
  334. return;
  335. }
  336. void
  337. ACL_CacheEnterGet(char *uri, ACLListHandle_t **acllistp)
  338. {
  339. ACL_INTCacheEnter(ACL_URI_GET_HASH, uri, acllistp);
  340. return;
  341. }
  342. /* ACL_AddAclName
  343. * Adds the ACLs for just the terminal object specified in a pathname.
  344. * INPUT
  345. * path The filesystem pathname of the terminal object.
  346. * acllistp The address of the list of ACLs found thus far.
  347. * Could be NULL. If so, a new acllist will be allocated (if any
  348. * acls are found). Otherwise the existing list will be added to.
  349. * masterlist Usually acl_root_30.
  350. */
  351. void
  352. ACL_AddAclName(char *path, ACLListHandle_t **acllistp, ACLListHandle_t
  353. *masterlist)
  354. {
  355. ACLHandle_t *acl;
  356. NSErr_t *errp = 0;
  357. #ifdef XP_WIN32
  358. acl = ACL_ListFind(errp, masterlist, path, ACL_CASE_INSENSITIVE);
  359. #else
  360. acl = ACL_ListFind(errp, masterlist, path, ACL_CASE_SENSITIVE);
  361. #endif
  362. if (!acl)
  363. return;
  364. PR_ASSERT(ACL_AssertAcl(acl));
  365. if (!*acllistp)
  366. *acllistp = ACL_ListNew(errp);
  367. ACL_ListAppend(NULL, *acllistp, acl, 0);
  368. PR_ASSERT(ACL_AssertAcllist(*acllistp));
  369. return;
  370. }
  371. /* ACL_GetPathAcls
  372. * Adds the ACLs for all directories plus the terminal object along a given
  373. * filesystem pathname. For each pathname component, look for the name, the
  374. * name + "/", and the name + "/*". The last one is because the resource
  375. * picker likes to postpend "/*" for directories.
  376. * INPUT
  377. * path The filesystem pathname of the terminal object.
  378. * acllistp The address of the list of ACLs found thus far.
  379. * Could be NULL. If so, a new acllist will be allocated (if any
  380. * acls are found). Otherwise the existing list will be added to.
  381. * prefix A string to be prepended to the path component when looking
  382. * for a matching ACL tag.
  383. */
  384. void
  385. ACL_GetPathAcls(char *path, ACLListHandle_t **acllistp, char *prefix,
  386. ACLListHandle_t *masterlist)
  387. {
  388. char *slashp=path;
  389. int slashidx;
  390. char ppath[ACL_PATH_MAX];
  391. int prefixlen;
  392. char *dst;
  393. PR_ASSERT(path);
  394. PR_ASSERT(prefix);
  395. dst = strncpy(ppath, prefix, ACL_PATH_MAX);
  396. if (dst >= (ppath+ACL_PATH_MAX-1)) {
  397. ereport(LOG_SECURITY, "Abort - the path is too long for ACL_GetPathAcls to handle\n");
  398. abort();
  399. }
  400. prefixlen = strlen(ppath);
  401. /* Handle the first "/". i.e. the root directory */
  402. if (*path == '/') {
  403. ppath[prefixlen]='/';
  404. ppath[prefixlen+1]='\0';
  405. ACL_AddAclName(ppath, acllistp, masterlist);
  406. strcat(ppath, "*");
  407. ACL_AddAclName(ppath, acllistp, masterlist);
  408. slashp = path;
  409. }
  410. do {
  411. slashp = strchr(++slashp, '/');
  412. if (slashp) {
  413. slashidx = slashp - path;
  414. strncpy(&ppath[prefixlen], path, slashidx);
  415. ppath[slashidx+prefixlen] = '\0';
  416. ACL_AddAclName(ppath, acllistp, masterlist);
  417. /* Must also handle "/a/b/" in addition to "/a/b" */
  418. strcat(ppath, "/");
  419. ACL_AddAclName(ppath, acllistp, masterlist);
  420. strcat(ppath, "*");
  421. ACL_AddAclName(ppath, acllistp, masterlist);
  422. continue;
  423. }
  424. strcpy(&ppath[prefixlen], path);
  425. ACL_AddAclName(ppath, acllistp, masterlist);
  426. strcat(ppath, "/");
  427. ACL_AddAclName(ppath, acllistp, masterlist);
  428. strcat(ppath, "*");
  429. ACL_AddAclName(ppath, acllistp, masterlist);
  430. break;
  431. } while (slashp);
  432. }
  433. static int get_is_owner_default (NSErr_t *errp, PList_t subject,
  434. PList_t resource, PList_t auth_info,
  435. PList_t global_auth, void *unused)
  436. {
  437. /* Make sure we don't generate error "all getters declined" message from
  438. * ACL_GetAttribute.
  439. */
  440. PListInitProp(subject, ACL_ATTR_IS_OWNER_INDEX, ACL_ATTR_IS_OWNER,
  441. "true", 0);
  442. return LAS_EVAL_TRUE;
  443. }
  444. NSAPI_PUBLIC int
  445. ACL_Init(void)
  446. {
  447. ACL_InitAttr2Index();
  448. ACLGlobal = (ACLGlobal_p)PERM_CALLOC(sizeof(ACLGlobal_s));
  449. oldACLGlobal = (ACLGlobal_p)PERM_CALLOC(sizeof(ACLGlobal_s));
  450. PR_ASSERT(ACLGlobal && oldACLGlobal);
  451. ACL_DATABASE_POOL = pool_create();
  452. ACL_METHOD_POOL = pool_create();
  453. ACL_CritInit();
  454. ACL_UriHashInit();
  455. ACL_ListHashInit();
  456. ACL_LasHashInit();
  457. ACL_Init2();
  458. init_ldb_rwlock();
  459. ACL_RegisterInit();
  460. return 0;
  461. }
  462. /* This one gets called at startup AND at cache flush time. */
  463. void
  464. ACL_Init2(void)
  465. {
  466. /* Register the ACL functions */
  467. ACL_LasRegister(NULL, "timeofday", LASTimeOfDayEval, LASTimeOfDayFlush);
  468. ACL_LasRegister(NULL, "dayofweek", LASDayOfWeekEval, LASDayOfWeekFlush);
  469. ACL_LasRegister(NULL, "ip", LASIpEval, LASIpFlush);
  470. ACL_LasRegister(NULL, "dns", LASDnsEval, LASDnsFlush);
  471. ACL_LasRegister(NULL, "dnsalias", LASDnsEval, LASDnsFlush);
  472. ACL_LasRegister(NULL, "group", LASGroupEval, (LASFlushFunc_t)NULL);
  473. ACL_LasRegister(NULL, "user", LASUserEval, (LASFlushFunc_t)NULL);
  474. #ifdef MCC_ADMSERV
  475. ACL_LasRegister(NULL, "program", LASProgramEval, (LASFlushFunc_t)NULL);
  476. #endif
  477. ACL_AttrGetterRegister(NULL, ACL_ATTR_USERDN,
  478. get_userdn_ldap,
  479. ACL_METHOD_ANY, ACL_DBTYPE_ANY,
  480. ACL_AT_END, NULL);
  481. return;
  482. }
  483. NSAPI_PUBLIC int
  484. ACL_InitPostMagnus(void)
  485. {
  486. int rv;
  487. rv = ACL_AttrGetterRegister(NULL, ACL_ATTR_IS_OWNER,
  488. get_is_owner_default,
  489. ACL_METHOD_ANY, ACL_DBTYPE_ANY,
  490. ACL_AT_END, NULL);
  491. return rv;
  492. }
  493. NSAPI_PUBLIC int
  494. ACL_LateInitPostMagnus(void)
  495. {
  496. return acl_usr_cache_init();
  497. }