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.
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.
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.
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
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 **/
45
/****************************************************************************
50
* This file contains the functions related to Access Control List (ACL)
51
* checking. The ACL checking is based on the ONE ACL design implemented
52
* in the Web server 2.0. For more information on the ACL design look
53
* into the barracuda home page.
56
******************************************************************************/
59
/****************************************************************************/
60
/* Globals. Must be protected by Mutex. */
61
/****************************************************************************/
62
/* Signatures to see if things have changed */
63
static short acl_signature = 0;
65
/****************************************************************************/
66
/* Defines, Constants, ande Declarations */
67
/****************************************************************************/
68
static char *ds_map_generic[2] = { NULL, NULL };
70
/****************************************************************************/
72
/****************************************************************************/
73
static int acl__resource_match_aci(struct acl_pblock *aclpb, aci_t *aci ,
74
int skip_attrEval, int *a_matched);
75
static int acl__TestRights(Acl_PBlock *aclpb,int access, char **right,
76
char ** map_generic, aclResultReason_t *result_reason);
77
static int acl__scan_for_acis(struct acl_pblock *aclpb, int *err);
78
static void acl__reset_cached_result (struct acl_pblock *aclpb );
79
static int acl__scan_match_handles ( struct acl_pblock *aclpb, int type);
80
static int acl__attr_cached_result (struct acl_pblock *aclpb, char *attr, int access );
81
static int acl__match_handlesFromCache (struct acl_pblock *aclpb, char *attr, int access);
82
static int acl__get_attrEval ( struct acl_pblock *aclpb, char *attr );
83
static int acl__recompute_acl (Acl_PBlock *aclpb, AclAttrEval *a_eval,
84
int access, int aciIndex);
85
static void __acl_set_aclIndex_inResult ( Acl_PBlock *aclpb,
86
int access, int index );
87
static int acl__make_filter_test_entry ( Slapi_Entry **entry,
88
char *attr_type, struct berval *attr_val);
89
static int acl__test_filter ( Slapi_Entry *entry, struct slapi_filter *f,
91
static void print_access_control_summary( char * source,
92
int ret_val, char *clientDn,
93
struct acl_pblock *aclpb,
97
aclResultReason_t *acl_reason);
98
static int check_rdn_access( Slapi_PBlock *pb, Slapi_Entry *e,
99
const char * newrdn, int access);
103
* Check the rdn permissions for this entry:
104
* require: write access to the entry, write (add) access to the new
105
* naming attribute, write (del) access to the old naming attribute if
108
* Valid only for the modrdn operation.
111
acl_access_allowed_modrdn(
113
Slapi_Entry *e, /* The Slapi_Entry */
114
char *attr, /* Attribute of the entry */
115
struct berval *val, /* value of attr. NOT USED */
116
int access /* requested access rights */
123
Slapi_DN *target_sdn = NULL;
124
int deleteoldrdn = 0;
127
* First check write permission on the entry--this is actually
128
* specially for modrdn.
130
retCode = acl_access_allowed ( pb, e, NULL /* attr */, NULL /* val */,
133
if ( retCode != LDAP_SUCCESS ) {
134
slapi_log_error( SLAPI_LOG_ACL, plugin_name,
135
"modrdn:write permission to entry not allowed\n");
139
/* Now get the new rdn attribute name and value */
140
slapi_pblock_get( pb, SLAPI_MODRDN_TARGET_SDN, &target_sdn );
141
slapi_pblock_get( pb, SLAPI_MODRDN_NEWRDN, &newrdn );
143
ci_newrdn = slapi_ch_strdup(newrdn);
144
slapi_dn_ignore_case(ci_newrdn);
145
/* Check can add the new naming attribute */
146
retCode = check_rdn_access( pb, e, ci_newrdn, ACLPB_SLAPI_ACL_WRITE_ADD) ;
147
slapi_ch_free_string(&ci_newrdn);
148
if ( retCode != LDAP_SUCCESS ) {
149
slapi_log_error( SLAPI_LOG_ACL, plugin_name,
150
"modrdn:write permission to add new naming attribute not allowed\n");
154
/* Check can delete the new naming attribute--if required */
155
slapi_pblock_get( pb, SLAPI_MODRDN_DELOLDRDN, &deleteoldrdn );
156
if ( deleteoldrdn ) {
157
oldrdn = slapi_sdn_get_ndn(target_sdn);
158
retCode = check_rdn_access( pb, e, oldrdn, ACLPB_SLAPI_ACL_WRITE_DEL) ;
159
if ( retCode != LDAP_SUCCESS ) {
160
slapi_log_error( SLAPI_LOG_ACL, plugin_name,
161
"modrdn:write permission to delete old naming attribute not allowed\n");
170
* Test if have access to make the first rdn of dn in entry e.
173
static int check_rdn_access( Slapi_PBlock *pb, Slapi_Entry *e, const char *dn,
178
int retCode = LDAP_INSUFFICIENT_ACCESS;
181
if ( (dns = slapi_ldap_explode_dn( dn, 0 )) != NULL ) {
183
if ( (rdns = slapi_ldap_explode_rdn( dns[0], 0 )) != NULL ) {
185
for ( i = 0; rdns[i] != NULL; i++ ) {
189
if ( slapi_rdn2typeval( rdns[i], &type, &bv ) != 0 ) {
190
slapi_log_error( SLAPI_LOG_ACL, plugin_name,
191
"modrdn: rdn2typeval (%s) failed\n", rdns[i]);
192
retCode = LDAP_INSUFFICIENT_ACCESS;
195
if ( (retCode = acl_access_allowed ( pb, e, type /* attr */,
197
access)) != LDAP_SUCCESS) {
202
slapi_ldap_value_free( rdns );
204
slapi_ldap_value_free( dns );
210
/***************************************************************************
213
* Determines if access to the resource is allowed or not.
220
* Returns success/Denied/error condition
222
* LDAP_SUCCESS -- access allowed
223
* LDAP_INSUFFICIENT_ACCESS -- access denied
227
* Some of the definition of the return values used copied from
228
* "ldap.h" for convienience.
229
* LDAP_OPERATIONS_ERROR
230
* LDAP_PROTOCOL_ERROR
231
* LDAP_UNWILLING_TO_PERFORM
235
* Returned error code.
236
**************************************************************************/
240
Slapi_Entry *e, /* The Slapi_Entry */
241
char *attr, /* Attribute of the entry */
242
struct berval *val, /* value of attr */
243
int access /* requested access rights */
246
char *n_edn; /* Normalized DN of the entry */
251
struct acl_pblock *aclpb = NULL;
252
AclAttrEval *c_attrEval = NULL;
253
int got_reader_locked = 0;
254
int deallocate_attrEval = 0;
257
Slapi_Operation *op = NULL;
258
aclResultReason_t decision_reason;
261
loglevel = slapi_is_loglevel_set(SLAPI_LOG_ACL) ? SLAPI_LOG_ACL : SLAPI_LOG_ACLSUMMARY;
262
slapi_pblock_get(pb, SLAPI_OPERATION, &op); /* for logging */
264
TNF_PROBE_1_DEBUG(acl_access_allowed_start,"ACL","",
265
tnf_int,access,access);
267
decision_reason.deciding_aci = NULL;
268
decision_reason.reason = ACL_REASON_NONE;
271
* First, if the acl private write/delete on attribute right
272
* is requested, turn this into SLAPI_ACL_WRITE
273
* and record the original value.
274
* Need to make sure that these rights do not clash with the SLAPI
275
* public rights. This should be easy as the requested rights
276
* in the aclpb are stored in the bottom byte of aclpb_res_type,
277
* so if we keep the ACL private bits here too we make sure
282
if ( access & (ACLPB_SLAPI_ACL_WRITE_ADD | ACLPB_SLAPI_ACL_WRITE_DEL) ) {
283
access |= SLAPI_ACL_WRITE;
286
n_edn = slapi_entry_get_ndn ( e );
287
e_sdn = slapi_entry_get_sdn ( e );
289
/* Check if this is a write operation and the database is readonly */
290
/* No one, even the rootdn should be allowed to write to the database */
291
/* jcm: ReadOnly only applies to the public backends, the private ones */
292
/* (the DSEs) should still be writable for configuration. */
293
if ( access & ( SLAPI_ACL_WRITE | SLAPI_ACL_ADD | SLAPI_ACL_DELETE )) {
294
int be_readonly, privateBackend;
297
slapi_pblock_get ( pb, SLAPI_BE_READONLY, &be_readonly );
298
slapi_pblock_get ( pb, SLAPI_BACKEND, &be );
299
privateBackend = slapi_be_private ( be );
301
if ( !privateBackend && (be_readonly || slapi_config_get_readonly () )){
302
slapi_log_error (loglevel, plugin_name,
303
"conn=%" NSPRIu64 " op=%d (main): Deny %s on entry(%s)"
304
": readonly backend\n",
305
op->o_connid, op->o_opid,
306
acl_access2str(access),
308
return LDAP_UNWILLING_TO_PERFORM;
312
/* Check for things we need to skip */
313
TNF_PROBE_0_DEBUG(acl_skipaccess_start,"ACL","");
314
if ( acl_skip_access_check ( pb, e )) {
315
slapi_log_error (loglevel, plugin_name,
316
"conn=%" NSPRIu64 " op=%d (main): Allow %s on entry(%s)"
318
op->o_connid, op->o_opid,
319
acl_access2str(access),
321
return(LDAP_SUCCESS);
323
TNF_PROBE_0_DEBUG(acl_skipaccess_end,"ACL","");
326
/* Get the bindDN (normalized & case-ignored) */
327
slapi_pblock_get ( pb, SLAPI_REQUESTOR_DN, &clientDn );
329
/* Initialize aclpb */
330
aclplugin_preop_common( pb );
332
/* get the right acl pblock to work with */
333
if ( access & SLAPI_ACL_PROXY )
334
aclpb = acl_get_aclpb ( pb, ACLPB_PROXYDN_PBLOCK );
336
aclpb = acl_get_aclpb ( pb, ACLPB_BINDDN_PBLOCK );
339
slapi_log_error ( SLAPI_LOG_FATAL, plugin_name, "Missing aclpb 1 \n" );
340
ret_val = LDAP_OPERATIONS_ERROR;
341
goto cleanup_and_ret;
344
if ( !aclpb->aclpb_curr_entry_sdn ) {
345
slapi_log_error ( SLAPI_LOG_FATAL, plugin_name, "NULL aclpb_curr_entry_sdn \n" );
346
ret_val = LDAP_OPERATIONS_ERROR;
347
goto cleanup_and_ret;
350
/* check if aclpb is initialized or not */
351
TNF_PROBE_0_DEBUG(acl_aclpbinit_start,"ACL","");
352
acl_init_aclpb ( pb, aclpb, clientDn, 0 );
353
TNF_PROBE_0_DEBUG(acl_aclpbinit_end,"ACL","");
355
/* Here we mean if "I am trying to add/delete "myself" to a group, etc." We
356
* basically just want to see if the value matches the DN of the user that
357
* we're checking access for */
358
if (val && (access & SLAPI_ACL_WRITE) && (val->bv_len > 0)) {
359
Slapi_Attr *sa = slapi_attr_new();
362
slapi_attr_init(sa, attr);
363
slapi_attr_get_syntax_oid_copy(sa, &oid);
365
/* We only want to perform this check if the attribute is
366
* defined using the DN or Name And Optional UID syntaxes. */
367
if (oid && ((strcasecmp(oid, DN_SYNTAX_OID) == 0) ||
368
(strcasecmp(oid, NAMEANDOPTIONALUID_SYNTAX_OID) == 0))) {
369
/* should use slapi_sdn_compare() but that'a an extra malloc/free */
370
char *dn_val_to_write = slapi_create_dn_string("%s", val->bv_val);
371
if ( dn_val_to_write && aclpb->aclpb_authorization_sdn &&
372
slapi_utf8casecmp((ACLUCHP)dn_val_to_write, (ACLUCHP)
373
slapi_sdn_get_ndn(aclpb->aclpb_authorization_sdn)) == 0) {
374
access |= SLAPI_ACL_SELF;
377
slapi_ch_free_string(&dn_val_to_write);
380
slapi_ch_free_string(&oid);
381
slapi_attr_free(&sa);
384
/* Convert access to string of rights eg SLAPI_ACL_ADD->"add". */
385
if ((right= acl_access2str(access)) == NULL) {
386
/* ERROR: unknown rights */
387
slapi_log_error(SLAPI_LOG_ACL, plugin_name,
388
"acl_access_allowed unknown rights:%d\n", access);
390
ret_val = LDAP_OPERATIONS_ERROR;
391
goto cleanup_and_ret;
396
* Am I a anonymous dude ? then we can use our anonymous profile
397
* We don't require the aclpb to have been initialized for anom stuff
400
TNF_PROBE_0_DEBUG(acl_anon_test_start,"ACL","");
401
if ( (access & (SLAPI_ACL_SEARCH | SLAPI_ACL_READ )) &&
402
(clientDn && *clientDn == '\0')) {
403
aclanom_get_suffix_info(e, aclpb);
404
ret_val = aclanom_match_profile ( pb, aclpb, e, attr, access );
405
if (ret_val != -1 ) {
406
if (ret_val == LDAP_SUCCESS ) {
407
decision_reason.reason = ACL_REASON_ANON_ALLOWED;
408
} else if (ret_val == LDAP_INSUFFICIENT_ACCESS) {
409
decision_reason.reason = ACL_REASON_ANON_DENIED;
411
goto cleanup_and_ret;
414
TNF_PROBE_0_DEBUG(acl_anon_test_end,"ACL","");
416
/* copy the value into the aclpb for later checking by the value acl code */
418
aclpb->aclpb_curr_attrVal = val;
420
if (!(aclpb->aclpb_state & ACLPB_SEARCH_BASED_ON_LIST) &&
421
(access & SLAPI_ACL_SEARCH)) {
422
/* We are evaluating SEARCH right for the entry. After that
423
** we will eval the READ right. We need to refresh the
424
** list of acls selected for evaluation for the entry.
425
** Initialize the array so that we indicate nothing has been
428
aclpb->aclpb_handles_index[0] = -1;
429
/* access is not allowed on entry for search -- it's for
432
aclpb->aclpb_state &= ~ACLPB_ACCESS_ALLOWED_ON_ENTRY;
435
/* set that this is a new entry */
436
aclpb->aclpb_res_type |= ACLPB_NEW_ENTRY;
437
aclpb->aclpb_access = 0;
438
aclpb->aclpb_access |= access;
441
* stub the Slapi_Entry info first time and only it has changed
442
* or if the pblock is a psearch pblock--in this case the lifetime
443
* of entries associated with psearches is such that we cannot cache
444
* pointers to them--we must always start afresh (see psearch.c).
446
slapi_pblock_get( pb, SLAPI_OPERATION, &op);
447
if ( operation_is_flag_set(op, OP_FLAG_PS) ||
448
(aclpb->aclpb_curr_entry_sdn == NULL) ||
449
(slapi_sdn_compare ( aclpb->aclpb_curr_entry_sdn, e_sdn) != 0) ||
450
(aclpb->aclpb_curr_entry != e) /* cannot trust the cached entry */ ) {
451
TNF_PROBE_0_DEBUG(acl_entry_first_touch_start,"ACL","");
453
slapi_log_error(loglevel, plugin_name,
454
"#### conn=%" NSPRIu64 " op=%d binddn=\"%s\"\n",
455
op->o_connid, op->o_opid, clientDn);
456
aclpb->aclpb_stat_total_entries++;
458
if (!(access & SLAPI_ACL_PROXY) &&
459
!( aclpb->aclpb_state & ACLPB_DONOT_EVALUATE_PROXY )) {
460
Acl_PBlock *proxy_pb;
462
proxy_pb = acl_get_aclpb( pb, ACLPB_PROXYDN_PBLOCK );
464
TNF_PROBE_0_DEBUG(acl_access_allowed_proxy_start,"ACL","");
465
ret_val = acl_access_allowed( pb, e, attr, val, SLAPI_ACL_PROXY );
466
TNF_PROBE_0_DEBUG(acl_access_allowed_proxy_end,"ACL","");
468
if (ret_val != LDAP_SUCCESS) goto cleanup_and_ret;
471
if ( access & SLAPI_ACL_SEARCH) {
472
aclpb->aclpb_num_entries++;
474
if ( aclpb->aclpb_num_entries == 1) {
475
aclpb->aclpb_state |= ACLPB_COPY_EVALCONTEXT;
476
} else if ( aclpb->aclpb_state & ACLPB_COPY_EVALCONTEXT ) {
477
/* We need to copy the evalContext */
478
acl_copyEval_context ( aclpb, &aclpb->aclpb_curr_entryEval_context,
479
&aclpb->aclpb_prev_entryEval_context, 0 );
480
aclpb->aclpb_state &= ~ACLPB_COPY_EVALCONTEXT;
482
acl_clean_aclEval_context ( &aclpb->aclpb_curr_entryEval_context, 1 /*scrub */);
485
/* reset the cached result based on the scope */
486
acl__reset_cached_result (aclpb );
488
/* Find all the candidate aci's that apply by scanning up the DIT tree from edn. */
490
TNF_PROBE_0_DEBUG(acl_aciscan_start,"ACL","");
491
slapi_sdn_done ( aclpb->aclpb_curr_entry_sdn );
492
slapi_sdn_set_ndn_byval ( aclpb->aclpb_curr_entry_sdn, n_edn );
493
acllist_aciscan_update_scan ( aclpb, n_edn );
494
TNF_PROBE_0_DEBUG(acl_aciscan_end,"ACL","");
496
/* Keep the ptr to the current entry */
497
aclpb->aclpb_curr_entry = (Slapi_Entry *) e;
499
/* Get the attr info */
500
deallocate_attrEval = acl__get_attrEval ( aclpb, attr );
502
aclutil_print_resource ( aclpb, right, attr, clientDn );
505
* Used to be PListInitProp(aclpb->aclpb_proplist, 0,
506
* DS_ATTR_ENTRY, e, 0);
508
* The difference is that PListInitProp() allocates a new property
509
* every time it's called, overwriting the old name in the PList hash
510
* table, but not freeing the original property.
511
* Now, we just create the property at aclpb_malloc() time and
512
* Assign a new value each time.
515
rv = PListAssignValue(aclpb->aclpb_proplist,
516
DS_ATTR_ENTRY, e, 0);
519
slapi_log_error(SLAPI_LOG_ACL, plugin_name,
520
"Unable to set the Slapi_Entry in the Plist\n");
521
ret_val = LDAP_OPERATIONS_ERROR;
522
goto cleanup_and_ret;
525
TNF_PROBE_0_DEBUG(acl_entry_first_touch_end,"ACL","");
528
/* we are processing the same entry but for a different
529
** attribute. If access is already allowed on that, entry, then
530
** it's not a new entry anymore. It's the same old one.
533
TNF_PROBE_0_DEBUG(acl_entry_subs_touch_start,"ACL","");
535
aclpb->aclpb_res_type &= ~ACLPB_NEW_ENTRY;
537
/* Get the attr info */
538
deallocate_attrEval = acl__get_attrEval ( aclpb, attr );
540
TNF_PROBE_0_DEBUG(acl_entry_subs_touch_end,"ACL","");
544
/* get a lock for the reader */
545
acllist_acicache_READ_LOCK();
546
got_reader_locked = 1;
549
** Check if we can use any cached information to determine
550
** access to this resource
552
if ( (access & SLAPI_ACL_SEARCH) &&
553
(ret_val = acl__match_handlesFromCache ( aclpb , attr, access)) != -1) {
554
/* means got a result: allowed or not*/
556
if (ret_val == LDAP_SUCCESS ) {
557
decision_reason.reason = ACL_REASON_EVALCONTEXT_CACHED_ALLOW;
558
} else if (ret_val == LDAP_INSUFFICIENT_ACCESS) {
559
decision_reason.reason =
560
ACL_REASON_EVALCONTEXT_CACHED_NOT_ALLOWED;
562
goto cleanup_and_ret;
566
** Now we have all the information about the resource. Now we need to
567
** figure out if there are any ACLs which can be applied.
568
** If no ACLs are there, then it's a DENY as default.
570
if (!(acl__scan_for_acis(aclpb, &err))) {
572
/* We might have accessed the ACL first time which could
573
** have caused syntax error.
575
if ( err == ACL_ONEACL_TEXT_ERR)
576
ret_val = LDAP_INVALID_SYNTAX;
578
ret_val = LDAP_INSUFFICIENT_ACCESS;
579
decision_reason.reason = ACL_REASON_NO_MATCHED_RESOURCE_ALLOWS;
581
goto cleanup_and_ret;
584
slapi_log_error( SLAPI_LOG_ACL, plugin_name,
585
"Processed attr:%s for entry:%s\n", attr ? attr : "NULL",
589
** Now evaluate the rights.
590
** This is what we have been waiting for.
591
** The return value should be ACL_RES_DENY or ACL_RES_ALLOW.
593
rv = acl__TestRights(aclpb, access, &right, ds_map_generic,
595
if ( rv != ACL_RES_ALLOW && (0 == strcasecmp ( right, "selfwrite") ) ) {
596
/* If I am adding myself to a group, we don't need selfwrite always,
597
** write priv is good enough. Since libaccess doesn't provide me a nice
598
** way to evaluate OR rights, I have to try again with wite priv.
601
right = access_str_write;
602
rv = acl__TestRights(aclpb, access, &right, ds_map_generic,
606
if (rv == ACL_RES_ALLOW) {
607
ret_val = LDAP_SUCCESS;
609
ret_val = LDAP_INSUFFICIENT_ACCESS;
614
TNF_PROBE_0_DEBUG(acl_cleanup_start,"ACL","");
616
/* I am ready to get out. */
617
if ( got_reader_locked ) acllist_acicache_READ_UNLOCK();
619
/* Store the status of the evaluation for this attr */
620
if ( aclpb && (c_attrEval = aclpb->aclpb_curr_attrEval )) {
621
if ( deallocate_attrEval ) {
622
/* In this case we are not caching the result as
623
** we have too many attrs. we have malloced space.
626
slapi_ch_free ( (void **) &c_attrEval->attrEval_name );
627
slapi_ch_free ( (void **) &c_attrEval );
628
} else if (ret_val == LDAP_SUCCESS ) {
629
if ( access & SLAPI_ACL_SEARCH )
630
c_attrEval->attrEval_s_status |= ACL_ATTREVAL_SUCCESS;
631
else if ( access & SLAPI_ACL_READ )
632
c_attrEval->attrEval_r_status |= ACL_ATTREVAL_SUCCESS;
634
c_attrEval->attrEval_r_status |= ACL_ATTREVAL_INVALID;
636
if ( access & SLAPI_ACL_SEARCH )
637
c_attrEval->attrEval_s_status |= ACL_ATTREVAL_FAIL;
638
else if ( access & SLAPI_ACL_READ )
639
c_attrEval->attrEval_r_status |= ACL_ATTREVAL_FAIL;
641
c_attrEval->attrEval_r_status |= ACL_ATTREVAL_INVALID;
645
if ( aclpb ) aclpb->aclpb_curr_attrEval = NULL;
647
print_access_control_summary( "main", ret_val, clientDn, aclpb, right,
648
(attr ? attr : "NULL"), n_edn,
650
TNF_PROBE_0_DEBUG(acl_cleanup_end,"ACL","");
652
TNF_PROBE_0_DEBUG(acl_access_allowed_end,"ACL","");
658
static void print_access_control_summary( char *source, int ret_val, char *clientDn,
659
struct acl_pblock *aclpb,
663
aclResultReason_t *acl_reason)
670
static struct codebook reasonbook[] = {
671
{ACL_REASON_NO_ALLOWS, "no allow acis"},
672
{ACL_REASON_RESULT_CACHED_DENY, "cached deny"},
673
{ACL_REASON_RESULT_CACHED_ALLOW, "cached allow"},
674
{ACL_REASON_EVALUATED_ALLOW, "allowed"},
675
{ACL_REASON_EVALUATED_DENY, "denied"},
676
{ACL_REASON_NO_MATCHED_RESOURCE_ALLOWS, "no aci matched the resource"},
677
{ACL_REASON_NO_MATCHED_SUBJECT_ALLOWS, "no aci matched the subject"},
678
{ACL_REASON_ANON_ALLOWED, "allow anyone aci matched anon user"},
679
{ACL_REASON_ANON_DENIED, "no matching anyone aci for anon user"},
680
{ACL_REASON_EVALCONTEXT_CACHED_ALLOW, "cached context/parent allow"},
681
{ACL_REASON_EVALCONTEXT_CACHED_NOT_ALLOWED, "cached context/parent deny"},
682
{ACL_REASON_EVALCONTEXT_CACHED_ATTR_STAR_ALLOW, "cached context/parent allow any attr"},
683
{ACL_REASON_NONE, "error occurred"},
686
char *anon = "anonymous";
687
char *null_user = "NULL"; /* bizare case */
688
char *real_user = NULL;
689
char *proxy_user = NULL;
690
char *access_allowed_string = "Allow";
691
char *access_not_allowed_string = "Deny";
692
char *access_error_string = "access_error";
693
char *access_status = NULL;
694
char *access_reason_none = "no reason available";
695
char *access_reason = access_reason_none;
696
char acl_info[ BUFSIZ ];
697
Slapi_Operation *op = NULL;
701
loglevel = slapi_is_loglevel_set(SLAPI_LOG_ACL) ? SLAPI_LOG_ACL : SLAPI_LOG_ACLSUMMARY;
703
if ( !slapi_is_loglevel_set(loglevel) ) {
708
slapi_log_error ( SLAPI_LOG_FATAL, plugin_name, "Missing aclpb \n" );
712
slapi_pblock_get(aclpb->aclpb_pblock, SLAPI_OPERATION, &op); /* for logging */
714
if (ret_val == LDAP_INSUFFICIENT_ACCESS) {
715
access_status = access_not_allowed_string;
716
} else if ( ret_val == LDAP_SUCCESS) {
717
access_status = access_allowed_string;
718
} else { /* some kind of error */
719
access_status = access_error_string;
722
/* decode the reason */
723
for (i = 0; i < sizeof(reasonbook) / sizeof(struct codebook); i++) {
724
if ( acl_reason->reason == reasonbook[i].code ) {
725
access_reason = reasonbook[i].text;
732
if (acl_reason->deciding_aci) {
733
if (acl_reason->reason == ACL_REASON_RESULT_CACHED_DENY ||
734
acl_reason->reason == ACL_REASON_RESULT_CACHED_ALLOW) {
735
/* acl is in cache. Its detail must have been printed before.
736
* So no need to print out acl detail this time.
738
PR_snprintf( &acl_info[0], BUFSIZ, "%s by aci(%d)",
740
acl_reason->deciding_aci->aci_index);
743
PR_snprintf( &acl_info[0], BUFSIZ, "%s by aci(%d): aciname=%s, acidn=\"%s\"",
745
acl_reason->deciding_aci->aci_index,
746
acl_reason->deciding_aci->aclName,
747
slapi_sdn_get_ndn (acl_reason->deciding_aci->aci_sdn) );
751
/* Say who was denied access */
754
if (clientDn[0] == '\0') {
758
real_user = clientDn;
761
real_user = null_user;
764
/* Is there a proxy */
766
if ( aclpb->aclpb_proxy != NULL) {
768
if ( aclpb->aclpb_authorization_sdn != NULL ) {
771
(char *)(slapi_sdn_get_ndn(aclpb->aclpb_authorization_sdn)?
772
slapi_sdn_get_ndn(aclpb->aclpb_authorization_sdn):
775
slapi_log_error(loglevel, plugin_name,
776
"conn=%" NSPRIu64 " op=%d (%s): %s %s on entry(%s).attr(%s) to proxy (%s)"
778
op->o_connid, op->o_opid,
785
acl_info[0] ? acl_info : access_reason);
787
proxy_user = null_user;
788
slapi_log_error(loglevel, plugin_name,
789
"conn=%" NSPRIu64 " op=%d (%s): %s %s on entry(%s).attr(%s) to proxy (%s)"
791
op->o_connid, op->o_opid,
798
acl_info[0] ? acl_info : access_reason);
801
slapi_log_error(loglevel, plugin_name,
802
"conn=%" NSPRIu64 " op=%d (%s): %s %s on entry(%s).attr(%s) to %s"
804
op->o_connid, op->o_opid,
811
acl_info[0] ? acl_info : access_reason);
816
/***************************************************************************
818
* acl_read_access_allowed_on_entry
819
* check read access control on the given entry.
821
* Only used during seearch to test for read access on the entry.
822
* (Could be generalized).
824
* attrs is the list of requested attributes passed with the search.
825
* If the entry has no attributes (weird case) then the routine survives.
831
* LDAP_SUCCESS - access allowed
832
* LDAP_INSUFFICIENT_ACCESS - access denied
837
**************************************************************************/
839
acl_read_access_allowed_on_entry (
841
Slapi_Entry *e, /* The Slapi_Entry */
843
int access /* access rights */
847
struct acl_pblock *aclpb;
848
Slapi_Attr *currAttr;
849
Slapi_Attr *nextAttr;
851
#ifdef DETERMINE_ACCESS_BASED_ON_REQUESTED_ATTRIBUTES
854
char *attr_type = NULL;
858
aclResultReason_t decision_reason;
861
loglevel = slapi_is_loglevel_set(SLAPI_LOG_ACL) ? SLAPI_LOG_ACL : SLAPI_LOG_ACLSUMMARY;
863
TNF_PROBE_0_DEBUG(acl_read_access_allowed_on_entry_start ,"ACL","");
865
decision_reason.deciding_aci = NULL;
866
decision_reason.reason = ACL_REASON_NONE;
868
slapi_pblock_get ( pb, SLAPI_REQUESTOR_ISROOT, &isRoot );
871
** If it's the root, or acl is off or the entry is a rootdse,
872
** Then you have the privilege to read it.
874
if ( acl_skip_access_check ( pb, e ) ) {
875
char *n_edn = slapi_entry_get_ndn ( e );
876
slapi_log_error (SLAPI_LOG_ACL, plugin_name,
877
"Root access (%s) allowed on entry(%s)\n",
878
acl_access2str(access),
880
TNF_PROBE_1_DEBUG(acl_read_access_allowed_on_entry_end ,"ACL","",
881
tnf_string,skip_access,"");
885
aclpb = acl_get_aclpb ( pb, ACLPB_BINDDN_PBLOCK );
887
slapi_log_error ( SLAPI_LOG_FATAL, plugin_name, "Missing aclpb 2 \n" );
888
TNF_PROBE_1_DEBUG(acl_read_access_allowed_on_entry_end ,"ACL","",
889
tnf_string,end,"aclpb error");
890
return LDAP_OPERATIONS_ERROR;
894
* Am I a anonymous dude ? then we can use our anonympous profile
895
* We don't require the aclpb to have been initialized for anom stuff
898
slapi_pblock_get ( pb, SLAPI_REQUESTOR_DN, &clientDn );
899
if ( clientDn && *clientDn == '\0' ) {
901
ret_val = aclanom_match_profile ( pb, aclpb, e, NULL, SLAPI_ACL_READ );
902
TNF_PROBE_1_DEBUG(acl_read_access_allowed_on_entry_end ,"ACL","",
903
tnf_string,end,"anon");
905
if (ret_val != -1 ) return ret_val;
908
aclpb->aclpb_state &= ~ACLPB_RESET_MASK;
909
if (aclpb->aclpb_state & ACLPB_MATCHES_ALL_ACLS ) {
911
ret_val = acl__attr_cached_result (aclpb, NULL, SLAPI_ACL_READ);
912
if (ret_val != -1 ) {
913
/* print summary if loglevel set */
914
if ( slapi_is_loglevel_set(loglevel) ) {
916
n_edn = slapi_entry_get_ndn ( e );
917
if ( ret_val == LDAP_SUCCESS) {
918
decision_reason.reason =
919
ACL_REASON_EVALCONTEXT_CACHED_ALLOW;
921
decision_reason.reason =
922
ACL_REASON_EVALCONTEXT_CACHED_NOT_ALLOWED;
925
* pass NULL as the attr as this routine is concerned with
926
* access at the entry level.
928
print_access_control_summary( "on entry",
929
ret_val, clientDn, aclpb,
930
acl_access2str(SLAPI_ACL_READ),
934
TNF_PROBE_1_DEBUG(acl_read_access_allowed_on_entry_end ,"ACL","",
935
tnf_string,eval_context_cached,"");
942
* Currently do not use this code--it results in confusing
943
* behaviour..see 529905
945
#ifdef DETERMINE_ACCESS_BASED_ON_REQUESTED_ATTRIBUTES
947
/* Do we have access to the entry by virtue of
948
** having access to an attr. Before that, let's find out which attrs
949
** the user want. If the user has specified certain attributes, then
950
** we check aginst that set of attributes.
952
if (!((aclpb->aclpb_state & ACLPB_USER_WANTS_ALL_ATTRS) ||
953
(aclpb->aclpb_state & ACLPB_USER_SPECIFIED_ATTARS))) {
956
aclpb->aclpb_state |= ACLPB_USER_WANTS_ALL_ATTRS;
958
for ( i = 0; attrs != NULL && attrs[i] != NULL; i++ ) {
959
if ( strcmp( LDAP_ALL_USER_ATTRS, attrs[i] ) == 0 ) {
960
aclpb->aclpb_state |= ACLPB_USER_WANTS_ALL_ATTRS;
966
if (!(aclpb->aclpb_state & ACLPB_USER_WANTS_ALL_ATTRS)) {
967
for (i = 0; attrs != NULL && attrs[i] != NULL; i++ ) {
968
if ( !slapi_entry_attr_find ( e, attrs[i], &currAttr ) ) {
969
aclpb->aclpb_state |= ACLPB_USER_SPECIFIED_ATTARS;
974
} /* end of all user test*/
978
** If user has specified a list of attrs, might as well use it
979
** to determine access control.
983
if ( aclpb->aclpb_state & ACLPB_USER_SPECIFIED_ATTARS) {
985
attr_type = attrs[attr_index++];
987
/* Skip the operational attributes -- if there are any in the front */
988
slapi_entry_first_attr ( e, &currAttr );
989
if (currAttr != NULL) {
990
slapi_attr_get_flags ( currAttr, &flags );
991
while ( flags & SLAPI_ATTR_FLAG_OPATTR ) {
993
rv = slapi_entry_next_attr ( e, currAttr, &nextAttr );
994
if ( !rv ) slapi_attr_get_flags ( nextAttr, &flags );
998
/* Get the attr type */
999
if ( currAttr ) slapi_attr_get_type ( currAttr , &attr_type );
1003
#endif /*DETERMINE_ACCESS_BASED_ON_REQUESTED_ATTRIBUTES*/
1005
#ifndef DETERMINE_ACCESS_BASED_ON_REQUESTED_ATTRIBUTES
1008
* Here look at each attribute in the entry and see if
1009
* we have read access to it--if we do
1010
* and we are not denied access to the entry then this
1011
* is taken as implying access to the entry.
1013
slapi_entry_first_attr ( e, &currAttr );
1014
if (currAttr != NULL) {
1015
slapi_attr_get_type ( currAttr , &attr_type );
1018
aclpb->aclpb_state |= ACLPB_EVALUATING_FIRST_ATTR;
1021
if (acl_access_allowed (pb, e,attr_type, NULL,
1022
SLAPI_ACL_READ) == LDAP_SUCCESS) {
1024
** We found a rule which requires us to test access
1027
if ( aclpb->aclpb_state & ACLPB_FOUND_A_ENTRY_TEST_RULE){
1028
/* Do I have access on the entry itself */
1029
if (acl_access_allowed (pb, e, NULL,
1030
NULL, access) != LDAP_SUCCESS) {
1031
/* How was I denied ?
1032
** I could be denied on a DENY rule or because
1033
** there is no allow rule. If it's a DENY from
1034
** a DENY rule, then we don't have access to
1035
** the entry ( nice trick to get in )
1037
if ( aclpb->aclpb_state &
1038
ACLPB_EXECUTING_DENY_HANDLES)
1039
return LDAP_INSUFFICIENT_ACCESS;
1041
/* The other case is I don't have an
1042
** explicit allow rule -- which is fine.
1043
** Since, I am already here, it means that I have
1044
** an implicit allow to the entry.
1048
aclpb->aclpb_state &= ~ACLPB_EVALUATING_FIRST_ATTR;
1051
** If we are not sending all the attrs, then we must
1052
** make sure that we have right on a attr that we are
1055
len = strlen(attr_type);
1056
if ( (len + 1) > ACLPB_MAX_ATTR_LEN) {
1057
slapi_ch_free ( (void **) &aclpb->aclpb_Evalattr);
1058
aclpb->aclpb_Evalattr = slapi_ch_malloc(len+1);
1060
PL_strncpyz (aclpb->aclpb_Evalattr, attr_type, len);
1061
#ifdef DETERMINE_ACCESS_BASED_ON_REQUESTED_ATTRIBUTES
1062
if ( attr_index >= 0 ) {
1064
* access was granted to one of the user specified attributes
1065
* which was found in the entry and that attribute is
1066
* now in aclpb_Evalattr
1068
aclpb->aclpb_state |= ACLPB_ACCESS_ALLOWED_USERATTR;
1070
#endif /* DETERMINE_ACCESS_BASED_ON_REQUESTED_ATTRIBUTES */
1072
* Access was granted to _an_ attribute in the entry and that
1073
* attribute is now in aclpb_Evalattr
1075
aclpb->aclpb_state |= ACLPB_ACCESS_ALLOWED_ON_A_ATTR;
1076
#ifdef DETERMINE_ACCESS_BASED_ON_REQUESTED_ATTRIBUTES
1078
#endif /* DETERMINE_ACCESS_BASED_ON_REQUESTED_ATTRIBUTES */
1079
TNF_PROBE_1_DEBUG(acl_read_access_allowed_on_entry_end , "ACL","",
1080
tnf_string,called_access_allowed,"");
1082
return LDAP_SUCCESS;
1084
/* try the next one */
1086
#ifdef DETERMINE_ACCESS_BASED_ON_REQUESTED_ATTRIBUTES
1087
if (attr_index >= 0) {
1088
attr_type = attrs[attr_index++];
1090
#endif /* DETERMINE_ACCESS_BASED_ON_REQUESTED_ATTRIBUTES */
1091
rv = slapi_entry_next_attr ( e, currAttr, &nextAttr );
1092
if ( rv != 0 ) break;
1093
currAttr = nextAttr;
1094
slapi_attr_get_flags ( currAttr, &flags );
1095
while ( flags & SLAPI_ATTR_FLAG_OPATTR ) {
1097
rv = slapi_entry_next_attr ( e, currAttr, &nextAttr );
1098
if ( !rv ) slapi_attr_get_flags ( nextAttr, &flags );
1099
currAttr = nextAttr;
1101
/* Get the attr type */
1102
if ( currAttr ) slapi_attr_get_type ( currAttr , &attr_type );
1103
#ifdef DETERMINE_ACCESS_BASED_ON_REQUESTED_ATTRIBUTES
1105
#endif /* DETERMINE_ACCESS_BASED_ON_REQUESTED_ATTRIBUTES */
1110
** That means. we have searched thru all the attrs and found
1111
** access is denied on all attrs.
1113
** If there were no attributes in the entry at all (can have
1114
** such entries thrown up by the b/e, then we do
1115
** not have such an implied access.
1117
aclpb->aclpb_state |= ACLPB_ACCESS_DENIED_ON_ALL_ATTRS;
1118
aclpb->aclpb_state &= ~ACLPB_EVALUATING_FIRST_ATTR;
1119
TNF_PROBE_0_DEBUG(acl_read_access_allowed_on_entry_end ,"ACL","");
1121
return LDAP_INSUFFICIENT_ACCESS;
1124
/***************************************************************************
1126
* acl_read_access_allowed_on_attr
1127
* check access control on the given attr.
1129
* Only used during search to test for read access to an attr.
1130
* (Could be generalized)
1136
* LDAP_SUCCESS - access allowed
1137
* LDAP_INSUFFICIENT_ACCESS - access denied
1142
**************************************************************************/
1144
acl_read_access_allowed_on_attr (
1146
Slapi_Entry *e, /* The Slapi_Entry */
1147
char *attr, /* Attribute of the entry */
1148
struct berval *val, /* value of attr. NOT USED */
1149
int access /* access rights */
1153
struct acl_pblock *aclpb = NULL;
1154
char *clientDn = NULL;
1156
aclResultReason_t decision_reason;
1160
loglevel = slapi_is_loglevel_set(SLAPI_LOG_ACL) ? SLAPI_LOG_ACL : SLAPI_LOG_ACLSUMMARY;
1162
TNF_PROBE_0_DEBUG(acl_read_access_allowed_on_attr_start ,"ACL","");
1164
decision_reason.deciding_aci = NULL;
1165
decision_reason.reason = ACL_REASON_NONE;
1167
/* I am here, because I have access to the entry */
1169
n_edn = slapi_entry_get_ndn ( e );
1171
/* If it's the root or acl is off or rootdse, he has all the priv */
1172
if ( acl_skip_access_check ( pb, e ) ) {
1173
slapi_log_error (SLAPI_LOG_ACL, plugin_name,
1174
"Root access (%s) allowed on entry(%s)\n",
1175
acl_access2str(access),
1177
TNF_PROBE_1_DEBUG(acl_read_access_allowed_on_attr_end ,"ACL","",
1178
tnf_string,skip_aclcheck,"");
1180
return LDAP_SUCCESS;
1183
aclpb = acl_get_aclpb ( pb, ACLPB_BINDDN_PBLOCK );
1185
slapi_log_error ( SLAPI_LOG_FATAL, plugin_name, "Missing aclpb 3 \n" );
1186
TNF_PROBE_1_DEBUG(acl_read_access_allowed_on_attr_end ,"ACL","",
1187
tnf_string,aclpb_error,"");
1189
return LDAP_OPERATIONS_ERROR;
1193
* Am I a anonymous dude ? then we can use our anonympous profile
1194
* We don't require the aclpb to have been initialized for anom stuff
1197
slapi_pblock_get (pb, SLAPI_REQUESTOR_DN ,&clientDn );
1198
if ( clientDn && *clientDn == '\0' ) {
1199
ret_val = aclanom_match_profile ( pb, aclpb, e, attr,
1201
TNF_PROBE_1_DEBUG(acl_read_access_allowed_on_attr_end ,"ACL","",
1202
tnf_string,anon_decision,"");
1203
if (ret_val != -1 ) return ret_val;
1206
/* Then I must have a access to the entry. */
1207
aclpb->aclpb_state |= ACLPB_ACCESS_ALLOWED_ON_ENTRY;
1209
if ( aclpb->aclpb_state & ACLPB_MATCHES_ALL_ACLS ) {
1211
ret_val = acl__attr_cached_result (aclpb, attr, SLAPI_ACL_READ);
1212
if (ret_val != -1 ) {
1213
slapi_log_error(SLAPI_LOG_ACL, plugin_name,
1214
"MATCHED HANDLE:dn:%s attr: %s val:%d\n",
1215
n_edn, attr, ret_val );
1216
if ( ret_val == LDAP_SUCCESS) {
1217
decision_reason.reason =
1218
ACL_REASON_EVALCONTEXT_CACHED_ALLOW;
1220
decision_reason.reason =
1221
ACL_REASON_EVALCONTEXT_CACHED_NOT_ALLOWED;
1223
goto acl_access_allowed_on_attr_Exit;
1225
aclpb->aclpb_state |= ACLPB_COPY_EVALCONTEXT;
1229
if (aclpb->aclpb_state & ACLPB_ACCESS_DENIED_ON_ALL_ATTRS) {
1230
/* access is denied on all the attributes */
1231
TNF_PROBE_1_DEBUG(acl_read_access_allowed_on_attr_end ,"ACL","",
1232
tnf_string,deny_all_attrs,"");
1234
return LDAP_INSUFFICIENT_ACCESS;
1237
/* do I have access to all the entries by virtue of having aci
1238
** rules with targetattr ="*". If yes, then allow access to
1239
** rest of the attributes.
1241
if (aclpb->aclpb_state & ACLPB_ATTR_STAR_MATCHED) {
1242
slapi_log_error(SLAPI_LOG_ACL, plugin_name,
1243
"STAR Access allowed on attr:%s; entry:%s \n",
1245
decision_reason.reason = ACL_REASON_EVALCONTEXT_CACHED_ATTR_STAR_ALLOW;
1246
ret_val = LDAP_SUCCESS;
1247
goto acl_access_allowed_on_attr_Exit;
1251
if (aclpb->aclpb_state & ACLPB_ACCESS_ALLOWED_ON_A_ATTR) {
1253
/* access is allowed on that attr.
1254
** for example: Slapi_Entry: cn, sn. phone, uid, passwd, address
1255
** We found that access is allowed on phone. That means the
1256
** -- access is denied on cn, sn
1257
** -- access is allowed on phone
1258
** -- Don't know about the rest. Need to evaluate.
1261
if ( slapi_attr_type_cmp (attr, aclpb->aclpb_Evalattr, 1) == 0) {
1262
/* from now on we need to evaluate access on
1263
** rest of the attrs.
1265
aclpb->aclpb_state &= ~ACLPB_ACCESS_ALLOWED_ON_A_ATTR;
1266
TNF_PROBE_1_DEBUG(acl_read_access_allowed_on_attr_end ,"ACL","",
1267
tnf_string,aclp_Evalattr1,"");
1269
return LDAP_SUCCESS;
1272
* Here, the attr that implied access to the entry (aclpb_Evalattr),
1274
* the one we currently want evaluated--so
1275
* we need to evaluate access to attr--so fall through.
1279
} else if (aclpb->aclpb_state & ACLPB_ACCESS_ALLOWED_USERATTR) {
1280
/* Only skip evaluation on the user attr on which we have
1281
** evaluated before.
1283
if ( slapi_attr_type_cmp (attr, aclpb->aclpb_Evalattr, 1) == 0) {
1284
aclpb->aclpb_state &= ~ACLPB_ACCESS_ALLOWED_USERATTR;
1285
TNF_PROBE_1_DEBUG(acl_read_access_allowed_on_attr_end ,"ACL","",
1286
tnf_string,aclp_Evalattr2,"");
1287
return LDAP_SUCCESS;
1291
/* we need to evaluate the access on this attr */
1292
return ( acl_access_allowed(pb, e, attr, val, access) );
1294
/* This exit point prints a summary and returns ret_val */
1295
acl_access_allowed_on_attr_Exit:
1297
/* print summary if loglevel set */
1298
if ( slapi_is_loglevel_set(loglevel) ) {
1300
print_access_control_summary( "on attr",
1301
ret_val, clientDn, aclpb,
1302
acl_access2str(SLAPI_ACL_READ),
1303
attr, n_edn, &decision_reason);
1305
TNF_PROBE_0_DEBUG(acl_read_access_allowed_on_attr_end ,"ACL","");
1309
/***************************************************************************
1312
* check access control on the given entry to see if
1313
* it allows the given modifications by the user associated with op.
1320
* LDAP_SUCCESS - mods allowed ok
1321
* <err> - same return value as acl_access_allowed()
1326
**************************************************************************/
1336
int rv, accessCheckDisabled;
1338
Slapi_Attr *attr = NULL;
1340
Slapi_Backend *be = NULL;
1342
Acl_PBlock *aclpb = acl_get_aclpb ( pb, ACLPB_PROXYDN_PBLOCK );
1346
rv = slapi_pblock_get ( pb, SLAPI_PLUGIN_DB_NO_ACL, &accessCheckDisabled );
1347
if ( rv != -1 && accessCheckDisabled ) return LDAP_SUCCESS;
1349
if ( NULL == aclpb )
1350
aclpb = acl_get_aclpb ( pb, ACLPB_BINDDN_PBLOCK );
1352
n_edn = slapi_entry_get_ndn ( e );
1353
e_sdn = slapi_entry_get_sdn ( e );
1355
slapi_mods_init_byref(&smods,mods);
1357
for (mod = slapi_mods_get_first_mod(&smods);
1359
mod = slapi_mods_get_next_mod(&smods)) {
1360
switch (mod->mod_op & ~LDAP_MOD_BVALUES ) {
1362
case LDAP_MOD_DELETE:
1363
if (mod->mod_bvalues != NULL ) {
1368
* Here, check that we have the right to delete all
1369
* the values of the attribute in the entry.
1372
case LDAP_MOD_REPLACE:
1375
if (slapi_pblock_get( pb, SLAPI_BACKEND, &be )) {
1380
slapi_pblock_get ( pb, SLAPI_BE_LASTMOD, &lastmod );
1383
(strcmp (mod->mod_type, "modifiersname")== 0 ||
1384
strcmp (mod->mod_type, "modifytimestamp")== 0 ||
1385
strcmp (mod->mod_type, PSEUDO_ATTR_UNHASHEDUSERPASSWORD)== 0)
1390
slapi_entry_attr_find (e, mod->mod_type, &attr);
1391
if ( attr != NULL) {
1392
Slapi_Value *sval=NULL;
1393
const struct berval *attrVal=NULL;
1394
int k= slapi_attr_first_value(attr,&sval);
1396
attrVal = slapi_value_get_berval(sval);
1397
rv = slapi_access_allowed (pb, e,
1399
(struct berval *)attrVal, /* XXXggood had to cast away const - BAD */
1400
ACLPB_SLAPI_ACL_WRITE_DEL); /* was SLAPI_ACL_WRITE */
1401
if ( rv != LDAP_SUCCESS) {
1408
slapi_mods_done(&smods);
1411
k= slapi_attr_next_value(attr, k, &sval);
1415
rv = slapi_access_allowed (pb, e,
1418
ACLPB_SLAPI_ACL_WRITE_DEL); /* was SLAPI_ACL_WRITE */
1419
if ( rv != LDAP_SUCCESS) {
1426
slapi_mods_done(&smods);
1437
* Check that we have add/delete writes on the specific values
1438
* we are trying to add.
1441
if ( aclpb && aclpb->aclpb_curr_entry_sdn )
1442
slapi_sdn_done ( aclpb->aclpb_curr_entry_sdn );
1444
if ( mod->mod_bvalues != NULL ) {
1447
* Here, there are specific values specified.
1448
* For add and replace--we need add rights for these values.
1449
* For delete we need delete rights for these values.
1452
for ( i = 0; mod->mod_bvalues[i] != NULL; i++ ) {
1454
if (SLAPI_IS_MOD_ADD(mod->mod_op) ||
1455
SLAPI_IS_MOD_REPLACE(mod->mod_op)) {
1457
rv = acl_access_allowed (pb,e,
1459
mod->mod_bvalues[i],
1460
ACLPB_SLAPI_ACL_WRITE_ADD); /*was SLAPI_ACL_WRITE*/
1461
} else if (SLAPI_IS_MOD_DELETE(mod->mod_op)) {
1462
rv = acl_access_allowed (pb,e,
1464
mod->mod_bvalues[i],
1465
ACLPB_SLAPI_ACL_WRITE_DEL); /*was SLAPI_ACL_WRITE*/
1467
rv = LDAP_INSUFFICIENT_ACCESS;
1470
if ( rv != LDAP_SUCCESS ) {
1477
slapi_mods_done(&smods);
1480
/* Need to check for all the values because
1481
** we may be modifying a "self<right>" value.
1484
/* Are we adding/replacing a aci attribute
1485
** value. In that case, we need to make
1486
** sure that the new value has thr right
1489
if (strcmp(mod->mod_type,
1490
aci_attr_type) == 0) {
1491
if ( 0 != (rv = acl_verify_syntax( e_sdn,
1492
mod->mod_bvalues[i], errbuf))) {
1493
aclutil_print_err(rv, e_sdn,
1494
mod->mod_bvalues[i],
1497
slapi_mods_done(&smods);
1498
return LDAP_INVALID_SYNTAX;
1503
} /* end of big for */
1505
slapi_mods_done(&smods);
1506
return( LDAP_SUCCESS );
1508
/***************************************************************************
1511
* Modifies ( removed, add, changes) the ACI LIST.
1514
* int *optype - op code
1515
* char *dn - DN of the entry
1516
* void *change - The change struct which contais the
1525
**************************************************************************/
1527
acl_modified (Slapi_PBlock *pb, int optype, char *n_dn, void *change)
1529
struct berval **bvalue;
1531
int rv=0; /* returned value */
1538
Slapi_Attr *attr = NULL;
1539
Slapi_Entry *e = NULL;
1541
aclUserGroup *ugroup = NULL;
1543
e_sdn = slapi_sdn_new_normdn_byval ( n_dn );
1544
/* Before we proceed, Let's first check if we are changing any groups.
1545
** If we are, then we need to change the signature
1548
case SLAPI_OPERATION_MODIFY:
1549
case SLAPI_OPERATION_DELETE:
1550
slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, (void*)&e);
1552
case SLAPI_OPERATION_ADD:
1553
e = (Slapi_Entry *)change;
1557
/* e can be null for RDN */
1558
if ( e ) slapi_entry_attr_find( e, "objectclass", &attr);
1561
int group_change = 0;
1562
Slapi_Value *sval=NULL;
1563
const struct berval *attrVal;
1566
i= slapi_attr_first_value ( attr,&sval );
1568
attrVal = slapi_value_get_berval ( sval );
1569
if ( (strcasecmp (attrVal->bv_val, "groupOfNames") == 0 ) ||
1570
(strcasecmp (attrVal->bv_val, "groupOfUniqueNames") == 0 ) ||
1571
(strcasecmp (attrVal->bv_val, "groupOfCertificates") == 0 ) ||
1572
(strcasecmp (attrVal->bv_val, "groupOfURLs") == 0 ) ) {
1574
if ( optype == SLAPI_OPERATION_MODIFY ) {
1575
Slapi_Attr *a = NULL;
1577
rv = slapi_entry_attr_find ( e, "uniqueMember", &a);
1578
if ( rv != 0 ) break;
1579
rv = slapi_entry_attr_find ( e, "Member", &a );
1580
if ( rv != 0 ) break;
1581
rv = slapi_entry_attr_find ( e, "MemberURL", &a );
1582
if ( rv != 0 ) break;
1583
/* That means we are not changing the member
1584
** list, so it's okay to let go this
1591
i= slapi_attr_next_value ( attr, i, &sval );
1595
** We can do better here XXX, i.e invalidate the cache for users who
1596
** use this group. for now just do the whole thing.
1598
if ( group_change ) {
1599
slapi_log_error(SLAPI_LOG_ACL, plugin_name,
1600
"Group Change: Invalidating entire UserGroup Cache %s\n",
1602
aclg_regen_group_signature();
1603
if ( (optype == SLAPI_OPERATION_MODIFY) || (optype == SLAPI_OPERATION_DELETE ) ) {
1604
/* Then we need to invalidate the acl signature also */
1605
acl_signature = aclutil_gen_signature ( acl_signature );
1611
* Here if the target entry is in the group cache
1612
* as a user then, as it's being changed it may move out of any dynamic
1613
* groups it belongs to.
1614
* Just remove it for now--can do better XXX by checking to see if
1615
* it really needs to be removed by testing to see if he's
1616
* still in th group after the change--but this requires keeping
1617
* the memberURL of the group which we don't currently do.
1619
* the attributes that are being used in dynamic
1620
* groups then we could only remove the user if a sensitive
1621
* attribute was being modified (rather than scanning the whole user cache
1622
* all the time). Also could do a hash lookup.
1624
* aclg_find_userGroup() incs a refcnt so we can still refer to ugroup.
1625
* aclg_markUgroupForRemoval() decs it and marks it for removal
1626
* , so after that you cannot refer to ugroup.
1630
if ( (ugroup = aclg_find_userGroup(n_dn)) != NULL) {
1632
* Mark this for deletion next time round--try to impact
1633
* this mainline code as little as possible.
1635
slapi_log_error(SLAPI_LOG_ACL, plugin_name,
1636
"Marking entry %s for removal from ACL user Group Cache\n",
1638
aclg_markUgroupForRemoval (ugroup);
1642
* Take the write lock around all the mods--so that
1643
* other operations will see the acicache either before the whole mod
1644
* or after but not, as it was before, during the mod.
1645
* This is in line with the LDAP concept of the operation
1646
* on the whole entry being the atomic unit.
1651
case SLAPI_OPERATION_DELETE:
1652
/* In this case we have already checked if the user has
1653
** right to delete the entry. Part of delete of entry is
1654
** remove all the ACLs also.
1657
acllist_acicache_WRITE_LOCK();
1658
rv = acllist_remove_aci_needsLock(e_sdn, NULL);
1659
acllist_acicache_WRITE_UNLOCK();
1662
case SLAPI_OPERATION_ADD:
1663
slapi_entry_attr_find ( (Slapi_Entry *) change, aci_attr_type, &attr );
1666
Slapi_Value *sval=NULL;
1667
const struct berval *attrVal;
1670
acllist_acicache_WRITE_LOCK();
1671
i= slapi_attr_first_value ( attr,&sval );
1673
attrVal = slapi_value_get_berval(sval);
1674
rv= acllist_insert_aci_needsLock(e_sdn, attrVal );
1676
aclutil_print_err(rv, e_sdn, attrVal, NULL);
1677
/* Print the aci list */
1678
i= slapi_attr_next_value ( attr, i, &sval );
1680
acllist_acicache_WRITE_UNLOCK();
1684
case SLAPI_OPERATION_MODIFY:
1686
int got_write_lock = 0;
1688
mods = (LDAPMod **) change;
1690
for (j=0; mods[j] != NULL; j++) {
1691
if (strcasecmp(mods[j]->mod_type, aci_attr_type) == 0) {
1693
/* Got an aci to mod in this list of mods, so
1694
* take the acicache lock for the whole list of mods,
1695
* remembering to free it below.
1697
if ( !got_write_lock) {
1698
acllist_acicache_WRITE_LOCK();
1702
switch (mods[j]->mod_op & ~LDAP_MOD_BVALUES) {
1703
case LDAP_MOD_REPLACE:
1704
/* First remove the item */
1705
rv = acllist_remove_aci_needsLock(e_sdn, NULL);
1707
/* now fall thru to add the new one */
1709
/* Add the new aci */
1710
if (mods[j]->mod_op & LDAP_MOD_BVALUES) {
1711
bvalue = mods[j]->mod_bvalues;
1714
for (; *bvalue != NULL; ++bvalue) {
1715
rv=acllist_insert_aci_needsLock( e_sdn, *bvalue);
1716
if (rv <= ACL_ERR) {
1717
aclutil_print_err(rv, e_sdn,
1722
value = mods[j]->mod_values;
1725
for (; *value != NULL; ++value) {
1726
b.bv_len = strlen (*value);
1728
rv=acllist_insert_aci_needsLock( e_sdn, &b);
1729
if (rv <= ACL_ERR) {
1730
aclutil_print_err(rv, e_sdn,
1736
case LDAP_MOD_DELETE:
1737
if (mods[j]->mod_op & LDAP_MOD_BVALUES) {
1738
bvalue = mods[j]->mod_bvalues;
1739
if (bvalue == NULL || *bvalue == NULL) {
1740
rv = acllist_remove_aci_needsLock( e_sdn, NULL);
1742
for (; *bvalue != NULL; ++bvalue)
1743
acllist_remove_aci_needsLock( e_sdn, *bvalue);
1746
value = mods[j]->mod_values;
1747
if (value == NULL || *value == NULL) {
1748
acllist_remove_aci_needsLock( e_sdn,NULL);
1750
for (; *value != NULL; ++value) {
1751
b.bv_len = strlen (*value);
1753
acllist_remove_aci_needsLock( e_sdn, &b);
1762
}/* modtype switch */
1763
}/* attrtype is aci */
1765
if ( got_write_lock ) {
1766
acllist_acicache_WRITE_UNLOCK();
1771
}/* case op is modify*/
1773
case SLAPI_OPERATION_MODRDN:
1775
new_RDN = (char*) change;
1776
slapi_log_error (SLAPI_LOG_ACL, plugin_name,
1777
"acl_modified (MODRDN %s => \"%s\"\n",
1780
/* compute new_DN: */
1781
parent_DN = slapi_dn_parent (n_dn);
1782
if (parent_DN == NULL) {
1785
new_DN = slapi_create_dn_string("%s,%s", new_RDN, parent_DN);
1788
/* Change the acls */
1789
acllist_acicache_WRITE_LOCK();
1790
/* acllist_moddn_aci_needsLock expects normalized new_DN,
1791
* which is no need to be case-ignored */
1792
acllist_moddn_aci_needsLock ( e_sdn, new_DN );
1793
acllist_acicache_WRITE_UNLOCK();
1795
/* deallocat the parent_DN */
1796
if (parent_DN != NULL) {
1797
slapi_ch_free ( (void **) &new_DN );
1798
slapi_ch_free ( (void **) &parent_DN );
1805
} /*optype switch */
1807
slapi_sdn_free ( &e_sdn );
1810
/***************************************************************************
1812
* acl__scan_for_acis
1813
* Scan the list and picup the correct acls for evaluation.
1816
* Acl_PBlock *aclpb - Main ACL pblock
1817
* int *err; - Any error status
1819
* num_handles - Number of handles matched to the
1824
**************************************************************************/
1826
acl__scan_for_acis(Acl_PBlock *aclpb, int *err)
1833
int gen_allow_handle = ACI_MAX_ELEVEL+1;
1834
int gen_deny_handle = ACI_MAX_ELEVEL+1;
1837
TNF_PROBE_0_DEBUG(acl__scan_for_acis_start,"ACL","");
1840
** Determine if we are traversing via the list Vs. we have our own
1843
if ( aclpb->aclpb_state & ACLPB_SEARCH_BASED_ON_LIST ||
1844
aclpb->aclpb_handles_index[0] != -1 ) {
1846
while ( kk < aclpb_max_selected_acls && aclpb->aclpb_handles_index[kk] != -1 ) {
1847
slapi_log_error(SLAPI_LOG_ACL, plugin_name, "Using ACL Container:%d for evaluation\n", kk);
1852
memset (&errp, 0, sizeof(NSErr_t));
1854
aclpb->aclpb_num_deny_handles = -1;
1855
aclpb->aclpb_num_allow_handles = -1;
1856
memset(aclpb->aclpb_deny_handles, 0, sizeof(aci_t *)*(ACI_MAX_ELEVEL+1));
1857
memset(aclpb->aclpb_allow_handles, 0, sizeof(aci_t *)*(ACI_MAX_ELEVEL+1));
1859
/* Check the signature. If it has changed, start fresh */
1860
if ( aclpb->aclpb_signature != acl_signature ) {
1861
slapi_log_error (SLAPI_LOG_ACL, plugin_name,
1862
"Restart the scan -- due to acl changes\n");
1863
acllist_init_scan ( aclpb->aclpb_pblock, LDAP_SCOPE_BASE, NULL );
1866
attr_matched = ACL_FALSE;
1870
aclpb->aclpb_stat_acllist_scanned++;
1871
aci = acllist_get_first_aci ( aclpb, &cookie );
1874
if (acl__resource_match_aci(aclpb, aci, 0, &attr_matched)) {
1875
/* Generate the ACL list handle */
1876
if (aci->aci_handle == NULL) {
1877
aci = acllist_get_next_aci ( aclpb, aci, &cookie );
1880
aclutil_print_aci (aci, acl_access2str (aclpb->aclpb_access));
1882
if (aci->aci_type & ACI_HAS_DENY_RULE) {
1883
if (aclpb->aclpb_deny_handles[aci->aci_elevel] == NULL ) {
1884
aclpb->aclpb_deny_handles[aci->aci_elevel] = aci;
1886
if ((gen_deny_handle + ACI_DEFAULT_ELEVEL + 1) ==
1887
aclpb->aclpb_deny_handles_size ) {
1888
int num = ACLPB_INCR_LIST_HANDLES +
1889
aclpb->aclpb_deny_handles_size;
1890
/* allocate more space */
1891
aclpb->aclpb_deny_handles =
1894
(void *) aclpb->aclpb_deny_handles,
1895
num * sizeof (aci_t *));
1896
aclpb->aclpb_deny_handles_size = num;
1898
aclpb->aclpb_deny_handles [gen_deny_handle] = aci;
1904
** It's possible that a single acl is in both the camps i.e
1905
** It has a allow and a deny rule
1906
** In that case we keep the same acl in both the camps.
1908
if (aci->aci_type & ACI_HAS_ALLOW_RULE) {
1909
if (aclpb->aclpb_allow_handles[aci->aci_elevel] == NULL ) {
1910
aclpb->aclpb_allow_handles[aci->aci_elevel] = aci;
1912
if ((gen_allow_handle + ACI_DEFAULT_ELEVEL + 1) ==
1913
aclpb->aclpb_allow_handles_size) {
1914
/* allocate more space */
1915
int num = ACLPB_INCR_LIST_HANDLES +
1916
aclpb->aclpb_allow_handles_size;
1918
aclpb->aclpb_allow_handles =
1921
(void *) aclpb->aclpb_allow_handles,
1922
num * sizeof (aci_t *));
1923
aclpb->aclpb_allow_handles_size = num;
1925
aclpb->aclpb_allow_handles [gen_allow_handle] = aci;
1931
aci = acllist_get_next_aci ( aclpb, aci, &cookie );
1932
} /* end of while */
1934
/* make the last one a null */
1935
aclpb->aclpb_deny_handles [gen_deny_handle] = NULL;
1936
aclpb->aclpb_allow_handles [gen_allow_handle] = NULL;
1938
/* specify how many we found */
1939
aclpb->aclpb_num_deny_handles = deny_handle;
1940
aclpb->aclpb_num_allow_handles = allow_handle;
1942
slapi_log_error(SLAPI_LOG_ACL, plugin_name, "Num of ALLOW Handles:%d, DENY handles:%d\n",
1943
aclpb->aclpb_num_allow_handles, aclpb->aclpb_num_deny_handles);
1945
TNF_PROBE_0_DEBUG(acl__scan_for_acis_end,"ACL","");
1947
return(allow_handle + deny_handle);
1950
/***************************************************************************
1952
* acl__resource_match_aci
1954
* This compares the ACI for the given resource and determines if
1955
* the ACL applies to the resource or not.
1957
* For read/search operation, we collect all the possible acls which
1958
* will apply, We will be using this list for future acl evaluation
1962
* struct acl_pblock *aclpb - Main acl private block
1963
* aci_t *aci - The ACI item
1964
* int skip_attrEval - DOn't check for attrs
1965
* int *a_matched - Attribute matched
1969
* ACL_TRUE - Yep, This ACL is applicable to the
1971
* ACL_FALSE - No it is not.
1976
**************************************************************************/
1977
#define ACL_RIGHTS_TARGETATTR_NOT_NEEDED ( SLAPI_ACL_ADD | SLAPI_ACL_DELETE | SLAPI_ACL_PROXY)
1979
acl__resource_match_aci( Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a_matched)
1982
struct slapi_filter *f; /* filter */
1983
int rv; /* return value */
1984
/* Assume that resource matches */
1985
int matches = ACL_TRUE;
1986
int attr_matched = ACL_TRUE;
1987
int attr_matched_in_targetattrfilters = 0;
1992
int star_matched = ACL_FALSE;
1994
AclAttrEval *c_attrEval = NULL;
1995
const char *res_ndn = NULL;
1996
const char *aci_ndn = NULL;
1997
char *matched_val = NULL;
1998
int add_matched_val_to_ht = 0;
1999
char res_right_str[128];
2001
TNF_PROBE_0_DEBUG(acl__resource_match_aci_start,"ACL","");
2003
if (NULL == aclpb) {
2004
matches = ACL_FALSE;
2005
goto acl__resource_match_aci_EXIT;
2008
/* Figure out if the acl has the correct rights or not */
2009
aci_right = aci->aci_access;
2010
res_right = aclpb->aclpb_access;
2011
if (!(aci_right & res_right)) {
2012
/* If we are looking for read/search and the acl has read/search
2013
** then go further because if targets match we may keep that
2014
** acl in the entry cache list.
2016
if (!((res_right & (SLAPI_ACL_SEARCH | SLAPI_ACL_READ)) &&
2017
(aci_right & (SLAPI_ACL_SEARCH | SLAPI_ACL_READ))))
2018
matches = ACL_FALSE;
2019
goto acl__resource_match_aci_EXIT;
2023
/* first Let's see if the entry is under the subtree where the
2024
** ACL resides. We can't let somebody affect a target beyond the
2025
** scope of where the ACL resides
2026
** Example: ACL is located in "ou=engineering, o=ace industry, c=us
2027
** but if the target is "o=ace industry, c=us", then we are in trouble.
2029
** If the aci is in the rootdse and the entry is not, then we do not
2030
** match--ie. acis in the rootdse do NOT apply below...for the moment.
2033
res_ndn = slapi_sdn_get_ndn ( aclpb->aclpb_curr_entry_sdn );
2034
aci_ndn = slapi_sdn_get_ndn ( aci->aci_sdn );
2035
if (!slapi_sdn_issuffix(aclpb->aclpb_curr_entry_sdn, aci->aci_sdn)
2036
|| (!slapi_is_rootdse(res_ndn) && slapi_is_rootdse(aci_ndn)) ) {
2038
/* cant' poke around */
2039
matches = ACL_FALSE;
2040
goto acl__resource_match_aci_EXIT;
2044
** We have a single ACI which we need to find if it applies to
2045
** the resource or not.
2047
if ((aci->aci_type & ACI_TARGET_DN) && (aclpb->aclpb_curr_entry_sdn)) {
2049
struct berval *avaValue;
2052
dn_matched = ACL_TRUE;
2053
slapi_filter_get_ava ( f, &avaType, &avaValue );
2055
if (!slapi_dn_issuffix( res_ndn, avaValue->bv_val)) {
2056
dn_matched = ACL_FALSE;
2058
if (aci->aci_type & ACI_TARGET_NOT) {
2059
matches = (dn_matched ? ACL_FALSE : ACL_TRUE);
2061
matches = (dn_matched ? ACL_TRUE: ACL_FALSE);
2065
/* No need to look further */
2066
if (matches == ACL_FALSE) {
2067
goto acl__resource_match_aci_EXIT;
2070
if (aci->aci_type & ACI_TARGET_PATTERN) {
2073
dn_matched = ACL_TRUE;
2075
if ((rv = acl_match_substring(f, (char *)res_ndn, 0 /* match suffux */)) != ACL_TRUE) {
2076
dn_matched = ACL_FALSE;
2078
slapi_log_error(SLAPI_LOG_ACL, plugin_name,
2079
"acl__resource_match_aci:pattern err\n");
2080
matches = ACL_FALSE;
2081
goto acl__resource_match_aci_EXIT;
2084
if (aci->aci_type & ACI_TARGET_NOT) {
2085
matches = (dn_matched ? ACL_FALSE : ACL_TRUE);
2087
matches = (dn_matched ? ACL_TRUE: ACL_FALSE);
2091
/* No need to look further */
2092
if (matches == ACL_FALSE) {
2093
goto acl__resource_match_aci_EXIT;
2097
* Is it a (target="ldap://cn=*,($dn),o=sun.com") kind of thing.
2099
if (aci->aci_type & ACI_TARGET_MACRO_DN) {
2101
* See if the ($dn) component matches the string and
2102
* retrieve the matched substring for later use
2104
* The macro string is a function of the dn only, so if the
2105
* entry is the same one don't recalculate it--
2106
* this flag only works for search right now, could
2107
* also optimise for mods by making it work for mods.
2110
if ( (aclpb->aclpb_res_type & ACLPB_NEW_ENTRY) == 0 ) {
2112
* Here same entry so just look up the matched value,
2113
* calculated from the targetdn and stored judiciously there
2115
matched_val = (char *)acl_ht_lookup( aclpb->aclpb_macro_ht,
2116
(PLHashNumber)aci->aci_index);
2118
if ( matched_val == NULL &&
2119
(aclpb->aclpb_res_type & (ACLPB_NEW_ENTRY | ACLPB_EFFECTIVE_RIGHTS))) {
2121
slapi_log_error (SLAPI_LOG_ACL, plugin_name,
2122
"Evaluating macro aci(%d)%s for resource %s\n",
2123
aci->aci_index, aci->aclName,
2124
aclutil__access_str(res_right, res_right_str));
2125
matched_val = acl_match_macro_in_target( res_ndn,
2126
aci->aci_macro->match_this,
2127
aci->aci_macro->macro_ptr);
2128
add_matched_val_to_ht = 1; /* may need to add matched value to ht */
2130
if (matched_val == NULL) {
2131
dn_matched = ACL_FALSE;
2133
dn_matched = ACL_TRUE;
2136
if (aci->aci_type & ACI_TARGET_NOT) {
2137
matches = (dn_matched ? ACL_FALSE : ACL_TRUE);
2139
matches = (dn_matched ? ACL_TRUE: ACL_FALSE);
2142
if ( add_matched_val_to_ht ) {
2143
if ( matches == ACL_TRUE && matched_val ) {
2145
* matched_val may be needed later for matching on
2146
* other targets or on the subject--so optimistically
2147
* put it in the hash table.
2148
* If, at the end of this routine, we
2149
* find that after all the resource did not match then
2150
* that's ok--the value is freed at aclpb cleanup time.
2151
* If there is already an entry for this aci in this
2152
* aclpb then remove it--it's an old value for a
2156
acl_ht_add_and_freeOld(aclpb->aclpb_macro_ht,
2157
(PLHashNumber)aci->aci_index,
2159
slapi_log_error (SLAPI_LOG_ACL, plugin_name,
2160
"-- Added aci(%d) and matched value (%s) to macro ht\n",
2161
aci->aci_index, matched_val);
2162
acl_ht_display_ht(aclpb->aclpb_macro_ht);
2164
slapi_ch_free((void **)&matched_val);
2165
if (matches == ACL_FALSE) {
2166
slapi_log_error (SLAPI_LOG_ACL, plugin_name,
2167
"Evaluated ACL_FALSE\n");
2173
/* No need to look further */
2174
if (matches == ACL_FALSE) {
2175
goto acl__resource_match_aci_EXIT;
2179
** Here, if there's a targetfilter field, see if it matches.
2181
** The commented out code below was an erroneous attempt to skip
2182
** this test. It is wrong because: 1. you need to store
2183
** whether the last test matched or not (you cannot just assume it did)
2184
** and 2. It may not be the same aci, so the previous matched
2185
** value is a function of the aci.
2186
** May be interesting to build such a cache...but no evidence for
2187
** for that right now. See Bug 383424.
2190
** && ((aclpb->aclpb_state & ACLPB_SEARCH_BASED_ON_LIST) ||
2191
** (aclpb->aclpb_res_type & ACLPB_NEW_ENTRY))
2193
if (aci->aci_type & ACI_TARGET_FILTER ) {
2194
int filter_matched = ACL_TRUE;
2198
* For targetfilter we need to fake the lasinfo structure--it's
2199
* created "naturally" for subjects but not targets.
2203
if ( aci->aci_type & ACI_TARGET_FILTER_MACRO_DN) {
2205
lasInfo *lasinfo = NULL;
2207
lasinfo = (lasInfo*) slapi_ch_malloc( sizeof(lasInfo) );
2209
lasinfo->aclpb = aclpb;
2210
lasinfo->resourceEntry = aclpb->aclpb_curr_entry;
2211
aclpb->aclpb_curr_aci = aci;
2212
filter_matched = aclutil_evaluate_macro( aci->targetFilterStr,
2214
ACL_EVAL_TARGET_FILTER);
2215
slapi_ch_free((void**)&lasinfo);
2219
if (slapi_vattr_filter_test(NULL, aclpb->aclpb_curr_entry,
2221
0 /*don't do acess chk*/)!= 0) {
2222
filter_matched = ACL_FALSE;
2227
/* If it's a logical value we can do logic on it...otherwise we do not match */
2228
if ( filter_matched == ACL_TRUE || filter_matched == ACL_FALSE) {
2229
if (aci->aci_type & ACI_TARGET_FILTER_NOT) {
2230
matches = (filter_matched == ACL_TRUE ? ACL_FALSE : ACL_TRUE);
2232
matches = (filter_matched == ACL_TRUE ? ACL_TRUE: ACL_FALSE);
2235
matches = ACL_FALSE;
2236
slapi_log_error( SLAPI_LOG_ACL, plugin_name,
2237
"Returning UNDEFINED for targetfilter evaluation.\n");
2240
if (matches == ACL_FALSE) {
2241
goto acl__resource_match_aci_EXIT;
2246
* Check to see if we need to evaluate any targetattrfilters.
2247
* They look as follows:
2248
* (targetattrfilters="add=sn:(sn=rob) && gn:(gn!=byrne),
2249
* del=sn:(sn=rob) && gn:(gn=byrne)")
2252
* If theres's a targetattrfilter then each add/del filter
2253
* that applies to an attribute in the entry, must be satisfied
2254
* by each value of the attribute in the entry.
2257
* If there's a targetattrfilter then the add/del filter
2258
* must be satisfied by the attribute to be added/deleted.
2259
* (MODIFY acl is evaluated one value at a time).
2264
if (((aclpb->aclpb_access & SLAPI_ACL_ADD) &&
2265
(aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS) )||
2266
((aclpb->aclpb_access & SLAPI_ACL_DELETE) &&
2267
(aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS) ) ) {
2269
Targetattrfilter **attrFilterArray;
2271
Targetattrfilter *attrFilter = NULL;
2273
Slapi_Attr *attr_ptr = NULL;
2275
const struct berval *attrVal;
2280
if (aclpb->aclpb_access & SLAPI_ACL_ADD &&
2281
aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS) {
2283
attrFilterArray = aci->targetAttrAddFilters;
2285
} else if (aclpb->aclpb_access & SLAPI_ACL_DELETE &&
2286
aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS) {
2288
attrFilterArray = aci->targetAttrDelFilters;
2292
attr_matched = ACL_TRUE;
2295
while (attrFilterArray[num_attrs] && attr_matched) {
2296
attrFilter = attrFilterArray[num_attrs];
2299
* If this filter applies to an attribute in the entry,
2300
* apply it to the entry.
2301
* Otherwise just ignore it.
2305
if (slapi_entry_attr_find ( aclpb->aclpb_curr_entry,
2306
attrFilter->attr_str,
2310
* This is an applicable filter.
2311
* The filter is to be appplied to the entry being added
2313
* The filter needs to be satisfied by _each_ occurence
2314
* of the attribute in the entry--otherwise you
2315
* could satisfy the filter and then put loads of other
2316
* values in on the back of it.
2321
k= slapi_attr_first_value(attr_ptr,&sval);
2323
while(k != -1 && !done) {
2324
attrVal = slapi_value_get_berval(sval);
2326
if ( acl__make_filter_test_entry(
2327
&aclpb->aclpb_filter_test_entry,
2328
attrFilter->attr_str,
2329
(struct berval *)attrVal) == LDAP_SUCCESS ) {
2331
attr_matched= acl__test_filter(
2332
aclpb->aclpb_filter_test_entry,
2334
1 /* Do filter sense evaluation below */
2336
done = !attr_matched;
2337
slapi_entry_free( aclpb->aclpb_filter_test_entry );
2340
k= slapi_attr_next_value(attr_ptr, k, &sval);
2344
* Here, we applied an applicable filter to the entry.
2345
* So if attr_matched is ACL_TRUE then every value
2346
* of the attribute in the entry satisfied the filter.
2347
* Otherwise, attr_matched is ACL_FALSE and not every
2348
* value satisfied the filter, so we will teminate the
2349
* scan of the filter list.
2358
* Here, we've applied all the applicable filters to the entry.
2359
* Each one must have been satisfied by all the values of the attribute.
2360
* The result of this is stored in attr_matched.
2365
* Don't support a notion of "add != " or "del != "
2367
* To do this, need to test whether it's an add test or del test
2368
* then if it's add and ACI_TARGET_ATTR_ADD_FILTERS_NOT then
2369
* flip the bit. Same for del.
2372
if (aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS_NOT) {
2373
matches = (matches ? ACL_FALSE : ACL_TRUE);
2375
matches = (matches ? ACL_TRUE: ACL_FALSE);
2379
/* No need to look further */
2380
if (attr_matched == ACL_FALSE) {
2381
matches = ACL_FALSE;
2382
goto acl__resource_match_aci_EXIT;
2385
} else if ( ((aclpb->aclpb_access & ACLPB_SLAPI_ACL_WRITE_ADD) &&
2386
(aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS)) ||
2387
((aclpb->aclpb_access & ACLPB_SLAPI_ACL_WRITE_DEL) &&
2388
(aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS)) ) {
2392
* Here, it's a modify add/del and we have attr filters.
2393
* So, we need to scan the add/del filter list to find the filter
2394
* that applies to the current attribute.
2395
* Then the (attribute,value) pair being added/deleted better
2396
* match that filter.
2401
Targetattrfilter **attrFilterArray = NULL;
2402
Targetattrfilter *attrFilter;
2405
if ((aclpb->aclpb_access & ACLPB_SLAPI_ACL_WRITE_ADD) &&
2406
(aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS)) {
2408
attrFilterArray = aci->targetAttrAddFilters;
2410
} else if ((aclpb->aclpb_access & ACLPB_SLAPI_ACL_WRITE_DEL) &&
2411
(aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS)) {
2413
attrFilterArray = aci->targetAttrDelFilters;
2419
* Scan this filter list for an applicable filter.
2425
while (attrFilterArray[num_attrs] && !found) {
2426
attrFilter = attrFilterArray[num_attrs];
2428
/* If this filter applies to the attribute, stop. */
2429
if ((aclpb->aclpb_curr_attrEval) &&
2430
slapi_attr_type_cmp ( aclpb->aclpb_curr_attrEval->attrEval_name,
2431
attrFilter->attr_str, 1) == 0) {
2438
* Here, if found an applicable filter, then apply the filter to the
2440
* Otherwise, ignore the targetattrfilters.
2445
if ( acl__make_filter_test_entry(
2446
&aclpb->aclpb_filter_test_entry,
2447
aclpb->aclpb_curr_attrEval->attrEval_name,
2448
aclpb->aclpb_curr_attrVal) == LDAP_SUCCESS ) {
2450
attr_matched= acl__test_filter(aclpb->aclpb_filter_test_entry,
2452
1 /* Do filter sense evaluation below */
2454
slapi_entry_free( aclpb->aclpb_filter_test_entry );
2457
/* No need to look further */
2458
if (attr_matched == ACL_FALSE) {
2459
matches = attr_matched;
2460
goto acl__resource_match_aci_EXIT;
2464
* Here this attribute appeared and was matched in a
2465
* targetattrfilters list, so record this fact so we do
2466
* not have to scan the targetattr list for the attribute.
2469
attr_matched_in_targetattrfilters = 1;
2471
} /* targetvaluefilters */
2474
/* There are 3 cases by which acis are selected.
2475
** 1) By scanning the whole list and picking based on the resource.
2476
** 2) By picking a subset of the list which will be used for the whole
2478
** 3) A finer granularity, i.e, a selected list of acls which will be
2479
** used for only that entry's evaluation.
2481
if ( !(skip_attrEval) && (aclpb->aclpb_state & ACLPB_SEARCH_BASED_ON_ENTRY_LIST) &&
2482
(res_right & SLAPI_ACL_SEARCH) &&
2483
((aci->aci_access & SLAPI_ACL_READ) || (aci->aci_access & SLAPI_ACL_SEARCH))) {
2486
while ( kk < aclpb_max_selected_acls && aclpb->aclpb_handles_index[kk] >=0 ) kk++;
2487
if (kk >= aclpb_max_selected_acls) {
2488
aclpb->aclpb_state &= ~ACLPB_SEARCH_BASED_ON_ENTRY_LIST;
2490
aclpb->aclpb_handles_index[kk++] = aci->aci_index;
2491
aclpb->aclpb_handles_index[kk] = -1;
2496
/* If we are suppose to skip attr eval, then let's skip it */
2497
if ( (aclpb->aclpb_access & SLAPI_ACL_SEARCH ) && ( ! skip_attrEval ) &&
2498
( aclpb->aclpb_res_type & ACLPB_NEW_ENTRY )) {
2499
aclEvalContext *c_evalContext = &aclpb->aclpb_curr_entryEval_context;
2500
int nhandle = c_evalContext->acle_numof_tmatched_handles;
2502
if ( nhandle < aclpb_max_selected_acls) {
2503
c_evalContext->acle_handles_matched_target[nhandle] = aci->aci_index;
2504
c_evalContext->acle_numof_tmatched_handles++;
2508
if ( skip_attrEval ) {
2509
goto acl__resource_match_aci_EXIT;
2512
/* We need to check again because we don't want to select this handle
2513
** if the right doesn't match for now.
2515
if (!(aci_right & res_right)) {
2516
matches = ACL_FALSE;
2517
goto acl__resource_match_aci_EXIT;
2521
* Here if the request is one that requires matching
2522
* on a targetattr then do it here.
2523
* If we have already matched an attribute in the targetattrfitlers list
2524
* then we do not require a match in the targetattr so we can skip it.
2525
* The operations that require targetattr are SLAPI_ACL_COMPARE,
2526
* SLAPI_ACL_SEARCH, SLAPI_ACL_READ and SLAPI_ACL_WRITE, as long as
2527
* c_attrEval is non-null (otherwise it's a modrdn op which
2528
* does not require the targetattr list).
2530
* rbyrneXXX if we had a proper permission for modrdn eg SLAPI_ACL_MODRDN
2531
* then we would not need this crappy way of telling it was a MODRDN
2532
* request ie. SLAPI_ACL_WRITE && !(c_attrEval).
2535
c_attrEval = aclpb->aclpb_curr_attrEval;
2538
* If we've already matched on targattrfilter then do not
2539
* bother to look at the attrlist.
2542
if (!attr_matched_in_targetattrfilters) {
2544
/* match target attr */
2546
(aci->aci_type & ACI_TARGET_ATTR)) {
2547
/* there is a target ATTR */
2548
Targetattr **attrArray = aci->targetAttr;
2549
Targetattr *attr = NULL;
2551
res_attr = c_attrEval->attrEval_name;
2552
attr_matched = ACL_FALSE;
2553
star_matched = ACL_FALSE;
2556
while (attrArray[num_attrs] && !attr_matched) {
2557
attr = attrArray[num_attrs];
2558
if (attr->attr_type & ACL_ATTR_STRING) {
2559
if (slapi_attr_type_cmp ( res_attr,
2560
attr->u.attr_str, 1) == 0) {
2561
attr_matched = ACL_TRUE;
2562
*a_matched = ACL_TRUE;
2564
} else if (attr->attr_type & ACL_ATTR_FILTER) {
2565
if (ACL_TRUE == acl_match_substring (
2566
attr->u.attr_filter,
2568
attr_matched = ACL_TRUE;
2569
*a_matched = ACL_TRUE;
2571
} else if (attr->attr_type & ACL_ATTR_STAR) {
2572
attr_matched = ACL_TRUE;
2573
*a_matched = ACL_TRUE;
2574
star_matched = ACL_TRUE;
2579
if (aci->aci_type & ACI_TARGET_ATTR_NOT) {
2580
matches = (attr_matched ? ACL_FALSE : ACL_TRUE);
2582
matches = (attr_matched ? ACL_TRUE: ACL_FALSE);
2586
aclpb->aclpb_state &= ~ACLPB_ATTR_STAR_MATCHED;
2587
/* figure out how it matched, i.e star matched */
2588
if (matches && star_matched && num_attrs == 1 &&
2589
!(aclpb->aclpb_state & ACLPB_FOUND_ATTR_RULE))
2590
aclpb->aclpb_state |= ACLPB_ATTR_STAR_MATCHED;
2592
/* we are here means that there is a specific
2593
** attr in the rule for this resource.
2594
** We need to avoid this case
2595
** Rule 1: (targetattr = "uid")
2596
** Rule 2: (targetattr = "*")
2597
** we cannot use STAR optimization
2599
aclpb->aclpb_state |= ACLPB_FOUND_ATTR_RULE;
2600
aclpb->aclpb_state &= ~ACLPB_ATTR_STAR_MATCHED;
2602
} else if ( (c_attrEval) ||
2603
(aci->aci_type & ACI_TARGET_ATTR)) {
2604
if ((aci_right & ACL_RIGHTS_TARGETATTR_NOT_NEEDED) &&
2605
(aclpb->aclpb_access & ACL_RIGHTS_TARGETATTR_NOT_NEEDED)) {
2607
** Targetattr rule doesn't make any sense
2608
** in this case. So select this rule
2609
** default: matches = ACL_TRUE;
2612
} else if (aci_right & SLAPI_ACL_WRITE &&
2613
(aci->aci_type & ACI_TARGET_ATTR) &&
2615
/* We need to handle modrdn operation. Modrdn doesn't
2616
** change any attrs but changes the RDN and so (attr=NULL).
2617
** Here we found an acl which has a targetattr but
2618
** the resource doesn't need one. In that case, we should
2619
** consider this acl.
2620
** default: matches = ACL_TRUE;
2624
matches = ACL_FALSE;
2627
}/* !attr_matched_in_targetattrfilters */
2630
** Here we are testing if we find a entry test rule (which should
2631
** be rare). In that case, just remember it. An entry test rule
2632
** doesn't have "(targetattr)".
2634
if ((aclpb->aclpb_state & ACLPB_EVALUATING_FIRST_ATTR) &&
2635
(!(aci->aci_type & ACI_TARGET_ATTR))) {
2636
aclpb->aclpb_state |= ACLPB_FOUND_A_ENTRY_TEST_RULE;
2640
* Generic exit point for this routine:
2641
* matches is ACL_TRUE if the aci matches the target of the resource,
2642
* ACL_FALSE othrewise.
2643
* Apologies for the goto--this is a retro-fitted exit point.
2645
acl__resource_match_aci_EXIT:
2648
* For macro acis, there may be a partial macro string
2649
* placed in the aclpb_macro_ht
2650
* even if the aci did not finally match.
2651
* All the partial strings will be freed at aclpb
2654
if (ACL_TRUE == matches) {
2655
aclpb->aclpb_stat_aclres_matched++;
2658
TNF_PROBE_0_DEBUG(acl__resource_match_aci_end,"ACL","");
2662
/* Macro to determine if the cached result is valid or not. */
2663
#define ACL_CACHED_RESULT_VALID( result) \
2664
(((result & ACLPB_CACHE_READ_RES_ALLOW) && \
2665
(result & ACLPB_CACHE_READ_RES_SKIP)) || \
2666
((result & ACLPB_CACHE_SEARCH_RES_ALLOW) && \
2667
(result & ACLPB_CACHE_SEARCH_RES_SKIP))) ? 0 : 1
2668
/***************************************************************************
2672
* Test the rights and find out if access is allowed or not.
2674
* Processing Alogorithm:
2676
* First, process the DENY rules one by one. If the user is not explicitly
2677
* denied, then check if the user is allowed by processing the ALLOW handles
2679
* The result of the evaluation is cached. Exceptions are
2680
* -- If an acl happens to be in both DENY and ALLOW camp.
2681
* -- Only interested for READ/SEARCH right.
2684
* struct acl_pblock *aclpb - main acl private block
2685
* int access - The access bits
2686
* char **right - The right we are looking for
2687
* char ** generic - Generic rights
2691
* ACL_RES_ALLOW - Access allowed
2692
* ACL_RES_DENY - Access denied
2693
* err - error condition
2698
**************************************************************************/
2700
acl__TestRights(Acl_PBlock *aclpb,int access, char **right, char ** map_generic,
2701
aclResultReason_t *result_reason)
2703
ACLEvalHandle_t *acleval;
2704
int rights_rv = ACL_RES_DENY;
2708
char *deny_generic = NULL;
2711
char *testRights[2];
2715
TNF_PROBE_0_DEBUG(acl__TestRights_start,"ACL","");
2717
/* record the aci and reason for access decision */
2718
result_reason->deciding_aci = NULL;
2719
result_reason->reason = ACL_REASON_NONE;
2721
/* If we don't have any ALLLOW handles, it's DENY by default */
2722
if (aclpb->aclpb_num_allow_handles <= 0) {
2723
result_reason->deciding_aci = NULL;
2724
result_reason->reason = ACL_REASON_NO_MATCHED_RESOURCE_ALLOWS;
2726
TNF_PROBE_1_DEBUG(acl__TestRights_end,"ACL","",
2727
tnf_string,no_allows,"");
2729
return ACL_RES_DENY;
2732
/* Get the ACL evaluation Context */
2733
acleval = aclpb->aclpb_acleval;
2735
testRights[0] = *right;
2736
testRights[1] = '\0';
2739
** START PROCESSING DENY HANDLES
2740
** Process each handle at a time. Do not concatenate the handles or else
2741
** all the context information will be build again and we will pay a
2742
** lot of penalty. The context is built the first time the handle is
2745
** First we set the default to INVALID so that if rules are not matched, then
2746
** we get INVALID and if a rule matched, the we get DENY.
2748
aclpb->aclpb_state &= ~ACLPB_EXECUTING_ALLOW_HANDLES;
2749
aclpb->aclpb_state |= ACLPB_EXECUTING_DENY_HANDLES;
2750
ACL_SetDefaultResult (NULL, acleval, ACL_RES_INVALID);
2752
numHandles = ACI_MAX_ELEVEL + aclpb->aclpb_num_deny_handles;
2753
for (i=0, k=0; i < numHandles && k < aclpb->aclpb_num_deny_handles ; ++i) {
2757
** If the handle has been evaluated before, we can
2758
** cache the result.
2760
if ((aci = aclpb->aclpb_deny_handles[i]) == NULL) {
2761
if (i <= ACI_MAX_ELEVEL) {
2768
index = aci->aci_index;
2769
slapi_log_error(SLAPI_LOG_ACL, plugin_name,
2770
"Evaluating DENY aci(%d) \"%s\"\n", index, aci->aclName);
2772
if (access & ( SLAPI_ACL_SEARCH | SLAPI_ACL_READ)) {
2775
* aclpb->aclpb_cache_result[0..aclpb->aclpb_last_cache_result] is
2776
* a cache of info about whether applicable acis
2777
* allowed, did_not_allow or denied access
2779
for (j =0; j < aclpb->aclpb_last_cache_result; j++) {
2780
if (index == aclpb->aclpb_cache_result[j].aci_index) {
2783
result = aclpb->aclpb_cache_result[j].result;
2784
if ( result <= 0) break;
2785
if (!ACL_CACHED_RESULT_VALID(result)) {
2786
/* something is wrong. Need to evaluate */
2787
aclpb->aclpb_cache_result[j].result = -1;
2791
** We have a valid cached result. Let's see if we
2792
** have what we need.
2794
if (access & SLAPI_ACL_SEARCH) {
2795
if ( result & ACLPB_CACHE_SEARCH_RES_DENY){
2796
slapi_log_error(SLAPI_LOG_ACL, plugin_name,
2797
"DENY:Found SEARCH DENY in cache\n");
2798
__acl_set_aclIndex_inResult ( aclpb, access, index );
2799
result_reason->deciding_aci = aci;
2800
result_reason->reason = ACL_REASON_RESULT_CACHED_DENY;
2801
TNF_PROBE_1_DEBUG(acl__TestRights_end,"ACL","",
2802
tnf_string,cached_deny,"");
2803
return ACL_RES_DENY;
2804
} else if ((result & ACLPB_CACHE_SEARCH_RES_SKIP) ||
2805
(result & ACLPB_CACHE_SEARCH_RES_ALLOW)) {
2806
slapi_log_error(SLAPI_LOG_ACL, plugin_name,
2807
"DENY:Found SEARCH SKIP in cache\n");
2813
} else { /* must be READ */
2814
if (result & ACLPB_CACHE_READ_RES_DENY) {
2815
slapi_log_error(SLAPI_LOG_ACL, plugin_name,
2816
"DENY:Found READ DENY in cache\n");
2817
__acl_set_aclIndex_inResult ( aclpb, access, index );
2818
result_reason->deciding_aci = aci;
2819
result_reason->reason = ACL_REASON_RESULT_CACHED_DENY;
2820
TNF_PROBE_1_DEBUG(acl__TestRights_end,"ACL","",
2821
tnf_string,cached_deny,"");
2822
return ACL_RES_DENY;
2823
} else if ( result & ACLPB_CACHE_READ_RES_SKIP) {
2824
slapi_log_error(SLAPI_LOG_ACL, plugin_name,
2825
"DENY:Found READ SKIP in cache\n");
2840
rv = ACL_EvalSetACL(NULL, acleval, aci->aci_handle);
2842
slapi_log_error(SLAPI_LOG_ACL, plugin_name,
2843
"acl__TestRights:Unable to set the DENY acllist\n");
2847
** Now we have all the information we need. We need to call
2848
** the ONE ACL to test the rights.
2849
** return value: ACL_RES_DENY, ACL_RES_ALLOW, error codes
2851
aclpb->aclpb_curr_aci = aci;
2852
rights_rv = ACL_EvalTestRights (NULL, acleval, testRights,
2855
&acl_tag, &expr_num);
2857
slapi_log_error( SLAPI_LOG_ACL, plugin_name, "Processed:%d DENY handles Result:%d\n",index, rights_rv);
2859
if (rights_rv == ACL_RES_FAIL) {
2860
result_reason->deciding_aci = aci;
2861
result_reason->reason = ACL_REASON_NONE;
2862
TNF_PROBE_1_DEBUG(acl__TestRights_end,"ACL","",
2863
tnf_string,evaled_deny,"");
2864
return ACL_RES_DENY;
2867
/* have we executed an ATTR RULE */
2868
if ( aci->aci_ruleType & ACI_ATTR_RULES )
2869
aclpb->aclpb_state |= ACLPB_ATTR_RULE_EVALUATED;
2871
if (access & (SLAPI_ACL_SEARCH | SLAPI_ACL_READ)) {
2873
for (j=0; j <aclpb->aclpb_last_cache_result; ++j) {
2874
if (index == aclpb->aclpb_cache_result[j].aci_index) {
2879
if ( j < aclpb->aclpb_last_cache_result) {
2880
/* already in cache */
2881
} else if ( j < aclpb_max_cache_results ) {
2882
/* j == aclpb->aclpb_last_cache_result &&
2883
j < ACLPB_MAX_CACHE_RESULTS */
2884
aclpb->aclpb_last_cache_result++;
2885
aclpb->aclpb_cache_result[j].aci_index = index;
2886
aclpb->aclpb_cache_result[j].aci_ruleType = aci->aci_ruleType;
2888
} else { /* cache overflow */
2889
if ( rights_rv == ACL_RES_DENY) {
2890
result_reason->deciding_aci = aci;
2891
result_reason->reason = ACL_REASON_EVALUATED_DENY;
2892
TNF_PROBE_1_DEBUG(acl__TestRights_end,"ACL","",
2893
tnf_string,evaled_deny,"");
2894
return ACL_RES_DENY;
2900
__acl_set_aclIndex_inResult ( aclpb, access, index );
2901
if (rights_rv == ACL_RES_DENY) {
2902
if (access & SLAPI_ACL_SEARCH) {
2903
aclpb->aclpb_cache_result[j].result |=
2904
ACLPB_CACHE_SEARCH_RES_DENY;
2905
} else { /* MUST BE READ */
2906
aclpb->aclpb_cache_result[j].result |=
2907
ACLPB_CACHE_READ_RES_DENY;
2909
/* We are done -- return */
2910
result_reason->deciding_aci = aci;
2911
result_reason->reason = ACL_REASON_EVALUATED_DENY;
2912
TNF_PROBE_1_DEBUG(acl__TestRights_end,"ACL","",
2913
tnf_string,evaled_deny,"");
2914
return ACL_RES_DENY;
2915
} else if (rights_rv == ACL_RES_ALLOW) {
2916
/* This will happen, of we have an acl with both deny and allow
2917
** Since we may not have finished all the deny acl, go thru all
2918
** of them. We will use this cached result when we evaluate this
2919
** handle in the context of allow handles.
2921
if (access & SLAPI_ACL_SEARCH) {
2922
aclpb->aclpb_cache_result[j].result |=
2923
ACLPB_CACHE_SEARCH_RES_ALLOW;
2925
aclpb->aclpb_cache_result[j].result |=
2926
ACLPB_CACHE_READ_RES_ALLOW;
2930
if (access & SLAPI_ACL_SEARCH) {
2931
aclpb->aclpb_cache_result[j].result |=
2932
ACLPB_CACHE_SEARCH_RES_SKIP;
2934
aclpb->aclpb_cache_result[j].result |=
2935
ACLPB_CACHE_READ_RES_SKIP;
2940
if ( rights_rv == ACL_RES_DENY ) {
2941
result_reason->deciding_aci = aci;
2942
result_reason->reason = ACL_REASON_EVALUATED_DENY;
2943
TNF_PROBE_1_DEBUG(acl__TestRights_end,"ACL","",
2944
tnf_string,evaled_deny,"");
2945
return ACL_RES_DENY;
2952
** START PROCESSING ALLOW HANDLES.
2953
** Process each handle at a time. Do not concatenate the handles or else
2954
** all the context information will be build again and we will pay a
2955
** lot of penalty. The context is built the first time the handle is
2958
** First we set the default to INVALID so that if rules are not matched, then
2959
** we get INVALID and if a rule matched, the we get ALLOW.
2961
aclpb->aclpb_state &= ~ACLPB_EXECUTING_DENY_HANDLES;
2962
aclpb->aclpb_state |= ACLPB_EXECUTING_ALLOW_HANDLES;
2963
ACL_SetDefaultResult (NULL, acleval, ACL_RES_INVALID);
2964
numHandles = ACI_MAX_ELEVEL + aclpb->aclpb_num_allow_handles;
2965
for (i=0, k=0; i < numHandles && k < aclpb->aclpb_num_allow_handles ; ++i) {
2968
** If the handle has been evaluated before, we can
2969
** cache the result.
2971
if ((aci = aclpb->aclpb_allow_handles[i]) == NULL) {
2972
if (i <= ACI_MAX_ELEVEL) {
2979
index = aci->aci_index;
2980
slapi_log_error(SLAPI_LOG_ACL, plugin_name,
2981
"%d. Evaluating ALLOW aci(%d) \"%s\"\n", k, index, aci->aclName);
2983
if (access & ( SLAPI_ACL_SEARCH | SLAPI_ACL_READ)) {
2986
* aclpb->aclpb_cache_result[0..aclpb->aclpb_last_cache_result] is
2987
* a cache of info about whether applicable acis
2988
* allowed, did_not_allow or denied access
2991
for (j =0; j < aclpb->aclpb_last_cache_result; j++) {
2992
if (index == aclpb->aclpb_cache_result[j].aci_index) {
2994
result = aclpb->aclpb_cache_result[j].result;
2995
if ( result <= 0) break;
2997
if (!ACL_CACHED_RESULT_VALID(result)) {
2998
/* something is wrong. Need to evaluate */
2999
aclpb->aclpb_cache_result[j].result = -1;
3004
** We have a valid cached result. Let's see if we
3005
** have what we need.
3007
if (access & SLAPI_ACL_SEARCH) {
3008
if (result & ACLPB_CACHE_SEARCH_RES_ALLOW) {
3009
slapi_log_error(SLAPI_LOG_ACL, plugin_name,
3010
"Found SEARCH ALLOW in cache\n");
3011
__acl_set_aclIndex_inResult ( aclpb, access, index );
3012
result_reason->deciding_aci = aci;
3013
result_reason->reason = ACL_REASON_RESULT_CACHED_ALLOW;
3014
TNF_PROBE_1_DEBUG(acl__TestRights_end,"ACL","",
3015
tnf_string,cached_allow,"");
3016
return ACL_RES_ALLOW;
3017
} else if ( result & ACLPB_CACHE_SEARCH_RES_SKIP) {
3018
slapi_log_error(SLAPI_LOG_ACL, plugin_name,
3019
"Found SEARCH SKIP in cache\n");
3023
/* need to evaluate */
3027
if ( result & ACLPB_CACHE_READ_RES_ALLOW) {
3028
slapi_log_error(SLAPI_LOG_ACL, plugin_name,
3029
"Found READ ALLOW in cache\n");
3030
__acl_set_aclIndex_inResult ( aclpb, access, index );
3031
result_reason->deciding_aci = aci;
3032
result_reason->reason = ACL_REASON_RESULT_CACHED_ALLOW;
3033
TNF_PROBE_1_DEBUG(acl__TestRights_end,"ACL","",
3034
tnf_string,cached_allow,"");
3035
return ACL_RES_ALLOW;
3036
} else if ( result & ACLPB_CACHE_READ_RES_SKIP) {
3037
slapi_log_error(SLAPI_LOG_ACL, plugin_name,
3038
"Found READ SKIP in cache\n");
3053
TNF_PROBE_0_DEBUG(acl__libaccess_start,"ACL","");
3054
rv = ACL_EvalSetACL(NULL, acleval, aci->aci_handle);
3056
slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
3057
"acl__TestRights:Unable to set the acllist\n");
3061
** Now we have all the information we need. We need to call
3062
** the ONE ACL to test the rights.
3063
** return value: ACL_RES_DENY, ACL_RES_ALLOW, error codes
3065
aclpb->aclpb_curr_aci = aci;
3066
rights_rv = ACL_EvalTestRights (NULL, acleval, testRights,
3069
&acl_tag, &expr_num);
3070
TNF_PROBE_0_DEBUG(acl__libaccess_end,"ACL","");
3072
if (aci->aci_ruleType & ACI_ATTR_RULES)
3073
aclpb->aclpb_state |= ACLPB_ATTR_RULE_EVALUATED;
3075
if (access & (SLAPI_ACL_SEARCH | SLAPI_ACL_READ)) {
3077
for (j=0; j <aclpb->aclpb_last_cache_result; ++j) {
3078
if (index == aclpb->aclpb_cache_result[j].aci_index) {
3083
if ( j < aclpb->aclpb_last_cache_result) {
3084
/* already in cache */
3085
} else if ( j < aclpb_max_cache_results ) {
3086
/* j == aclpb->aclpb_last_cache_result &&
3087
j < ACLPB_MAX_CACHE_RESULTS */
3088
aclpb->aclpb_last_cache_result++;
3089
aclpb->aclpb_cache_result[j].aci_index = index;
3090
aclpb->aclpb_cache_result[j].aci_ruleType = aci->aci_ruleType;
3091
} else { /* cache overflow */
3092
slapi_log_error (SLAPI_LOG_FATAL, "acl__TestRights", "cache overflown\n");
3093
if ( rights_rv == ACL_RES_ALLOW) {
3094
result_reason->deciding_aci = aci;
3095
result_reason->reason = ACL_REASON_EVALUATED_ALLOW;
3096
TNF_PROBE_1_DEBUG(acl__TestRights_end,"ACL","",
3097
tnf_string,evaled_allow,"");
3098
return ACL_RES_ALLOW;
3104
__acl_set_aclIndex_inResult ( aclpb, access, index );
3105
if (rights_rv == ACL_RES_ALLOW) {
3106
if (access & SLAPI_ACL_SEARCH) {
3107
aclpb->aclpb_cache_result[j].result |=
3108
ACLPB_CACHE_SEARCH_RES_ALLOW;
3109
} else { /* must be READ */
3110
aclpb->aclpb_cache_result[j].result |=
3111
ACLPB_CACHE_READ_RES_ALLOW;
3114
/* We are done -- return */
3115
result_reason->deciding_aci = aci;
3116
result_reason->reason = ACL_REASON_EVALUATED_ALLOW;
3117
TNF_PROBE_1_DEBUG(acl__TestRights_end,"ACL","",
3118
tnf_string,evaled_allow,"");
3119
return ACL_RES_ALLOW;
3122
if (access & SLAPI_ACL_SEARCH) {
3123
aclpb->aclpb_cache_result[j].result |=
3124
ACLPB_CACHE_SEARCH_RES_SKIP;
3126
aclpb->aclpb_cache_result[j].result |=
3127
ACLPB_CACHE_READ_RES_SKIP;
3132
if ( rights_rv == ACL_RES_ALLOW ) {
3133
result_reason->deciding_aci = aci;
3134
result_reason->reason = ACL_REASON_EVALUATED_ALLOW;
3135
TNF_PROBE_1_DEBUG(acl__TestRights_end,"ACL","",
3136
tnf_string,evaled_allow,"");
3137
return ACL_RES_ALLOW;
3141
result_reason->deciding_aci = aci;
3142
result_reason->reason = ACL_REASON_NO_MATCHED_SUBJECT_ALLOWS;
3144
TNF_PROBE_0_DEBUG(acl__TestRights_end,"ACL","");
3146
return (ACL_RES_DENY);
3148
/***************************************************************************
3150
* acl_match_substring
3152
* Compare the input string to the patteren in the filter
3155
* struct slapi_filter *f - Filter which has the patteren
3156
* char *str - String to compare
3157
* int exact_match - 1; match the pattern exactly
3158
* - 0; match the pattern as a suffix
3161
* ACL_TRUE - The sting matches with the patteren
3162
* ACL_FALSE - No it doesn't
3168
**************************************************************************/
3170
acl_match_substring ( Slapi_Filter *f, char *str, int exact_match)
3174
char *end, *realval, *tmp;
3177
char *type, *initial, *final;
3179
Slapi_Regex *re = NULL;
3180
const char *re_result = NULL;
3182
if ( 0 != slapi_filter_get_subfilt ( f, &type, &initial, &any, &final ) ) {
3186
/* convert the input to lower. */
3187
for (p = str; *p; p++)
3188
*p = TOLOWER ( *p );
3190
/* construct a regular expression corresponding to the filter: */
3193
end = pat + sizeof(pat) - 2; /* leave room for null */
3196
if ( initial != NULL) {
3198
p = strchr (p, '\0');
3200
/* 2 * in case every char is special */
3201
if (p + 2 * strlen ( initial ) > end) {
3202
slapi_log_error (SLAPI_LOG_ACL, plugin_name,
3203
"not enough pattern space\n");
3210
p = strchr (p, '\0');
3212
acl_strcpy_special (p, initial);
3213
p = strchr (p, '\0');
3217
for (i = 0; any && any[i] != NULL; i++) {
3219
if (p + 2 * strlen ( any[i]) + 2 > end) {
3220
slapi_log_error (SLAPI_LOG_ACL, plugin_name,
3221
"not enough pattern space\n");
3226
p = strchr (p, '\0');
3227
acl_strcpy_special (p, any[i]);
3228
p = strchr (p, '\0');
3233
if ( final != NULL) {
3235
if (p + 2 * strlen ( final ) + 2 > end) {
3236
slapi_log_error (SLAPI_LOG_ACL, plugin_name,
3237
"not enough pattern space\n");
3242
p = strchr (p, '\0');
3243
acl_strcpy_special (p, final);
3244
p = strchr (p, '\0');
3248
/* see if regex matches with the input string */
3252
if (len < sizeof(buf)) {
3256
tmp = (char*) slapi_ch_malloc (len + 1);
3261
/* What we have built is a regular pattaren expression.
3262
** Now we will compile the pattern and compare wth the string to
3263
** see if the input string matches with the patteren or not.
3265
re = slapi_re_comp( pat, &re_result );
3267
slapi_log_error (SLAPI_LOG_ACL, plugin_name,
3268
"acl_match_substring:re_comp failed (%s)\n", re_result?re_result:"unknown");
3272
/* slapi_re_exec() returns 1 if the string p1 matches the last compiled
3273
** regular expression, 0 if the string p1 failed to match
3275
rc = slapi_re_exec( re, realval, -1 /* no timelimit */ );
3278
slapi_ch_free ( (void **) &tmp );
3286
/***************************************************************************
3288
* acl__reset_cached_result
3290
* Go thru the cached result and invlalidate the cached evaluation results for
3291
* rules which can only be cached based on the scope.
3292
* If we have scope ACI_CACHE_RESULT_PER_ENTRY, then we need to invalidate the
3293
* cacched reult whenever we hit a new entry.
3298
**************************************************************************/
3300
acl__reset_cached_result (struct acl_pblock *aclpb )
3305
for (j =0; j < aclpb->aclpb_last_cache_result; j++) {
3306
/* Unless we have to clear the result, move on */
3307
if (!( aclpb->aclpb_cache_result[j].aci_ruleType & ACI_CACHE_RESULT_PER_ENTRY))
3309
aclpb->aclpb_cache_result[j].result = 0;
3313
* acl_access_allowed_disjoint_resource
3315
* This is an internal module which can be used to verify
3316
* access to a resource which may not be inside the search scope.
3319
* - Same return val as acl_access_allowed().
3322
acl_access_allowed_disjoint_resource(
3324
Slapi_Entry *e, /* The Slapi_Entry */
3325
char *attr, /* Attribute of the entry */
3326
struct berval *val, /* value of attr. NOT USED */
3327
int access /* access rights */
3332
struct acl_pblock *aclpb = NULL;
3334
aclpb = acl_get_aclpb ( pb, ACLPB_BINDDN_PBLOCK );
3336
** It's possible that we already have a context of ACLs.
3337
** However once in a while, we need to test
3338
** access to a resource which (like vlv, schema) which falls
3339
** outside the search base. In that case, we need to go
3340
** thru all the ACLs and not depend upon the acls which we have
3344
/* If you have the right to use the resource, then we don't need to check for
3345
** proxy right on that resource.
3348
aclpb->aclpb_state |= ( ACLPB_DONOT_USE_CONTEXT_ACLS| ACLPB_DONOT_EVALUATE_PROXY );
3350
rv = acl_access_allowed(pb, e, attr, val, access);
3352
if (aclpb) aclpb->aclpb_state &= ~ACLPB_DONOT_USE_CONTEXT_ACLS;
3353
if (aclpb ) aclpb->aclpb_state &= ~ACLPB_DONOT_EVALUATE_PROXY;
3359
* acl__attr_cached_result
3360
* Loops thru the cached result and determines if we can use the cached value.
3363
* Slapi_pblock *aclpb - acl private block
3364
* char *attr - attribute name
3365
* int access - access type
3367
* LDAP_SUCCESS: - access is granted
3368
* LDAP_INSUFFICIENT_ACCESS - access denied
3369
* ACL_ERR - no cached info about this attr.
3370
* - or the attr had multiple result and so
3371
* - we can't determine the outcome.
3375
acl__attr_cached_result (struct acl_pblock *aclpb, char *attr, int access )
3379
aclEvalContext *c_evalContext;
3381
if ( !(access & ( SLAPI_ACL_SEARCH | SLAPI_ACL_READ) ))
3384
if (aclpb->aclpb_state & ACLPB_HAS_ACLCB_EVALCONTEXT ) {
3385
c_evalContext = &aclpb->aclpb_prev_opEval_context;
3386
slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
3387
"acl__attr_cached_result:Using Context: ACLPB_ACLCB\n" );
3389
c_evalContext = &aclpb->aclpb_prev_entryEval_context;
3390
slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
3391
"acl__attr_cached_result:Using Context: ACLPB_PREV\n" );
3394
if ( attr == NULL ) {
3397
** Do I have access to at least one attribute, then I have
3398
** access to the entry.
3400
for (i=0; i < c_evalContext->acle_numof_attrs; i++ ) {
3401
AclAttrEval *a_eval = &c_evalContext->acle_attrEval[i];
3403
if ( (access & SLAPI_ACL_READ ) && a_eval->attrEval_r_status &&
3404
a_eval->attrEval_r_status < ACL_ATTREVAL_DETERMINISTIC ) {
3406
if ( a_eval->attrEval_r_status & ACL_ATTREVAL_SUCCESS)
3407
return LDAP_SUCCESS;
3408
/* rbyrne: recompute if we have to.
3409
* How does this cached result get turned off for
3410
* attr style acis which acannot be cached becuase entry
3411
* can result in a diff value.
3413
else if ( a_eval->attrEval_r_status & ACL_ATTREVAL_RECOMPUTE ) {
3414
rc = acl__recompute_acl ( aclpb, a_eval, access,
3415
a_eval->attrEval_r_aciIndex);
3416
if ( rc != ACL_ERR ) {
3417
acl_copyEval_context ( aclpb, c_evalContext,
3418
&aclpb->aclpb_curr_entryEval_context, 1);
3420
if ( rc == LDAP_SUCCESS) {
3421
return LDAP_SUCCESS;
3427
* If we have scanned the whole list without success then
3428
* we are not granting access to this entry through access
3429
* to an attribute in the list--however this does not mean
3430
* that we do not have access to the entry via another attribute
3431
* not already in the list, so return -1 meaning
3437
return LDAP_INSUFFICIENT_ACCESS;
3443
for (i=0; i < c_evalContext->acle_numof_attrs; i++ ) {
3444
AclAttrEval *a_eval = &c_evalContext->acle_attrEval[i];
3446
if ( a_eval == NULL ) continue;
3448
if (strcasecmp ( attr, a_eval->attrEval_name ) == 0 ) {
3449
if ( access & SLAPI_ACL_SEARCH ) {
3450
if (a_eval->attrEval_s_status < ACL_ATTREVAL_DETERMINISTIC ) {
3451
if ( a_eval->attrEval_s_status & ACL_ATTREVAL_SUCCESS)
3452
return LDAP_SUCCESS;
3453
else if ( a_eval->attrEval_s_status & ACL_ATTREVAL_FAIL)
3454
return LDAP_INSUFFICIENT_ACCESS;
3455
else if ( a_eval->attrEval_s_status & ACL_ATTREVAL_RECOMPUTE ) {
3456
rc = acl__recompute_acl ( aclpb, a_eval, access,
3457
a_eval->attrEval_s_aciIndex);
3458
if ( rc != ACL_ERR ) {
3459
acl_copyEval_context ( aclpb, c_evalContext,
3460
&aclpb->aclpb_curr_entryEval_context, 1);
3465
/* This means that for the same attribute and same type of
3466
** access, we had different results at different time.
3467
** Since we are not caching per object, we can't
3468
** determine exactly. So, can't touch this
3473
if (a_eval->attrEval_r_status < ACL_ATTREVAL_DETERMINISTIC ) {
3474
if ( a_eval->attrEval_r_status & ACL_ATTREVAL_SUCCESS)
3475
return LDAP_SUCCESS;
3476
else if ( a_eval->attrEval_r_status & ACL_ATTREVAL_FAIL)
3477
return LDAP_INSUFFICIENT_ACCESS;
3478
else if ( a_eval->attrEval_r_status & ACL_ATTREVAL_RECOMPUTE ) {
3479
rc = acl__recompute_acl ( aclpb, a_eval, access,
3480
a_eval->attrEval_r_aciIndex);
3481
if ( rc != ACL_ERR ) {
3482
acl_copyEval_context ( aclpb, c_evalContext,
3483
&aclpb->aclpb_curr_entryEval_context, 1);
3488
/* Look above for explanation */
3498
* Had to do this juggling of casting to make
3499
* both Nt & unix compiler happy.
3502
acl__cmp(const void *a, const void *b)
3504
short *i = (short *) a;
3505
short *j = (short *) b;
3507
if ( (short) *i > (short) *j )
3509
if ( (short)*i < (short) *j)
3515
* acl__scan_match_handles
3516
* Go thru the ACL list and determine if the list of acls selected matches
3517
* what we have in the cache.
3520
* Acl_PBlock *pb - Main pblock ( blacvk hole)
3521
* int type - Which context to look on
3524
* 0 - matches all the acl handles
3525
* ACL_ERR - sorry; no match
3527
* ASSUMPTION: A READER LOCK ON ACL LIST
3530
acl__scan_match_handles ( Acl_PBlock *aclpb, int type)
3538
aclEvalContext *c_evalContext = NULL;
3540
if (type == ACLPB_EVALCONTEXT_PREV ) {
3541
c_evalContext = &aclpb->aclpb_prev_entryEval_context;
3542
} else if ( type == ACLPB_EVALCONTEXT_ACLCB ){
3543
c_evalContext = &aclpb->aclpb_prev_opEval_context;
3549
if ( !c_evalContext->acle_numof_tmatched_handles )
3552
aclpb->aclpb_stat_acllist_scanned++;
3553
aci = acllist_get_first_aci ( aclpb, &cookie );
3556
index = aci->aci_index;
3557
if (acl__resource_match_aci(aclpb, aci, 1 /* skip attr matching */, NULL )) {
3559
int s_matched = matched;
3561
/* We have a sorted list of handles that matched the target */
3563
for (j=0; j < c_evalContext->acle_numof_tmatched_handles ; j++ ) {
3564
if ( c_evalContext->acle_handles_matched_target[j] > index )
3567
else if ( index == c_evalContext->acle_handles_matched_target[j] ) {
3571
/* See if this is a ATTR rule that matched -- in that case we have
3572
** to nullify the cached result
3574
if ( aci->aci_ruleType & ACI_ATTR_RULES ) {
3575
slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
3576
"Found an attr Rule [Name:%s Index:%d\n", aci->aclName,
3578
for ( jj =0; jj < c_evalContext->acle_numof_attrs; jj++ ) {
3579
AclAttrEval *a_eval = &c_evalContext->acle_attrEval[jj];
3580
if ( a_eval->attrEval_r_aciIndex == aci->aci_index )
3581
a_eval->attrEval_r_status = ACL_ATTREVAL_RECOMPUTE;
3582
if ( a_eval->attrEval_s_aciIndex == aci->aci_index )
3583
a_eval->attrEval_s_status = ACL_ATTREVAL_RECOMPUTE;
3589
if ( s_matched == matched ) return ACL_ERR;
3591
aci = acllist_get_next_aci ( aclpb, aci, &cookie );
3593
if ( matched == c_evalContext->acle_numof_tmatched_handles )
3599
* acl_copyEval_context
3600
* Copy the context info which include attr info and handles.
3603
* struct acl_pblock *aclpb - acl private main block
3604
* aclEvalContext *src - src context
3605
* aclEvalContext *dest - dest context
3611
acl_copyEval_context ( struct acl_pblock *aclpb, aclEvalContext *src,
3612
aclEvalContext *dest , int copy_attr_only )
3617
/* Do a CLEAN copy we have nothing or else do an incremental copy.*/
3618
if ( src->acle_numof_attrs < 1 )
3621
/* Copy the attr info */
3622
if ( dest->acle_numof_attrs < 1 )
3623
acl_clean_aclEval_context ( dest, 0 /*clean */ );
3625
d_slot = dest->acle_numof_attrs;
3626
for (i=0; i < src->acle_numof_attrs; i++ ) {
3628
int attr_exists = 0;
3629
int dd_slot = d_slot;
3631
if ( aclpb && (i == 0) ) aclpb->aclpb_stat_num_copycontext++;
3633
if ( src->acle_attrEval[i].attrEval_r_status == 0 &&
3634
src->acle_attrEval[i].attrEval_s_status == 0 )
3637
for ( j = 0; j < dest->acle_numof_attrs; j++ ) {
3638
if ( strcasecmp ( src->acle_attrEval[i].attrEval_name,
3639
dest->acle_attrEval[j].attrEval_name ) == 0 ) {
3640
/* We have it. skip it. */
3646
if ( !attr_exists ) {
3647
if ( dd_slot >= ACLPB_MAX_ATTRS -1 )
3650
if ( aclpb) aclpb->aclpb_stat_num_copy_attrs++;
3652
if ( dest->acle_attrEval[dd_slot].attrEval_name )
3653
slapi_ch_free ( (void **) &dest->acle_attrEval[dd_slot].attrEval_name );
3655
dest->acle_attrEval[dd_slot].attrEval_name =
3656
slapi_ch_strdup ( src->acle_attrEval[i].attrEval_name );
3658
/* Copy the result status and the aci index */
3659
dest->acle_attrEval[dd_slot].attrEval_r_status =
3660
src->acle_attrEval[i].attrEval_r_status;
3661
dest->acle_attrEval[dd_slot].attrEval_r_aciIndex =
3662
src->acle_attrEval[i].attrEval_r_aciIndex;
3663
dest->acle_attrEval[dd_slot].attrEval_s_status =
3664
src->acle_attrEval[i].attrEval_s_status;
3665
dest->acle_attrEval[dd_slot].attrEval_s_aciIndex =
3666
src->acle_attrEval[i].attrEval_s_aciIndex;
3668
if (!attr_exists ) d_slot++;
3671
dest->acle_numof_attrs = d_slot;
3672
dest->acle_attrEval[d_slot].attrEval_name = NULL;
3674
if ( copy_attr_only )
3677
/* First sort the arrays which keeps the acl index numbers */
3678
qsort ( (char *) src->acle_handles_matched_target,
3679
(size_t)src->acle_numof_tmatched_handles, sizeof( int ), acl__cmp );
3681
for (i=0; i < src->acle_numof_tmatched_handles; i++ ) {
3682
dest->acle_handles_matched_target[i] =
3683
src->acle_handles_matched_target[i];
3686
if ( src->acle_numof_tmatched_handles ) {
3687
dest->acle_numof_tmatched_handles = src->acle_numof_tmatched_handles;
3688
if ( aclpb) aclpb->aclpb_stat_num_tmatched_acls = src->acle_numof_tmatched_handles;
3693
* acl_clean_aclEval_context
3694
* Clean the eval context
3697
* aclEvalContext *clean_me - COntext to be cleaned
3698
* int clean_type - 0: clean, 1 scrub
3703
acl_clean_aclEval_context ( aclEvalContext *clean_me, int scrub_only )
3707
/* Copy the attr info */
3708
for (i=0; i < clean_me->acle_numof_attrs; i++ ) {
3710
char *a_name = clean_me->acle_attrEval[i].attrEval_name;
3711
if ( a_name && !scrub_only) {
3712
slapi_ch_free ( (void **) &a_name );
3713
clean_me->acle_attrEval[i].attrEval_name = NULL;
3715
clean_me->acle_attrEval[i].attrEval_r_status = 0;
3716
clean_me->acle_attrEval[i].attrEval_s_status = 0;
3717
clean_me->acle_attrEval[i].attrEval_r_aciIndex = 0;
3718
clean_me->acle_attrEval[i].attrEval_s_aciIndex = 0;
3721
if ( !scrub_only ) clean_me->acle_numof_attrs = 0;
3722
clean_me->acle_numof_tmatched_handles = 0;
3725
* acl__match_handlesFromCache
3727
* We have 2 cacheed information
3728
* 1) cached info from the previous operation
3729
* 2) cached info from the prev entry evaluation
3731
* What we are doing here is going thru all the acls and see if the same
3732
* set of acls apply to this resource or not. If it does, then do we have
3733
* a cached info for the attr. If we don't for both of the cases then we need
3734
* to evaluate all over again.
3737
* struct acl_pblock - ACL private block;
3738
* char *attr - Attribute name
3739
* int access - acces type
3742
* LDAP_SUCCESS (0) - The same acls apply and we have
3743
* access ALLOWED on the attr
3744
* LDAP_INSUFFICIENT_ACCESS - The same acls apply and we have
3745
* access DENIED on the attr
3746
* -1 - Acls doesn't match or we don't have
3747
* cached info for this attr.
3749
* ASSUMPTIONS: A reader lock has been obtained for the acl list.
3752
acl__match_handlesFromCache ( Acl_PBlock *aclpb, char *attr, int access)
3755
aclEvalContext *c_evalContext = NULL;
3756
int context_type = 0;
3757
int ret_val = -1; /* it doen't match by default */
3759
/* Before we proceed, find out if we have evaluated any ATTR RULE. If we have
3760
** then we can't use any caching mechanism
3763
if ( aclpb->aclpb_state & ACLPB_HAS_ACLCB_EVALCONTEXT ) {
3764
context_type = ACLPB_EVALCONTEXT_ACLCB;
3765
c_evalContext = &aclpb->aclpb_prev_opEval_context;
3767
context_type = ACLPB_EVALCONTEXT_PREV;
3768
c_evalContext = &aclpb->aclpb_prev_entryEval_context;
3772
if ( aclpb->aclpb_res_type & (ACLPB_NEW_ENTRY | ACLPB_EFFECTIVE_RIGHTS) ) {
3773
aclpb->aclpb_state |= ACLPB_MATCHES_ALL_ACLS;
3774
ret_val = acl__scan_match_handles ( aclpb, context_type );
3775
if ( -1 == ret_val ) {
3776
aclpb->aclpb_state &= ~ACLPB_MATCHES_ALL_ACLS;
3777
aclpb->aclpb_state |= ACLPB_UPD_ACLCB_CACHE;
3779
if ( context_type == ACLPB_EVALCONTEXT_ACLCB ) {
3780
aclpb->aclpb_state &= ~ACLPB_HAS_ACLCB_EVALCONTEXT;
3782
aclpb->aclpb_state |= ACLPB_COPY_EVALCONTEXT;
3783
c_evalContext->acle_numof_tmatched_handles = 0;
3787
if ( aclpb->aclpb_state & ACLPB_MATCHES_ALL_ACLS ) {
3788
/* See if we have a cached result for this attr */
3789
ret_val = acl__attr_cached_result (aclpb, attr, access);
3791
/* It's not in the ACLCB context but we might have it in the
3792
** current/prev context. Take a look at it. we might have evaluated
3793
** this attribute already.
3795
if ( (-1 == ret_val ) &&
3796
( aclpb->aclpb_state & ACLPB_HAS_ACLCB_EVALCONTEXT )) {
3797
aclpb->aclpb_state &= ~ACLPB_HAS_ACLCB_EVALCONTEXT ;
3798
ret_val = acl__attr_cached_result (aclpb, attr, access);
3799
aclpb->aclpb_state |= ACLPB_HAS_ACLCB_EVALCONTEXT ;
3801
/* We need to do an incremental update */
3802
if ( !ret_val ) aclpb->aclpb_state |= ACLPB_INCR_ACLCB_CACHE;
3809
* Get the atteval from the current context and hold the ptr in aclpb.
3810
* If we have too many attrs, then allocate a new one. In that case
3811
* we let the caller know about that so that it will be deallocated.
3814
* int - 0: The context was indexed. So, no allocations.
3815
* - 1; context was allocated - deallocate it.
3818
acl__get_attrEval ( struct acl_pblock *aclpb, char *attr )
3822
aclEvalContext *c_ContextEval = &aclpb->aclpb_curr_entryEval_context;
3823
int deallocate_attrEval = 0;
3824
AclAttrEval *c_attrEval = NULL;
3826
if ( !attr ) return deallocate_attrEval;
3828
aclpb->aclpb_curr_attrEval = NULL;
3830
/* Go thru and see if we have the attr already */
3831
for (j=0; j < c_ContextEval->acle_numof_attrs; j++) {
3832
c_attrEval = &c_ContextEval->acle_attrEval[j];
3835
slapi_attr_type_cmp ( c_attrEval->attrEval_name, attr, 1) == 0 ) {
3836
aclpb->aclpb_curr_attrEval = c_attrEval;
3841
if ( !aclpb->aclpb_curr_attrEval) {
3842
if ( c_ContextEval->acle_numof_attrs == ACLPB_MAX_ATTRS -1 ) {
3843
/* Too many attrs. create a temp one */
3844
c_attrEval = (AclAttrEval * ) slapi_ch_calloc ( 1, sizeof ( AclAttrEval ) );
3845
deallocate_attrEval =1;
3847
c_attrEval = &c_ContextEval->acle_attrEval[c_ContextEval->acle_numof_attrs++];
3848
c_attrEval->attrEval_r_status = 0;
3849
c_attrEval->attrEval_s_status = 0;
3850
c_attrEval->attrEval_r_aciIndex = 0;
3851
c_attrEval->attrEval_s_aciIndex = 0;
3853
/* clean it before use */
3854
c_attrEval->attrEval_name = slapi_ch_strdup ( attr );
3855
aclpb->aclpb_curr_attrEval = c_attrEval;
3857
return deallocate_attrEval;
3860
* acl_skip_access_check
3862
* See if we need to go thru the ACL check or not. We don't need to if I am root
3863
* or internal operation or ...
3866
* ACL_TRUE - Yes; skip the ACL check
3867
* ACL_FALSE - No; you have to go thru ACL check
3871
acl_skip_access_check ( Slapi_PBlock *pb, Slapi_Entry *e )
3873
int rv, isRoot, accessCheckDisabled;
3877
slapi_pblock_get ( pb, SLAPI_REQUESTOR_ISROOT, &isRoot );
3878
if ( isRoot ) return ACL_TRUE;
3880
/* See if this is local request */
3881
slapi_pblock_get ( pb, SLAPI_CONNECTION, &conn);
3883
if ( NULL == conn ) return ACL_TRUE;
3886
* Turn on access checking in the rootdse--this code used
3887
* to skip the access check.
3889
* check if the entry is the RootDSE entry
3891
char * edn = slapi_entry_get_ndn ( e );
3892
if ( slapi_is_rootdse ( edn ) ) return ACL_TRUE;
3896
/* GB : when referrals are directly set in the mappin tree
3897
* we can reach this code without a backend in the pblock
3898
* in such a case, allow access for now
3899
* we may want to reconsider this is NULL DSE implementation happens
3901
rv = slapi_pblock_get ( pb, SLAPI_BACKEND, &be );
3905
rv = slapi_pblock_get ( pb, SLAPI_PLUGIN_DB_NO_ACL, &accessCheckDisabled );
3906
if ( rv != -1 && accessCheckDisabled ) return ACL_TRUE;
3911
acl_get_aclsignature ()
3913
return acl_signature;
3916
acl_set_aclsignature ( short value)
3918
acl_signature = value;
3921
acl_regen_aclsignature ()
3923
acl_signature = aclutil_gen_signature ( acl_signature );
3930
* 1) Called for read/search right.
3933
acl__recompute_acl ( Acl_PBlock *aclpb,
3934
AclAttrEval *a_eval,
3941
char *unused_str1, *unused_str2;
3942
char *acl_tag, *testRight[2];
3944
int result_status = ACL_RES_INVALID, cache_result;
3949
PR_ASSERT ( aciIndex >= 0 );
3950
PR_ASSERT ( a_eval != NULL );
3951
PR_ASSERT (aclpb != NULL );
3954
/* We might have evaluated this acl just now, check it there first */
3956
for ( j =0; j < aclpb->aclpb_last_cache_result; j++) {
3957
if (aciIndex == aclpb->aclpb_cache_result[j].aci_index) {
3959
result_status =ACL_RES_INVALID;
3961
result = aclpb->aclpb_cache_result[j].result;
3962
if ( result <= 0) break;
3963
if (!ACL_CACHED_RESULT_VALID(result)) {
3964
/* something is wrong. Need to evaluate */
3965
aclpb->aclpb_cache_result[j].result = -1;
3971
** We have a valid cached result. Let's see if we
3972
** have what we need.
3974
if ((result & ACLPB_CACHE_SEARCH_RES_ALLOW) ||
3975
(result & ACLPB_CACHE_READ_RES_ALLOW) )
3976
result_status = ACL_RES_ALLOW;
3977
else if ((result & ACLPB_CACHE_SEARCH_RES_DENY) ||
3978
(result & ACLPB_CACHE_READ_RES_DENY) )
3979
result_status = ACL_RES_DENY;
3984
if ( result_status != ACL_RES_INVALID ) {
3985
goto set_result_status;
3988
slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
3989
"Recomputing the ACL Index:%d for entry:%s\n",
3990
aciIndex, slapi_entry_get_ndn ( aclpb->aclpb_curr_entry) );
3992
/* First find this one ACL and then evaluate it. */
3995
aci = acllist_get_first_aci ( aclpb, &cookie );
3996
while ( aci && aci->aci_index != aciIndex ) {
3997
aci = acllist_get_next_aci ( aclpb, aci, &cookie );
4004
ACL_SetDefaultResult (NULL, aclpb->aclpb_acleval, ACL_RES_INVALID);
4005
ACL_EvalSetACL(NULL, aclpb->aclpb_acleval, aci->aci_handle);
4007
testRight[0] = acl_access2str ( access );
4008
testRight[1] = '\0';
4009
aclpb->aclpb_curr_aci = aci;
4010
result_status = ACL_EvalTestRights (NULL, aclpb->aclpb_acleval, testRight,
4011
ds_map_generic, &unused_str1,
4013
&acl_tag, &expr_num);
4016
if ( result_status == ACL_RES_DENY && aci->aci_type & ACI_HAS_DENY_RULE ) {
4017
if ( access & SLAPI_ACL_SEARCH)
4018
cache_result = ACLPB_CACHE_SEARCH_RES_DENY;
4020
cache_result = ACLPB_CACHE_READ_RES_DENY;
4021
} else if ( result_status == ACL_RES_ALLOW && aci->aci_type & ACI_HAS_ALLOW_RULE ) {
4022
if ( access & SLAPI_ACL_SEARCH)
4023
cache_result = ACLPB_CACHE_SEARCH_RES_ALLOW;
4025
cache_result = ACLPB_CACHE_READ_RES_ALLOW;
4031
/* Now we need to put the cached result in the aclpb */
4033
for (j=0; j <aclpb->aclpb_last_cache_result; ++j) {
4034
if (aciIndex == aclpb->aclpb_cache_result[j].aci_index) {
4039
if ( j < aclpb->aclpb_last_cache_result) {
4040
/* already in cache */
4041
} else if ( j < aclpb_max_cache_results-1) {
4042
/* rbyrneXXX: make this same as other last_cache_result code! */
4043
j = ++aclpb->aclpb_last_cache_result;
4044
aclpb->aclpb_cache_result[j].aci_index = aci->aci_index;
4045
aclpb->aclpb_cache_result[j].aci_ruleType = aci->aci_ruleType;
4047
} else { /* No more space */
4048
goto set_result_status;
4051
/* Add the cached result status */
4052
aclpb->aclpb_cache_result[j].result |= cache_result;
4057
if (result_status == ACL_RES_ALLOW) {
4058
if (access & SLAPI_ACL_SEARCH)
4059
/*wrong bit maskes were being used here--
4060
a_eval->attrEval_s_status = ACLPB_CACHE_SEARCH_RES_ALLOW;*/
4061
a_eval->attrEval_s_status = ACL_ATTREVAL_SUCCESS;
4063
a_eval->attrEval_r_status = ACL_ATTREVAL_SUCCESS;
4065
} else if ( result_status == ACL_RES_DENY) {
4066
if (access & SLAPI_ACL_SEARCH)
4067
a_eval->attrEval_s_status = ACL_ATTREVAL_FAIL;
4069
a_eval->attrEval_r_status = ACL_ATTREVAL_FAIL;
4071
/* Here, set it to recompute--try again later */
4072
if (access & SLAPI_ACL_SEARCH)
4073
a_eval->attrEval_s_status = ACL_ATTREVAL_RECOMPUTE;
4075
a_eval->attrEval_r_status = ACL_ATTREVAL_RECOMPUTE;
4079
return result_status;
4083
__acl_set_aclIndex_inResult ( Acl_PBlock *aclpb, int access, int index )
4085
AclAttrEval *c_attrEval = aclpb->aclpb_curr_attrEval;
4088
if ( access & SLAPI_ACL_SEARCH )
4089
c_attrEval->attrEval_s_aciIndex = index;
4090
else if ( access & SLAPI_ACL_READ )
4091
c_attrEval->attrEval_r_aciIndex = index;
4096
* If filter_sense is true then return (entry satisfies f).
4097
* Otherwise, return !(entry satisfies f)
4101
acl__test_filter ( Slapi_Entry *entry, struct slapi_filter *f, int filter_sense) {
4104
/* slapi_vattr_filter_test() returns 0 for match */
4106
filter_matched = !slapi_vattr_filter_test(NULL, entry,
4108
0 /*don't do acess chk*/);
4111
return(filter_matched ? ACL_TRUE : ACL_FALSE);
4113
return(filter_matched ? ACL_FALSE: ACL_TRUE);
4118
* Make an entry consisting of attr_type and attr_val and put
4119
* a pointer to it in *entry.
4120
* We will use this afterwards to test for against a filter.
4124
acl__make_filter_test_entry ( Slapi_Entry **entry, char *attr_type,
4125
struct berval *attr_val) {
4127
struct berval *vals_array[2];
4129
vals_array[0] = attr_val;
4130
vals_array[1] = NULL;
4132
*entry = slapi_entry_alloc();
4133
slapi_entry_init(*entry, NULL, NULL);
4135
return (slapi_entry_add_values( *entry, (const char *)attr_type,
4136
(struct berval**)&vals_array[0] ));
4140
/*********************************************************************************/
4142
/*********************************************************************************/