oneeval.cpp 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051
  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. /*
  7. * Description (acleval.c)
  8. *
  9. * This module provides functions for evaluating Access Control List
  10. * (ACL) structures in memory.
  11. *
  12. */
  13. #include <string.h>
  14. #include <sys/types.h>
  15. #include <assert.h>
  16. #include <netsite.h>
  17. #include <base/systems.h>
  18. #include <base/crit.h>
  19. #include <libaccess/nserror.h>
  20. #include <libaccess/acl.h>
  21. #include "aclpriv.h"
  22. #include <libaccess/aclproto.h>
  23. #include <libaccess/las.h>
  24. #include <libaccess/symbols.h>
  25. #include <libaccess/aclerror.h>
  26. #include <libaccess/aclglobal.h>
  27. #include <libaccess/dbtlibaccess.h>
  28. #include <libaccess/aclerror.h>
  29. #include "access_plhash.h"
  30. #include "aclutil.h"
  31. #include "aclcache.h"
  32. #include "oneeval.h"
  33. #include "permhash.h"
  34. static ACLDispatchVector_t __nsacl_vector = {
  35. /* Error frame stack support */
  36. nserrDispose,
  37. nserrFAlloc,
  38. nserrFFree,
  39. nserrGenerate,
  40. /* Property list support */
  41. PListAssignValue,
  42. PListCreate,
  43. PListDefProp,
  44. PListDeleteProp,
  45. PListFindValue,
  46. PListInitProp,
  47. PListNew,
  48. PListDestroy,
  49. PListGetValue,
  50. PListNameProp,
  51. PListSetType,
  52. PListSetValue,
  53. PListEnumerate,
  54. PListDuplicate,
  55. PListGetPool,
  56. /* ACL attribute handling */
  57. ACL_LasRegister,
  58. /* method/dbtype registration routines */
  59. ACL_MethodRegister,
  60. ACL_MethodIsEqual,
  61. ACL_MethodNameIsEqual,
  62. ACL_MethodFind,
  63. ACL_MethodGetDefault,
  64. ACL_MethodSetDefault,
  65. ACL_AuthInfoGetMethod,
  66. ACL_DbTypeRegister,
  67. ACL_DbTypeIsEqual,
  68. ACL_DbTypeNameIsEqual,
  69. ACL_DbTypeFind,
  70. ACL_DbTypeGetDefault,
  71. ACL_AuthInfoGetDbType,
  72. ACL_DbTypeIsRegistered,
  73. ACL_DbTypeParseFn,
  74. ACL_AttrGetterRegister,
  75. ACL_ModuleRegister,
  76. ACL_GetAttribute,
  77. ACL_DatabaseRegister,
  78. ACL_DatabaseFind,
  79. ACL_DatabaseSetDefault,
  80. ACL_LDAPDatabaseHandle,
  81. ACL_AuthInfoGetDbname,
  82. ACL_CacheFlushRegister,
  83. ACL_CacheFlush,
  84. /* ACL language and file interfaces */
  85. ACL_ParseFile,
  86. ACL_ParseString,
  87. ACL_WriteString,
  88. ACL_WriteFile,
  89. ACL_FileRenameAcl,
  90. ACL_FileDeleteAcl,
  91. ACL_FileGetAcl,
  92. ACL_FileSetAcl,
  93. /* ACL Expression construction interfaces */
  94. ACL_ExprNew,
  95. ACL_ExprDestroy,
  96. ACL_ExprSetPFlags,
  97. ACL_ExprClearPFlags,
  98. ACL_ExprTerm,
  99. ACL_ExprNot,
  100. ACL_ExprAnd,
  101. ACL_ExprOr,
  102. ACL_ExprAddAuthInfo,
  103. ACL_ExprAddArg,
  104. ACL_ExprSetDenyWith,
  105. ACL_ExprGetDenyWith,
  106. ACL_ExprAppend,
  107. /* ACL manipulation */
  108. ACL_AclNew,
  109. ACL_AclDestroy,
  110. /* ACL list manipulation */
  111. ACL_ListNew,
  112. ACL_ListConcat,
  113. ACL_ListAppend,
  114. ACL_ListDestroy,
  115. ACL_ListFind,
  116. ACL_ListAclDelete,
  117. ACL_ListGetNameList,
  118. ACL_NameListDestroy,
  119. /* ACL evaluation */
  120. ACL_EvalTestRights,
  121. ACL_EvalNew,
  122. ACL_EvalDestroy,
  123. ACL_EvalSetACL,
  124. ACL_EvalGetSubject,
  125. ACL_EvalSetSubject,
  126. ACL_EvalGetResource,
  127. ACL_EvalSetResource,
  128. /* Access to critical section for ACL cache */
  129. ACL_CritEnter,
  130. ACL_CritExit,
  131. /* Miscellaneous functions */
  132. ACL_AclGetTag,
  133. ACL_ListGetFirst,
  134. ACL_ListGetNext,
  135. /* Functions added after ES 3.0 release */
  136. ACL_DatabaseGetDefault,
  137. ACL_SetDefaultResult,
  138. ACL_GetDefaultResult
  139. };
  140. NSAPI_PUBLIC ACLDispatchVector_t *__nsacl_table = &__nsacl_vector;
  141. int ACLEvalAce(
  142. NSErr_t *errp,
  143. ACLEvalHandle_t *acleval,
  144. ACLExprHandle_t *ace,
  145. ACLCachable_t *cachable,
  146. PList_t autharray[],
  147. PList_t global_auth
  148. )
  149. {
  150. ACLCachable_t local_cachable;
  151. int result;
  152. ACLExprEntry_t *expr;
  153. int expr_index = 0;
  154. expr = &ace->expr_arry[0];
  155. *cachable = ACL_INDEF_CACHABLE;
  156. while (TRUE)
  157. {
  158. local_cachable = ACL_NOT_CACHABLE;
  159. /* Call the LAS driver */
  160. if (!expr->las_eval_func) {
  161. ACL_CritEnter();
  162. if (!expr->las_eval_func) { /* Must check again after locking */
  163. ACL_LasFindEval(errp, expr->attr_name, &expr->las_eval_func);
  164. if (!expr->las_eval_func) { /* Couldn't find it */
  165. ACL_CritExit();
  166. return LAS_EVAL_INVALID;
  167. }
  168. }
  169. ACL_CritExit();
  170. }
  171. result = (*expr->las_eval_func)(
  172. errp,
  173. expr->attr_name,
  174. expr->comparator,
  175. expr->attr_pattern,
  176. &local_cachable,
  177. &expr->las_cookie,
  178. acleval->subject,
  179. acleval->resource,
  180. autharray ? autharray[expr_index] : NULL,
  181. global_auth);
  182. /* Evaluate the cachable value */
  183. if (local_cachable < *cachable) {
  184. /* Take the minimum value */
  185. *cachable = local_cachable;
  186. }
  187. /* Evaluate the return code */
  188. switch (result) {
  189. case LAS_EVAL_TRUE:
  190. if (expr->true_idx < 0)
  191. return (expr->true_idx);
  192. else {
  193. expr_index = expr->true_idx;
  194. expr = &ace->expr_arry[expr->true_idx];
  195. }
  196. break;
  197. case LAS_EVAL_FALSE:
  198. if (expr->false_idx < 0)
  199. return (expr->false_idx);
  200. else {
  201. expr_index = expr->false_idx;
  202. expr = &ace->expr_arry[expr->false_idx];
  203. }
  204. break;
  205. default:
  206. return (result);
  207. }
  208. }
  209. }
  210. int
  211. ACL_EvalDestroyContext(ACLListCache_t *cache)
  212. {
  213. ACLAceEntry_t *cur_ace, *next_ace;
  214. ACLAceNumEntry_t *cur_num_p, *next_num_p;
  215. ACLExprHandle_t *acep;
  216. if (!cache)
  217. return 0;
  218. PR_HashTableDestroy(cache->Table);
  219. cache->Table = NULL;
  220. cur_ace = cache->acelist;
  221. cache->acelist = NULL;
  222. while (cur_ace) {
  223. if (cur_ace->autharray)
  224. PERM_FREE(cur_ace->autharray);
  225. if ((cur_ace->global_auth) &&
  226. (cur_ace->acep->expr_type == ACL_EXPR_TYPE_AUTH))
  227. PListDestroy(cur_ace->global_auth);
  228. next_ace = cur_ace->next;
  229. acep = cur_ace->acep; /* The ACE structure itself */
  230. PERM_FREE(cur_ace);
  231. cur_ace = next_ace;
  232. }
  233. cur_num_p = cache->chain_head;
  234. cache->chain_head = NULL;
  235. while (cur_num_p) {
  236. next_num_p = cur_num_p->chain;
  237. PERM_FREE(cur_num_p);
  238. cur_num_p = next_num_p;
  239. }
  240. PERM_FREE(cache);
  241. return 0;
  242. }
  243. /* ACLEvalBuildContext
  244. * Builds three structures:
  245. * Table - A hash table of all access rights referenced by any ACE in any
  246. * of the ACLs in this list. Each hash entry then has a list of
  247. * the relevant ACEs, in the form of indexes to the ACE linked
  248. * list.
  249. * ACE List - A linked list of all the ACEs in the proper evaluation order.
  250. *
  251. * For concurrency control, the caller must call ACL_CritEnter()
  252. */
  253. int
  254. ACLEvalBuildContext(
  255. NSErr_t *errp,
  256. ACLEvalHandle_t *acleval)
  257. {
  258. ACLHandle_t *acl;
  259. ACLExprHandle_t *ace;
  260. int ace_cnt = -1;
  261. ACLAceEntry_t *acelast, *new_ace;
  262. ACLAceNumEntry_t *entry, *temp_entry;
  263. char **argp;
  264. ACLListCache_t *cache;
  265. ACLWrapper_t *wrapper;
  266. PList_t curauthplist=NULL, absauthplist=NULL;
  267. int i, rv;
  268. ACLExprEntry_t *expr;
  269. PList_t authplist;
  270. /* Allocate the cache context and link it into the ACLListHandle */
  271. cache = (ACLListCache_t *)PERM_CALLOC(sizeof(ACLListCache_t));
  272. if (cache == NULL) {
  273. nserrGenerate(errp, ACLERRNOMEM, ACLERR4010, ACL_Program, 0);
  274. goto error;
  275. }
  276. /* Allocate the access rights hash table */
  277. cache->Table = PR_NewHashTable(0,
  278. PR_HashString,
  279. PR_CompareStrings,
  280. PR_CompareValues,
  281. &ACLPermAllocOps,
  282. NULL);
  283. if (cache->Table == NULL) {
  284. nserrGenerate(errp, ACLERRNOMEM, ACLERR4000, ACL_Program, 1,
  285. XP_GetAdminStr(DBT_EvalBuildContextUnableToCreateHash));
  286. goto error;
  287. }
  288. wrapper = acleval->acllist->acl_list_head;
  289. /* Loop through all the ACLs in the list */
  290. while (wrapper)
  291. {
  292. acl = wrapper->acl;
  293. ace = acl->expr_list_head;
  294. while (ace) /* Loop through all the ACEs in this ACL */
  295. {
  296. /* allocate a new ace list entry and link it in to the ordered
  297. * list.
  298. */
  299. new_ace = (ACLAceEntry_t *)PERM_CALLOC(sizeof(ACLAceEntry_t));
  300. if (new_ace == (ACLAceEntry_t *)NULL) {
  301. nserrGenerate(errp, ACLERRNOMEM, ACLERR4020, ACL_Program, 1,
  302. XP_GetAdminStr(DBT_EvalBuildContextUnableToAllocAceEntry));
  303. goto error;
  304. }
  305. new_ace->acep = ace;
  306. ace_cnt++;
  307. if (cache->acelist == NULL)
  308. cache->acelist = acelast = new_ace;
  309. else {
  310. acelast->next = new_ace;
  311. acelast = new_ace;
  312. new_ace->acep = ace;
  313. }
  314. new_ace->next = NULL;
  315. argp = ace->expr_argv;
  316. switch (ace->expr_type)
  317. {
  318. case ACL_EXPR_TYPE_ALLOW:
  319. case ACL_EXPR_TYPE_DENY:
  320. /* Add this ACE to the appropriate entries in the access rights
  321. * hash table
  322. */
  323. while (*argp)
  324. {
  325. entry =
  326. (ACLAceNumEntry_t *)PERM_CALLOC(sizeof(ACLAceNumEntry_t));
  327. if (entry == (ACLAceNumEntry_t *)NULL) {
  328. nserrGenerate(errp, ACLERRNOMEM, ACLERR4030, ACL_Program, 1,
  329. XP_GetAdminStr(DBT_EvalBuildContextUnableToAllocAceEntry));
  330. goto error;
  331. }
  332. if (cache->chain_head == NULL)
  333. cache->chain_head = cache->chain_tail = entry;
  334. else {
  335. cache->chain_tail->chain = entry;
  336. cache->chain_tail = entry;
  337. }
  338. entry->acenum = ace_cnt;
  339. /*
  340. * OK to call PL_HasTableLookup() even though it mods
  341. * the Table as this routine is called in critical section.
  342. */
  343. temp_entry = (ACLAceNumEntry_t *)PL_HashTableLookup(cache->Table, *argp);
  344. /* the first ACE for this right? */
  345. if (temp_entry) {
  346. /* Link it in at the end */
  347. while (temp_entry->next) {
  348. temp_entry = temp_entry->next;
  349. }
  350. temp_entry->next = entry;
  351. } else /* just link it in */
  352. PR_HashTableAdd(cache->Table, *argp, entry);
  353. argp++;
  354. }
  355. /* See if any of the clauses require authentication. */
  356. if (curauthplist) {
  357. for (i = 0; i < ace->expr_term_index; i++) {
  358. expr = &ace->expr_arry[i];
  359. rv = PListFindValue(curauthplist, expr->attr_name,
  360. NULL, &authplist);
  361. if (rv > 0) {
  362. /* First one for this ACE? */
  363. if (!new_ace->autharray) {
  364. new_ace->autharray = (PList_t *)PERM_CALLOC(sizeof(PList_t *) * ace->expr_term_index);
  365. if (!new_ace->autharray) {
  366. nserrGenerate(errp, ACLERRNOMEM, ACLERR4040, ACL_Program, 1, XP_GetAdminStr(DBT_EvalBuildContextUnableToAllocAuthPointerArray));
  367. goto error;
  368. }
  369. }
  370. new_ace->autharray[i] = authplist;
  371. }
  372. }
  373. }
  374. break;
  375. case ACL_EXPR_TYPE_AUTH:
  376. /* Allocate the running auth tables if none yet */
  377. if (!curauthplist) {
  378. curauthplist = PListNew(NULL);
  379. if (!curauthplist) {
  380. nserrGenerate(errp, ACLERRNOMEM, ACLERR4050, ACL_Program, 1, XP_GetAdminStr(DBT_EvalBuildContextUnableToAllocAuthPlist));
  381. goto error;
  382. }
  383. absauthplist = PListNew(NULL);
  384. if (!absauthplist) {
  385. nserrGenerate(errp, ACLERRNOMEM, ACLERR4050, ACL_Program, 1, XP_GetAdminStr(DBT_EvalBuildContextUnableToAllocAuthPlist));
  386. goto error;
  387. }
  388. } else { /* duplicate the existing auth table */
  389. curauthplist = PListDuplicate(curauthplist, NULL, 0);
  390. if (!curauthplist) {
  391. nserrGenerate(errp, ACLERRNOMEM, ACLERR4050, ACL_Program, 1, XP_GetAdminStr(DBT_EvalBuildContextUnableToAllocAuthPlist));
  392. goto error;
  393. }
  394. }
  395. /* For each listed attribute */
  396. while (*argp)
  397. {
  398. /* skip any attributes that were absoluted */
  399. if (PListFindValue(absauthplist, *argp, NULL, NULL) < 0)
  400. {
  401. /* Save pointer to the property list */
  402. PListInitProp(curauthplist, 0, *argp, ace->expr_auth,
  403. ace->expr_auth);
  404. if (IS_ABSOLUTE(ace->expr_flags))
  405. PListInitProp(absauthplist, 0, *argp, NULL,
  406. NULL);
  407. }
  408. argp++;
  409. }
  410. break;
  411. case ACL_EXPR_TYPE_RESPONSE:
  412. (void) ACL_ExprGetDenyWith(NULL, ace, &cache->deny_type,
  413. &cache->deny_response);
  414. break;
  415. default:
  416. PR_ASSERT(0);
  417. } /* switch expr_type */
  418. new_ace->global_auth = curauthplist;
  419. ace = ace->expr_next;
  420. }
  421. /* Next ACL please */
  422. wrapper = wrapper->wrap_next;
  423. }
  424. if (absauthplist)
  425. PListDestroy(absauthplist);
  426. /* This must be done last to avoid a race in initialization */
  427. acleval->acllist->cache = (void *)cache;
  428. return 0;
  429. error:
  430. if (absauthplist)
  431. PListDestroy(absauthplist);
  432. if (cache) {
  433. ACL_EvalDestroyContext(cache);
  434. }
  435. acleval->acllist->cache = NULL;
  436. return ACL_RES_ERROR;
  437. }
  438. /* ACL_InvalidateSubjectPList
  439. * Given a new authentication plist, enumerate the plist and for each
  440. * key in the plist, search for the matching key in the subject plist
  441. * and delete any matches. E.g. "user", "group".
  442. */
  443. void
  444. ACL_InvalidateSubjectPList(char *attr, const void *value, void *user_data)
  445. {
  446. PList_t subject = (PList_t)user_data;
  447. PListDeleteProp(subject, 0, attr);
  448. return;
  449. }
  450. NSAPI_PUBLIC int ACL_SetDefaultResult (NSErr_t *errp,
  451. ACLEvalHandle_t *acleval,
  452. int result)
  453. {
  454. int rv;
  455. switch(result) {
  456. case ACL_RES_ALLOW:
  457. case ACL_RES_DENY:
  458. case ACL_RES_FAIL:
  459. case ACL_RES_INVALID:
  460. acleval->default_result = result;
  461. rv = 0;
  462. break;
  463. default:
  464. rv = -1;
  465. }
  466. return rv;
  467. }
  468. NSAPI_PUBLIC int ACL_GetDefaultResult (ACLEvalHandle_t *acleval)
  469. {
  470. return acleval->default_result;
  471. }
  472. /* ACL_INTEvalTestRights
  473. * INPUT
  474. * *errp The usual error context stack
  475. * *acleval A list of ACLs
  476. * **rights An array of strings listing the requested rights
  477. * **map_generic An array of strings listing the specific rights
  478. * that map from the generic rights.
  479. * OUTPUT
  480. * **deny_type bong file type passed on the way back out
  481. * **deny_response bong file pathname passed on the way back out
  482. * **acl_tag Name of the ACL that denies access
  483. * *expr_num ACE number within the denying ACL
  484. * *cachable Is the result cachable?
  485. */
  486. static int
  487. ACL_INTEvalTestRights(
  488. NSErr_t *errp,
  489. ACLEvalHandle_t *acleval,
  490. char **rights,
  491. char **map_generic,
  492. char **deny_type,
  493. char **deny_response,
  494. char **acl_tag,
  495. int *expr_num,
  496. ACLCachable_t *cachable)
  497. {
  498. struct rights_ent {
  499. char right[64]; /* lowercase-ed rights string */
  500. int result; /* Interim result value */
  501. int absolute; /* ACE with absolute keyword */
  502. int count; /* # specific + generic rights */
  503. ACLAceNumEntry_t *acelist[ACL_MAX_GENERIC+1];
  504. /* List of relevant ACEs */
  505. };
  506. struct rights_ent *rarray_p;
  507. struct rights_ent rights_arry[ACL_MAX_TEST_RIGHTS];
  508. ACLAceNumEntry_t *alllist; /* List of ACEs for "all" rights */
  509. ACLAceEntry_t *cur_ace;
  510. ACLListCache_t *cache;
  511. int rights_cnt = 0;
  512. int prev_acenum, cur_acenum;
  513. int i, j, right_num, delta;
  514. ACLCachable_t ace_cachable;
  515. int result;
  516. int absolute;
  517. int skipflag;
  518. int g_num; /* index into the generic rights array. */
  519. char **g_rights;
  520. PList_t global_auth=NULL;
  521. int allow_error = 0;
  522. int allow_absolute = 0;
  523. char *allow_tag = NULL;
  524. int allow_num = 0;
  525. int default_result = ACL_GetDefaultResult(acleval);
  526. *acl_tag = NULL;
  527. *expr_num = 0;
  528. *cachable = ACL_INDEF_CACHABLE;
  529. /*
  530. * The acleval contains the list of acis we are asking about.
  531. * In our case it's always of length 1.
  532. * The acleval is a per aclpb structure but
  533. * the acllist is a global structure derived from the global
  534. * aci cache--so access to acllist is multi-threaded.
  535. * Hence, for example the use of the "read-only" hash
  536. * lookup routines in this function--ACL_EvalTestRights()
  537. * is called in a "reader only context" so this code is therefore
  538. * thread-safe.
  539. */
  540. if (acleval->acllist == ACL_LIST_NO_ACLS) return ACL_RES_ALLOW;
  541. /* Build up the access right - indexed structures */
  542. if (acleval->acllist->cache == NULL) {
  543. ACL_CritEnter();
  544. if (acleval->acllist->cache == NULL) { /* Check again */
  545. if (ACLEvalBuildContext(errp, acleval) == ACL_RES_ERROR) {
  546. nserrGenerate(errp, ACLERRINTERNAL, ACLERR4110, ACL_Program,
  547. 1, XP_GetAdminStr(DBT_EvalTestRightsEvalBuildContextFailed));
  548. ACL_CritExit();
  549. return ACL_RES_ERROR;
  550. }
  551. }
  552. ACL_CritExit();
  553. }
  554. cache = (ACLListCache_t *)acleval->acllist->cache;
  555. *deny_response = cache->deny_response;
  556. *deny_type = cache->deny_type;
  557. /* For the list of rights requested, get back the list of relevant
  558. * ACEs. If we want
  559. * to alter the precedence of allow/deny, this would be a good
  560. * place to do it.
  561. */
  562. while (*rights)
  563. {
  564. rarray_p = &rights_arry[rights_cnt];
  565. /* Initialize the rights array entry */
  566. strcpy(&rarray_p->right[0], *rights);
  567. makelower(&rarray_p->right[0]);
  568. rarray_p->result = default_result;
  569. rarray_p->absolute = 0;
  570. rarray_p->count = 1; // There's always the specific right
  571. /* Locate the list of ACEs that apply to the right */
  572. rarray_p->acelist[0] =
  573. (ACLAceNumEntry_t *)ACL_HashTableLookup_const(cache->Table, rarray_p->right);
  574. /* See if the requested right also maps back to a generic right and
  575. * if so, locate the acelist for it as well.
  576. */
  577. if (map_generic)
  578. {
  579. for (g_rights=map_generic, g_num=0; *g_rights; g_rights++, g_num++)
  580. {
  581. if (strstr(*g_rights, rarray_p->right)) {
  582. // Add it to our acelist, but skip 0 'cause that's the
  583. // specific right.
  584. rarray_p->acelist[rarray_p->count++] =
  585. (ACLAceNumEntry_t *)ACL_HashTableLookup_const(cache->Table,
  586. (char *)generic_rights[g_num]);
  587. PR_ASSERT (rarray_p->count < ACL_MAX_GENERIC);
  588. }
  589. }
  590. }
  591. rights_cnt++;
  592. rights++;
  593. PR_ASSERT (rights_cnt < ACL_MAX_TEST_RIGHTS);
  594. }
  595. /* Special case - look for an entry that applies to "all" rights */
  596. alllist = (ACLAceNumEntry_t *)ACL_HashTableLookup_const(cache->Table, "all");
  597. /* Ok, we've now got a list of relevant ACEs. Now evaluate things. */
  598. prev_acenum = -1;
  599. cur_ace = cache->acelist;
  600. /* Loop through the relevant ACEs for the requested rights */
  601. while (TRUE)
  602. {
  603. cur_acenum = 10000; /* Pick a really high num so we lose */
  604. /* Find the lowest ACE among the rights lists */
  605. for (i=0; i<rights_cnt; i++) {
  606. rarray_p = &rights_arry[i];
  607. if (rarray_p->absolute) continue; // This right doesn't matter
  608. for (j=0; j<rarray_p->count; j++) {
  609. if ((rarray_p->acelist[j] != NULL) &&
  610. (rarray_p->acelist[j]->acenum < cur_acenum)) {
  611. cur_acenum = rarray_p->acelist[j]->acenum;
  612. }
  613. }
  614. }
  615. /* Special case - look for the "all" rights ace list and see if its
  616. * the lowest of all.
  617. */
  618. if (alllist && (alllist->acenum < cur_acenum))
  619. cur_acenum = alllist->acenum;
  620. /* If no new ACEs then we're done - evaluate the rights list */
  621. if (cur_acenum == 10000)
  622. break;
  623. /* Locate that ACE and evaluate it. We have to step through the
  624. * linked list of ACEs to find it.
  625. */
  626. if (prev_acenum == -1)
  627. delta = cur_acenum;
  628. else
  629. delta = cur_acenum - prev_acenum;
  630. for (i=0; i<delta; i++)
  631. cur_ace = cur_ace->next;
  632. if (global_auth && global_auth != cur_ace->global_auth) {
  633. /* We must enumerate the auth_info plist and remove entries for
  634. * each attribute from the subject property list.
  635. */
  636. PListEnumerate(cur_ace->global_auth, ACL_InvalidateSubjectPList,
  637. acleval->subject);
  638. }
  639. global_auth = cur_ace->global_auth;
  640. result = ACLEvalAce(errp, acleval, cur_ace->acep, &ace_cachable,
  641. cur_ace->autharray, cur_ace->global_auth);
  642. /* Evaluate the cachable value */
  643. if (ace_cachable < *cachable) {
  644. /* Take the minimum value */
  645. *cachable = ace_cachable;
  646. }
  647. /* Under certain circumstances, no matter what happens later,
  648. * the current result is not gonna change.
  649. */
  650. if ((result != LAS_EVAL_TRUE) && (result != LAS_EVAL_FALSE)) {
  651. if (cur_ace->acep->expr_type != ACL_EXPR_TYPE_ALLOW) {
  652. if (allow_error) {
  653. *acl_tag = allow_tag;
  654. *expr_num = allow_num;
  655. return (allow_error);
  656. } else {
  657. *acl_tag = cur_ace->acep->acl_tag;
  658. *expr_num = cur_ace->acep->expr_number;
  659. return (EvalToRes(result));
  660. }
  661. } else {
  662. /* If the error is on an allow statement, continue processing
  663. * and see if a subsequent allow works. If not, remember the
  664. * error and return it.
  665. */
  666. if (!allow_error) {
  667. allow_error = EvalToRes(result);
  668. allow_tag = cur_ace->acep->acl_tag;
  669. allow_num = cur_ace->acep->expr_number;
  670. }
  671. if (IS_ABSOLUTE(cur_ace->acep->expr_flags)) {
  672. allow_absolute = 1;
  673. }
  674. }
  675. }
  676. /* Now apply the result to the rights array. Look to see which rights'
  677. * acelist include the current one, or if the current one is on the
  678. * "all" rights ace list.
  679. */
  680. for (right_num=0; right_num<rights_cnt; right_num++)
  681. {
  682. rarray_p = &rights_arry[right_num];
  683. /* Have we fixated on a prior result? */
  684. if (rarray_p->absolute)
  685. continue;
  686. skipflag = 1;
  687. // Did this ace apply to this right?
  688. for (i=0; i<rarray_p->count; i++) {
  689. if ((rarray_p->acelist[i]) &&
  690. (rarray_p->acelist[i]->acenum == cur_acenum)) {
  691. rarray_p->acelist[i] = rarray_p->acelist[i]->next;
  692. skipflag = 0;
  693. }
  694. }
  695. /* This ace was on the "all" rights queue */
  696. if ((alllist) && (alllist->acenum == cur_acenum)) {
  697. skipflag = 0;
  698. }
  699. if (skipflag)
  700. continue; /* doesn't apply to this right */
  701. if (IS_ABSOLUTE(cur_ace->acep->expr_flags) && (result ==
  702. LAS_EVAL_TRUE)) {
  703. rarray_p->absolute = 1;
  704. absolute = 1;
  705. } else
  706. absolute = 0;
  707. switch (cur_ace->acep->expr_type) {
  708. case ACL_EXPR_TYPE_ALLOW:
  709. if (result == LAS_EVAL_TRUE) {
  710. rarray_p->result = ACL_RES_ALLOW;
  711. if (!allow_absolute) {
  712. /* A previous ALLOW error was superceded */
  713. allow_error = 0;
  714. }
  715. }
  716. else if (!*acl_tag) {
  717. *acl_tag = cur_ace->acep->acl_tag;
  718. *expr_num = cur_ace->acep->expr_number;
  719. }
  720. break;
  721. case ACL_EXPR_TYPE_DENY:
  722. if (result == LAS_EVAL_TRUE) {
  723. *acl_tag = cur_ace->acep->acl_tag;
  724. *expr_num = cur_ace->acep->expr_number;
  725. if (absolute) {
  726. if (allow_error) {
  727. *acl_tag = allow_tag;
  728. *expr_num = allow_num;
  729. return (allow_error);
  730. }
  731. return (ACL_RES_DENY);
  732. }
  733. rarray_p->result = ACL_RES_DENY;
  734. }
  735. break;
  736. default:
  737. /* a non-authorization ACE, just ignore */
  738. break;
  739. }
  740. }
  741. /* This ace was on the "all" rights queue */
  742. if ((alllist) && (alllist->acenum == cur_acenum)) {
  743. alllist = alllist->next;
  744. }
  745. /* If this is an absolute, check to see if all the rights
  746. * have already been fixed by this or previous absolute
  747. * statements. If so, we can compute the response without
  748. * evaluating any more of the ACL list.
  749. */
  750. if (absolute) {
  751. for (i=0; i<rights_cnt; i++) {
  752. /* Non absolute right, so skip this section */
  753. if (rights_arry[i].absolute == 0)
  754. break;
  755. /* This shouldn't be possible, but check anyway.
  756. * Any absolute non-allow result should already
  757. * have been returned earlier.
  758. */
  759. if (rights_arry[i].result != ACL_RES_ALLOW) {
  760. char result_str[16];
  761. sprintf(result_str, "%d", rights_arry[i].result);
  762. nserrGenerate(errp, ACLERRINTERNAL, ACLERR4100, ACL_Program, 3, XP_GetAdminStr(DBT_EvalTestRightsInterimAbsoluteNonAllowValue), rights[i], result_str);
  763. break;
  764. }
  765. if (i == (rights_cnt - 1))
  766. return ACL_RES_ALLOW;
  767. }
  768. }
  769. prev_acenum = cur_acenum;
  770. } /* Next ACE */
  771. /* Do an AND on the results for the individual rights */
  772. for (right_num=0; right_num<rights_cnt; right_num++)
  773. if (rights_arry[right_num].result != ACL_RES_ALLOW) {
  774. if (allow_error) {
  775. *acl_tag = allow_tag;
  776. *expr_num = allow_num;
  777. return (allow_error);
  778. }
  779. return (rights_arry[right_num].result);
  780. }
  781. return (ACL_RES_ALLOW);
  782. }
  783. /* ACL_CachableAclList
  784. * Returns 1 if the ACL list will always evaluate to ALLOW for http_get.
  785. */
  786. NSAPI_PUBLIC int
  787. ACL_CachableAclList(ACLListHandle_t *acllist)
  788. {
  789. ACLEvalHandle_t *acleval;
  790. char *bong;
  791. char *bong_type;
  792. char *acl_tag;
  793. int expr_num;
  794. int rv;
  795. static char *rights[] = { "http_get", NULL };
  796. ACLCachable_t cachable=ACL_INDEF_CACHABLE;
  797. if (!acllist || acllist == ACL_LIST_NO_ACLS) {
  798. return 1;
  799. }
  800. acleval = ACL_EvalNew(NULL, NULL);
  801. ACL_EvalSetACL(NULL, acleval, acllist);
  802. rv = ACL_INTEvalTestRights(NULL, acleval, rights, http_generic,
  803. &bong_type, &bong, &acl_tag, &expr_num,
  804. &cachable);
  805. ACL_EvalDestroyNoDecrement(NULL, NULL, acleval);
  806. if (rv == ACL_RES_ALLOW && cachable == ACL_INDEF_CACHABLE) {
  807. return 1;
  808. }
  809. return 0;
  810. }
  811. NSAPI_PUBLIC int
  812. ACL_EvalTestRights(
  813. NSErr_t *errp,
  814. ACLEvalHandle_t *acleval,
  815. char **rights,
  816. char **map_generic,
  817. char **deny_type,
  818. char **deny_response,
  819. char **acl_tag,
  820. int *expr_num)
  821. {
  822. ACLCachable_t cachable;
  823. return (ACL_INTEvalTestRights(errp, acleval, rights, map_generic,
  824. deny_type, deny_response,
  825. acl_tag, expr_num, &cachable));
  826. }
  827. NSAPI_PUBLIC ACLEvalHandle_t *
  828. ACL_EvalNew(NSErr_t *errp, pool_handle_t *pool)
  829. {
  830. ACLEvalHandle_t *rv = ((ACLEvalHandle_t *)pool_calloc(pool, sizeof(ACLEvalHandle_t), 1));
  831. rv->default_result = ACL_RES_DENY;
  832. return rv;
  833. }
  834. NSAPI_PUBLIC void
  835. ACL_EvalDestroy(NSErr_t *errp, pool_handle_t *pool, ACLEvalHandle_t *acleval)
  836. {
  837. if (!acleval->acllist || acleval->acllist == ACL_LIST_NO_ACLS)
  838. return;
  839. PR_ASSERT(acleval->acllist->ref_count > 0);
  840. ACL_CritEnter();
  841. PR_ASSERT(ACL_CritHeld());
  842. if (--acleval->acllist->ref_count == 0) {
  843. if (ACL_LIST_IS_STALE(acleval->acllist)) {
  844. ACL_ListDestroy(errp, acleval->acllist);
  845. }
  846. }
  847. ACL_CritExit();
  848. pool_free(pool, acleval);
  849. }
  850. NSAPI_PUBLIC void
  851. ACL_EvalDestroyNoDecrement(NSErr_t *errp, pool_handle_t *pool, ACLEvalHandle_t *acleval)
  852. {
  853. /*if (!acleval->acllist || acleval->acllist == ACL_LIST_NO_ACLS)
  854. return; */
  855. /* olga: we need to free acleval unconditionally to avoid memory leaks */
  856. if (acleval)
  857. pool_free(pool, acleval);
  858. }
  859. NSAPI_PUBLIC int
  860. ACL_ListDecrement(NSErr_t *errp, ACLListHandle_t *acllist)
  861. {
  862. if (!acllist || acllist == ACL_LIST_NO_ACLS)
  863. return 0;
  864. PR_ASSERT(ACL_AssertAcllist(acllist));
  865. ACL_CritEnter();
  866. PR_ASSERT(ACL_CritHeld());
  867. if (--acllist->ref_count == 0) {
  868. if (ACL_LIST_IS_STALE(acllist)) {
  869. ACL_ListDestroy(errp, acllist);
  870. }
  871. }
  872. ACL_CritExit();
  873. return 0;
  874. }
  875. NSAPI_PUBLIC int
  876. ACL_EvalSetACL(NSErr_t *errp, ACLEvalHandle_t *acleval, ACLListHandle_t *acllist)
  877. {
  878. PR_ASSERT(ACL_AssertAcllist(acllist));
  879. acleval->acllist = acllist;
  880. return(0);
  881. }
  882. NSAPI_PUBLIC int
  883. ACL_EvalSetSubject(NSErr_t *errp, ACLEvalHandle_t *acleval, PList_t subject)
  884. {
  885. acleval->subject = subject;
  886. return 0;
  887. }
  888. NSAPI_PUBLIC PList_t
  889. ACL_EvalGetSubject(NSErr_t *errp, ACLEvalHandle_t *acleval)
  890. {
  891. return (acleval->subject);
  892. }
  893. NSAPI_PUBLIC int
  894. ACL_EvalSetResource(NSErr_t *errp, ACLEvalHandle_t *acleval, PList_t resource)
  895. {
  896. acleval->resource = resource;
  897. return 0;
  898. }
  899. NSAPI_PUBLIC PList_t
  900. ACL_EvalGetResource(NSErr_t *errp, ACLEvalHandle_t *acleval)
  901. {
  902. return (acleval->resource);
  903. }