Author: nhosoi
Update of /cvs/dirsec/ldapserver/ldap/servers/plugins/acl In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv6584/ldap/servers/plugins/acl
Modified Files: acleffectiverights.c Log Message: 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...
Index: acleffectiverights.c =================================================================== RCS file: /cvs/dirsec/ldapserver/ldap/servers/plugins/acl/acleffectiverights.c,v retrieving revision 1.7 retrieving revision 1.8 diff -u -r1.7 -r1.8 --- acleffectiverights.c 18 Oct 2007 00:08:27 -0000 1.7 +++ acleffectiverights.c 27 Jun 2008 19:28:22 -0000 1.8 @@ -46,7 +46,13 @@ /* news2 is optional, provided as a convenience */ /* capacity is the capacity of the gerstr, size is the current length */ static void -_append_gerstr(char **gerstr, size_t *capacity, size_t *size, const char *news, const char *news2) +_append_gerstr( + char **gerstr, + size_t *capacity, + size_t *size, + const char *news, + const char *news2 + ) { size_t len; size_t increment = 128; @@ -90,7 +96,12 @@ }
static int -_ger_g_permission_granted ( Slapi_PBlock *pb, Slapi_Entry *e, char **errbuf ) +_ger_g_permission_granted ( + Slapi_PBlock *pb, + Slapi_Entry *e, + const char *subjectdn, + char **errbuf + ) { char *proxydn = NULL; Slapi_DN *requestor_sdn, *entry_sdn; @@ -151,6 +162,14 @@ goto bailout; }
+ /* if the requestor and the subject user are identical, let's grant it */ + if ( strcasecmp ( slapi_sdn_get_ndn(requestor_sdn), subjectdn ) == 0) + { + /* Requestor should see his own permission rights on any entry */ + rc = LDAP_SUCCESS; + goto bailout; + } + aclutil_str_appened ( errbuf, "get-effective-rights: requestor has no g permission on the entry" ); slapi_log_error (SLAPI_LOG_ACL, plugin_name, "_ger_g_permission_granted: %s\n", *errbuf); @@ -166,11 +185,17 @@ }
static int -_ger_parse_control ( Slapi_PBlock *pb, char **subjectndn, int *iscritical, char **errbuf ) +_ger_parse_control ( + Slapi_PBlock *pb, + char **subjectndn, + int *iscritical, + char **errbuf + ) { LDAPControl **requestcontrols; struct berval *subjectber; BerElement *ber; + int subjectndnlen = 0;
if (NULL == subjectndn) { @@ -231,7 +256,8 @@ * (see section 9 of RFC 2829) only. It also only supports the "dnAuthzId" * flavor, which looks like "dn:<DN>" where null <DN> is for anonymous. */ - if ( NULL == *subjectndn || strlen (*subjectndn) < 3 || + subjectndnlen = strlen(*subjectndn); + if ( NULL == *subjectndn || subjectndnlen < 3 || strncasecmp ( "dn:", *subjectndn, 3 ) != 0 ) { aclutil_str_appened ( errbuf, "get-effective-rights: subject is not dnAuthzId" ); @@ -239,7 +265,8 @@ return LDAP_INVALID_SYNTAX; }
- strcpy ( *subjectndn, *subjectndn + 3 ); + /* memmove is safe for overlapping copy */ + memmove ( *subjectndn, *subjectndn + 3, subjectndnlen - 2);/* 1 for '\0' */ slapi_dn_normalize ( *subjectndn ); return LDAP_SUCCESS; } @@ -533,6 +560,27 @@ return attrrights; }
+#define GER_GET_ATTR_RIGHTS(attrs) \ + for (thisattr = (attrs); thisattr && *thisattr; thisattr++) \ + { \ + _ger_get_attr_rights (gerpb, e, subjectndn, *thisattr, \ + gerstr, gerstrsize, gerstrcap, isfirstattr, errbuf); \ + isfirstattr = 0; \ + } \ + +#define GER_GET_ATTR_RIGHTA_EXT(c, inattrs, exattrs); \ + for ( i = 0; attrs[i]; i++ ) \ + { \ + if ((c) != *attrs[i] && charray_inlist((inattrs), attrs[i]) && \ + !charray_inlist((exattrs), attrs[i])) \ + { \ + _ger_get_attr_rights ( gerpb, e, subjectndn, attrs[i], \ + gerstr, gerstrsize, gerstrcap, isfirstattr, errbuf ); \ + isfirstattr = 0; \ + } \ + } + + void _ger_get_attrs_rights ( Slapi_PBlock *gerpb, @@ -552,12 +600,76 @@
if (attrs && *attrs) { - int i; - for ( i = 0; attrs[i]; i++ ) + int i = 0; + char **allattrs = NULL; + char **opattrs = NULL; + char **myattrs = NULL; + char **thisattr = NULL; + int hasstar = charray_inlist(attrs, "*"); + int hasplus = charray_inlist(attrs, "+"); + Slapi_Attr *objclasses = NULL; + Slapi_ValueSet *objclassvals = NULL; + + /* get all attrs available for the entry */ + slapi_entry_attr_find(e, "objectclass", &objclasses); + if (NULL != objclasses) { + Slapi_Value *v; + slapi_attr_get_valueset(objclasses, &objclassvals); + i = slapi_valueset_first_value(objclassvals, &v); + if (-1 != i) { + allattrs = slapi_schema_list_objectclass_attributes( + (const char *)v->bv.bv_val, + SLAPI_OC_FLAG_REQUIRED|SLAPI_OC_FLAG_ALLOWED); + /* add "aci" to the allattrs to adjust to do_search */ + charray_add(&allattrs, slapi_attr_syntax_normalize("aci")); + while (-1 != i) + { + i = slapi_valueset_next_value(objclassvals, i, &v); + if (-1 != i) + { + myattrs = slapi_schema_list_objectclass_attributes( + (const char *)v->bv.bv_val, + SLAPI_OC_FLAG_REQUIRED|SLAPI_OC_FLAG_ALLOWED); + charray_merge_nodup(&allattrs, myattrs, 1/*copy_strs*/); + charray_free(myattrs); + } + } + } + } + + /* get operational attrs */ + opattrs = slapi_schema_list_attribute_names(SLAPI_ATTR_FLAG_OPATTR); + + if (hasstar && hasplus) + { + GER_GET_ATTR_RIGHTS(allattrs); + GER_GET_ATTR_RIGHTS(opattrs); + } + else if (hasstar) { - _ger_get_attr_rights ( gerpb, e, subjectndn, attrs[i], gerstr, gerstrsize, gerstrcap, isfirstattr, errbuf ); - isfirstattr = 0; + GER_GET_ATTR_RIGHTS(allattrs); + GER_GET_ATTR_RIGHTA_EXT('*', opattrs, allattrs); } + else if (hasplus) + { + GER_GET_ATTR_RIGHTS(opattrs); + GER_GET_ATTR_RIGHTA_EXT('+', allattrs, opattrs); + } + else + { + for ( i = 0; attrs[i]; i++ ) + { + if (charray_inlist(allattrs, attrs[i]) || + charray_inlist(opattrs, attrs[i])) + { + _ger_get_attr_rights ( gerpb, e, subjectndn, attrs[i], + gerstr, gerstrsize, gerstrcap, isfirstattr, errbuf ); + isfirstattr = 0; + } + } + } + charray_free(allattrs); + charray_free(opattrs); } else { @@ -569,7 +681,8 @@ if ( ! slapi_attr_flag_is_set (attr, SLAPI_ATTR_FLAG_OPATTR) ) { slapi_attr_get_type ( attr, &type ); - _ger_get_attr_rights ( gerpb, e, subjectndn, type, gerstr, gerstrsize, gerstrcap, isfirstattr, errbuf ); + _ger_get_attr_rights ( gerpb, e, subjectndn, type, gerstr, + gerstrsize, gerstrcap, isfirstattr, errbuf ); isfirstattr = 0; } prevattr = attr; @@ -648,6 +761,131 @@ }
int +_ger_generate_template_entry ( + Slapi_PBlock *pb + ) +{ + Slapi_Entry *e = NULL; + char **gerattrs = NULL; + char **attrs = NULL; + char *templateentry = NULL; + char *object = NULL; + char *superior = NULL; + char *p = NULL; + int siz = 0; + int len = 0; + int i = 0; + int notfirst = 0; + int rc = LDAP_SUCCESS; + + slapi_pblock_get( pb, SLAPI_SEARCH_GERATTRS, &gerattrs ); + if (NULL == gerattrs) + { + slapi_log_error (SLAPI_LOG_FATAL, plugin_name, + "Objectclass info is expected " + "in the attr list, e.g., "*@person"\n"); + rc = LDAP_SUCCESS; + goto bailout; + } + for (i = 0; gerattrs && gerattrs[i]; i++) + { + object = strchr(gerattrs[i], '@'); + if (NULL != object && '\0' != *(++object)) + { + break; + } + } + if (NULL == object) + { + rc = LDAP_SUCCESS; /* no objectclass info; ok to return */ + goto bailout; + } + attrs = slapi_schema_list_objectclass_attributes( + (const char *)object, SLAPI_OC_FLAG_REQUIRED); + if (NULL == attrs) + { + rc = LDAP_SUCCESS; /* bogus objectclass info; ok to return */ + goto bailout; + } + for (i = 0; attrs[i]; i++) + { + if (0 == strcasecmp(attrs[i], "objectclass")) + { + /* <*attrp>: <object>\n\0 */ + siz += strlen(attrs[i]) + 4 + strlen(object); + } + else + { + /* <*attrp>: dummy\n\0 */ + siz += strlen(attrs[i]) + 4 + 5; + } + } + siz += 32 + strlen(object); /* dn: cn=<template_name>\n\0 */ + templateentry = (char *)slapi_ch_malloc(siz); + PR_snprintf(templateentry, siz, + "dn: cn=template_%s_objectclass\n", object); + for (--i; i >= 0; i--) + { + len = strlen(templateentry); + p = templateentry + len; + if (0 == strcasecmp(attrs[i], "objectclass")) + { + PR_snprintf(p, siz - len, "%s: %s\n", attrs[i], object); + } + else + { + PR_snprintf(p, siz - len, "%s: dummy\n", attrs[i]); + } + } + charray_free(attrs); + + while ((superior = slapi_schema_get_superior_name(object)) && + (0 != strcasecmp(superior, "top"))) + { + if (notfirst) + { + slapi_ch_free_string(&object); + } + notfirst = 1; + object = superior; + attrs = slapi_schema_list_objectclass_attributes( + (const char *)superior, SLAPI_OC_FLAG_REQUIRED); + for (i = 0; attrs && attrs[i]; i++) + { + if (0 == strcasecmp(attrs[i], "objectclass")) + { + /* <*attrp>: <object>\n\0 */ + siz += strlen(attrs[i]) + 4 + strlen(object); + } + } + templateentry = (char *)slapi_ch_realloc(templateentry, siz); + for (--i; i >= 0; i--) + { + len = strlen(templateentry); + p = templateentry + len; + if (0 == strcasecmp(attrs[i], "objectclass")) + { + PR_snprintf(p, siz - len, "%s: %s\n", attrs[i], object); + } + } + charray_free(attrs); + } + slapi_ch_free_string(&superior); + siz += 18; /* objectclass: top\n\0 */ + len = strlen(templateentry); + templateentry = (char *)slapi_ch_realloc(templateentry, siz); + p = templateentry + len; + PR_snprintf(p, siz - len, "objectclass: top\n"); + + e = slapi_str2entry(templateentry, SLAPI_STR2ENTRY_NOT_WELL_FORMED_LDIF); + /* set the template entry to send the result to clients */ + slapi_pblock_set(pb, SLAPI_SEARCH_RESULT_ENTRY, e); +bailout: + slapi_ch_free_string(&templateentry); + return rc; +} + +int acl_get_effective_rights ( Slapi_PBlock *pb, Slapi_Entry *e, /* target entry */ @@ -664,10 +902,20 @@ size_t gerstrsize = 0; size_t gerstrcap = 0; int iscritical = 1; - int rc; + int rc = LDAP_SUCCESS;
*errbuf = '\0';
+ if (NULL == e) /* create a template entry from SLAPI_SEARCH_GERATTRS */ + { + rc = _ger_generate_template_entry ( pb ); + slapi_pblock_get ( pb, SLAPI_SEARCH_RESULT_ENTRY, &e ); + if ( rc != LDAP_SUCCESS || NULL == e ) + { + goto bailout; + } + } + /* * Get the subject */ @@ -681,7 +929,7 @@ * The requestor should have g permission on the entry * to get the effective rights. */ - rc = _ger_g_permission_granted (pb, e, errbuf); + rc = _ger_g_permission_granted (pb, e, subjectndn, errbuf); if ( rc != LDAP_SUCCESS ) { goto bailout; @@ -718,7 +966,7 @@
slapi_log_error (SLAPI_LOG_ACLSUMMARY, plugin_name, "###### Effective Rights on Entry (%s) for Subject (%s) ######\n", - slapi_entry_get_ndn (e), subjectndn); + e?slapi_entry_get_ndn(e):"null", subjectndn?subjectndn:"null"); slapi_log_error (SLAPI_LOG_ACLSUMMARY, plugin_name, "%s\n", gerstr);
/* Restore pb */
389-commits@lists.fedoraproject.org