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