oneeval.cpp 33 KB

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