summaryrefslogtreecommitdiffstats
path: root/contrib/slapd-modules/acl
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--contrib/slapd-modules/acl/Makefile50
-rw-r--r--contrib/slapd-modules/acl/README.gssacl32
-rw-r--r--contrib/slapd-modules/acl/README.posixgroup35
-rw-r--r--contrib/slapd-modules/acl/gssacl.c316
-rw-r--r--contrib/slapd-modules/acl/posixgroup.c329
5 files changed, 762 insertions, 0 deletions
diff --git a/contrib/slapd-modules/acl/Makefile b/contrib/slapd-modules/acl/Makefile
new file mode 100644
index 0000000..40a8e9e
--- /dev/null
+++ b/contrib/slapd-modules/acl/Makefile
@@ -0,0 +1,50 @@
+# $OpenLDAP$
+
+LDAP_SRC = ../../..
+LDAP_BUILD = $(LDAP_SRC)
+LDAP_INC = -I$(LDAP_BUILD)/include -I$(LDAP_SRC)/include -I$(LDAP_SRC)/servers/slapd
+LDAP_LIB = $(LDAP_BUILD)/libraries/libldap_r/libldap_r.la \
+ $(LDAP_BUILD)/libraries/liblber/liblber.la
+
+LIBTOOL = $(LDAP_BUILD)/libtool
+CC = gcc
+OPT = -g -O2 -Wall
+DEFS =
+INCS = $(LDAP_INC)
+LIBS = $(LDAP_LIB)
+
+PROGRAMS = posixgroup.la gssacl.la
+LTVER = 0:0:0
+
+prefix=/usr/local
+exec_prefix=$(prefix)
+ldap_subdir=/openldap
+
+libdir=$(exec_prefix)/lib
+libexecdir=$(exec_prefix)/libexec
+moduledir = $(libexecdir)$(ldap_subdir)
+
+.SUFFIXES: .c .o .lo
+
+.c.lo:
+ $(LIBTOOL) --mode=compile $(CC) $(OPT) $(DEFS) $(INCS) -c $<
+
+all: $(PROGRAMS)
+
+posixgroup.la: posixgroup.lo
+ $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \
+ -rpath $(moduledir) -module -o $@ $? $(LIBS)
+
+gssacl.la: gssacl.lo
+ $(LIBTOOL) --mode=link $(CC) $(OPT) -version-info $(LTVER) \
+ -rpath $(moduledir) -module -o $@ $? $(LIBS)
+
+clean:
+ rm -rf *.o *.lo *.la .libs
+
+install: $(PROGRAMS)
+ mkdir -p $(DESTDIR)$(moduledir)
+ for p in $(PROGRAMS) ; do \
+ $(LIBTOOL) --mode=install cp $$p $(DESTDIR)$(moduledir) ; \
+ done
+
diff --git a/contrib/slapd-modules/acl/README.gssacl b/contrib/slapd-modules/acl/README.gssacl
new file mode 100644
index 0000000..368b178
--- /dev/null
+++ b/contrib/slapd-modules/acl/README.gssacl
@@ -0,0 +1,32 @@
+This directory contains native slapd plugins that implement access rules.
+
+gssacl.c contains a simple example that implements access control
+based on GSS naming extensions attributes.
+
+To use the acl-gssacl plugin, add:
+
+moduleload acl-gssacl.so
+
+to your slapd configuration file.
+It is configured using
+
+access to <what>
+ by dynacl/gss/<attribute>.[.{base,regex,expand}]=<valpat> {<level>|<priv(s)>}
+
+The default is "exact"; in case of "expand", "<valpat>" results from
+the expansion of submatches in the "<what>" portion. "<level>|<priv(s)>"
+describe the level of privilege this rule can assume.
+
+Use Makefile to compile this plugin or use a command line similar to:
+
+gcc -shared -I../../../include -I../../../servers/slapd -Wall -g \
+ -o acl-gssacl.so gssacl.c
+
+
+---
+Copyright 2011 PADL Software Pty Ltd. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted only as authorized by the OpenLDAP
+Public License.
+
diff --git a/contrib/slapd-modules/acl/README.posixgroup b/contrib/slapd-modules/acl/README.posixgroup
new file mode 100644
index 0000000..30f4e38
--- /dev/null
+++ b/contrib/slapd-modules/acl/README.posixgroup
@@ -0,0 +1,35 @@
+This directory contains native slapd plugins that implement access rules.
+
+posixgroup.c contains a simple example that implements access control
+based on posixGroup membership, loosely inspired by ITS#3849. It should
+be made clear that this access control policy does not reflect any
+standard track model of handling access control, and should be
+essentially viewed as an illustration of the use of the dynamic
+extension of access control within slapd.
+
+To use the acl-posixgroup plugin, add:
+
+moduleload acl-posixgroup.so
+
+to your slapd configuration file; it requires "nis.schema" to be loaded.
+It is configured using
+
+access to <what>
+ by dynacl/posixGroup[.{exact,expand}]=<dnpat> {<level>|<priv(s)}
+
+The default is "exact"; in case of "expand", "<dnpat>" results from
+the expansion of submatches in the "<what>" portion. "<level>|<priv(s)>"
+describe the level of privilege this rule can assume.
+
+Use Makefile to compile this plugin or use a command line similar to:
+
+gcc -shared -I../../../include -I../../../servers/slapd -Wall -g \
+ -o acl-posixgroup.so posixgroup.c
+
+---
+Copyright 2005-2021 The OpenLDAP Foundation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted only as authorized by the OpenLDAP
+Public License.
+
diff --git a/contrib/slapd-modules/acl/gssacl.c b/contrib/slapd-modules/acl/gssacl.c
new file mode 100644
index 0000000..2fba789
--- /dev/null
+++ b/contrib/slapd-modules/acl/gssacl.c
@@ -0,0 +1,316 @@
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2011 PADL Software Pty Ltd.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+
+#include <portable.h>
+
+#include <ac/string.h>
+#include <slap.h>
+#include <lutil.h>
+
+#include <sasl/sasl.h>
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_ext.h>
+
+#define ACL_BUF_SIZE 1024
+
+typedef struct gssattr_t {
+ slap_style_t gssattr_style;
+ struct berval gssattr_name; /* asserted name */
+ struct berval gssattr_value; /* asserted value */
+} gssattr_t;
+
+static int gssattr_dynacl_destroy( void *priv );
+
+static int
+regex_matches(
+ struct berval *pat, /* pattern to expand and match against */
+ char *str, /* string to match against pattern */
+ struct berval *dn_matches, /* buffer with $N expansion variables from DN */
+ struct berval *val_matches, /* buffer with $N expansion variables from val */
+ AclRegexMatches *matches /* offsets in buffer for $N expansion variables */
+);
+
+static int
+gssattr_dynacl_parse(
+ const char *fname,
+ int lineno,
+ const char *opts,
+ slap_style_t style,
+ const char *pattern,
+ void **privp )
+{
+ gssattr_t *gssattr;
+
+ gssattr = (gssattr_t *)ch_calloc( 1, sizeof( gssattr_t ) );
+
+ if ( opts == NULL || opts[0] == '\0' ) {
+ fprintf( stderr, "%s line %d: GSS ACL: no attribute specified.\n",
+ fname, lineno );
+ goto cleanup;
+ }
+
+ if ( pattern == NULL || pattern[0] == '\0' ) {
+ fprintf( stderr, "%s line %d: GSS ACL: no attribute value specified.\n",
+ fname, lineno );
+ goto cleanup;
+ }
+
+ gssattr->gssattr_style = style;
+
+ switch ( gssattr->gssattr_style ) {
+ case ACL_STYLE_BASE:
+ case ACL_STYLE_REGEX:
+ case ACL_STYLE_EXPAND:
+ break;
+ default:
+ fprintf( stderr, "%s line %d: GSS ACL: unsupported style \"%s\".\n",
+ fname, lineno, style_strings[style] );
+ goto cleanup;
+ break;
+ }
+
+ ber_str2bv( opts, 0, 1, &gssattr->gssattr_name );
+ ber_str2bv( pattern, 0, 1, &gssattr->gssattr_value );
+
+ *privp = (void *)gssattr;
+ return 0;
+
+cleanup:
+ (void)gssattr_dynacl_destroy( (void *)gssattr );
+
+ return 1;
+}
+
+static int
+gssattr_dynacl_unparse(
+ void *priv,
+ struct berval *bv )
+{
+ gssattr_t *gssattr = (gssattr_t *)priv;
+ char *ptr;
+
+ bv->bv_len = STRLENOF( " dynacl/gss/.expand=" ) +
+ gssattr->gssattr_name.bv_len +
+ gssattr->gssattr_value.bv_len;
+ bv->bv_val = ch_malloc( bv->bv_len + 1 );
+
+ ptr = lutil_strcopy( bv->bv_val, " dynacl/gss/" );
+ ptr = lutil_strncopy( ptr, gssattr->gssattr_name.bv_val,
+ gssattr->gssattr_name.bv_len );
+ switch ( gssattr->gssattr_style ) {
+ case ACL_STYLE_BASE:
+ ptr = lutil_strcopy( ptr, ".exact=" );
+ break;
+ case ACL_STYLE_REGEX:
+ ptr = lutil_strcopy( ptr, ".regex=" );
+ break;
+ case ACL_STYLE_EXPAND:
+ ptr = lutil_strcopy( ptr, ".expand=" );
+ break;
+ default:
+ assert( 0 );
+ break;
+ }
+
+ ptr = lutil_strncopy( ptr, gssattr->gssattr_value.bv_val,
+ gssattr->gssattr_value.bv_len );
+
+ ptr[ 0 ] = '\0';
+
+ bv->bv_len = ptr - bv->bv_val;
+
+ return 0;
+}
+
+static int
+gssattr_dynacl_mask(
+ void *priv,
+ Operation *op,
+ Entry *target,
+ AttributeDescription *desc,
+ struct berval *val,
+ int nmatch,
+ regmatch_t *matches,
+ slap_access_t *grant,
+ slap_access_t *deny )
+{
+ gssattr_t *gssattr = (gssattr_t *)priv;
+ sasl_conn_t *sasl_ctx = op->o_conn->c_sasl_authctx;
+ gss_name_t gss_name = GSS_C_NO_NAME;
+ OM_uint32 major, minor;
+ int more = -1;
+ int authenticated, complete;
+ gss_buffer_desc attr = GSS_C_EMPTY_BUFFER;
+ int granted = 0;
+
+ ACL_INVALIDATE( *deny );
+
+ if ( sasl_ctx == NULL ||
+ sasl_getprop( sasl_ctx, SASL_GSS_PEER_NAME, (const void **)&gss_name) != 0 ||
+ gss_name == GSS_C_NO_NAME ) {
+ return 0;
+ }
+
+ attr.length = gssattr->gssattr_name.bv_len;
+ attr.value = gssattr->gssattr_name.bv_val;
+
+ while ( more != 0 ) {
+ AclRegexMatches amatches = { 0 };
+ gss_buffer_desc gss_value = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc gss_display_value = GSS_C_EMPTY_BUFFER;
+ struct berval bv_value;
+
+ major = gss_get_name_attribute( &minor, gss_name, &attr,
+ &authenticated, &complete,
+ &gss_value, &gss_display_value, &more );
+ if ( GSS_ERROR( major ) ) {
+ break;
+ } else if ( authenticated == 0 ) {
+ gss_release_buffer( &minor, &gss_value );
+ gss_release_buffer( &minor, &gss_display_value );
+ continue;
+ }
+
+ bv_value.bv_len = gss_value.length;
+ bv_value.bv_val = (char *)gss_value.value;
+
+ if ( !ber_bvccmp( &gssattr->gssattr_value, '*' ) ) {
+ if ( gssattr->gssattr_style != ACL_STYLE_BASE ) {
+ amatches.dn_count = nmatch;
+ AC_MEMCPY( amatches.dn_data, matches, sizeof( amatches.dn_data ) );
+ }
+
+ switch ( gssattr->gssattr_style ) {
+ case ACL_STYLE_REGEX:
+ /* XXX assumes value NUL terminated */
+ granted = regex_matches( &gssattr->gssattr_value, bv_value.bv_val,
+ &target->e_nname, val, &amatches );
+ break;
+ case ACL_STYLE_EXPAND: {
+ struct berval bv;
+ char buf[ACL_BUF_SIZE];
+
+ bv.bv_len = sizeof( buf ) - 1;
+ bv.bv_val = buf;
+
+ granted = ( acl_string_expand( &bv, &gssattr->gssattr_value,
+ &target->e_nname, val,
+ &amatches ) == 0 ) &&
+ ( ber_bvstrcmp( &bv, &bv_value) == 0 );
+ break;
+ }
+ case ACL_STYLE_BASE:
+ granted = ( ber_bvstrcmp( &gssattr->gssattr_value, &bv_value ) == 0 );
+ break;
+ default:
+ assert(0);
+ break;
+ }
+ } else {
+ granted = 1;
+ }
+
+ gss_release_buffer( &minor, &gss_value );
+ gss_release_buffer( &minor, &gss_display_value );
+
+ if ( granted ) {
+ break;
+ }
+ }
+
+ if ( granted ) {
+ ACL_LVL_ASSIGN_WRITE( *grant );
+ }
+
+ return 0;
+}
+
+static int
+gssattr_dynacl_destroy(
+ void *priv )
+{
+ gssattr_t *gssattr = (gssattr_t *)priv;
+
+ if ( gssattr != NULL ) {
+ if ( !BER_BVISNULL( &gssattr->gssattr_name ) ) {
+ ber_memfree( gssattr->gssattr_name.bv_val );
+ }
+ if ( !BER_BVISNULL( &gssattr->gssattr_value ) ) {
+ ber_memfree( gssattr->gssattr_value.bv_val );
+ }
+ ch_free( gssattr );
+ }
+
+ return 0;
+}
+
+static struct slap_dynacl_t gssattr_dynacl = {
+ "gss",
+ gssattr_dynacl_parse,
+ gssattr_dynacl_unparse,
+ gssattr_dynacl_mask,
+ gssattr_dynacl_destroy
+};
+
+int
+init_module( int argc, char *argv[] )
+{
+ return slap_dynacl_register( &gssattr_dynacl );
+}
+
+
+static int
+regex_matches(
+ struct berval *pat, /* pattern to expand and match against */
+ char *str, /* string to match against pattern */
+ struct berval *dn_matches, /* buffer with $N expansion variables from DN */
+ struct berval *val_matches, /* buffer with $N expansion variables from val */
+ AclRegexMatches *matches /* offsets in buffer for $N expansion variables */
+)
+{
+ regex_t re;
+ char newbuf[ACL_BUF_SIZE];
+ struct berval bv;
+ int rc;
+
+ bv.bv_len = sizeof( newbuf ) - 1;
+ bv.bv_val = newbuf;
+
+ if (str == NULL) {
+ str = "";
+ };
+
+ acl_string_expand( &bv, pat, dn_matches, val_matches, matches );
+ rc = regcomp( &re, newbuf, REG_EXTENDED|REG_ICASE );
+ if ( rc ) {
+ char error[ACL_BUF_SIZE];
+ regerror( rc, &re, error, sizeof( error ) );
+
+ Debug( LDAP_DEBUG_TRACE,
+ "compile( \"%s\", \"%s\") failed %s\n",
+ pat->bv_val, str, error );
+ return( 0 );
+ }
+
+ rc = regexec( &re, str, 0, NULL, 0 );
+ regfree( &re );
+
+ Debug( LDAP_DEBUG_TRACE,
+ "=> regex_matches: string: %s\n", str, 0, 0 );
+ Debug( LDAP_DEBUG_TRACE,
+ "=> regex_matches: rc: %d %s\n",
+ rc, !rc ? "matches" : "no matches", 0 );
+ return( !rc );
+}
+
diff --git a/contrib/slapd-modules/acl/posixgroup.c b/contrib/slapd-modules/acl/posixgroup.c
new file mode 100644
index 0000000..bc1a008
--- /dev/null
+++ b/contrib/slapd-modules/acl/posixgroup.c
@@ -0,0 +1,329 @@
+/* posixgroup.c */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 1998-2021 The OpenLDAP Foundation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+
+#include <portable.h>
+
+#include <ac/string.h>
+#include <slap.h>
+#include <lutil.h>
+
+/* Need dynacl... */
+
+#ifdef SLAP_DYNACL
+
+typedef struct pg_t {
+ slap_style_t pg_style;
+ struct berval pg_pat;
+} pg_t;
+
+static ObjectClass *pg_posixGroup;
+static AttributeDescription *pg_memberUid;
+static ObjectClass *pg_posixAccount;
+static AttributeDescription *pg_uidNumber;
+
+static int pg_dynacl_destroy( void *priv );
+
+static int
+pg_dynacl_parse(
+ const char *fname,
+ int lineno,
+ const char *opts,
+ slap_style_t style,
+ const char *pattern,
+ void **privp )
+{
+ pg_t *pg;
+ int rc;
+ const char *text = NULL;
+ struct berval pat;
+
+ ber_str2bv( pattern, 0, 0, &pat );
+
+ pg = ch_calloc( 1, sizeof( pg_t ) );
+
+ pg->pg_style = style;
+
+ switch ( pg->pg_style ) {
+ case ACL_STYLE_BASE:
+ rc = dnNormalize( 0, NULL, NULL, &pat, &pg->pg_pat, NULL );
+ if ( rc != LDAP_SUCCESS ) {
+ fprintf( stderr, "%s line %d: posixGroup ACL: "
+ "unable to normalize DN \"%s\".\n",
+ fname, lineno, pattern );
+ goto cleanup;
+ }
+ break;
+
+ case ACL_STYLE_EXPAND:
+ ber_dupbv( &pg->pg_pat, &pat );
+ break;
+
+ default:
+ fprintf( stderr, "%s line %d: posixGroup ACL: "
+ "unsupported style \"%s\".\n",
+ fname, lineno, style_strings[ pg->pg_style ] );
+ goto cleanup;
+ }
+
+ /* TODO: use opts to allow the use of different
+ * group objects and member attributes */
+ if ( pg_posixGroup == NULL ) {
+ pg_posixGroup = oc_find( "posixGroup" );
+ if ( pg_posixGroup == NULL ) {
+ fprintf( stderr, "%s line %d: posixGroup ACL: "
+ "unable to lookup \"posixGroup\" "
+ "objectClass.\n",
+ fname, lineno );
+ goto cleanup;
+ }
+
+ pg_posixAccount = oc_find( "posixAccount" );
+ if ( pg_posixGroup == NULL ) {
+ fprintf( stderr, "%s line %d: posixGroup ACL: "
+ "unable to lookup \"posixAccount\" "
+ "objectClass.\n",
+ fname, lineno );
+ goto cleanup;
+ }
+
+ rc = slap_str2ad( "memberUid", &pg_memberUid, &text );
+ if ( rc != LDAP_SUCCESS ) {
+ fprintf( stderr, "%s line %d: posixGroup ACL: "
+ "unable to lookup \"memberUid\" "
+ "attributeDescription (%d: %s).\n",
+ fname, lineno, rc, text );
+ goto cleanup;
+ }
+
+ rc = slap_str2ad( "uidNumber", &pg_uidNumber, &text );
+ if ( rc != LDAP_SUCCESS ) {
+ fprintf( stderr, "%s line %d: posixGroup ACL: "
+ "unable to lookup \"uidNumber\" "
+ "attributeDescription (%d: %s).\n",
+ fname, lineno, rc, text );
+ goto cleanup;
+ }
+ }
+
+ *privp = (void *)pg;
+ return 0;
+
+cleanup:
+ (void)pg_dynacl_destroy( (void *)pg );
+
+ return 1;
+}
+
+static int
+pg_dynacl_unparse(
+ void *priv,
+ struct berval *bv )
+{
+ pg_t *pg = (pg_t *)priv;
+ char *ptr;
+
+ bv->bv_len = STRLENOF( " dynacl/posixGroup.expand=" ) + pg->pg_pat.bv_len;
+ bv->bv_val = ch_malloc( bv->bv_len + 1 );
+
+ ptr = lutil_strcopy( bv->bv_val, " dynacl/posixGroup" );
+
+ switch ( pg->pg_style ) {
+ case ACL_STYLE_BASE:
+ ptr = lutil_strcopy( ptr, ".exact=" );
+ break;
+
+ case ACL_STYLE_EXPAND:
+ ptr = lutil_strcopy( ptr, ".expand=" );
+ break;
+
+ default:
+ assert( 0 );
+ }
+
+ ptr = lutil_strncopy( ptr, pg->pg_pat.bv_val, pg->pg_pat.bv_len );
+ ptr[ 0 ] = '\0';
+
+ bv->bv_len = ptr - bv->bv_val;
+
+ return 0;
+}
+
+static int
+pg_dynacl_mask(
+ void *priv,
+ Operation *op,
+ Entry *target,
+ AttributeDescription *desc,
+ struct berval *val,
+ int nmatch,
+ regmatch_t *matches,
+ slap_access_t *grant,
+ slap_access_t *deny )
+{
+ pg_t *pg = (pg_t *)priv;
+ Entry *group = NULL,
+ *user = NULL;
+ int rc;
+ Backend *be = op->o_bd,
+ *group_be = NULL,
+ *user_be = NULL;
+ struct berval group_ndn;
+
+ ACL_INVALIDATE( *deny );
+
+ /* get user */
+ if ( target && dn_match( &target->e_nname, &op->o_ndn ) ) {
+ user = target;
+ rc = LDAP_SUCCESS;
+
+ } else {
+ user_be = op->o_bd = select_backend( &op->o_ndn, 0 );
+ if ( op->o_bd == NULL ) {
+ op->o_bd = be;
+ return 0;
+ }
+ rc = be_entry_get_rw( op, &op->o_ndn, pg_posixAccount, pg_uidNumber, 0, &user );
+ }
+
+ if ( rc != LDAP_SUCCESS || user == NULL ) {
+ op->o_bd = be;
+ return 0;
+ }
+
+ /* get target */
+ if ( pg->pg_style == ACL_STYLE_EXPAND ) {
+ char buf[ 1024 ];
+ struct berval bv;
+ AclRegexMatches amatches = { 0 };
+
+ amatches.dn_count = nmatch;
+ AC_MEMCPY( amatches.dn_data, matches, sizeof( amatches.dn_data ) );
+
+ bv.bv_len = sizeof( buf ) - 1;
+ bv.bv_val = buf;
+
+ if ( acl_string_expand( &bv, &pg->pg_pat,
+ &target->e_nname,
+ NULL, &amatches ) )
+ {
+ goto cleanup;
+ }
+
+ if ( dnNormalize( 0, NULL, NULL, &bv, &group_ndn,
+ op->o_tmpmemctx ) != LDAP_SUCCESS )
+ {
+ /* did not expand to a valid dn */
+ goto cleanup;
+ }
+
+ } else {
+ group_ndn = pg->pg_pat;
+ }
+
+ if ( target && dn_match( &target->e_nname, &group_ndn ) ) {
+ group = target;
+ rc = LDAP_SUCCESS;
+
+ } else {
+ group_be = op->o_bd = select_backend( &group_ndn, 0 );
+ if ( op->o_bd == NULL ) {
+ goto cleanup;
+ }
+ rc = be_entry_get_rw( op, &group_ndn, pg_posixGroup, pg_memberUid, 0, &group );
+ }
+
+ if ( group_ndn.bv_val != pg->pg_pat.bv_val ) {
+ op->o_tmpfree( group_ndn.bv_val, op->o_tmpmemctx );
+ }
+
+ if ( rc == LDAP_SUCCESS && group != NULL ) {
+ Attribute *a_uid,
+ *a_member;
+
+ a_uid = attr_find( user->e_attrs, pg_uidNumber );
+ if ( !a_uid || !BER_BVISNULL( &a_uid->a_nvals[ 1 ] ) ) {
+ rc = LDAP_NO_SUCH_ATTRIBUTE;
+
+ } else {
+ a_member = attr_find( group->e_attrs, pg_memberUid );
+ if ( !a_member ) {
+ rc = LDAP_NO_SUCH_ATTRIBUTE;
+
+ } else {
+ rc = value_find_ex( pg_memberUid,
+ SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH |
+ SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH,
+ a_member->a_nvals, &a_uid->a_nvals[ 0 ],
+ op->o_tmpmemctx );
+ }
+ }
+
+ } else {
+ rc = LDAP_NO_SUCH_OBJECT;
+ }
+
+
+ if ( rc == LDAP_SUCCESS ) {
+ ACL_LVL_ASSIGN_WRITE( *grant );
+ }
+
+cleanup:;
+ if ( group != NULL && group != target ) {
+ op->o_bd = group_be;
+ be_entry_release_r( op, group );
+ op->o_bd = be;
+ }
+
+ if ( user != NULL && user != target ) {
+ op->o_bd = user_be;
+ be_entry_release_r( op, user );
+ op->o_bd = be;
+ }
+
+ return 0;
+}
+
+static int
+pg_dynacl_destroy(
+ void *priv )
+{
+ pg_t *pg = (pg_t *)priv;
+
+ if ( pg != NULL ) {
+ if ( !BER_BVISNULL( &pg->pg_pat ) ) {
+ ber_memfree( pg->pg_pat.bv_val );
+ }
+ ch_free( pg );
+ }
+
+ return 0;
+}
+
+static struct slap_dynacl_t pg_dynacl = {
+ "posixGroup",
+ pg_dynacl_parse,
+ pg_dynacl_unparse,
+ pg_dynacl_mask,
+ pg_dynacl_destroy
+};
+
+int
+init_module( int argc, char *argv[] )
+{
+ return slap_dynacl_register( &pg_dynacl );
+}
+
+#endif /* SLAP_DYNACL */