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