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