1
0

aclanom.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578
  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. *
  6. * License: GPL (version 3 or any later version).
  7. * See LICENSE for details.
  8. * END COPYRIGHT BLOCK **/
  9. #ifdef HAVE_CONFIG_H
  10. # include <config.h>
  11. #endif
  12. #include "acl.h"
  13. /************************************************************************
  14. Anonymous profile
  15. **************************************************************************/
  16. struct anom_targetacl {
  17. int anom_type; /* defines for anom types same as aci_type */
  18. int anom_access;
  19. Slapi_DN *anom_target; /* target of the ACL */
  20. Slapi_Filter *anom_filter; /* targetfilter part */
  21. char **anom_targetAttrs; /* list of attrs */
  22. };
  23. struct anom_profile {
  24. short anom_signature;
  25. short anom_numacls;
  26. struct anom_targetacl anom_targetinfo[ACL_ANOM_MAX_ACL];
  27. };
  28. static struct anom_profile *acl_anom_profile = NULL;
  29. static Slapi_RWLock *anom_rwlock = NULL;
  30. #define ANOM_LOCK_READ() slapi_rwlock_rdlock (anom_rwlock )
  31. #define ANOM_UNLOCK_READ() slapi_rwlock_unlock (anom_rwlock )
  32. #define ANOM_LOCK_WRITE() slapi_rwlock_wrlock (anom_rwlock )
  33. #define ANOM_UNLOCK_WRITE() slapi_rwlock_unlock (anom_rwlock )
  34. /*
  35. * aclanom_init ();
  36. * Generate a profile for the anonymous user. We can use this profile
  37. * later to determine what resources the client is allowed to.
  38. *
  39. * Dependency:
  40. * Before calling this, it is assumed that all the ACLs have been read
  41. * and parsed.
  42. *
  43. * We will go thru all the ACL and pick the ANYONE ACL and generate the anom
  44. * profile.
  45. *
  46. */
  47. int
  48. aclanom_init ()
  49. {
  50. acl_anom_profile = (struct anom_profile * )
  51. slapi_ch_calloc (1, sizeof ( struct anom_profile ) );
  52. if (( anom_rwlock = slapi_new_rwlock()) == NULL ) {
  53. slapi_log_error( SLAPI_LOG_FATAL, plugin_name,
  54. "Failed in getting the ANOM rwlock\n" );
  55. return 1;
  56. }
  57. return 0;
  58. }
  59. /*
  60. * Depending on the context, this routine may need to take the
  61. * acicache read lock.
  62. */
  63. void
  64. aclanom_gen_anomProfile (acl_lock_flag_t lock_flag)
  65. {
  66. aci_t *aci = NULL;
  67. int i;
  68. Targetattr **srcattrArray;
  69. Targetattr *attr;
  70. struct anom_profile *a_profile;
  71. PRUint32 cookie;
  72. PR_ASSERT( lock_flag == DO_TAKE_ACLCACHE_READLOCK ||
  73. lock_flag == DONT_TAKE_ACLCACHE_READLOCK);
  74. /*
  75. * This routine requires two locks:
  76. * the one for the global cache in acllist_acicache_READ_LOCK() and
  77. * the one for the anom profile.
  78. * They _must_ be taken in the order presented here or there
  79. * is a deadlock scenario with acllist_remove_aci_needsLock() which
  80. * takes them is this order.
  81. */
  82. if ( lock_flag == DO_TAKE_ACLCACHE_READLOCK ) {
  83. acllist_acicache_READ_LOCK();
  84. }
  85. ANOM_LOCK_WRITE ();
  86. a_profile = acl_anom_profile;
  87. if ( (!acl_get_aclsignature()) || ( !a_profile) ||
  88. (a_profile->anom_signature == acl_get_aclsignature()) ) {
  89. ANOM_UNLOCK_WRITE ();
  90. if ( lock_flag == DO_TAKE_ACLCACHE_READLOCK ) {
  91. acllist_acicache_READ_UNLOCK();
  92. }
  93. return;
  94. }
  95. /* D0 we have one already. If we do, then clean it up */
  96. aclanom__del_profile(0);
  97. /* We have a new signature now */
  98. a_profile->anom_signature = acl_get_aclsignature();
  99. slapi_log_error(SLAPI_LOG_ACL, plugin_name, "GENERATING ANOM USER PROFILE\n");
  100. /*
  101. ** Go thru the ACL list and find all the ACLs which apply to the
  102. ** anonymous user i.e anyone. we can generate a profile for that.
  103. ** We will llok at the simple case i.e it matches
  104. ** cases not handled:
  105. ** 1) When there is a mix if rule types ( allows & denies )
  106. **
  107. */
  108. aci = acllist_get_first_aci ( NULL, &cookie );
  109. while ( aci ) {
  110. int a_numacl;
  111. struct slapi_filter *f;
  112. char **destattrArray;
  113. /*
  114. * We must not have a rule like: deny ( all ) userdn != "xyz"
  115. * or groupdn !=
  116. */
  117. if ( (aci->aci_type & ACI_HAS_DENY_RULE) &&
  118. ( (aci->aci_type & ACI_CONTAIN_NOT_USERDN ) ||
  119. (aci->aci_type & ACI_CONTAIN_NOT_GROUPDN) ||
  120. (aci->aci_type & ACI_CONTAIN_NOT_ROLEDN)) ){
  121. slapi_log_error(SLAPI_LOG_ACL, plugin_name,
  122. "CANCELLING ANOM USER PROFILE BECAUSE OF DENY RULE\n");
  123. goto cleanup;
  124. }
  125. /* Must be a anyone rule */
  126. if ( aci->aci_elevel != ACI_ELEVEL_USERDN_ANYONE ) {
  127. aci = acllist_get_next_aci ( NULL, aci, &cookie);
  128. continue;
  129. }
  130. if (! (aci->aci_access & ( SLAPI_ACL_READ | SLAPI_ACL_SEARCH)) ) {
  131. aci = acllist_get_next_aci ( NULL, aci, &cookie);
  132. continue;
  133. }
  134. /* If the rule has anything other than userdn = "ldap:///anyone"
  135. ** let's not consider complex rules - let's make this lean.
  136. */
  137. if ( aci->aci_ruleType & ~ACI_USERDN_RULE ){
  138. slapi_log_error(SLAPI_LOG_ACL, plugin_name,
  139. "CANCELLING ANOM USER PROFILE BECAUSE OF COMPLEX RULE\n");
  140. goto cleanup;
  141. }
  142. /* Must not be a or have a
  143. ** 1 ) DENY RULE 2) targetfilter
  144. ** 3) no target pattern ( skip monitor acl )
  145. */
  146. if ( aci->aci_type & ( ACI_HAS_DENY_RULE | ACI_TARGET_PATTERN |
  147. ACI_TARGET_NOT | ACI_TARGET_FILTER_NOT )) {
  148. const char *dn = slapi_sdn_get_dn ( aci->aci_sdn );
  149. /* see if this is a monitor acl */
  150. if (( strcasecmp ( dn, "cn=monitor") == 0 ) ||
  151. /* cn=monitor,cn=ldbm: No such object */
  152. ( strcasecmp ( dn, "cn=monitor,cn=ldbm") == 0 )) {
  153. aci = acllist_get_next_aci ( NULL, aci, &cookie);
  154. continue;
  155. } else {
  156. /* clean up before leaving */
  157. slapi_log_error(SLAPI_LOG_ACL, plugin_name,
  158. "CANCELLING ANOM USER PROFILE 1\n");
  159. goto cleanup;
  160. }
  161. }
  162. /* Now we have an ALLOW ACL which applies to anyone */
  163. a_numacl = a_profile->anom_numacls++;
  164. if ( a_profile->anom_numacls == ACL_ANOM_MAX_ACL ) {
  165. slapi_log_error(SLAPI_LOG_ACL, plugin_name, "CANCELLING ANOM USER PROFILE 2\n");
  166. goto cleanup;
  167. }
  168. if ( (f = aci->target) != NULL ) {
  169. char *avaType;
  170. struct berval *avaValue;
  171. slapi_filter_get_ava ( f, &avaType, &avaValue );
  172. a_profile->anom_targetinfo[a_numacl].anom_target =
  173. slapi_sdn_new_dn_byval ( avaValue->bv_val );
  174. } else {
  175. a_profile->anom_targetinfo[a_numacl].anom_target =
  176. slapi_sdn_dup ( aci->aci_sdn );
  177. }
  178. a_profile->anom_targetinfo[a_numacl].anom_filter = NULL;
  179. if ( aci->targetFilterStr ) {
  180. a_profile->anom_targetinfo[a_numacl].anom_filter = slapi_str2filter ( aci->targetFilterStr );
  181. if (NULL == a_profile->anom_targetinfo[a_numacl].anom_filter) {
  182. const char *dn = slapi_sdn_get_dn ( aci->aci_sdn );
  183. slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
  184. "Error: invalid filter [%s] in anonymous aci in entry [%s]\n",
  185. aci->targetFilterStr, dn);
  186. goto cleanup;
  187. }
  188. }
  189. i = 0;
  190. srcattrArray = aci->targetAttr;
  191. while ( srcattrArray[i])
  192. i++;
  193. a_profile->anom_targetinfo[a_numacl].anom_targetAttrs =
  194. (char **) slapi_ch_calloc ( 1, (i+1) * sizeof(char *));
  195. srcattrArray = aci->targetAttr;
  196. destattrArray = a_profile->anom_targetinfo[a_numacl].anom_targetAttrs;
  197. i = 0;
  198. while ( srcattrArray[i] ) {
  199. attr = srcattrArray[i];
  200. if ( attr->attr_type & ACL_ATTR_FILTER ) {
  201. /* Do'nt want to support these kind now */
  202. destattrArray[i] = NULL;
  203. /* clean up before leaving */
  204. aclanom__del_profile (0);
  205. slapi_log_error(SLAPI_LOG_ACL, plugin_name,
  206. "CANCELLING ANOM USER PROFILE 3\n");
  207. goto cleanup;
  208. }
  209. destattrArray[i] = slapi_ch_strdup ( attr->u.attr_str );
  210. i++;
  211. }
  212. destattrArray[i] = NULL;
  213. aclutil_print_aci ( aci, "anom" );
  214. /* Here we are storing att the info from the acls. However
  215. ** we are only interested in a few things like ACI_TARGETATTR_NOT.
  216. */
  217. a_profile->anom_targetinfo[a_numacl].anom_type = aci->aci_type;
  218. a_profile->anom_targetinfo[a_numacl].anom_access = aci->aci_access;
  219. aci = acllist_get_next_aci ( NULL, aci, &cookie);
  220. }
  221. ANOM_UNLOCK_WRITE ();
  222. if ( lock_flag == DO_TAKE_ACLCACHE_READLOCK ) {
  223. acllist_acicache_READ_UNLOCK();
  224. }
  225. return;
  226. cleanup:
  227. aclanom__del_profile (0);
  228. ANOM_UNLOCK_WRITE ();
  229. if ( lock_flag == DO_TAKE_ACLCACHE_READLOCK ) {
  230. acllist_acicache_READ_UNLOCK();
  231. }
  232. }
  233. void
  234. aclanom_invalidateProfile ()
  235. {
  236. ANOM_LOCK_WRITE();
  237. if ( acl_anom_profile && acl_anom_profile->anom_numacls )
  238. acl_anom_profile->anom_signature = 0;
  239. ANOM_UNLOCK_WRITE();
  240. }
  241. /*
  242. * __aclanom_del_profile
  243. *
  244. * Cleanup the anonymous user's profile we have.
  245. *
  246. * ASSUMPTION: A WRITE LOCK HAS BEEN OBTAINED
  247. *
  248. */
  249. void
  250. aclanom__del_profile (int closing)
  251. {
  252. int i;
  253. struct anom_profile *a_profile;
  254. if ( (a_profile = acl_anom_profile) == NULL ) {
  255. return;
  256. }
  257. for ( i=0; i < a_profile->anom_numacls; i++ ) {
  258. int j = 0;
  259. char **destArray = a_profile->anom_targetinfo[i].anom_targetAttrs;
  260. /* Deallocate target */
  261. slapi_sdn_free ( &a_profile->anom_targetinfo[i].anom_target );
  262. /* Deallocate filter */
  263. if ( a_profile->anom_targetinfo[i].anom_filter )
  264. slapi_filter_free ( a_profile->anom_targetinfo[i].anom_filter, 1 );
  265. /* Deallocate attrs */
  266. if ( destArray ) {
  267. while ( destArray[j] ) {
  268. slapi_ch_free ( (void **) &destArray[j] );
  269. j++;
  270. }
  271. slapi_ch_free ( (void **) &destArray );
  272. }
  273. a_profile->anom_targetinfo[i].anom_targetAttrs = NULL;
  274. a_profile->anom_targetinfo[i].anom_type = 0;
  275. a_profile->anom_targetinfo[i].anom_access = 0;
  276. }
  277. a_profile->anom_numacls = 0;
  278. if(closing){
  279. slapi_destroy_rwlock(anom_rwlock);
  280. anom_rwlock = NULL;
  281. slapi_ch_free((void **)&acl_anom_profile);
  282. }
  283. /* Don't clean the signatue */
  284. }
  285. /*
  286. * This routine sets up a "context" for evaluation of access control
  287. * on a given entry for an anonymous user.
  288. * It just factors out the scope and targetfilter info into a list
  289. * of indices of the global anom profile list, that apply to this
  290. * entry, and stores them in the aclpb.
  291. * It's use relies on the way that access control is checked in the mailine search
  292. * code in the core server, namely: check filter, check entry, then check each
  293. * attribute. So, we call this in acl_access_allowed() before calling
  294. * aclanom_match_profile()--therafter, aclanom_match_profile() uses the
  295. * context to evaluate access to the entry and attributes.
  296. *
  297. * If there are no anom profiles, or the anom profiles get cancelled
  298. * due to complex anon acis, then that's OK, aclanom_match_profile()
  299. * returns -1 and the mainline acl code kicks in.
  300. *
  301. * The lifetime of this context info is the time it takes to check
  302. * access control for all parts of this entry (filter, entry, attributes).
  303. * So, if for an example an entry changes and a given anom profile entry
  304. * no longer applies, we will not notice until the next round of access
  305. * control checking on the entry--this is acceptable.
  306. *
  307. * The gain on doing this factoring in the following type of search
  308. * was approx 6%:
  309. * anon bind, 20 threads, exact match, ~20 attributes returned,
  310. * (searchrate & DirectoryMark).
  311. *
  312. */
  313. void
  314. aclanom_get_suffix_info(Slapi_Entry *e,
  315. struct acl_pblock *aclpb ) {
  316. int i;
  317. char *ndn = NULL;
  318. Slapi_DN *e_sdn;
  319. const char *aci_ndn;
  320. struct scoped_entry_anominfo *s_e_anominfo =
  321. &aclpb->aclpb_scoped_entry_anominfo;
  322. ANOM_LOCK_READ ();
  323. s_e_anominfo->anom_e_nummatched=0;
  324. ndn = slapi_entry_get_ndn ( e ) ;
  325. e_sdn= slapi_entry_get_sdn ( e ) ;
  326. for (i=acl_anom_profile->anom_numacls-1; i >= 0; i-- ) {
  327. aci_ndn = slapi_sdn_get_ndn (acl_anom_profile->anom_targetinfo[i].anom_target);
  328. if (!slapi_sdn_issuffix(e_sdn,acl_anom_profile->anom_targetinfo[i].anom_target)
  329. || (!slapi_is_rootdse(ndn) && slapi_is_rootdse(aci_ndn)))
  330. continue;
  331. if ( acl_anom_profile->anom_targetinfo[i].anom_filter ) {
  332. if ( slapi_vattr_filter_test( aclpb->aclpb_pblock, e,
  333. acl_anom_profile->anom_targetinfo[i].anom_filter,
  334. 0 /*don't do acess chk*/) != 0)
  335. continue;
  336. }
  337. s_e_anominfo->anom_e_targetInfo[s_e_anominfo->anom_e_nummatched]=i;
  338. s_e_anominfo->anom_e_nummatched++;
  339. }
  340. ANOM_UNLOCK_READ ();
  341. }
  342. /*
  343. * aclanom_match_profile
  344. * Look at the anonymous profile and see if we can use it or not.
  345. *
  346. *
  347. * Inputs:
  348. * Slapi_Pblock - The Pblock
  349. * Slapi_Entry *e - The entry for which we are asking permission.
  350. * char *attr - Attribute name
  351. * int access - access type
  352. *
  353. * Return:
  354. * LDAP_SUCCESS ( 0 ) - acess is allowed.
  355. * LDAP_INSUFFICIENT_ACCESS (50 ) - access denied.
  356. * -1 - didn't match the targets
  357. *
  358. * Assumptions:
  359. * The caller of this module has to make sure that the client is
  360. * an anonymous client.
  361. */
  362. int
  363. aclanom_match_profile (Slapi_PBlock *pb, struct acl_pblock *aclpb, Slapi_Entry *e,
  364. char *attr, int access )
  365. {
  366. struct anom_profile *a_profile;
  367. int result, i, k;
  368. char **destArray;
  369. int tmatched = 0;
  370. int loglevel;
  371. struct scoped_entry_anominfo *s_e_anominfo =
  372. &aclpb->aclpb_scoped_entry_anominfo;
  373. loglevel = slapi_is_loglevel_set(SLAPI_LOG_ACL) ? SLAPI_LOG_ACL : SLAPI_LOG_ACLSUMMARY;
  374. /* WE are only interested for READ/SEARCH */
  375. if ( !(access & ( SLAPI_ACL_SEARCH | SLAPI_ACL_READ)) )
  376. return -1;
  377. /* If we are here means, the client is doing a anonymous read/search */
  378. if ((a_profile = acl_anom_profile) == NULL ) {
  379. return -1;
  380. }
  381. ANOM_LOCK_READ ();
  382. /* Check the signature first */
  383. if ( a_profile->anom_signature != acl_get_aclsignature () ) {
  384. /* Need to regenrate the signature.
  385. * Need a WRITE lock to generate the anom profile -
  386. * which is obtained in acl__gen_anom_user_profile (). Since
  387. * I don't have upgrade lock -- I have to do this way.
  388. */
  389. ANOM_UNLOCK_READ ();
  390. aclanom_gen_anomProfile (DO_TAKE_ACLCACHE_READLOCK);
  391. aclanom_get_suffix_info(e, aclpb );
  392. ANOM_LOCK_READ ();
  393. }
  394. /* doing this early saves use a malloc/free/normalize cost */
  395. if ( !a_profile->anom_numacls ) {
  396. ANOM_UNLOCK_READ ();
  397. return -1;
  398. }
  399. result = LDAP_INSUFFICIENT_ACCESS;
  400. for ( k=0; k<s_e_anominfo->anom_e_nummatched; k++ ) {
  401. short matched = 0;
  402. short j = 0;
  403. i = s_e_anominfo->anom_e_targetInfo[k];
  404. /* Check for right */
  405. if ( !(a_profile->anom_targetinfo[i].anom_access & access) )
  406. continue;
  407. /*
  408. * XXX rbyrne Don't really understand the role of this
  409. * but not causing any obvious bugs...get back to it.
  410. */
  411. tmatched++;
  412. if ( attr == NULL ) {
  413. result = LDAP_SUCCESS;
  414. break;
  415. }
  416. destArray = a_profile->anom_targetinfo[i].anom_targetAttrs;
  417. while ( destArray[j] ) {
  418. if ( strcasecmp ( destArray[j], "*") == 0 ||
  419. slapi_attr_type_cmp ( attr, destArray[j], 1 ) == 0 ) {
  420. matched = 1;
  421. break;
  422. }
  423. j++;
  424. }
  425. if ( a_profile->anom_targetinfo[i].anom_type & ACI_TARGET_ATTR_NOT )
  426. result = matched ? LDAP_INSUFFICIENT_ACCESS : LDAP_SUCCESS;
  427. else
  428. result = matched ? LDAP_SUCCESS : LDAP_INSUFFICIENT_ACCESS;
  429. if ( result == LDAP_SUCCESS )
  430. break;
  431. } /* for */
  432. if ( slapi_is_loglevel_set(loglevel) ) {
  433. char *ndn = NULL;
  434. Slapi_Operation *op = NULL;
  435. PRUint64 o_connid = 0xffffffffffffffff; /* no op */
  436. int o_opid = -1; /* no op */
  437. ndn = slapi_entry_get_ndn ( e ) ;
  438. slapi_pblock_get(pb, SLAPI_OPERATION, &op);
  439. if (op) {
  440. o_connid = op->o_connid;
  441. o_opid = op->o_opid;
  442. }
  443. if ( result == LDAP_SUCCESS) {
  444. const char *aci_ndn;
  445. aci_ndn = slapi_sdn_get_ndn (acl_anom_profile->anom_targetinfo[i].anom_target);
  446. if (access & SLAPI_ACL_MODDN) {
  447. slapi_log_error(loglevel, plugin_name,
  448. "conn=%" NSPRIu64 " op=%d: Allow access on entry(%s).attr(%s) (from %s) to anonymous: acidn=\"%s\"\n",
  449. o_connid, o_opid,
  450. ndn,
  451. attr ? attr:"NULL",
  452. aclpb->aclpb_moddn_source_sdn ? slapi_sdn_get_dn(aclpb->aclpb_moddn_source_sdn) : "NULL",
  453. aci_ndn);
  454. } else {
  455. slapi_log_error(loglevel, plugin_name,
  456. "conn=%" NSPRIu64 " op=%d: Allow access on entry(%s).attr(%s) to anonymous: acidn=\"%s\"\n",
  457. o_connid, o_opid,
  458. ndn,
  459. attr ? attr:"NULL",
  460. aci_ndn);
  461. }
  462. } else {
  463. if (access & SLAPI_ACL_MODDN) {
  464. slapi_log_error(loglevel, plugin_name,
  465. "conn=%" NSPRIu64 " op=%d: Deny access on entry(%s).attr(%s) (from %s) to anonymous\n",
  466. o_connid, o_opid,
  467. ndn, attr ? attr:"NULL" ,
  468. aclpb->aclpb_moddn_source_sdn ? slapi_sdn_get_dn(aclpb->aclpb_moddn_source_sdn) : "NULL");
  469. } else {
  470. slapi_log_error(loglevel, plugin_name,
  471. "conn=%" NSPRIu64 " op=%d: Deny access on entry(%s).attr(%s) to anonymous\n",
  472. o_connid, o_opid,
  473. ndn, attr ? attr:"NULL" );
  474. }
  475. }
  476. }
  477. ANOM_UNLOCK_READ ();
  478. if ( tmatched == 0)
  479. return -1;
  480. else
  481. return result;
  482. }
  483. int
  484. aclanom_is_client_anonymous ( Slapi_PBlock *pb )
  485. {
  486. char *clientDn;
  487. slapi_pblock_get ( pb, SLAPI_REQUESTOR_DN, &clientDn );
  488. if (acl_anom_profile->anom_numacls &&
  489. acl_anom_profile->anom_signature &&
  490. (( NULL == clientDn) || (clientDn && *clientDn == '\0')) )
  491. return 1;
  492. return 0;
  493. }