diff options
author | Noriko Hosoi <nhosoi@redhat.com> | 2008-06-27 19:28:22 +0000 |
---|---|---|
committer | Noriko Hosoi <nhosoi@redhat.com> | 2008-06-27 19:28:22 +0000 |
commit | 70425fbcea96d1b477fea27eca67fb7e828c446e (patch) | |
tree | 7142ac3a793a263cafbd486458fcaeb7c092e54d /ldap/servers/slapd/search.c | |
parent | b643fa2279635381cdb0ff6d62f39b93f6a6e22f (diff) | |
download | ds-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.c | 329 |
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) |