]> git.sur5r.net Git - openldap/commitdiff
add on demand allowedAttributes/allowedAttributesEffective to entries (ITS#4730)
authorPierangelo Masarati <ando@openldap.org>
Tue, 18 Aug 2009 00:27:05 +0000 (00:27 +0000)
committerPierangelo Masarati <ando@openldap.org>
Tue, 18 Aug 2009 00:27:05 +0000 (00:27 +0000)
contrib/slapd-modules/allowed/allowed.c [new file with mode: 0644]

diff --git a/contrib/slapd-modules/allowed/allowed.c b/contrib/slapd-modules/allowed/allowed.c
new file mode 100644 (file)
index 0000000..ae0d232
--- /dev/null
@@ -0,0 +1,401 @@
+/* allowed.c - add allowed attributes based on ACL */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ *
+ * Copyright 2006-2009 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>.
+ */
+/* ACKNOWLEDGEMENTS:
+ * This work was initially developed by Pierangelo Masarati for inclusion in
+ * OpenLDAP Software.
+ */
+
+/*
+ * Rationale: return in allowedAttributes the attributes required/allowed
+ * by the objectClasses that are currently present in an object; return
+ * in allowedAttributesEffective the subset of the above that can be written
+ * by the identity that performs the search.
+ *
+ * Caveats:
+ * - right now, the overlay assumes that all values of the objectClass
+ *   attribute will be returned in rs->sr_entry; this may not be true
+ *   in general, but it usually is for back-bdb/back-hdb.  To generalize,
+ *   the search request should be analyzed, and if allowedAttributes or
+ *   allowedAttributesEffective are requested, add objectClass to the
+ *   requested attributes
+ * - it assumes that there is no difference between write-add and 
+ *   write-delete
+ * - it assumes that access rules do not depend on the values of the 
+ *   attributes or on the contents of the entry (attr/val, filter, ...)
+ *   allowedAttributes and allowedAttributesEffective cannot be used
+ *   in filters or in compare
+ */
+
+#include "portable.h"
+
+/* define SLAPD_OVER_ALLOWED=2 to build as run-time loadable module */
+#ifdef SLAPD_OVER_ALLOWED
+
+#include "slap.h"
+
+/*
+ * Schema from
+ *
+ * <http://www.redhat.com/archives/fedora-directory-devel/2006-August/msg00007.html>
+ *
+ * posted by Andrew Bartlett
+ */
+
+#define AA_SCHEMA_AT "1.2.840.113556.1.4"
+
+static AttributeDescription
+               *ad_allowedChildClasses,
+               *ad_allowedChildClassesEffective,
+               *ad_allowedAttributes,
+               *ad_allowedAttributesEffective;
+
+static struct {
+       char *at;
+       AttributeDescription **ad;
+} aa_attrs[] = {
+       { "( " AA_SCHEMA_AT ".911 "
+               "NAME 'allowedChildClasses' "
+               "EQUALITY objectIdentifierMatch "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 "
+               /* added by me :) */
+               "DESC 'Child classes allowed for a given object' "
+               "NO-USER-MODIFICATION "
+               "USAGE directoryOperation )", &ad_allowedChildClasses },
+       { "( " AA_SCHEMA_AT ".912 "
+               "NAME 'allowedChildClassesEffective' "
+               "EQUALITY objectIdentifierMatch "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 "
+               /* added by me :) */
+               "DESC 'Child classes allowed for a given object according to ACLs' "
+               "NO-USER-MODIFICATION "
+               "USAGE directoryOperation )", &ad_allowedChildClassesEffective },
+       { "( " AA_SCHEMA_AT ".913 "
+               "NAME 'allowedAttributes' "
+               "EQUALITY objectIdentifierMatch "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 "
+               /* added by me :) */
+               "DESC 'Attributes allowed for a given object' "
+               "NO-USER-MODIFICATION "
+               "USAGE directoryOperation )", &ad_allowedAttributes },
+       { "( " AA_SCHEMA_AT ".914 "
+               "NAME 'allowedAttributesEffective' "
+               "EQUALITY objectIdentifierMatch "
+               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 "
+               /* added by me :) */
+               "DESC 'Attributes allowed for a given object according to ACLs' "
+               "NO-USER-MODIFICATION "
+               "USAGE directoryOperation )", &ad_allowedAttributesEffective },
+
+       /* TODO: add objectClass stuff? */
+
+       { NULL, NULL }
+};
+
+static int
+aa_add_at( AttributeType *at, AttributeType ***atpp )
+{
+       int             i = 0;
+
+       if ( *atpp ) {
+               for ( i = 0; (*atpp)[ i ] != NULL; i++ ) {
+                       if ( (*atpp)[ i ] == at ) {
+                               break;
+                       }
+               }
+       
+               if ( (*atpp)[ i ] != NULL ) {
+                       return 0;
+               }
+       }
+
+       *atpp = ch_realloc( *atpp, sizeof( AttributeType * ) * ( i + 2 ) );
+       (*atpp)[ i ] = at;
+       (*atpp)[ i + 1 ] = NULL;
+
+       return 0;
+}
+
+static int
+aa_add_oc( ObjectClass *oc, ObjectClass ***ocpp, AttributeType ***atpp )
+{
+       int             i = 0;
+
+       if ( *ocpp ) {
+               for ( ; (*ocpp)[ i ] != NULL; i++ ) {
+                       if ( (*ocpp)[ i ] == oc ) {
+                               break;
+                       }
+               }
+
+               if ( (*ocpp)[ i ] != NULL ) {
+                       return 0;
+               }
+       }
+
+       *ocpp = ch_realloc( *ocpp, sizeof( ObjectClass * ) * ( i + 2 ) );
+       (*ocpp)[ i ] = oc;
+       (*ocpp)[ i + 1 ] = NULL;
+
+       if ( oc->soc_required ) {
+               int             i;
+
+               for ( i = 0; oc->soc_required[ i ] != NULL; i++ ) {
+                       aa_add_at( oc->soc_required[ i ], atpp );
+               }
+       }
+
+       if ( oc->soc_allowed ) {
+               int             i;
+
+               for ( i = 0; oc->soc_allowed[ i ] != NULL; i++ ) {
+                       aa_add_at( oc->soc_allowed[ i ], atpp );
+               }
+       }
+
+       return 0;
+}
+
+static int
+aa_operational( Operation *op, SlapReply *rs )
+{
+       Attribute               *a, **ap;
+       AccessControlState      acl_state = ACL_STATE_INIT;
+       struct berval           *v;
+       AttributeType           **atp = NULL;
+       ObjectClass             **ocp = NULL;
+       BerVarray               bv_allowed = NULL,
+                               bv_effective = NULL;
+       int                     i, ja, je;
+
+#define        GOT_NONE        (0x0U)
+#define        GOT_C           (0x1U)
+#define        GOT_CE          (0x2U)
+#define        GOT_A           (0x4U)
+#define        GOT_AE          (0x8U)
+#define        GOT_ALL         (GOT_C|GOT_CE|GOT_A|GOT_AE)
+       int             got = GOT_NONE;
+
+       /* only add if requested */
+       if ( SLAP_OPATTRS( rs->sr_attr_flags ) ) {
+               got = GOT_ALL;
+
+       } else {
+               if ( ad_inlist( ad_allowedChildClasses, rs->sr_attrs ) ) {
+                       got |= GOT_C;
+               }
+
+               if ( ad_inlist( ad_allowedChildClassesEffective, rs->sr_attrs ) ) {
+                       got |= GOT_CE;
+               }
+
+               if ( ad_inlist( ad_allowedAttributes, rs->sr_attrs ) ) {
+                       got |= GOT_A;
+               }
+
+               if ( ad_inlist( ad_allowedAttributesEffective, rs->sr_attrs ) ) {
+                       got |= GOT_AE;
+               }
+       }
+
+       if ( got == GOT_NONE ) {
+               return SLAP_CB_CONTINUE;
+       }
+
+       /* shouldn't be called without an entry; please check */
+       assert( rs->sr_entry != NULL );
+
+       /* see caveats; this is not guaranteed for all backends */
+       a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_objectClass );
+       if ( a == NULL ) {
+               return SLAP_CB_CONTINUE;
+       }
+
+       /* if client has no access to objectClass attribute; don't compute */
+       if ( !access_allowed( op, rs->sr_entry, slap_schema.si_ad_objectClass,
+                               NULL, ACL_READ, &acl_state ) )
+       {
+               return SLAP_CB_CONTINUE;
+       }
+
+       for ( v = a->a_nvals; !BER_BVISNULL( v ); v++ ) {
+               ObjectClass     *oc = oc_bvfind( v );
+
+               assert( oc != NULL );
+
+               /* if client has no access to specific value, don't compute */
+               if ( !access_allowed( op, rs->sr_entry,
+                       slap_schema.si_ad_objectClass,
+                       &oc->soc_cname, ACL_READ, &acl_state ) )
+               {
+                       continue;
+               }
+
+               aa_add_oc( oc, &ocp, &atp );
+
+               if ( oc->soc_sups ) {
+                       for ( i = 0; oc->soc_sups[ i ] != NULL; i++ ) {
+                               aa_add_oc( oc->soc_sups[ i ], &ocp, &atp );
+                       }
+               }
+       }
+
+       if ( atp != NULL ) {
+               for ( i = 0; atp[ i ] != NULL; i++ )
+                       /* just count */ ;
+       
+               if ( got & GOT_A ) {
+                       bv_allowed = ber_memalloc( sizeof( struct berval ) * ( i + 1 ) );
+               }
+               if ( got & GOT_AE ) {
+                       bv_effective = ber_memalloc( sizeof( struct berval ) * ( i + 1 ) );
+               }
+
+               for ( i = 0, ja = 0, je = 0; atp[ i ] != NULL; i++ ) {
+                       if ( got & GOT_A ) {
+                               ber_dupbv( &bv_allowed[ ja ], &atp[ i ]->sat_cname );
+                               ja++;
+                       }
+
+                       if ( got & GOT_AE ) {
+                               AttributeDescription    *ad = NULL;
+                               const char              *text = NULL;
+       
+                               if ( slap_bv2ad( &atp[ i ]->sat_cname, &ad, &text ) ) {
+                                       /* log? */
+                                       continue;
+                               }
+
+                               if ( access_allowed( op, rs->sr_entry,
+                                       ad, NULL, ACL_WRITE, NULL ) )
+                               {
+                                       ber_dupbv( &bv_effective[ je ], &atp[ i ]->sat_cname );
+                                       je++;
+                               }
+                       }
+               }
+
+               for ( ap = &rs->sr_operational_attrs; *ap != NULL; ap = &(*ap)->a_next )
+                       /* go to last */ ;
+
+               if ( got & GOT_A ) {
+                       BER_BVZERO( &bv_allowed[ ja ] );
+                       *ap = attr_alloc( ad_allowedAttributes );
+                       (*ap)->a_vals = bv_allowed;
+                       (*ap)->a_nvals = bv_allowed;
+                       ap = &(*ap)->a_next;
+               }
+       
+               if ( got & GOT_AE ) {
+                       BER_BVZERO( &bv_effective[ je ] );
+                       *ap = attr_alloc( ad_allowedAttributesEffective );
+                       (*ap)->a_vals = bv_effective;
+                       (*ap)->a_nvals = bv_effective;
+                       ap = &(*ap)->a_next;
+               }
+       
+               *ap = NULL;
+       }
+
+       ch_free( atp );
+       ch_free( ocp );
+
+       return SLAP_CB_CONTINUE;
+}
+
+static slap_overinst aa;
+
+#if LDAP_VENDOR_VERSION_MINOR != X && LDAP_VENDOR_VERSION_MINOR <= 3
+/* backport register_at() from HEAD, to allow building with OL <= 2.3 */
+static int
+register_at( char *def, AttributeDescription **rad, int dupok )
+{
+       LDAPAttributeType *at;
+       int code, freeit = 0;
+       const char *err;
+       AttributeDescription *ad = NULL;
+
+       at = ldap_str2attributetype( def, &code, &err, LDAP_SCHEMA_ALLOW_ALL );
+       if ( !at ) {
+               Debug( LDAP_DEBUG_ANY,
+                       "register_at: AttributeType \"%s\": %s, %s\n",
+                               def, ldap_scherr2str(code), err );
+               return code;
+       }
+
+       code = at_add( at, 0, NULL, &err );
+       if ( code ) {
+               if ( code == SLAP_SCHERR_ATTR_DUP && dupok ) {
+                       freeit = 1;
+
+               } else {
+                       ldap_attributetype_free( at );
+                       Debug( LDAP_DEBUG_ANY,
+                               "register_at: AttributeType \"%s\": %s, %s\n",
+                               def, scherr2str(code), err );
+                       return code;
+               }
+       }
+       code = slap_str2ad( at->at_names[0], &ad, &err );
+       if ( freeit || code ) {
+               ldap_attributetype_free( at );
+       } else {
+               ldap_memfree( at );
+       }
+       if ( code ) {
+               Debug( LDAP_DEBUG_ANY, "register_at: AttributeType \"%s\": %s\n",
+                       def, err, 0 );
+       }
+       if ( rad ) *rad = ad;
+       return code;
+}
+#endif
+
+#if SLAPD_OVER_ALLOWED == SLAPD_MOD_DYNAMIC
+static
+#endif /* SLAPD_OVER_ALLOWED == SLAPD_MOD_DYNAMIC */
+int
+aa_initialize( void )
+{
+       int i;
+
+       aa.on_bi.bi_type = "aa";
+
+       aa.on_bi.bi_operational = aa_operational;
+
+       /* aa schema integration */
+       for ( i = 0; aa_attrs[i].at; i++ ) {
+               int code;
+
+               code = register_at( aa_attrs[i].at, aa_attrs[i].ad, 0 );
+               if ( code ) {
+                       Debug( LDAP_DEBUG_ANY,
+                               "aa_initialize: register_at failed\n", 0, 0, 0 );
+                       return -1;
+               }
+       }
+
+       return overlay_register( &aa );
+}
+
+#if SLAPD_OVER_ALLOWED == SLAPD_MOD_DYNAMIC
+int
+init_module( int argc, char *argv[] )
+{
+       return aa_initialize();
+}
+#endif /* SLAPD_OVER_ALLOWED == SLAPD_MOD_DYNAMIC */
+
+#endif /* SLAPD_OVER_ALLOWED */