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