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