rwm.c revision 1.1.1.6.6.1 1 /* $NetBSD: rwm.c,v 1.1.1.6.6.1 2019/08/10 06:17:21 martin Exp $ */
2
3 /* rwm.c - rewrite/remap operations */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 *
7 * Copyright 2003-2019 The OpenLDAP Foundation.
8 * Portions Copyright 2003 Pierangelo Masarati.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted only as authorized by the OpenLDAP
13 * Public License.
14 *
15 * A copy of this license is available in the file LICENSE in the
16 * top-level directory of the distribution or, alternatively, at
17 * <http://www.OpenLDAP.org/license.html>.
18 */
19
20 #include <sys/cdefs.h>
21 __RCSID("$NetBSD: rwm.c,v 1.1.1.6.6.1 2019/08/10 06:17:21 martin Exp $");
22
23 #include "portable.h"
24
25 #ifdef SLAPD_OVER_RWM
26
27 #include <stdio.h>
28
29 #include <ac/string.h>
30
31 #include "slap.h"
32 #include "config.h"
33 #include "lutil.h"
34 #include "rwm.h"
35
36 typedef struct rwm_op_state {
37 ber_tag_t r_tag;
38 struct berval ro_dn;
39 struct berval ro_ndn;
40 struct berval r_dn;
41 struct berval r_ndn;
42 struct berval rx_dn;
43 struct berval rx_ndn;
44 AttributeName *mapped_attrs;
45 OpRequest o_request;
46 } rwm_op_state;
47
48 typedef struct rwm_op_cb {
49 slap_callback cb;
50 rwm_op_state ros;
51 } rwm_op_cb;
52
53 static int
54 rwm_db_destroy( BackendDB *be, ConfigReply *cr );
55
56 static int
57 rwm_send_entry( Operation *op, SlapReply *rs );
58
59 static void
60 rwm_op_rollback( Operation *op, SlapReply *rs, rwm_op_state *ros )
61 {
62 /* in case of successful extended operation cleanup
63 * gets called *after* (ITS#6632); this hack counts
64 * on others to cleanup our o_req_dn/o_req_ndn,
65 * while we cleanup theirs. */
66 if ( ros->r_tag == LDAP_REQ_EXTENDED && rs->sr_err == LDAP_SUCCESS ) {
67 if ( !BER_BVISNULL( &ros->rx_dn ) ) {
68 ch_free( ros->rx_dn.bv_val );
69 }
70 if ( !BER_BVISNULL( &ros->rx_ndn ) ) {
71 ch_free( ros->rx_ndn.bv_val );
72 }
73
74 } else {
75 if ( !BER_BVISNULL( &ros->ro_dn ) ) {
76 op->o_req_dn = ros->ro_dn;
77 }
78 if ( !BER_BVISNULL( &ros->ro_ndn ) ) {
79 op->o_req_ndn = ros->ro_ndn;
80 }
81
82 if ( !BER_BVISNULL( &ros->r_dn )
83 && ros->r_dn.bv_val != ros->ro_dn.bv_val )
84 {
85 assert( ros->r_dn.bv_val != ros->r_ndn.bv_val );
86 ch_free( ros->r_dn.bv_val );
87 }
88
89 if ( !BER_BVISNULL( &ros->r_ndn )
90 && ros->r_ndn.bv_val != ros->ro_ndn.bv_val )
91 {
92 ch_free( ros->r_ndn.bv_val );
93 }
94 }
95
96 BER_BVZERO( &ros->r_dn );
97 BER_BVZERO( &ros->r_ndn );
98 BER_BVZERO( &ros->ro_dn );
99 BER_BVZERO( &ros->ro_ndn );
100 BER_BVZERO( &ros->rx_dn );
101 BER_BVZERO( &ros->rx_ndn );
102
103 switch( ros->r_tag ) {
104 case LDAP_REQ_COMPARE:
105 if ( op->orc_ava->aa_value.bv_val != ros->orc_ava->aa_value.bv_val )
106 op->o_tmpfree( op->orc_ava->aa_value.bv_val, op->o_tmpmemctx );
107 op->orc_ava = ros->orc_ava;
108 break;
109 case LDAP_REQ_MODIFY:
110 slap_mods_free( op->orm_modlist, 1 );
111 op->orm_modlist = ros->orm_modlist;
112 break;
113 case LDAP_REQ_MODRDN:
114 if ( op->orr_newSup != ros->orr_newSup ) {
115 if ( op->orr_newSup ) {
116 ch_free( op->orr_newSup->bv_val );
117 ch_free( op->orr_nnewSup->bv_val );
118 op->o_tmpfree( op->orr_newSup, op->o_tmpmemctx );
119 op->o_tmpfree( op->orr_nnewSup, op->o_tmpmemctx );
120 }
121 op->orr_newSup = ros->orr_newSup;
122 op->orr_nnewSup = ros->orr_nnewSup;
123 }
124 if ( op->orr_newrdn.bv_val != ros->orr_newrdn.bv_val ) {
125 ch_free( op->orr_newrdn.bv_val );
126 ch_free( op->orr_nnewrdn.bv_val );
127 op->orr_newrdn = ros->orr_newrdn;
128 op->orr_nnewrdn = ros->orr_nnewrdn;
129 }
130 break;
131 case LDAP_REQ_SEARCH:
132 op->o_tmpfree( ros->mapped_attrs, op->o_tmpmemctx );
133 op->ors_attrs = ros->ors_attrs;
134 if ( op->ors_filter != ros->ors_filter ) {
135 filter_free_x( op, op->ors_filter, 1 );
136 op->ors_filter = ros->ors_filter;
137 }
138 if ( op->ors_filterstr.bv_val != ros->ors_filterstr.bv_val ) {
139 op->o_tmpfree( op->ors_filterstr.bv_val, op->o_tmpmemctx );
140 op->ors_filterstr = ros->ors_filterstr;
141 }
142 break;
143 case LDAP_REQ_EXTENDED:
144 if ( op->ore_reqdata != ros->ore_reqdata ) {
145 ber_bvfree( op->ore_reqdata );
146 op->ore_reqdata = ros->ore_reqdata;
147 }
148 break;
149 case LDAP_REQ_BIND:
150 if ( rs->sr_err == LDAP_SUCCESS ) {
151 #if 0
152 ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex );
153 /* too late, c_mutex released */
154 Debug( LDAP_DEBUG_ANY, "*** DN: \"%s\" => \"%s\"\n",
155 op->o_conn->c_ndn.bv_val,
156 op->o_req_ndn.bv_val );
157 ber_bvreplace( &op->o_conn->c_ndn,
158 &op->o_req_ndn );
159 ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex );
160 #endif
161 }
162 break;
163 default: break;
164 }
165 }
166
167 static int
168 rwm_op_cleanup( Operation *op, SlapReply *rs )
169 {
170 slap_callback *cb = op->o_callback;
171 rwm_op_state *ros = cb->sc_private;
172
173 if ( rs->sr_type == REP_RESULT || rs->sr_type == REP_EXTENDED ||
174 op->o_abandon || rs->sr_err == SLAPD_ABANDON )
175 {
176 rwm_op_rollback( op, rs, ros );
177
178 op->o_callback = op->o_callback->sc_next;
179 op->o_tmpfree( cb, op->o_tmpmemctx );
180 }
181
182 return SLAP_CB_CONTINUE;
183 }
184
185 static rwm_op_cb *
186 rwm_callback_get( Operation *op )
187 {
188 rwm_op_cb *roc;
189
190 roc = op->o_tmpcalloc( 1, sizeof( struct rwm_op_cb ), op->o_tmpmemctx );
191 roc->cb.sc_cleanup = rwm_op_cleanup;
192 roc->cb.sc_response = NULL;
193 roc->cb.sc_next = op->o_callback;
194 roc->cb.sc_private = &roc->ros;
195 roc->ros.r_tag = op->o_tag;
196 roc->ros.ro_dn = op->o_req_dn;
197 roc->ros.ro_ndn = op->o_req_ndn;
198 BER_BVZERO( &roc->ros.r_dn );
199 BER_BVZERO( &roc->ros.r_ndn );
200 BER_BVZERO( &roc->ros.rx_dn );
201 BER_BVZERO( &roc->ros.rx_ndn );
202 roc->ros.mapped_attrs = NULL;
203 roc->ros.o_request = op->o_request;
204
205 return roc;
206 }
207
208
209 static int
210 rwm_op_dn_massage( Operation *op, SlapReply *rs, void *cookie,
211 rwm_op_state *ros )
212 {
213 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
214 struct ldaprwmap *rwmap =
215 (struct ldaprwmap *)on->on_bi.bi_private;
216
217 struct berval dn = BER_BVNULL,
218 ndn = BER_BVNULL;
219 int rc = 0;
220 dncookie dc;
221
222 /*
223 * Rewrite the dn if needed
224 */
225 dc.rwmap = rwmap;
226 dc.conn = op->o_conn;
227 dc.rs = rs;
228 dc.ctx = (char *)cookie;
229
230 /* NOTE: in those cases where only the ndn is available,
231 * and the caller sets op->o_req_dn = op->o_req_ndn,
232 * only rewrite the op->o_req_ndn and use it as
233 * op->o_req_dn as well */
234 ndn = op->o_req_ndn;
235 if ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val ) {
236 dn = op->o_req_dn;
237 rc = rwm_dn_massage_pretty_normalize( &dc, &op->o_req_dn, &dn, &ndn );
238 } else {
239 rc = rwm_dn_massage_normalize( &dc, &op->o_req_ndn, &ndn );
240 }
241
242 if ( rc != LDAP_SUCCESS ) {
243 return rc;
244 }
245
246 if ( ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val && dn.bv_val == op->o_req_dn.bv_val )
247 || ndn.bv_val == op->o_req_ndn.bv_val )
248 {
249 return LDAP_SUCCESS;
250 }
251
252 if ( op->o_req_dn.bv_val != op->o_req_ndn.bv_val ) {
253 op->o_req_dn = dn;
254 assert( BER_BVISNULL( &ros->r_dn ) );
255 ros->r_dn = dn;
256 } else {
257 op->o_req_dn = ndn;
258 }
259 op->o_req_ndn = ndn;
260 assert( BER_BVISNULL( &ros->r_ndn ) );
261 ros->r_ndn = ndn;
262
263 if ( ros->r_tag == LDAP_REQ_EXTENDED ) {
264 ros->rx_dn = ros->r_dn;
265 ros->rx_ndn = ros->r_ndn;
266 }
267
268 return LDAP_SUCCESS;
269 }
270
271 static int
272 rwm_op_add( Operation *op, SlapReply *rs )
273 {
274 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
275 struct ldaprwmap *rwmap =
276 (struct ldaprwmap *)on->on_bi.bi_private;
277
278 int rc,
279 i;
280 Attribute **ap = NULL;
281 char *olddn = op->o_req_dn.bv_val;
282 int isupdate;
283
284 rwm_op_cb *roc = rwm_callback_get( op );
285
286 rc = rwm_op_dn_massage( op, rs, "addDN", &roc->ros );
287 if ( rc != LDAP_SUCCESS ) {
288 op->o_bd->bd_info = (BackendInfo *)on->on_info;
289 send_ldap_error( op, rs, rc, "addDN massage error" );
290 return -1;
291 }
292
293 if ( olddn != op->o_req_dn.bv_val ) {
294 ber_bvreplace( &op->ora_e->e_name, &op->o_req_dn );
295 ber_bvreplace( &op->ora_e->e_nname, &op->o_req_ndn );
296 }
297
298 /* Count number of attributes in entry */
299 isupdate = be_shadow_update( op );
300 for ( i = 0, ap = &op->oq_add.rs_e->e_attrs; *ap; ) {
301 Attribute *a;
302
303 if ( (*ap)->a_desc == slap_schema.si_ad_objectClass ||
304 (*ap)->a_desc == slap_schema.si_ad_structuralObjectClass )
305 {
306 int j, last;
307
308 last = (*ap)->a_numvals - 1;
309 for ( j = 0; !BER_BVISNULL( &(*ap)->a_vals[ j ] ); j++ ) {
310 struct ldapmapping *mapping = NULL;
311
312 ( void )rwm_mapping( &rwmap->rwm_oc, &(*ap)->a_vals[ j ],
313 &mapping, RWM_MAP );
314 if ( mapping == NULL ) {
315 if ( rwmap->rwm_at.drop_missing ) {
316 /* FIXME: we allow to remove objectClasses as well;
317 * if the resulting entry is inconsistent, that's
318 * the relayed database's business...
319 */
320 ch_free( (*ap)->a_vals[ j ].bv_val );
321 if ( last > j ) {
322 (*ap)->a_vals[ j ] = (*ap)->a_vals[ last ];
323 }
324 BER_BVZERO( &(*ap)->a_vals[ last ] );
325 (*ap)->a_numvals--;
326 last--;
327 j--;
328 }
329
330 } else {
331 ch_free( (*ap)->a_vals[ j ].bv_val );
332 ber_dupbv( &(*ap)->a_vals[ j ], &mapping->m_dst );
333 }
334 }
335
336 } else if ( !isupdate && !get_relax( op ) && (*ap)->a_desc->ad_type->sat_no_user_mod )
337 {
338 goto next_attr;
339
340 } else {
341 struct ldapmapping *mapping = NULL;
342
343 ( void )rwm_mapping( &rwmap->rwm_at, &(*ap)->a_desc->ad_cname,
344 &mapping, RWM_MAP );
345 if ( mapping == NULL ) {
346 if ( rwmap->rwm_at.drop_missing ) {
347 goto cleanup_attr;
348 }
349 }
350
351 if ( (*ap)->a_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
352 || ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
353 {
354 /*
355 * FIXME: rewrite could fail; in this case
356 * the operation should give up, right?
357 */
358 rc = rwm_dnattr_rewrite( op, rs, "addAttrDN",
359 (*ap)->a_vals,
360 (*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
361 if ( rc ) {
362 goto cleanup_attr;
363 }
364
365 } else if ( (*ap)->a_desc == slap_schema.si_ad_ref ) {
366 rc = rwm_referral_rewrite( op, rs, "referralAttrDN",
367 (*ap)->a_vals,
368 (*ap)->a_nvals ? &(*ap)->a_nvals : NULL );
369 if ( rc != LDAP_SUCCESS ) {
370 goto cleanup_attr;
371 }
372 }
373
374 if ( mapping != NULL ) {
375 assert( mapping->m_dst_ad != NULL );
376 (*ap)->a_desc = mapping->m_dst_ad;
377 }
378 }
379
380 next_attr:;
381 ap = &(*ap)->a_next;
382 continue;
383
384 cleanup_attr:;
385 /* FIXME: leaking attribute/values? */
386 a = *ap;
387
388 *ap = (*ap)->a_next;
389 attr_free( a );
390 }
391
392 op->o_callback = &roc->cb;
393
394 return SLAP_CB_CONTINUE;
395 }
396
397 static int
398 rwm_conn_init( BackendDB *be, Connection *conn )
399 {
400 slap_overinst *on = (slap_overinst *) be->bd_info;
401 struct ldaprwmap *rwmap =
402 (struct ldaprwmap *)on->on_bi.bi_private;
403
404 ( void )rewrite_session_init( rwmap->rwm_rw, conn );
405
406 return SLAP_CB_CONTINUE;
407 }
408
409 static int
410 rwm_conn_destroy( BackendDB *be, Connection *conn )
411 {
412 slap_overinst *on = (slap_overinst *) be->bd_info;
413 struct ldaprwmap *rwmap =
414 (struct ldaprwmap *)on->on_bi.bi_private;
415
416 ( void )rewrite_session_delete( rwmap->rwm_rw, conn );
417
418 return SLAP_CB_CONTINUE;
419 }
420
421 static int
422 rwm_op_bind( Operation *op, SlapReply *rs )
423 {
424 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
425 int rc;
426
427 rwm_op_cb *roc = rwm_callback_get( op );
428
429 rc = rwm_op_dn_massage( op, rs, "bindDN", &roc->ros );
430 if ( rc != LDAP_SUCCESS ) {
431 op->o_bd->bd_info = (BackendInfo *)on->on_info;
432 send_ldap_error( op, rs, rc, "bindDN massage error" );
433 return -1;
434 }
435
436 overlay_callback_after_backover( op, &roc->cb, 1 );
437
438 return SLAP_CB_CONTINUE;
439 }
440
441 static int
442 rwm_op_unbind( Operation *op, SlapReply *rs )
443 {
444 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
445 struct ldaprwmap *rwmap =
446 (struct ldaprwmap *)on->on_bi.bi_private;
447
448 rewrite_session_delete( rwmap->rwm_rw, op->o_conn );
449
450 return SLAP_CB_CONTINUE;
451 }
452
453 static int
454 rwm_op_compare( Operation *op, SlapReply *rs )
455 {
456 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
457 struct ldaprwmap *rwmap =
458 (struct ldaprwmap *)on->on_bi.bi_private;
459
460 int rc;
461 struct berval mapped_vals[2] = { BER_BVNULL, BER_BVNULL };
462
463 rwm_op_cb *roc = rwm_callback_get( op );
464
465 rc = rwm_op_dn_massage( op, rs, "compareDN", &roc->ros );
466 if ( rc != LDAP_SUCCESS ) {
467 op->o_bd->bd_info = (BackendInfo *)on->on_info;
468 send_ldap_error( op, rs, rc, "compareDN massage error" );
469 return -1;
470 }
471
472 /* if the attribute is an objectClass, try to remap its value */
473 if ( op->orc_ava->aa_desc == slap_schema.si_ad_objectClass
474 || op->orc_ava->aa_desc == slap_schema.si_ad_structuralObjectClass )
475 {
476 rwm_map( &rwmap->rwm_oc, &op->orc_ava->aa_value,
477 &mapped_vals[0], RWM_MAP );
478 if ( BER_BVISNULL( &mapped_vals[0] ) || BER_BVISEMPTY( &mapped_vals[0] ) )
479 {
480 op->o_bd->bd_info = (BackendInfo *)on->on_info;
481 send_ldap_error( op, rs, LDAP_OTHER, "compare objectClass map error" );
482 return -1;
483
484 } else if ( mapped_vals[0].bv_val != op->orc_ava->aa_value.bv_val ) {
485 ber_dupbv_x( &op->orc_ava->aa_value, &mapped_vals[0],
486 op->o_tmpmemctx );
487 }
488
489 } else {
490 struct ldapmapping *mapping = NULL;
491 AttributeDescription *ad = op->orc_ava->aa_desc;
492
493 ( void )rwm_mapping( &rwmap->rwm_at, &op->orc_ava->aa_desc->ad_cname,
494 &mapping, RWM_MAP );
495 if ( mapping == NULL ) {
496 if ( rwmap->rwm_at.drop_missing ) {
497 op->o_bd->bd_info = (BackendInfo *)on->on_info;
498 send_ldap_error( op, rs, LDAP_OTHER, "compare attributeType map error" );
499 return -1;
500 }
501
502 } else {
503 assert( mapping->m_dst_ad != NULL );
504 ad = mapping->m_dst_ad;
505 }
506
507 if ( op->orc_ava->aa_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
508 || ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
509 {
510 struct berval *mapped_valsp[2];
511
512 mapped_valsp[0] = &mapped_vals[0];
513 mapped_valsp[1] = &mapped_vals[1];
514
515 mapped_vals[0] = op->orc_ava->aa_value;
516
517 rc = rwm_dnattr_rewrite( op, rs, "compareAttrDN", NULL, mapped_valsp );
518
519 if ( rc != LDAP_SUCCESS ) {
520 op->o_bd->bd_info = (BackendInfo *)on->on_info;
521 send_ldap_error( op, rs, rc, "compareAttrDN massage error" );
522 return -1;
523 }
524
525 if ( mapped_vals[ 0 ].bv_val != op->orc_ava->aa_value.bv_val ) {
526 /* NOTE: if we get here, rwm_dnattr_rewrite()
527 * already freed the old value, so now
528 * it's invalid */
529 ber_dupbv_x( &op->orc_ava->aa_value, &mapped_vals[0],
530 op->o_tmpmemctx );
531 ber_memfree_x( mapped_vals[ 0 ].bv_val, NULL );
532 }
533 }
534 op->orc_ava->aa_desc = ad;
535 }
536
537 op->o_callback = &roc->cb;
538
539 return SLAP_CB_CONTINUE;
540 }
541
542 static int
543 rwm_op_delete( Operation *op, SlapReply *rs )
544 {
545 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
546 int rc;
547
548 rwm_op_cb *roc = rwm_callback_get( op );
549
550 rc = rwm_op_dn_massage( op, rs, "deleteDN", &roc->ros );
551 if ( rc != LDAP_SUCCESS ) {
552 op->o_bd->bd_info = (BackendInfo *)on->on_info;
553 send_ldap_error( op, rs, rc, "deleteDN massage error" );
554 return -1;
555 }
556
557 op->o_callback = &roc->cb;
558
559 return SLAP_CB_CONTINUE;
560 }
561
562 static int
563 rwm_op_modify( Operation *op, SlapReply *rs )
564 {
565 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
566 struct ldaprwmap *rwmap =
567 (struct ldaprwmap *)on->on_bi.bi_private;
568
569 int isupdate;
570 Modifications **mlp;
571 int rc;
572
573 rwm_op_cb *roc = rwm_callback_get( op );
574
575 rc = rwm_op_dn_massage( op, rs, "modifyDN", &roc->ros );
576 if ( rc != LDAP_SUCCESS ) {
577 op->o_bd->bd_info = (BackendInfo *)on->on_info;
578 send_ldap_error( op, rs, rc, "modifyDN massage error" );
579 return -1;
580 }
581
582 isupdate = be_shadow_update( op );
583 for ( mlp = &op->orm_modlist; *mlp; ) {
584 int is_oc = 0;
585 Modifications *ml = *mlp;
586 struct ldapmapping *mapping = NULL;
587
588 /* ml points to a temporary mod until needs duplication */
589 if ( ml->sml_desc == slap_schema.si_ad_objectClass
590 || ml->sml_desc == slap_schema.si_ad_structuralObjectClass )
591 {
592 is_oc = 1;
593
594 } else if ( !isupdate && !get_relax( op ) && ml->sml_desc->ad_type->sat_no_user_mod )
595 {
596 ml = ch_malloc( sizeof( Modifications ) );
597 *ml = **mlp;
598 if ( (*mlp)->sml_values ) {
599 ber_bvarray_dup_x( &ml->sml_values, (*mlp)->sml_values, NULL );
600 if ( (*mlp)->sml_nvalues ) {
601 ber_bvarray_dup_x( &ml->sml_nvalues, (*mlp)->sml_nvalues, NULL );
602 }
603 }
604 *mlp = ml;
605 goto next_mod;
606
607 } else {
608 int drop_missing;
609
610 drop_missing = rwm_mapping( &rwmap->rwm_at,
611 &ml->sml_desc->ad_cname,
612 &mapping, RWM_MAP );
613 if ( drop_missing || ( mapping != NULL && BER_BVISNULL( &mapping->m_dst ) ) )
614 {
615 goto skip_mod;
616 }
617 }
618
619 /* duplicate the modlist */
620 ml = ch_malloc( sizeof( Modifications ));
621 *ml = **mlp;
622 *mlp = ml;
623
624 if ( ml->sml_values != NULL ) {
625 int i, num;
626 struct berval *bva;
627
628 for ( num = 0; !BER_BVISNULL( &ml->sml_values[ num ] ); num++ )
629 /* count values */ ;
630
631 bva = ch_malloc( (num+1) * sizeof( struct berval ));
632 for (i=0; i<num; i++)
633 ber_dupbv( &bva[i], &ml->sml_values[i] );
634 BER_BVZERO( &bva[i] );
635 ml->sml_values = bva;
636
637 if ( ml->sml_nvalues ) {
638 bva = ch_malloc( (num+1) * sizeof( struct berval ));
639 for (i=0; i<num; i++)
640 ber_dupbv( &bva[i], &ml->sml_nvalues[i] );
641 BER_BVZERO( &bva[i] );
642 ml->sml_nvalues = bva;
643 }
644
645 if ( is_oc ) {
646 int last, j;
647
648 last = num-1;
649
650 for ( j = 0; !BER_BVISNULL( &ml->sml_values[ j ] ); j++ ) {
651 struct ldapmapping *oc_mapping = NULL;
652
653 ( void )rwm_mapping( &rwmap->rwm_oc, &ml->sml_values[ j ],
654 &oc_mapping, RWM_MAP );
655 if ( oc_mapping == NULL ) {
656 if ( rwmap->rwm_at.drop_missing ) {
657 /* FIXME: we allow to remove objectClasses as well;
658 * if the resulting entry is inconsistent, that's
659 * the relayed database's business...
660 */
661 if ( last > j ) {
662 ch_free( ml->sml_values[ j ].bv_val );
663 ml->sml_values[ j ] = ml->sml_values[ last ];
664 }
665 BER_BVZERO( &ml->sml_values[ last ] );
666 last--;
667 j--;
668 }
669
670 } else {
671 ch_free( ml->sml_values[ j ].bv_val );
672 ber_dupbv( &ml->sml_values[ j ], &oc_mapping->m_dst );
673 }
674 }
675
676 } else {
677 if ( ml->sml_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
678 || ( mapping != NULL && mapping->m_dst_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
679 {
680 rc = rwm_dnattr_rewrite( op, rs, "modifyAttrDN",
681 ml->sml_values,
682 ml->sml_nvalues ? &ml->sml_nvalues : NULL );
683
684 } else if ( ml->sml_desc == slap_schema.si_ad_ref ) {
685 rc = rwm_referral_rewrite( op, rs,
686 "referralAttrDN",
687 ml->sml_values,
688 ml->sml_nvalues ? &ml->sml_nvalues : NULL );
689 if ( rc != LDAP_SUCCESS ) {
690 goto cleanup_mod;
691 }
692 }
693
694 if ( rc != LDAP_SUCCESS ) {
695 goto cleanup_mod;
696 }
697 }
698 }
699
700 next_mod:;
701 if ( mapping != NULL ) {
702 /* use new attribute description */
703 assert( mapping->m_dst_ad != NULL );
704 ml->sml_desc = mapping->m_dst_ad;
705 }
706
707 mlp = &ml->sml_next;
708 continue;
709
710 skip_mod:;
711 *mlp = (*mlp)->sml_next;
712 continue;
713
714 cleanup_mod:;
715 ml = *mlp;
716 *mlp = (*mlp)->sml_next;
717 slap_mod_free( &ml->sml_mod, 0 );
718 free( ml );
719 }
720
721 op->o_callback = &roc->cb;
722
723 return SLAP_CB_CONTINUE;
724 }
725
726 static int
727 rwm_op_modrdn( Operation *op, SlapReply *rs )
728 {
729 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
730 struct ldaprwmap *rwmap =
731 (struct ldaprwmap *)on->on_bi.bi_private;
732
733 int rc;
734 dncookie dc;
735
736 rwm_op_cb *roc = rwm_callback_get( op );
737
738 if ( op->orr_newSup ) {
739 struct berval nnewSup = BER_BVNULL;
740 struct berval newSup = BER_BVNULL;
741
742 /*
743 * Rewrite the new superior, if defined and required
744 */
745 dc.rwmap = rwmap;
746 dc.conn = op->o_conn;
747 dc.rs = rs;
748 dc.ctx = "newSuperiorDN";
749 newSup = *op->orr_newSup;
750 nnewSup = *op->orr_nnewSup;
751 rc = rwm_dn_massage_pretty_normalize( &dc, op->orr_newSup, &newSup, &nnewSup );
752 if ( rc != LDAP_SUCCESS ) {
753 op->o_bd->bd_info = (BackendInfo *)on->on_info;
754 send_ldap_error( op, rs, rc, "newSuperiorDN massage error" );
755 return -1;
756 }
757
758 if ( op->orr_newSup->bv_val != newSup.bv_val ) {
759 op->orr_newSup = op->o_tmpalloc( sizeof( struct berval ),
760 op->o_tmpmemctx );
761 op->orr_nnewSup = op->o_tmpalloc( sizeof( struct berval ),
762 op->o_tmpmemctx );
763 *op->orr_newSup = newSup;
764 *op->orr_nnewSup = nnewSup;
765 }
766 }
767
768 /*
769 * Rewrite the newRDN, if needed
770 */
771 {
772 struct berval newrdn = BER_BVNULL;
773 struct berval nnewrdn = BER_BVNULL;
774
775 dc.rwmap = rwmap;
776 dc.conn = op->o_conn;
777 dc.rs = rs;
778 dc.ctx = "newRDN";
779 newrdn = op->orr_newrdn;
780 nnewrdn = op->orr_nnewrdn;
781 rc = rwm_dn_massage_pretty_normalize( &dc, &op->orr_newrdn, &newrdn, &nnewrdn );
782 if ( rc != LDAP_SUCCESS ) {
783 op->o_bd->bd_info = (BackendInfo *)on->on_info;
784 send_ldap_error( op, rs, rc, "newRDN massage error" );
785 goto err;
786 }
787
788 if ( op->orr_newrdn.bv_val != newrdn.bv_val ) {
789 op->orr_newrdn = newrdn;
790 op->orr_nnewrdn = nnewrdn;
791 }
792 }
793
794 /*
795 * Rewrite the dn, if needed
796 */
797 rc = rwm_op_dn_massage( op, rs, "renameDN", &roc->ros );
798 if ( rc != LDAP_SUCCESS ) {
799 op->o_bd->bd_info = (BackendInfo *)on->on_info;
800 send_ldap_error( op, rs, rc, "renameDN massage error" );
801 goto err;
802 }
803
804 op->o_callback = &roc->cb;
805
806 rc = SLAP_CB_CONTINUE;
807
808 if ( 0 ) {
809 err:;
810 if ( op->orr_newSup != roc->ros.orr_newSup ) {
811 ch_free( op->orr_newSup->bv_val );
812 ch_free( op->orr_nnewSup->bv_val );
813 op->o_tmpfree( op->orr_newSup, op->o_tmpmemctx );
814 op->o_tmpfree( op->orr_nnewSup, op->o_tmpmemctx );
815 op->orr_newSup = roc->ros.orr_newSup;
816 op->orr_nnewSup = roc->ros.orr_nnewSup;
817 }
818
819 if ( op->orr_newrdn.bv_val != roc->ros.orr_newrdn.bv_val ) {
820 ch_free( op->orr_newrdn.bv_val );
821 ch_free( op->orr_nnewrdn.bv_val );
822 op->orr_newrdn = roc->ros.orr_newrdn;
823 op->orr_nnewrdn = roc->ros.orr_nnewrdn;
824 }
825 }
826
827 return rc;
828 }
829
830
831 static int
832 rwm_swap_attrs( Operation *op, SlapReply *rs )
833 {
834 slap_callback *cb = op->o_callback;
835 rwm_op_state *ros = cb->sc_private;
836
837 rs->sr_attrs = ros->ors_attrs;
838
839 /* other overlays might have touched op->ors_attrs,
840 * so we restore the original version here, otherwise
841 * attribute-mapping might fail */
842 op->ors_attrs = ros->mapped_attrs;
843
844 return SLAP_CB_CONTINUE;
845 }
846
847 /*
848 * NOTE: this implementation of get/release entry is probably far from
849 * optimal. The rationale consists in intercepting the request directed
850 * to the underlying database, in order to rewrite/remap the request,
851 * perform it using the modified data, duplicate the resulting entry
852 * and finally free it when release is called.
853 * This implies that subsequent overlays are not called, as the request
854 * is directly shunted to the underlying database.
855 */
856 static int
857 rwm_entry_release_rw( Operation *op, Entry *e, int rw )
858 {
859 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
860
861 /* can't be ours */
862 if ( ((BackendInfo *)on->on_info->oi_orig)->bi_entry_get_rw == NULL ) {
863 return SLAP_CB_CONTINUE;
864 }
865
866 /* just free entry if (probably) ours */
867 if ( e->e_private == NULL && BER_BVISNULL( &e->e_bv ) ) {
868 entry_free( e );
869 return LDAP_SUCCESS;
870 }
871
872 return SLAP_CB_CONTINUE;
873 }
874
875 static int
876 rwm_entry_get_rw( Operation *op, struct berval *ndn,
877 ObjectClass *oc, AttributeDescription *at, int rw, Entry **ep )
878 {
879 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
880 int rc;
881 BackendDB db;
882 Operation op2;
883 SlapReply rs = { REP_SEARCH };
884
885 rwm_op_state ros = { 0 };
886 struct berval mndn = BER_BVNULL;
887
888 if ( ((BackendInfo *)on->on_info->oi_orig)->bi_entry_get_rw == NULL ) {
889 return SLAP_CB_CONTINUE;
890 }
891
892 /* massage DN */
893 op2.o_tag = LDAP_REQ_SEARCH;
894 op2 = *op;
895 op2.o_req_dn = *ndn;
896 op2.o_req_ndn = *ndn;
897 rc = rwm_op_dn_massage( &op2, &rs, "searchDN", &ros );
898 if ( rc != LDAP_SUCCESS ) {
899 return LDAP_OTHER;
900 }
901
902 mndn = BER_BVISNULL( &ros.r_ndn ) ? *ndn : ros.r_ndn;
903
904 /* map attribute & objectClass */
905 if ( at != NULL ) {
906 }
907
908 if ( oc != NULL ) {
909 }
910
911 /* fetch entry */
912 db = *op->o_bd;
913 op2.o_bd = &db;
914 op2.o_bd->bd_info = (BackendInfo *)on->on_info->oi_orig;
915 op2.ors_attrs = slap_anlist_all_attributes;
916 rc = op2.o_bd->bd_info->bi_entry_get_rw( &op2, &mndn, oc, at, rw, ep );
917 if ( rc == LDAP_SUCCESS && *ep != NULL ) {
918 /* we assume be_entry_release() needs to be called */
919 rs.sr_flags = REP_ENTRY_MUSTRELEASE;
920 rs.sr_entry = *ep;
921
922 /* duplicate & release */
923 op2.o_bd->bd_info = (BackendInfo *)on;
924 rc = rwm_send_entry( &op2, &rs );
925 RS_ASSERT( rs.sr_flags & REP_ENTRY_MUSTFLUSH );
926 if ( rc == SLAP_CB_CONTINUE ) {
927 *ep = rs.sr_entry;
928 rc = LDAP_SUCCESS;
929 } else {
930 assert( rc != LDAP_SUCCESS && rs.sr_entry == *ep );
931 *ep = NULL;
932 op2.o_bd->bd_info = (BackendInfo *)on->on_info;
933 be_entry_release_r( &op2, rs.sr_entry );
934 op2.o_bd->bd_info = (BackendInfo *)on;
935 }
936 }
937
938 if ( !BER_BVISNULL( &ros.r_ndn) && ros.r_ndn.bv_val != ndn->bv_val ) {
939 op->o_tmpfree( ros.r_ndn.bv_val, op->o_tmpmemctx );
940 }
941
942 return rc;
943 }
944
945 static int
946 rwm_op_search( Operation *op, SlapReply *rs )
947 {
948 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
949 struct ldaprwmap *rwmap =
950 (struct ldaprwmap *)on->on_bi.bi_private;
951
952 int rc;
953 dncookie dc;
954
955 struct berval fstr = BER_BVNULL;
956 Filter *f = NULL;
957
958 AttributeName *an = NULL;
959
960 char *text = NULL;
961
962 rwm_op_cb *roc = rwm_callback_get( op );
963
964 rc = rewrite_session_var_set( rwmap->rwm_rw, op->o_conn,
965 "searchFilter", op->ors_filterstr.bv_val );
966 if ( rc == LDAP_SUCCESS )
967 rc = rwm_op_dn_massage( op, rs, "searchDN", &roc->ros );
968 if ( rc != LDAP_SUCCESS ) {
969 text = "searchDN massage error";
970 goto error_return;
971 }
972
973 /*
974 * Rewrite the dn if needed
975 */
976 dc.rwmap = rwmap;
977 dc.conn = op->o_conn;
978 dc.rs = rs;
979 dc.ctx = "searchFilterAttrDN";
980
981 rc = rwm_filter_map_rewrite( op, &dc, op->ors_filter, &fstr );
982 if ( rc != LDAP_SUCCESS ) {
983 text = "searchFilter/searchFilterAttrDN massage error";
984 goto error_return;
985 }
986
987 f = str2filter_x( op, fstr.bv_val );
988
989 if ( f == NULL ) {
990 text = "massaged filter parse error";
991 goto error_return;
992 }
993
994 op->ors_filter = f;
995 op->ors_filterstr = fstr;
996
997 rc = rwm_map_attrnames( op, &rwmap->rwm_at, &rwmap->rwm_oc,
998 op->ors_attrs, &an, RWM_MAP );
999 if ( rc != LDAP_SUCCESS ) {
1000 text = "attribute list mapping error";
1001 goto error_return;
1002 }
1003
1004 op->ors_attrs = an;
1005 /* store the mapped Attributes for later usage, in
1006 * the case that other overlays change op->ors_attrs */
1007 roc->ros.mapped_attrs = an;
1008 roc->cb.sc_response = rwm_swap_attrs;
1009
1010 op->o_callback = &roc->cb;
1011
1012 return SLAP_CB_CONTINUE;
1013
1014 error_return:;
1015 if ( an != NULL ) {
1016 ch_free( an );
1017 }
1018
1019 if ( f != NULL ) {
1020 filter_free_x( op, f, 1 );
1021 }
1022
1023 if ( !BER_BVISNULL( &fstr ) ) {
1024 op->o_tmpfree( fstr.bv_val, op->o_tmpmemctx );
1025 }
1026
1027 rwm_op_rollback( op, rs, &roc->ros );
1028 op->oq_search = roc->ros.oq_search;
1029 op->o_tmpfree( roc, op->o_tmpmemctx );
1030
1031 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1032 send_ldap_error( op, rs, rc, text );
1033
1034 return -1;
1035
1036 }
1037
1038 static int
1039 rwm_exop_passwd( Operation *op, SlapReply *rs )
1040 {
1041 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
1042 int rc;
1043 rwm_op_cb *roc;
1044
1045 struct berval id = BER_BVNULL,
1046 pwold = BER_BVNULL,
1047 pwnew = BER_BVNULL;
1048 BerElement *ber = NULL;
1049
1050 if ( !BER_BVISNULL( &op->o_req_ndn ) ) {
1051 return LDAP_SUCCESS;
1052 }
1053
1054 if ( !SLAP_ISGLOBALOVERLAY( op->o_bd ) ) {
1055 rs->sr_err = LDAP_OTHER;
1056 return rs->sr_err;
1057 }
1058
1059 rs->sr_err = slap_passwd_parse( op->ore_reqdata, &id,
1060 &pwold, &pwnew, &rs->sr_text );
1061 if ( rs->sr_err != LDAP_SUCCESS ) {
1062 return rs->sr_err;
1063 }
1064
1065 if ( !BER_BVISNULL( &id ) ) {
1066 char idNul = id.bv_val[id.bv_len];
1067 id.bv_val[id.bv_len] = '\0';
1068 rs->sr_err = dnPrettyNormal( NULL, &id, &op->o_req_dn,
1069 &op->o_req_ndn, op->o_tmpmemctx );
1070 id.bv_val[id.bv_len] = idNul;
1071 if ( rs->sr_err != LDAP_SUCCESS ) {
1072 rs->sr_text = "Invalid DN";
1073 return rs->sr_err;
1074 }
1075
1076 } else {
1077 ber_dupbv_x( &op->o_req_dn, &op->o_dn, op->o_tmpmemctx );
1078 ber_dupbv_x( &op->o_req_ndn, &op->o_ndn, op->o_tmpmemctx );
1079 }
1080
1081 roc = rwm_callback_get( op );
1082
1083 rc = rwm_op_dn_massage( op, rs, "extendedDN", &roc->ros );
1084 if ( rc != LDAP_SUCCESS ) {
1085 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1086 send_ldap_error( op, rs, rc, "extendedDN massage error" );
1087 return -1;
1088 }
1089
1090 ber = ber_alloc_t( LBER_USE_DER );
1091 if ( !ber ) {
1092 rs->sr_err = LDAP_OTHER;
1093 rs->sr_text = "No memory";
1094 return rs->sr_err;
1095 }
1096 ber_printf( ber, "{" );
1097 if ( !BER_BVISNULL( &id )) {
1098 ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_ID,
1099 &op->o_req_dn );
1100 }
1101 if ( !BER_BVISNULL( &pwold )) {
1102 ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_OLD, &pwold );
1103 }
1104 if ( !BER_BVISNULL( &pwnew )) {
1105 ber_printf( ber, "tO", LDAP_TAG_EXOP_MODIFY_PASSWD_NEW, &pwnew );
1106 }
1107 ber_printf( ber, "N}" );
1108 ber_flatten( ber, &op->ore_reqdata );
1109 ber_free( ber, 1 );
1110
1111 op->o_callback = &roc->cb;
1112
1113 return SLAP_CB_CONTINUE;
1114 }
1115
1116 static struct exop {
1117 struct berval oid;
1118 BI_op_extended *extended;
1119 } exop_table[] = {
1120 { BER_BVC(LDAP_EXOP_MODIFY_PASSWD), rwm_exop_passwd },
1121 { BER_BVNULL, NULL }
1122 };
1123
1124 static int
1125 rwm_extended( Operation *op, SlapReply *rs )
1126 {
1127 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
1128 int rc;
1129 rwm_op_cb *roc;
1130
1131 int i;
1132
1133 for ( i = 0; exop_table[i].extended != NULL; i++ ) {
1134 if ( bvmatch( &exop_table[i].oid, &op->oq_extended.rs_reqoid ) )
1135 {
1136 rc = exop_table[i].extended( op, rs );
1137 switch ( rc ) {
1138 case LDAP_SUCCESS:
1139 break;
1140
1141 case SLAP_CB_CONTINUE:
1142 case SLAPD_ABANDON:
1143 return rc;
1144
1145 default:
1146 send_ldap_result( op, rs );
1147 return rc;
1148 }
1149 break;
1150 }
1151 }
1152
1153 roc = rwm_callback_get( op );
1154
1155 rc = rwm_op_dn_massage( op, rs, "extendedDN", &roc->ros );
1156 if ( rc != LDAP_SUCCESS ) {
1157 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1158 send_ldap_error( op, rs, rc, "extendedDN massage error" );
1159 return -1;
1160 }
1161
1162 /* TODO: rewrite/map extended data ? ... */
1163 op->o_callback = &roc->cb;
1164
1165 return SLAP_CB_CONTINUE;
1166 }
1167
1168 static void
1169 rwm_matched( Operation *op, SlapReply *rs )
1170 {
1171 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
1172 struct ldaprwmap *rwmap =
1173 (struct ldaprwmap *)on->on_bi.bi_private;
1174
1175 struct berval dn, mdn;
1176 dncookie dc;
1177 int rc;
1178
1179 if ( rs->sr_matched == NULL ) {
1180 return;
1181 }
1182
1183 dc.rwmap = rwmap;
1184 dc.conn = op->o_conn;
1185 dc.rs = rs;
1186 dc.ctx = "matchedDN";
1187 ber_str2bv( rs->sr_matched, 0, 0, &dn );
1188 mdn = dn;
1189 rc = rwm_dn_massage_pretty( &dc, &dn, &mdn );
1190 if ( rc != LDAP_SUCCESS ) {
1191 rs->sr_err = rc;
1192 rs->sr_text = "Rewrite error";
1193
1194 } else if ( mdn.bv_val != dn.bv_val ) {
1195 if ( rs->sr_flags & REP_MATCHED_MUSTBEFREED ) {
1196 ch_free( (void *)rs->sr_matched );
1197
1198 } else {
1199 rs->sr_flags |= REP_MATCHED_MUSTBEFREED;
1200 }
1201 rs->sr_matched = mdn.bv_val;
1202 }
1203 }
1204
1205 static int
1206 rwm_attrs( Operation *op, SlapReply *rs, Attribute** a_first, int stripEntryDN )
1207 {
1208 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
1209 struct ldaprwmap *rwmap =
1210 (struct ldaprwmap *)on->on_bi.bi_private;
1211
1212 dncookie dc;
1213 int rc;
1214 Attribute **ap;
1215 int isupdate;
1216 int check_duplicate_attrs = 0;
1217
1218 /*
1219 * Rewrite the dn attrs, if needed
1220 */
1221 dc.rwmap = rwmap;
1222 dc.conn = op->o_conn;
1223 dc.rs = NULL;
1224
1225 /* FIXME: the entries are in the remote mapping form;
1226 * so we need to select those attributes we are willing
1227 * to return, and remap them accordingly */
1228
1229 /* FIXME: in principle, one could map an attribute
1230 * on top of another, which already exists.
1231 * As such, in the end there might exist more than
1232 * one instance of an attribute.
1233 * We should at least check if this occurs, and issue
1234 * an error (because multiple instances of attrs in
1235 * response are not valid), or merge the values (what
1236 * about duplicate values?) */
1237 isupdate = be_shadow_update( op );
1238 for ( ap = a_first; *ap; ) {
1239 struct ldapmapping *mapping = NULL;
1240 int drop_missing;
1241 int last = -1;
1242 Attribute *a;
1243
1244 if ( ( rwmap->rwm_flags & RWM_F_DROP_UNREQUESTED_ATTRS ) &&
1245 op->ors_attrs != NULL &&
1246 !SLAP_USERATTRS( rs->sr_attr_flags ) &&
1247 !ad_inlist( (*ap)->a_desc, op->ors_attrs ) )
1248 {
1249 goto cleanup_attr;
1250 }
1251
1252 drop_missing = rwm_mapping( &rwmap->rwm_at,
1253 &(*ap)->a_desc->ad_cname, &mapping, RWM_REMAP );
1254 if ( drop_missing || ( mapping != NULL && BER_BVISEMPTY( &mapping->m_dst ) ) )
1255 {
1256 goto cleanup_attr;
1257 }
1258 if ( mapping != NULL ) {
1259 assert( mapping->m_dst_ad != NULL );
1260
1261 /* try to normalize mapped Attributes if the original
1262 * AttributeType was not normalized */
1263 if ( (!(*ap)->a_desc->ad_type->sat_equality ||
1264 !(*ap)->a_desc->ad_type->sat_equality->smr_normalize) &&
1265 mapping->m_dst_ad->ad_type->sat_equality &&
1266 mapping->m_dst_ad->ad_type->sat_equality->smr_normalize )
1267 {
1268 if ((rwmap->rwm_flags & RWM_F_NORMALIZE_MAPPED_ATTRS))
1269 {
1270 int i = 0;
1271
1272 last = (*ap)->a_numvals;
1273 if ( last )
1274 {
1275 (*ap)->a_nvals = ch_malloc( (last+1) * sizeof(struct berval) );
1276
1277 for ( i = 0; !BER_BVISNULL( &(*ap)->a_vals[i]); i++ ) {
1278 int rc;
1279 /*
1280 * check that each value is valid per syntax
1281 * and pretty if appropriate
1282 */
1283 rc = mapping->m_dst_ad->ad_type->sat_equality->smr_normalize(
1284 SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
1285 mapping->m_dst_ad->ad_type->sat_syntax,
1286 mapping->m_dst_ad->ad_type->sat_equality,
1287 &(*ap)->a_vals[i], &(*ap)->a_nvals[i],
1288 NULL );
1289
1290 if ( rc != LDAP_SUCCESS ) {
1291 /* FIXME: this is wrong, putting a non-normalized value
1292 * into nvals. But when a proxy sends us bogus data,
1293 * we still need to give it to the client, even if it
1294 * violates the syntax. I.e., we don't want to silently
1295 * drop things and trigger an apparent data loss.
1296 */
1297 ber_dupbv( &(*ap)->a_nvals[i], &(*ap)->a_vals[i] );
1298 }
1299 }
1300 BER_BVZERO( &(*ap)->a_nvals[i] );
1301 }
1302
1303 } else {
1304 assert( (*ap)->a_nvals == (*ap)->a_vals );
1305 (*ap)->a_nvals = NULL;
1306 ber_bvarray_dup_x( &(*ap)->a_nvals, (*ap)->a_vals, NULL );
1307 }
1308 }
1309
1310 /* rewrite the attribute description */
1311 (*ap)->a_desc = mapping->m_dst_ad;
1312
1313 /* will need to check for duplicate attrs */
1314 check_duplicate_attrs++;
1315 }
1316
1317 if ( (*ap)->a_desc == slap_schema.si_ad_entryDN ) {
1318 if ( stripEntryDN ) {
1319 /* will be generated by frontend */
1320 goto cleanup_attr;
1321 }
1322
1323 } else if ( !isupdate
1324 && !get_relax( op )
1325 && (*ap)->a_desc->ad_type->sat_no_user_mod
1326 && (*ap)->a_desc->ad_type != slap_schema.si_at_undefined )
1327 {
1328 goto next_attr;
1329 }
1330
1331 if ( last == -1 ) { /* not yet counted */
1332 last = (*ap)->a_numvals;
1333 }
1334
1335 if ( last == 0 ) {
1336 /* empty? leave it in place because of attrsonly and vlv */
1337 goto next_attr;
1338 }
1339 last--;
1340
1341 if ( (*ap)->a_desc == slap_schema.si_ad_objectClass
1342 || (*ap)->a_desc == slap_schema.si_ad_structuralObjectClass )
1343 {
1344 struct berval *bv;
1345
1346 for ( bv = (*ap)->a_vals; !BER_BVISNULL( bv ); bv++ ) {
1347 struct berval mapped;
1348
1349 rwm_map( &rwmap->rwm_oc, &bv[0], &mapped, RWM_REMAP );
1350 if ( BER_BVISNULL( &mapped ) || BER_BVISEMPTY( &mapped ) ) {
1351 remove_oc:;
1352 ch_free( bv[0].bv_val );
1353 BER_BVZERO( &bv[0] );
1354 if ( &(*ap)->a_vals[last] > &bv[0] ) {
1355 bv[0] = (*ap)->a_vals[last];
1356 BER_BVZERO( &(*ap)->a_vals[last] );
1357 }
1358 last--;
1359 bv--;
1360
1361 } else if ( mapped.bv_val != bv[0].bv_val
1362 && ber_bvstrcasecmp( &mapped, &bv[0] ) != 0 )
1363 {
1364 int i;
1365
1366 for ( i = 0; !BER_BVISNULL( &(*ap)->a_vals[ i ] ); i++ ) {
1367 if ( &(*ap)->a_vals[ i ] == bv ) {
1368 continue;
1369 }
1370
1371 if ( ber_bvstrcasecmp( &mapped, &(*ap)->a_vals[ i ] ) == 0 ) {
1372 break;
1373 }
1374 }
1375
1376 if ( !BER_BVISNULL( &(*ap)->a_vals[ i ] ) ) {
1377 goto remove_oc;
1378 }
1379
1380 /*
1381 * FIXME: after LBER_FREEing
1382 * the value is replaced by
1383 * ch_alloc'ed memory
1384 */
1385 ber_bvreplace( &bv[0], &mapped );
1386
1387 /* FIXME: will need to check
1388 * if the structuralObjectClass
1389 * changed */
1390 }
1391 }
1392
1393 /*
1394 * It is necessary to try to rewrite attributes with
1395 * dn syntax because they might be used in ACLs as
1396 * members of groups; since ACLs are applied to the
1397 * rewritten stuff, no dn-based subject clause could
1398 * be used at the ldap backend side (see
1399 * http://www.OpenLDAP.org/faq/data/cache/452.html)
1400 * The problem can be overcome by moving the dn-based
1401 * ACLs to the target directory server, and letting
1402 * everything pass thru the ldap backend. */
1403 /* FIXME: handle distinguishedName-like syntaxes, like
1404 * nameAndOptionalUID */
1405 } else if ( (*ap)->a_desc->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName
1406 || ( mapping != NULL && mapping->m_src_ad->ad_type->sat_syntax == slap_schema.si_syn_distinguishedName ) )
1407 {
1408 dc.ctx = "searchAttrDN";
1409 rc = rwm_dnattr_result_rewrite( &dc, (*ap)->a_vals, (*ap)->a_nvals );
1410 if ( rc != LDAP_SUCCESS ) {
1411 goto cleanup_attr;
1412 }
1413
1414 } else if ( (*ap)->a_desc == slap_schema.si_ad_ref ) {
1415 dc.ctx = "searchAttrDN";
1416 rc = rwm_referral_result_rewrite( &dc, (*ap)->a_vals );
1417 if ( rc != LDAP_SUCCESS ) {
1418 goto cleanup_attr;
1419 }
1420 }
1421
1422
1423 next_attr:;
1424 ap = &(*ap)->a_next;
1425 continue;
1426
1427 cleanup_attr:;
1428 a = *ap;
1429 *ap = (*ap)->a_next;
1430
1431 attr_free( a );
1432 }
1433
1434 /* only check if some mapping occurred */
1435 if ( check_duplicate_attrs ) {
1436 for ( ap = a_first; *ap != NULL; ap = &(*ap)->a_next ) {
1437 Attribute **tap;
1438
1439 for ( tap = &(*ap)->a_next; *tap != NULL; ) {
1440 if ( (*tap)->a_desc == (*ap)->a_desc ) {
1441 Entry e = { 0 };
1442 Modification mod = { 0 };
1443 const char *text = NULL;
1444 char textbuf[ SLAP_TEXT_BUFLEN ];
1445 Attribute *next = (*tap)->a_next;
1446
1447 BER_BVSTR( &e.e_name, "" );
1448 BER_BVSTR( &e.e_nname, "" );
1449 e.e_attrs = *ap;
1450 mod.sm_op = LDAP_MOD_ADD;
1451 mod.sm_desc = (*ap)->a_desc;
1452 mod.sm_type = mod.sm_desc->ad_cname;
1453 mod.sm_numvals = (*tap)->a_numvals;
1454 mod.sm_values = (*tap)->a_vals;
1455 if ( (*tap)->a_nvals != (*tap)->a_vals ) {
1456 mod.sm_nvalues = (*tap)->a_nvals;
1457 }
1458
1459 (void)modify_add_values( &e, &mod,
1460 /* permissive */ 1,
1461 &text, textbuf, sizeof( textbuf ) );
1462
1463 /* should not insert new attrs! */
1464 assert( e.e_attrs == *ap );
1465
1466 attr_free( *tap );
1467 *tap = next;
1468
1469 } else {
1470 tap = &(*tap)->a_next;
1471 }
1472 }
1473 }
1474 }
1475
1476 return 0;
1477 }
1478
1479 /* Should return SLAP_CB_CONTINUE or failure, never LDAP_SUCCESS. */
1480 static int
1481 rwm_send_entry( Operation *op, SlapReply *rs )
1482 {
1483 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
1484 struct ldaprwmap *rwmap =
1485 (struct ldaprwmap *)on->on_bi.bi_private;
1486
1487 Entry *e = NULL;
1488 struct berval dn = BER_BVNULL,
1489 ndn = BER_BVNULL;
1490 dncookie dc;
1491 int rc;
1492
1493 assert( rs->sr_entry != NULL );
1494
1495 /*
1496 * Rewrite the dn of the result, if needed
1497 */
1498 dc.rwmap = rwmap;
1499 dc.conn = op->o_conn;
1500 dc.rs = NULL;
1501 dc.ctx = "searchEntryDN";
1502
1503 e = rs->sr_entry;
1504 if ( !( rs->sr_flags & REP_ENTRY_MODIFIABLE ) ) {
1505 /* FIXME: all we need to duplicate are:
1506 * - dn
1507 * - ndn
1508 * - attributes that are requested
1509 * - no values if attrsonly is set
1510 */
1511 e = entry_dup( e );
1512 if ( e == NULL ) {
1513 rc = LDAP_NO_MEMORY;
1514 goto fail;
1515 }
1516 } else if ( rs->sr_flags & REP_ENTRY_MUSTRELEASE ) {
1517 /* ITS#6423: REP_ENTRY_MUSTRELEASE incompatible
1518 * with REP_ENTRY_MODIFIABLE */
1519 RS_ASSERT( 0 );
1520 rc = 1;
1521 goto fail;
1522 }
1523
1524 /*
1525 * Note: this may fail if the target host(s) schema differs
1526 * from the one known to the meta, and a DN with unknown
1527 * attributes is returned.
1528 */
1529 dn = e->e_name;
1530 ndn = e->e_nname;
1531 rc = rwm_dn_massage_pretty_normalize( &dc, &e->e_name, &dn, &ndn );
1532 if ( rc != LDAP_SUCCESS ) {
1533 rc = 1;
1534 goto fail;
1535 }
1536
1537 if ( e->e_name.bv_val != dn.bv_val ) {
1538 ch_free( e->e_name.bv_val );
1539 ch_free( e->e_nname.bv_val );
1540
1541 e->e_name = dn;
1542 e->e_nname = ndn;
1543 }
1544
1545 /* TODO: map entry attribute types, objectclasses
1546 * and dn-valued attribute values */
1547
1548 /* FIXME: the entries are in the remote mapping form;
1549 * so we need to select those attributes we are willing
1550 * to return, and remap them accordingly */
1551 (void)rwm_attrs( op, rs, &e->e_attrs, 1 );
1552
1553 if ( e != rs->sr_entry ) {
1554 /* Reimplementing rs_replace_entry(), I suppose to
1555 * bypass our own dubious rwm_entry_release_rw() */
1556 if ( rs->sr_flags & REP_ENTRY_MUSTRELEASE ) {
1557 rs->sr_flags ^= REP_ENTRY_MUSTRELEASE;
1558 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1559 be_entry_release_r( op, rs->sr_entry );
1560 op->o_bd->bd_info = (BackendInfo *)on;
1561 } else if ( rs->sr_flags & REP_ENTRY_MUSTBEFREED ) {
1562 entry_free( rs->sr_entry );
1563 }
1564 rs->sr_entry = e;
1565 rs->sr_flags |= REP_ENTRY_MODIFIABLE | REP_ENTRY_MUSTBEFREED;
1566 }
1567
1568 return SLAP_CB_CONTINUE;
1569
1570 fail:;
1571 if ( e != NULL && e != rs->sr_entry ) {
1572 if ( e->e_name.bv_val == dn.bv_val ) {
1573 BER_BVZERO( &e->e_name );
1574 }
1575
1576 if ( e->e_nname.bv_val == ndn.bv_val ) {
1577 BER_BVZERO( &e->e_nname );
1578 }
1579
1580 entry_free( e );
1581 }
1582
1583 if ( !BER_BVISNULL( &dn ) ) {
1584 ch_free( dn.bv_val );
1585 }
1586
1587 if ( !BER_BVISNULL( &ndn ) ) {
1588 ch_free( ndn.bv_val );
1589 }
1590
1591 return rc;
1592 }
1593
1594 static int
1595 rwm_operational( Operation *op, SlapReply *rs )
1596 {
1597 /* FIXME: the entries are in the remote mapping form;
1598 * so we need to select those attributes we are willing
1599 * to return, and remap them accordingly */
1600 if ( rs->sr_operational_attrs ) {
1601 rwm_attrs( op, rs, &rs->sr_operational_attrs, 1 );
1602 }
1603
1604 return SLAP_CB_CONTINUE;
1605 }
1606
1607 #if 0
1608 /* don't use this; it cannot be reverted, and leaves op->o_req_dn
1609 * rewritten for subsequent operations; fine for plain suffixmassage,
1610 * but destroys everything else */
1611 static int
1612 rwm_chk_referrals( Operation *op, SlapReply *rs )
1613 {
1614 slap_overinst *on = (slap_overinst *) op->o_bd->bd_info;
1615 int rc;
1616
1617 rc = rwm_op_dn_massage( op, rs, "referralCheckDN" );
1618 if ( rc != LDAP_SUCCESS ) {
1619 op->o_bd->bd_info = (BackendInfo *)on->on_info;
1620 send_ldap_error( op, rs, rc, "referralCheckDN massage error" );
1621 return -1;
1622 }
1623
1624 return SLAP_CB_CONTINUE;
1625 }
1626 #endif
1627
1628 static int
1629 rwm_rw_config(
1630 BackendDB *be,
1631 const char *fname,
1632 int lineno,
1633 int argc,
1634 char **argv )
1635 {
1636 slap_overinst *on = (slap_overinst *) be->bd_info;
1637 struct ldaprwmap *rwmap =
1638 (struct ldaprwmap *)on->on_bi.bi_private;
1639
1640 return rewrite_parse( rwmap->rwm_rw,
1641 fname, lineno, argc, argv );
1642
1643 return 0;
1644 }
1645
1646 static int
1647 rwm_suffixmassage_config(
1648 BackendDB *be,
1649 const char *fname,
1650 int lineno,
1651 int argc,
1652 char **argv )
1653 {
1654 slap_overinst *on = (slap_overinst *) be->bd_info;
1655 struct ldaprwmap *rwmap =
1656 (struct ldaprwmap *)on->on_bi.bi_private;
1657
1658 struct berval bvnc, nvnc, pvnc, brnc, nrnc, prnc;
1659 int massaged;
1660 int rc;
1661
1662 /*
1663 * syntax:
1664 *
1665 * suffixmassage [<suffix>] <massaged suffix>
1666 *
1667 * the [<suffix>] field must be defined as a valid suffix
1668 * for the current database;
1669 * the <massaged suffix> shouldn't have already been
1670 * defined as a valid suffix for the current server
1671 */
1672 if ( argc == 2 ) {
1673 if ( be->be_suffix == NULL ) {
1674 Debug( LDAP_DEBUG_ANY, "%s: line %d: "
1675 " \"suffixMassage [<suffix>]"
1676 " <massaged suffix>\" without "
1677 "<suffix> part requires database "
1678 "suffix be defined first.\n",
1679 fname, lineno, 0 );
1680 return 1;
1681 }
1682 bvnc = be->be_suffix[ 0 ];
1683 massaged = 1;
1684
1685 } else if ( argc == 3 ) {
1686 ber_str2bv( argv[ 1 ], 0, 0, &bvnc );
1687 massaged = 2;
1688
1689 } else {
1690 Debug( LDAP_DEBUG_ANY, "%s: line %d: syntax is"
1691 " \"suffixMassage [<suffix>]"
1692 " <massaged suffix>\"\n",
1693 fname, lineno, 0 );
1694 return 1;
1695 }
1696
1697 if ( dnPrettyNormal( NULL, &bvnc, &pvnc, &nvnc, NULL ) != LDAP_SUCCESS ) {
1698 Debug( LDAP_DEBUG_ANY, "%s: line %d: suffix DN %s is invalid\n",
1699 fname, lineno, bvnc.bv_val );
1700 return 1;
1701 }
1702
1703 ber_str2bv( argv[ massaged ], 0, 0, &brnc );
1704 if ( dnPrettyNormal( NULL, &brnc, &prnc, &nrnc, NULL ) != LDAP_SUCCESS ) {
1705 Debug( LDAP_DEBUG_ANY, "%s: line %d: suffix DN %s is invalid\n",
1706 fname, lineno, brnc.bv_val );
1707 free( nvnc.bv_val );
1708 free( pvnc.bv_val );
1709 return 1;
1710 }
1711
1712 /*
1713 * The suffix massaging is emulated
1714 * by means of the rewrite capabilities
1715 */
1716 rc = rwm_suffix_massage_config( rwmap->rwm_rw,
1717 &pvnc, &nvnc, &prnc, &nrnc );
1718 free( nvnc.bv_val );
1719 free( pvnc.bv_val );
1720 free( nrnc.bv_val );
1721 free( prnc.bv_val );
1722
1723 return rc;
1724 }
1725
1726 static int
1727 rwm_m_config(
1728 BackendDB *be,
1729 const char *fname,
1730 int lineno,
1731 int argc,
1732 char **argv )
1733 {
1734 slap_overinst *on = (slap_overinst *) be->bd_info;
1735 struct ldaprwmap *rwmap =
1736 (struct ldaprwmap *)on->on_bi.bi_private;
1737
1738 /* objectclass/attribute mapping */
1739 return rwm_map_config( &rwmap->rwm_oc,
1740 &rwmap->rwm_at,
1741 fname, lineno, argc, argv );
1742 }
1743
1744 static int
1745 rwm_response( Operation *op, SlapReply *rs )
1746 {
1747 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
1748 struct ldaprwmap *rwmap =
1749 (struct ldaprwmap *)on->on_bi.bi_private;
1750
1751 int rc;
1752
1753 if ( op->o_tag == LDAP_REQ_SEARCH && rs->sr_type == REP_SEARCH ) {
1754 return rwm_send_entry( op, rs );
1755 }
1756
1757 switch( op->o_tag ) {
1758 case LDAP_REQ_SEARCH:
1759 case LDAP_REQ_BIND:
1760 case LDAP_REQ_ADD:
1761 case LDAP_REQ_DELETE:
1762 case LDAP_REQ_MODRDN:
1763 case LDAP_REQ_MODIFY:
1764 case LDAP_REQ_COMPARE:
1765 case LDAP_REQ_EXTENDED:
1766 if ( rs->sr_ref ) {
1767 dncookie dc;
1768
1769 /*
1770 * Rewrite the dn of the referrals, if needed
1771 */
1772 dc.rwmap = rwmap;
1773 dc.conn = op->o_conn;
1774 dc.rs = NULL;
1775 dc.ctx = "referralDN";
1776 rc = rwm_referral_result_rewrite( &dc, rs->sr_ref );
1777 /* FIXME: impossible, so far */
1778 if ( rc != LDAP_SUCCESS ) {
1779 rs->sr_err = rc;
1780 break;
1781 }
1782 }
1783
1784 rwm_matched( op, rs );
1785 break;
1786 }
1787
1788 return SLAP_CB_CONTINUE;
1789 }
1790
1791 static int
1792 rwm_db_config(
1793 BackendDB *be,
1794 const char *fname,
1795 int lineno,
1796 int argc,
1797 char **argv )
1798 {
1799 slap_overinst *on = (slap_overinst *) be->bd_info;
1800 struct ldaprwmap *rwmap =
1801 (struct ldaprwmap *)on->on_bi.bi_private;
1802
1803 int rc = 0;
1804 char *argv0 = NULL;
1805
1806 if ( strncasecmp( argv[ 0 ], "rwm-", STRLENOF( "rwm-" ) ) == 0 ) {
1807 argv0 = argv[ 0 ];
1808 argv[ 0 ] = &argv0[ STRLENOF( "rwm-" ) ];
1809 }
1810
1811 if ( strncasecmp( argv[0], "rewrite", STRLENOF("rewrite") ) == 0 ) {
1812 rc = rwm_rw_config( be, fname, lineno, argc, argv );
1813
1814 } else if ( strcasecmp( argv[0], "map" ) == 0 ) {
1815 rc = rwm_m_config( be, fname, lineno, argc, argv );
1816
1817 } else if ( strcasecmp( argv[0], "suffixmassage" ) == 0 ) {
1818 rc = rwm_suffixmassage_config( be, fname, lineno, argc, argv );
1819
1820 } else if ( strcasecmp( argv[0], "t-f-support" ) == 0 ) {
1821 if ( argc != 2 ) {
1822 Debug( LDAP_DEBUG_ANY,
1823 "%s: line %d: \"t-f-support {no|yes|discover}\" needs 1 argument.\n",
1824 fname, lineno, 0 );
1825 return( 1 );
1826 }
1827
1828 if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
1829 rwmap->rwm_flags &= ~(RWM_F_SUPPORT_T_F_MASK2);
1830
1831 } else if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
1832 rwmap->rwm_flags |= RWM_F_SUPPORT_T_F;
1833
1834 /* TODO: not implemented yet */
1835 } else if ( strcasecmp( argv[ 1 ], "discover" ) == 0 ) {
1836 Debug( LDAP_DEBUG_ANY,
1837 "%s: line %d: \"discover\" not supported yet "
1838 "in \"t-f-support {no|yes|discover}\".\n",
1839 fname, lineno, 0 );
1840 return( 1 );
1841 #if 0
1842 rwmap->rwm_flags |= RWM_F_SUPPORT_T_F_DISCOVER;
1843 #endif
1844
1845 } else {
1846 Debug( LDAP_DEBUG_ANY,
1847 "%s: line %d: unknown value \"%s\" for \"t-f-support {no|yes|discover}\".\n",
1848 fname, lineno, argv[ 1 ] );
1849 return 1;
1850 }
1851
1852 } else if ( strcasecmp( argv[0], "normalize-mapped-attrs" ) == 0 ) {
1853 if ( argc !=2 ) {
1854 Debug( LDAP_DEBUG_ANY,
1855 "%s: line %d: \"normalize-mapped-attrs {no|yes}\" needs 1 argument.\n",
1856 fname, lineno, 0 );
1857 return( 1 );
1858 }
1859
1860 if ( strcasecmp( argv[ 1 ], "no" ) == 0 ) {
1861 rwmap->rwm_flags &= ~(RWM_F_NORMALIZE_MAPPED_ATTRS);
1862
1863 } else if ( strcasecmp( argv[ 1 ], "yes" ) == 0 ) {
1864 rwmap->rwm_flags |= RWM_F_NORMALIZE_MAPPED_ATTRS;
1865 }
1866
1867 } else {
1868 rc = SLAP_CONF_UNKNOWN;
1869 }
1870
1871 if ( argv0 ) {
1872 argv[ 0 ] = argv0;
1873 }
1874
1875 return rc;
1876 }
1877
1878 /*
1879 * dynamic configuration...
1880 */
1881
1882 enum {
1883 /* rewrite */
1884 RWM_CF_REWRITE = 1,
1885
1886 /* map */
1887 RWM_CF_MAP,
1888 RWM_CF_T_F_SUPPORT,
1889 RWM_CF_NORMALIZE_MAPPED,
1890 RWM_CF_DROP_UNREQUESTED,
1891
1892 RWM_CF_LAST
1893 };
1894
1895 static slap_verbmasks t_f_mode[] = {
1896 { BER_BVC( "true" ), RWM_F_SUPPORT_T_F },
1897 { BER_BVC( "yes" ), RWM_F_SUPPORT_T_F },
1898 { BER_BVC( "discover" ), RWM_F_SUPPORT_T_F_DISCOVER },
1899 { BER_BVC( "false" ), RWM_F_NONE },
1900 { BER_BVC( "no" ), RWM_F_NONE },
1901 { BER_BVNULL, 0 }
1902 };
1903
1904 static ConfigDriver rwm_cf_gen;
1905
1906 static ConfigTable rwmcfg[] = {
1907 { "rwm-rewrite", "rewrite",
1908 2, 0, STRLENOF("rwm-rewrite"),
1909 ARG_MAGIC|RWM_CF_REWRITE, rwm_cf_gen,
1910 "( OLcfgOvAt:16.1 NAME 'olcRwmRewrite' "
1911 "DESC 'Rewrites strings' "
1912 "EQUALITY caseIgnoreMatch "
1913 "SYNTAX OMsDirectoryString "
1914 "X-ORDERED 'VALUES' )",
1915 NULL, NULL },
1916
1917 { "rwm-suffixmassage", "[virtual]> <real",
1918 2, 3, 0, ARG_MAGIC|RWM_CF_REWRITE, rwm_cf_gen,
1919 NULL, NULL, NULL },
1920
1921 { "rwm-t-f-support", "true|false|discover",
1922 2, 2, 0, ARG_MAGIC|RWM_CF_T_F_SUPPORT, rwm_cf_gen,
1923 "( OLcfgOvAt:16.2 NAME 'olcRwmTFSupport' "
1924 "DESC 'Absolute filters support' "
1925 "SYNTAX OMsDirectoryString "
1926 "SINGLE-VALUE )",
1927 NULL, NULL },
1928
1929 { "rwm-map", "{objectClass|attribute}",
1930 2, 4, 0, ARG_MAGIC|RWM_CF_MAP, rwm_cf_gen,
1931 "( OLcfgOvAt:16.3 NAME 'olcRwmMap' "
1932 "DESC 'maps attributes/objectClasses' "
1933 "EQUALITY caseIgnoreMatch "
1934 "SYNTAX OMsDirectoryString "
1935 "X-ORDERED 'VALUES' )",
1936 NULL, NULL },
1937
1938 { "rwm-normalize-mapped-attrs", "true|false",
1939 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|RWM_CF_NORMALIZE_MAPPED, rwm_cf_gen,
1940 "( OLcfgOvAt:16.4 NAME 'olcRwmNormalizeMapped' "
1941 "DESC 'Normalize mapped attributes/objectClasses' "
1942 "SYNTAX OMsBoolean "
1943 "SINGLE-VALUE )",
1944 NULL, NULL },
1945
1946 { "rwm-drop-unrequested-attrs", "true|false",
1947 2, 2, 0, ARG_MAGIC|ARG_ON_OFF|RWM_CF_DROP_UNREQUESTED, rwm_cf_gen,
1948 "( OLcfgOvAt:16.5 NAME 'olcRwmDropUnrequested' "
1949 "DESC 'Drop unrequested attributes' "
1950 "SYNTAX OMsBoolean "
1951 "SINGLE-VALUE )",
1952 NULL, NULL },
1953
1954 { NULL, NULL, 0, 0, 0, ARG_IGNORED }
1955 };
1956
1957 static ConfigOCs rwmocs[] = {
1958 { "( OLcfgOvOc:16.1 "
1959 "NAME 'olcRwmConfig' "
1960 "DESC 'Rewrite/remap configuration' "
1961 "SUP olcOverlayConfig "
1962 "MAY ( "
1963 "olcRwmRewrite $ "
1964 "olcRwmTFSupport $ "
1965 "olcRwmMap $ "
1966 "olcRwmNormalizeMapped $ "
1967 "olcRwmDropUnrequested"
1968 ") )",
1969 Cft_Overlay, rwmcfg, NULL, NULL },
1970 { NULL, 0, NULL }
1971 };
1972
1973 static void
1974 slap_bv_x_ordered_unparse( BerVarray in, BerVarray *out )
1975 {
1976 int i;
1977 BerVarray bva = NULL;
1978 char ibuf[32], *ptr;
1979 struct berval idx;
1980
1981 assert( in != NULL );
1982
1983 for ( i = 0; !BER_BVISNULL( &in[i] ); i++ )
1984 /* count'em */ ;
1985
1986 if ( i == 0 ) {
1987 return;
1988 }
1989
1990 idx.bv_val = ibuf;
1991
1992 bva = ch_malloc( ( i + 1 ) * sizeof(struct berval) );
1993 BER_BVZERO( &bva[ 0 ] );
1994
1995 for ( i = 0; !BER_BVISNULL( &in[i] ); i++ ) {
1996 idx.bv_len = snprintf( idx.bv_val, sizeof( ibuf ), "{%d}", i );
1997 if ( idx.bv_len >= sizeof( ibuf ) ) {
1998 ber_bvarray_free( bva );
1999 return;
2000 }
2001
2002 bva[i].bv_len = idx.bv_len + in[i].bv_len;
2003 bva[i].bv_val = ch_malloc( bva[i].bv_len + 1 );
2004 ptr = lutil_strcopy( bva[i].bv_val, ibuf );
2005 ptr = lutil_strcopy( ptr, in[i].bv_val );
2006 *ptr = '\0';
2007 BER_BVZERO( &bva[ i + 1 ] );
2008 }
2009
2010 *out = bva;
2011 }
2012
2013 static int
2014 rwm_bva_add(
2015 BerVarray *bva,
2016 int idx,
2017 char **argv )
2018 {
2019 char *line;
2020 struct berval bv;
2021
2022 line = ldap_charray2str( argv, "\" \"" );
2023 if ( line != NULL ) {
2024 int len = strlen( argv[ 0 ] );
2025
2026 ber_str2bv( line, 0, 0, &bv );
2027 AC_MEMCPY( &bv.bv_val[ len ], &bv.bv_val[ len + 1 ],
2028 bv.bv_len - ( len + 1 ) );
2029 bv.bv_val[ bv.bv_len - 1 ] = '"';
2030
2031 if ( idx == -1 ) {
2032 ber_bvarray_add( bva, &bv );
2033
2034 } else {
2035 (*bva)[ idx ] = bv;
2036 }
2037
2038 return 0;
2039 }
2040
2041 return -1;
2042 }
2043
2044 static int
2045 rwm_bva_rewrite_add(
2046 struct ldaprwmap *rwmap,
2047 int idx,
2048 char **argv )
2049 {
2050 return rwm_bva_add( &rwmap->rwm_bva_rewrite, idx, argv );
2051 }
2052
2053 #ifdef unused
2054 static int
2055 rwm_bva_map_add(
2056 struct ldaprwmap *rwmap,
2057 int idx,
2058 char **argv )
2059 {
2060 return rwm_bva_add( &rwmap->rwm_bva_map, idx, argv );
2061 }
2062 #endif /* unused */
2063
2064 static int
2065 rwm_info_init( struct rewrite_info ** rwm_rw )
2066 {
2067 char *rargv[ 3 ];
2068
2069 *rwm_rw = rewrite_info_init( REWRITE_MODE_USE_DEFAULT );
2070 if ( *rwm_rw == NULL ) {
2071 return -1;
2072 }
2073
2074 /* this rewriteContext by default must be null;
2075 * rules can be added if required */
2076 rargv[ 0 ] = "rewriteContext";
2077 rargv[ 1 ] = "searchFilter";
2078 rargv[ 2 ] = NULL;
2079 rewrite_parse( *rwm_rw, "<suffix massage>", 1, 2, rargv );
2080
2081 rargv[ 0 ] = "rewriteContext";
2082 rargv[ 1 ] = "default";
2083 rargv[ 2 ] = NULL;
2084 rewrite_parse( *rwm_rw, "<suffix massage>", 2, 2, rargv );
2085
2086 return 0;
2087 }
2088
2089 static int
2090 rwm_cf_gen( ConfigArgs *c )
2091 {
2092 slap_overinst *on = (slap_overinst *)c->bi;
2093 struct ldaprwmap *rwmap =
2094 (struct ldaprwmap *)on->on_bi.bi_private;
2095
2096 BackendDB db;
2097 char *argv0;
2098 int idx0 = 0;
2099 int rc = 0;
2100
2101 db = *c->be;
2102 db.bd_info = c->bi;
2103
2104 if ( c->op == SLAP_CONFIG_EMIT ) {
2105 struct berval bv = BER_BVNULL;
2106
2107 switch ( c->type ) {
2108 case RWM_CF_REWRITE:
2109 if ( rwmap->rwm_bva_rewrite == NULL ) {
2110 rc = 1;
2111
2112 } else {
2113 slap_bv_x_ordered_unparse( rwmap->rwm_bva_rewrite, &c->rvalue_vals );
2114 if ( !c->rvalue_vals ) {
2115 rc = 1;
2116 }
2117 }
2118 break;
2119
2120 case RWM_CF_T_F_SUPPORT:
2121 enum_to_verb( t_f_mode, (rwmap->rwm_flags & RWM_F_SUPPORT_T_F_MASK2), &bv );
2122 if ( BER_BVISNULL( &bv ) ) {
2123 /* there's something wrong... */
2124 assert( 0 );
2125 rc = 1;
2126
2127 } else {
2128 value_add_one( &c->rvalue_vals, &bv );
2129 }
2130 break;
2131
2132 case RWM_CF_MAP:
2133 if ( rwmap->rwm_bva_map == NULL ) {
2134 rc = 1;
2135
2136 } else {
2137 slap_bv_x_ordered_unparse( rwmap->rwm_bva_map, &c->rvalue_vals );
2138 if ( !c->rvalue_vals ) {
2139 rc = 1;
2140 }
2141 }
2142 break;
2143
2144 case RWM_CF_NORMALIZE_MAPPED:
2145 c->value_int = ( rwmap->rwm_flags & RWM_F_NORMALIZE_MAPPED_ATTRS );
2146 break;
2147
2148 case RWM_CF_DROP_UNREQUESTED:
2149 c->value_int = ( rwmap->rwm_flags & RWM_F_DROP_UNREQUESTED_ATTRS );
2150 break;
2151
2152 default:
2153 assert( 0 );
2154 rc = 1;
2155 }
2156
2157 return rc;
2158
2159 } else if ( c->op == LDAP_MOD_DELETE ) {
2160 switch ( c->type ) {
2161 case RWM_CF_REWRITE:
2162 if ( c->valx >= 0 ) {
2163 int i;
2164
2165 for ( i = 0; !BER_BVISNULL( &rwmap->rwm_bva_rewrite[ i ] ); i++ )
2166 /* count'em */ ;
2167
2168 if ( c->valx >= i ) {
2169 rc = 1;
2170 break;
2171 }
2172
2173 ber_memfree( rwmap->rwm_bva_rewrite[ c->valx ].bv_val );
2174 for ( i = c->valx; !BER_BVISNULL( &rwmap->rwm_bva_rewrite[ i + 1 ] ); i++ )
2175 {
2176 rwmap->rwm_bva_rewrite[ i ] = rwmap->rwm_bva_rewrite[ i + 1 ];
2177 }
2178 BER_BVZERO( &rwmap->rwm_bva_rewrite[ i ] );
2179
2180 rewrite_info_delete( &rwmap->rwm_rw );
2181 assert( rwmap->rwm_rw == NULL );
2182
2183 rc = rwm_info_init( &rwmap->rwm_rw );
2184
2185 for ( i = 0; !BER_BVISNULL( &rwmap->rwm_bva_rewrite[ i ] ); i++ )
2186 {
2187 ConfigArgs ca = { 0 };
2188
2189 ca.line = rwmap->rwm_bva_rewrite[ i ].bv_val;
2190 ca.argc = 0;
2191 init_config_argv( &ca );
2192 config_parse_ldif( &ca );
2193
2194 argv0 = ca.argv[ 0 ];
2195 ca.argv[ 0 ] += STRLENOF( "rwm-" );
2196
2197 if ( strcasecmp( ca.argv[ 0 ], "suffixmassage" ) == 0 ) {
2198 rc = rwm_suffixmassage_config( &db, c->fname, c->lineno,
2199 ca.argc, ca.argv );
2200
2201 } else {
2202 rc = rwm_rw_config( &db, c->fname, c->lineno,
2203 ca.argc, ca.argv );
2204 }
2205
2206 ca.argv[ 0 ] = argv0;
2207
2208 ch_free( ca.tline );
2209 ch_free( ca.argv );
2210
2211 assert( rc == 0 );
2212 }
2213
2214 } else if ( rwmap->rwm_rw != NULL ) {
2215 rewrite_info_delete( &rwmap->rwm_rw );
2216 assert( rwmap->rwm_rw == NULL );
2217
2218 ber_bvarray_free( rwmap->rwm_bva_rewrite );
2219 rwmap->rwm_bva_rewrite = NULL;
2220
2221 rc = rwm_info_init( &rwmap->rwm_rw );
2222 }
2223 break;
2224
2225 case RWM_CF_T_F_SUPPORT:
2226 rwmap->rwm_flags &= ~RWM_F_SUPPORT_T_F_MASK2;
2227 break;
2228
2229 case RWM_CF_MAP:
2230 if ( c->valx >= 0 ) {
2231 struct ldapmap rwm_oc = rwmap->rwm_oc;
2232 struct ldapmap rwm_at = rwmap->rwm_at;
2233 char *argv[5];
2234 int cnt = 0;
2235
2236 if ( rwmap->rwm_bva_map ) {
2237 for ( ; !BER_BVISNULL( &rwmap->rwm_bva_map[ cnt ] ); cnt++ )
2238 /* count */ ;
2239 }
2240
2241 if ( c->valx >= cnt ) {
2242 rc = 1;
2243 break;
2244 }
2245
2246 memset( &rwmap->rwm_oc, 0, sizeof( rwmap->rwm_oc ) );
2247 memset( &rwmap->rwm_at, 0, sizeof( rwmap->rwm_at ) );
2248
2249 /* re-parse all mappings except the one
2250 * that needs to be eliminated */
2251 argv[0] = "map";
2252 for ( cnt = 0; !BER_BVISNULL( &rwmap->rwm_bva_map[ cnt ] ); cnt++ ) {
2253 ConfigArgs ca = { 0 };
2254
2255 if ( cnt == c->valx ) {
2256 continue;
2257 }
2258
2259 ca.line = rwmap->rwm_bva_map[ cnt ].bv_val;
2260 ca.argc = 0;
2261 init_config_argv( &ca );
2262 config_parse_ldif( &ca );
2263
2264 argv[1] = ca.argv[0];
2265 argv[2] = ca.argv[1];
2266 argv[3] = ca.argv[2];
2267 argv[4] = ca.argv[3];
2268
2269 rc = rwm_m_config( &db, c->fname, c->lineno, ca.argc + 1, argv );
2270
2271 ch_free( ca.tline );
2272 ch_free( ca.argv );
2273
2274 /* in case of failure, restore
2275 * the existing mapping */
2276 if ( rc ) {
2277 avl_free( rwmap->rwm_oc.remap, rwm_mapping_dst_free );
2278 avl_free( rwmap->rwm_oc.map, rwm_mapping_free );
2279 avl_free( rwmap->rwm_at.remap, rwm_mapping_dst_free );
2280 avl_free( rwmap->rwm_at.map, rwm_mapping_free );
2281 rwmap->rwm_oc = rwm_oc;
2282 rwmap->rwm_at = rwm_at;
2283 break;
2284 }
2285 }
2286
2287 /* in case of success, destroy the old mapping
2288 * and eliminate the deleted one */
2289 if ( rc == 0 ) {
2290 avl_free( rwm_oc.remap, rwm_mapping_dst_free );
2291 avl_free( rwm_oc.map, rwm_mapping_free );
2292 avl_free( rwm_at.remap, rwm_mapping_dst_free );
2293 avl_free( rwm_at.map, rwm_mapping_free );
2294
2295 ber_memfree( rwmap->rwm_bva_map[ c->valx ].bv_val );
2296 for ( cnt = c->valx; !BER_BVISNULL( &rwmap->rwm_bva_map[ cnt ] ); cnt++ ) {
2297 rwmap->rwm_bva_map[ cnt ] = rwmap->rwm_bva_map[ cnt + 1 ];
2298 }
2299 }
2300
2301 } else {
2302 avl_free( rwmap->rwm_oc.remap, rwm_mapping_dst_free );
2303 avl_free( rwmap->rwm_oc.map, rwm_mapping_free );
2304 avl_free( rwmap->rwm_at.remap, rwm_mapping_dst_free );
2305 avl_free( rwmap->rwm_at.map, rwm_mapping_free );
2306
2307 rwmap->rwm_oc.remap = NULL;
2308 rwmap->rwm_oc.map = NULL;
2309 rwmap->rwm_at.remap = NULL;
2310 rwmap->rwm_at.map = NULL;
2311
2312 ber_bvarray_free( rwmap->rwm_bva_map );
2313 rwmap->rwm_bva_map = NULL;
2314 }
2315 break;
2316
2317 case RWM_CF_NORMALIZE_MAPPED:
2318 rwmap->rwm_flags &= ~RWM_F_NORMALIZE_MAPPED_ATTRS;
2319 break;
2320
2321 case RWM_CF_DROP_UNREQUESTED:
2322 rwmap->rwm_flags &= ~RWM_F_DROP_UNREQUESTED_ATTRS;
2323 break;
2324
2325 default:
2326 return 1;
2327 }
2328 return rc;
2329 }
2330
2331 if ( strncasecmp( c->argv[ 0 ], "olcRwm", STRLENOF( "olcRwm" ) ) == 0 ) {
2332 idx0 = 1;
2333 }
2334
2335 switch ( c->type ) {
2336 case RWM_CF_REWRITE:
2337 if ( c->valx >= 0 ) {
2338 struct rewrite_info *rwm_rw = rwmap->rwm_rw;
2339 int i, last;
2340
2341 for ( last = 0; rwmap->rwm_bva_rewrite && !BER_BVISNULL( &rwmap->rwm_bva_rewrite[ last ] ); last++ )
2342 /* count'em */ ;
2343
2344 if ( c->valx > last ) {
2345 c->valx = last;
2346 }
2347
2348 rwmap->rwm_rw = NULL;
2349 rc = rwm_info_init( &rwmap->rwm_rw );
2350
2351 for ( i = 0; i < c->valx; i++ ) {
2352 ConfigArgs ca = { 0 };
2353
2354 ca.line = rwmap->rwm_bva_rewrite[ i ].bv_val;
2355 ca.argc = 0;
2356 init_config_argv( &ca );
2357 config_parse_ldif( &ca );
2358
2359 argv0 = ca.argv[ 0 ];
2360 ca.argv[ 0 ] += STRLENOF( "rwm-" );
2361
2362 if ( strcasecmp( ca.argv[ 0 ], "suffixmassage" ) == 0 ) {
2363 rc = rwm_suffixmassage_config( &db, c->fname, c->lineno,
2364 ca.argc, ca.argv );
2365
2366 } else {
2367 rc = rwm_rw_config( &db, c->fname, c->lineno,
2368 ca.argc, ca.argv );
2369 }
2370
2371 ca.argv[ 0 ] = argv0;
2372
2373 ch_free( ca.tline );
2374 ch_free( ca.argv );
2375
2376 assert( rc == 0 );
2377 }
2378
2379 argv0 = c->argv[ idx0 ];
2380 if ( strncasecmp( argv0, "rwm-", STRLENOF( "rwm-" ) ) != 0 ) {
2381 return 1;
2382 }
2383 c->argv[ idx0 ] += STRLENOF( "rwm-" );
2384 if ( strcasecmp( c->argv[ idx0 ], "suffixmassage" ) == 0 ) {
2385 rc = rwm_suffixmassage_config( &db, c->fname, c->lineno,
2386 c->argc - idx0, &c->argv[ idx0 ] );
2387
2388 } else {
2389 rc = rwm_rw_config( &db, c->fname, c->lineno,
2390 c->argc - idx0, &c->argv[ idx0 ] );
2391 }
2392 c->argv[ idx0 ] = argv0;
2393 if ( rc != 0 ) {
2394 rewrite_info_delete( &rwmap->rwm_rw );
2395 assert( rwmap->rwm_rw == NULL );
2396
2397 rwmap->rwm_rw = rwm_rw;
2398 return 1;
2399 }
2400
2401 for ( i = c->valx; rwmap->rwm_bva_rewrite && !BER_BVISNULL( &rwmap->rwm_bva_rewrite[ i ] ); i++ )
2402 {
2403 ConfigArgs ca = { 0 };
2404
2405 ca.line = rwmap->rwm_bva_rewrite[ i ].bv_val;
2406 ca.argc = 0;
2407 init_config_argv( &ca );
2408 config_parse_ldif( &ca );
2409
2410 argv0 = ca.argv[ 0 ];
2411 ca.argv[ 0 ] += STRLENOF( "rwm-" );
2412
2413 if ( strcasecmp( ca.argv[ 0 ], "suffixmassage" ) == 0 ) {
2414 rc = rwm_suffixmassage_config( &db, c->fname, c->lineno,
2415 ca.argc, ca.argv );
2416
2417 } else {
2418 rc = rwm_rw_config( &db, c->fname, c->lineno,
2419 ca.argc, ca.argv );
2420 }
2421
2422 ca.argv[ 0 ] = argv0;
2423
2424 ch_free( ca.tline );
2425 ch_free( ca.argv );
2426
2427 assert( rc == 0 );
2428 }
2429
2430 rwmap->rwm_bva_rewrite = ch_realloc( rwmap->rwm_bva_rewrite,
2431 ( last + 2 )*sizeof( struct berval ) );
2432 BER_BVZERO( &rwmap->rwm_bva_rewrite[last+1] );
2433
2434 for ( i = last - 1; i >= c->valx; i-- )
2435 {
2436 rwmap->rwm_bva_rewrite[ i + 1 ] = rwmap->rwm_bva_rewrite[ i ];
2437 }
2438
2439 rwm_bva_rewrite_add( rwmap, c->valx, &c->argv[ idx0 ] );
2440
2441 rewrite_info_delete( &rwm_rw );
2442 assert( rwm_rw == NULL );
2443
2444 break;
2445 }
2446
2447 argv0 = c->argv[ idx0 ];
2448 if ( strncasecmp( argv0, "rwm-", STRLENOF( "rwm-" ) ) != 0 ) {
2449 return 1;
2450 }
2451 c->argv[ idx0 ] += STRLENOF( "rwm-" );
2452 if ( strcasecmp( c->argv[ idx0 ], "suffixmassage" ) == 0 ) {
2453 rc = rwm_suffixmassage_config( &db, c->fname, c->lineno,
2454 c->argc - idx0, &c->argv[ idx0 ] );
2455
2456 } else {
2457 rc = rwm_rw_config( &db, c->fname, c->lineno,
2458 c->argc - idx0, &c->argv[ idx0 ] );
2459 }
2460 c->argv[ idx0 ] = argv0;
2461 if ( rc ) {
2462 return 1;
2463
2464 } else {
2465 rwm_bva_rewrite_add( rwmap, -1, &c->argv[ idx0 ] );
2466 }
2467 break;
2468
2469 case RWM_CF_T_F_SUPPORT:
2470 rc = verb_to_mask( c->argv[ 1 ], t_f_mode );
2471 if ( BER_BVISNULL( &t_f_mode[ rc ].word ) ) {
2472 return 1;
2473 }
2474
2475 rwmap->rwm_flags &= ~RWM_F_SUPPORT_T_F_MASK2;
2476 rwmap->rwm_flags |= t_f_mode[ rc ].mask;
2477 rc = 0;
2478 break;
2479
2480 case RWM_CF_MAP:
2481 if ( c->valx >= 0 ) {
2482 struct ldapmap rwm_oc = rwmap->rwm_oc;
2483 struct ldapmap rwm_at = rwmap->rwm_at;
2484 char *argv[5];
2485 int cnt = 0;
2486
2487 if ( rwmap->rwm_bva_map ) {
2488 for ( ; !BER_BVISNULL( &rwmap->rwm_bva_map[ cnt ] ); cnt++ )
2489 /* count */ ;
2490 }
2491
2492 if ( c->valx >= cnt ) {
2493 c->valx = cnt;
2494 }
2495
2496 memset( &rwmap->rwm_oc, 0, sizeof( rwmap->rwm_oc ) );
2497 memset( &rwmap->rwm_at, 0, sizeof( rwmap->rwm_at ) );
2498
2499 /* re-parse all mappings, including the one
2500 * that needs to be added */
2501 argv[0] = "map";
2502 for ( cnt = 0; cnt < c->valx; cnt++ ) {
2503 ConfigArgs ca = { 0 };
2504
2505 ca.line = rwmap->rwm_bva_map[ cnt ].bv_val;
2506 ca.argc = 0;
2507 init_config_argv( &ca );
2508 config_parse_ldif( &ca );
2509
2510 argv[1] = ca.argv[0];
2511 argv[2] = ca.argv[1];
2512 argv[3] = ca.argv[2];
2513 argv[4] = ca.argv[3];
2514
2515 rc = rwm_m_config( &db, c->fname, c->lineno, ca.argc + 1, argv );
2516
2517 ch_free( ca.tline );
2518 ch_free( ca.argv );
2519
2520 /* in case of failure, restore
2521 * the existing mapping */
2522 if ( rc ) {
2523 goto rwmmap_fail;
2524 }
2525 }
2526
2527 argv0 = c->argv[0];
2528 c->argv[0] = "map";
2529 rc = rwm_m_config( &db, c->fname, c->lineno, c->argc, c->argv );
2530 c->argv[0] = argv0;
2531 if ( rc ) {
2532 goto rwmmap_fail;
2533 }
2534
2535 if ( rwmap->rwm_bva_map ) {
2536 for ( ; !BER_BVISNULL( &rwmap->rwm_bva_map[ cnt ] ); cnt++ ) {
2537 ConfigArgs ca = { 0 };
2538
2539 ca.line = rwmap->rwm_bva_map[ cnt ].bv_val;
2540 ca.argc = 0;
2541 init_config_argv( &ca );
2542 config_parse_ldif( &ca );
2543
2544 argv[1] = ca.argv[0];
2545 argv[2] = ca.argv[1];
2546 argv[3] = ca.argv[2];
2547 argv[4] = ca.argv[3];
2548
2549 rc = rwm_m_config( &db, c->fname, c->lineno, ca.argc + 1, argv );
2550
2551 ch_free( ca.tline );
2552 ch_free( ca.argv );
2553
2554 /* in case of failure, restore
2555 * the existing mapping */
2556 if ( rc ) {
2557 goto rwmmap_fail;
2558 }
2559 }
2560 }
2561
2562 /* in case of success, destroy the old mapping
2563 * and add the new one */
2564 if ( rc == 0 ) {
2565 BerVarray tmp;
2566 struct berval bv, *bvp = &bv;
2567
2568 if ( rwm_bva_add( &bvp, 0, &c->argv[ idx0 ] ) ) {
2569 rc = 1;
2570 goto rwmmap_fail;
2571 }
2572
2573 tmp = ber_memrealloc( rwmap->rwm_bva_map,
2574 sizeof( struct berval )*( cnt + 2 ) );
2575 if ( tmp == NULL ) {
2576 ber_memfree( bv.bv_val );
2577 rc = 1;
2578 goto rwmmap_fail;
2579 }
2580 rwmap->rwm_bva_map = tmp;
2581 BER_BVZERO( &rwmap->rwm_bva_map[ cnt + 1 ] );
2582
2583 avl_free( rwm_oc.remap, rwm_mapping_dst_free );
2584 avl_free( rwm_oc.map, rwm_mapping_free );
2585 avl_free( rwm_at.remap, rwm_mapping_dst_free );
2586 avl_free( rwm_at.map, rwm_mapping_free );
2587
2588 for ( ; cnt-- > c->valx; ) {
2589 rwmap->rwm_bva_map[ cnt + 1 ] = rwmap->rwm_bva_map[ cnt ];
2590 }
2591 rwmap->rwm_bva_map[ c->valx ] = bv;
2592
2593 } else {
2594 rwmmap_fail:;
2595 avl_free( rwmap->rwm_oc.remap, rwm_mapping_dst_free );
2596 avl_free( rwmap->rwm_oc.map, rwm_mapping_free );
2597 avl_free( rwmap->rwm_at.remap, rwm_mapping_dst_free );
2598 avl_free( rwmap->rwm_at.map, rwm_mapping_free );
2599 rwmap->rwm_oc = rwm_oc;
2600 rwmap->rwm_at = rwm_at;
2601 }
2602
2603 break;
2604 }
2605
2606 argv0 = c->argv[ 0 ];
2607 c->argv[ 0 ] += STRLENOF( "rwm-" );
2608 rc = rwm_m_config( &db, c->fname, c->lineno, c->argc, c->argv );
2609 c->argv[ 0 ] = argv0;
2610 if ( rc ) {
2611 return 1;
2612
2613 } else {
2614 char *line;
2615 struct berval bv;
2616
2617 line = ldap_charray2str( &c->argv[ 1 ], " " );
2618 if ( line != NULL ) {
2619 ber_str2bv( line, 0, 0, &bv );
2620 ber_bvarray_add( &rwmap->rwm_bva_map, &bv );
2621 }
2622 }
2623 break;
2624
2625 case RWM_CF_NORMALIZE_MAPPED:
2626 if ( c->value_int ) {
2627 rwmap->rwm_flags |= RWM_F_NORMALIZE_MAPPED_ATTRS;
2628 } else {
2629 rwmap->rwm_flags &= ~RWM_F_NORMALIZE_MAPPED_ATTRS;
2630 }
2631 break;
2632
2633 case RWM_CF_DROP_UNREQUESTED:
2634 if ( c->value_int ) {
2635 rwmap->rwm_flags |= RWM_F_DROP_UNREQUESTED_ATTRS;
2636 } else {
2637 rwmap->rwm_flags &= ~RWM_F_DROP_UNREQUESTED_ATTRS;
2638 }
2639 break;
2640
2641 default:
2642 assert( 0 );
2643 return 1;
2644 }
2645
2646 return rc;
2647 }
2648
2649 static int
2650 rwm_db_init(
2651 BackendDB *be,
2652 ConfigReply *cr )
2653 {
2654 slap_overinst *on = (slap_overinst *) be->bd_info;
2655 struct ldaprwmap *rwmap;
2656 int rc = 0;
2657
2658 rwmap = (struct ldaprwmap *)ch_calloc( 1, sizeof( struct ldaprwmap ) );
2659
2660 /* default */
2661 rwmap->rwm_flags = RWM_F_DROP_UNREQUESTED_ATTRS;
2662
2663 rc = rwm_info_init( &rwmap->rwm_rw );
2664
2665 on->on_bi.bi_private = (void *)rwmap;
2666
2667 if ( rc ) {
2668 (void)rwm_db_destroy( be, NULL );
2669 }
2670
2671 return rc;
2672 }
2673
2674 static int
2675 rwm_db_destroy(
2676 BackendDB *be,
2677 ConfigReply *cr )
2678 {
2679 slap_overinst *on = (slap_overinst *) be->bd_info;
2680 int rc = 0;
2681
2682 if ( on->on_bi.bi_private ) {
2683 struct ldaprwmap *rwmap =
2684 (struct ldaprwmap *)on->on_bi.bi_private;
2685
2686 if ( rwmap->rwm_rw ) {
2687 rewrite_info_delete( &rwmap->rwm_rw );
2688 if ( rwmap->rwm_bva_rewrite )
2689 ber_bvarray_free( rwmap->rwm_bva_rewrite );
2690 }
2691
2692 avl_free( rwmap->rwm_oc.remap, rwm_mapping_dst_free );
2693 avl_free( rwmap->rwm_oc.map, rwm_mapping_free );
2694 avl_free( rwmap->rwm_at.remap, rwm_mapping_dst_free );
2695 avl_free( rwmap->rwm_at.map, rwm_mapping_free );
2696 ber_bvarray_free( rwmap->rwm_bva_map );
2697
2698 ch_free( rwmap );
2699 }
2700
2701 return rc;
2702 }
2703
2704 static slap_overinst rwm = { { NULL } };
2705
2706 #if SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC
2707 static
2708 #endif /* SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC */
2709 int
2710 rwm_initialize( void )
2711 {
2712 int rc;
2713
2714 /* Make sure we don't exceed the bits reserved for userland */
2715 config_check_userland( RWM_CF_LAST );
2716
2717 memset( &rwm, 0, sizeof( slap_overinst ) );
2718
2719 rwm.on_bi.bi_type = "rwm";
2720 rwm.on_bi.bi_flags =
2721 SLAPO_BFLAG_SINGLE |
2722 0;
2723
2724 rwm.on_bi.bi_db_init = rwm_db_init;
2725 rwm.on_bi.bi_db_config = rwm_db_config;
2726 rwm.on_bi.bi_db_destroy = rwm_db_destroy;
2727
2728 rwm.on_bi.bi_op_bind = rwm_op_bind;
2729 rwm.on_bi.bi_op_search = rwm_op_search;
2730 rwm.on_bi.bi_op_compare = rwm_op_compare;
2731 rwm.on_bi.bi_op_modify = rwm_op_modify;
2732 rwm.on_bi.bi_op_modrdn = rwm_op_modrdn;
2733 rwm.on_bi.bi_op_add = rwm_op_add;
2734 rwm.on_bi.bi_op_delete = rwm_op_delete;
2735 rwm.on_bi.bi_op_unbind = rwm_op_unbind;
2736 rwm.on_bi.bi_extended = rwm_extended;
2737 #if 1 /* TODO */
2738 rwm.on_bi.bi_entry_release_rw = rwm_entry_release_rw;
2739 rwm.on_bi.bi_entry_get_rw = rwm_entry_get_rw;
2740 #endif
2741
2742 rwm.on_bi.bi_operational = rwm_operational;
2743 rwm.on_bi.bi_chk_referrals = 0 /* rwm_chk_referrals */ ;
2744
2745 rwm.on_bi.bi_connection_init = rwm_conn_init;
2746 rwm.on_bi.bi_connection_destroy = rwm_conn_destroy;
2747
2748 rwm.on_response = rwm_response;
2749
2750 rwm.on_bi.bi_cf_ocs = rwmocs;
2751
2752 rc = config_register_schema( rwmcfg, rwmocs );
2753 if ( rc ) {
2754 return rc;
2755 }
2756
2757 return overlay_register( &rwm );
2758 }
2759
2760 #if SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC
2761 int
2762 init_module( int argc, char *argv[] )
2763 {
2764 return rwm_initialize();
2765 }
2766 #endif /* SLAPD_OVER_RWM == SLAPD_MOD_DYNAMIC */
2767
2768 #endif /* SLAPD_OVER_RWM */
2769