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