summaryrefslogtreecommitdiffstats
path: root/ldap/servers/slapd/search.c
diff options
context:
space:
mode:
authorNoriko Hosoi <nhosoi@redhat.com>2008-06-27 19:28:22 +0000
committerNoriko Hosoi <nhosoi@redhat.com>2008-06-27 19:28:22 +0000
commit70425fbcea96d1b477fea27eca67fb7e828c446e (patch)
tree7142ac3a793a263cafbd486458fcaeb7c092e54d /ldap/servers/slapd/search.c
parentb643fa2279635381cdb0ff6d62f39b93f6a6e22f (diff)
downloadds-70425fbcea96d1b477fea27eca67fb7e828c446e.tar.gz
ds-70425fbcea96d1b477fea27eca67fb7e828c446e.tar.xz
ds-70425fbcea96d1b477fea27eca67fb7e828c446e.zip
Resolves: #437525
Summary: GER: allow GER for non-existing entries Description: [slapd/charray.c] new: charray_merge_nodup -- merge 2 string arrays skipping the duplicates modified: charray_remove -- introduced "freeit" flag. If true, the removed string is freed. (The API is used only in chainingdb. The change is applied to the plugin.) [slapd/opshared.c] modified: check OP_FLAG_GET_EFFECTIVE_RIGHTS in the iterate to support "@<objectclass>". It's needed to do at the location since we have to call acl plugin even when no entries are returned from the search. If no entries are returned and "@<objectclass>" is found in the attribute list, acl effective rights code generates the corresponding template entry. [slapd/pblock.c] place to store gerattrs is added (SLAPI_SEARCH_GERATTRS), where gerattrs is an array of strings which store "...@<objectclass>". [slapd/result.c] moved OP_FLAG_GET_EFFECTIVE_RIGHTS checking to iterate (opshared.c) [slapd/schema.c] new: slapi_schema_list_objectclass_attributes -- return the required and/or allowed attributes belonging to the given objectclass. This is used to support "*" and "+" in the get effective rights. new: slapi_schema_get_superior_name -- return the superior objectclass name of the given objectclass. [slapd/search.c] if "<attr>@<objectclass>" is found in the attribute list, cut the <attr> part out and added to the attrs array (pblock SLAPI_SEARCH_ATTRS) and store the original string to the gerattrs (pblock SLAPI_SEARCH_GERATTRS). [plugin/acl/acleffectiverights.c] modified: _ger_g_permission_granted -- if the requester and the subject user are identical, give "g" permission modified: _ger_parse_control -- replaced strcpy with memmove since strcpy does not guarantee the result of the overlap copy. modified: _ger_get_attrs_rights -- support "*" (all attributes belonging to the object) and "+" (operational attributes). If repeated attributes are found in the given attribute list, they are reduced to one. new: _ger_generate_template_entry -- generate a template entry if "@<objectclass>" is passed. [pluginc/cb/*] adjusted to the updated charray_remove. Please see also this wiki page for the overview and test cases. http://directory.fedoraproject.org/wiki/Get_Effective_Rights_for_non-present_attributes
Diffstat (limited to 'ldap/servers/slapd/search.c')
-rw-r--r--ldap/servers/slapd/search.c329
1 files changed, 201 insertions, 128 deletions
diff --git a/ldap/servers/slapd/search.c b/ldap/servers/slapd/search.c
index dcd8265c..c3d1c80d 100644
--- a/ldap/servers/slapd/search.c
+++ b/ldap/servers/slapd/search.c
@@ -65,92 +65,93 @@ void
do_search( Slapi_PBlock *pb )
{
Slapi_Operation *operation;
- BerElement *ber;
- int i, err, attrsonly;
- ber_int_t scope, deref, sizelimit, timelimit;
- char *base = NULL, *fstr = NULL;
- struct slapi_filter *filter = NULL;
- char **attrs = NULL;
- int psearch = 0;
- struct berval *psbvp;
- ber_int_t changetypes;
+ BerElement *ber;
+ int i, err, attrsonly;
+ ber_int_t scope, deref, sizelimit, timelimit;
+ char *base = NULL, *fstr = NULL;
+ struct slapi_filter *filter = NULL;
+ char **attrs = NULL;
+ char **gerattrs = NULL;
+ int psearch = 0;
+ struct berval *psbvp;
+ ber_int_t changetypes;
int send_entchg_controls;
int changesonly = 0;
int rc = -1;
char *original_base = 0;
char *new_base = 0;
- LDAPDebug( LDAP_DEBUG_TRACE, "do_search\n", 0, 0, 0 );
+ LDAPDebug( LDAP_DEBUG_TRACE, "do_search\n", 0, 0, 0 );
slapi_pblock_get( pb, SLAPI_OPERATION, &operation);
- ber = operation->o_ber;
+ ber = operation->o_ber;
- /* count the search request */
- snmp_increment_counter(g_get_global_snmp_vars()->ops_tbl.dsSearchOps);
+ /* count the search request */
+ snmp_increment_counter(g_get_global_snmp_vars()->ops_tbl.dsSearchOps);
- /*
- * Parse the search request. It looks like this:
- *
- * SearchRequest := [APPLICATION 3] SEQUENCE {
- * baseObject DistinguishedName,
- * scope ENUMERATED {
- * baseObject (0),
- * singleLevel (1),
- * wholeSubtree (2)
- * },
- * derefAliases ENUMERATED {
- * neverDerefaliases (0),
- * derefInSearching (1),
- * derefFindingBaseObj (2),
- * alwaysDerefAliases (3)
- * },
- * sizelimit INTEGER (0 .. 65535),
- * timelimit INTEGER (0 .. 65535),
- * attrsOnly BOOLEAN,
- * filter Filter,
- * attributes SEQUENCE OF AttributeType
- * }
- */
+ /*
+ * Parse the search request. It looks like this:
+ *
+ * SearchRequest := [APPLICATION 3] SEQUENCE {
+ * baseObject DistinguishedName,
+ * scope ENUMERATED {
+ * baseObject (0),
+ * singleLevel (1),
+ * wholeSubtree (2)
+ * },
+ * derefAliases ENUMERATED {
+ * neverDerefaliases (0),
+ * derefInSearching (1),
+ * derefFindingBaseObj (2),
+ * alwaysDerefAliases (3)
+ * },
+ * sizelimit INTEGER (0 .. 65535),
+ * timelimit INTEGER (0 .. 65535),
+ * attrsOnly BOOLEAN,
+ * filter Filter,
+ * attributes SEQUENCE OF AttributeType
+ * }
+ */
- /* baseObject, scope, derefAliases, sizelimit, timelimit, attrsOnly */
- if ( ber_scanf( ber, "{aiiiib", &base, &scope, &deref, &sizelimit, &timelimit, &attrsonly ) == LBER_ERROR ){
- slapi_ch_free((void**)&base );
- log_search_access (pb, "???", -1, "???", "decoding error");
- send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, NULL, 0, NULL );
- return;
- }
+ /* baseObject, scope, derefAliases, sizelimit, timelimit, attrsOnly */
+ if ( ber_scanf( ber, "{aiiiib", &base, &scope, &deref, &sizelimit, &timelimit, &attrsonly ) == LBER_ERROR ){
+ slapi_ch_free((void**)&base );
+ log_search_access (pb, "???", -1, "???", "decoding error");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, NULL, 0, NULL );
+ return;
+ }
- /*
- * ignore negative time and size limits since they make no sense
- */
- if ( timelimit < 0 ) {
+ /*
+ * ignore negative time and size limits since they make no sense
+ */
+ if ( timelimit < 0 ) {
timelimit = 0;
- }
- if ( sizelimit < 0 ) {
+ }
+ if ( sizelimit < 0 ) {
sizelimit = 0;
- }
+ }
- if ( scope != LDAP_SCOPE_BASE && scope != LDAP_SCOPE_ONELEVEL
+ if ( scope != LDAP_SCOPE_BASE && scope != LDAP_SCOPE_ONELEVEL
&& scope != LDAP_SCOPE_SUBTREE ) {
log_search_access (pb, base, scope, "???", "Unknown search scope");
- send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL,
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL,
"Unknown search scope", 0, NULL );
- goto free_and_return;
- }
- /* check and record the scope for snmp */
- if ( scope == LDAP_SCOPE_ONELEVEL) {
+ goto free_and_return;
+ }
+ /* check and record the scope for snmp */
+ if ( scope == LDAP_SCOPE_ONELEVEL) {
/* count the one level search request */
snmp_increment_counter(g_get_global_snmp_vars()->ops_tbl.dsOneLevelSearchOps);
- } else if (scope == LDAP_SCOPE_SUBTREE) {
+ } else if (scope == LDAP_SCOPE_SUBTREE) {
/* count the subtree search request */
snmp_increment_counter(g_get_global_snmp_vars()->ops_tbl.dsWholeSubtreeSearchOps);
- }
+ }
- /* filter - returns a "normalized" version */
- filter = NULL;
- fstr = NULL;
- if ( (err = get_filter( pb->pb_conn, ber, scope, &filter, &fstr )) != 0 ) {
+ /* filter - returns a "normalized" version */
+ filter = NULL;
+ fstr = NULL;
+ if ( (err = get_filter( pb->pb_conn, ber, scope, &filter, &fstr )) != 0 ) {
char *errtxt;
if ( LDAP_UNWILLING_TO_PERFORM == err ) {
@@ -159,18 +160,18 @@ do_search( Slapi_PBlock *pb )
errtxt = "Bad search filter";
}
log_search_access( pb, base, scope, "???", errtxt );
- send_ldap_result( pb, err, NULL, errtxt, 0, NULL );
- goto free_and_return;
- }
+ send_ldap_result( pb, err, NULL, errtxt, 0, NULL );
+ goto free_and_return;
+ }
- /* attributes */
- attrs = NULL;
- if ( ber_scanf( ber, "{v}}", &attrs ) == LBER_ERROR ) {
+ /* attributes */
+ attrs = NULL;
+ if ( ber_scanf( ber, "{v}}", &attrs ) == LBER_ERROR ) {
log_search_access (pb, base, scope, fstr, "decoding error");
- send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, NULL, 0,
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, NULL, 0,
NULL );
- goto free_and_return;
- }
+ goto free_and_return;
+ }
/*
* This search is performed against the legacy consumer, so ask explicitly
@@ -186,56 +187,128 @@ do_search( Slapi_PBlock *pb )
charray_add(&attrs, slapi_attr_syntax_normalize("aci"));
charray_add(&attrs, slapi_attr_syntax_normalize(LDAP_ALL_USER_ATTRS));
}
- else
+ }
+
+ if ( attrs != NULL ) {
+ int gerattrsiz = 1;
+ int gerattridx = 0;
+ int aciin = 0;
+ /*
+ * . store gerattrs if any
+ * . add "aci" once if "*" is given
+ */
+ for ( i = 0; attrs[i] != NULL; i++ )
{
- for ( i = 0; attrs[i] != NULL; i++ )
+ char *p = NULL;
+ /* check if @<objectclass> is included */
+ p = strchr(attrs[i], '@');
+ if ( p && '\0' != *(p+1) ) /* don't store "*@", e.g. */
{
- if ( strcasecmp(attrs[i], LDAP_ALL_USER_ATTRS) == 0 )
+ int j = 0;
+ if (gerattridx + 1 >= gerattrsiz)
+ {
+ char **tmpgerattrs;
+ gerattrsiz *= 2;
+ tmpgerattrs =
+ (char **)slapi_ch_calloc(1, gerattrsiz*sizeof(char *));
+ if (NULL != gerattrs)
+ {
+ memcpy(tmpgerattrs, gerattrs, gerattrsiz*sizeof(char *));
+ slapi_ch_free((void **)&gerattrs);
+ }
+ gerattrs = tmpgerattrs;
+ }
+ for ( j = 0; gerattrs; j++ )
{
- charray_add(&attrs, slapi_attr_syntax_normalize("aci"));
- break;
+ char *attri = NULL;
+ if ( NULL == gerattrs[j] )
+ {
+ if (0 == j)
+ {
+ /* first time */
+ gerattrs[gerattridx++] = attrs[i];
+ /* get rid of "@<objectclass>" part from the attr
+ list, which is needed only in gerattr list */
+ *p = '\0';
+ attri = slapi_ch_strdup(attrs[i]);
+ attrs[i] = attri;
+ *p = '@';
+ }
+ else
+ {
+ break; /* done */
+ }
+ }
+ else if ( 0 == strcasecmp( attrs[i], gerattrs[j] ))
+ {
+ /* skip if attrs[i] is already in gerattrs */
+ continue;
+ }
+ else
+ {
+ char *q = strchr(gerattrs[j], '@'); /* q never be 0 */
+ if ( 0 != strcasecmp( p+1, q+1 ))
+ {
+ /* you don't want to display the same template
+ entry multiple times */
+ gerattrs[gerattridx++] = attrs[i];
+ }
+ /* get rid of "@<objectclass>" part from the attr
+ list, which is needed only in gerattr list */
+ *p = '\0';
+ attri = slapi_ch_strdup(attrs[i]);
+ attrs[i] = attri;
+ *p = '@';
+ }
}
}
+ else if ( !aciin && strcasecmp(attrs[i], LDAP_ALL_USER_ATTRS) == 0 )
+ {
+ charray_add(&attrs, slapi_attr_syntax_normalize("aci"));
+ aciin = 1;
+ }
+ }
+ if (NULL != gerattrs)
+ {
+ gerattrs[gerattridx] = NULL;
}
- }
- if ( attrs != NULL ) {
- operation->o_searchattrs = cool_charray_dup( attrs );
- for ( i = 0; attrs[i] != NULL; i++ ) {
- char *type;
+ operation->o_searchattrs = cool_charray_dup( attrs );
+ for ( i = 0; attrs[i] != NULL; i++ ) {
+ char *type;
- type = slapi_attr_syntax_normalize(attrs[i]);
- slapi_ch_free( (void**)&(attrs[i]) );
- attrs[i] = type;
- }
- }
- if ( slapd_ldap_debug & LDAP_DEBUG_ARGS ) {
- char abuf[ 1024 ], *astr;
+ type = slapi_attr_syntax_normalize(attrs[i]);
+ slapi_ch_free( (void**)&(attrs[i]) );
+ attrs[i] = type;
+ }
+ }
+ if ( slapd_ldap_debug & LDAP_DEBUG_ARGS ) {
+ char abuf[ 1024 ], *astr;
- if ( NULL == attrs ) {
- astr = "ALL";
- } else {
- strarray2str( attrs, abuf, sizeof( abuf ), 1 /* include quotes */);
- astr = abuf;
+ if ( NULL == attrs ) {
+ astr = "ALL";
+ } else {
+ strarray2str( attrs, abuf, sizeof( abuf ), 1 /* include quotes */);
+ astr = abuf;
+ }
+ slapi_log_error( SLAPI_LOG_ARGS, NULL, "SRCH base=\"%s\" "
+ "scope=%d deref=%d "
+ "sizelimit=%d timelimit=%d attrsonly=%d filter=\"%s\" "
+ "attrs=%s\n", base, scope, deref, sizelimit, timelimit,
+ attrsonly, fstr, astr );
}
- slapi_log_error( SLAPI_LOG_ARGS, NULL, "SRCH base=\"%s\" "
- "scope=%d deref=%d "
- "sizelimit=%d timelimit=%d attrsonly=%d filter=\"%s\" "
- "attrs=%s\n", base, scope, deref, sizelimit, timelimit,
- attrsonly, fstr, astr );
- }
- /*
- * in LDAPv3 there can be optional control extensions on
- * the end of an LDAPMessage. we need to read them in and
- * pass them to the backend. get_ldapmessage_controls()
- * reads the controls and sets any we know about in the pb.
- */
- if ( (err = get_ldapmessage_controls( pb, ber, NULL )) != 0 ) {
+ /*
+ * in LDAPv3 there can be optional control extensions on
+ * the end of an LDAPMessage. we need to read them in and
+ * pass them to the backend. get_ldapmessage_controls()
+ * reads the controls and sets any we know about in the pb.
+ */
+ if ( (err = get_ldapmessage_controls( pb, ber, NULL )) != 0 ) {
log_search_access (pb, base, scope, fstr, "failed to decode LDAP controls");
- send_ldap_result( pb, err, NULL, NULL, 0, NULL );
- goto free_and_return;
- }
+ send_ldap_result( pb, err, NULL, NULL, 0, NULL );
+ goto free_and_return;
+ }
/* we support persistent search for regular operations only */
if ( slapi_control_present( operation->o_params.request_controls,
@@ -254,15 +327,16 @@ do_search( Slapi_PBlock *pb )
}
}
- slapi_pblock_set( pb, SLAPI_SEARCH_TARGET, base );
+ slapi_pblock_set( pb, SLAPI_SEARCH_TARGET, base );
slapi_pblock_set( pb, SLAPI_ORIGINAL_TARGET_DN, slapi_ch_strdup(base) );
- slapi_pblock_set( pb, SLAPI_SEARCH_SCOPE, &scope );
- slapi_pblock_set( pb, SLAPI_SEARCH_DEREF, &deref );
- slapi_pblock_set( pb, SLAPI_SEARCH_FILTER, filter );
- slapi_pblock_set( pb, SLAPI_SEARCH_STRFILTER, fstr );
- slapi_pblock_set( pb, SLAPI_SEARCH_ATTRS, attrs );
- slapi_pblock_set( pb, SLAPI_SEARCH_ATTRSONLY, &attrsonly );
- slapi_pblock_set( pb, SLAPI_REQUESTOR_ISROOT, &operation->o_isroot );
+ slapi_pblock_set( pb, SLAPI_SEARCH_SCOPE, &scope );
+ slapi_pblock_set( pb, SLAPI_SEARCH_DEREF, &deref );
+ slapi_pblock_set( pb, SLAPI_SEARCH_FILTER, filter );
+ slapi_pblock_set( pb, SLAPI_SEARCH_STRFILTER, fstr );
+ slapi_pblock_set( pb, SLAPI_SEARCH_ATTRS, attrs );
+ slapi_pblock_set( pb, SLAPI_SEARCH_GERATTRS, gerattrs );
+ slapi_pblock_set( pb, SLAPI_SEARCH_ATTRSONLY, &attrsonly );
+ slapi_pblock_set( pb, SLAPI_REQUESTOR_ISROOT, &operation->o_isroot );
slapi_pblock_set( pb, SLAPI_SEARCH_SIZELIMIT, &sizelimit );
slapi_pblock_set( pb, SLAPI_SEARCH_TIMELIMIT, &timelimit );
@@ -277,23 +351,22 @@ do_search( Slapi_PBlock *pb )
slapi_pblock_get(pb, SLAPI_SEARCH_TARGET, &new_base);
slapi_pblock_get (pb, SLAPI_PLUGIN_OPRETURN, &rc);
- slapi_pblock_get( pb, SLAPI_SEARCH_FILTER, &filter );
+ slapi_pblock_get( pb, SLAPI_SEARCH_FILTER, &filter );
- if ( psearch && rc == 0 ) {
+ if ( psearch && rc == 0 ) {
ps_add( pb, changetypes, send_entchg_controls );
- }
+ }
free_and_return:;
- if ( !psearch || rc < 0 ) {
+ if ( !psearch || rc < 0 ) {
if(original_base != new_base) {
slapi_ch_free_string(&new_base);
}
- slapi_ch_free_string(&base);
- slapi_ch_free_string(&fstr);
- slapi_filter_free( filter, 1 );
- if ( attrs != NULL ) {
- charray_free( attrs );
- }
+ slapi_ch_free_string(&base);
+ slapi_ch_free_string(&fstr);
+ slapi_filter_free( filter, 1 );
+ charray_free( attrs ); /* passing NULL is fine */
+ charray_free( gerattrs ); /* passing NULL is fine */
/*
* Fix for defect 526719 / 553356 : Persistent search op failed.
* Marking it as non-persistent so that operation resources get freed
@@ -304,7 +377,7 @@ free_and_return:;
/* we strdup'd this above - need to free */
slapi_pblock_get(pb, SLAPI_ORIGINAL_TARGET_DN, &base);
slapi_ch_free_string(&base);
- }
+ }
}
static void log_search_access (Slapi_PBlock *pb, const char *base, int scope, const char *fstr, const char *msg)