aclanom.c 17 KB

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