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