xref: /netbsd-src/external/bsd/openldap/dist/contrib/slapd-modules/datamorph/datamorph.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
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