summaryrefslogtreecommitdiffstats
path: root/ldap/servers/plugins/acl/acleffectiverights.c
diff options
context:
space:
mode:
Diffstat (limited to 'ldap/servers/plugins/acl/acleffectiverights.c')
-rw-r--r--ldap/servers/plugins/acl/acleffectiverights.c674
1 files changed, 674 insertions, 0 deletions
diff --git a/ldap/servers/plugins/acl/acleffectiverights.c b/ldap/servers/plugins/acl/acleffectiverights.c
new file mode 100644
index 00000000..1e250e96
--- /dev/null
+++ b/ldap/servers/plugins/acl/acleffectiverights.c
@@ -0,0 +1,674 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2004 Netscape Communications Corporation
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "acl.h"
+
+static int
+_ger_g_permission_granted ( Slapi_PBlock *pb, Slapi_Entry *e, char **errbuf )
+{
+ char *proxydn = NULL;
+ Slapi_DN *requestor_sdn, *entry_sdn;
+ char *errtext = NULL;
+ int isroot;
+ int rc;
+
+ /*
+ * Theorically, we should check if the entry has "g"
+ * permission granted to the requestor. If granted,
+ * allows the effective rights on that entry and its
+ * attributes within the entry to be returned for
+ * ANY subject.
+ *
+ * "G" permission granting has not been implemented yet,
+ * the current release assumes that "g" permission be
+ * granted to root and owner of any entry.
+ */
+
+ /*
+ * The requestor may be either the bind dn or a proxy dn
+ */
+ acl_get_proxyauth_dn ( pb, &proxydn, &errtext );
+ if ( proxydn != NULL )
+ {
+ requestor_sdn = slapi_sdn_new_dn_passin ( proxydn );
+ }
+ else
+ {
+ requestor_sdn = &(pb->pb_op->o_sdn);
+ }
+ if ( slapi_sdn_get_dn (requestor_sdn) == NULL )
+ {
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "_ger_g_permission_granted: anonymous has no g permission\n" );
+ rc = LDAP_INSUFFICIENT_ACCESS;
+ goto bailout;
+ }
+ isroot = slapi_dn_isroot ( slapi_sdn_get_dn (requestor_sdn) );
+ if ( isroot )
+ {
+ /* Root has "g" permission on any entry */
+ rc = LDAP_SUCCESS;
+ goto bailout;
+ }
+
+ entry_sdn = slapi_entry_get_sdn ( e );
+ if ( entry_sdn == NULL || slapi_sdn_get_dn (entry_sdn) == NULL )
+ {
+ rc = LDAP_SUCCESS;
+ goto bailout;
+ }
+
+ if ( slapi_sdn_compare ( requestor_sdn, entry_sdn ) == 0 )
+ {
+ /* Owner has "g" permission on his own 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);
+ rc = LDAP_INSUFFICIENT_ACCESS;
+
+bailout:
+ if ( proxydn )
+ {
+ /* The ownership of proxydn has passed to requestor_sdn */
+ slapi_sdn_free ( &requestor_sdn );
+ }
+ return rc;
+}
+
+static int
+_ger_parse_control ( Slapi_PBlock *pb, char **subjectndn, int *iscritical, char **errbuf )
+{
+ LDAPControl **requestcontrols;
+ struct berval *subjectber;
+ BerElement *ber;
+
+ if (NULL == subjectndn)
+ {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ *subjectndn = NULL;
+
+ /*
+ * Get the control
+ */
+ slapi_pblock_get ( pb, SLAPI_REQCONTROLS, (void *) &requestcontrols );
+ slapi_control_present ( requestcontrols,
+ LDAP_CONTROL_GET_EFFECTIVE_RIGHTS,
+ &subjectber,
+ iscritical );
+ if ( subjectber == NULL || subjectber->bv_val == NULL ||
+ subjectber->bv_len == 0 )
+ {
+ aclutil_str_appened ( errbuf, "get-effective-rights: missing subject" );
+ slapi_log_error (SLAPI_LOG_FATAL, plugin_name, "%s\n", *errbuf );
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ if ( strncasecmp ( "dn:", subjectber->bv_val, 3 ) == 0 )
+ {
+ /*
+ * This is a non-standard support to allow the subject being a plain
+ * or base64 encoding string. Hence users using -J option in
+ * ldapsearch don't have to do BER encoding for the subject.
+ */
+ *subjectndn = slapi_ch_malloc ( subjectber->bv_len + 1 );
+ strncpy ( *subjectndn, subjectber->bv_val, subjectber->bv_len );
+ *(*subjectndn + subjectber->bv_len) = '\0';
+ }
+ else
+ {
+ ber = ber_init (subjectber);
+ if ( ber == NULL )
+ {
+ aclutil_str_appened ( errbuf, "get-effective-rights: ber_init failed for the subject" );
+ slapi_log_error (SLAPI_LOG_FATAL, plugin_name, "%s\n", *errbuf );
+ return LDAP_OPERATIONS_ERROR;
+ }
+ /* "a" means to allocate storage as needed for octet string */
+ if ( ber_scanf (ber, "a", subjectndn) == LBER_ERROR )
+ {
+ aclutil_str_appened ( errbuf, "get-effective-rights: invalid ber tag in the subject" );
+ slapi_log_error (SLAPI_LOG_FATAL, plugin_name, "%s\n", *errbuf );
+ ber_free ( ber, 1 );
+ return LDAP_INVALID_SYNTAX;
+ }
+ ber_free ( ber, 1 );
+ }
+
+ /*
+ * The current implementation limits the subject to authorization ID
+ * (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 ||
+ strncasecmp ( "dn:", *subjectndn, 3 ) != 0 )
+ {
+ aclutil_str_appened ( errbuf, "get-effective-rights: subject is not dnAuthzId" );
+ slapi_log_error (SLAPI_LOG_FATAL, plugin_name, "%s\n", *errbuf );
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ strcpy ( *subjectndn, *subjectndn + 3 );
+ slapi_dn_normalize ( *subjectndn );
+ return LDAP_SUCCESS;
+}
+
+static void
+_ger_release_gerpb (
+ Slapi_PBlock **gerpb,
+ void **aclcb, /* original aclcb */
+ Slapi_PBlock *pb /* original pb */
+ )
+{
+ if ( *gerpb )
+ {
+ /* Return conn to pb */
+ slapi_pblock_set ( *gerpb, SLAPI_CONNECTION, NULL );
+ slapi_pblock_destroy ( *gerpb );
+ *gerpb = NULL;
+ }
+
+ /* Put the original aclcb back to pb */
+ if ( *aclcb )
+ {
+ Connection *conn = NULL;
+ slapi_pblock_get ( pb, SLAPI_CONNECTION, &conn );
+ if (conn)
+ {
+ struct aclcb *geraclcb;
+ geraclcb = (struct aclcb *) acl_get_ext ( ACL_EXT_CONNECTION, conn );
+ acl_conn_ext_destructor ( geraclcb, NULL, NULL );
+ acl_set_ext ( ACL_EXT_CONNECTION, conn, *aclcb );
+ *aclcb = NULL;
+ }
+ }
+}
+
+static int
+_ger_new_gerpb (
+ Slapi_PBlock *pb,
+ Slapi_Entry *e,
+ const char *subjectndn,
+ Slapi_PBlock **gerpb,
+ void **aclcb, /* original aclcb */
+ char **errbuf
+ )
+{
+ Connection *conn;
+ struct acl_cblock *geraclcb;
+ Acl_PBlock *aclpb, *geraclpb;
+ Operation *op, *gerop;
+ int rc = LDAP_SUCCESS;
+
+ *aclcb = NULL;
+ *gerpb = slapi_pblock_new ();
+ if ( *gerpb == NULL )
+ {
+ rc = LDAP_NO_MEMORY;
+ goto bailout;
+ }
+
+ {
+ /* aclpb initialization needs the backend */
+ Slapi_Backend *be;
+ slapi_pblock_get ( pb, SLAPI_BACKEND, &be );
+ slapi_pblock_set ( *gerpb, SLAPI_BACKEND, be );
+ }
+
+ {
+ int isroot = slapi_dn_isroot ( subjectndn );
+ slapi_pblock_set ( *gerpb, SLAPI_REQUESTOR_ISROOT, &isroot );
+ }
+
+ /* Save requestor's aclcb and set subjectdn's one */
+ {
+ slapi_pblock_get ( pb, SLAPI_CONNECTION, &conn );
+ slapi_pblock_set ( *gerpb, SLAPI_CONNECTION, conn );
+
+ /* Can't share the conn->aclcb because of different context */
+ geraclcb = (struct acl_cblock *) acl_conn_ext_constructor ( NULL, NULL);
+ if ( geraclcb == NULL )
+ {
+ rc = LDAP_NO_MEMORY;
+ goto bailout;
+ }
+ slapi_sdn_set_ndn_byval ( geraclcb->aclcb_sdn, subjectndn );
+ *aclcb = acl_get_ext ( ACL_EXT_CONNECTION, conn );
+ acl_set_ext ( ACL_EXT_CONNECTION, conn, (void *) geraclcb );
+ }
+
+ {
+ gerop = operation_new ( OP_FLAG_INTERNAL );
+ if ( gerop == NULL )
+ {
+ rc = LDAP_NO_MEMORY;
+ goto bailout;
+ }
+ /*
+ * conn is a no-use parameter in the functions
+ * chained down from factory_create_extension
+ */
+ gerop->o_extension = factory_create_extension ( get_operation_object_type(), (void *)gerop, (void *)conn );
+ slapi_pblock_set ( *gerpb, SLAPI_OPERATION, gerop );
+ slapi_sdn_set_dn_byval ( &gerop->o_sdn, subjectndn );
+ geraclpb = acl_get_ext ( ACL_EXT_OPERATION, (void *)gerop);
+ acl_init_aclpb ( *gerpb, geraclpb, subjectndn, 0 );
+ geraclpb->aclpb_res_type |= ACLPB_EFFECTIVE_RIGHTS;
+ }
+
+
+bailout:
+ if ( rc != LDAP_SUCCESS )
+ {
+ _ger_release_gerpb ( gerpb, aclcb, pb );
+ }
+
+ return rc;
+}
+
+/*
+ * Callers should have already allocated *gerstr to hold at least
+ * "entryLevelRights: adnvxxx\n".
+ */
+unsigned long
+_ger_get_entry_rights (
+ Slapi_PBlock *gerpb,
+ Slapi_Entry *e,
+ const char *subjectndn,
+ char *gerstr,
+ char **errbuf
+ )
+{
+ unsigned long entryrights = 0;
+ Slapi_RDN *rdn = NULL;
+ const char *rdnstr = NULL;
+ char *equalsign = NULL;
+ char *rdntype = NULL;
+
+ strcpy ( gerstr, "entryLevelRights: " );
+
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "_ger_get_entry_rights: SLAPI_ACL_READ\n" );
+ if (acl_access_allowed(gerpb, e, "*", NULL, SLAPI_ACL_READ) == LDAP_SUCCESS)
+ {
+ /* v - view e */
+ entryrights |= SLAPI_ACL_READ;
+ strcat (gerstr, "v");
+ }
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "_ger_get_entry_rights: SLAPI_ACL_ADD\n" );
+ if (acl_access_allowed(gerpb, e, NULL, NULL, SLAPI_ACL_ADD) == LDAP_SUCCESS)
+ {
+ /* a - add child entry below e */
+ entryrights |= SLAPI_ACL_ADD;
+ strcat (gerstr, "a");
+ }
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "_ger_get_entry_rights: SLAPI_ACL_DELETE\n" );
+ if (acl_access_allowed(gerpb, e, NULL, NULL, SLAPI_ACL_DELETE) == LDAP_SUCCESS)
+ {
+ /* d - delete e */
+ entryrights |= SLAPI_ACL_DELETE;
+ strcat (gerstr, "d");
+ }
+ /*
+ * Some limitation/simplification applied here:
+ * - The modrdn right requires the rights to delete the old rdn and
+ * the new one. However we have no knowledge of what the new rdn
+ * is going to be.
+ * - In multi-valued RDN case, we check the right on
+ * the first rdn type only for now.
+ */
+ rdn = slapi_rdn_new_dn ( slapi_entry_get_ndn (e) );
+ rdnstr = slapi_rdn_get_rdn ( rdn );
+ if ( NULL != (equalsign = strchr ( rdnstr, '=' )) )
+ {
+ rdntype = slapi_ch_malloc ( equalsign-rdnstr+1 );
+ strncpy ( rdntype, rdnstr, equalsign-rdnstr );
+ rdntype [ equalsign-rdnstr ] = '\0';
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "_ger_get_entry_rights: SLAPI_ACL_WRITE_DEL & _ADD %s\n", rdntype );
+ if (acl_access_allowed(gerpb, e, rdntype, NULL,
+ ACLPB_SLAPI_ACL_WRITE_DEL) == LDAP_SUCCESS &&
+ acl_access_allowed(gerpb, e, rdntype, NULL,
+ ACLPB_SLAPI_ACL_WRITE_ADD) == LDAP_SUCCESS)
+ {
+ /* n - rename e */
+ entryrights |= SLAPI_ACL_WRITE;
+ strcat (gerstr, "n");
+ }
+ slapi_ch_free ( (void**) &rdntype );
+ }
+ slapi_rdn_free ( &rdn );
+
+done:
+ if ( entryrights == 0 )
+ {
+ strcat (gerstr, "none");
+ }
+
+ strcat (gerstr, "\n");
+
+ return entryrights;
+}
+
+/*
+ * *gerstr should point to a heap buffer since it may need
+ * to expand dynamically.
+ */
+unsigned long
+_ger_get_attr_rights (
+ Slapi_PBlock *gerpb,
+ Slapi_Entry *e,
+ const char *subjectndn,
+ char *type,
+ char **gerstr,
+ int *gerstrsize,
+ int isfirstattr,
+ char **errbuf
+ )
+{
+ unsigned long attrrights = 0;
+
+ /* Enough space for " $type:rwoscxx" ? */
+ if ( (*gerstrsize - strlen(*gerstr)) < (strlen(type) + 16) )
+ {
+ /* slapi_ch_realloc() exits if realloc() failed */
+ *gerstrsize += 256;
+ *gerstr = slapi_ch_realloc ( *gerstr, *gerstrsize );
+ }
+ if (!isfirstattr)
+ {
+ strcat ( *gerstr, ", " );
+ }
+ sprintf ( *gerstr + strlen(*gerstr), "%s:", type );
+
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "_ger_get_attr_rights: SLAPI_ACL_READ %s\n", type );
+ if (acl_access_allowed(gerpb, e, type, NULL, SLAPI_ACL_READ) == LDAP_SUCCESS)
+ {
+ /* r - read the values of type */
+ attrrights |= SLAPI_ACL_READ;
+ strcat (*gerstr, "r");
+ }
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "_ger_get_attr_rights: SLAPI_ACL_SEARCH %s\n", type );
+ if (acl_access_allowed(gerpb, e, type, NULL, SLAPI_ACL_SEARCH) == LDAP_SUCCESS)
+ {
+ /* s - search the values of type */
+ attrrights |= SLAPI_ACL_SEARCH;
+ strcat (*gerstr, "s");
+ }
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "_ger_get_attr_rights: SLAPI_ACL_COMPARE %s\n", type );
+ if (acl_access_allowed(gerpb, e, type, NULL, SLAPI_ACL_COMPARE) == LDAP_SUCCESS)
+ {
+ /* c - compare the values of type */
+ attrrights |= SLAPI_ACL_COMPARE;
+ strcat (*gerstr, "c");
+ }
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "_ger_get_attr_rights: SLAPI_ACL_WRITE_ADD %s\n", type );
+ if (acl_access_allowed(gerpb, e, type, NULL, ACLPB_SLAPI_ACL_WRITE_ADD) == LDAP_SUCCESS)
+ {
+ /* w - add the values of type */
+ attrrights |= ACLPB_SLAPI_ACL_WRITE_ADD;
+ strcat (*gerstr, "w");
+ }
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "_ger_get_attr_rights: SLAPI_ACL_WRITE_DEL %s\n", type );
+ if (acl_access_allowed(gerpb, e, type, NULL, ACLPB_SLAPI_ACL_WRITE_DEL) == LDAP_SUCCESS)
+ {
+ /* o - delete the values of type */
+ attrrights |= ACLPB_SLAPI_ACL_WRITE_DEL;
+ strcat (*gerstr, "o");
+ }
+ /* If subjectdn has no general write right, check for self write */
+ if ( 0 == (attrrights & (ACLPB_SLAPI_ACL_WRITE_DEL | ACLPB_SLAPI_ACL_WRITE_ADD)) )
+ {
+ struct berval val;
+
+ val.bv_val = (char *)subjectndn;
+ val.bv_len = strlen (subjectndn);
+
+ if (acl_access_allowed(gerpb, e, type, &val, ACLPB_SLAPI_ACL_WRITE_ADD) == LDAP_SUCCESS)
+ {
+ /* W - add self to the attribute */
+ attrrights |= ACLPB_SLAPI_ACL_WRITE_ADD;
+ strcat (*gerstr, "W");
+ }
+ if (acl_access_allowed(gerpb, e, type, &val, ACLPB_SLAPI_ACL_WRITE_DEL) == LDAP_SUCCESS)
+ {
+ /* O - delete self from the attribute */
+ attrrights |= ACLPB_SLAPI_ACL_WRITE_DEL;
+ strcat (*gerstr, "O");
+ }
+ }
+
+ if ( attrrights == 0 )
+ {
+ strcat (*gerstr, "none");
+ }
+
+ return attrrights;
+}
+
+void
+_ger_get_attrs_rights (
+ Slapi_PBlock *gerpb,
+ Slapi_Entry *e,
+ const char *subjectndn,
+ char **attrs,
+ char **gerstr,
+ int *gerstrsize,
+ char **errbuf
+ )
+{
+ int isfirstattr = 1;
+
+ /* gerstr was initially allocated with enough space for one more line */
+ strcat ( *gerstr, "attributeLevelRights: " );
+
+ if (attrs && *attrs)
+ {
+ int i;
+ for ( i = 0; attrs[i]; i++ )
+ {
+ _ger_get_attr_rights ( gerpb, e, subjectndn, attrs[i], gerstr, gerstrsize, isfirstattr, errbuf );
+ isfirstattr = 0;
+ }
+ }
+ else
+ {
+ Slapi_Attr *prevattr = NULL, *attr;
+ char *type;
+
+ while ( slapi_entry_next_attr ( e, prevattr, &attr ) == 0 )
+ {
+ 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, isfirstattr, errbuf );
+ isfirstattr = 0;
+ }
+ prevattr = attr;
+ }
+ }
+
+ if ( isfirstattr )
+ {
+ /* not a single attribute was retrived or specified */
+ strcat ( *gerstr, "*:none" );
+ }
+ return;
+}
+
+/*
+ * controlType = LDAP_CONTROL_GET_EFFECTIVE_RIGHTS;
+ * criticality = n/a;
+ * controlValue = OCTET STRING of BER encoding of the SEQUENCE of
+ * ENUMERATED LDAP code
+ */
+void
+_ger_set_response_control (
+ Slapi_PBlock *pb,
+ int iscritical,
+ int rc
+ )
+{
+ LDAPControl **resultctrls = NULL;
+ LDAPControl gerrespctrl;
+ BerElement *ber = NULL;
+ struct berval *berval = NULL;
+ int found = 0;
+ int i;
+
+ if ( (ber = der_alloc ()) == NULL )
+ {
+ goto bailout;
+ }
+
+ /* begin sequence, enumeration, end sequence */
+ ber_printf ( ber, "{e}", rc );
+ if ( ber_flatten ( ber, &berval ) != LDAP_SUCCESS )
+ {
+ goto bailout;
+ }
+ gerrespctrl.ldctl_oid = LDAP_CONTROL_GET_EFFECTIVE_RIGHTS;
+ gerrespctrl.ldctl_iscritical = iscritical;
+ gerrespctrl.ldctl_value.bv_val = berval->bv_val;
+ gerrespctrl.ldctl_value.bv_len = berval->bv_len;
+
+ slapi_pblock_get ( pb, SLAPI_RESCONTROLS, &resultctrls );
+ for (i = 0; resultctrls && resultctrls[i]; i++)
+ {
+ if (strcmp(resultctrls[i]->ldctl_oid, LDAP_CONTROL_GET_EFFECTIVE_RIGHTS) == 0)
+ {
+ /*
+ * We get here if search returns more than one entry
+ * and this is not the first entry.
+ */
+ ldap_control_free ( resultctrls[i] );
+ resultctrls[i] = slapi_dup_control (&gerrespctrl);
+ found = 1;
+ break;
+ }
+ }
+
+ if ( !found )
+ {
+ /* slapi_pblock_set() will dup the control */
+ slapi_pblock_set ( pb, SLAPI_ADD_RESCONTROL, &gerrespctrl );
+ }
+
+bailout:
+ ber_free ( ber, 1 ); /* ber_free() checks for NULL param */
+ ber_bvfree ( berval ); /* ber_bvfree() checks for NULL param */
+}
+
+int
+acl_get_effective_rights (
+ Slapi_PBlock *pb,
+ Slapi_Entry *e, /* target entry */
+ char **attrs, /* Attribute of the entry */
+ struct berval *val, /* value of attr. NOT USED */
+ int access, /* requested access rights */
+ char **errbuf
+ )
+{
+ Slapi_PBlock *gerpb = NULL;
+ void *aclcb = NULL;
+ char *subjectndn = NULL;
+ char *gerstr = NULL;
+ int gerstrsize = 1024;
+ unsigned long entryrights;
+ int iscritical = 1;
+ int rc;
+
+ *errbuf = '\0';
+ gerstr = slapi_ch_malloc ( gerstrsize );
+
+ /*
+ * Get the subject
+ */
+ rc = _ger_parse_control (pb, &subjectndn, &iscritical, errbuf );
+ if ( rc != LDAP_SUCCESS )
+ {
+ goto bailout;
+ }
+
+ /*
+ * The requestor should have g permission on the entry
+ * to get the effective rights.
+ */
+ rc = _ger_g_permission_granted (pb, e, errbuf);
+ if ( rc != LDAP_SUCCESS )
+ {
+ goto bailout;
+ }
+
+ /*
+ * Construct a new pb
+ */
+ rc = _ger_new_gerpb ( pb, e, subjectndn, &gerpb, &aclcb, errbuf );
+ if ( rc != LDAP_SUCCESS )
+ {
+ goto bailout;
+ }
+
+ /* Get entry level effective rights */
+ entryrights = _ger_get_entry_rights ( gerpb, e, subjectndn, gerstr, errbuf );
+
+ /*
+ * Attribute level effective rights may not be NULL
+ * even if entry level's is.
+ */
+ _ger_get_attrs_rights ( gerpb, e, subjectndn, attrs, &gerstr, &gerstrsize, errbuf );
+
+bailout:
+ /*
+ * Now construct the response control
+ */
+ _ger_set_response_control ( pb, iscritical, rc );
+
+ if ( rc != LDAP_SUCCESS )
+ {
+ sprintf ( gerstr, "entryLevelRights: %d\nattributeLevelRights: *:%d", rc, rc );
+ }
+
+ slapi_log_error (SLAPI_LOG_ACLSUMMARY, plugin_name,
+ "###### Effective Rights on Entry (%s) for Subject (%s) ######\n",
+ slapi_entry_get_ndn (e), subjectndn);
+ slapi_log_error (SLAPI_LOG_ACLSUMMARY, plugin_name, "%s\n", gerstr);
+
+ /* Restore pb */
+ _ger_release_gerpb ( &gerpb, &aclcb, pb );
+
+ /*
+ * General plugin uses SLAPI_RESULT_TEXT for error text. Here
+ * SLAPI_PB_RESULT_TEXT is exclusively shared with add, dse and schema.
+ * slapi_pblock_set() will free any previous data, and
+ * pblock_done() will free SLAPI_PB_RESULT_TEXT.
+ */
+ slapi_pblock_set (pb, SLAPI_PB_RESULT_TEXT, gerstr);
+
+ if ( !iscritical )
+ {
+ /*
+ * If return code is not LDAP_SUCCESS, the server would
+ * abort sending the data of the entry to the client.
+ */
+ rc = LDAP_SUCCESS;
+ }
+
+ slapi_ch_free ( (void **) &subjectndn );
+ slapi_ch_free ( (void **) &gerstr );
+ return rc;
+}