1 /* $NetBSD: retcode.c,v 1.1.1.4 2014/05/28 09:58:52 tron Exp $ */ 2 3 /* retcode.c - customizable response for client testing purposes */ 4 /* $OpenLDAP$ */ 5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>. 6 * 7 * Copyright 2005-2014 The OpenLDAP Foundation. 8 * Portions Copyright 2005 Pierangelo Masarati <ando@sys-net.it> 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 /* ACKNOWLEDGEMENTS: 20 * This work was initially developed by Pierangelo Masarati for inclusion 21 * in OpenLDAP Software. 22 */ 23 24 #include "portable.h" 25 26 #ifdef SLAPD_OVER_RETCODE 27 28 #include <stdio.h> 29 30 #include <ac/unistd.h> 31 #include <ac/string.h> 32 #include <ac/ctype.h> 33 #include <ac/socket.h> 34 35 #include "slap.h" 36 #include "config.h" 37 #include "lutil.h" 38 #include "ldif.h" 39 40 static slap_overinst retcode; 41 42 static AttributeDescription *ad_errCode; 43 static AttributeDescription *ad_errText; 44 static AttributeDescription *ad_errOp; 45 static AttributeDescription *ad_errSleepTime; 46 static AttributeDescription *ad_errMatchedDN; 47 static AttributeDescription *ad_errUnsolicitedOID; 48 static AttributeDescription *ad_errUnsolicitedData; 49 static AttributeDescription *ad_errDisconnect; 50 51 static ObjectClass *oc_errAbsObject; 52 static ObjectClass *oc_errObject; 53 static ObjectClass *oc_errAuxObject; 54 55 typedef enum retcode_op_e { 56 SN_DG_OP_NONE = 0x0000, 57 SN_DG_OP_ADD = 0x0001, 58 SN_DG_OP_BIND = 0x0002, 59 SN_DG_OP_COMPARE = 0x0004, 60 SN_DG_OP_DELETE = 0x0008, 61 SN_DG_OP_MODIFY = 0x0010, 62 SN_DG_OP_RENAME = 0x0020, 63 SN_DG_OP_SEARCH = 0x0040, 64 SN_DG_EXTENDED = 0x0080, 65 SN_DG_OP_AUTH = SN_DG_OP_BIND, 66 SN_DG_OP_READ = (SN_DG_OP_COMPARE|SN_DG_OP_SEARCH), 67 SN_DG_OP_WRITE = (SN_DG_OP_ADD|SN_DG_OP_DELETE|SN_DG_OP_MODIFY|SN_DG_OP_RENAME), 68 SN_DG_OP_ALL = (SN_DG_OP_AUTH|SN_DG_OP_READ|SN_DG_OP_WRITE|SN_DG_EXTENDED) 69 } retcode_op_e; 70 71 typedef struct retcode_item_t { 72 struct berval rdi_line; 73 struct berval rdi_dn; 74 struct berval rdi_ndn; 75 struct berval rdi_text; 76 struct berval rdi_matched; 77 int rdi_err; 78 BerVarray rdi_ref; 79 int rdi_sleeptime; 80 Entry rdi_e; 81 slap_mask_t rdi_mask; 82 struct berval rdi_unsolicited_oid; 83 struct berval rdi_unsolicited_data; 84 85 unsigned rdi_flags; 86 #define RDI_PRE_DISCONNECT (0x1U) 87 #define RDI_POST_DISCONNECT (0x2U) 88 89 struct retcode_item_t *rdi_next; 90 } retcode_item_t; 91 92 typedef struct retcode_t { 93 struct berval rd_pdn; 94 struct berval rd_npdn; 95 96 int rd_sleep; 97 98 retcode_item_t *rd_item; 99 100 int rd_indir; 101 #define RETCODE_FINDIR 0x01 102 #define RETCODE_INDIR( rd ) ( (rd)->rd_indir ) 103 } retcode_t; 104 105 static int 106 retcode_entry_response( Operation *op, SlapReply *rs, BackendInfo *bi, Entry *e ); 107 108 static unsigned int 109 retcode_sleep( int s ) 110 { 111 unsigned int r = 0; 112 113 /* sleep as required */ 114 if ( s < 0 ) { 115 #if 0 /* use high-order bits for better randomness (Numerical Recipes in "C") */ 116 r = rand() % (-s); 117 #endif 118 r = ((double)(-s))*rand()/(RAND_MAX + 1.0); 119 } else if ( s > 0 ) { 120 r = (unsigned int)s; 121 } 122 if ( r ) { 123 sleep( r ); 124 } 125 126 return r; 127 } 128 129 static int 130 retcode_cleanup_cb( Operation *op, SlapReply *rs ) 131 { 132 rs->sr_matched = NULL; 133 rs->sr_text = NULL; 134 135 if ( rs->sr_ref != NULL ) { 136 ber_bvarray_free( rs->sr_ref ); 137 rs->sr_ref = NULL; 138 } 139 140 ch_free( op->o_callback ); 141 op->o_callback = NULL; 142 143 return SLAP_CB_CONTINUE; 144 } 145 146 static int 147 retcode_send_onelevel( Operation *op, SlapReply *rs ) 148 { 149 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 150 retcode_t *rd = (retcode_t *)on->on_bi.bi_private; 151 152 retcode_item_t *rdi; 153 154 for ( rdi = rd->rd_item; rdi != NULL; rdi = rdi->rdi_next ) { 155 if ( op->o_abandon ) { 156 return rs->sr_err = SLAPD_ABANDON; 157 } 158 159 rs->sr_err = test_filter( op, &rdi->rdi_e, op->ors_filter ); 160 if ( rs->sr_err == LDAP_COMPARE_TRUE ) { 161 /* safe default */ 162 rs->sr_attrs = op->ors_attrs; 163 rs->sr_operational_attrs = NULL; 164 rs->sr_ctrls = NULL; 165 rs->sr_flags = 0; 166 rs->sr_err = LDAP_SUCCESS; 167 rs->sr_entry = &rdi->rdi_e; 168 169 rs->sr_err = send_search_entry( op, rs ); 170 rs->sr_flags = 0; 171 rs->sr_entry = NULL; 172 rs->sr_attrs = NULL; 173 174 switch ( rs->sr_err ) { 175 case LDAP_UNAVAILABLE: /* connection closed */ 176 rs->sr_err = LDAP_OTHER; 177 /* fallthru */ 178 case LDAP_SIZELIMIT_EXCEEDED: 179 goto done; 180 } 181 } 182 rs->sr_err = LDAP_SUCCESS; 183 } 184 185 done:; 186 187 send_ldap_result( op, rs ); 188 189 return rs->sr_err; 190 } 191 192 static int 193 retcode_op_add( Operation *op, SlapReply *rs ) 194 { 195 return retcode_entry_response( op, rs, NULL, op->ora_e ); 196 } 197 198 typedef struct retcode_cb_t { 199 BackendInfo *rdc_info; 200 unsigned rdc_flags; 201 ber_tag_t rdc_tag; 202 AttributeName *rdc_attrs; 203 } retcode_cb_t; 204 205 static int 206 retcode_cb_response( Operation *op, SlapReply *rs ) 207 { 208 retcode_cb_t *rdc = (retcode_cb_t *)op->o_callback->sc_private; 209 210 op->o_tag = rdc->rdc_tag; 211 if ( rs->sr_type == REP_SEARCH ) { 212 ber_tag_t o_tag = op->o_tag; 213 int rc; 214 215 if ( op->o_tag == LDAP_REQ_SEARCH ) { 216 rs->sr_attrs = rdc->rdc_attrs; 217 } 218 rc = retcode_entry_response( op, rs, rdc->rdc_info, rs->sr_entry ); 219 op->o_tag = o_tag; 220 221 return rc; 222 } 223 224 switch ( rs->sr_err ) { 225 case LDAP_SUCCESS: 226 case LDAP_NO_SUCH_OBJECT: 227 /* in case of noSuchObject, stop the internal search 228 * for in-directory error stuff */ 229 if ( !op->o_abandon ) { 230 rdc->rdc_flags = SLAP_CB_CONTINUE; 231 } 232 return 0; 233 } 234 235 return SLAP_CB_CONTINUE; 236 } 237 238 static int 239 retcode_op_internal( Operation *op, SlapReply *rs ) 240 { 241 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 242 243 Operation op2 = *op; 244 BackendDB db = *op->o_bd; 245 slap_callback sc = { 0 }; 246 retcode_cb_t rdc; 247 248 int rc; 249 250 op2.o_tag = LDAP_REQ_SEARCH; 251 op2.ors_scope = LDAP_SCOPE_BASE; 252 op2.ors_deref = LDAP_DEREF_NEVER; 253 op2.ors_tlimit = SLAP_NO_LIMIT; 254 op2.ors_slimit = SLAP_NO_LIMIT; 255 op2.ors_limit = NULL; 256 op2.ors_attrsonly = 0; 257 op2.ors_attrs = slap_anlist_all_attributes; 258 259 ber_str2bv_x( "(objectClass=errAbsObject)", 260 STRLENOF( "(objectClass=errAbsObject)" ), 261 1, &op2.ors_filterstr, op2.o_tmpmemctx ); 262 op2.ors_filter = str2filter_x( &op2, op2.ors_filterstr.bv_val ); 263 264 /* errAbsObject is defined by this overlay! */ 265 assert( op2.ors_filter != NULL ); 266 267 db.bd_info = on->on_info->oi_orig; 268 op2.o_bd = &db; 269 270 rdc.rdc_info = on->on_info->oi_orig; 271 rdc.rdc_flags = RETCODE_FINDIR; 272 if ( op->o_tag == LDAP_REQ_SEARCH ) { 273 rdc.rdc_attrs = op->ors_attrs; 274 } 275 rdc.rdc_tag = op->o_tag; 276 sc.sc_response = retcode_cb_response; 277 sc.sc_private = &rdc; 278 op2.o_callback = ≻ 279 280 rc = op2.o_bd->be_search( &op2, rs ); 281 op->o_abandon = op2.o_abandon; 282 283 filter_free_x( &op2, op2.ors_filter, 1 ); 284 ber_memfree_x( op2.ors_filterstr.bv_val, op2.o_tmpmemctx ); 285 286 if ( rdc.rdc_flags == SLAP_CB_CONTINUE ) { 287 return SLAP_CB_CONTINUE; 288 } 289 290 return rc; 291 } 292 293 static int 294 retcode_op_func( Operation *op, SlapReply *rs ) 295 { 296 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 297 retcode_t *rd = (retcode_t *)on->on_bi.bi_private; 298 299 retcode_item_t *rdi; 300 struct berval nrdn, npdn; 301 302 slap_callback *cb = NULL; 303 304 /* sleep as required */ 305 retcode_sleep( rd->rd_sleep ); 306 307 if ( !dnIsSuffix( &op->o_req_ndn, &rd->rd_npdn ) ) { 308 if ( RETCODE_INDIR( rd ) ) { 309 switch ( op->o_tag ) { 310 case LDAP_REQ_ADD: 311 return retcode_op_add( op, rs ); 312 313 case LDAP_REQ_BIND: 314 /* skip if rootdn */ 315 /* FIXME: better give the db a chance? */ 316 if ( be_isroot_pw( op ) ) { 317 return LDAP_SUCCESS; 318 } 319 return retcode_op_internal( op, rs ); 320 321 case LDAP_REQ_SEARCH: 322 if ( op->ors_scope == LDAP_SCOPE_BASE ) { 323 rs->sr_err = retcode_op_internal( op, rs ); 324 switch ( rs->sr_err ) { 325 case SLAP_CB_CONTINUE: 326 if ( rs->sr_nentries == 0 ) { 327 break; 328 } 329 rs->sr_err = LDAP_SUCCESS; 330 /* fallthru */ 331 332 default: 333 send_ldap_result( op, rs ); 334 break; 335 } 336 return rs->sr_err; 337 } 338 break; 339 340 case LDAP_REQ_MODIFY: 341 case LDAP_REQ_DELETE: 342 case LDAP_REQ_MODRDN: 343 case LDAP_REQ_COMPARE: 344 return retcode_op_internal( op, rs ); 345 } 346 } 347 348 return SLAP_CB_CONTINUE; 349 } 350 351 if ( op->o_tag == LDAP_REQ_SEARCH 352 && op->ors_scope != LDAP_SCOPE_BASE 353 && op->o_req_ndn.bv_len == rd->rd_npdn.bv_len ) 354 { 355 return retcode_send_onelevel( op, rs ); 356 } 357 358 dnParent( &op->o_req_ndn, &npdn ); 359 if ( npdn.bv_len != rd->rd_npdn.bv_len ) { 360 rs->sr_err = LDAP_NO_SUCH_OBJECT; 361 rs->sr_matched = rd->rd_pdn.bv_val; 362 send_ldap_result( op, rs ); 363 rs->sr_matched = NULL; 364 return rs->sr_err; 365 } 366 367 dnRdn( &op->o_req_ndn, &nrdn ); 368 369 for ( rdi = rd->rd_item; rdi != NULL; rdi = rdi->rdi_next ) { 370 struct berval rdi_nrdn; 371 372 dnRdn( &rdi->rdi_ndn, &rdi_nrdn ); 373 if ( dn_match( &nrdn, &rdi_nrdn ) ) { 374 break; 375 } 376 } 377 378 if ( rdi != NULL && rdi->rdi_mask != SN_DG_OP_ALL ) { 379 retcode_op_e o_tag = SN_DG_OP_NONE; 380 381 switch ( op->o_tag ) { 382 case LDAP_REQ_ADD: 383 o_tag = SN_DG_OP_ADD; 384 break; 385 386 case LDAP_REQ_BIND: 387 o_tag = SN_DG_OP_BIND; 388 break; 389 390 case LDAP_REQ_COMPARE: 391 o_tag = SN_DG_OP_COMPARE; 392 break; 393 394 case LDAP_REQ_DELETE: 395 o_tag = SN_DG_OP_DELETE; 396 break; 397 398 case LDAP_REQ_MODIFY: 399 o_tag = SN_DG_OP_MODIFY; 400 break; 401 402 case LDAP_REQ_MODRDN: 403 o_tag = SN_DG_OP_RENAME; 404 break; 405 406 case LDAP_REQ_SEARCH: 407 o_tag = SN_DG_OP_SEARCH; 408 break; 409 410 case LDAP_REQ_EXTENDED: 411 o_tag = SN_DG_EXTENDED; 412 break; 413 414 default: 415 /* Should not happen */ 416 break; 417 } 418 419 if ( !( o_tag & rdi->rdi_mask ) ) { 420 return SLAP_CB_CONTINUE; 421 } 422 } 423 424 if ( rdi == NULL ) { 425 rs->sr_matched = rd->rd_pdn.bv_val; 426 rs->sr_err = LDAP_NO_SUCH_OBJECT; 427 rs->sr_text = "retcode not found"; 428 429 } else { 430 if ( rdi->rdi_flags & RDI_PRE_DISCONNECT ) { 431 return rs->sr_err = SLAPD_DISCONNECT; 432 } 433 434 rs->sr_err = rdi->rdi_err; 435 rs->sr_text = rdi->rdi_text.bv_val; 436 rs->sr_matched = rdi->rdi_matched.bv_val; 437 438 /* FIXME: we only honor the rdi_ref field in case rdi_err 439 * is LDAP_REFERRAL otherwise send_ldap_result() bails out */ 440 if ( rs->sr_err == LDAP_REFERRAL ) { 441 BerVarray ref; 442 443 if ( rdi->rdi_ref != NULL ) { 444 ref = rdi->rdi_ref; 445 } else { 446 ref = default_referral; 447 } 448 449 if ( ref != NULL ) { 450 rs->sr_ref = referral_rewrite( ref, 451 NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT ); 452 453 } else { 454 rs->sr_err = LDAP_OTHER; 455 rs->sr_text = "bad referral object"; 456 } 457 } 458 459 retcode_sleep( rdi->rdi_sleeptime ); 460 } 461 462 switch ( op->o_tag ) { 463 case LDAP_REQ_EXTENDED: 464 if ( rdi == NULL ) { 465 break; 466 } 467 cb = ( slap_callback * )ch_malloc( sizeof( slap_callback ) ); 468 memset( cb, 0, sizeof( slap_callback ) ); 469 cb->sc_cleanup = retcode_cleanup_cb; 470 op->o_callback = cb; 471 break; 472 473 default: 474 if ( rdi && !BER_BVISNULL( &rdi->rdi_unsolicited_oid ) ) { 475 ber_int_t msgid = op->o_msgid; 476 477 /* RFC 4511 unsolicited response */ 478 479 op->o_msgid = 0; 480 if ( strcmp( rdi->rdi_unsolicited_oid.bv_val, "0" ) == 0 ) { 481 send_ldap_result( op, rs ); 482 483 } else { 484 ber_tag_t tag = op->o_tag; 485 486 op->o_tag = LDAP_REQ_EXTENDED; 487 rs->sr_rspoid = rdi->rdi_unsolicited_oid.bv_val; 488 if ( !BER_BVISNULL( &rdi->rdi_unsolicited_data ) ) { 489 rs->sr_rspdata = &rdi->rdi_unsolicited_data; 490 } 491 send_ldap_extended( op, rs ); 492 rs->sr_rspoid = NULL; 493 rs->sr_rspdata = NULL; 494 op->o_tag = tag; 495 496 } 497 op->o_msgid = msgid; 498 499 } else { 500 send_ldap_result( op, rs ); 501 } 502 503 if ( rs->sr_ref != NULL ) { 504 ber_bvarray_free( rs->sr_ref ); 505 rs->sr_ref = NULL; 506 } 507 rs->sr_matched = NULL; 508 rs->sr_text = NULL; 509 510 if ( rdi && rdi->rdi_flags & RDI_POST_DISCONNECT ) { 511 return rs->sr_err = SLAPD_DISCONNECT; 512 } 513 break; 514 } 515 516 return rs->sr_err; 517 } 518 519 static int 520 retcode_op2str( ber_tag_t op, struct berval *bv ) 521 { 522 switch ( op ) { 523 case LDAP_REQ_BIND: 524 BER_BVSTR( bv, "bind" ); 525 return 0; 526 case LDAP_REQ_ADD: 527 BER_BVSTR( bv, "add" ); 528 return 0; 529 case LDAP_REQ_DELETE: 530 BER_BVSTR( bv, "delete" ); 531 return 0; 532 case LDAP_REQ_MODRDN: 533 BER_BVSTR( bv, "modrdn" ); 534 return 0; 535 case LDAP_REQ_MODIFY: 536 BER_BVSTR( bv, "modify" ); 537 return 0; 538 case LDAP_REQ_COMPARE: 539 BER_BVSTR( bv, "compare" ); 540 return 0; 541 case LDAP_REQ_SEARCH: 542 BER_BVSTR( bv, "search" ); 543 return 0; 544 case LDAP_REQ_EXTENDED: 545 BER_BVSTR( bv, "extended" ); 546 return 0; 547 } 548 return -1; 549 } 550 551 static int 552 retcode_entry_response( Operation *op, SlapReply *rs, BackendInfo *bi, Entry *e ) 553 { 554 Attribute *a; 555 int err; 556 char *next; 557 int disconnect = 0; 558 559 if ( get_manageDSAit( op ) ) { 560 return SLAP_CB_CONTINUE; 561 } 562 563 if ( !is_entry_objectclass_or_sub( e, oc_errAbsObject ) ) { 564 return SLAP_CB_CONTINUE; 565 } 566 567 /* operation */ 568 a = attr_find( e->e_attrs, ad_errOp ); 569 if ( a != NULL ) { 570 int i, 571 gotit = 0; 572 struct berval bv = BER_BVNULL; 573 574 (void)retcode_op2str( op->o_tag, &bv ); 575 576 if ( BER_BVISNULL( &bv ) ) { 577 return SLAP_CB_CONTINUE; 578 } 579 580 for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) { 581 if ( bvmatch( &a->a_nvals[ i ], &bv ) ) { 582 gotit = 1; 583 break; 584 } 585 } 586 587 if ( !gotit ) { 588 return SLAP_CB_CONTINUE; 589 } 590 } 591 592 /* disconnect */ 593 a = attr_find( e->e_attrs, ad_errDisconnect ); 594 if ( a != NULL ) { 595 if ( bvmatch( &a->a_nvals[ 0 ], &slap_true_bv ) ) { 596 return rs->sr_err = SLAPD_DISCONNECT; 597 } 598 disconnect = 1; 599 } 600 601 /* error code */ 602 a = attr_find( e->e_attrs, ad_errCode ); 603 if ( a == NULL ) { 604 return SLAP_CB_CONTINUE; 605 } 606 err = strtol( a->a_nvals[ 0 ].bv_val, &next, 0 ); 607 if ( next == a->a_nvals[ 0 ].bv_val || next[ 0 ] != '\0' ) { 608 return SLAP_CB_CONTINUE; 609 } 610 rs->sr_err = err; 611 612 /* sleep time */ 613 a = attr_find( e->e_attrs, ad_errSleepTime ); 614 if ( a != NULL && a->a_nvals[ 0 ].bv_val[ 0 ] != '-' ) { 615 int sleepTime; 616 617 if ( lutil_atoi( &sleepTime, a->a_nvals[ 0 ].bv_val ) == 0 ) { 618 retcode_sleep( sleepTime ); 619 } 620 } 621 622 if ( rs->sr_err != LDAP_SUCCESS && !LDAP_API_ERROR( rs->sr_err )) { 623 BackendDB db = *op->o_bd, 624 *o_bd = op->o_bd; 625 void *o_callback = op->o_callback; 626 627 /* message text */ 628 a = attr_find( e->e_attrs, ad_errText ); 629 if ( a != NULL ) { 630 rs->sr_text = a->a_vals[ 0 ].bv_val; 631 } 632 633 /* matched DN */ 634 a = attr_find( e->e_attrs, ad_errMatchedDN ); 635 if ( a != NULL ) { 636 rs->sr_matched = a->a_vals[ 0 ].bv_val; 637 } 638 639 if ( bi == NULL ) { 640 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 641 642 bi = on->on_info->oi_orig; 643 } 644 645 db.bd_info = bi; 646 op->o_bd = &db; 647 op->o_callback = NULL; 648 649 /* referral */ 650 if ( rs->sr_err == LDAP_REFERRAL ) { 651 BerVarray refs = default_referral; 652 653 a = attr_find( e->e_attrs, slap_schema.si_ad_ref ); 654 if ( a != NULL ) { 655 refs = a->a_vals; 656 } 657 rs->sr_ref = referral_rewrite( refs, 658 NULL, &op->o_req_dn, op->oq_search.rs_scope ); 659 660 send_search_reference( op, rs ); 661 ber_bvarray_free( rs->sr_ref ); 662 rs->sr_ref = NULL; 663 664 } else { 665 a = attr_find( e->e_attrs, ad_errUnsolicitedOID ); 666 if ( a != NULL ) { 667 struct berval oid = BER_BVNULL, 668 data = BER_BVNULL; 669 ber_int_t msgid = op->o_msgid; 670 671 /* RFC 4511 unsolicited response */ 672 673 op->o_msgid = 0; 674 675 oid = a->a_nvals[ 0 ]; 676 677 a = attr_find( e->e_attrs, ad_errUnsolicitedData ); 678 if ( a != NULL ) { 679 data = a->a_nvals[ 0 ]; 680 } 681 682 if ( strcmp( oid.bv_val, "0" ) == 0 ) { 683 send_ldap_result( op, rs ); 684 685 } else { 686 ber_tag_t tag = op->o_tag; 687 688 op->o_tag = LDAP_REQ_EXTENDED; 689 rs->sr_rspoid = oid.bv_val; 690 if ( !BER_BVISNULL( &data ) ) { 691 rs->sr_rspdata = &data; 692 } 693 send_ldap_extended( op, rs ); 694 rs->sr_rspoid = NULL; 695 rs->sr_rspdata = NULL; 696 op->o_tag = tag; 697 } 698 op->o_msgid = msgid; 699 700 } else { 701 send_ldap_result( op, rs ); 702 } 703 } 704 705 rs->sr_text = NULL; 706 rs->sr_matched = NULL; 707 op->o_bd = o_bd; 708 op->o_callback = o_callback; 709 } 710 711 if ( rs->sr_err != LDAP_SUCCESS ) { 712 if ( disconnect ) { 713 return rs->sr_err = SLAPD_DISCONNECT; 714 } 715 716 op->o_abandon = 1; 717 return rs->sr_err; 718 } 719 720 return SLAP_CB_CONTINUE; 721 } 722 723 static int 724 retcode_response( Operation *op, SlapReply *rs ) 725 { 726 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info; 727 retcode_t *rd = (retcode_t *)on->on_bi.bi_private; 728 729 if ( rs->sr_type != REP_SEARCH || !RETCODE_INDIR( rd ) ) { 730 return SLAP_CB_CONTINUE; 731 } 732 733 return retcode_entry_response( op, rs, NULL, rs->sr_entry ); 734 } 735 736 static int 737 retcode_db_init( BackendDB *be, ConfigReply *cr ) 738 { 739 slap_overinst *on = (slap_overinst *)be->bd_info; 740 retcode_t *rd; 741 742 srand( getpid() ); 743 744 rd = (retcode_t *)ch_malloc( sizeof( retcode_t ) ); 745 memset( rd, 0, sizeof( retcode_t ) ); 746 747 on->on_bi.bi_private = (void *)rd; 748 749 return 0; 750 } 751 752 static void 753 retcode_item_destroy( retcode_item_t *rdi ) 754 { 755 ber_memfree( rdi->rdi_line.bv_val ); 756 757 ber_memfree( rdi->rdi_dn.bv_val ); 758 ber_memfree( rdi->rdi_ndn.bv_val ); 759 760 if ( !BER_BVISNULL( &rdi->rdi_text ) ) { 761 ber_memfree( rdi->rdi_text.bv_val ); 762 } 763 764 if ( !BER_BVISNULL( &rdi->rdi_matched ) ) { 765 ber_memfree( rdi->rdi_matched.bv_val ); 766 } 767 768 if ( rdi->rdi_ref ) { 769 ber_bvarray_free( rdi->rdi_ref ); 770 } 771 772 BER_BVZERO( &rdi->rdi_e.e_name ); 773 BER_BVZERO( &rdi->rdi_e.e_nname ); 774 775 entry_clean( &rdi->rdi_e ); 776 777 if ( !BER_BVISNULL( &rdi->rdi_unsolicited_oid ) ) { 778 ber_memfree( rdi->rdi_unsolicited_oid.bv_val ); 779 if ( !BER_BVISNULL( &rdi->rdi_unsolicited_data ) ) 780 ber_memfree( rdi->rdi_unsolicited_data.bv_val ); 781 } 782 783 ch_free( rdi ); 784 } 785 786 enum { 787 RC_PARENT = 1, 788 RC_ITEM 789 }; 790 791 static ConfigDriver rc_cf_gen; 792 793 static ConfigTable rccfg[] = { 794 { "retcode-parent", "dn", 795 2, 2, 0, ARG_MAGIC|ARG_DN|RC_PARENT, rc_cf_gen, 796 "( OLcfgOvAt:20.1 NAME 'olcRetcodeParent' " 797 "DESC '' " 798 "SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL }, 799 { "retcode-item", "rdn> <retcode> <...", 800 3, 0, 0, ARG_MAGIC|RC_ITEM, rc_cf_gen, 801 "( OLcfgOvAt:20.2 NAME 'olcRetcodeItem' " 802 "DESC '' " 803 "EQUALITY caseIgnoreMatch " 804 "SYNTAX OMsDirectoryString " 805 "X-ORDERED 'VALUES' )", NULL, NULL }, 806 { "retcode-indir", "on|off", 807 1, 2, 0, ARG_OFFSET|ARG_ON_OFF, 808 (void *)offsetof(retcode_t, rd_indir), 809 "( OLcfgOvAt:20.3 NAME 'olcRetcodeInDir' " 810 "DESC '' " 811 "SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL }, 812 813 { "retcode-sleep", "sleeptime", 814 2, 2, 0, ARG_OFFSET|ARG_INT, 815 (void *)offsetof(retcode_t, rd_sleep), 816 "( OLcfgOvAt:20.4 NAME 'olcRetcodeSleep' " 817 "DESC '' " 818 "SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL }, 819 820 { NULL, NULL, 0, 0, 0, ARG_IGNORED } 821 }; 822 823 static ConfigOCs rcocs[] = { 824 { "( OLcfgOvOc:20.1 " 825 "NAME 'olcRetcodeConfig' " 826 "DESC 'Retcode configuration' " 827 "SUP olcOverlayConfig " 828 "MAY ( olcRetcodeParent " 829 "$ olcRetcodeItem " 830 "$ olcRetcodeInDir " 831 "$ olcRetcodeSleep " 832 ") )", 833 Cft_Overlay, rccfg, NULL, NULL }, 834 { NULL, 0, NULL } 835 }; 836 837 static int 838 rc_cf_gen( ConfigArgs *c ) 839 { 840 slap_overinst *on = (slap_overinst *)c->bi; 841 retcode_t *rd = (retcode_t *)on->on_bi.bi_private; 842 int rc = ARG_BAD_CONF; 843 844 if ( c->op == SLAP_CONFIG_EMIT ) { 845 switch( c->type ) { 846 case RC_PARENT: 847 if ( !BER_BVISEMPTY( &rd->rd_pdn )) { 848 rc = value_add_one( &c->rvalue_vals, 849 &rd->rd_pdn ); 850 if ( rc == 0 ) { 851 rc = value_add_one( &c->rvalue_nvals, 852 &rd->rd_npdn ); 853 } 854 return rc; 855 } 856 rc = 0; 857 break; 858 859 case RC_ITEM: { 860 retcode_item_t *rdi; 861 int i; 862 863 for ( rdi = rd->rd_item, i = 0; rdi; rdi = rdi->rdi_next, i++ ) { 864 char buf[4096]; 865 struct berval bv; 866 char *ptr; 867 868 bv.bv_len = snprintf( buf, sizeof( buf ), SLAP_X_ORDERED_FMT, i ); 869 bv.bv_len += rdi->rdi_line.bv_len; 870 ptr = bv.bv_val = ch_malloc( bv.bv_len + 1 ); 871 ptr = lutil_strcopy( ptr, buf ); 872 ptr = lutil_strncopy( ptr, rdi->rdi_line.bv_val, rdi->rdi_line.bv_len ); 873 ber_bvarray_add( &c->rvalue_vals, &bv ); 874 } 875 rc = 0; 876 } break; 877 878 default: 879 assert( 0 ); 880 break; 881 } 882 883 return rc; 884 885 } else if ( c->op == LDAP_MOD_DELETE ) { 886 switch( c->type ) { 887 case RC_PARENT: 888 if ( rd->rd_pdn.bv_val ) { 889 ber_memfree ( rd->rd_pdn.bv_val ); 890 rc = 0; 891 } 892 if ( rd->rd_npdn.bv_val ) { 893 ber_memfree ( rd->rd_npdn.bv_val ); 894 } 895 break; 896 897 case RC_ITEM: 898 if ( c->valx == -1 ) { 899 retcode_item_t *rdi, *next; 900 901 for ( rdi = rd->rd_item; rdi != NULL; rdi = next ) { 902 next = rdi->rdi_next; 903 retcode_item_destroy( rdi ); 904 } 905 906 } else { 907 retcode_item_t **rdip, *rdi; 908 int i; 909 910 for ( rdip = &rd->rd_item, i = 0; i <= c->valx && *rdip; i++, rdip = &(*rdip)->rdi_next ) 911 ; 912 if ( *rdip == NULL ) { 913 return 1; 914 } 915 rdi = *rdip; 916 *rdip = rdi->rdi_next; 917 918 retcode_item_destroy( rdi ); 919 } 920 rc = 0; 921 break; 922 923 default: 924 assert( 0 ); 925 break; 926 } 927 return rc; /* FIXME */ 928 } 929 930 switch( c->type ) { 931 case RC_PARENT: 932 if ( rd->rd_pdn.bv_val ) { 933 ber_memfree ( rd->rd_pdn.bv_val ); 934 } 935 if ( rd->rd_npdn.bv_val ) { 936 ber_memfree ( rd->rd_npdn.bv_val ); 937 } 938 rd->rd_pdn = c->value_dn; 939 rd->rd_npdn = c->value_ndn; 940 rc = 0; 941 break; 942 943 case RC_ITEM: { 944 retcode_item_t rdi = { BER_BVNULL }, **rdip; 945 struct berval bv, rdn, nrdn; 946 char *next = NULL; 947 int i; 948 949 if ( c->argc < 3 ) { 950 snprintf( c->cr_msg, sizeof(c->cr_msg), 951 "\"retcode-item <RDN> <retcode> [<text>]\": " 952 "missing args" ); 953 Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 954 c->log, c->cr_msg, 0 ); 955 return ARG_BAD_CONF; 956 } 957 958 ber_str2bv( c->argv[ 1 ], 0, 0, &bv ); 959 960 rc = dnPrettyNormal( NULL, &bv, &rdn, &nrdn, NULL ); 961 if ( rc != LDAP_SUCCESS ) { 962 snprintf( c->cr_msg, sizeof(c->cr_msg), 963 "unable to normalize RDN \"%s\": %d", 964 c->argv[ 1 ], rc ); 965 Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 966 c->log, c->cr_msg, 0 ); 967 return ARG_BAD_CONF; 968 } 969 970 if ( !dnIsOneLevelRDN( &nrdn ) ) { 971 snprintf( c->cr_msg, sizeof(c->cr_msg), 972 "value \"%s\" is not a RDN", 973 c->argv[ 1 ] ); 974 Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 975 c->log, c->cr_msg, 0 ); 976 return ARG_BAD_CONF; 977 } 978 979 if ( BER_BVISNULL( &rd->rd_npdn ) ) { 980 /* FIXME: we use the database suffix */ 981 if ( c->be->be_nsuffix == NULL ) { 982 snprintf( c->cr_msg, sizeof(c->cr_msg), 983 "either \"retcode-parent\" " 984 "or \"suffix\" must be defined" ); 985 Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 986 c->log, c->cr_msg, 0 ); 987 return ARG_BAD_CONF; 988 } 989 990 ber_dupbv( &rd->rd_pdn, &c->be->be_suffix[ 0 ] ); 991 ber_dupbv( &rd->rd_npdn, &c->be->be_nsuffix[ 0 ] ); 992 } 993 994 build_new_dn( &rdi.rdi_dn, &rd->rd_pdn, &rdn, NULL ); 995 build_new_dn( &rdi.rdi_ndn, &rd->rd_npdn, &nrdn, NULL ); 996 997 ch_free( rdn.bv_val ); 998 ch_free( nrdn.bv_val ); 999 1000 rdi.rdi_err = strtol( c->argv[ 2 ], &next, 0 ); 1001 if ( next == c->argv[ 2 ] || next[ 0 ] != '\0' ) { 1002 snprintf( c->cr_msg, sizeof(c->cr_msg), 1003 "unable to parse return code \"%s\"", 1004 c->argv[ 2 ] ); 1005 Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 1006 c->log, c->cr_msg, 0 ); 1007 return ARG_BAD_CONF; 1008 } 1009 1010 rdi.rdi_mask = SN_DG_OP_ALL; 1011 1012 if ( c->argc > 3 ) { 1013 for ( i = 3; i < c->argc; i++ ) { 1014 if ( strncasecmp( c->argv[ i ], "op=", STRLENOF( "op=" ) ) == 0 ) 1015 { 1016 char **ops; 1017 int j; 1018 1019 ops = ldap_str2charray( &c->argv[ i ][ STRLENOF( "op=" ) ], "," ); 1020 assert( ops != NULL ); 1021 1022 rdi.rdi_mask = SN_DG_OP_NONE; 1023 1024 for ( j = 0; ops[ j ] != NULL; j++ ) { 1025 if ( strcasecmp( ops[ j ], "add" ) == 0 ) { 1026 rdi.rdi_mask |= SN_DG_OP_ADD; 1027 1028 } else if ( strcasecmp( ops[ j ], "bind" ) == 0 ) { 1029 rdi.rdi_mask |= SN_DG_OP_BIND; 1030 1031 } else if ( strcasecmp( ops[ j ], "compare" ) == 0 ) { 1032 rdi.rdi_mask |= SN_DG_OP_COMPARE; 1033 1034 } else if ( strcasecmp( ops[ j ], "delete" ) == 0 ) { 1035 rdi.rdi_mask |= SN_DG_OP_DELETE; 1036 1037 } else if ( strcasecmp( ops[ j ], "modify" ) == 0 ) { 1038 rdi.rdi_mask |= SN_DG_OP_MODIFY; 1039 1040 } else if ( strcasecmp( ops[ j ], "rename" ) == 0 1041 || strcasecmp( ops[ j ], "modrdn" ) == 0 ) 1042 { 1043 rdi.rdi_mask |= SN_DG_OP_RENAME; 1044 1045 } else if ( strcasecmp( ops[ j ], "search" ) == 0 ) { 1046 rdi.rdi_mask |= SN_DG_OP_SEARCH; 1047 1048 } else if ( strcasecmp( ops[ j ], "extended" ) == 0 ) { 1049 rdi.rdi_mask |= SN_DG_EXTENDED; 1050 1051 } else if ( strcasecmp( ops[ j ], "auth" ) == 0 ) { 1052 rdi.rdi_mask |= SN_DG_OP_AUTH; 1053 1054 } else if ( strcasecmp( ops[ j ], "read" ) == 0 ) { 1055 rdi.rdi_mask |= SN_DG_OP_READ; 1056 1057 } else if ( strcasecmp( ops[ j ], "write" ) == 0 ) { 1058 rdi.rdi_mask |= SN_DG_OP_WRITE; 1059 1060 } else if ( strcasecmp( ops[ j ], "all" ) == 0 ) { 1061 rdi.rdi_mask |= SN_DG_OP_ALL; 1062 1063 } else { 1064 snprintf( c->cr_msg, sizeof(c->cr_msg), 1065 "unknown op \"%s\"", 1066 ops[ j ] ); 1067 ldap_charray_free( ops ); 1068 Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 1069 c->log, c->cr_msg, 0 ); 1070 return ARG_BAD_CONF; 1071 } 1072 } 1073 1074 ldap_charray_free( ops ); 1075 1076 } else if ( strncasecmp( c->argv[ i ], "text=", STRLENOF( "text=" ) ) == 0 ) 1077 { 1078 if ( !BER_BVISNULL( &rdi.rdi_text ) ) { 1079 snprintf( c->cr_msg, sizeof(c->cr_msg), 1080 "\"text\" already provided" ); 1081 Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 1082 c->log, c->cr_msg, 0 ); 1083 return ARG_BAD_CONF; 1084 } 1085 ber_str2bv( &c->argv[ i ][ STRLENOF( "text=" ) ], 0, 1, &rdi.rdi_text ); 1086 1087 } else if ( strncasecmp( c->argv[ i ], "matched=", STRLENOF( "matched=" ) ) == 0 ) 1088 { 1089 struct berval dn; 1090 1091 if ( !BER_BVISNULL( &rdi.rdi_matched ) ) { 1092 snprintf( c->cr_msg, sizeof(c->cr_msg), 1093 "\"matched\" already provided" ); 1094 Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 1095 c->log, c->cr_msg, 0 ); 1096 return ARG_BAD_CONF; 1097 } 1098 ber_str2bv( &c->argv[ i ][ STRLENOF( "matched=" ) ], 0, 0, &dn ); 1099 if ( dnPretty( NULL, &dn, &rdi.rdi_matched, NULL ) != LDAP_SUCCESS ) { 1100 snprintf( c->cr_msg, sizeof(c->cr_msg), 1101 "unable to prettify matched DN \"%s\"", 1102 &c->argv[ i ][ STRLENOF( "matched=" ) ] ); 1103 Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 1104 c->log, c->cr_msg, 0 ); 1105 return ARG_BAD_CONF; 1106 } 1107 1108 } else if ( strncasecmp( c->argv[ i ], "ref=", STRLENOF( "ref=" ) ) == 0 ) 1109 { 1110 char **refs; 1111 int j; 1112 1113 if ( rdi.rdi_ref != NULL ) { 1114 snprintf( c->cr_msg, sizeof(c->cr_msg), 1115 "\"ref\" already provided" ); 1116 Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 1117 c->log, c->cr_msg, 0 ); 1118 return ARG_BAD_CONF; 1119 } 1120 1121 if ( rdi.rdi_err != LDAP_REFERRAL ) { 1122 snprintf( c->cr_msg, sizeof(c->cr_msg), 1123 "providing \"ref\" " 1124 "along with a non-referral " 1125 "resultCode may cause slapd failures " 1126 "related to internal checks" ); 1127 Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 1128 c->log, c->cr_msg, 0 ); 1129 } 1130 1131 refs = ldap_str2charray( &c->argv[ i ][ STRLENOF( "ref=" ) ], " " ); 1132 assert( refs != NULL ); 1133 1134 for ( j = 0; refs[ j ] != NULL; j++ ) { 1135 struct berval bv; 1136 1137 ber_str2bv( refs[ j ], 0, 1, &bv ); 1138 ber_bvarray_add( &rdi.rdi_ref, &bv ); 1139 } 1140 1141 ldap_charray_free( refs ); 1142 1143 } else if ( strncasecmp( c->argv[ i ], "sleeptime=", STRLENOF( "sleeptime=" ) ) == 0 ) 1144 { 1145 if ( rdi.rdi_sleeptime != 0 ) { 1146 snprintf( c->cr_msg, sizeof(c->cr_msg), 1147 "\"sleeptime\" already provided" ); 1148 Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 1149 c->log, c->cr_msg, 0 ); 1150 return ARG_BAD_CONF; 1151 } 1152 1153 if ( lutil_atoi( &rdi.rdi_sleeptime, &c->argv[ i ][ STRLENOF( "sleeptime=" ) ] ) ) { 1154 snprintf( c->cr_msg, sizeof(c->cr_msg), 1155 "unable to parse \"sleeptime=%s\"", 1156 &c->argv[ i ][ STRLENOF( "sleeptime=" ) ] ); 1157 Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 1158 c->log, c->cr_msg, 0 ); 1159 return ARG_BAD_CONF; 1160 } 1161 1162 } else if ( strncasecmp( c->argv[ i ], "unsolicited=", STRLENOF( "unsolicited=" ) ) == 0 ) 1163 { 1164 char *data; 1165 1166 if ( !BER_BVISNULL( &rdi.rdi_unsolicited_oid ) ) { 1167 snprintf( c->cr_msg, sizeof(c->cr_msg), 1168 "\"unsolicited\" already provided" ); 1169 Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 1170 c->log, c->cr_msg, 0 ); 1171 return ARG_BAD_CONF; 1172 } 1173 1174 data = strchr( &c->argv[ i ][ STRLENOF( "unsolicited=" ) ], ':' ); 1175 if ( data != NULL ) { 1176 struct berval oid; 1177 1178 if ( ldif_parse_line2( &c->argv[ i ][ STRLENOF( "unsolicited=" ) ], 1179 &oid, &rdi.rdi_unsolicited_data, NULL ) ) 1180 { 1181 snprintf( c->cr_msg, sizeof(c->cr_msg), 1182 "unable to parse \"unsolicited\"" ); 1183 Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 1184 c->log, c->cr_msg, 0 ); 1185 return ARG_BAD_CONF; 1186 } 1187 1188 ber_dupbv( &rdi.rdi_unsolicited_oid, &oid ); 1189 1190 } else { 1191 ber_str2bv( &c->argv[ i ][ STRLENOF( "unsolicited=" ) ], 0, 1, 1192 &rdi.rdi_unsolicited_oid ); 1193 } 1194 1195 } else if ( strncasecmp( c->argv[ i ], "flags=", STRLENOF( "flags=" ) ) == 0 ) 1196 { 1197 char *arg = &c->argv[ i ][ STRLENOF( "flags=" ) ]; 1198 if ( strcasecmp( arg, "disconnect" ) == 0 ) { 1199 rdi.rdi_flags |= RDI_PRE_DISCONNECT; 1200 1201 } else if ( strcasecmp( arg, "pre-disconnect" ) == 0 ) { 1202 rdi.rdi_flags |= RDI_PRE_DISCONNECT; 1203 1204 } else if ( strcasecmp( arg, "post-disconnect" ) == 0 ) { 1205 rdi.rdi_flags |= RDI_POST_DISCONNECT; 1206 1207 } else { 1208 snprintf( c->cr_msg, sizeof(c->cr_msg), 1209 "unknown flag \"%s\"", arg ); 1210 Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 1211 c->log, c->cr_msg, 0 ); 1212 return ARG_BAD_CONF; 1213 } 1214 1215 } else { 1216 snprintf( c->cr_msg, sizeof(c->cr_msg), 1217 "unknown option \"%s\"", 1218 c->argv[ i ] ); 1219 Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n", 1220 c->log, c->cr_msg, 0 ); 1221 return ARG_BAD_CONF; 1222 } 1223 } 1224 } 1225 1226 rdi.rdi_line.bv_len = 2*(c->argc - 1) + c->argc - 2; 1227 for ( i = 1; i < c->argc; i++ ) { 1228 rdi.rdi_line.bv_len += strlen( c->argv[ i ] ); 1229 } 1230 next = rdi.rdi_line.bv_val = ch_malloc( rdi.rdi_line.bv_len + 1 ); 1231 1232 for ( i = 1; i < c->argc; i++ ) { 1233 *next++ = '"'; 1234 next = lutil_strcopy( next, c->argv[ i ] ); 1235 *next++ = '"'; 1236 *next++ = ' '; 1237 } 1238 *--next = '\0'; 1239 1240 for ( rdip = &rd->rd_item; *rdip; rdip = &(*rdip)->rdi_next ) 1241 /* go to last */ ; 1242 1243 1244 *rdip = ( retcode_item_t * )ch_malloc( sizeof( retcode_item_t ) ); 1245 *(*rdip) = rdi; 1246 1247 rc = 0; 1248 } break; 1249 1250 default: 1251 rc = SLAP_CONF_UNKNOWN; 1252 break; 1253 } 1254 1255 return rc; 1256 } 1257 1258 static int 1259 retcode_db_open( BackendDB *be, ConfigReply *cr) 1260 { 1261 slap_overinst *on = (slap_overinst *)be->bd_info; 1262 retcode_t *rd = (retcode_t *)on->on_bi.bi_private; 1263 1264 retcode_item_t *rdi; 1265 1266 for ( rdi = rd->rd_item; rdi; rdi = rdi->rdi_next ) { 1267 LDAPRDN rdn = NULL; 1268 int rc, j; 1269 char* p; 1270 struct berval val[ 3 ]; 1271 char buf[ SLAP_TEXT_BUFLEN ]; 1272 1273 /* DN */ 1274 rdi->rdi_e.e_name = rdi->rdi_dn; 1275 rdi->rdi_e.e_nname = rdi->rdi_ndn; 1276 1277 /* objectClass */ 1278 val[ 0 ] = oc_errObject->soc_cname; 1279 val[ 1 ] = slap_schema.si_oc_extensibleObject->soc_cname; 1280 BER_BVZERO( &val[ 2 ] ); 1281 1282 attr_merge( &rdi->rdi_e, slap_schema.si_ad_objectClass, val, NULL ); 1283 1284 /* RDN avas */ 1285 rc = ldap_bv2rdn( &rdi->rdi_dn, &rdn, (char **) &p, 1286 LDAP_DN_FORMAT_LDAP ); 1287 1288 assert( rc == LDAP_SUCCESS ); 1289 1290 for ( j = 0; rdn[ j ]; j++ ) { 1291 LDAPAVA *ava = rdn[ j ]; 1292 AttributeDescription *ad = NULL; 1293 const char *text; 1294 1295 rc = slap_bv2ad( &ava->la_attr, &ad, &text ); 1296 assert( rc == LDAP_SUCCESS ); 1297 1298 attr_merge_normalize_one( &rdi->rdi_e, ad, 1299 &ava->la_value, NULL ); 1300 } 1301 1302 ldap_rdnfree( rdn ); 1303 1304 /* error code */ 1305 snprintf( buf, sizeof( buf ), "%d", rdi->rdi_err ); 1306 ber_str2bv( buf, 0, 0, &val[ 0 ] ); 1307 1308 attr_merge_one( &rdi->rdi_e, ad_errCode, &val[ 0 ], NULL ); 1309 1310 if ( rdi->rdi_ref != NULL ) { 1311 attr_merge_normalize( &rdi->rdi_e, slap_schema.si_ad_ref, 1312 rdi->rdi_ref, NULL ); 1313 } 1314 1315 /* text */ 1316 if ( !BER_BVISNULL( &rdi->rdi_text ) ) { 1317 val[ 0 ] = rdi->rdi_text; 1318 1319 attr_merge_normalize_one( &rdi->rdi_e, ad_errText, &val[ 0 ], NULL ); 1320 } 1321 1322 /* matched */ 1323 if ( !BER_BVISNULL( &rdi->rdi_matched ) ) { 1324 val[ 0 ] = rdi->rdi_matched; 1325 1326 attr_merge_normalize_one( &rdi->rdi_e, ad_errMatchedDN, &val[ 0 ], NULL ); 1327 } 1328 1329 /* sleep time */ 1330 if ( rdi->rdi_sleeptime ) { 1331 snprintf( buf, sizeof( buf ), "%d", rdi->rdi_sleeptime ); 1332 ber_str2bv( buf, 0, 0, &val[ 0 ] ); 1333 1334 attr_merge_one( &rdi->rdi_e, ad_errSleepTime, &val[ 0 ], NULL ); 1335 } 1336 1337 /* operations */ 1338 if ( rdi->rdi_mask & SN_DG_OP_ADD ) { 1339 BER_BVSTR( &val[ 0 ], "add" ); 1340 attr_merge_normalize_one( &rdi->rdi_e, ad_errOp, &val[ 0 ], NULL ); 1341 } 1342 1343 if ( rdi->rdi_mask & SN_DG_OP_BIND ) { 1344 BER_BVSTR( &val[ 0 ], "bind" ); 1345 attr_merge_normalize_one( &rdi->rdi_e, ad_errOp, &val[ 0 ], NULL ); 1346 } 1347 1348 if ( rdi->rdi_mask & SN_DG_OP_COMPARE ) { 1349 BER_BVSTR( &val[ 0 ], "compare" ); 1350 attr_merge_normalize_one( &rdi->rdi_e, ad_errOp, &val[ 0 ], NULL ); 1351 } 1352 1353 if ( rdi->rdi_mask & SN_DG_OP_DELETE ) { 1354 BER_BVSTR( &val[ 0 ], "delete" ); 1355 attr_merge_normalize_one( &rdi->rdi_e, ad_errOp, &val[ 0 ], NULL ); 1356 } 1357 1358 if ( rdi->rdi_mask & SN_DG_EXTENDED ) { 1359 BER_BVSTR( &val[ 0 ], "extended" ); 1360 attr_merge_normalize_one( &rdi->rdi_e, ad_errOp, &val[ 0 ], NULL ); 1361 } 1362 1363 if ( rdi->rdi_mask & SN_DG_OP_MODIFY ) { 1364 BER_BVSTR( &val[ 0 ], "modify" ); 1365 attr_merge_normalize_one( &rdi->rdi_e, ad_errOp, &val[ 0 ], NULL ); 1366 } 1367 1368 if ( rdi->rdi_mask & SN_DG_OP_RENAME ) { 1369 BER_BVSTR( &val[ 0 ], "rename" ); 1370 attr_merge_normalize_one( &rdi->rdi_e, ad_errOp, &val[ 0 ], NULL ); 1371 } 1372 1373 if ( rdi->rdi_mask & SN_DG_OP_SEARCH ) { 1374 BER_BVSTR( &val[ 0 ], "search" ); 1375 attr_merge_normalize_one( &rdi->rdi_e, ad_errOp, &val[ 0 ], NULL ); 1376 } 1377 } 1378 1379 return 0; 1380 } 1381 1382 static int 1383 retcode_db_destroy( BackendDB *be, ConfigReply *cr ) 1384 { 1385 slap_overinst *on = (slap_overinst *)be->bd_info; 1386 retcode_t *rd = (retcode_t *)on->on_bi.bi_private; 1387 1388 if ( rd ) { 1389 retcode_item_t *rdi, *next; 1390 1391 for ( rdi = rd->rd_item; rdi != NULL; rdi = next ) { 1392 next = rdi->rdi_next; 1393 retcode_item_destroy( rdi ); 1394 } 1395 1396 if ( !BER_BVISNULL( &rd->rd_pdn ) ) { 1397 ber_memfree( rd->rd_pdn.bv_val ); 1398 } 1399 1400 if ( !BER_BVISNULL( &rd->rd_npdn ) ) { 1401 ber_memfree( rd->rd_npdn.bv_val ); 1402 } 1403 1404 ber_memfree( rd ); 1405 } 1406 1407 return 0; 1408 } 1409 1410 #if SLAPD_OVER_RETCODE == SLAPD_MOD_DYNAMIC 1411 static 1412 #endif /* SLAPD_OVER_RETCODE == SLAPD_MOD_DYNAMIC */ 1413 int 1414 retcode_initialize( void ) 1415 { 1416 int i, code; 1417 1418 static struct { 1419 char *desc; 1420 AttributeDescription **ad; 1421 } retcode_at[] = { 1422 { "( 1.3.6.1.4.1.4203.666.11.4.1.1 " 1423 "NAME ( 'errCode' ) " 1424 "DESC 'LDAP error code' " 1425 "EQUALITY integerMatch " 1426 "ORDERING integerOrderingMatch " 1427 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 " 1428 "SINGLE-VALUE )", 1429 &ad_errCode }, 1430 { "( 1.3.6.1.4.1.4203.666.11.4.1.2 " 1431 "NAME ( 'errOp' ) " 1432 "DESC 'Operations the errObject applies to' " 1433 "EQUALITY caseIgnoreMatch " 1434 "SUBSTR caseIgnoreSubstringsMatch " 1435 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )", 1436 &ad_errOp}, 1437 { "( 1.3.6.1.4.1.4203.666.11.4.1.3 " 1438 "NAME ( 'errText' ) " 1439 "DESC 'LDAP error textual description' " 1440 "EQUALITY caseIgnoreMatch " 1441 "SUBSTR caseIgnoreSubstringsMatch " 1442 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 " 1443 "SINGLE-VALUE )", 1444 &ad_errText }, 1445 { "( 1.3.6.1.4.1.4203.666.11.4.1.4 " 1446 "NAME ( 'errSleepTime' ) " 1447 "DESC 'Time to wait before returning the error' " 1448 "EQUALITY integerMatch " 1449 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 " 1450 "SINGLE-VALUE )", 1451 &ad_errSleepTime }, 1452 { "( 1.3.6.1.4.1.4203.666.11.4.1.5 " 1453 "NAME ( 'errMatchedDN' ) " 1454 "DESC 'Value to be returned as matched DN' " 1455 "EQUALITY distinguishedNameMatch " 1456 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 " 1457 "SINGLE-VALUE )", 1458 &ad_errMatchedDN }, 1459 { "( 1.3.6.1.4.1.4203.666.11.4.1.6 " 1460 "NAME ( 'errUnsolicitedOID' ) " 1461 "DESC 'OID to be returned within unsolicited response' " 1462 "EQUALITY objectIdentifierMatch " 1463 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 " 1464 "SINGLE-VALUE )", 1465 &ad_errUnsolicitedOID }, 1466 { "( 1.3.6.1.4.1.4203.666.11.4.1.7 " 1467 "NAME ( 'errUnsolicitedData' ) " 1468 "DESC 'Data to be returned within unsolicited response' " 1469 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 " 1470 "SINGLE-VALUE )", 1471 &ad_errUnsolicitedData }, 1472 { "( 1.3.6.1.4.1.4203.666.11.4.1.8 " 1473 "NAME ( 'errDisconnect' ) " 1474 "DESC 'Disconnect without notice' " 1475 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 " 1476 "SINGLE-VALUE )", 1477 &ad_errDisconnect }, 1478 { NULL } 1479 }; 1480 1481 static struct { 1482 char *desc; 1483 ObjectClass **oc; 1484 } retcode_oc[] = { 1485 { "( 1.3.6.1.4.1.4203.666.11.4.3.0 " 1486 "NAME ( 'errAbsObject' ) " 1487 "SUP top ABSTRACT " 1488 "MUST ( errCode ) " 1489 "MAY ( " 1490 "cn " 1491 "$ description " 1492 "$ errOp " 1493 "$ errText " 1494 "$ errSleepTime " 1495 "$ errMatchedDN " 1496 "$ errUnsolicitedOID " 1497 "$ errUnsolicitedData " 1498 "$ errDisconnect " 1499 ") )", 1500 &oc_errAbsObject }, 1501 { "( 1.3.6.1.4.1.4203.666.11.4.3.1 " 1502 "NAME ( 'errObject' ) " 1503 "SUP errAbsObject STRUCTURAL " 1504 ")", 1505 &oc_errObject }, 1506 { "( 1.3.6.1.4.1.4203.666.11.4.3.2 " 1507 "NAME ( 'errAuxObject' ) " 1508 "SUP errAbsObject AUXILIARY " 1509 ")", 1510 &oc_errAuxObject }, 1511 { NULL } 1512 }; 1513 1514 1515 for ( i = 0; retcode_at[ i ].desc != NULL; i++ ) { 1516 code = register_at( retcode_at[ i ].desc, retcode_at[ i ].ad, 0 ); 1517 if ( code ) { 1518 Debug( LDAP_DEBUG_ANY, 1519 "retcode: register_at failed\n", 0, 0, 0 ); 1520 return code; 1521 } 1522 1523 (*retcode_at[ i ].ad)->ad_type->sat_flags |= SLAP_AT_HIDE; 1524 } 1525 1526 for ( i = 0; retcode_oc[ i ].desc != NULL; i++ ) { 1527 code = register_oc( retcode_oc[ i ].desc, retcode_oc[ i ].oc, 0 ); 1528 if ( code ) { 1529 Debug( LDAP_DEBUG_ANY, 1530 "retcode: register_oc failed\n", 0, 0, 0 ); 1531 return code; 1532 } 1533 1534 (*retcode_oc[ i ].oc)->soc_flags |= SLAP_OC_HIDE; 1535 } 1536 1537 retcode.on_bi.bi_type = "retcode"; 1538 1539 retcode.on_bi.bi_db_init = retcode_db_init; 1540 retcode.on_bi.bi_db_open = retcode_db_open; 1541 retcode.on_bi.bi_db_destroy = retcode_db_destroy; 1542 1543 retcode.on_bi.bi_op_add = retcode_op_func; 1544 retcode.on_bi.bi_op_bind = retcode_op_func; 1545 retcode.on_bi.bi_op_compare = retcode_op_func; 1546 retcode.on_bi.bi_op_delete = retcode_op_func; 1547 retcode.on_bi.bi_op_modify = retcode_op_func; 1548 retcode.on_bi.bi_op_modrdn = retcode_op_func; 1549 retcode.on_bi.bi_op_search = retcode_op_func; 1550 1551 retcode.on_bi.bi_extended = retcode_op_func; 1552 1553 retcode.on_response = retcode_response; 1554 1555 retcode.on_bi.bi_cf_ocs = rcocs; 1556 1557 code = config_register_schema( rccfg, rcocs ); 1558 if ( code ) { 1559 return code; 1560 } 1561 1562 return overlay_register( &retcode ); 1563 } 1564 1565 #if SLAPD_OVER_RETCODE == SLAPD_MOD_DYNAMIC 1566 int 1567 init_module( int argc, char *argv[] ) 1568 { 1569 return retcode_initialize(); 1570 } 1571 #endif /* SLAPD_OVER_RETCODE == SLAPD_MOD_DYNAMIC */ 1572 1573 #endif /* SLAPD_OVER_RETCODE */ 1574