aclanom.c 15 KB

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