]> git.sur5r.net Git - openldap/blobdiff - contrib/slapd-modules/acl/posixgroup.c
add posixGroup access control via dynacl as an example of how dynacl work
[openldap] / contrib / slapd-modules / acl / posixgroup.c
diff --git a/contrib/slapd-modules/acl/posixgroup.c b/contrib/slapd-modules/acl/posixgroup.c
new file mode 100644 (file)
index 0000000..3f06b7f
--- /dev/null
@@ -0,0 +1,320 @@
+/* $OpenLDAP$ */
+/*
+ * Copyright 1998-2005 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,
+       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;
+       }
+
+       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,
+       struct slap_op          *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, 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;
+
+               bv.bv_len = sizeof( buf ) - 1;
+               bv.bv_val = buf;
+
+               if ( acl_string_expand( &bv, &pg->pg_pat,
+                               target->e_nname.bv_val,
+                               nmatch, matches ) )
+               {
+                       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, 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, group );
+               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 */