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