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