1 /* $NetBSD: datamorph.c,v 1.2 2021/08/14 16:14:51 christos Exp $ */ 2 3 /* datamorph.c - enumerated and native integer value support */ 4 /* $OpenLDAP$ */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2016-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 /* ACKNOWLEDGEMENTS: 19 * This work was developed in 2016 by Ondřej Kuzník for Symas Corp. 20 */ 21 22 #include <sys/cdefs.h> 23 __RCSID("$NetBSD: datamorph.c,v 1.2 2021/08/14 16:14:51 christos Exp $"); 24 25 #include "portable.h" 26 27 #ifdef SLAPD_OVER_DATAMORPH 28 29 #include <inttypes.h> 30 #include <ac/stdlib.h> 31 32 #if defined(__linux__) 33 #include <endian.h> 34 35 #elif defined(sun) 36 37 #define be16toh(x) BE_16(x) 38 #define le16toh(x) LE_16(x) 39 #define htobe16(x) BE_16(x) 40 #define htole16(x) LE_16(x) 41 42 #define be32toh(x) BE_32(x) 43 #define le32toh(x) LE_32(x) 44 #define htobe32(x) BE_32(x) 45 #define htole32(x) LE_32(x) 46 47 #define be64toh(x) BE_64(x) 48 #define le64toh(x) LE_64(x) 49 #define htobe64(x) BE_64(x) 50 #define htole64(x) LE_64(x) 51 52 #elif defined(__NetBSD__) || defined(__FreeBSD__) 53 #include <sys/endian.h> 54 55 #elif defined(__OpenBSD__) 56 #include <sys/endian.h> 57 58 #define be16toh(x) betoh16(x) 59 #define le16toh(x) letoh16(x) 60 61 #define be32toh(x) betoh32(x) 62 #define le32toh(x) letoh32(x) 63 64 #define be64toh(x) betoh64(x) 65 #define le64toh(x) letoh64(x) 66 67 #elif defined(__BYTE_ORDER__) && \ 68 ( defined(__GNUC__) || defined(__clang__) ) 69 70 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 71 #define be16toh(x) __builtin_bswap16(x) 72 #define le16toh(x) (x) 73 #define htobe16(x) __builtin_bswap16(x) 74 #define htole16(x) (x) 75 76 #define be32toh(x) __builtin_bswap32(x) 77 #define le32toh(x) (x) 78 #define htobe32(x) __builtin_bswap32(x) 79 #define htole32(x) (x) 80 81 #define be64toh(x) __builtin_bswap64(x) 82 #define le64toh(x) (x) 83 #define htobe64(x) __builtin_bswap64(x) 84 #define htole64(x) (x) 85 86 #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 87 #define be16toh(x) (x) 88 #define le16toh(x) __builtin_bswap16(x) 89 #define htobe16(x) (x) 90 #define htole16(x) __builtin_bswap16(x) 91 92 #define be32toh(x) (x) 93 #define le32toh(x) __builtin_bswap32(x) 94 #define htobe32(x) (x) 95 #define htole32(x) __builtin_bswap32(x) 96 97 #define be64toh(x) (x) 98 #define le64toh(x) __builtin_bswap64(x) 99 #define htobe64(x) (x) 100 #define htole64(x) __builtin_bswap64(x) 101 102 #else 103 #error "Only support pure big and little endian at the moment" 104 #endif 105 106 #else 107 #error "I lack the way to check my endianness and convert to/from big-endian" 108 #endif 109 110 #include "slap.h" 111 #include "slap-config.h" 112 #include "lutil.h" 113 #include "ldap_queue.h" 114 115 typedef enum datamorph_type_t { 116 DATAMORPH_UNSET, 117 DATAMORPH_ENUM, 118 DATAMORPH_INT, 119 } datamorph_type; 120 121 typedef enum datamorph_flags_t { 122 DATAMORPH_FLAG_SIGNED = 1 << 0, 123 DATAMORPH_FLAG_LOWER = 1 << 1, 124 DATAMORPH_FLAG_UPPER = 1 << 2, 125 } datamorph_flags; 126 127 typedef union datamorph_interval_bound_t { 128 int64_t i; 129 uint64_t u; 130 } datamorph_interval_bound; 131 132 typedef struct transformation_info_t { 133 AttributeDescription *attr; 134 datamorph_type type; 135 union { 136 struct { 137 Avlnode *to_db; 138 struct berval from_db[256]; 139 } maps; 140 #define ti_enum info.maps 141 struct { 142 datamorph_flags flags; 143 unsigned int size; 144 datamorph_interval_bound lower, upper; 145 } interval; 146 #define ti_int info.interval 147 } info; 148 } transformation_info; 149 150 typedef struct datamorph_enum_mapping_t { 151 struct berval wire_value; 152 uint8_t db_value; 153 transformation_info *transformation; 154 } datamorph_enum_mapping; 155 156 typedef struct datamorph_info_t { 157 Avlnode *transformations; 158 transformation_info *wip_transformation; 159 } datamorph_info; 160 161 static int 162 transformation_mapping_cmp( const void *l, const void *r ) 163 { 164 const datamorph_enum_mapping *left = l, *right = r; 165 166 return ber_bvcmp( &left->wire_value, &right->wire_value ); 167 } 168 169 static int 170 transformation_info_cmp( const void *l, const void *r ) 171 { 172 const transformation_info *left = l, *right = r; 173 174 return ( left->attr == right->attr ) ? 0 : 175 ( left->attr < right->attr ) ? -1 : 176 1; 177 } 178 179 static int 180 transform_to_db_format_one( 181 Operation *op, 182 transformation_info *definition, 183 struct berval *value, 184 struct berval *outval ) 185 { 186 switch ( definition->type ) { 187 case DATAMORPH_ENUM: { 188 datamorph_enum_mapping *mapping, needle = { .wire_value = *value }; 189 struct berval db_value = { .bv_len = 1 }; 190 191 mapping = ldap_avl_find( definition->ti_enum.to_db, &needle, 192 transformation_mapping_cmp ); 193 if ( !mapping ) { 194 Debug( LDAP_DEBUG_ANY, "transform_to_db_format_one: " 195 "value '%s' not mapped\n", 196 value->bv_val ); 197 return LDAP_CONSTRAINT_VIOLATION; 198 } 199 200 db_value.bv_val = (char *)&mapping->db_value; 201 ber_dupbv( outval, &db_value ); 202 assert( outval->bv_val ); 203 break; 204 } 205 206 case DATAMORPH_INT: { 207 union { 208 char s[8]; 209 uint8_t be8; 210 uint16_t be16; 211 uint32_t be32; 212 uint64_t be64; 213 } buf; 214 struct berval db_value = { .bv_val = buf.s }; 215 char *ptr = value->bv_val + value->bv_len; 216 uint64_t unsigned_value; 217 int64_t signed_value; 218 219 assert( definition->ti_int.size == 1 || 220 definition->ti_int.size == 2 || 221 definition->ti_int.size == 4 || 222 definition->ti_int.size == 8 ); 223 224 /* Read number */ 225 if ( definition->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { 226 signed_value = strtoll( value->bv_val, &ptr, 10 ); 227 } else { 228 unsigned_value = strtoull( value->bv_val, &ptr, 10 ); 229 } 230 if ( *value->bv_val == '\0' || *ptr != '\0' ) { 231 Debug( LDAP_DEBUG_ANY, "transform_to_db_format_one: " 232 "value '%s' not an integer\n", 233 value->bv_val ); 234 return LDAP_CONSTRAINT_VIOLATION; 235 } 236 /* Check it's within configured bounds */ 237 if ( definition->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { 238 if ( signed_value < definition->ti_int.lower.i || 239 signed_value > definition->ti_int.upper.i ) { 240 Debug( LDAP_DEBUG_ANY, "transform_to_db_format_one: " 241 "value '%s' doesn't fit configured constraints\n", 242 value->bv_val ); 243 return LDAP_CONSTRAINT_VIOLATION; 244 } 245 } else { 246 if ( unsigned_value < definition->ti_int.lower.u || 247 unsigned_value > definition->ti_int.upper.u ) { 248 Debug( LDAP_DEBUG_ANY, "transform_to_db_format_one: " 249 "value '%s' doesn't fit configured constraints\n", 250 value->bv_val ); 251 return LDAP_CONSTRAINT_VIOLATION; 252 } 253 } 254 255 db_value.bv_len = definition->ti_int.size; 256 switch ( definition->ti_int.size ) { 257 case 1: { 258 if ( definition->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { 259 buf.be8 = (unsigned char)((char)signed_value); 260 } else { 261 buf.be8 = unsigned_value; 262 } 263 break; 264 } 265 case 2: { 266 uint16_t h16; 267 if ( definition->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { 268 h16 = signed_value; 269 } else { 270 h16 = unsigned_value; 271 } 272 buf.be16 = htobe16( h16 ); 273 break; 274 } 275 case 4: { 276 uint32_t h32; 277 if ( definition->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { 278 h32 = signed_value; 279 } else { 280 h32 = unsigned_value; 281 } 282 buf.be32 = htobe32( h32 ); 283 break; 284 } 285 case 8: { 286 uint64_t h64; 287 if ( definition->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { 288 h64 = signed_value; 289 } else { 290 h64 = unsigned_value; 291 } 292 buf.be64 = htobe64( h64 ); 293 break; 294 } 295 } 296 ber_dupbv( outval, &db_value ); 297 assert( outval->bv_val ); 298 break; 299 } 300 301 default: 302 assert(0); 303 } 304 305 return LDAP_SUCCESS; 306 } 307 308 static int 309 transform_to_db_format( 310 Operation *op, 311 transformation_info *definition, 312 BerVarray values, 313 int numvals, 314 BerVarray *out ) 315 { 316 struct berval *value; 317 int i, rc = LDAP_SUCCESS; 318 319 if ( numvals == 0 ) { 320 for ( value = values; value; value++, numvals++ ) 321 ; /* Count them */ 322 } 323 324 assert( out ); 325 *out = ch_calloc( numvals + 1, sizeof(struct berval) ); 326 327 for ( i = 0; i < numvals; i++ ) { 328 rc = transform_to_db_format_one( 329 op, definition, &values[i], &(*out)[i] ); 330 if ( rc ) { 331 break; 332 } 333 } 334 335 if ( rc ) { 336 for ( ; i >= 0; i-- ) { 337 ch_free((*out)[i].bv_val); 338 } 339 ch_free(*out); 340 } 341 342 return rc; 343 } 344 345 static int 346 transform_from_db_format_one( 347 Operation *op, 348 transformation_info *definition, 349 struct berval *value, 350 struct berval *outval ) 351 { 352 switch ( definition->type ) { 353 case DATAMORPH_ENUM: { 354 uint8_t index = value->bv_val[0]; 355 struct berval *val = &definition->info.maps.from_db[index]; 356 357 if ( !BER_BVISNULL( val ) ) { 358 ber_dupbv( outval, val ); 359 assert( outval->bv_val ); 360 } else { 361 Debug( LDAP_DEBUG_ANY, "transform_from_db_format_one: " 362 "DB value %d has no mapping!\n", 363 index ); 364 /* FIXME: probably still need to return an error */ 365 BER_BVZERO( outval ); 366 } 367 break; 368 } 369 370 case DATAMORPH_INT: { 371 char buf[24]; 372 struct berval wire_value = { .bv_val = buf }; 373 union lens_t { 374 uint8_t be8; 375 uint16_t be16; 376 uint32_t be32; 377 uint64_t be64; 378 } *lens = (union lens_t *)value->bv_val; 379 uint64_t unsigned_value; 380 int64_t signed_value; 381 382 if ( value->bv_len != definition->ti_int.size ) { 383 Debug( LDAP_DEBUG_ANY, "transform_from_db_format_one(%s): " 384 "unexpected DB value of length %lu when configured " 385 "for %u!\n", 386 definition->attr->ad_cname.bv_val, value->bv_len, 387 definition->ti_int.size ); 388 /* FIXME: probably still need to return an error */ 389 BER_BVZERO( outval ); 390 break; 391 } 392 393 assert( definition->ti_int.size == 1 || 394 definition->ti_int.size == 2 || 395 definition->ti_int.size == 4 || 396 definition->ti_int.size == 8 ); 397 398 switch ( definition->ti_int.size ) { 399 case 1: { 400 if ( definition->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { 401 signed_value = (int8_t)lens->be8; 402 } else { 403 unsigned_value = (uint8_t)lens->be8; 404 } 405 break; 406 } 407 case 2: { 408 uint16_t h16 = be16toh( lens->be16 ); 409 if ( definition->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { 410 signed_value = (int16_t)h16; 411 } else { 412 unsigned_value = (uint16_t)h16; 413 } 414 break; 415 } 416 case 4: { 417 uint32_t h32 = be32toh( lens->be32 ); 418 if ( definition->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { 419 signed_value = (int32_t)h32; 420 } else { 421 unsigned_value = (uint32_t)h32; 422 } 423 break; 424 } 425 case 8: { 426 uint64_t h64 = be64toh( lens->be64 ); 427 if ( definition->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { 428 signed_value = (int64_t)h64; 429 } else { 430 unsigned_value = (uint64_t)h64; 431 } 432 break; 433 } 434 } 435 if ( definition->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { 436 wire_value.bv_len = sprintf( buf, "%" PRId64, signed_value ); 437 } else { 438 wire_value.bv_len = sprintf( buf, "%" PRIu64, unsigned_value ); 439 } 440 ber_dupbv( outval, &wire_value ); 441 assert( outval->bv_val ); 442 break; 443 } 444 445 default: 446 assert(0); 447 } 448 449 return LDAP_SUCCESS; 450 } 451 452 static int 453 transform_from_db_format( 454 Operation *op, 455 transformation_info *definition, 456 BerVarray values, 457 int numvals, 458 BerVarray *out ) 459 { 460 struct berval *value; 461 int i, rc = LDAP_SUCCESS; 462 463 if ( numvals == 0 ) { 464 for ( value = values; value; value++, numvals++ ) 465 ; /* Count them */ 466 } 467 468 assert( out ); 469 *out = ch_calloc( numvals + 1, sizeof(struct berval) ); 470 471 for ( i = 0; i < numvals; i++ ) { 472 struct berval bv; 473 rc = transform_from_db_format_one( op, definition, &values[i], &bv ); 474 if ( !BER_BVISNULL( &bv ) ) { 475 ber_bvarray_add( out, &bv ); 476 } 477 if ( rc ) { 478 break; 479 } 480 } 481 482 if ( rc ) { 483 for ( ; i >= 0; i-- ) { 484 ch_free( (*out)[i].bv_val ); 485 } 486 ch_free( *out ); 487 } 488 489 return rc; 490 } 491 492 static int 493 datamorph_filter( Operation *op, datamorph_info *ov, Filter *f ) 494 { 495 switch ( f->f_choice ) { 496 case LDAP_FILTER_PRESENT: 497 /* The matching rules are not in place, 498 * so the filter will be ignored */ 499 case LDAP_FILTER_APPROX: 500 case LDAP_FILTER_SUBSTRINGS: 501 default: 502 break; 503 return LDAP_SUCCESS; 504 505 case LDAP_FILTER_AND: 506 case LDAP_FILTER_OR: { 507 for ( f = f->f_and; f; f = f->f_next ) { 508 int rc = datamorph_filter( op, ov, f ); 509 if ( rc != LDAP_SUCCESS ) { 510 return rc; 511 } 512 } 513 } break; 514 515 case LDAP_FILTER_NOT: 516 return datamorph_filter( op, ov, f->f_not ); 517 518 case LDAP_FILTER_EQUALITY: 519 case LDAP_FILTER_GE: 520 case LDAP_FILTER_LE: { 521 transformation_info *t, needle = { .attr = f->f_ava->aa_desc }; 522 523 t = ldap_avl_find( 524 ov->transformations, &needle, transformation_info_cmp ); 525 if ( t ) { 526 struct berval new_val; 527 int rc = transform_to_db_format_one( 528 op, t, &f->f_ava->aa_value, &new_val ); 529 ch_free( f->f_ava->aa_value.bv_val ); 530 531 if ( rc != LDAP_SUCCESS ) { 532 f->f_choice = SLAPD_FILTER_COMPUTED; 533 f->f_result = SLAPD_COMPARE_UNDEFINED; 534 } else { 535 f->f_ava->aa_value = new_val; 536 } 537 } 538 } break; 539 } 540 return LDAP_SUCCESS; 541 } 542 543 static int 544 datamorph_op_add( Operation *op, SlapReply *rs ) 545 { 546 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 547 datamorph_info *ov = on->on_bi.bi_private; 548 Entry *e = op->ora_e; 549 Attribute *a, *next; 550 AttributeDescription *stop = NULL; 551 int rc = LDAP_SUCCESS; 552 553 if ( !BER_BVISNULL( &e->e_nname ) && !BER_BVISEMPTY( &e->e_nname ) ) { 554 LDAPRDN rDN; 555 const char *p; 556 int i; 557 558 rc = ldap_bv2rdn_x( &e->e_nname, &rDN, (char **)&p, LDAP_DN_FORMAT_LDAP, 559 op->o_tmpmemctx ); 560 if ( rc != LDAP_SUCCESS ) { 561 Debug( LDAP_DEBUG_ANY, "datamorph_op_add: " 562 "can't parse rdn: dn=%s\n", 563 op->o_req_ndn.bv_val ); 564 return SLAP_CB_CONTINUE; 565 } 566 567 for ( i = 0; rDN[i]; i++ ) { 568 transformation_info needle = {}; 569 570 /* If we can't resolve the attribute, ignore it */ 571 if ( slap_bv2ad( &rDN[i]->la_attr, &needle.attr, &p ) ) { 572 continue; 573 } 574 575 if ( ldap_avl_find( ov->transformations, &needle, 576 transformation_info_cmp ) ) { 577 rc = LDAP_CONSTRAINT_VIOLATION; 578 Debug( LDAP_DEBUG_TRACE, "datamorph_op_add: " 579 "attempted to add transformed attribute in RDN\n" ); 580 break; 581 } 582 } 583 584 ldap_rdnfree_x( rDN, op->o_tmpmemctx ); 585 if ( rc != LDAP_SUCCESS ) { 586 send_ldap_error( op, rs, rc, 587 "datamorph: trying to add transformed attribute in RDN" ); 588 return rc; 589 } 590 } 591 592 for ( a = e->e_attrs; a && a->a_desc != stop; a = next ) { 593 transformation_info *t, needle = { .attr = a->a_desc }; 594 BerVarray new_vals; 595 596 next = a->a_next; 597 598 t = ldap_avl_find( ov->transformations, &needle, transformation_info_cmp ); 599 if ( !t ) continue; 600 601 rc = transform_to_db_format( 602 op, t, a->a_vals, a->a_numvals, &new_vals ); 603 if ( rc != LDAP_SUCCESS ) { 604 goto fail; 605 } 606 607 (void)attr_delete( &e->e_attrs, needle.attr ); 608 609 rc = attr_merge( e, needle.attr, new_vals, NULL ); 610 ber_bvarray_free( new_vals ); 611 if ( rc != LDAP_SUCCESS ) { 612 goto fail; 613 } 614 if ( !stop ) { 615 stop = needle.attr; 616 } 617 } 618 619 return SLAP_CB_CONTINUE; 620 621 fail: 622 send_ldap_error( 623 op, rs, rc, "datamorph: trying to add values outside definitions" ); 624 return rc; 625 } 626 627 static int 628 datamorph_op_compare( Operation *op, SlapReply *rs ) 629 { 630 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 631 datamorph_info *ov = on->on_bi.bi_private; 632 transformation_info *t, needle = { .attr = op->orc_ava->aa_desc }; 633 int rc = SLAP_CB_CONTINUE; 634 635 t = ldap_avl_find( ov->transformations, &needle, transformation_info_cmp ); 636 if ( t ) { 637 struct berval new_val; 638 639 rc = transform_to_db_format_one( 640 op, t, &op->orc_ava->aa_value, &new_val ); 641 if ( rc != LDAP_SUCCESS ) { 642 Debug( LDAP_DEBUG_TRACE, "datamorph_op_compare: " 643 "transformation failed for '%s', rc=%d\n", 644 op->orc_ava->aa_value.bv_val, rc ); 645 rs->sr_err = rc = LDAP_COMPARE_FALSE; 646 send_ldap_result( op, rs ); 647 return rc; 648 } 649 ch_free( op->orc_ava->aa_value.bv_val ); 650 op->orc_ava->aa_value = new_val; 651 } 652 653 return SLAP_CB_CONTINUE; 654 } 655 656 static int 657 datamorph_op_mod( Operation *op, SlapReply *rs ) 658 { 659 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 660 datamorph_info *ov = on->on_bi.bi_private; 661 Modifications *mod; 662 int rc = SLAP_CB_CONTINUE; 663 664 for ( mod = op->orm_modlist; mod; mod = mod->sml_next ) { 665 transformation_info *t, needle = { .attr = mod->sml_desc }; 666 BerVarray new_vals = NULL; 667 668 if ( mod->sml_numvals == 0 ) continue; /* Nothing to transform */ 669 670 t = ldap_avl_find( ov->transformations, &needle, transformation_info_cmp ); 671 if ( !t ) continue; 672 673 assert( !mod->sml_nvalues ); 674 rc = transform_to_db_format( 675 op, t, mod->sml_values, mod->sml_numvals, &new_vals ); 676 if ( rc != LDAP_SUCCESS ) { 677 goto fail; 678 } 679 ber_bvarray_free( mod->sml_values ); 680 mod->sml_values = new_vals; 681 } 682 683 return SLAP_CB_CONTINUE; 684 685 fail: 686 Debug( LDAP_DEBUG_TRACE, "datamorph_op_mod: " 687 "dn=%s failed rc=%d\n", 688 op->o_req_ndn.bv_val, rc ); 689 send_ldap_error( op, rs, rc, 690 "datamorph: trying to operate on values outside definitions" ); 691 return rc; 692 } 693 694 static int 695 datamorph_op_modrdn( Operation *op, SlapReply *rs ) 696 { 697 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 698 datamorph_info *ov = on->on_bi.bi_private; 699 LDAPRDN rDN; 700 const char *p; 701 int i, rc; 702 703 rc = ldap_bv2rdn_x( &op->orr_nnewrdn, &rDN, (char **)&p, 704 LDAP_DN_FORMAT_LDAP, op->o_tmpmemctx ); 705 if ( rc != LDAP_SUCCESS ) { 706 Debug( LDAP_DEBUG_ANY, "datamorph_op_modrdn: " 707 "can't parse rdn for dn=%s\n", 708 op->o_req_ndn.bv_val ); 709 return SLAP_CB_CONTINUE; 710 } 711 712 for ( i = 0; rDN[i]; i++ ) { 713 transformation_info needle = {}; 714 715 /* If we can't resolve the attribute, ignore it */ 716 if ( slap_bv2ad( &rDN[i]->la_attr, &needle.attr, &p ) ) { 717 continue; 718 } 719 720 if ( ldap_avl_find( 721 ov->transformations, &needle, transformation_info_cmp ) ) { 722 rc = LDAP_CONSTRAINT_VIOLATION; 723 Debug( LDAP_DEBUG_TRACE, "datamorph_op_modrdn: " 724 "attempted to add transformed values in RDN\n" ); 725 break; 726 } 727 } 728 729 ldap_rdnfree_x( rDN, op->o_tmpmemctx ); 730 if ( rc != LDAP_SUCCESS ) { 731 send_ldap_error( op, rs, rc, 732 "datamorph: trying to put transformed values in RDN" ); 733 return rc; 734 } 735 736 return SLAP_CB_CONTINUE; 737 } 738 739 static int 740 datamorph_response( Operation *op, SlapReply *rs ) 741 { 742 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 743 datamorph_info *ov = on->on_bi.bi_private; 744 Entry *e = NULL, *e_orig = rs->sr_entry; 745 AttributeDescription *stop = NULL; 746 Attribute *a, *next = NULL; 747 int rc = SLAP_CB_CONTINUE; 748 749 if ( rs->sr_type != REP_SEARCH ) { 750 return rc; 751 } 752 753 for ( a = e_orig->e_attrs; a && a->a_desc != stop; a = next ) { 754 transformation_info *t, needle = { .attr = a->a_desc }; 755 BerVarray new_vals; 756 757 next = a->a_next; 758 759 t = ldap_avl_find( ov->transformations, &needle, transformation_info_cmp ); 760 if ( !t ) continue; 761 762 rc = transform_from_db_format( 763 op, t, a->a_vals, a->a_numvals, &new_vals ); 764 if ( rc != LDAP_SUCCESS ) { 765 break; 766 } 767 if ( !e ) { 768 if ( rs->sr_flags & REP_ENTRY_MODIFIABLE ) { 769 e = e_orig; 770 } else { 771 e = entry_dup( e_orig ); 772 } 773 } 774 775 (void)attr_delete( &e->e_attrs, needle.attr ); 776 777 rc = attr_merge( e, needle.attr, new_vals, NULL ); 778 ber_bvarray_free( new_vals ); 779 if ( rc != LDAP_SUCCESS ) { 780 break; 781 } 782 if ( !stop ) { 783 stop = needle.attr; 784 } 785 } 786 787 if ( rc == LDAP_SUCCESS ) { 788 rc = SLAP_CB_CONTINUE; 789 if ( e && e != e_orig ) { 790 rs_replace_entry( op, rs, on, e ); 791 rs->sr_flags &= ~REP_ENTRY_MASK; 792 rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED; 793 } 794 } else if ( e && e != e_orig ) { 795 entry_free( e ); 796 } 797 798 return rc; 799 } 800 801 static int 802 datamorph_op_search( Operation *op, SlapReply *rs ) 803 { 804 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 805 datamorph_info *ov = on->on_bi.bi_private; 806 int rc = SLAP_CB_CONTINUE; 807 808 /* 809 * 1. check all requested attributes -> register callback if one matches 810 * 2. check filter: parse filter, traverse, for configured attributes: 811 * - presence -> do not touch 812 * - ava -> replace assertion value with db value if possible, assertion with undefined otherwise 813 * - inequality -> ??? 814 * - anything else -> undefined 815 * - might just check for equality and leave the rest to syntax? 816 * 3. unparse filter 817 */ 818 if ( datamorph_filter( op, ov, op->ors_filter ) ) { 819 send_ldap_error( 820 op, rs, LDAP_OTHER, "datamorph: failed to process filter" ); 821 return LDAP_OTHER; 822 } 823 824 return rc; 825 } 826 827 static int 828 datamorph_entry_release_rw( Operation *op, Entry *e, int rw ) 829 { 830 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 831 int rc = LDAP_SUCCESS; 832 833 if ( on->on_next ) { 834 rc = overlay_entry_release_ov( op, e, rw, on->on_next ); 835 } else if ( on->on_info->oi_orig->bi_entry_release_rw ) { 836 /* FIXME: there should be a better way */ 837 rc = on->on_info->oi_orig->bi_entry_release_rw( op, e, rw ); 838 } else { 839 entry_free( e ); 840 } 841 842 return rc; 843 } 844 845 static int 846 datamorph_entry_get_rw( 847 Operation *op, 848 struct berval *ndn, 849 ObjectClass *oc, 850 AttributeDescription *at, 851 int rw, 852 Entry **ep ) 853 { 854 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 855 datamorph_info *ov = on->on_bi.bi_private; 856 Entry *e_orig, *e = NULL; 857 int rc; 858 859 if ( on->on_next ) { 860 rc = overlay_entry_get_ov( op, ndn, oc, at, rw, ep, on->on_next ); 861 } else { 862 /* FIXME: there should be a better way */ 863 rc = on->on_info->oi_orig->bi_entry_get_rw( op, ndn, oc, at, rw, ep ); 864 } 865 e_orig = *ep; 866 867 if ( rc == LDAP_SUCCESS && e_orig ) { 868 AttributeDescription *stop = NULL; 869 Attribute *a; 870 871 for ( a = e_orig->e_attrs; a; a = a->a_next ) { 872 transformation_info *t, needle = { .attr = a->a_desc }; 873 BerVarray new_vals; 874 875 t = ldap_avl_find( 876 ov->transformations, &needle, transformation_info_cmp ); 877 if ( !t ) continue; 878 879 rc = transform_from_db_format( 880 op, t, a->a_vals, a->a_numvals, &new_vals ); 881 if ( rc != LDAP_SUCCESS ) { 882 goto fail; 883 } 884 if ( !e ) { 885 e = entry_dup( e_orig ); 886 } 887 888 (void)attr_delete( &e->e_attrs, needle.attr ); 889 890 rc = attr_merge( e, needle.attr, new_vals, NULL ); 891 ber_bvarray_free( new_vals ); 892 if ( rc != LDAP_SUCCESS ) { 893 goto fail; 894 } 895 if ( !stop ) { 896 stop = needle.attr; 897 } 898 } 899 } 900 if ( e ) { 901 datamorph_entry_release_rw( op, e_orig, rw ); 902 *ep = e; 903 } 904 905 return rc; 906 907 fail: 908 if ( e ) { 909 entry_free( e ); 910 } 911 (void)datamorph_entry_release_rw( op, *ep, rw ); 912 return rc; 913 } 914 915 /* Schema */ 916 917 static int 918 datamorphBlobValidate( Syntax *syntax, struct berval *in ) 919 { 920 /* any value allowed */ 921 return LDAP_SUCCESS; 922 } 923 924 int 925 datamorphBinarySignedOrderingMatch( int *matchp, 926 slap_mask_t flags, 927 Syntax *syntax, 928 MatchingRule *mr, 929 struct berval *value, 930 void *assertedValue ) 931 { 932 struct berval *asserted = assertedValue; 933 ber_len_t v_len = value->bv_len; 934 ber_len_t av_len = asserted->bv_len; 935 936 /* Ordering: 937 * 1. Negative always before non-negative 938 * 2. Shorter before longer 939 * 3. Rest ordered by memory contents (they are big-endian numbers) 940 */ 941 int match = ( *value->bv_val >= 0 ) - ( *asserted->bv_val >= 0 ); 942 943 if ( match == 0 ) match = (int)v_len - (int)av_len; 944 945 if ( match == 0 ) match = memcmp( value->bv_val, asserted->bv_val, v_len ); 946 947 /* If used in extensible match filter, match if value < asserted */ 948 if ( flags & SLAP_MR_EXT ) match = ( match >= 0 ); 949 950 *matchp = match; 951 return LDAP_SUCCESS; 952 } 953 954 /* Index generation function: Ordered index */ 955 int 956 datamorphUnsignedIndexer( slap_mask_t use, 957 slap_mask_t flags, 958 Syntax *syntax, 959 MatchingRule *mr, 960 struct berval *prefix, 961 BerVarray values, 962 BerVarray *keysp, 963 void *ctx ) 964 { 965 int i; 966 BerVarray keys; 967 968 for ( i = 0; values[i].bv_val != NULL; i++ ) { 969 /* just count them */ 970 } 971 972 /* we should have at least one value at this point */ 973 assert( i > 0 ); 974 975 keys = slap_sl_malloc( sizeof(struct berval) * ( i + 1 ), ctx ); 976 977 for ( i = 0; values[i].bv_val != NULL; i++ ) { 978 ber_dupbv_x( &keys[i], &values[i], ctx ); 979 } 980 981 BER_BVZERO( &keys[i] ); 982 983 *keysp = keys; 984 985 return LDAP_SUCCESS; 986 } 987 988 /* Index generation function: Ordered index */ 989 int 990 datamorphUnsignedFilter( 991 slap_mask_t use, 992 slap_mask_t flags, 993 Syntax *syntax, 994 MatchingRule *mr, 995 struct berval *prefix, 996 void *assertedValue, 997 BerVarray *keysp, 998 void *ctx ) 999 { 1000 BerVarray keys; 1001 BerValue *value = assertedValue; 1002 1003 keys = slap_sl_malloc( sizeof(struct berval) * 2, ctx ); 1004 ber_dupbv_x( &keys[0], value, ctx ); 1005 1006 BER_BVZERO( &keys[1] ); 1007 1008 *keysp = keys; 1009 1010 return LDAP_SUCCESS; 1011 } 1012 1013 /* Index generation function: Ordered index */ 1014 int 1015 datamorphSignedIndexer( 1016 slap_mask_t use, 1017 slap_mask_t flags, 1018 Syntax *syntax, 1019 MatchingRule *mr, 1020 struct berval *prefix, 1021 BerVarray values, 1022 BerVarray *keysp, 1023 void *ctx ) 1024 { 1025 int i; 1026 BerVarray keys; 1027 1028 for ( i = 0; values[i].bv_val != NULL; i++ ) { 1029 /* just count them */ 1030 } 1031 1032 /* we should have at least one value at this point */ 1033 assert( i > 0 ); 1034 1035 keys = slap_sl_malloc( sizeof(struct berval) * ( i + 1 ), ctx ); 1036 1037 for ( i = 0; values[i].bv_val != NULL; i++ ) { 1038 keys[i].bv_len = values[i].bv_len + 1; 1039 keys[i].bv_val = slap_sl_malloc( keys[i].bv_len, ctx ); 1040 1041 /* if positive (highest bit is not set), note that in the first byte */ 1042 *keys[i].bv_val = ~( *values[i].bv_val & 0x80 ); 1043 AC_MEMCPY( keys[i].bv_val + 1, values[i].bv_val, values[i].bv_len ); 1044 } 1045 1046 BER_BVZERO( &keys[i] ); 1047 1048 *keysp = keys; 1049 1050 return LDAP_SUCCESS; 1051 } 1052 1053 /* Index generation function: Ordered index */ 1054 int 1055 datamorphSignedFilter( 1056 slap_mask_t use, 1057 slap_mask_t flags, 1058 Syntax *syntax, 1059 MatchingRule *mr, 1060 struct berval *prefix, 1061 void *assertedValue, 1062 BerVarray *keysp, 1063 void *ctx ) 1064 { 1065 BerVarray keys; 1066 BerValue *value = assertedValue; 1067 1068 keys = slap_sl_malloc( sizeof(struct berval) * 2, ctx ); 1069 1070 keys[0].bv_len = value->bv_len + 1; 1071 keys[0].bv_val = slap_sl_malloc( keys[0].bv_len, ctx ); 1072 1073 /* if positive (highest bit is not set), note that in the first byte */ 1074 *keys[0].bv_val = ~( *value->bv_val & 0x80 ); 1075 AC_MEMCPY( keys[0].bv_val + 1, value->bv_val, value->bv_len ); 1076 1077 BER_BVZERO( &keys[1] ); 1078 1079 *keysp = keys; 1080 1081 return LDAP_SUCCESS; 1082 } 1083 1084 #define DATAMORPH_ARC "1.3.6.1.4.1.4203.666.11.12" 1085 1086 #define DATAMORPH_SYNTAXES DATAMORPH_ARC ".1" 1087 #define DATAMORPH_SYNTAX_BASE DATAMORPH_SYNTAXES ".1" 1088 #define DATAMORPH_SYNTAX_ENUM DATAMORPH_SYNTAXES ".2" 1089 #define DATAMORPH_SYNTAX_INT DATAMORPH_SYNTAXES ".3" 1090 #define DATAMORPH_SYNTAX_SIGNED_INT DATAMORPH_SYNTAXES ".4" 1091 1092 #define DATAMORPH_MATCHES DATAMORPH_ARC ".2" 1093 #define DATAMORPH_MATCH_EQUALITY DATAMORPH_MATCHES ".1" 1094 #define DATAMORPH_MATCH_SIGNED_EQUALITY DATAMORPH_MATCHES ".2" 1095 #define DATAMORPH_MATCH_ORDERING DATAMORPH_MATCHES ".3" 1096 #define DATAMORPH_MATCH_SIGNED_ORDERING DATAMORPH_MATCHES ".4" 1097 1098 static char *datamorph_sups[] = { 1099 DATAMORPH_SYNTAX_BASE, 1100 NULL 1101 }; 1102 1103 static char *datamorphSyntaxes[] = { 1104 DATAMORPH_SYNTAX_SIGNED_INT, 1105 DATAMORPH_SYNTAX_ENUM, 1106 DATAMORPH_SYNTAX_INT, 1107 1108 NULL 1109 }; 1110 1111 static slap_syntax_defs_rec datamorph_syntax_defs[] = { 1112 { "( " DATAMORPH_SYNTAX_BASE " DESC 'Fixed size value' )", 1113 0, NULL, NULL, NULL 1114 }, 1115 { "( " DATAMORPH_SYNTAX_ENUM " DESC 'Enumerated value' )", 1116 0, datamorph_sups, datamorphBlobValidate, NULL 1117 }, 1118 { "( " DATAMORPH_SYNTAX_INT " DESC 'Fixed-size integer' )", 1119 0, datamorph_sups, datamorphBlobValidate, NULL 1120 }, 1121 { "( " DATAMORPH_SYNTAX_SIGNED_INT " DESC 'Fixed-size signed integer' )", 1122 0, datamorph_sups, datamorphBlobValidate, NULL 1123 }, 1124 1125 { NULL, 0, NULL, NULL, NULL } 1126 }; 1127 1128 static Syntax *datamorph_base_syntax; 1129 1130 static slap_mrule_defs_rec datamorph_mrule_defs[] = { 1131 { "( " DATAMORPH_MATCH_EQUALITY 1132 " NAME 'fixedSizeIntegerMatch'" 1133 " SYNTAX " DATAMORPH_SYNTAX_INT " )", 1134 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_ORDERED_INDEX, 1135 datamorphSyntaxes + 1, 1136 NULL, NULL, octetStringOrderingMatch, 1137 datamorphUnsignedIndexer, datamorphUnsignedFilter, 1138 NULL 1139 }, 1140 1141 { "( " DATAMORPH_MATCH_SIGNED_EQUALITY 1142 " NAME 'fixedSizeSignedIntegerMatch'" 1143 " SYNTAX " DATAMORPH_SYNTAX_SIGNED_INT " )", 1144 SLAP_MR_EQUALITY|SLAP_MR_EXT|SLAP_MR_ORDERED_INDEX, 1145 NULL, 1146 NULL, NULL, datamorphBinarySignedOrderingMatch, 1147 datamorphSignedIndexer, datamorphSignedFilter, 1148 NULL 1149 }, 1150 1151 { "( " DATAMORPH_MATCH_ORDERING 1152 " NAME 'fixedSizeIntegerOrderingMatch'" 1153 " SYNTAX " DATAMORPH_SYNTAX_INT " )", 1154 SLAP_MR_ORDERING|SLAP_MR_EXT|SLAP_MR_ORDERED_INDEX, 1155 datamorphSyntaxes + 1, 1156 NULL, NULL, octetStringOrderingMatch, 1157 datamorphUnsignedIndexer, datamorphUnsignedFilter, 1158 "octetStringMatch" }, 1159 1160 { "( " DATAMORPH_MATCH_SIGNED_ORDERING 1161 " NAME 'fixedSizeSignedIntegerOrderingMatch'" 1162 " SYNTAX " DATAMORPH_SYNTAX_SIGNED_INT " )", 1163 SLAP_MR_ORDERING|SLAP_MR_EXT|SLAP_MR_ORDERED_INDEX, 1164 NULL, 1165 NULL, NULL, datamorphBinarySignedOrderingMatch, 1166 datamorphSignedIndexer, datamorphSignedFilter, 1167 "octetStringMatch" }, 1168 1169 { NULL, SLAP_MR_NONE, NULL, NULL, NULL, NULL, NULL, NULL, NULL } 1170 }; 1171 1172 /* Configuration */ 1173 1174 static ConfigLDAPadd datamorph_ldadd_enum; 1175 static ConfigLDAPadd datamorph_ldadd_interval; 1176 static ConfigLDAPadd datamorph_ldadd_mapping; 1177 1178 static ConfigDriver datamorph_set_attribute; 1179 static ConfigDriver datamorph_set_size; 1180 static ConfigDriver datamorph_set_signed; 1181 static ConfigDriver datamorph_set_bounds; 1182 static ConfigDriver datamorph_set_index; 1183 static ConfigDriver datamorph_set_value; 1184 static ConfigDriver datamorph_add_mapping; 1185 static ConfigDriver datamorph_add_transformation; 1186 1187 static ConfigCfAdd datamorph_cfadd; 1188 1189 enum { 1190 DATAMORPH_INT_SIZE = 1, 1191 DATAMORPH_INT_SIGNED, 1192 DATAMORPH_INT_LOWER, 1193 DATAMORPH_INT_UPPER, 1194 1195 DATAMORPH_INT_LAST, 1196 }; 1197 1198 static ConfigTable datamorph_cfg[] = { 1199 { "datamorph_attribute", "attr", 2, 2, 0, 1200 ARG_STRING|ARG_QUOTE|ARG_MAGIC, 1201 datamorph_set_attribute, 1202 "( OLcfgCtAt:7.1 NAME 'olcDatamorphAttribute' " 1203 "DESC 'Attribute to transform' " 1204 "EQUALITY caseIgnoreMatch " 1205 "SYNTAX OMsDirectoryString " 1206 "SINGLE-VALUE )", 1207 NULL, NULL 1208 }, 1209 { "datamorph_size", "<1|2|4|8>", 2, 2, 0, 1210 ARG_INT|ARG_MAGIC|DATAMORPH_INT_SIZE, 1211 datamorph_set_size, 1212 "( OLcfgCtAt:7.2 NAME 'olcDatamorphIntegerBytes' " 1213 "DESC 'Integer size in bytes' " 1214 "EQUALITY integerMatch " 1215 "SYNTAX OMsInteger " 1216 "SINGLE-VALUE )", 1217 NULL, NULL 1218 }, 1219 { "datamorph_signed", "TRUE|FALSE", 2, 2, 0, 1220 ARG_ON_OFF|ARG_MAGIC|DATAMORPH_INT_SIGNED, 1221 datamorph_set_signed, 1222 "( OLcfgCtAt:7.3 NAME 'olcDatamorphIntegerSigned' " 1223 "DESC 'Whether integers maintain sign' " 1224 "EQUALITY booleanMatch " 1225 "SYNTAX OMsBoolean " 1226 "SINGLE-VALUE )", 1227 NULL, NULL 1228 }, 1229 { "datamorph_lower_bound", "int", 2, 2, 0, 1230 ARG_BERVAL|ARG_MAGIC|DATAMORPH_INT_LOWER, 1231 datamorph_set_bounds, 1232 "( OLcfgCtAt:7.4 NAME 'olcDatamorphIntegerLowerBound' " 1233 "DESC 'Lowest valid value for the attribute' " 1234 "EQUALITY integerMatch " 1235 "SYNTAX OMsInteger " 1236 "SINGLE-VALUE )", 1237 NULL, NULL 1238 }, 1239 { "datamorph_upper_bound", "int", 2, 2, 0, 1240 ARG_BERVAL|ARG_MAGIC|DATAMORPH_INT_UPPER, 1241 datamorph_set_bounds, 1242 "( OLcfgCtAt:7.5 NAME 'olcDatamorphIntegerUpperBound' " 1243 "DESC 'Highest valid value for the attribute' " 1244 "EQUALITY integerMatch " 1245 "SYNTAX OMsInteger " 1246 "SINGLE-VALUE )", 1247 NULL, NULL 1248 }, 1249 1250 /* These have no equivalent in slapd.conf */ 1251 { "", NULL, 2, 2, 0, 1252 ARG_INT|ARG_MAGIC, 1253 datamorph_set_index, 1254 "( OLcfgCtAt:7.6 NAME 'olcDatamorphIndex' " 1255 "DESC 'Internal DB value' " 1256 "EQUALITY integerMatch " 1257 "SYNTAX OMsInteger " 1258 "SINGLE-VALUE )", 1259 NULL, NULL 1260 }, 1261 { "", NULL, 2, 2, 0, 1262 ARG_BERVAL|ARG_QUOTE|ARG_MAGIC, 1263 datamorph_set_value, 1264 "( OLcfgCtAt:7.7 NAME 'olcDatamorphValue' " 1265 "DESC 'Wire value' " 1266 "EQUALITY caseExactMatch " 1267 "SYNTAX OMsDirectoryString " 1268 "SINGLE-VALUE )", 1269 NULL, NULL 1270 }, 1271 1272 /* slapd.conf alternative for the two above */ 1273 { "datamorph_value", "int> <name", 3, 3, 0, 1274 ARG_QUOTE|ARG_MAGIC, 1275 datamorph_add_mapping, 1276 NULL, NULL, NULL 1277 }, 1278 1279 /* slapd.conf alternative for objectclasses below */ 1280 { "datamorph", "enum|int> <attr", 3, 3, 0, 1281 ARG_QUOTE|ARG_MAGIC, 1282 datamorph_add_transformation, 1283 NULL, NULL, NULL 1284 }, 1285 1286 { NULL, NULL, 0, 0, 0, ARG_IGNORED } 1287 }; 1288 1289 static ConfigOCs datamorph_ocs[] = { 1290 { "( OLcfgCtOc:7.1 " 1291 "NAME 'olcDatamorphConfig' " 1292 "DESC 'Datamorph overlay configuration' " 1293 "SUP olcOverlayConfig )", 1294 Cft_Overlay, datamorph_cfg, NULL, datamorph_cfadd }, 1295 { "( OLcfgCtOc:7.2 " 1296 "NAME 'olcTransformation' " 1297 "DESC 'Transformation configuration' " 1298 "MUST ( olcDatamorphAttribute ) " 1299 "SUP top " 1300 "ABSTRACT )", 1301 Cft_Misc, datamorph_cfg, NULL }, 1302 { "( OLcfgCtOc:7.3 " 1303 "NAME 'olcDatamorphEnum' " 1304 "DESC 'Configuration for an enumerated attribute' " 1305 "SUP olcTransformation " 1306 "STRUCTURAL )", 1307 Cft_Misc, datamorph_cfg, datamorph_ldadd_enum }, 1308 { "( OLcfgCtOc:7.4 " 1309 "NAME 'olcDatamorphInteger' " 1310 "DESC 'Configuration for a compact integer attribute' " 1311 "MUST ( olcDatamorphIntegerBytes ) " 1312 "MAY ( olcDatamorphIntegerLowerBound $ " 1313 "olcDatamorphIntegerUpperBound $ " 1314 "olcDatamorphIntegerSigned " 1315 ") " 1316 "SUP olcTransformation " 1317 "STRUCTURAL )", 1318 Cft_Misc, datamorph_cfg, datamorph_ldadd_interval }, 1319 { "( OLcfgCtOc:7.5 " 1320 "NAME 'olcDatamorphEnumValue' " 1321 "DESC 'Configuration for an enumerated attribute' " 1322 "MUST ( olcDatamorphIndex $ " 1323 "olcDatamorphValue " 1324 ") " 1325 "STRUCTURAL )", 1326 Cft_Misc, datamorph_cfg, datamorph_ldadd_mapping }, 1327 1328 { NULL, 0, NULL } 1329 }; 1330 1331 static void 1332 datamorph_mapping_free( void *arg ) 1333 { 1334 datamorph_enum_mapping *mapping = arg; 1335 1336 ch_free( mapping->wire_value.bv_val ); 1337 ch_free( mapping ); 1338 } 1339 1340 static void 1341 datamorph_info_free( void *arg ) 1342 { 1343 transformation_info *info = arg; 1344 1345 if ( info->type == DATAMORPH_ENUM ) { 1346 ldap_avl_free( info->ti_enum.to_db, datamorph_mapping_free ); 1347 } 1348 ch_free( info ); 1349 } 1350 1351 static int 1352 datamorph_set_attribute( ConfigArgs *ca ) 1353 { 1354 transformation_info needle = {}, *info = ca->ca_private; 1355 slap_overinst *on = (slap_overinst *)ca->bi; 1356 datamorph_info *ov = on->on_bi.bi_private; 1357 char *s = ca->value_string; 1358 const char *text; 1359 int rc = LDAP_SUCCESS; 1360 1361 if ( ca->op == SLAP_CONFIG_EMIT ) { 1362 ca->value_string = info->attr->ad_cname.bv_val; 1363 return LDAP_SUCCESS; 1364 } else if ( ca->op == LDAP_MOD_DELETE ) { 1365 info = ldap_avl_delete( &ov->transformations, info, 1366 transformation_info_cmp ); 1367 assert( info ); 1368 1369 info->attr = NULL; 1370 return LDAP_SUCCESS; 1371 } 1372 1373 if ( *s == '{' ) { 1374 s = strchr( s, '}' ); 1375 if ( !s ) { 1376 rc = LDAP_UNDEFINED_TYPE; 1377 goto done; 1378 } 1379 s += 1; 1380 } 1381 1382 rc = slap_str2ad( s, &info->attr, &text ); 1383 ch_free( ca->value_string ); 1384 if ( rc ) { 1385 goto done; 1386 } 1387 1388 /* The type has to be set appropriately */ 1389 if ( !info->attr->ad_type->sat_syntax->ssyn_sups || 1390 info->attr->ad_type->sat_syntax->ssyn_sups[0] != 1391 datamorph_base_syntax ) { 1392 snprintf( ca->cr_msg, sizeof(ca->cr_msg), 1393 "improper syntax for attribute %s", 1394 info->attr->ad_cname.bv_val ); 1395 Debug( LDAP_DEBUG_ANY, "%s: %s\n", ca->log, ca->cr_msg ); 1396 rc = LDAP_CONSTRAINT_VIOLATION; 1397 goto done; 1398 } 1399 1400 needle.attr = info->attr; 1401 if ( ldap_avl_find( ov->transformations, &needle, transformation_info_cmp ) ) { 1402 rc = LDAP_CONSTRAINT_VIOLATION; 1403 goto done; 1404 } 1405 1406 done: 1407 if ( rc ) { 1408 ca->reply.err = rc; 1409 } 1410 return rc; 1411 } 1412 1413 static int 1414 datamorph_set_size( ConfigArgs *ca ) 1415 { 1416 transformation_info *info = ca->ca_private; 1417 1418 if ( !info ) { 1419 slap_overinst *on = (slap_overinst *)ca->bi; 1420 datamorph_info *ov = on->on_bi.bi_private; 1421 info = ov->wip_transformation; 1422 assert( ca->op == SLAP_CONFIG_ADD ); 1423 } 1424 1425 if ( ca->op == SLAP_CONFIG_EMIT ) { 1426 ca->value_int = info->ti_int.size; 1427 return LDAP_SUCCESS; 1428 } else if ( ca->op == LDAP_MOD_DELETE ) { 1429 info->ti_int.size = 0; 1430 return LDAP_SUCCESS; 1431 } 1432 1433 if ( ca->value_int != 1 && 1434 ca->value_int != 2 && 1435 ca->value_int != 4 && 1436 ca->value_int != 8 ) { 1437 snprintf( ca->cr_msg, sizeof(ca->cr_msg), "invalid size %d", 1438 ca->value_int ); 1439 Debug( LDAP_DEBUG_ANY, "%s: %s\n", ca->log, ca->cr_msg ); 1440 ca->reply.err = LDAP_CONSTRAINT_VIOLATION; 1441 return ca->reply.err; 1442 } 1443 info->ti_int.size = ca->value_int; 1444 1445 return LDAP_SUCCESS; 1446 } 1447 1448 static int 1449 datamorph_set_signed( ConfigArgs *ca ) 1450 { 1451 transformation_info *info = ca->ca_private; 1452 1453 if ( !info ) { 1454 slap_overinst *on = (slap_overinst *)ca->bi; 1455 datamorph_info *ov = on->on_bi.bi_private; 1456 info = ov->wip_transformation; 1457 assert( ca->op == SLAP_CONFIG_ADD ); 1458 } 1459 1460 if ( ca->op == SLAP_CONFIG_EMIT ) { 1461 ca->value_int = info->ti_int.flags & DATAMORPH_FLAG_SIGNED; 1462 return LDAP_SUCCESS; 1463 } else if ( ca->op == LDAP_MOD_DELETE ) { 1464 info->ti_int.flags &= ~DATAMORPH_FLAG_SIGNED; 1465 return LDAP_SUCCESS; 1466 } 1467 1468 info->ti_int.flags &= ~DATAMORPH_FLAG_SIGNED; 1469 if ( ca->value_int ) { 1470 info->ti_int.flags |= DATAMORPH_FLAG_SIGNED; 1471 } 1472 1473 return LDAP_SUCCESS; 1474 } 1475 1476 static int 1477 datamorph_set_bounds( ConfigArgs *ca ) 1478 { 1479 transformation_info *info = ca->ca_private; 1480 datamorph_interval_bound *bound; 1481 uint64_t unsigned_bound; 1482 int64_t signed_bound; 1483 char *ptr = ca->value_bv.bv_val + ca->value_bv.bv_len; 1484 int flag; 1485 1486 if ( !info ) { 1487 slap_overinst *on = (slap_overinst *)ca->bi; 1488 datamorph_info *ov = on->on_bi.bi_private; 1489 info = ov->wip_transformation; 1490 assert( ca->op == SLAP_CONFIG_ADD ); 1491 } 1492 1493 switch ( ca->type ) { 1494 case DATAMORPH_INT_LOWER: 1495 bound = &info->ti_int.lower; 1496 flag = DATAMORPH_FLAG_LOWER; 1497 break; 1498 case DATAMORPH_INT_UPPER: 1499 bound = &info->ti_int.upper; 1500 flag = DATAMORPH_FLAG_UPPER; 1501 break; 1502 default: 1503 assert(0); 1504 } 1505 1506 if ( ca->op == SLAP_CONFIG_EMIT ) { 1507 char buf[24]; 1508 struct berval bv = { .bv_val = buf }; 1509 1510 if ( !(info->ti_int.flags & flag) ) { 1511 /* Bound not set, do not emit */ 1512 return LDAP_SUCCESS; 1513 } 1514 if ( info->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { 1515 bv.bv_len = sprintf( buf, "%" PRId64, bound->i ); 1516 } else { 1517 bv.bv_len = sprintf( buf, "%" PRIu64, bound->u ); 1518 } 1519 ber_dupbv_x( &ca->value_bv, &bv, ca->ca_op->o_tmpmemctx ); 1520 1521 return LDAP_SUCCESS; 1522 } else if ( ca->op == LDAP_MOD_DELETE ) { 1523 info->ti_int.flags &= ~flag; 1524 if ( info->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { 1525 bound->i = (flag == DATAMORPH_FLAG_LOWER) ? INT64_MIN : INT64_MAX; 1526 } else { 1527 bound->u = (flag == DATAMORPH_FLAG_LOWER) ? 0 : UINT64_MAX; 1528 } 1529 return LDAP_SUCCESS; 1530 } 1531 1532 /* FIXME: if attributes in the Add operation come in the wrong order 1533 * (signed=true after the bound definition), we can't check the interval 1534 * sanity. */ 1535 /* 1536 if ( info->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { 1537 signed_bound = strtoll( ca->value_bv.bv_val, &ptr, 10 ); 1538 } else { 1539 unsigned_bound = strtoull( ca->value_bv.bv_val, &ptr, 10 ); 1540 } 1541 */ 1542 /* Also, no idea what happens in the case of big-endian, hopefully, 1543 * it behaves the same */ 1544 unsigned_bound = strtoull( ca->value_bv.bv_val, &ptr, 10 ); 1545 signed_bound = (int64_t)unsigned_bound; 1546 1547 if ( *ca->value_bv.bv_val == '\0' || *ptr != '\0' ) { 1548 snprintf( ca->cr_msg, sizeof(ca->cr_msg), 1549 "failed to parse '%s' as integer", 1550 ca->value_bv.bv_val ); 1551 Debug( LDAP_DEBUG_ANY, "%s: %s\n", ca->log, ca->cr_msg ); 1552 ca->reply.err = LDAP_CONSTRAINT_VIOLATION; 1553 return ca->reply.err; 1554 } 1555 ch_free( ca->value_bv.bv_val ); 1556 1557 info->ti_int.flags |= flag; 1558 switch ( info->ti_int.size ) { 1559 case 1: 1560 if ( info->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { 1561 /* See FIXME above 1562 if ( signed_bound < INT8_MIN || signed_bound > INT8_MAX ) { 1563 goto fail; 1564 } 1565 */ 1566 } else { 1567 /* See FIXME above 1568 if ( unsigned_bound > UINT8_MAX ) { 1569 goto fail; 1570 } 1571 */ 1572 } 1573 break; 1574 case 2: 1575 if ( info->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { 1576 /* See FIXME above 1577 if ( signed_bound < INT16_MIN || signed_bound > INT16_MAX ) { 1578 goto fail; 1579 } 1580 */ 1581 } else { 1582 /* See FIXME above 1583 if ( unsigned_bound > UINT16_MAX ) { 1584 goto fail; 1585 } 1586 */ 1587 } 1588 break; 1589 case 4: 1590 if ( info->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { 1591 /* See FIXME above 1592 if ( signed_bound < INT32_MIN || signed_bound > INT32_MAX ) { 1593 goto fail; 1594 } 1595 */ 1596 } else { 1597 /* See FIXME above 1598 if ( unsigned_bound > UINT32_MAX ) { 1599 goto fail; 1600 } 1601 */ 1602 } 1603 break; 1604 case 8: 1605 break; 1606 default: 1607 /* Should only happen in these two cases: 1608 * 1. datamorph_size not yet encountered for this one (when 1609 * processing slapd.conf) 1610 * 2. When someone runs a fun modification on the config entry 1611 * messing with more attributes at once 1612 * 1613 * The error message is expected to be helpful only for the former, 1614 * so use the slapd.conf name. 1615 */ 1616 snprintf( ca->cr_msg, sizeof(ca->cr_msg), 1617 "datamorph_size has to be set first!" ); 1618 Debug( LDAP_DEBUG_ANY, "%s: %s\n", ca->log, ca->cr_msg ); 1619 ca->reply.err = LDAP_CONSTRAINT_VIOLATION; 1620 return ca->reply.err; 1621 } 1622 if ( info->ti_int.flags & DATAMORPH_FLAG_SIGNED ) { 1623 bound->i = signed_bound; 1624 } else { 1625 bound->u = unsigned_bound; 1626 } 1627 1628 return LDAP_SUCCESS; 1629 } 1630 1631 static int 1632 datamorph_set_value( ConfigArgs *ca ) 1633 { 1634 datamorph_enum_mapping *mapping = ca->ca_private; 1635 char *s = ca->value_bv.bv_val; 1636 1637 if ( ca->op == SLAP_CONFIG_EMIT ) { 1638 /* We generate the value as part of the RDN, don't add anything */ 1639 return LDAP_SUCCESS; 1640 } else if ( ca->op == LDAP_MOD_DELETE ) { 1641 ch_free( mapping->wire_value.bv_val ); 1642 BER_BVZERO( &mapping->wire_value ); 1643 /* TODO: remove from info->ti_enum.to_db? */ 1644 return LDAP_SUCCESS; 1645 } 1646 1647 /* As long as this attribute can be in the RDN, 1648 * we have to expect the '{n}' prefix */ 1649 if ( *s == '{' ) { 1650 ber_len_t len; 1651 s = memchr( s, '}', ca->value_bv.bv_len ); 1652 if ( !s ) { 1653 ca->reply.err = LDAP_UNDEFINED_TYPE; 1654 return ca->reply.err; 1655 } 1656 s += 1; 1657 1658 len = ca->value_bv.bv_len - ( s - ca->value_bv.bv_val ); 1659 ber_str2bv( s, len, 1, &mapping->wire_value ); 1660 ch_free( ca->value_bv.bv_val ); 1661 } else { 1662 mapping->wire_value = ca->value_bv; 1663 } 1664 1665 return LDAP_SUCCESS; 1666 } 1667 1668 static int 1669 datamorph_set_index( ConfigArgs *ca ) 1670 { 1671 datamorph_enum_mapping *mapping = ca->ca_private; 1672 struct berval *from_db = mapping->transformation->ti_enum.from_db; 1673 1674 if ( ca->op == SLAP_CONFIG_EMIT ) { 1675 ca->value_int = mapping->db_value; 1676 return LDAP_SUCCESS; 1677 } else if ( ca->op == LDAP_MOD_DELETE ) { 1678 BER_BVZERO( &from_db[mapping->db_value] ); 1679 return LDAP_SUCCESS; 1680 } 1681 1682 if ( ca->value_int < 0 || ca->value_int >= 256 ) { 1683 ca->reply.err = LDAP_CONSTRAINT_VIOLATION; 1684 return ca->reply.err; 1685 } else if ( !BER_BVISNULL( &from_db[ca->value_int] ) ) { 1686 snprintf( ca->cr_msg, sizeof(ca->cr_msg), "duplicate index %d", 1687 ca->value_int ); 1688 Debug( LDAP_DEBUG_ANY, "%s: %s\n", ca->log, ca->cr_msg ); 1689 ca->reply.err = LDAP_CONSTRAINT_VIOLATION; 1690 return ca->reply.err; 1691 } 1692 mapping->db_value = ca->value_int; 1693 from_db[ca->value_int] = mapping->wire_value; 1694 1695 return LDAP_SUCCESS; 1696 } 1697 1698 /* Called when processing slapd.conf only, 1699 * cn=config uses the objectclass to decide which type we're dealing with. 1700 */ 1701 static int 1702 datamorph_add_transformation( ConfigArgs *ca ) 1703 { 1704 slap_overinst *on = (slap_overinst *)ca->bi; 1705 datamorph_info *ov = on->on_bi.bi_private; 1706 transformation_info *info; 1707 1708 if ( ov->wip_transformation ) { 1709 /* We checked everything as were processing the lines */ 1710 int rc = ldap_avl_insert( &ov->transformations, ov->wip_transformation, 1711 transformation_info_cmp, ldap_avl_dup_error ); 1712 assert( rc == LDAP_SUCCESS ); 1713 } 1714 1715 info = ch_calloc( 1, sizeof(transformation_info) ); 1716 ov->wip_transformation = ca->ca_private = info; 1717 1718 if ( !strcasecmp( ca->argv[1], "enum" ) ) { 1719 info->type = DATAMORPH_ENUM; 1720 } else if ( !strcasecmp( ca->argv[1], "int" ) ) { 1721 info->type = DATAMORPH_INT; 1722 } else { 1723 snprintf( ca->cr_msg, sizeof(ca->cr_msg), 1724 "unknown transformation type '%s'", ca->argv[1] ); 1725 Debug( LDAP_DEBUG_ANY, "%s: %s\n", ca->log, ca->cr_msg ); 1726 ca->reply.err = LDAP_CONSTRAINT_VIOLATION; 1727 return ca->reply.err; 1728 } 1729 1730 ca->value_string = strdup( ca->argv[2] ); 1731 1732 return datamorph_set_attribute( ca ); 1733 } 1734 1735 static int 1736 datamorph_add_mapping( ConfigArgs *ca ) 1737 { 1738 slap_overinst *on = (slap_overinst *)ca->bi; 1739 datamorph_info *ov = on->on_bi.bi_private; 1740 transformation_info *info = ov->wip_transformation; 1741 datamorph_enum_mapping *mapping; 1742 int rc = LDAP_CONSTRAINT_VIOLATION; 1743 1744 if ( !info ) { 1745 snprintf( ca->cr_msg, sizeof(ca->cr_msg), "no attribute configured" ); 1746 Debug( LDAP_DEBUG_ANY, "%s: %s\n", ca->log, ca->cr_msg ); 1747 goto done; 1748 } 1749 1750 mapping = ch_calloc( 1, sizeof(datamorph_enum_mapping) ); 1751 mapping->transformation = info; 1752 ca->ca_private = mapping; 1753 1754 ber_str2bv( ca->argv[2], 0, 1, &ca->value_bv ); 1755 rc = datamorph_set_value( ca ); 1756 if ( rc != LDAP_SUCCESS ) { 1757 goto done; 1758 } 1759 1760 rc = lutil_atoix( &ca->value_int, ca->argv[1], 0 ); 1761 if ( rc != LDAP_SUCCESS ) { 1762 snprintf( ca->cr_msg, sizeof(ca->cr_msg), "invalid integer %s", 1763 ca->argv[1] ); 1764 Debug( LDAP_DEBUG_ANY, "%s: %s\n", ca->log, ca->cr_msg ); 1765 goto done; 1766 } 1767 1768 rc = datamorph_set_index( ca ); 1769 if ( rc != LDAP_SUCCESS ) { 1770 goto done; 1771 } 1772 1773 done: 1774 if ( rc == LDAP_SUCCESS ) { 1775 rc = ldap_avl_insert( &info->ti_enum.to_db, mapping, 1776 transformation_mapping_cmp, ldap_avl_dup_error ); 1777 } 1778 if ( rc ) { 1779 ca->reply.err = rc; 1780 } 1781 1782 return rc; 1783 } 1784 1785 static int 1786 datamorph_ldadd_info_cleanup( ConfigArgs *ca ) 1787 { 1788 slap_overinst *on = (slap_overinst *)ca->bi; 1789 datamorph_info *ov = on->on_bi.bi_private; 1790 transformation_info *info = ca->ca_private; 1791 1792 if ( ca->reply.err != LDAP_SUCCESS ) { 1793 /* Not reached since cleanup is only called on success */ 1794 fail: 1795 ch_free( info ); 1796 return LDAP_SUCCESS; 1797 } 1798 1799 if ( ldap_avl_insert( &ov->transformations, info, transformation_info_cmp, 1800 ldap_avl_dup_error ) ) { 1801 goto fail; 1802 } 1803 return LDAP_SUCCESS; 1804 } 1805 1806 static int 1807 datamorph_ldadd_transformation( 1808 CfEntryInfo *cei, 1809 Entry *e, 1810 ConfigArgs *ca, 1811 datamorph_type type ) 1812 { 1813 transformation_info *info; 1814 1815 if ( cei->ce_type != Cft_Overlay || !cei->ce_bi || 1816 cei->ce_bi->bi_cf_ocs != datamorph_ocs ) 1817 return LDAP_CONSTRAINT_VIOLATION; 1818 1819 info = ch_calloc( 1, sizeof(transformation_info) ); 1820 info->type = type; 1821 1822 ca->bi = cei->ce_bi; 1823 ca->ca_private = info; 1824 config_push_cleanup( ca, datamorph_ldadd_info_cleanup ); 1825 /* config_push_cleanup is only run in the case of online config but we use it to 1826 * enable the new config when done with the entry */ 1827 ca->lineno = 0; 1828 1829 return LDAP_SUCCESS; 1830 } 1831 1832 static int 1833 datamorph_ldadd_enum( CfEntryInfo *cei, Entry *e, ConfigArgs *ca ) 1834 { 1835 return datamorph_ldadd_transformation( cei, e, ca, DATAMORPH_ENUM ); 1836 } 1837 1838 static int 1839 datamorph_ldadd_interval( CfEntryInfo *cei, Entry *e, ConfigArgs *ca ) 1840 { 1841 return datamorph_ldadd_transformation( cei, e, ca, DATAMORPH_INT ); 1842 } 1843 1844 static int 1845 datamorph_ldadd_mapping_cleanup( ConfigArgs *ca ) 1846 { 1847 datamorph_enum_mapping *mapping = ca->ca_private; 1848 transformation_info *info = mapping->transformation; 1849 1850 if ( ca->reply.err != LDAP_SUCCESS ) { 1851 /* Not reached since cleanup is only called on success */ 1852 fail: 1853 datamorph_mapping_free( mapping ); 1854 return LDAP_SUCCESS; 1855 } 1856 1857 if ( ldap_avl_insert( &info->ti_enum.to_db, mapping, transformation_mapping_cmp, 1858 ldap_avl_dup_error ) ) { 1859 goto fail; 1860 } 1861 info->ti_enum.from_db[mapping->db_value] = mapping->wire_value; 1862 1863 return LDAP_SUCCESS; 1864 } 1865 1866 static int 1867 datamorph_ldadd_mapping( CfEntryInfo *cei, Entry *e, ConfigArgs *ca ) 1868 { 1869 transformation_info *info; 1870 datamorph_enum_mapping *mapping; 1871 CfEntryInfo *parent = cei->ce_parent; 1872 1873 if ( cei->ce_type != Cft_Misc || !parent || !parent->ce_bi || 1874 parent->ce_bi->bi_cf_ocs != datamorph_ocs ) 1875 return LDAP_CONSTRAINT_VIOLATION; 1876 1877 info = cei->ce_private; 1878 1879 mapping = ch_calloc( 1, sizeof(datamorph_enum_mapping) ); 1880 mapping->transformation = info; 1881 1882 ca->ca_private = mapping; 1883 config_push_cleanup( ca, datamorph_ldadd_mapping_cleanup ); 1884 /* config_push_cleanup is only run in the case of online config but we use it to 1885 * enable the new config when done with the entry */ 1886 ca->lineno = 0; 1887 1888 return LDAP_SUCCESS; 1889 } 1890 1891 struct datamorph_cfadd_args { 1892 Operation *op; 1893 SlapReply *rs; 1894 Entry *p; 1895 ConfigArgs *ca; 1896 int index; 1897 }; 1898 1899 static int 1900 datamorph_config_build_enum( void *item, void *arg ) 1901 { 1902 datamorph_enum_mapping *mapping = item; 1903 struct datamorph_cfadd_args *args = arg; 1904 struct berval rdn; 1905 Entry *e; 1906 char *p; 1907 ber_len_t index; 1908 1909 rdn.bv_len = snprintf( args->ca->cr_msg, sizeof(args->ca->cr_msg), 1910 "olcDatamorphValue={%d}", args->index++ ); 1911 rdn.bv_val = args->ca->cr_msg; 1912 p = rdn.bv_val + rdn.bv_len; 1913 1914 rdn.bv_len += mapping->wire_value.bv_len; 1915 for ( index = 0; index < mapping->wire_value.bv_len; index++ ) { 1916 if ( RDN_NEEDSESCAPE(mapping->wire_value.bv_val[index]) ) { 1917 rdn.bv_len++; 1918 *p++ = '\\'; 1919 } 1920 *p++ = mapping->wire_value.bv_val[index]; 1921 } 1922 *p = '\0'; 1923 1924 args->ca->ca_private = mapping; 1925 args->ca->ca_op = args->op; 1926 e = config_build_entry( args->op, args->rs, args->p->e_private, args->ca, 1927 &rdn, &datamorph_ocs[4], NULL ); 1928 assert( e ); 1929 1930 return LDAP_SUCCESS; 1931 } 1932 1933 static int 1934 datamorph_config_build_attr( void *item, void *arg ) 1935 { 1936 transformation_info *info = item; 1937 struct datamorph_cfadd_args *args = arg; 1938 struct berval rdn; 1939 ConfigOCs *oc; 1940 Entry *e; 1941 1942 rdn.bv_len = snprintf( args->ca->cr_msg, sizeof(args->ca->cr_msg), 1943 "olcDatamorphAttribute={%d}%s", args->index++, 1944 info->attr->ad_cname.bv_val ); 1945 rdn.bv_val = args->ca->cr_msg; 1946 1947 switch ( info->type ) { 1948 case DATAMORPH_ENUM: 1949 oc = &datamorph_ocs[2]; 1950 break; 1951 case DATAMORPH_INT: 1952 oc = &datamorph_ocs[3]; 1953 break; 1954 default: 1955 assert(0); 1956 break; 1957 } 1958 1959 args->ca->ca_private = info; 1960 args->ca->ca_op = args->op; 1961 e = config_build_entry( 1962 args->op, args->rs, args->p->e_private, args->ca, &rdn, oc, NULL ); 1963 assert( e ); 1964 1965 if ( info->type == DATAMORPH_ENUM ) { 1966 struct datamorph_cfadd_args new_args = *args; 1967 new_args.p = e; 1968 new_args.index = 0; 1969 1970 return ldap_avl_apply( info->ti_enum.to_db, datamorph_config_build_enum, 1971 &new_args, 1, AVL_PREORDER ); 1972 } 1973 1974 return LDAP_SUCCESS; 1975 } 1976 1977 static int 1978 datamorph_cfadd( Operation *op, SlapReply *rs, Entry *p, ConfigArgs *ca ) 1979 { 1980 slap_overinst *on = (slap_overinst *)ca->bi; 1981 datamorph_info *ov = on->on_bi.bi_private; 1982 struct datamorph_cfadd_args args = { 1983 .op = op, 1984 .rs = rs, 1985 .p = p, 1986 .ca = ca, 1987 .index = 0, 1988 }; 1989 1990 if ( ov->wip_transformation ) { 1991 /* There is one last item that is unfinished */ 1992 int rc = ldap_avl_insert( &ov->transformations, ov->wip_transformation, 1993 transformation_info_cmp, ldap_avl_dup_error ); 1994 assert( rc == LDAP_SUCCESS ); 1995 } 1996 1997 return ldap_avl_apply( ov->transformations, &datamorph_config_build_attr, &args, 1998 1, AVL_PREORDER ); 1999 } 2000 2001 static slap_overinst datamorph; 2002 2003 static int 2004 datamorph_db_init( BackendDB *be, ConfigReply *cr ) 2005 { 2006 slap_overinst *on = (slap_overinst *)be->bd_info; 2007 datamorph_info *ov; 2008 2009 /* TODO: can this be global? */ 2010 if ( SLAP_ISGLOBALOVERLAY(be) ) { 2011 Debug( LDAP_DEBUG_ANY, "datamorph overlay must be instantiated " 2012 "within a database.\n" ); 2013 return 1; 2014 } 2015 2016 ov = ch_calloc( 1, sizeof(datamorph_info) ); 2017 on->on_bi.bi_private = ov; 2018 2019 return LDAP_SUCCESS; 2020 } 2021 2022 static int 2023 datamorph_db_destroy( BackendDB *be, ConfigReply *cr ) 2024 { 2025 slap_overinst *on = (slap_overinst *)be->bd_info; 2026 datamorph_info *ov = on->on_bi.bi_private; 2027 2028 if ( ov ) { 2029 ldap_avl_free( ov->transformations, datamorph_info_free ); 2030 } 2031 ch_free( ov ); 2032 2033 return LDAP_SUCCESS; 2034 } 2035 2036 int 2037 datamorph_initialize() 2038 { 2039 int rc, i; 2040 2041 datamorph.on_bi.bi_type = "datamorph"; 2042 datamorph.on_bi.bi_db_init = datamorph_db_init; 2043 datamorph.on_bi.bi_db_destroy = datamorph_db_destroy; 2044 2045 datamorph.on_bi.bi_op_add = datamorph_op_add; 2046 datamorph.on_bi.bi_op_compare = datamorph_op_compare; 2047 datamorph.on_bi.bi_op_modify = datamorph_op_mod; 2048 datamorph.on_bi.bi_op_modrdn = datamorph_op_modrdn; 2049 datamorph.on_bi.bi_op_search = datamorph_op_search; 2050 datamorph.on_response = datamorph_response; 2051 2052 datamorph.on_bi.bi_entry_release_rw = datamorph_entry_release_rw; 2053 datamorph.on_bi.bi_entry_get_rw = datamorph_entry_get_rw; 2054 2055 datamorph.on_bi.bi_cf_ocs = datamorph_ocs; 2056 2057 for ( i = 0; datamorph_syntax_defs[i].sd_desc != NULL; i++ ) { 2058 rc = register_syntax( &datamorph_syntax_defs[i] ); 2059 2060 if ( rc ) { 2061 Debug( LDAP_DEBUG_ANY, "datamorph_initialize: " 2062 "error registering syntax %s\n", 2063 datamorph_syntax_defs[i].sd_desc ); 2064 return rc; 2065 } 2066 } 2067 2068 datamorph_base_syntax = syn_find( DATAMORPH_SYNTAX_BASE ); 2069 assert( datamorph_base_syntax ); 2070 2071 for ( i = 0; datamorph_mrule_defs[i].mrd_desc != NULL; i++ ) { 2072 rc = register_matching_rule( &datamorph_mrule_defs[i] ); 2073 2074 if ( rc ) { 2075 Debug( LDAP_DEBUG_ANY, "datamorph_initialize: " 2076 "error registering matching rule %s\n", 2077 datamorph_mrule_defs[i].mrd_desc ); 2078 return rc; 2079 } 2080 } 2081 2082 rc = config_register_schema( datamorph_cfg, datamorph_ocs ); 2083 if ( rc ) return rc; 2084 2085 return overlay_register( &datamorph ); 2086 } 2087 2088 #if SLAPD_OVER_DATAMORPH == SLAPD_MOD_DYNAMIC 2089 int 2090 init_module( int argc, char *argv[] ) 2091 { 2092 return datamorph_initialize(); 2093 } 2094 #endif 2095 2096 #endif /* SLAPD_OVER_DATAMORPH */ 2097