Back to index

openldap  2.4.31
allowed.c
Go to the documentation of this file.
00001 /* allowed.c - add allowed attributes based on ACL */
00002 /* $OpenLDAP$ */
00003 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00004  *
00005  * Copyright 2006-2012 The OpenLDAP Foundation.
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted only as authorized by the OpenLDAP
00010  * Public License.
00011  *
00012  * A copy of this license is available in the file LICENSE in the
00013  * top-level directory of the distribution or, alternatively, at
00014  * <http://www.OpenLDAP.org/license.html>.
00015  */
00016 /* ACKNOWLEDGEMENTS:
00017  * This work was initially developed by Pierangelo Masarati for inclusion in
00018  * OpenLDAP Software.
00019  */
00020 
00021 /*
00022  * Rationale: return in allowedAttributes the attributes required/allowed
00023  * by the objectClasses that are currently present in an object; return
00024  * in allowedAttributesEffective the subset of the above that can be written
00025  * by the identity that performs the search.
00026  *
00027  * Caveats:
00028  * - right now, the overlay assumes that all values of the objectClass
00029  *   attribute will be returned in rs->sr_entry; this may not be true
00030  *   in general, but it usually is for back-bdb/back-hdb.  To generalize,
00031  *   the search request should be analyzed, and if allowedAttributes or
00032  *   allowedAttributesEffective are requested, add objectClass to the
00033  *   requested attributes
00034  * - it assumes that there is no difference between write-add and 
00035  *   write-delete
00036  * - it assumes that access rules do not depend on the values of the 
00037  *   attributes or on the contents of the entry (attr/val, filter, ...)
00038  *   allowedAttributes and allowedAttributesEffective cannot be used
00039  *   in filters or in compare
00040  */
00041 
00042 #include "portable.h"
00043 
00044 /* define SLAPD_OVER_ALLOWED=2 to build as run-time loadable module */
00045 #ifdef SLAPD_OVER_ALLOWED
00046 
00047 #include "slap.h"
00048 
00049 /*
00050  * Schema from
00051  *
00052  * <http://www.redhat.com/archives/fedora-directory-devel/2006-August/msg00007.html>
00053  *
00054  * posted by Andrew Bartlett
00055  */
00056 
00057 #define AA_SCHEMA_AT "1.2.840.113556.1.4"
00058 
00059 static AttributeDescription
00060               *ad_allowedChildClasses,
00061               *ad_allowedChildClassesEffective,
00062               *ad_allowedAttributes,
00063               *ad_allowedAttributesEffective;
00064 
00065 static struct {
00066        char *at;
00067        AttributeDescription **ad;
00068 } aa_attrs[] = {
00069        { "( " AA_SCHEMA_AT ".911 "
00070               "NAME 'allowedChildClasses' "
00071               "EQUALITY objectIdentifierMatch "
00072               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 "
00073               /* added by me :) */
00074               "DESC 'Child classes allowed for a given object' "
00075               "NO-USER-MODIFICATION "
00076               "USAGE directoryOperation )", &ad_allowedChildClasses },
00077        { "( " AA_SCHEMA_AT ".912 "
00078               "NAME 'allowedChildClassesEffective' "
00079               "EQUALITY objectIdentifierMatch "
00080               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 "
00081               /* added by me :) */
00082               "DESC 'Child classes allowed for a given object according to ACLs' "
00083               "NO-USER-MODIFICATION "
00084               "USAGE directoryOperation )", &ad_allowedChildClassesEffective },
00085        { "( " AA_SCHEMA_AT ".913 "
00086               "NAME 'allowedAttributes' "
00087               "EQUALITY objectIdentifierMatch "
00088               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 "
00089               /* added by me :) */
00090               "DESC 'Attributes allowed for a given object' "
00091               "NO-USER-MODIFICATION "
00092               "USAGE directoryOperation )", &ad_allowedAttributes },
00093        { "( " AA_SCHEMA_AT ".914 "
00094               "NAME 'allowedAttributesEffective' "
00095               "EQUALITY objectIdentifierMatch "
00096               "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 "
00097               /* added by me :) */
00098               "DESC 'Attributes allowed for a given object according to ACLs' "
00099               "NO-USER-MODIFICATION "
00100               "USAGE directoryOperation )", &ad_allowedAttributesEffective },
00101 
00102        /* TODO: add objectClass stuff? */
00103 
00104        { NULL, NULL }
00105 };
00106 
00107 static int
00108 aa_add_at( AttributeType *at, AttributeType ***atpp )
00109 {
00110        int           i = 0;
00111 
00112        if ( *atpp ) {
00113               for ( i = 0; (*atpp)[ i ] != NULL; i++ ) {
00114                      if ( (*atpp)[ i ] == at ) {
00115                             break;
00116                      }
00117               }
00118        
00119               if ( (*atpp)[ i ] != NULL ) {
00120                      return 0;
00121               }
00122        }
00123 
00124        *atpp = ch_realloc( *atpp, sizeof( AttributeType * ) * ( i + 2 ) );
00125        (*atpp)[ i ] = at;
00126        (*atpp)[ i + 1 ] = NULL;
00127 
00128        return 0;
00129 }
00130 
00131 static int
00132 aa_add_oc( ObjectClass *oc, ObjectClass ***ocpp, AttributeType ***atpp )
00133 {
00134        int           i = 0;
00135 
00136        if ( *ocpp ) {
00137               for ( ; (*ocpp)[ i ] != NULL; i++ ) {
00138                      if ( (*ocpp)[ i ] == oc ) {
00139                             break;
00140                      }
00141               }
00142 
00143               if ( (*ocpp)[ i ] != NULL ) {
00144                      return 0;
00145               }
00146        }
00147 
00148        *ocpp = ch_realloc( *ocpp, sizeof( ObjectClass * ) * ( i + 2 ) );
00149        (*ocpp)[ i ] = oc;
00150        (*ocpp)[ i + 1 ] = NULL;
00151 
00152        if ( oc->soc_required ) {
00153               int           i;
00154 
00155               for ( i = 0; oc->soc_required[ i ] != NULL; i++ ) {
00156                      aa_add_at( oc->soc_required[ i ], atpp );
00157               }
00158        }
00159 
00160        if ( oc->soc_allowed ) {
00161               int           i;
00162 
00163               for ( i = 0; oc->soc_allowed[ i ] != NULL; i++ ) {
00164                      aa_add_at( oc->soc_allowed[ i ], atpp );
00165               }
00166        }
00167 
00168        return 0;
00169 }
00170 
00171 static int
00172 aa_operational( Operation *op, SlapReply *rs )
00173 {
00174        Attribute            *a, **ap;
00175        AccessControlState   acl_state = ACL_STATE_INIT;
00176        struct berval        *v;
00177        AttributeType        **atp = NULL;
00178        ObjectClass          **ocp = NULL;
00179 
00180 #define       GOT_NONE      (0x0U)
00181 #define       GOT_C         (0x1U)
00182 #define       GOT_CE        (0x2U)
00183 #define       GOT_A         (0x4U)
00184 #define       GOT_AE        (0x8U)
00185 #define       GOT_ALL              (GOT_C|GOT_CE|GOT_A|GOT_AE)
00186        int           got = GOT_NONE;
00187 
00188        /* only add if requested */
00189        if ( SLAP_OPATTRS( rs->sr_attr_flags ) ) {
00190               got = GOT_ALL;
00191 
00192        } else {
00193               if ( ad_inlist( ad_allowedChildClasses, rs->sr_attrs ) ) {
00194                      got |= GOT_C;
00195               }
00196 
00197               if ( ad_inlist( ad_allowedChildClassesEffective, rs->sr_attrs ) ) {
00198                      got |= GOT_CE;
00199               }
00200 
00201               if ( ad_inlist( ad_allowedAttributes, rs->sr_attrs ) ) {
00202                      got |= GOT_A;
00203               }
00204 
00205               if ( ad_inlist( ad_allowedAttributesEffective, rs->sr_attrs ) ) {
00206                      got |= GOT_AE;
00207               }
00208        }
00209 
00210        if ( got == GOT_NONE ) {
00211               return SLAP_CB_CONTINUE;
00212        }
00213 
00214        /* shouldn't be called without an entry; please check */
00215        assert( rs->sr_entry != NULL );
00216 
00217        for ( ap = &rs->sr_operational_attrs; *ap != NULL; ap = &(*ap)->a_next )
00218               /* go to last */ ;
00219 
00220        /* see caveats; this is not guaranteed for all backends */
00221        a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_objectClass );
00222        if ( a == NULL ) {
00223               goto do_oc;
00224        }
00225 
00226        /* if client has no access to objectClass attribute; don't compute */
00227        if ( !access_allowed( op, rs->sr_entry, slap_schema.si_ad_objectClass,
00228                             NULL, ACL_READ, &acl_state ) )
00229        {
00230               return SLAP_CB_CONTINUE;
00231        }
00232 
00233        for ( v = a->a_nvals; !BER_BVISNULL( v ); v++ ) {
00234               ObjectClass   *oc = oc_bvfind( v );
00235 
00236               assert( oc != NULL );
00237 
00238               /* if client has no access to specific value, don't compute */
00239               if ( !access_allowed( op, rs->sr_entry,
00240                      slap_schema.si_ad_objectClass,
00241                      &oc->soc_cname, ACL_READ, &acl_state ) )
00242               {
00243                      continue;
00244               }
00245 
00246               aa_add_oc( oc, &ocp, &atp );
00247 
00248               if ( oc->soc_sups ) {
00249                      int i;
00250 
00251                      for ( i = 0; oc->soc_sups[ i ] != NULL; i++ ) {
00252                             aa_add_oc( oc->soc_sups[ i ], &ocp, &atp );
00253                      }
00254               }
00255        }
00256 
00257        ch_free( ocp );
00258 
00259        if ( atp != NULL ) {
00260               BerVarray     bv_allowed = NULL,
00261                             bv_effective = NULL;
00262               int           i, ja = 0, je = 0;
00263 
00264               for ( i = 0; atp[ i ] != NULL; i++ )
00265                      /* just count */ ;
00266        
00267               if ( got & GOT_A ) {
00268                      bv_allowed = ber_memalloc( sizeof( struct berval ) * ( i + 1 ) );
00269               }
00270               if ( got & GOT_AE ) {
00271                      bv_effective = ber_memalloc( sizeof( struct berval ) * ( i + 1 ) );
00272               }
00273 
00274               for ( i = 0, ja = 0, je = 0; atp[ i ] != NULL; i++ ) {
00275                      if ( got & GOT_A ) {
00276                             ber_dupbv( &bv_allowed[ ja ], &atp[ i ]->sat_cname );
00277                             ja++;
00278                      }
00279 
00280                      if ( got & GOT_AE ) {
00281                             AttributeDescription *ad = NULL;
00282                             const char           *text = NULL;
00283        
00284                             if ( slap_bv2ad( &atp[ i ]->sat_cname, &ad, &text ) ) {
00285                                    /* log? */
00286                                    continue;
00287                             }
00288 
00289                             if ( access_allowed( op, rs->sr_entry,
00290                                    ad, NULL, ACL_WRITE, NULL ) )
00291                             {
00292                                    ber_dupbv( &bv_effective[ je ], &atp[ i ]->sat_cname );
00293                                    je++;
00294                             }
00295                      }
00296               }
00297 
00298               ch_free( atp );
00299 
00300               if ( ( got & GOT_A ) && ja > 0 ) {
00301                      BER_BVZERO( &bv_allowed[ ja ] );
00302                      *ap = attr_alloc( ad_allowedAttributes );
00303                      (*ap)->a_vals = bv_allowed;
00304                      (*ap)->a_nvals = bv_allowed;
00305                      (*ap)->a_numvals = ja;
00306                      ap = &(*ap)->a_next;
00307               }
00308 
00309               if ( ( got & GOT_AE ) && je > 0 ) {
00310                      BER_BVZERO( &bv_effective[ je ] );
00311                      *ap = attr_alloc( ad_allowedAttributesEffective );
00312                      (*ap)->a_vals = bv_effective;
00313                      (*ap)->a_nvals = bv_effective;
00314                      (*ap)->a_numvals = je;
00315                      ap = &(*ap)->a_next;
00316               }
00317 
00318               *ap = NULL;
00319        }
00320 
00321 do_oc:;
00322        if ( ( got & GOT_C ) || ( got & GOT_CE ) ) {
00323               BerVarray     bv_allowed = NULL,
00324                             bv_effective = NULL;
00325               int           i, ja = 0, je = 0;
00326 
00327               ObjectClass   *oc;
00328 
00329               for ( oc_start( &oc ); oc != NULL; oc_next( &oc ) ) {
00330                      /* we can only add AUXILIARY objectClasses */
00331                      if ( oc->soc_kind != LDAP_SCHEMA_AUXILIARY ) {
00332                             continue;
00333                      }
00334 
00335                      i++;
00336               }
00337 
00338               if ( got & GOT_C ) {
00339                      bv_allowed = ber_memalloc( sizeof( struct berval ) * ( i + 1 ) );
00340               }
00341               if ( got & GOT_CE ) {
00342                      bv_effective = ber_memalloc( sizeof( struct berval ) * ( i + 1 ) );
00343               }
00344 
00345               for ( oc_start( &oc ); oc != NULL; oc_next( &oc ) ) {
00346                      /* we can only add AUXILIARY objectClasses */
00347                      if ( oc->soc_kind != LDAP_SCHEMA_AUXILIARY ) {
00348                             continue;
00349                      }
00350 
00351                      if ( got & GOT_C ) {
00352                             ber_dupbv( &bv_allowed[ ja ], &oc->soc_cname );
00353                             ja++;
00354                      }
00355 
00356                      if ( got & GOT_CE ) {
00357                             if ( !access_allowed( op, rs->sr_entry,
00358                                    slap_schema.si_ad_objectClass,
00359                                    &oc->soc_cname, ACL_WRITE, NULL ) )
00360                             {
00361                                    goto done_ce;
00362                             }
00363 
00364                             if ( oc->soc_required ) {
00365                                    for ( i = 0; oc->soc_required[ i ] != NULL; i++ ) {
00366                                           AttributeDescription *ad = NULL;
00367                                           const char           *text = NULL;
00368        
00369                                           if ( slap_bv2ad( &oc->soc_required[ i ]->sat_cname, &ad, &text ) ) {
00370                                                  /* log? */
00371                                                  continue;
00372                                           }
00373 
00374                                           if ( !access_allowed( op, rs->sr_entry,
00375                                                  ad, NULL, ACL_WRITE, NULL ) )
00376                                           {
00377                                                  goto done_ce;
00378                                           }
00379                                    }
00380                             }
00381 
00382                             ber_dupbv( &bv_effective[ je ], &oc->soc_cname );
00383                             je++;
00384                      }
00385 done_ce:;
00386               }
00387 
00388               if ( ( got & GOT_C ) && ja > 0 ) {
00389                      BER_BVZERO( &bv_allowed[ ja ] );
00390                      *ap = attr_alloc( ad_allowedChildClasses );
00391                      (*ap)->a_vals = bv_allowed;
00392                      (*ap)->a_nvals = bv_allowed;
00393                      (*ap)->a_numvals = ja;
00394                      ap = &(*ap)->a_next;
00395               }
00396 
00397               if ( ( got & GOT_CE ) && je > 0 ) {
00398                      BER_BVZERO( &bv_effective[ je ] );
00399                      *ap = attr_alloc( ad_allowedChildClassesEffective );
00400                      (*ap)->a_vals = bv_effective;
00401                      (*ap)->a_nvals = bv_effective;
00402                      (*ap)->a_numvals = je;
00403                      ap = &(*ap)->a_next;
00404               }
00405 
00406               *ap = NULL;
00407        }
00408 
00409        return SLAP_CB_CONTINUE;
00410 }
00411 
00412 static slap_overinst aa;
00413 
00414 #if LDAP_VENDOR_VERSION_MINOR != X && LDAP_VENDOR_VERSION_MINOR <= 3
00415 /* backport register_at() from HEAD, to allow building with OL <= 2.3 */
00416 static int
00417 register_at( char *def, AttributeDescription **rad, int dupok )
00418 {
00419        LDAPAttributeType *at;
00420        int code, freeit = 0;
00421        const char *err;
00422        AttributeDescription *ad = NULL;
00423 
00424        at = ldap_str2attributetype( def, &code, &err, LDAP_SCHEMA_ALLOW_ALL );
00425        if ( !at ) {
00426               Debug( LDAP_DEBUG_ANY,
00427                      "register_at: AttributeType \"%s\": %s, %s\n",
00428                             def, ldap_scherr2str(code), err );
00429               return code;
00430        }
00431 
00432        code = at_add( at, 0, NULL, &err );
00433        if ( code ) {
00434               if ( code == SLAP_SCHERR_ATTR_DUP && dupok ) {
00435                      freeit = 1;
00436 
00437               } else {
00438                      ldap_attributetype_free( at );
00439                      Debug( LDAP_DEBUG_ANY,
00440                             "register_at: AttributeType \"%s\": %s, %s\n",
00441                             def, scherr2str(code), err );
00442                      return code;
00443               }
00444        }
00445        code = slap_str2ad( at->at_names[0], &ad, &err );
00446        if ( freeit || code ) {
00447               ldap_attributetype_free( at );
00448        } else {
00449               ldap_memfree( at );
00450        }
00451        if ( code ) {
00452               Debug( LDAP_DEBUG_ANY, "register_at: AttributeType \"%s\": %s\n",
00453                      def, err, 0 );
00454        }
00455        if ( rad ) *rad = ad;
00456        return code;
00457 }
00458 #endif
00459 
00460 #if SLAPD_OVER_ALLOWED == SLAPD_MOD_DYNAMIC
00461 static
00462 #endif /* SLAPD_OVER_ALLOWED == SLAPD_MOD_DYNAMIC */
00463 int
00464 aa_initialize( void )
00465 {
00466        int i;
00467 
00468        aa.on_bi.bi_type = "allowed";
00469 
00470        aa.on_bi.bi_operational = aa_operational;
00471 
00472        /* aa schema integration */
00473        for ( i = 0; aa_attrs[i].at; i++ ) {
00474               int code;
00475 
00476               code = register_at( aa_attrs[i].at, aa_attrs[i].ad, 0 );
00477               if ( code ) {
00478                      Debug( LDAP_DEBUG_ANY,
00479                             "aa_initialize: register_at failed\n", 0, 0, 0 );
00480                      return -1;
00481               }
00482        }
00483 
00484        return overlay_register( &aa );
00485 }
00486 
00487 #if SLAPD_OVER_ALLOWED == SLAPD_MOD_DYNAMIC
00488 int
00489 init_module( int argc, char *argv[] )
00490 {
00491        return aa_initialize();
00492 }
00493 #endif /* SLAPD_OVER_ALLOWED == SLAPD_MOD_DYNAMIC */
00494 
00495 #endif /* SLAPD_OVER_ALLOWED */