diff --git a/CHANGES b/CHANGES index 9b4a93214ee77909009acb5b8ff2b00a5cd02a9e..c34611375af02ea29738fd868112f4480c3013e1 100644 --- a/CHANGES +++ b/CHANGES @@ -23,13 +23,14 @@ OpenLDAP 2.4.18 Engineering Fixed slapd-relay response/cleanup callback mismatch (ITS#6154) Fixed slapd-sql with baseObject query (ITS#6172) Fixed slapd-sql with empty attribute (ITS#6163) - Added slapo-pcache olcProxyCacheOffline (ITS#6152) + Fixed slapo-pcache multiple enhancements (ITS#6152) Fixed slapo-translucent attribute return (ITS#6254) Fixed slapo-translucent filter matching (ITS#6255) Fixed slapo-translucent to honor sizelimit (ITS#6253) Fixed slapo-unique filter matching (ITS#6077) Fixed tools off by one error (ITS#6233) Fixed tools resource leaks (ITS#6145) + Added contrib/allowed (ITS#4730) Fixed contrib/autogroup with RE24 (ITS#6227) Fixed contrib/nss symbols (ITS#6273) Build Environment diff --git a/contrib/slapd-modules/allowed/README b/contrib/slapd-modules/allowed/README new file mode 100644 index 0000000000000000000000000000000000000000..32abdf5f64e0955987e9da198ea55a6a1a392e08 --- /dev/null +++ b/contrib/slapd-modules/allowed/README @@ -0,0 +1,83 @@ +This directory contains a slapd overlay, "allowed". + + --- o --- o --- o --- + +It adds to entries returned by search operations the value of attributes + +"allowedAttributes" + <http://msdn.microsoft.com/en-us/library/ms675217(VS.85).aspx> + +"allowedAttributesEffective" + <http://msdn.microsoft.com/en-us/library/ms675218(VS.85).aspx> + +No other use is made of those attributes: they cannot be compared, +they cannot be used in search filters, they cannot be used in ACLs, ... + + --- o --- o --- o --- + +Other attributes like + +"allowedChildClasses" + <http://msdn.microsoft.com/en-us/library/ms675219(VS.85).aspx> +"allowedChildClassesEffective" + <http://msdn.microsoft.com/en-us/library/ms675220(VS.85).aspx> + +make little sense within OpenLDAP's slapd right now, since any AUXILIARY +objectClass can be added to an entry, while no STRUCTURAL objectClass can. +This may change when DIT structure rules are implemented, while ACLs may +restrict what AUXILIARY objectClasses can be added to an entry. + + --- o --- o --- o --- + +Usage: add to slapd.conf(5) + + +moduleload path/to/allowed.so +overlay allowed + +or add + +dn: olcOverlay={0}allowed,olcDatabase={1}bdb,cn=config +objectClass: olcOverlayConfig +olcOverlay: {0}allowed + +as a child of the database that's intended to support this feature +(replace "olcDatabase={1}bdb,cn=config" with the appropriate parent); +or use + +dn: olcOverlay={0}allowed,olcDatabase={-1}frontend,cn=config +objectClass: olcOverlayConfig +olcOverlay: {0}allowed + +if it's supposed to be global. + + --- o --- o --- o --- + +No Makefile is provided. Use a command line similar to: + +gcc -shared -I../../../include -I../../../servers/slapd -Wall -g \ + -o allowed.so allowed.c + +to compile this overlay, or even better use OpenLDAP's libtool as appropriate. + +--- +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. + +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. + diff --git a/contrib/slapd-modules/allowed/allowed.c b/contrib/slapd-modules/allowed/allowed.c new file mode 100644 index 0000000000000000000000000000000000000000..415aeefa9bed4281268f56493d040d87cbf18189 --- /dev/null +++ b/contrib/slapd-modules/allowed/allowed.c @@ -0,0 +1,403 @@ +/* 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 = 0, je = 0; + +#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 ) && ja > 0 ) { + BER_BVZERO( &bv_allowed[ ja ] ); + *ap = attr_alloc( ad_allowedAttributes ); + (*ap)->a_vals = bv_allowed; + (*ap)->a_nvals = bv_allowed; + (*ap)->a_numvals = ja; + ap = &(*ap)->a_next; + } + + if ( ( got & GOT_AE ) && je > 0 ) { + BER_BVZERO( &bv_effective[ je ] ); + *ap = attr_alloc( ad_allowedAttributesEffective ); + (*ap)->a_vals = bv_effective; + (*ap)->a_nvals = bv_effective; + (*ap)->a_numvals = je; + 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 = "allowed"; + + 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 */