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