1 /* $NetBSD: allowed.c,v 1.1.1.2 2010/12/12 15:18:55 adam Exp $ */ 2 3 /* allowed.c - add allowed attributes based on ACL */ 4 /* OpenLDAP: pkg/ldap/contrib/slapd-modules/allowed/allowed.c,v 1.3.2.4 2010/04/15 20:35:22 quanah Exp */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2006-2010 The OpenLDAP Foundation. 8 * All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted only as authorized by the OpenLDAP 12 * Public License. 13 * 14 * A copy of this license is available in the file LICENSE in the 15 * top-level directory of the distribution or, alternatively, at 16 * <http://www.OpenLDAP.org/license.html>. 17 */ 18 /* ACKNOWLEDGEMENTS: 19 * This work was initially developed by Pierangelo Masarati for inclusion in 20 * OpenLDAP Software. 21 */ 22 23 /* 24 * Rationale: return in allowedAttributes the attributes required/allowed 25 * by the objectClasses that are currently present in an object; return 26 * in allowedAttributesEffective the subset of the above that can be written 27 * by the identity that performs the search. 28 * 29 * Caveats: 30 * - right now, the overlay assumes that all values of the objectClass 31 * attribute will be returned in rs->sr_entry; this may not be true 32 * in general, but it usually is for back-bdb/back-hdb. To generalize, 33 * the search request should be analyzed, and if allowedAttributes or 34 * allowedAttributesEffective are requested, add objectClass to the 35 * requested attributes 36 * - it assumes that there is no difference between write-add and 37 * write-delete 38 * - it assumes that access rules do not depend on the values of the 39 * attributes or on the contents of the entry (attr/val, filter, ...) 40 * allowedAttributes and allowedAttributesEffective cannot be used 41 * in filters or in compare 42 */ 43 44 #include "portable.h" 45 46 /* define SLAPD_OVER_ALLOWED=2 to build as run-time loadable module */ 47 #ifdef SLAPD_OVER_ALLOWED 48 49 #include "slap.h" 50 51 /* 52 * Schema from 53 * 54 * <http://www.redhat.com/archives/fedora-directory-devel/2006-August/msg00007.html> 55 * 56 * posted by Andrew Bartlett 57 */ 58 59 #define AA_SCHEMA_AT "1.2.840.113556.1.4" 60 61 static AttributeDescription 62 *ad_allowedChildClasses, 63 *ad_allowedChildClassesEffective, 64 *ad_allowedAttributes, 65 *ad_allowedAttributesEffective; 66 67 static struct { 68 char *at; 69 AttributeDescription **ad; 70 } aa_attrs[] = { 71 { "( " AA_SCHEMA_AT ".911 " 72 "NAME 'allowedChildClasses' " 73 "EQUALITY objectIdentifierMatch " 74 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 " 75 /* added by me :) */ 76 "DESC 'Child classes allowed for a given object' " 77 "NO-USER-MODIFICATION " 78 "USAGE directoryOperation )", &ad_allowedChildClasses }, 79 { "( " AA_SCHEMA_AT ".912 " 80 "NAME 'allowedChildClassesEffective' " 81 "EQUALITY objectIdentifierMatch " 82 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 " 83 /* added by me :) */ 84 "DESC 'Child classes allowed for a given object according to ACLs' " 85 "NO-USER-MODIFICATION " 86 "USAGE directoryOperation )", &ad_allowedChildClassesEffective }, 87 { "( " AA_SCHEMA_AT ".913 " 88 "NAME 'allowedAttributes' " 89 "EQUALITY objectIdentifierMatch " 90 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 " 91 /* added by me :) */ 92 "DESC 'Attributes allowed for a given object' " 93 "NO-USER-MODIFICATION " 94 "USAGE directoryOperation )", &ad_allowedAttributes }, 95 { "( " AA_SCHEMA_AT ".914 " 96 "NAME 'allowedAttributesEffective' " 97 "EQUALITY objectIdentifierMatch " 98 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 " 99 /* added by me :) */ 100 "DESC 'Attributes allowed for a given object according to ACLs' " 101 "NO-USER-MODIFICATION " 102 "USAGE directoryOperation )", &ad_allowedAttributesEffective }, 103 104 /* TODO: add objectClass stuff? */ 105 106 { NULL, NULL } 107 }; 108 109 static int 110 aa_add_at( AttributeType *at, AttributeType ***atpp ) 111 { 112 int i = 0; 113 114 if ( *atpp ) { 115 for ( i = 0; (*atpp)[ i ] != NULL; i++ ) { 116 if ( (*atpp)[ i ] == at ) { 117 break; 118 } 119 } 120 121 if ( (*atpp)[ i ] != NULL ) { 122 return 0; 123 } 124 } 125 126 *atpp = ch_realloc( *atpp, sizeof( AttributeType * ) * ( i + 2 ) ); 127 (*atpp)[ i ] = at; 128 (*atpp)[ i + 1 ] = NULL; 129 130 return 0; 131 } 132 133 static int 134 aa_add_oc( ObjectClass *oc, ObjectClass ***ocpp, AttributeType ***atpp ) 135 { 136 int i = 0; 137 138 if ( *ocpp ) { 139 for ( ; (*ocpp)[ i ] != NULL; i++ ) { 140 if ( (*ocpp)[ i ] == oc ) { 141 break; 142 } 143 } 144 145 if ( (*ocpp)[ i ] != NULL ) { 146 return 0; 147 } 148 } 149 150 *ocpp = ch_realloc( *ocpp, sizeof( ObjectClass * ) * ( i + 2 ) ); 151 (*ocpp)[ i ] = oc; 152 (*ocpp)[ i + 1 ] = NULL; 153 154 if ( oc->soc_required ) { 155 int i; 156 157 for ( i = 0; oc->soc_required[ i ] != NULL; i++ ) { 158 aa_add_at( oc->soc_required[ i ], atpp ); 159 } 160 } 161 162 if ( oc->soc_allowed ) { 163 int i; 164 165 for ( i = 0; oc->soc_allowed[ i ] != NULL; i++ ) { 166 aa_add_at( oc->soc_allowed[ i ], atpp ); 167 } 168 } 169 170 return 0; 171 } 172 173 static int 174 aa_operational( Operation *op, SlapReply *rs ) 175 { 176 Attribute *a, **ap; 177 AccessControlState acl_state = ACL_STATE_INIT; 178 struct berval *v; 179 AttributeType **atp = NULL; 180 ObjectClass **ocp = NULL; 181 182 #define GOT_NONE (0x0U) 183 #define GOT_C (0x1U) 184 #define GOT_CE (0x2U) 185 #define GOT_A (0x4U) 186 #define GOT_AE (0x8U) 187 #define GOT_ALL (GOT_C|GOT_CE|GOT_A|GOT_AE) 188 int got = GOT_NONE; 189 190 /* only add if requested */ 191 if ( SLAP_OPATTRS( rs->sr_attr_flags ) ) { 192 got = GOT_ALL; 193 194 } else { 195 if ( ad_inlist( ad_allowedChildClasses, rs->sr_attrs ) ) { 196 got |= GOT_C; 197 } 198 199 if ( ad_inlist( ad_allowedChildClassesEffective, rs->sr_attrs ) ) { 200 got |= GOT_CE; 201 } 202 203 if ( ad_inlist( ad_allowedAttributes, rs->sr_attrs ) ) { 204 got |= GOT_A; 205 } 206 207 if ( ad_inlist( ad_allowedAttributesEffective, rs->sr_attrs ) ) { 208 got |= GOT_AE; 209 } 210 } 211 212 if ( got == GOT_NONE ) { 213 return SLAP_CB_CONTINUE; 214 } 215 216 /* shouldn't be called without an entry; please check */ 217 assert( rs->sr_entry != NULL ); 218 219 for ( ap = &rs->sr_operational_attrs; *ap != NULL; ap = &(*ap)->a_next ) 220 /* go to last */ ; 221 222 /* see caveats; this is not guaranteed for all backends */ 223 a = attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_objectClass ); 224 if ( a == NULL ) { 225 goto do_oc; 226 } 227 228 /* if client has no access to objectClass attribute; don't compute */ 229 if ( !access_allowed( op, rs->sr_entry, slap_schema.si_ad_objectClass, 230 NULL, ACL_READ, &acl_state ) ) 231 { 232 return SLAP_CB_CONTINUE; 233 } 234 235 for ( v = a->a_nvals; !BER_BVISNULL( v ); v++ ) { 236 ObjectClass *oc = oc_bvfind( v ); 237 238 assert( oc != NULL ); 239 240 /* if client has no access to specific value, don't compute */ 241 if ( !access_allowed( op, rs->sr_entry, 242 slap_schema.si_ad_objectClass, 243 &oc->soc_cname, ACL_READ, &acl_state ) ) 244 { 245 continue; 246 } 247 248 aa_add_oc( oc, &ocp, &atp ); 249 250 if ( oc->soc_sups ) { 251 int i; 252 253 for ( i = 0; oc->soc_sups[ i ] != NULL; i++ ) { 254 aa_add_oc( oc->soc_sups[ i ], &ocp, &atp ); 255 } 256 } 257 } 258 259 ch_free( ocp ); 260 261 if ( atp != NULL ) { 262 BerVarray bv_allowed = NULL, 263 bv_effective = NULL; 264 int i, ja = 0, je = 0; 265 266 for ( i = 0; atp[ i ] != NULL; i++ ) 267 /* just count */ ; 268 269 if ( got & GOT_A ) { 270 bv_allowed = ber_memalloc( sizeof( struct berval ) * ( i + 1 ) ); 271 } 272 if ( got & GOT_AE ) { 273 bv_effective = ber_memalloc( sizeof( struct berval ) * ( i + 1 ) ); 274 } 275 276 for ( i = 0, ja = 0, je = 0; atp[ i ] != NULL; i++ ) { 277 if ( got & GOT_A ) { 278 ber_dupbv( &bv_allowed[ ja ], &atp[ i ]->sat_cname ); 279 ja++; 280 } 281 282 if ( got & GOT_AE ) { 283 AttributeDescription *ad = NULL; 284 const char *text = NULL; 285 286 if ( slap_bv2ad( &atp[ i ]->sat_cname, &ad, &text ) ) { 287 /* log? */ 288 continue; 289 } 290 291 if ( access_allowed( op, rs->sr_entry, 292 ad, NULL, ACL_WRITE, NULL ) ) 293 { 294 ber_dupbv( &bv_effective[ je ], &atp[ i ]->sat_cname ); 295 je++; 296 } 297 } 298 } 299 300 ch_free( atp ); 301 302 if ( ( got & GOT_A ) && ja > 0 ) { 303 BER_BVZERO( &bv_allowed[ ja ] ); 304 *ap = attr_alloc( ad_allowedAttributes ); 305 (*ap)->a_vals = bv_allowed; 306 (*ap)->a_nvals = bv_allowed; 307 (*ap)->a_numvals = ja; 308 ap = &(*ap)->a_next; 309 } 310 311 if ( ( got & GOT_AE ) && je > 0 ) { 312 BER_BVZERO( &bv_effective[ je ] ); 313 *ap = attr_alloc( ad_allowedAttributesEffective ); 314 (*ap)->a_vals = bv_effective; 315 (*ap)->a_nvals = bv_effective; 316 (*ap)->a_numvals = je; 317 ap = &(*ap)->a_next; 318 } 319 320 *ap = NULL; 321 } 322 323 do_oc:; 324 if ( ( got & GOT_C ) || ( got & GOT_CE ) ) { 325 BerVarray bv_allowed = NULL, 326 bv_effective = NULL; 327 int i, ja = 0, je = 0; 328 329 ObjectClass *oc; 330 331 for ( oc_start( &oc ); oc != NULL; oc_next( &oc ) ) { 332 /* we can only add AUXILIARY objectClasses */ 333 if ( oc->soc_kind != LDAP_SCHEMA_AUXILIARY ) { 334 continue; 335 } 336 337 i++; 338 } 339 340 if ( got & GOT_C ) { 341 bv_allowed = ber_memalloc( sizeof( struct berval ) * ( i + 1 ) ); 342 } 343 if ( got & GOT_CE ) { 344 bv_effective = ber_memalloc( sizeof( struct berval ) * ( i + 1 ) ); 345 } 346 347 for ( oc_start( &oc ); oc != NULL; oc_next( &oc ) ) { 348 /* we can only add AUXILIARY objectClasses */ 349 if ( oc->soc_kind != LDAP_SCHEMA_AUXILIARY ) { 350 continue; 351 } 352 353 if ( got & GOT_C ) { 354 ber_dupbv( &bv_allowed[ ja ], &oc->soc_cname ); 355 ja++; 356 } 357 358 if ( got & GOT_CE ) { 359 if ( !access_allowed( op, rs->sr_entry, 360 slap_schema.si_ad_objectClass, 361 &oc->soc_cname, ACL_WRITE, NULL ) ) 362 { 363 goto done_ce; 364 } 365 366 if ( oc->soc_required ) { 367 for ( i = 0; oc->soc_required[ i ] != NULL; i++ ) { 368 AttributeDescription *ad = NULL; 369 const char *text = NULL; 370 371 if ( slap_bv2ad( &oc->soc_required[ i ]->sat_cname, &ad, &text ) ) { 372 /* log? */ 373 continue; 374 } 375 376 if ( !access_allowed( op, rs->sr_entry, 377 ad, NULL, ACL_WRITE, NULL ) ) 378 { 379 goto done_ce; 380 } 381 } 382 } 383 384 ber_dupbv( &bv_effective[ je ], &oc->soc_cname ); 385 je++; 386 } 387 done_ce:; 388 } 389 390 if ( ( got & GOT_C ) && ja > 0 ) { 391 BER_BVZERO( &bv_allowed[ ja ] ); 392 *ap = attr_alloc( ad_allowedChildClasses ); 393 (*ap)->a_vals = bv_allowed; 394 (*ap)->a_nvals = bv_allowed; 395 (*ap)->a_numvals = ja; 396 ap = &(*ap)->a_next; 397 } 398 399 if ( ( got & GOT_CE ) && je > 0 ) { 400 BER_BVZERO( &bv_effective[ je ] ); 401 *ap = attr_alloc( ad_allowedChildClassesEffective ); 402 (*ap)->a_vals = bv_effective; 403 (*ap)->a_nvals = bv_effective; 404 (*ap)->a_numvals = je; 405 ap = &(*ap)->a_next; 406 } 407 408 *ap = NULL; 409 } 410 411 return SLAP_CB_CONTINUE; 412 } 413 414 static slap_overinst aa; 415 416 #if LDAP_VENDOR_VERSION_MINOR != X && LDAP_VENDOR_VERSION_MINOR <= 3 417 /* backport register_at() from HEAD, to allow building with OL <= 2.3 */ 418 static int 419 register_at( char *def, AttributeDescription **rad, int dupok ) 420 { 421 LDAPAttributeType *at; 422 int code, freeit = 0; 423 const char *err; 424 AttributeDescription *ad = NULL; 425 426 at = ldap_str2attributetype( def, &code, &err, LDAP_SCHEMA_ALLOW_ALL ); 427 if ( !at ) { 428 Debug( LDAP_DEBUG_ANY, 429 "register_at: AttributeType \"%s\": %s, %s\n", 430 def, ldap_scherr2str(code), err ); 431 return code; 432 } 433 434 code = at_add( at, 0, NULL, &err ); 435 if ( code ) { 436 if ( code == SLAP_SCHERR_ATTR_DUP && dupok ) { 437 freeit = 1; 438 439 } else { 440 ldap_attributetype_free( at ); 441 Debug( LDAP_DEBUG_ANY, 442 "register_at: AttributeType \"%s\": %s, %s\n", 443 def, scherr2str(code), err ); 444 return code; 445 } 446 } 447 code = slap_str2ad( at->at_names[0], &ad, &err ); 448 if ( freeit || code ) { 449 ldap_attributetype_free( at ); 450 } else { 451 ldap_memfree( at ); 452 } 453 if ( code ) { 454 Debug( LDAP_DEBUG_ANY, "register_at: AttributeType \"%s\": %s\n", 455 def, err, 0 ); 456 } 457 if ( rad ) *rad = ad; 458 return code; 459 } 460 #endif 461 462 #if SLAPD_OVER_ALLOWED == SLAPD_MOD_DYNAMIC 463 static 464 #endif /* SLAPD_OVER_ALLOWED == SLAPD_MOD_DYNAMIC */ 465 int 466 aa_initialize( void ) 467 { 468 int i; 469 470 aa.on_bi.bi_type = "allowed"; 471 472 aa.on_bi.bi_operational = aa_operational; 473 474 /* aa schema integration */ 475 for ( i = 0; aa_attrs[i].at; i++ ) { 476 int code; 477 478 code = register_at( aa_attrs[i].at, aa_attrs[i].ad, 0 ); 479 if ( code ) { 480 Debug( LDAP_DEBUG_ANY, 481 "aa_initialize: register_at failed\n", 0, 0, 0 ); 482 return -1; 483 } 484 } 485 486 return overlay_register( &aa ); 487 } 488 489 #if SLAPD_OVER_ALLOWED == SLAPD_MOD_DYNAMIC 490 int 491 init_module( int argc, char *argv[] ) 492 { 493 return aa_initialize(); 494 } 495 #endif /* SLAPD_OVER_ALLOWED == SLAPD_MOD_DYNAMIC */ 496 497 #endif /* SLAPD_OVER_ALLOWED */ 498