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