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
transformation_mapping_cmp(const void * l,const void * r)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
transformation_info_cmp(const void * l,const void * r)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
transform_to_db_format_one(Operation * op,transformation_info * definition,struct berval * value,struct berval * outval)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
transform_to_db_format(Operation * op,transformation_info * definition,BerVarray values,int numvals,BerVarray * out)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
transform_from_db_format_one(Operation * op,transformation_info * definition,struct berval * value,struct berval * outval)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
transform_from_db_format(Operation * op,transformation_info * definition,BerVarray values,int numvals,BerVarray * out)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
datamorph_filter(Operation * op,datamorph_info * ov,Filter * f)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
datamorph_op_add(Operation * op,SlapReply * rs)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
datamorph_op_compare(Operation * op,SlapReply * rs)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
datamorph_op_mod(Operation * op,SlapReply * rs)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
datamorph_op_modrdn(Operation * op,SlapReply * rs)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
datamorph_response(Operation * op,SlapReply * rs)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
datamorph_op_search(Operation * op,SlapReply * rs)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
datamorph_entry_release_rw(Operation * op,Entry * e,int rw)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
datamorph_entry_get_rw(Operation * op,struct berval * ndn,ObjectClass * oc,AttributeDescription * at,int rw,Entry ** ep)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
datamorphBlobValidate(Syntax * syntax,struct berval * in)918 datamorphBlobValidate( Syntax *syntax, struct berval *in )
919 {
920 /* any value allowed */
921 return LDAP_SUCCESS;
922 }
923
924 int
datamorphBinarySignedOrderingMatch(int * matchp,slap_mask_t flags,Syntax * syntax,MatchingRule * mr,struct berval * value,void * assertedValue)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
datamorphUnsignedIndexer(slap_mask_t use,slap_mask_t flags,Syntax * syntax,MatchingRule * mr,struct berval * prefix,BerVarray values,BerVarray * keysp,void * ctx)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
datamorphUnsignedFilter(slap_mask_t use,slap_mask_t flags,Syntax * syntax,MatchingRule * mr,struct berval * prefix,void * assertedValue,BerVarray * keysp,void * ctx)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
datamorphSignedIndexer(slap_mask_t use,slap_mask_t flags,Syntax * syntax,MatchingRule * mr,struct berval * prefix,BerVarray values,BerVarray * keysp,void * ctx)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
datamorphSignedFilter(slap_mask_t use,slap_mask_t flags,Syntax * syntax,MatchingRule * mr,struct berval * prefix,void * assertedValue,BerVarray * keysp,void * ctx)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
datamorph_mapping_free(void * arg)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
datamorph_info_free(void * arg)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
datamorph_set_attribute(ConfigArgs * ca)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
datamorph_set_size(ConfigArgs * ca)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
datamorph_set_signed(ConfigArgs * ca)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
datamorph_set_bounds(ConfigArgs * ca)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
datamorph_set_value(ConfigArgs * ca)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
datamorph_set_index(ConfigArgs * ca)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
datamorph_add_transformation(ConfigArgs * ca)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
datamorph_add_mapping(ConfigArgs * ca)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
datamorph_ldadd_info_cleanup(ConfigArgs * ca)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
datamorph_ldadd_transformation(CfEntryInfo * cei,Entry * e,ConfigArgs * ca,datamorph_type type)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
datamorph_ldadd_enum(CfEntryInfo * cei,Entry * e,ConfigArgs * ca)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
datamorph_ldadd_interval(CfEntryInfo * cei,Entry * e,ConfigArgs * ca)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
datamorph_ldadd_mapping_cleanup(ConfigArgs * ca)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
datamorph_ldadd_mapping(CfEntryInfo * cei,Entry * e,ConfigArgs * ca)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
datamorph_config_build_enum(void * item,void * arg)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
datamorph_config_build_attr(void * item,void * arg)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
datamorph_cfadd(Operation * op,SlapReply * rs,Entry * p,ConfigArgs * ca)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
datamorph_db_init(BackendDB * be,ConfigReply * cr)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
datamorph_db_destroy(BackendDB * be,ConfigReply * cr)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
datamorph_initialize()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
init_module(int argc,char * argv[])2090 init_module( int argc, char *argv[] )
2091 {
2092 return datamorph_initialize();
2093 }
2094 #endif
2095
2096 #endif /* SLAPD_OVER_DATAMORPH */
2097