1/* cr.c - content rule routines */ 2/* $OpenLDAP$ */ 3/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 1998-2011 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 27struct cindexrec { 28 struct berval cir_name; 29 ContentRule *cir_cr; 30}; 31 32static Avlnode *cr_index = NULL; 33static LDAP_STAILQ_HEAD(CRList, ContentRule) cr_list 34 = LDAP_STAILQ_HEAD_INITIALIZER(cr_list); 35 36static int 37cr_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 48static int 49cr_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 60ContentRule * 61cr_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 71ContentRule * 72cr_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 85static int 86cr_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 99void 100cr_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 114static int 115cr_insert( 116 ContentRule *scr, 117 const char **err 118) 119{ 120 struct cindexrec *cir; 121 char **names; 122 123 assert( scr != NULL ); 124 125 if ( scr->scr_oid ) { 126 cir = (struct cindexrec *) 127 ch_calloc( 1, sizeof(struct cindexrec) ); 128 cir->cir_name.bv_val = scr->scr_oid; 129 cir->cir_name.bv_len = strlen( scr->scr_oid ); 130 cir->cir_cr = scr; 131 132 if ( avl_insert( &cr_index, (caddr_t) cir, 133 cr_index_cmp, avl_dup_error ) ) 134 { 135 *err = scr->scr_oid; 136 ldap_memfree(cir); 137 return SLAP_SCHERR_CR_DUP; 138 } 139 140 /* FIX: temporal consistency check */ 141 assert( cr_bvfind(&cir->cir_name) != NULL ); 142 } 143 144 if ( (names = scr->scr_names) ) { 145 while ( *names ) { 146 cir = (struct cindexrec *) 147 ch_calloc( 1, sizeof(struct cindexrec) ); 148 cir->cir_name.bv_val = *names; 149 cir->cir_name.bv_len = strlen( *names ); 150 cir->cir_cr = scr; 151 152 if ( avl_insert( &cr_index, (caddr_t) cir, 153 cr_index_cmp, avl_dup_error ) ) 154 { 155 *err = *names; 156 ldap_memfree(cir); 157 return SLAP_SCHERR_CR_DUP; 158 } 159 160 /* FIX: temporal consistency check */ 161 assert( cr_bvfind(&cir->cir_name) != NULL ); 162 163 names++; 164 } 165 } 166 167 LDAP_STAILQ_INSERT_TAIL(&cr_list, scr, scr_next); 168 169 return 0; 170} 171 172static int 173cr_add_auxiliaries( 174 ContentRule *scr, 175 int *op, 176 const char **err ) 177{ 178 int naux; 179 180 if( scr->scr_oc_oids_aux == NULL ) return 0; 181 182 for( naux=0; scr->scr_oc_oids_aux[naux]; naux++ ) { 183 /* count them */ ; 184 } 185 186 scr->scr_auxiliaries = ch_calloc( naux+1, sizeof(ObjectClass *)); 187 188 for( naux=0; scr->scr_oc_oids_aux[naux]; naux++ ) { 189 ObjectClass *soc = scr->scr_auxiliaries[naux] 190 = oc_find(scr->scr_oc_oids_aux[naux]); 191 if ( !soc ) { 192 *err = scr->scr_oc_oids_aux[naux]; 193 return SLAP_SCHERR_CLASS_NOT_FOUND; 194 } 195 196 if( soc->soc_flags & SLAP_OC_OPERATIONAL && 197 soc != slap_schema.si_oc_extensibleObject ) 198 { 199 (*op)++; 200 } 201 202 if( soc->soc_kind != LDAP_SCHEMA_AUXILIARY ) { 203 *err = scr->scr_oc_oids_aux[naux]; 204 return SLAP_SCHERR_CR_BAD_AUX; 205 } 206 } 207 208 scr->scr_auxiliaries[naux] = NULL; 209 return 0; 210} 211 212static int 213cr_create_required( 214 ContentRule *scr, 215 int *op, 216 const char **err ) 217{ 218 char **attrs = scr->scr_at_oids_must; 219 char **attrs1; 220 AttributeType *sat; 221 222 if ( attrs ) { 223 attrs1 = attrs; 224 while ( *attrs1 ) { 225 sat = at_find(*attrs1); 226 if ( !sat ) { 227 *err = *attrs1; 228 return SLAP_SCHERR_ATTR_NOT_FOUND; 229 } 230 231 if( is_at_operational( sat )) (*op)++; 232 233 if ( at_find_in_list(sat, scr->scr_required) < 0) { 234 if ( at_append_to_list(sat, &scr->scr_required) ) { 235 *err = *attrs1; 236 return SLAP_SCHERR_OUTOFMEM; 237 } 238 } else { 239 *err = *attrs1; 240 return SLAP_SCHERR_CR_BAD_AT; 241 } 242 attrs1++; 243 } 244 } 245 return 0; 246} 247 248static int 249cr_create_allowed( 250 ContentRule *scr, 251 int *op, 252 const char **err ) 253{ 254 char **attrs = scr->scr_at_oids_may; 255 char **attrs1; 256 AttributeType *sat; 257 258 if ( attrs ) { 259 attrs1 = attrs; 260 while ( *attrs1 ) { 261 sat = at_find(*attrs1); 262 if ( !sat ) { 263 *err = *attrs1; 264 return SLAP_SCHERR_ATTR_NOT_FOUND; 265 } 266 267 if( is_at_operational( sat )) (*op)++; 268 269 if ( at_find_in_list(sat, scr->scr_required) < 0 && 270 at_find_in_list(sat, scr->scr_allowed) < 0 ) 271 { 272 if ( at_append_to_list(sat, &scr->scr_allowed) ) { 273 *err = *attrs1; 274 return SLAP_SCHERR_OUTOFMEM; 275 } 276 } else { 277 *err = *attrs1; 278 return SLAP_SCHERR_CR_BAD_AT; 279 } 280 attrs1++; 281 } 282 } 283 return 0; 284} 285 286static int 287cr_create_precluded( 288 ContentRule *scr, 289 int *op, 290 const char **err ) 291{ 292 char **attrs = scr->scr_at_oids_not; 293 char **attrs1; 294 AttributeType *sat; 295 296 if ( attrs ) { 297 attrs1 = attrs; 298 while ( *attrs1 ) { 299 sat = at_find(*attrs1); 300 if ( !sat ) { 301 *err = *attrs1; 302 return SLAP_SCHERR_ATTR_NOT_FOUND; 303 } 304 305 if( is_at_operational( sat )) (*op)++; 306 307 /* FIXME: should also make sure attribute type is not 308 a required attribute of the structural class or 309 any auxiliary class */ 310 if ( at_find_in_list(sat, scr->scr_required) < 0 && 311 at_find_in_list(sat, scr->scr_allowed) < 0 && 312 at_find_in_list(sat, scr->scr_precluded) < 0 ) 313 { 314 if ( at_append_to_list(sat, &scr->scr_precluded) ) { 315 *err = *attrs1; 316 return SLAP_SCHERR_OUTOFMEM; 317 } 318 } else { 319 *err = *attrs1; 320 return SLAP_SCHERR_CR_BAD_AT; 321 } 322 attrs1++; 323 } 324 } 325 return 0; 326} 327 328int 329cr_add( 330 LDAPContentRule *cr, 331 int user, 332 ContentRule **rscr, 333 const char **err 334) 335{ 336 ContentRule *scr; 337 int code; 338 int op = 0; 339 char *oidm = NULL; 340 341 if ( cr->cr_names != NULL ) { 342 int i; 343 344 for( i=0; cr->cr_names[i]; i++ ) { 345 if( !slap_valid_descr( cr->cr_names[i] ) ) { 346 return SLAP_SCHERR_BAD_DESCR; 347 } 348 } 349 } 350 351 if ( !OID_LEADCHAR( cr->cr_oid[0] )) { 352 /* Expand OID macros */ 353 char *oid = oidm_find( cr->cr_oid ); 354 if ( !oid ) { 355 *err = cr->cr_oid; 356 return SLAP_SCHERR_OIDM; 357 } 358 if ( oid != cr->cr_oid ) { 359 oidm = cr->cr_oid; 360 cr->cr_oid = oid; 361 } 362 } 363 364 scr = (ContentRule *) ch_calloc( 1, sizeof(ContentRule) ); 365 AC_MEMCPY( &scr->scr_crule, cr, sizeof(LDAPContentRule) ); 366 367 scr->scr_oidmacro = oidm; 368 scr->scr_sclass = oc_find(cr->cr_oid); 369 if ( !scr->scr_sclass ) { 370 *err = cr->cr_oid; 371 code = SLAP_SCHERR_CLASS_NOT_FOUND; 372 goto fail; 373 } 374 375 /* check object class usage */ 376 if( scr->scr_sclass->soc_kind != LDAP_SCHEMA_STRUCTURAL ) 377 { 378 *err = cr->cr_oid; 379 code = SLAP_SCHERR_CR_BAD_STRUCT; 380 goto fail; 381 } 382 383 if( scr->scr_sclass->soc_flags & SLAP_OC_OPERATIONAL ) op++; 384 385 code = cr_add_auxiliaries( scr, &op, err ); 386 if ( code != 0 ) goto fail; 387 388 code = cr_create_required( scr, &op, err ); 389 if ( code != 0 ) goto fail; 390 391 code = cr_create_allowed( scr, &op, err ); 392 if ( code != 0 ) goto fail; 393 394 code = cr_create_precluded( scr, &op, err ); 395 if ( code != 0 ) goto fail; 396 397 if( user && op ) { 398 code = SLAP_SCHERR_CR_BAD_AUX; 399 goto fail; 400 } 401 402 code = cr_insert(scr,err); 403 if ( code == 0 && rscr ) 404 *rscr = scr; 405 return code; 406fail: 407 ch_free( scr ); 408 return code; 409} 410 411void 412cr_unparse( BerVarray *res, ContentRule *start, ContentRule *end, int sys ) 413{ 414 ContentRule *cr; 415 int i, num; 416 struct berval bv, *bva = NULL, idx; 417 char ibuf[32]; 418 419 if ( !start ) 420 start = LDAP_STAILQ_FIRST( &cr_list ); 421 422 /* count the result size */ 423 i = 0; 424 for ( cr=start; cr; cr=LDAP_STAILQ_NEXT(cr, scr_next)) { 425 if ( sys && !(cr->scr_flags & SLAP_CR_HARDCODE)) continue; 426 i++; 427 if ( cr == end ) break; 428 } 429 if (!i) return; 430 431 num = i; 432 bva = ch_malloc( (num+1) * sizeof(struct berval) ); 433 BER_BVZERO( bva ); 434 idx.bv_val = ibuf; 435 if ( sys ) { 436 idx.bv_len = 0; 437 ibuf[0] = '\0'; 438 } 439 i = 0; 440 for ( cr=start; cr; cr=LDAP_STAILQ_NEXT(cr, scr_next)) { 441 LDAPContentRule lcr, *lcrp; 442 if ( sys && !(cr->scr_flags & SLAP_CR_HARDCODE)) continue; 443 if ( cr->scr_oidmacro ) { 444 lcr = cr->scr_crule; 445 lcr.cr_oid = cr->scr_oidmacro; 446 lcrp = &lcr; 447 } else { 448 lcrp = &cr->scr_crule; 449 } 450 if ( ldap_contentrule2bv( lcrp, &bv ) == NULL ) { 451 ber_bvarray_free( bva ); 452 } 453 if ( !sys ) { 454 idx.bv_len = sprintf(idx.bv_val, "{%d}", i); 455 } 456 bva[i].bv_len = idx.bv_len + bv.bv_len; 457 bva[i].bv_val = ch_malloc( bva[i].bv_len + 1 ); 458 strcpy( bva[i].bv_val, ibuf ); 459 strcpy( bva[i].bv_val + idx.bv_len, bv.bv_val ); 460 i++; 461 bva[i].bv_val = NULL; 462 ldap_memfree( bv.bv_val ); 463 if ( cr == end ) break; 464 } 465 *res = bva; 466} 467 468int 469cr_schema_info( Entry *e ) 470{ 471 AttributeDescription *ad_ditContentRules 472 = slap_schema.si_ad_ditContentRules; 473 ContentRule *cr; 474 475 struct berval val; 476 struct berval nval; 477 478 LDAP_STAILQ_FOREACH(cr, &cr_list, scr_next) { 479 if ( ldap_contentrule2bv( &cr->scr_crule, &val ) == NULL ) { 480 return -1; 481 } 482 483#if 0 484 if( cr->scr_flags & SLAP_CR_HIDE ) continue; 485#endif 486#if 0 487 Debug( LDAP_DEBUG_TRACE, "Merging cr [%ld] %s\n", 488 (long) val.bv_len, val.bv_val, 0 ); 489#endif 490 491 nval.bv_val = cr->scr_oid; 492 nval.bv_len = strlen(cr->scr_oid); 493 494 if( attr_merge_one( e, ad_ditContentRules, &val, &nval ) ) 495 { 496 return -1; 497 } 498 ldap_memfree( val.bv_val ); 499 } 500 return 0; 501} 502