1 /* cr.c - content rule routines */ 2 /* $OpenLDAP: pkg/ldap/servers/slapd/cr.c,v 1.22.2.3 2008/02/11 23:26:44 kurt Exp $ */ 3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 1998-2008 The OpenLDAP Foundation. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted only as authorized by the OpenLDAP 10 * Public License. 11 * 12 * A copy of this license is available in the file LICENSE in the 13 * top-level directory of the distribution or, alternatively, at 14 * <http://www.OpenLDAP.org/license.html>. 15 */ 16 17 #include "portable.h" 18 19 #include <stdio.h> 20 21 #include <ac/ctype.h> 22 #include <ac/string.h> 23 #include <ac/socket.h> 24 25 #include "slap.h" 26 27 struct cindexrec { 28 struct berval cir_name; 29 ContentRule *cir_cr; 30 }; 31 32 static Avlnode *cr_index = NULL; 33 static LDAP_STAILQ_HEAD(CRList, ContentRule) cr_list 34 = LDAP_STAILQ_HEAD_INITIALIZER(cr_list); 35 36 static int 37 cr_index_cmp( 38 const void *v_cir1, 39 const void *v_cir2 ) 40 { 41 const struct cindexrec *cir1 = v_cir1; 42 const struct cindexrec *cir2 = v_cir2; 43 int i = cir1->cir_name.bv_len - cir2->cir_name.bv_len; 44 if (i) return i; 45 return strcasecmp( cir1->cir_name.bv_val, cir2->cir_name.bv_val ); 46 } 47 48 static int 49 cr_index_name_cmp( 50 const void *v_name, 51 const void *v_cir ) 52 { 53 const struct berval *name = v_name; 54 const struct cindexrec *cir = v_cir; 55 int i = name->bv_len - cir->cir_name.bv_len; 56 if (i) return i; 57 return strncasecmp( name->bv_val, cir->cir_name.bv_val, name->bv_len ); 58 } 59 60 ContentRule * 61 cr_find( const char *crname ) 62 { 63 struct berval bv; 64 65 bv.bv_val = (char *)crname; 66 bv.bv_len = strlen( crname ); 67 68 return( cr_bvfind( &bv ) ); 69 } 70 71 ContentRule * 72 cr_bvfind( struct berval *crname ) 73 { 74 struct cindexrec *cir; 75 76 cir = avl_find( cr_index, crname, cr_index_name_cmp ); 77 78 if ( cir != NULL ) { 79 return( cir->cir_cr ); 80 } 81 82 return( NULL ); 83 } 84 85 static int 86 cr_destroy_one( ContentRule *c ) 87 { 88 assert( c != NULL ); 89 90 if (c->scr_auxiliaries) ldap_memfree(c->scr_auxiliaries); 91 if (c->scr_required) ldap_memfree(c->scr_required); 92 if (c->scr_allowed) ldap_memfree(c->scr_allowed); 93 if (c->scr_precluded) ldap_memfree(c->scr_precluded); 94 ldap_contentrule_free((LDAPContentRule *)c); 95 96 return 0; 97 } 98 99 void 100 cr_destroy( void ) 101 { 102 ContentRule *c; 103 104 avl_free(cr_index, ldap_memfree); 105 106 while( !LDAP_STAILQ_EMPTY(&cr_list) ) { 107 c = LDAP_STAILQ_FIRST(&cr_list); 108 LDAP_STAILQ_REMOVE_HEAD(&cr_list, scr_next); 109 110 cr_destroy_one( c ); 111 } 112 } 113 114 static int 115 cr_insert( 116 ContentRule *scr, 117 const char **err 118 ) 119 { 120 struct cindexrec *cir; 121 char **names; 122 123 if ( scr->scr_oid ) { 124 cir = (struct cindexrec *) 125 ch_calloc( 1, sizeof(struct cindexrec) ); 126 cir->cir_name.bv_val = scr->scr_oid; 127 cir->cir_name.bv_len = strlen( scr->scr_oid ); 128 cir->cir_cr = scr; 129 130 assert( cir->cir_name.bv_val != NULL ); 131 assert( cir->cir_cr != NULL ); 132 133 if ( avl_insert( &cr_index, (caddr_t) cir, 134 cr_index_cmp, avl_dup_error ) ) 135 { 136 *err = scr->scr_oid; 137 ldap_memfree(cir); 138 return SLAP_SCHERR_CR_DUP; 139 } 140 141 /* FIX: temporal consistency check */ 142 assert( cr_bvfind(&cir->cir_name) != NULL ); 143 } 144 145 if ( (names = scr->scr_names) ) { 146 while ( *names ) { 147 cir = (struct cindexrec *) 148 ch_calloc( 1, sizeof(struct cindexrec) ); 149 cir->cir_name.bv_val = *names; 150 cir->cir_name.bv_len = strlen( *names ); 151 cir->cir_cr = scr; 152 153 assert( cir->cir_name.bv_val != NULL ); 154 assert( cir->cir_cr != NULL ); 155 156 if ( avl_insert( &cr_index, (caddr_t) cir, 157 cr_index_cmp, avl_dup_error ) ) 158 { 159 *err = *names; 160 ldap_memfree(cir); 161 return SLAP_SCHERR_CR_DUP; 162 } 163 164 /* FIX: temporal consistency check */ 165 assert( cr_bvfind(&cir->cir_name) != NULL ); 166 167 names++; 168 } 169 } 170 171 LDAP_STAILQ_INSERT_TAIL(&cr_list, scr, scr_next); 172 173 return 0; 174 } 175 176 static int 177 cr_add_auxiliaries( 178 ContentRule *scr, 179 int *op, 180 const char **err ) 181 { 182 int naux; 183 184 if( scr->scr_oc_oids_aux == NULL ) return 0; 185 186 for( naux=0; scr->scr_oc_oids_aux[naux]; naux++ ) { 187 /* count them */ ; 188 } 189 190 scr->scr_auxiliaries = ch_calloc( naux+1, sizeof(ObjectClass *)); 191 192 for( naux=0; scr->scr_oc_oids_aux[naux]; naux++ ) { 193 ObjectClass *soc = scr->scr_auxiliaries[naux] 194 = oc_find(scr->scr_oc_oids_aux[naux]); 195 if ( !soc ) { 196 *err = scr->scr_oc_oids_aux[naux]; 197 return SLAP_SCHERR_CLASS_NOT_FOUND; 198 } 199 200 if( soc->soc_flags & SLAP_OC_OPERATIONAL && 201 soc != slap_schema.si_oc_extensibleObject ) 202 { 203 (*op)++; 204 } 205 206 if( soc->soc_kind != LDAP_SCHEMA_AUXILIARY ) { 207 *err = scr->scr_oc_oids_aux[naux]; 208 return SLAP_SCHERR_CR_BAD_AUX; 209 } 210 } 211 212 scr->scr_auxiliaries[naux] = NULL; 213 return 0; 214 } 215 216 static int 217 cr_create_required( 218 ContentRule *scr, 219 int *op, 220 const char **err ) 221 { 222 char **attrs = scr->scr_at_oids_must; 223 char **attrs1; 224 AttributeType *sat; 225 226 if ( attrs ) { 227 attrs1 = attrs; 228 while ( *attrs1 ) { 229 sat = at_find(*attrs1); 230 if ( !sat ) { 231 *err = *attrs1; 232 return SLAP_SCHERR_ATTR_NOT_FOUND; 233 } 234 235 if( is_at_operational( sat )) (*op)++; 236 237 if ( at_find_in_list(sat, scr->scr_required) < 0) { 238 if ( at_append_to_list(sat, &scr->scr_required) ) { 239 *err = *attrs1; 240 return SLAP_SCHERR_OUTOFMEM; 241 } 242 } else { 243 *err = *attrs1; 244 return SLAP_SCHERR_CR_BAD_AT; 245 } 246 attrs1++; 247 } 248 } 249 return 0; 250 } 251 252 static int 253 cr_create_allowed( 254 ContentRule *scr, 255 int *op, 256 const char **err ) 257 { 258 char **attrs = scr->scr_at_oids_may; 259 char **attrs1; 260 AttributeType *sat; 261 262 if ( attrs ) { 263 attrs1 = attrs; 264 while ( *attrs1 ) { 265 sat = at_find(*attrs1); 266 if ( !sat ) { 267 *err = *attrs1; 268 return SLAP_SCHERR_ATTR_NOT_FOUND; 269 } 270 271 if( is_at_operational( sat )) (*op)++; 272 273 if ( at_find_in_list(sat, scr->scr_required) < 0 && 274 at_find_in_list(sat, scr->scr_allowed) < 0 ) 275 { 276 if ( at_append_to_list(sat, &scr->scr_allowed) ) { 277 *err = *attrs1; 278 return SLAP_SCHERR_OUTOFMEM; 279 } 280 } else { 281 *err = *attrs1; 282 return SLAP_SCHERR_CR_BAD_AT; 283 } 284 attrs1++; 285 } 286 } 287 return 0; 288 } 289 290 static int 291 cr_create_precluded( 292 ContentRule *scr, 293 int *op, 294 const char **err ) 295 { 296 char **attrs = scr->scr_at_oids_not; 297 char **attrs1; 298 AttributeType *sat; 299 300 if ( attrs ) { 301 attrs1 = attrs; 302 while ( *attrs1 ) { 303 sat = at_find(*attrs1); 304 if ( !sat ) { 305 *err = *attrs1; 306 return SLAP_SCHERR_ATTR_NOT_FOUND; 307 } 308 309 if( is_at_operational( sat )) (*op)++; 310 311 /* FIXME: should also make sure attribute type is not 312 a required attribute of the structural class or 313 any auxiliary class */ 314 if ( at_find_in_list(sat, scr->scr_required) < 0 && 315 at_find_in_list(sat, scr->scr_allowed) < 0 && 316 at_find_in_list(sat, scr->scr_precluded) < 0 ) 317 { 318 if ( at_append_to_list(sat, &scr->scr_precluded) ) { 319 *err = *attrs1; 320 return SLAP_SCHERR_OUTOFMEM; 321 } 322 } else { 323 *err = *attrs1; 324 return SLAP_SCHERR_CR_BAD_AT; 325 } 326 attrs1++; 327 } 328 } 329 return 0; 330 } 331 332 int 333 cr_add( 334 LDAPContentRule *cr, 335 int user, 336 ContentRule **rscr, 337 const char **err 338 ) 339 { 340 ContentRule *scr; 341 int code; 342 int op = 0; 343 char *oidm = NULL; 344 345 if ( cr->cr_names != NULL ) { 346 int i; 347 348 for( i=0; cr->cr_names[i]; i++ ) { 349 if( !slap_valid_descr( cr->cr_names[i] ) ) { 350 return SLAP_SCHERR_BAD_DESCR; 351 } 352 } 353 } 354 355 if ( !OID_LEADCHAR( cr->cr_oid[0] )) { 356 /* Expand OID macros */ 357 char *oid = oidm_find( cr->cr_oid ); 358 if ( !oid ) { 359 *err = cr->cr_oid; 360 return SLAP_SCHERR_OIDM; 361 } 362 if ( oid != cr->cr_oid ) { 363 oidm = cr->cr_oid; 364 cr->cr_oid = oid; 365 } 366 } 367 368 scr = (ContentRule *) ch_calloc( 1, sizeof(ContentRule) ); 369 AC_MEMCPY( &scr->scr_crule, cr, sizeof(LDAPContentRule) ); 370 371 scr->scr_oidmacro = oidm; 372 scr->scr_sclass = oc_find(cr->cr_oid); 373 if ( !scr->scr_sclass ) { 374 *err = cr->cr_oid; 375 code = SLAP_SCHERR_CLASS_NOT_FOUND; 376 goto fail; 377 } 378 379 /* check object class usage */ 380 if( scr->scr_sclass->soc_kind != LDAP_SCHEMA_STRUCTURAL ) 381 { 382 *err = cr->cr_oid; 383 code = SLAP_SCHERR_CR_BAD_STRUCT; 384 goto fail; 385 } 386 387 if( scr->scr_sclass->soc_flags & SLAP_OC_OPERATIONAL ) op++; 388 389 code = cr_add_auxiliaries( scr, &op, err ); 390 if ( code != 0 ) goto fail; 391 392 code = cr_create_required( scr, &op, err ); 393 if ( code != 0 ) goto fail; 394 395 code = cr_create_allowed( scr, &op, err ); 396 if ( code != 0 ) goto fail; 397 398 code = cr_create_precluded( scr, &op, err ); 399 if ( code != 0 ) goto fail; 400 401 if( user && op ) { 402 code = SLAP_SCHERR_CR_BAD_AUX; 403 goto fail; 404 } 405 406 code = cr_insert(scr,err); 407 if ( code == 0 && rscr ) 408 *rscr = scr; 409 return code; 410 fail: 411 ch_free( scr ); 412 return code; 413 } 414 415 void 416 cr_unparse( BerVarray *res, ContentRule *start, ContentRule *end, int sys ) 417 { 418 ContentRule *cr; 419 int i, num; 420 struct berval bv, *bva = NULL, idx; 421 char ibuf[32]; 422 423 if ( !start ) 424 start = LDAP_STAILQ_FIRST( &cr_list ); 425 426 /* count the result size */ 427 i = 0; 428 for ( cr=start; cr; cr=LDAP_STAILQ_NEXT(cr, scr_next)) { 429 if ( sys && !(cr->scr_flags & SLAP_CR_HARDCODE)) continue; 430 i++; 431 if ( cr == end ) break; 432 } 433 if (!i) return; 434 435 num = i; 436 bva = ch_malloc( (num+1) * sizeof(struct berval) ); 437 BER_BVZERO( bva ); 438 idx.bv_val = ibuf; 439 if ( sys ) { 440 idx.bv_len = 0; 441 ibuf[0] = '\0'; 442 } 443 i = 0; 444 for ( cr=start; cr; cr=LDAP_STAILQ_NEXT(cr, scr_next)) { 445 LDAPContentRule lcr, *lcrp; 446 if ( sys && !(cr->scr_flags & SLAP_CR_HARDCODE)) continue; 447 if ( cr->scr_oidmacro ) { 448 lcr = cr->scr_crule; 449 lcr.cr_oid = cr->scr_oidmacro; 450 lcrp = &lcr; 451 } else { 452 lcrp = &cr->scr_crule; 453 } 454 if ( ldap_contentrule2bv( lcrp, &bv ) == NULL ) { 455 ber_bvarray_free( bva ); 456 } 457 if ( !sys ) { 458 idx.bv_len = sprintf(idx.bv_val, "{%d}", i); 459 } 460 bva[i].bv_len = idx.bv_len + bv.bv_len; 461 bva[i].bv_val = ch_malloc( bva[i].bv_len + 1 ); 462 strcpy( bva[i].bv_val, ibuf ); 463 strcpy( bva[i].bv_val + idx.bv_len, bv.bv_val ); 464 i++; 465 bva[i].bv_val = NULL; 466 ldap_memfree( bv.bv_val ); 467 if ( cr == end ) break; 468 } 469 *res = bva; 470 } 471 472 int 473 cr_schema_info( Entry *e ) 474 { 475 AttributeDescription *ad_ditContentRules 476 = slap_schema.si_ad_ditContentRules; 477 ContentRule *cr; 478 479 struct berval val; 480 struct berval nval; 481 482 LDAP_STAILQ_FOREACH(cr, &cr_list, scr_next) { 483 if ( ldap_contentrule2bv( &cr->scr_crule, &val ) == NULL ) { 484 return -1; 485 } 486 487 #if 0 488 if( cr->scr_flags & SLAP_CR_HIDE ) continue; 489 #endif 490 #if 0 491 Debug( LDAP_DEBUG_TRACE, "Merging cr [%ld] %s\n", 492 (long) val.bv_len, val.bv_val, 0 ); 493 #endif 494 495 nval.bv_val = cr->scr_oid; 496 nval.bv_len = strlen(cr->scr_oid); 497 498 if( attr_merge_one( e, ad_ditContentRules, &val, &nval ) ) 499 { 500 return -1; 501 } 502 ldap_memfree( val.bv_val ); 503 } 504 return 0; 505 } 506