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