1 /* retcode.c - customizable response for client testing purposes */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2005-2006 The OpenLDAP Foundation.
6 * Portions Copyright 2005 Pierangelo Masarati <ando@sys-net.it>
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted only as authorized by the OpenLDAP
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>.
18 * This work was initially developed by Pierangelo Masarati for inclusion
19 * in OpenLDAP Software.
24 #ifdef SLAPD_OVER_RETCODE
28 #include <ac/unistd.h>
29 #include <ac/string.h>
31 #include <ac/socket.h>
36 static slap_overinst retcode;
38 static AttributeDescription *ad_errCode;
39 static AttributeDescription *ad_errText;
40 static AttributeDescription *ad_errOp;
41 static AttributeDescription *ad_errSleepTime;
42 static AttributeDescription *ad_errMatchedDN;
43 static ObjectClass *oc_errAbsObject;
44 static ObjectClass *oc_errObject;
45 static ObjectClass *oc_errAuxObject;
47 typedef enum retcode_op_e {
48 SN_DG_OP_NONE = 0x0000,
49 SN_DG_OP_ADD = 0x0001,
50 SN_DG_OP_BIND = 0x0002,
51 SN_DG_OP_COMPARE = 0x0004,
52 SN_DG_OP_DELETE = 0x0008,
53 SN_DG_OP_MODIFY = 0x0010,
54 SN_DG_OP_RENAME = 0x0020,
55 SN_DG_OP_SEARCH = 0x0040,
56 SN_DG_EXTENDED = 0x0080,
57 SN_DG_OP_AUTH = SN_DG_OP_BIND,
58 SN_DG_OP_READ = (SN_DG_OP_COMPARE|SN_DG_OP_SEARCH),
59 SN_DG_OP_WRITE = (SN_DG_OP_ADD|SN_DG_OP_DELETE|SN_DG_OP_MODIFY|SN_DG_OP_RENAME),
60 SN_DG_OP_ALL = (SN_DG_OP_AUTH|SN_DG_OP_READ|SN_DG_OP_WRITE|SN_DG_EXTENDED)
63 typedef struct retcode_item_t {
65 struct berval rdi_ndn;
66 struct berval rdi_text;
67 struct berval rdi_matched;
73 struct retcode_item_t *rdi_next;
76 typedef struct retcode_t {
78 struct berval rd_npdn;
82 retcode_item_t *rd_item;
85 #define RETCODE_FNONE 0x00
86 #define RETCODE_FINDIR 0x01
87 #define RETCODE_INDIR( rd ) ( (rd)->rd_flags & RETCODE_FINDIR )
91 retcode_entry_response( Operation *op, SlapReply *rs, BackendInfo *bi, Entry *e );
94 retcode_sleep( int s )
96 /* sleep as required */
98 #if 0 /* use high-order bits for better randomness (Numerical Recipes in "C") */
99 unsigned r = rand() % (-s);
101 unsigned r = ((double)(-s))*rand()/(RAND_MAX + 1.0);
106 return sleep( (unsigned int)s );
113 retcode_cleanup_cb( Operation *op, SlapReply *rs )
115 rs->sr_matched = NULL;
118 if ( rs->sr_ref != NULL ) {
119 ber_bvarray_free( rs->sr_ref );
123 ch_free( op->o_callback );
124 op->o_callback = NULL;
126 return SLAP_CB_CONTINUE;
130 retcode_send_onelevel( Operation *op, SlapReply *rs )
132 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
133 retcode_t *rd = (retcode_t *)on->on_bi.bi_private;
137 for ( rdi = rd->rd_item; rdi != NULL; rdi = rdi->rdi_next ) {
138 if ( op->o_abandon ) {
139 return rs->sr_err = SLAPD_ABANDON;
142 rs->sr_err = test_filter( op, &rdi->rdi_e, op->ors_filter );
143 if ( rs->sr_err == LDAP_COMPARE_TRUE ) {
144 if ( op->ors_slimit == rs->sr_nentries ) {
145 rs->sr_err = LDAP_SIZELIMIT_EXCEEDED;
150 rs->sr_attrs = op->ors_attrs;
151 rs->sr_operational_attrs = NULL;
154 rs->sr_err = LDAP_SUCCESS;
155 rs->sr_entry = &rdi->rdi_e;
157 rs->sr_err = send_search_entry( op, rs );
160 switch ( rs->sr_err ) {
161 case LDAP_UNAVAILABLE: /* connection closed */
162 rs->sr_err = LDAP_OTHER;
164 case LDAP_SIZELIMIT_EXCEEDED:
168 rs->sr_err = LDAP_SUCCESS;
173 send_ldap_result( op, rs );
179 retcode_op_add( Operation *op, SlapReply *rs )
181 return retcode_entry_response( op, rs, NULL, op->ora_e );
184 typedef struct retcode_cb_t {
185 BackendInfo *rdc_info;
188 AttributeName *rdc_attrs;
192 retcode_cb_response( Operation *op, SlapReply *rs )
194 retcode_cb_t *rdc = (retcode_cb_t *)op->o_callback->sc_private;
196 if ( rs->sr_type == REP_SEARCH ) {
197 ber_tag_t o_tag = op->o_tag;
200 op->o_tag = rdc->rdc_tag;
201 if ( op->o_tag == LDAP_REQ_SEARCH ) {
202 rs->sr_attrs = rdc->rdc_attrs;
204 rc = retcode_entry_response( op, rs, rdc->rdc_info, rs->sr_entry );
210 if ( rs->sr_err == LDAP_SUCCESS ) {
211 if ( !op->o_abandon ) {
212 rdc->rdc_flags = SLAP_CB_CONTINUE;
217 return SLAP_CB_CONTINUE;
221 retcode_op_internal( Operation *op, SlapReply *rs )
223 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
226 BackendDB db = *op->o_bd;
227 slap_callback sc = { 0 };
232 op2.o_tag = LDAP_REQ_SEARCH;
233 op2.ors_scope = LDAP_SCOPE_BASE;
234 op2.ors_deref = LDAP_DEREF_NEVER;
235 op2.ors_tlimit = SLAP_NO_LIMIT;
236 op2.ors_slimit = SLAP_NO_LIMIT;
237 op2.ors_limit = NULL;
238 op2.ors_attrsonly = 0;
239 op2.ors_attrs = slap_anlist_all_attributes;
241 ber_str2bv_x( "(objectClass=errAbsObject)",
242 STRLENOF( "(objectClass=errAbsObject)" ),
243 1, &op2.ors_filterstr, op2.o_tmpmemctx );
244 op2.ors_filter = str2filter_x( &op2, op2.ors_filterstr.bv_val );
246 db.bd_info = on->on_info->oi_orig;
249 rdc.rdc_info = on->on_info->oi_orig;
250 rdc.rdc_flags = RETCODE_FINDIR;
251 if ( op->o_tag == LDAP_REQ_SEARCH ) {
252 rdc.rdc_attrs = op->ors_attrs;
254 rdc.rdc_tag = op->o_tag;
255 sc.sc_response = retcode_cb_response;
256 sc.sc_private = &rdc;
257 op2.o_callback = ≻
259 rc = op2.o_bd->be_search( &op2, rs );
260 op->o_abandon = op2.o_abandon;
262 filter_free_x( &op2, op2.ors_filter );
263 ber_memfree_x( op2.ors_filterstr.bv_val, op2.o_tmpmemctx );
265 if ( rdc.rdc_flags == SLAP_CB_CONTINUE ) {
266 return SLAP_CB_CONTINUE;
273 retcode_op_func( Operation *op, SlapReply *rs )
275 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
276 retcode_t *rd = (retcode_t *)on->on_bi.bi_private;
279 struct berval nrdn, npdn;
281 slap_callback *cb = NULL;
283 /* sleep as required */
284 retcode_sleep( rd->rd_sleep );
286 if ( !dnIsSuffix( &op->o_req_ndn, &rd->rd_npdn ) ) {
287 if ( RETCODE_INDIR( rd ) ) {
288 switch ( op->o_tag ) {
290 return retcode_op_add( op, rs );
294 if ( be_isroot_pw( op ) ) {
295 return SLAP_CB_CONTINUE;
297 return retcode_op_internal( op, rs );
299 case LDAP_REQ_SEARCH:
300 if ( op->ors_scope == LDAP_SCOPE_BASE ) {
301 rs->sr_err = retcode_op_internal( op, rs );
302 switch ( rs->sr_err ) {
303 case SLAP_CB_CONTINUE:
304 if ( rs->sr_nentries == 0 ) {
307 rs->sr_err = LDAP_SUCCESS;
311 send_ldap_result( op, rs );
318 case LDAP_REQ_MODIFY:
319 case LDAP_REQ_DELETE:
320 case LDAP_REQ_MODRDN:
321 case LDAP_REQ_COMPARE:
322 return retcode_op_internal( op, rs );
326 return SLAP_CB_CONTINUE;
329 if ( op->o_tag == LDAP_REQ_SEARCH
330 && op->ors_scope != LDAP_SCOPE_BASE
331 && op->o_req_ndn.bv_len == rd->rd_npdn.bv_len )
333 return retcode_send_onelevel( op, rs );
336 dnParent( &op->o_req_ndn, &npdn );
337 if ( npdn.bv_len != rd->rd_npdn.bv_len ) {
338 rs->sr_err = LDAP_NO_SUCH_OBJECT;
339 rs->sr_matched = rd->rd_pdn.bv_val;
340 send_ldap_result( op, rs );
341 rs->sr_matched = NULL;
345 dnRdn( &op->o_req_ndn, &nrdn );
347 for ( rdi = rd->rd_item; rdi != NULL; rdi = rdi->rdi_next ) {
348 struct berval rdi_nrdn;
350 dnRdn( &rdi->rdi_ndn, &rdi_nrdn );
351 if ( dn_match( &nrdn, &rdi_nrdn ) ) {
356 if ( rdi != NULL && rdi->rdi_mask != SN_DG_OP_ALL ) {
357 retcode_op_e o_tag = SN_DG_OP_NONE;
359 switch ( op->o_tag ) {
361 o_tag = SN_DG_OP_ADD;
365 o_tag = SN_DG_OP_BIND;
368 case LDAP_REQ_COMPARE:
369 o_tag = SN_DG_OP_COMPARE;
372 case LDAP_REQ_DELETE:
373 o_tag = SN_DG_OP_DELETE;
376 case LDAP_REQ_MODIFY:
377 o_tag = SN_DG_OP_MODIFY;
380 case LDAP_REQ_MODRDN:
381 o_tag = SN_DG_OP_RENAME;
384 case LDAP_REQ_SEARCH:
385 o_tag = SN_DG_OP_SEARCH;
388 case LDAP_REQ_EXTENDED:
389 o_tag = SN_DG_EXTENDED;
393 /* Should not happen */
397 if ( !( o_tag & rdi->rdi_mask ) ) {
398 return SLAP_CB_CONTINUE;
403 rs->sr_matched = rd->rd_pdn.bv_val;
404 rs->sr_err = LDAP_NO_SUCH_OBJECT;
405 rs->sr_text = "retcode not found";
408 rs->sr_err = rdi->rdi_err;
409 rs->sr_text = rdi->rdi_text.bv_val;
410 rs->sr_matched = rdi->rdi_matched.bv_val;
412 /* FIXME: we only honor the rdi_ref field in case rdi_err
413 * is LDAP_REFERRAL otherwise send_ldap_result() bails out */
414 if ( rs->sr_err == LDAP_REFERRAL ) {
417 if ( rdi->rdi_ref != NULL ) {
420 ref = default_referral;
424 rs->sr_ref = referral_rewrite( ref,
425 NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );
428 rs->sr_err = LDAP_OTHER;
429 rs->sr_text = "bad referral object";
433 retcode_sleep( rdi->rdi_sleeptime );
436 switch ( op->o_tag ) {
437 case LDAP_REQ_EXTENDED:
441 cb = ( slap_callback * )ch_malloc( sizeof( slap_callback ) );
442 memset( cb, 0, sizeof( slap_callback ) );
443 cb->sc_cleanup = retcode_cleanup_cb;
448 send_ldap_result( op, rs );
449 if ( rs->sr_ref != NULL ) {
450 ber_bvarray_free( rs->sr_ref );
453 rs->sr_matched = NULL;
462 retcode_op2str( ber_tag_t op, struct berval *bv )
466 BER_BVSTR( bv, "bind" );
469 BER_BVSTR( bv, "add" );
471 case LDAP_REQ_DELETE:
472 BER_BVSTR( bv, "delete" );
474 case LDAP_REQ_MODRDN:
475 BER_BVSTR( bv, "modrdn" );
477 case LDAP_REQ_MODIFY:
478 BER_BVSTR( bv, "modify" );
480 case LDAP_REQ_COMPARE:
481 BER_BVSTR( bv, "compare" );
483 case LDAP_REQ_SEARCH:
484 BER_BVSTR( bv, "search" );
486 case LDAP_REQ_EXTENDED:
487 BER_BVSTR( bv, "extended" );
494 retcode_entry_response( Operation *op, SlapReply *rs, BackendInfo *bi, Entry *e )
500 if ( get_manageDSAit( op ) ) {
501 return SLAP_CB_CONTINUE;
504 if ( !is_entry_objectclass_or_sub( e, oc_errAbsObject ) ) {
505 return SLAP_CB_CONTINUE;
509 a = attr_find( e->e_attrs, ad_errOp );
513 struct berval bv = BER_BVNULL;
515 (void)retcode_op2str( op->o_tag, &bv );
517 if ( BER_BVISNULL( &bv ) ) {
518 return SLAP_CB_CONTINUE;
521 for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) {
522 if ( bvmatch( &a->a_nvals[ i ], &bv ) ) {
529 return SLAP_CB_CONTINUE;
534 a = attr_find( e->e_attrs, ad_errCode );
536 return SLAP_CB_CONTINUE;
538 err = strtol( a->a_nvals[ 0 ].bv_val, &next, 0 );
539 if ( next == a->a_nvals[ 0 ].bv_val || next[ 0 ] != '\0' ) {
540 return SLAP_CB_CONTINUE;
545 a = attr_find( e->e_attrs, ad_errSleepTime );
546 if ( a != NULL && a->a_nvals[ 0 ].bv_val[ 0 ] != '-' ) {
549 if ( lutil_atoi( &sleepTime, a->a_nvals[ 0 ].bv_val ) == 0 ) {
550 retcode_sleep( sleepTime );
554 if ( rs->sr_err != LDAP_SUCCESS ) {
555 BackendDB db = *op->o_bd,
557 void *o_callback = op->o_callback;
560 a = attr_find( e->e_attrs, ad_errText );
562 rs->sr_text = a->a_vals[ 0 ].bv_val;
566 a = attr_find( e->e_attrs, ad_errMatchedDN );
568 rs->sr_matched = a->a_vals[ 0 ].bv_val;
572 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
574 bi = on->on_info->oi_orig;
579 op->o_callback = NULL;
582 if ( rs->sr_err == LDAP_REFERRAL ) {
583 BerVarray refs = default_referral;
585 a = attr_find( e->e_attrs, slap_schema.si_ad_ref );
589 rs->sr_ref = referral_rewrite( refs,
590 NULL, &op->o_req_dn, op->oq_search.rs_scope );
592 send_search_reference( op, rs );
593 ber_bvarray_free( rs->sr_ref );
597 send_ldap_result( op, rs );
601 rs->sr_matched = NULL;
603 op->o_callback = o_callback;
606 if ( rs->sr_err != LDAP_SUCCESS ) {
611 return SLAP_CB_CONTINUE;
615 retcode_response( Operation *op, SlapReply *rs )
617 slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
618 retcode_t *rd = (retcode_t *)on->on_bi.bi_private;
620 if ( rs->sr_type != REP_SEARCH || !RETCODE_INDIR( rd ) ) {
621 return SLAP_CB_CONTINUE;
624 return retcode_entry_response( op, rs, NULL, rs->sr_entry );
628 retcode_db_init( BackendDB *be )
630 slap_overinst *on = (slap_overinst *)be->bd_info;
635 rd = (retcode_t *)ch_malloc( sizeof( retcode_t ) );
636 memset( rd, 0, sizeof( retcode_t ) );
638 on->on_bi.bi_private = (void *)rd;
651 slap_overinst *on = (slap_overinst *)be->bd_info;
652 retcode_t *rd = (retcode_t *)on->on_bi.bi_private;
654 char *argv0 = argv[ 0 ] + STRLENOF( "retcode-" );
656 if ( strncasecmp( argv[ 0 ], "retcode-", STRLENOF( "retcode-" ) ) != 0 ) {
657 return SLAP_CONF_UNKNOWN;
660 if ( strcasecmp( argv0, "parent" ) == 0 ) {
665 fprintf( stderr, "%s: line %d: retcode: "
666 "\"retcode-parent <DN>\": missing <DN>\n",
671 if ( !BER_BVISNULL( &rd->rd_pdn ) ) {
672 fprintf( stderr, "%s: line %d: retcode: "
673 "parent already defined.\n", fname, lineno );
677 ber_str2bv( argv[ 1 ], 0, 0, &dn );
679 rc = dnPrettyNormal( NULL, &dn, &rd->rd_pdn, &rd->rd_npdn, NULL );
680 if ( rc != LDAP_SUCCESS ) {
681 fprintf( stderr, "%s: line %d: retcode: "
682 "unable to normalize parent DN \"%s\": %d\n",
683 fname, lineno, argv[ 1 ], rc );
687 } else if ( strcasecmp( argv0, "item" ) == 0 ) {
688 retcode_item_t rdi = { BER_BVNULL }, **rdip;
689 struct berval bv, rdn, nrdn;
694 fprintf( stderr, "%s: line %d: retcode: "
695 "\"retcode-item <RDN> <retcode> [<text>]\": "
701 ber_str2bv( argv[ 1 ], 0, 0, &bv );
703 rc = dnPrettyNormal( NULL, &bv, &rdn, &nrdn, NULL );
704 if ( rc != LDAP_SUCCESS ) {
705 fprintf( stderr, "%s: line %d: retcode: "
706 "unable to normalize RDN \"%s\": %d\n",
707 fname, lineno, argv[ 1 ], rc );
711 if ( !dnIsOneLevelRDN( &nrdn ) ) {
712 fprintf( stderr, "%s: line %d: retcode: "
713 "value \"%s\" is not a RDN\n",
714 fname, lineno, argv[ 1 ] );
718 if ( BER_BVISNULL( &rd->rd_npdn ) ) {
719 /* FIXME: we use the database suffix */
720 if ( be->be_nsuffix == NULL ) {
721 fprintf( stderr, "%s: line %d: retcode: "
722 "either \"retcode-parent\" "
723 "or \"suffix\" must be defined.\n",
728 ber_dupbv( &rd->rd_pdn, &be->be_suffix[ 0 ] );
729 ber_dupbv( &rd->rd_npdn, &be->be_nsuffix[ 0 ] );
732 build_new_dn( &rdi.rdi_dn, &rd->rd_pdn, &rdn, NULL );
733 build_new_dn( &rdi.rdi_ndn, &rd->rd_npdn, &nrdn, NULL );
735 ch_free( rdn.bv_val );
736 ch_free( nrdn.bv_val );
738 rdi.rdi_err = strtol( argv[ 2 ], &next, 0 );
739 if ( next == argv[ 2 ] || next[ 0 ] != '\0' ) {
740 fprintf( stderr, "%s: line %d: retcode: "
741 "unable to parse return code \"%s\"\n",
742 fname, lineno, argv[ 2 ] );
746 rdi.rdi_mask = SN_DG_OP_ALL;
751 for ( i = 3; i < argc; i++ ) {
752 if ( strncasecmp( argv[ i ], "op=", STRLENOF( "op=" ) ) == 0 )
757 ops = ldap_str2charray( &argv[ i ][ STRLENOF( "op=" ) ], "," );
758 assert( ops != NULL );
760 rdi.rdi_mask = SN_DG_OP_NONE;
762 for ( j = 0; ops[ j ] != NULL; j++ ) {
763 if ( strcasecmp( ops[ j ], "add" ) == 0 ) {
764 rdi.rdi_mask |= SN_DG_OP_ADD;
766 } else if ( strcasecmp( ops[ j ], "bind" ) == 0 ) {
767 rdi.rdi_mask |= SN_DG_OP_BIND;
769 } else if ( strcasecmp( ops[ j ], "compare" ) == 0 ) {
770 rdi.rdi_mask |= SN_DG_OP_COMPARE;
772 } else if ( strcasecmp( ops[ j ], "delete" ) == 0 ) {
773 rdi.rdi_mask |= SN_DG_OP_DELETE;
775 } else if ( strcasecmp( ops[ j ], "modify" ) == 0 ) {
776 rdi.rdi_mask |= SN_DG_OP_MODIFY;
778 } else if ( strcasecmp( ops[ j ], "rename" ) == 0
779 || strcasecmp( ops[ j ], "modrdn" ) == 0 )
781 rdi.rdi_mask |= SN_DG_OP_RENAME;
783 } else if ( strcasecmp( ops[ j ], "search" ) == 0 ) {
784 rdi.rdi_mask |= SN_DG_OP_SEARCH;
786 } else if ( strcasecmp( ops[ j ], "extended" ) == 0 ) {
787 rdi.rdi_mask |= SN_DG_EXTENDED;
789 } else if ( strcasecmp( ops[ j ], "auth" ) == 0 ) {
790 rdi.rdi_mask |= SN_DG_OP_AUTH;
792 } else if ( strcasecmp( ops[ j ], "read" ) == 0 ) {
793 rdi.rdi_mask |= SN_DG_OP_READ;
795 } else if ( strcasecmp( ops[ j ], "write" ) == 0 ) {
796 rdi.rdi_mask |= SN_DG_OP_WRITE;
798 } else if ( strcasecmp( ops[ j ], "all" ) == 0 ) {
799 rdi.rdi_mask |= SN_DG_OP_ALL;
802 fprintf( stderr, "retcode: unknown op \"%s\"\n",
804 ldap_charray_free( ops );
809 ldap_charray_free( ops );
811 } else if ( strncasecmp( argv[ i ], "text=", STRLENOF( "text=" ) ) == 0 )
813 if ( !BER_BVISNULL( &rdi.rdi_text ) ) {
814 fprintf( stderr, "%s: line %d: retcode: "
815 "\"text\" already provided.\n",
819 ber_str2bv( &argv[ i ][ STRLENOF( "text=" ) ], 0, 1, &rdi.rdi_text );
821 } else if ( strncasecmp( argv[ i ], "matched=", STRLENOF( "matched=" ) ) == 0 )
825 if ( !BER_BVISNULL( &rdi.rdi_matched ) ) {
826 fprintf( stderr, "%s: line %d: retcode: "
827 "\"matched\" already provided.\n",
831 ber_str2bv( &argv[ i ][ STRLENOF( "matched=" ) ], 0, 0, &dn );
832 if ( dnPretty( NULL, &dn, &rdi.rdi_matched, NULL ) != LDAP_SUCCESS ) {
833 fprintf( stderr, "%s: line %d: retcode: "
834 "unable to prettify matched DN \"%s\".\n",
835 fname, lineno, &argv[ i ][ STRLENOF( "matched=" ) ] );
839 } else if ( strncasecmp( argv[ i ], "ref=", STRLENOF( "ref=" ) ) == 0 )
844 if ( rdi.rdi_ref != NULL ) {
845 fprintf( stderr, "%s: line %d: retcode: "
846 "\"ref\" already provided.\n",
851 if ( rdi.rdi_err != LDAP_REFERRAL ) {
852 fprintf( stderr, "%s: line %d: retcode: "
853 "providing \"ref\"\n"
854 "\talong with a non-referral "
855 "resultCode may cause slapd failures\n"
856 "\trelated to internal checks.\n",
860 refs = ldap_str2charray( &argv[ i ][ STRLENOF( "ref=" ) ], " " );
861 assert( refs != NULL );
863 for ( j = 0; refs[ j ] != NULL; j++ ) {
866 ber_str2bv( refs[ j ], 0, 1, &bv );
867 ber_bvarray_add( &rdi.rdi_ref, &bv );
870 ldap_charray_free( refs );
872 } else if ( strncasecmp( argv[ i ], "sleeptime=", STRLENOF( "sleeptime=" ) ) == 0 )
874 if ( rdi.rdi_sleeptime != 0 ) {
875 fprintf( stderr, "%s: line %d: retcode: "
876 "\"sleeptime\" already provided.\n",
881 if ( lutil_atoi( &rdi.rdi_sleeptime, &argv[ i ][ STRLENOF( "sleeptime=" ) ] ) ) {
882 fprintf( stderr, "%s: line %d: retcode: "
883 "unable to parse \"sleeptime=%s\".\n",
884 fname, lineno, &argv[ i ][ STRLENOF( "sleeptime=" ) ] );
889 fprintf( stderr, "%s: line %d: retcode: "
890 "unknown option \"%s\".\n",
891 fname, lineno, argv[ i ] );
897 for ( rdip = &rd->rd_item; *rdip; rdip = &(*rdip)->rdi_next )
901 *rdip = ( retcode_item_t * )ch_malloc( sizeof( retcode_item_t ) );
904 } else if ( strcasecmp( argv0, "indir" ) == 0 ) {
905 rd->rd_flags |= RETCODE_FINDIR;
907 } else if ( strcasecmp( argv0, "sleep" ) == 0 ) {
910 fprintf( stderr, "%s: line %d: retcode: "
911 "\"retcode-sleep <time>\": missing <time>\n",
919 fprintf( stderr, "%s: line %d: retcode: "
920 "\"retcode-sleep <time>\": extra cruft after <time>\n",
925 if ( lutil_atoi( &rd->rd_sleep, argv[ 1 ] ) != 0 ) {
926 fprintf( stderr, "%s: line %d: retcode: "
927 "\"retcode-sleep <time>\": unable to parse <time>\n",
933 return SLAP_CONF_UNKNOWN;
940 retcode_db_open( BackendDB *be )
942 slap_overinst *on = (slap_overinst *)be->bd_info;
943 retcode_t *rd = (retcode_t *)on->on_bi.bi_private;
947 for ( rdi = rd->rd_item; rdi; rdi = rdi->rdi_next ) {
951 struct berval val[ 3 ];
952 char buf[ SLAP_TEXT_BUFLEN ];
955 rdi->rdi_e.e_name = rdi->rdi_dn;
956 rdi->rdi_e.e_nname = rdi->rdi_ndn;
959 val[ 0 ] = oc_errObject->soc_cname;
960 val[ 1 ] = slap_schema.si_oc_extensibleObject->soc_cname;
961 BER_BVZERO( &val[ 2 ] );
963 attr_merge( &rdi->rdi_e, slap_schema.si_ad_objectClass, val, NULL );
966 rc = ldap_bv2rdn( &rdi->rdi_dn, &rdn, (char **) &p,
967 LDAP_DN_FORMAT_LDAP );
969 assert( rc == LDAP_SUCCESS );
971 for ( j = 0; rdn[ j ]; j++ ) {
972 LDAPAVA *ava = rdn[ j ];
973 AttributeDescription *ad = NULL;
976 rc = slap_bv2ad( &ava->la_attr, &ad, &text );
977 assert( rc == LDAP_SUCCESS );
979 attr_merge_normalize_one( &rdi->rdi_e, ad,
980 &ava->la_value, NULL );
986 snprintf( buf, sizeof( buf ), "%d", rdi->rdi_err );
987 ber_str2bv( buf, 0, 0, &val[ 0 ] );
989 attr_merge_one( &rdi->rdi_e, ad_errCode, &val[ 0 ], NULL );
991 if ( rdi->rdi_ref != NULL ) {
992 attr_merge_normalize( &rdi->rdi_e, slap_schema.si_ad_ref,
993 rdi->rdi_ref, NULL );
997 if ( !BER_BVISNULL( &rdi->rdi_text ) ) {
998 val[ 0 ] = rdi->rdi_text;
1000 attr_merge_normalize_one( &rdi->rdi_e, ad_errText, &val[ 0 ], NULL );
1004 if ( !BER_BVISNULL( &rdi->rdi_matched ) ) {
1005 val[ 0 ] = rdi->rdi_matched;
1007 attr_merge_normalize_one( &rdi->rdi_e, ad_errMatchedDN, &val[ 0 ], NULL );
1011 if ( rdi->rdi_sleeptime ) {
1012 snprintf( buf, sizeof( buf ), "%d", rdi->rdi_sleeptime );
1013 ber_str2bv( buf, 0, 0, &val[ 0 ] );
1015 attr_merge_one( &rdi->rdi_e, ad_errSleepTime, &val[ 0 ], NULL );
1019 if ( rdi->rdi_mask & SN_DG_OP_ADD ) {
1020 BER_BVSTR( &val[ 0 ], "add" );
1021 attr_merge_normalize_one( &rdi->rdi_e, ad_errOp, &val[ 0 ], NULL );
1024 if ( rdi->rdi_mask & SN_DG_OP_BIND ) {
1025 BER_BVSTR( &val[ 0 ], "bind" );
1026 attr_merge_normalize_one( &rdi->rdi_e, ad_errOp, &val[ 0 ], NULL );
1029 if ( rdi->rdi_mask & SN_DG_OP_COMPARE ) {
1030 BER_BVSTR( &val[ 0 ], "compare" );
1031 attr_merge_normalize_one( &rdi->rdi_e, ad_errOp, &val[ 0 ], NULL );
1034 if ( rdi->rdi_mask & SN_DG_OP_DELETE ) {
1035 BER_BVSTR( &val[ 0 ], "delete" );
1036 attr_merge_normalize_one( &rdi->rdi_e, ad_errOp, &val[ 0 ], NULL );
1039 if ( rdi->rdi_mask & SN_DG_EXTENDED ) {
1040 BER_BVSTR( &val[ 0 ], "extended" );
1041 attr_merge_normalize_one( &rdi->rdi_e, ad_errOp, &val[ 0 ], NULL );
1044 if ( rdi->rdi_mask & SN_DG_OP_MODIFY ) {
1045 BER_BVSTR( &val[ 0 ], "modify" );
1046 attr_merge_normalize_one( &rdi->rdi_e, ad_errOp, &val[ 0 ], NULL );
1049 if ( rdi->rdi_mask & SN_DG_OP_RENAME ) {
1050 BER_BVSTR( &val[ 0 ], "rename" );
1051 attr_merge_normalize_one( &rdi->rdi_e, ad_errOp, &val[ 0 ], NULL );
1054 if ( rdi->rdi_mask & SN_DG_OP_SEARCH ) {
1055 BER_BVSTR( &val[ 0 ], "search" );
1056 attr_merge_normalize_one( &rdi->rdi_e, ad_errOp, &val[ 0 ], NULL );
1064 retcode_db_destroy( BackendDB *be )
1066 slap_overinst *on = (slap_overinst *)be->bd_info;
1067 retcode_t *rd = (retcode_t *)on->on_bi.bi_private;
1070 retcode_item_t *rdi, *next;
1072 for ( rdi = rd->rd_item; rdi != NULL; rdi = next ) {
1073 ber_memfree( rdi->rdi_dn.bv_val );
1074 ber_memfree( rdi->rdi_ndn.bv_val );
1076 if ( !BER_BVISNULL( &rdi->rdi_text ) ) {
1077 ber_memfree( rdi->rdi_text.bv_val );
1080 if ( !BER_BVISNULL( &rdi->rdi_matched ) ) {
1081 ber_memfree( rdi->rdi_matched.bv_val );
1084 if ( rdi->rdi_ref ) {
1085 ber_bvarray_free( rdi->rdi_ref );
1088 BER_BVZERO( &rdi->rdi_e.e_name );
1089 BER_BVZERO( &rdi->rdi_e.e_nname );
1091 entry_clean( &rdi->rdi_e );
1093 next = rdi->rdi_next;
1098 if ( !BER_BVISNULL( &rd->rd_pdn ) ) {
1099 ber_memfree( rd->rd_pdn.bv_val );
1102 if ( !BER_BVISNULL( &rd->rd_npdn ) ) {
1103 ber_memfree( rd->rd_npdn.bv_val );
1112 #if SLAPD_OVER_RETCODE == SLAPD_MOD_DYNAMIC
1114 #endif /* SLAPD_OVER_RETCODE == SLAPD_MOD_DYNAMIC */
1116 retcode_initialize( void )
1123 AttributeDescription **ad;
1125 { "( 1.3.6.1.4.1.4203.666.11.4.1.1 "
1126 "NAME ( 'errCode' ) "
1127 "DESC 'LDAP error code' "
1128 "EQUALITY integerMatch "
1129 "ORDERING integerOrderingMatch "
1130 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
1133 { "( 1.3.6.1.4.1.4203.666.11.4.1.2 "
1135 "DESC 'Operations the errObject applies to' "
1136 "EQUALITY caseIgnoreMatch "
1137 "SUBSTR caseIgnoreSubstringsMatch "
1138 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
1140 { "( 1.3.6.1.4.1.4203.666.11.4.1.3 "
1141 "NAME ( 'errText' ) "
1142 "DESC 'LDAP error textual description' "
1143 "EQUALITY caseIgnoreMatch "
1144 "SUBSTR caseIgnoreSubstringsMatch "
1145 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 "
1148 { "( 1.3.6.1.4.1.4203.666.11.4.1.4 "
1149 "NAME ( 'errSleepTime' ) "
1150 "DESC 'Time to wait before returning the error' "
1151 "EQUALITY integerMatch "
1152 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
1155 { "( 1.3.6.1.4.1.4203.666.11.4.1.5 "
1156 "NAME ( 'errMatchedDN' ) "
1157 "DESC 'Value to be returned as matched DN' "
1158 "EQUALITY distinguishedNameMatch "
1159 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 "
1169 { "( 1.3.6.1.4.1.4203.666.11.4.3.0 "
1170 "NAME ( 'errAbsObject' ) "
1182 { "( 1.3.6.1.4.1.4203.666.11.4.3.1 "
1183 "NAME ( 'errObject' ) "
1184 "SUP errAbsObject STRUCTURAL "
1187 { "( 1.3.6.1.4.1.4203.666.11.4.3.2 "
1188 "NAME ( 'errAuxObject' ) "
1189 "SUP errAbsObject AUXILIARY "
1196 for ( i = 0; retcode_at[ i ].desc != NULL; i++ ) {
1197 code = register_at( retcode_at[ i ].desc, retcode_at[ i ].ad, 0 );
1199 Debug( LDAP_DEBUG_ANY,
1200 "retcode: register_at failed\n", 0, 0, 0 );
1205 for ( i = 0; retcode_oc[ i ].desc != NULL; i++ ) {
1206 code = register_oc( retcode_oc[ i ].desc, retcode_oc[ i ].oc, 0 );
1208 Debug( LDAP_DEBUG_ANY,
1209 "retcode: register_oc failed\n", 0, 0, 0 );
1214 retcode.on_bi.bi_type = "retcode";
1216 retcode.on_bi.bi_db_init = retcode_db_init;
1217 retcode.on_bi.bi_db_config = retcode_db_config;
1218 retcode.on_bi.bi_db_open = retcode_db_open;
1219 retcode.on_bi.bi_db_destroy = retcode_db_destroy;
1221 retcode.on_bi.bi_op_add = retcode_op_func;
1222 retcode.on_bi.bi_op_bind = retcode_op_func;
1223 retcode.on_bi.bi_op_compare = retcode_op_func;
1224 retcode.on_bi.bi_op_delete = retcode_op_func;
1225 retcode.on_bi.bi_op_modify = retcode_op_func;
1226 retcode.on_bi.bi_op_modrdn = retcode_op_func;
1227 retcode.on_bi.bi_op_search = retcode_op_func;
1229 retcode.on_bi.bi_extended = retcode_op_func;
1231 retcode.on_response = retcode_response;
1233 return overlay_register( &retcode );
1236 #if SLAPD_OVER_RETCODE == SLAPD_MOD_DYNAMIC
1238 init_module( int argc, char *argv[] )
1240 return retcode_initialize();
1242 #endif /* SLAPD_OVER_RETCODE == SLAPD_MOD_DYNAMIC */
1244 #endif /* SLAPD_OVER_RETCODE */