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