1 /* retcode.c - customizable response for client testing purposes */
2 /* $OpenLDAP: pkg/ldap/servers/slapd/overlays/retcode.c,v 1.18.2.7 2008/02/11 23:26:48 kurt Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2005-2008 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>
38 static slap_overinst retcode
;
40 static AttributeDescription
*ad_errCode
;
41 static AttributeDescription
*ad_errText
;
42 static AttributeDescription
*ad_errOp
;
43 static AttributeDescription
*ad_errSleepTime
;
44 static AttributeDescription
*ad_errMatchedDN
;
45 static AttributeDescription
*ad_errUnsolicitedOID
;
46 static AttributeDescription
*ad_errUnsolicitedData
;
47 static AttributeDescription
*ad_errDisconnect
;
49 static ObjectClass
*oc_errAbsObject
;
50 static ObjectClass
*oc_errObject
;
51 static ObjectClass
*oc_errAuxObject
;
53 typedef enum retcode_op_e
{
54 SN_DG_OP_NONE
= 0x0000,
55 SN_DG_OP_ADD
= 0x0001,
56 SN_DG_OP_BIND
= 0x0002,
57 SN_DG_OP_COMPARE
= 0x0004,
58 SN_DG_OP_DELETE
= 0x0008,
59 SN_DG_OP_MODIFY
= 0x0010,
60 SN_DG_OP_RENAME
= 0x0020,
61 SN_DG_OP_SEARCH
= 0x0040,
62 SN_DG_EXTENDED
= 0x0080,
63 SN_DG_OP_AUTH
= SN_DG_OP_BIND
,
64 SN_DG_OP_READ
= (SN_DG_OP_COMPARE
|SN_DG_OP_SEARCH
),
65 SN_DG_OP_WRITE
= (SN_DG_OP_ADD
|SN_DG_OP_DELETE
|SN_DG_OP_MODIFY
|SN_DG_OP_RENAME
),
66 SN_DG_OP_ALL
= (SN_DG_OP_AUTH
|SN_DG_OP_READ
|SN_DG_OP_WRITE
|SN_DG_EXTENDED
)
69 typedef struct retcode_item_t
{
71 struct berval rdi_ndn
;
72 struct berval rdi_text
;
73 struct berval rdi_matched
;
79 struct berval rdi_unsolicited_oid
;
80 struct berval rdi_unsolicited_data
;
83 #define RDI_PRE_DISCONNECT (0x1U)
84 #define RDI_POST_DISCONNECT (0x2U)
86 struct retcode_item_t
*rdi_next
;
89 typedef struct retcode_t
{
91 struct berval rd_npdn
;
95 retcode_item_t
*rd_item
;
98 #define RETCODE_FNONE 0x00
99 #define RETCODE_FINDIR 0x01
100 #define RETCODE_INDIR( rd ) ( (rd)->rd_flags & RETCODE_FINDIR )
104 retcode_entry_response( Operation
*op
, SlapReply
*rs
, BackendInfo
*bi
, Entry
*e
);
107 retcode_sleep( int s
)
111 /* sleep as required */
113 #if 0 /* use high-order bits for better randomness (Numerical Recipes in "C") */
116 r
= ((double)(-s
))*rand()/(RAND_MAX
+ 1.0);
117 } else if ( s
> 0 ) {
128 retcode_cleanup_cb( Operation
*op
, SlapReply
*rs
)
130 rs
->sr_matched
= NULL
;
133 if ( rs
->sr_ref
!= NULL
) {
134 ber_bvarray_free( rs
->sr_ref
);
138 ch_free( op
->o_callback
);
139 op
->o_callback
= NULL
;
141 return SLAP_CB_CONTINUE
;
145 retcode_send_onelevel( Operation
*op
, SlapReply
*rs
)
147 slap_overinst
*on
= (slap_overinst
*)op
->o_bd
->bd_info
;
148 retcode_t
*rd
= (retcode_t
*)on
->on_bi
.bi_private
;
152 for ( rdi
= rd
->rd_item
; rdi
!= NULL
; rdi
= rdi
->rdi_next
) {
153 if ( op
->o_abandon
) {
154 return rs
->sr_err
= SLAPD_ABANDON
;
157 rs
->sr_err
= test_filter( op
, &rdi
->rdi_e
, op
->ors_filter
);
158 if ( rs
->sr_err
== LDAP_COMPARE_TRUE
) {
160 rs
->sr_attrs
= op
->ors_attrs
;
161 rs
->sr_operational_attrs
= NULL
;
164 rs
->sr_err
= LDAP_SUCCESS
;
165 rs
->sr_entry
= &rdi
->rdi_e
;
167 rs
->sr_err
= send_search_entry( op
, rs
);
170 switch ( rs
->sr_err
) {
171 case LDAP_UNAVAILABLE
: /* connection closed */
172 rs
->sr_err
= LDAP_OTHER
;
174 case LDAP_SIZELIMIT_EXCEEDED
:
178 rs
->sr_err
= LDAP_SUCCESS
;
183 send_ldap_result( op
, rs
);
189 retcode_op_add( Operation
*op
, SlapReply
*rs
)
191 return retcode_entry_response( op
, rs
, NULL
, op
->ora_e
);
194 typedef struct retcode_cb_t
{
195 BackendInfo
*rdc_info
;
198 AttributeName
*rdc_attrs
;
202 retcode_cb_response( Operation
*op
, SlapReply
*rs
)
204 retcode_cb_t
*rdc
= (retcode_cb_t
*)op
->o_callback
->sc_private
;
206 op
->o_tag
= rdc
->rdc_tag
;
207 if ( rs
->sr_type
== REP_SEARCH
) {
208 ber_tag_t o_tag
= op
->o_tag
;
211 if ( op
->o_tag
== LDAP_REQ_SEARCH
) {
212 rs
->sr_attrs
= rdc
->rdc_attrs
;
214 rc
= retcode_entry_response( op
, rs
, rdc
->rdc_info
, rs
->sr_entry
);
220 switch ( rs
->sr_err
) {
222 case LDAP_NO_SUCH_OBJECT
:
223 /* in case of noSuchObject, stop the internal search
224 * for in-directory error stuff */
225 if ( !op
->o_abandon
) {
226 rdc
->rdc_flags
= SLAP_CB_CONTINUE
;
231 return SLAP_CB_CONTINUE
;
235 retcode_op_internal( Operation
*op
, SlapReply
*rs
)
237 slap_overinst
*on
= (slap_overinst
*)op
->o_bd
->bd_info
;
240 BackendDB db
= *op
->o_bd
;
241 slap_callback sc
= { 0 };
246 op2
.o_tag
= LDAP_REQ_SEARCH
;
247 op2
.ors_scope
= LDAP_SCOPE_BASE
;
248 op2
.ors_deref
= LDAP_DEREF_NEVER
;
249 op2
.ors_tlimit
= SLAP_NO_LIMIT
;
250 op2
.ors_slimit
= SLAP_NO_LIMIT
;
251 op2
.ors_limit
= NULL
;
252 op2
.ors_attrsonly
= 0;
253 op2
.ors_attrs
= slap_anlist_all_attributes
;
255 ber_str2bv_x( "(objectClass=errAbsObject)",
256 STRLENOF( "(objectClass=errAbsObject)" ),
257 1, &op2
.ors_filterstr
, op2
.o_tmpmemctx
);
258 op2
.ors_filter
= str2filter_x( &op2
, op2
.ors_filterstr
.bv_val
);
260 db
.bd_info
= on
->on_info
->oi_orig
;
263 rdc
.rdc_info
= on
->on_info
->oi_orig
;
264 rdc
.rdc_flags
= RETCODE_FINDIR
;
265 if ( op
->o_tag
== LDAP_REQ_SEARCH
) {
266 rdc
.rdc_attrs
= op
->ors_attrs
;
268 rdc
.rdc_tag
= op
->o_tag
;
269 sc
.sc_response
= retcode_cb_response
;
270 sc
.sc_private
= &rdc
;
271 op2
.o_callback
= &sc
;
273 rc
= op2
.o_bd
->be_search( &op2
, rs
);
274 op
->o_abandon
= op2
.o_abandon
;
276 filter_free_x( &op2
, op2
.ors_filter
);
277 ber_memfree_x( op2
.ors_filterstr
.bv_val
, op2
.o_tmpmemctx
);
279 if ( rdc
.rdc_flags
== SLAP_CB_CONTINUE
) {
280 return SLAP_CB_CONTINUE
;
287 retcode_op_func( Operation
*op
, SlapReply
*rs
)
289 slap_overinst
*on
= (slap_overinst
*)op
->o_bd
->bd_info
;
290 retcode_t
*rd
= (retcode_t
*)on
->on_bi
.bi_private
;
293 struct berval nrdn
, npdn
;
295 slap_callback
*cb
= NULL
;
297 /* sleep as required */
298 retcode_sleep( rd
->rd_sleep
);
300 if ( !dnIsSuffix( &op
->o_req_ndn
, &rd
->rd_npdn
) ) {
301 if ( RETCODE_INDIR( rd
) ) {
302 switch ( op
->o_tag
) {
304 return retcode_op_add( op
, rs
);
308 /* FIXME: better give the db a chance? */
309 if ( be_isroot_pw( op
) ) {
312 return retcode_op_internal( op
, rs
);
314 case LDAP_REQ_SEARCH
:
315 if ( op
->ors_scope
== LDAP_SCOPE_BASE
) {
316 rs
->sr_err
= retcode_op_internal( op
, rs
);
317 switch ( rs
->sr_err
) {
318 case SLAP_CB_CONTINUE
:
319 if ( rs
->sr_nentries
== 0 ) {
322 rs
->sr_err
= LDAP_SUCCESS
;
326 send_ldap_result( op
, rs
);
333 case LDAP_REQ_MODIFY
:
334 case LDAP_REQ_DELETE
:
335 case LDAP_REQ_MODRDN
:
336 case LDAP_REQ_COMPARE
:
337 return retcode_op_internal( op
, rs
);
341 return SLAP_CB_CONTINUE
;
344 if ( op
->o_tag
== LDAP_REQ_SEARCH
345 && op
->ors_scope
!= LDAP_SCOPE_BASE
346 && op
->o_req_ndn
.bv_len
== rd
->rd_npdn
.bv_len
)
348 return retcode_send_onelevel( op
, rs
);
351 dnParent( &op
->o_req_ndn
, &npdn
);
352 if ( npdn
.bv_len
!= rd
->rd_npdn
.bv_len
) {
353 rs
->sr_err
= LDAP_NO_SUCH_OBJECT
;
354 rs
->sr_matched
= rd
->rd_pdn
.bv_val
;
355 send_ldap_result( op
, rs
);
356 rs
->sr_matched
= NULL
;
360 dnRdn( &op
->o_req_ndn
, &nrdn
);
362 for ( rdi
= rd
->rd_item
; rdi
!= NULL
; rdi
= rdi
->rdi_next
) {
363 struct berval rdi_nrdn
;
365 dnRdn( &rdi
->rdi_ndn
, &rdi_nrdn
);
366 if ( dn_match( &nrdn
, &rdi_nrdn
) ) {
371 if ( rdi
!= NULL
&& rdi
->rdi_mask
!= SN_DG_OP_ALL
) {
372 retcode_op_e o_tag
= SN_DG_OP_NONE
;
374 switch ( op
->o_tag
) {
376 o_tag
= SN_DG_OP_ADD
;
380 o_tag
= SN_DG_OP_BIND
;
383 case LDAP_REQ_COMPARE
:
384 o_tag
= SN_DG_OP_COMPARE
;
387 case LDAP_REQ_DELETE
:
388 o_tag
= SN_DG_OP_DELETE
;
391 case LDAP_REQ_MODIFY
:
392 o_tag
= SN_DG_OP_MODIFY
;
395 case LDAP_REQ_MODRDN
:
396 o_tag
= SN_DG_OP_RENAME
;
399 case LDAP_REQ_SEARCH
:
400 o_tag
= SN_DG_OP_SEARCH
;
403 case LDAP_REQ_EXTENDED
:
404 o_tag
= SN_DG_EXTENDED
;
408 /* Should not happen */
412 if ( !( o_tag
& rdi
->rdi_mask
) ) {
413 return SLAP_CB_CONTINUE
;
418 rs
->sr_matched
= rd
->rd_pdn
.bv_val
;
419 rs
->sr_err
= LDAP_NO_SUCH_OBJECT
;
420 rs
->sr_text
= "retcode not found";
423 if ( rdi
->rdi_flags
& RDI_PRE_DISCONNECT
) {
424 return rs
->sr_err
= SLAPD_DISCONNECT
;
427 rs
->sr_err
= rdi
->rdi_err
;
428 rs
->sr_text
= rdi
->rdi_text
.bv_val
;
429 rs
->sr_matched
= rdi
->rdi_matched
.bv_val
;
431 /* FIXME: we only honor the rdi_ref field in case rdi_err
432 * is LDAP_REFERRAL otherwise send_ldap_result() bails out */
433 if ( rs
->sr_err
== LDAP_REFERRAL
) {
436 if ( rdi
->rdi_ref
!= NULL
) {
439 ref
= default_referral
;
443 rs
->sr_ref
= referral_rewrite( ref
,
444 NULL
, &op
->o_req_dn
, LDAP_SCOPE_DEFAULT
);
447 rs
->sr_err
= LDAP_OTHER
;
448 rs
->sr_text
= "bad referral object";
452 retcode_sleep( rdi
->rdi_sleeptime
);
455 switch ( op
->o_tag
) {
456 case LDAP_REQ_EXTENDED
:
460 cb
= ( slap_callback
* )ch_malloc( sizeof( slap_callback
) );
461 memset( cb
, 0, sizeof( slap_callback
) );
462 cb
->sc_cleanup
= retcode_cleanup_cb
;
467 if ( rdi
&& !BER_BVISNULL( &rdi
->rdi_unsolicited_oid
) ) {
468 ber_int_t msgid
= op
->o_msgid
;
470 /* RFC 4511 unsolicited response */
473 if ( strcmp( rdi
->rdi_unsolicited_oid
.bv_val
, "0" ) == 0 ) {
474 send_ldap_result( op
, rs
);
477 ber_tag_t tag
= op
->o_tag
;
479 op
->o_tag
= LDAP_REQ_EXTENDED
;
480 rs
->sr_rspoid
= rdi
->rdi_unsolicited_oid
.bv_val
;
481 if ( !BER_BVISNULL( &rdi
->rdi_unsolicited_data
) ) {
482 rs
->sr_rspdata
= &rdi
->rdi_unsolicited_data
;
484 send_ldap_extended( op
, rs
);
485 rs
->sr_rspoid
= NULL
;
486 rs
->sr_rspdata
= NULL
;
493 send_ldap_result( op
, rs
);
496 if ( rs
->sr_ref
!= NULL
) {
497 ber_bvarray_free( rs
->sr_ref
);
500 rs
->sr_matched
= NULL
;
503 if ( rdi
&& rdi
->rdi_flags
& RDI_POST_DISCONNECT
) {
504 return rs
->sr_err
= SLAPD_DISCONNECT
;
513 retcode_op2str( ber_tag_t op
, struct berval
*bv
)
517 BER_BVSTR( bv
, "bind" );
520 BER_BVSTR( bv
, "add" );
522 case LDAP_REQ_DELETE
:
523 BER_BVSTR( bv
, "delete" );
525 case LDAP_REQ_MODRDN
:
526 BER_BVSTR( bv
, "modrdn" );
528 case LDAP_REQ_MODIFY
:
529 BER_BVSTR( bv
, "modify" );
531 case LDAP_REQ_COMPARE
:
532 BER_BVSTR( bv
, "compare" );
534 case LDAP_REQ_SEARCH
:
535 BER_BVSTR( bv
, "search" );
537 case LDAP_REQ_EXTENDED
:
538 BER_BVSTR( bv
, "extended" );
545 retcode_entry_response( Operation
*op
, SlapReply
*rs
, BackendInfo
*bi
, Entry
*e
)
552 if ( get_manageDSAit( op
) ) {
553 return SLAP_CB_CONTINUE
;
556 if ( !is_entry_objectclass_or_sub( e
, oc_errAbsObject
) ) {
557 return SLAP_CB_CONTINUE
;
561 a
= attr_find( e
->e_attrs
, ad_errOp
);
565 struct berval bv
= BER_BVNULL
;
567 (void)retcode_op2str( op
->o_tag
, &bv
);
569 if ( BER_BVISNULL( &bv
) ) {
570 return SLAP_CB_CONTINUE
;
573 for ( i
= 0; !BER_BVISNULL( &a
->a_nvals
[ i
] ); i
++ ) {
574 if ( bvmatch( &a
->a_nvals
[ i
], &bv
) ) {
581 return SLAP_CB_CONTINUE
;
586 a
= attr_find( e
->e_attrs
, ad_errDisconnect
);
588 if ( bvmatch( &a
->a_nvals
[ 0 ], &slap_true_bv
) ) {
589 return rs
->sr_err
= SLAPD_DISCONNECT
;
595 a
= attr_find( e
->e_attrs
, ad_errCode
);
597 return SLAP_CB_CONTINUE
;
599 err
= strtol( a
->a_nvals
[ 0 ].bv_val
, &next
, 0 );
600 if ( next
== a
->a_nvals
[ 0 ].bv_val
|| next
[ 0 ] != '\0' ) {
601 return SLAP_CB_CONTINUE
;
606 a
= attr_find( e
->e_attrs
, ad_errSleepTime
);
607 if ( a
!= NULL
&& a
->a_nvals
[ 0 ].bv_val
[ 0 ] != '-' ) {
610 if ( lutil_atoi( &sleepTime
, a
->a_nvals
[ 0 ].bv_val
) == 0 ) {
611 retcode_sleep( sleepTime
);
615 if ( rs
->sr_err
!= LDAP_SUCCESS
&& !LDAP_API_ERROR( rs
->sr_err
)) {
616 BackendDB db
= *op
->o_bd
,
618 void *o_callback
= op
->o_callback
;
621 a
= attr_find( e
->e_attrs
, ad_errText
);
623 rs
->sr_text
= a
->a_vals
[ 0 ].bv_val
;
627 a
= attr_find( e
->e_attrs
, ad_errMatchedDN
);
629 rs
->sr_matched
= a
->a_vals
[ 0 ].bv_val
;
633 slap_overinst
*on
= (slap_overinst
*)op
->o_bd
->bd_info
;
635 bi
= on
->on_info
->oi_orig
;
640 op
->o_callback
= NULL
;
643 if ( rs
->sr_err
== LDAP_REFERRAL
) {
644 BerVarray refs
= default_referral
;
646 a
= attr_find( e
->e_attrs
, slap_schema
.si_ad_ref
);
650 rs
->sr_ref
= referral_rewrite( refs
,
651 NULL
, &op
->o_req_dn
, op
->oq_search
.rs_scope
);
653 send_search_reference( op
, rs
);
654 ber_bvarray_free( rs
->sr_ref
);
658 a
= attr_find( e
->e_attrs
, ad_errUnsolicitedOID
);
660 struct berval oid
= BER_BVNULL
,
662 ber_int_t msgid
= op
->o_msgid
;
664 /* RFC 4511 unsolicited response */
668 oid
= a
->a_nvals
[ 0 ];
670 a
= attr_find( e
->e_attrs
, ad_errUnsolicitedData
);
672 data
= a
->a_nvals
[ 0 ];
675 if ( strcmp( oid
.bv_val
, "0" ) == 0 ) {
676 send_ldap_result( op
, rs
);
679 ber_tag_t tag
= op
->o_tag
;
681 op
->o_tag
= LDAP_REQ_EXTENDED
;
682 rs
->sr_rspoid
= oid
.bv_val
;
683 if ( !BER_BVISNULL( &data
) ) {
684 rs
->sr_rspdata
= &data
;
686 send_ldap_extended( op
, rs
);
687 rs
->sr_rspoid
= NULL
;
688 rs
->sr_rspdata
= NULL
;
694 send_ldap_result( op
, rs
);
699 rs
->sr_matched
= NULL
;
701 op
->o_callback
= o_callback
;
704 if ( rs
->sr_err
!= LDAP_SUCCESS
) {
706 return rs
->sr_err
= SLAPD_DISCONNECT
;
713 return SLAP_CB_CONTINUE
;
717 retcode_response( Operation
*op
, SlapReply
*rs
)
719 slap_overinst
*on
= (slap_overinst
*)op
->o_bd
->bd_info
;
720 retcode_t
*rd
= (retcode_t
*)on
->on_bi
.bi_private
;
722 if ( rs
->sr_type
!= REP_SEARCH
|| !RETCODE_INDIR( rd
) ) {
723 return SLAP_CB_CONTINUE
;
726 return retcode_entry_response( op
, rs
, NULL
, rs
->sr_entry
);
730 retcode_db_init( BackendDB
*be
, ConfigReply
*cr
)
732 slap_overinst
*on
= (slap_overinst
*)be
->bd_info
;
737 rd
= (retcode_t
*)ch_malloc( sizeof( retcode_t
) );
738 memset( rd
, 0, sizeof( retcode_t
) );
740 on
->on_bi
.bi_private
= (void *)rd
;
753 slap_overinst
*on
= (slap_overinst
*)be
->bd_info
;
754 retcode_t
*rd
= (retcode_t
*)on
->on_bi
.bi_private
;
756 char *argv0
= argv
[ 0 ] + STRLENOF( "retcode-" );
758 if ( strncasecmp( argv
[ 0 ], "retcode-", STRLENOF( "retcode-" ) ) != 0 ) {
759 return SLAP_CONF_UNKNOWN
;
762 if ( strcasecmp( argv0
, "parent" ) == 0 ) {
767 fprintf( stderr
, "%s: line %d: retcode: "
768 "\"retcode-parent <DN>\": missing <DN>\n",
773 if ( !BER_BVISNULL( &rd
->rd_pdn
) ) {
774 fprintf( stderr
, "%s: line %d: retcode: "
775 "parent already defined.\n", fname
, lineno
);
779 ber_str2bv( argv
[ 1 ], 0, 0, &dn
);
781 rc
= dnPrettyNormal( NULL
, &dn
, &rd
->rd_pdn
, &rd
->rd_npdn
, NULL
);
782 if ( rc
!= LDAP_SUCCESS
) {
783 fprintf( stderr
, "%s: line %d: retcode: "
784 "unable to normalize parent DN \"%s\": %d\n",
785 fname
, lineno
, argv
[ 1 ], rc
);
789 } else if ( strcasecmp( argv0
, "item" ) == 0 ) {
790 retcode_item_t rdi
= { BER_BVNULL
}, **rdip
;
791 struct berval bv
, rdn
, nrdn
;
796 fprintf( stderr
, "%s: line %d: retcode: "
797 "\"retcode-item <RDN> <retcode> [<text>]\": "
803 ber_str2bv( argv
[ 1 ], 0, 0, &bv
);
805 rc
= dnPrettyNormal( NULL
, &bv
, &rdn
, &nrdn
, NULL
);
806 if ( rc
!= LDAP_SUCCESS
) {
807 fprintf( stderr
, "%s: line %d: retcode: "
808 "unable to normalize RDN \"%s\": %d\n",
809 fname
, lineno
, argv
[ 1 ], rc
);
813 if ( !dnIsOneLevelRDN( &nrdn
) ) {
814 fprintf( stderr
, "%s: line %d: retcode: "
815 "value \"%s\" is not a RDN\n",
816 fname
, lineno
, argv
[ 1 ] );
820 if ( BER_BVISNULL( &rd
->rd_npdn
) ) {
821 /* FIXME: we use the database suffix */
822 if ( be
->be_nsuffix
== NULL
) {
823 fprintf( stderr
, "%s: line %d: retcode: "
824 "either \"retcode-parent\" "
825 "or \"suffix\" must be defined.\n",
830 ber_dupbv( &rd
->rd_pdn
, &be
->be_suffix
[ 0 ] );
831 ber_dupbv( &rd
->rd_npdn
, &be
->be_nsuffix
[ 0 ] );
834 build_new_dn( &rdi
.rdi_dn
, &rd
->rd_pdn
, &rdn
, NULL
);
835 build_new_dn( &rdi
.rdi_ndn
, &rd
->rd_npdn
, &nrdn
, NULL
);
837 ch_free( rdn
.bv_val
);
838 ch_free( nrdn
.bv_val
);
840 rdi
.rdi_err
= strtol( argv
[ 2 ], &next
, 0 );
841 if ( next
== argv
[ 2 ] || next
[ 0 ] != '\0' ) {
842 fprintf( stderr
, "%s: line %d: retcode: "
843 "unable to parse return code \"%s\"\n",
844 fname
, lineno
, argv
[ 2 ] );
848 rdi
.rdi_mask
= SN_DG_OP_ALL
;
853 for ( i
= 3; i
< argc
; i
++ ) {
854 if ( strncasecmp( argv
[ i
], "op=", STRLENOF( "op=" ) ) == 0 )
859 ops
= ldap_str2charray( &argv
[ i
][ STRLENOF( "op=" ) ], "," );
860 assert( ops
!= NULL
);
862 rdi
.rdi_mask
= SN_DG_OP_NONE
;
864 for ( j
= 0; ops
[ j
] != NULL
; j
++ ) {
865 if ( strcasecmp( ops
[ j
], "add" ) == 0 ) {
866 rdi
.rdi_mask
|= SN_DG_OP_ADD
;
868 } else if ( strcasecmp( ops
[ j
], "bind" ) == 0 ) {
869 rdi
.rdi_mask
|= SN_DG_OP_BIND
;
871 } else if ( strcasecmp( ops
[ j
], "compare" ) == 0 ) {
872 rdi
.rdi_mask
|= SN_DG_OP_COMPARE
;
874 } else if ( strcasecmp( ops
[ j
], "delete" ) == 0 ) {
875 rdi
.rdi_mask
|= SN_DG_OP_DELETE
;
877 } else if ( strcasecmp( ops
[ j
], "modify" ) == 0 ) {
878 rdi
.rdi_mask
|= SN_DG_OP_MODIFY
;
880 } else if ( strcasecmp( ops
[ j
], "rename" ) == 0
881 || strcasecmp( ops
[ j
], "modrdn" ) == 0 )
883 rdi
.rdi_mask
|= SN_DG_OP_RENAME
;
885 } else if ( strcasecmp( ops
[ j
], "search" ) == 0 ) {
886 rdi
.rdi_mask
|= SN_DG_OP_SEARCH
;
888 } else if ( strcasecmp( ops
[ j
], "extended" ) == 0 ) {
889 rdi
.rdi_mask
|= SN_DG_EXTENDED
;
891 } else if ( strcasecmp( ops
[ j
], "auth" ) == 0 ) {
892 rdi
.rdi_mask
|= SN_DG_OP_AUTH
;
894 } else if ( strcasecmp( ops
[ j
], "read" ) == 0 ) {
895 rdi
.rdi_mask
|= SN_DG_OP_READ
;
897 } else if ( strcasecmp( ops
[ j
], "write" ) == 0 ) {
898 rdi
.rdi_mask
|= SN_DG_OP_WRITE
;
900 } else if ( strcasecmp( ops
[ j
], "all" ) == 0 ) {
901 rdi
.rdi_mask
|= SN_DG_OP_ALL
;
904 fprintf( stderr
, "retcode: unknown op \"%s\"\n",
906 ldap_charray_free( ops
);
911 ldap_charray_free( ops
);
913 } else if ( strncasecmp( argv
[ i
], "text=", STRLENOF( "text=" ) ) == 0 )
915 if ( !BER_BVISNULL( &rdi
.rdi_text
) ) {
916 fprintf( stderr
, "%s: line %d: retcode: "
917 "\"text\" already provided.\n",
921 ber_str2bv( &argv
[ i
][ STRLENOF( "text=" ) ], 0, 1, &rdi
.rdi_text
);
923 } else if ( strncasecmp( argv
[ i
], "matched=", STRLENOF( "matched=" ) ) == 0 )
927 if ( !BER_BVISNULL( &rdi
.rdi_matched
) ) {
928 fprintf( stderr
, "%s: line %d: retcode: "
929 "\"matched\" already provided.\n",
933 ber_str2bv( &argv
[ i
][ STRLENOF( "matched=" ) ], 0, 0, &dn
);
934 if ( dnPretty( NULL
, &dn
, &rdi
.rdi_matched
, NULL
) != LDAP_SUCCESS
) {
935 fprintf( stderr
, "%s: line %d: retcode: "
936 "unable to prettify matched DN \"%s\".\n",
937 fname
, lineno
, &argv
[ i
][ STRLENOF( "matched=" ) ] );
941 } else if ( strncasecmp( argv
[ i
], "ref=", STRLENOF( "ref=" ) ) == 0 )
946 if ( rdi
.rdi_ref
!= NULL
) {
947 fprintf( stderr
, "%s: line %d: retcode: "
948 "\"ref\" already provided.\n",
953 if ( rdi
.rdi_err
!= LDAP_REFERRAL
) {
954 fprintf( stderr
, "%s: line %d: retcode: "
955 "providing \"ref\"\n"
956 "\talong with a non-referral "
957 "resultCode may cause slapd failures\n"
958 "\trelated to internal checks.\n",
962 refs
= ldap_str2charray( &argv
[ i
][ STRLENOF( "ref=" ) ], " " );
963 assert( refs
!= NULL
);
965 for ( j
= 0; refs
[ j
] != NULL
; j
++ ) {
968 ber_str2bv( refs
[ j
], 0, 1, &bv
);
969 ber_bvarray_add( &rdi
.rdi_ref
, &bv
);
972 ldap_charray_free( refs
);
974 } else if ( strncasecmp( argv
[ i
], "sleeptime=", STRLENOF( "sleeptime=" ) ) == 0 )
976 if ( rdi
.rdi_sleeptime
!= 0 ) {
977 fprintf( stderr
, "%s: line %d: retcode: "
978 "\"sleeptime\" already provided.\n",
983 if ( lutil_atoi( &rdi
.rdi_sleeptime
, &argv
[ i
][ STRLENOF( "sleeptime=" ) ] ) ) {
984 fprintf( stderr
, "%s: line %d: retcode: "
985 "unable to parse \"sleeptime=%s\".\n",
986 fname
, lineno
, &argv
[ i
][ STRLENOF( "sleeptime=" ) ] );
990 } else if ( strncasecmp( argv
[ i
], "unsolicited=", STRLENOF( "unsolicited=" ) ) == 0 )
994 if ( !BER_BVISNULL( &rdi
.rdi_unsolicited_oid
) ) {
995 fprintf( stderr
, "%s: line %d: retcode: "
996 "\"unsolicited\" already provided.\n",
1001 data
= strchr( &argv
[ i
][ STRLENOF( "unsolicited=" ) ], ':' );
1002 if ( data
!= NULL
) {
1005 if ( ldif_parse_line2( &argv
[ i
][ STRLENOF( "unsolicited=" ) ],
1006 &oid
, &rdi
.rdi_unsolicited_data
, NULL
) )
1008 fprintf( stderr
, "%s: line %d: retcode: "
1009 "unable to parse \"unsolicited\".\n",
1014 ber_dupbv( &rdi
.rdi_unsolicited_oid
, &oid
);
1017 ber_str2bv( &argv
[ i
][ STRLENOF( "unsolicited=" ) ], 0, 1,
1018 &rdi
.rdi_unsolicited_oid
);
1021 } else if ( strncasecmp( argv
[ i
], "flags=", STRLENOF( "flags=" ) ) == 0 )
1023 char *arg
= &argv
[ i
][ STRLENOF( "flags=" ) ];
1024 if ( strcasecmp( arg
, "disconnect" ) == 0 ) {
1025 rdi
.rdi_flags
|= RDI_PRE_DISCONNECT
;
1027 } else if ( strcasecmp( arg
, "pre-disconnect" ) == 0 ) {
1028 rdi
.rdi_flags
|= RDI_PRE_DISCONNECT
;
1030 } else if ( strcasecmp( arg
, "post-disconnect" ) == 0 ) {
1031 rdi
.rdi_flags
|= RDI_POST_DISCONNECT
;
1034 fprintf( stderr
, "%s: line %d: retcode: "
1035 "unknown flag \"%s\".\n",
1036 fname
, lineno
, arg
);
1041 fprintf( stderr
, "%s: line %d: retcode: "
1042 "unknown option \"%s\".\n",
1043 fname
, lineno
, argv
[ i
] );
1049 for ( rdip
= &rd
->rd_item
; *rdip
; rdip
= &(*rdip
)->rdi_next
)
1053 *rdip
= ( retcode_item_t
* )ch_malloc( sizeof( retcode_item_t
) );
1056 } else if ( strcasecmp( argv0
, "indir" ) == 0 ) {
1057 rd
->rd_flags
|= RETCODE_FINDIR
;
1059 } else if ( strcasecmp( argv0
, "sleep" ) == 0 ) {
1062 fprintf( stderr
, "%s: line %d: retcode: "
1063 "\"retcode-sleep <time>\": missing <time>\n",
1071 fprintf( stderr
, "%s: line %d: retcode: "
1072 "\"retcode-sleep <time>\": extra cruft after <time>\n",
1077 if ( lutil_atoi( &rd
->rd_sleep
, argv
[ 1 ] ) != 0 ) {
1078 fprintf( stderr
, "%s: line %d: retcode: "
1079 "\"retcode-sleep <time>\": unable to parse <time>\n",
1085 return SLAP_CONF_UNKNOWN
;
1092 retcode_db_open( BackendDB
*be
, ConfigReply
*cr
)
1094 slap_overinst
*on
= (slap_overinst
*)be
->bd_info
;
1095 retcode_t
*rd
= (retcode_t
*)on
->on_bi
.bi_private
;
1097 retcode_item_t
*rdi
;
1099 for ( rdi
= rd
->rd_item
; rdi
; rdi
= rdi
->rdi_next
) {
1103 struct berval val
[ 3 ];
1104 char buf
[ SLAP_TEXT_BUFLEN
];
1107 rdi
->rdi_e
.e_name
= rdi
->rdi_dn
;
1108 rdi
->rdi_e
.e_nname
= rdi
->rdi_ndn
;
1111 val
[ 0 ] = oc_errObject
->soc_cname
;
1112 val
[ 1 ] = slap_schema
.si_oc_extensibleObject
->soc_cname
;
1113 BER_BVZERO( &val
[ 2 ] );
1115 attr_merge( &rdi
->rdi_e
, slap_schema
.si_ad_objectClass
, val
, NULL
);
1118 rc
= ldap_bv2rdn( &rdi
->rdi_dn
, &rdn
, (char **) &p
,
1119 LDAP_DN_FORMAT_LDAP
);
1121 assert( rc
== LDAP_SUCCESS
);
1123 for ( j
= 0; rdn
[ j
]; j
++ ) {
1124 LDAPAVA
*ava
= rdn
[ j
];
1125 AttributeDescription
*ad
= NULL
;
1128 rc
= slap_bv2ad( &ava
->la_attr
, &ad
, &text
);
1129 assert( rc
== LDAP_SUCCESS
);
1131 attr_merge_normalize_one( &rdi
->rdi_e
, ad
,
1132 &ava
->la_value
, NULL
);
1135 ldap_rdnfree( rdn
);
1138 snprintf( buf
, sizeof( buf
), "%d", rdi
->rdi_err
);
1139 ber_str2bv( buf
, 0, 0, &val
[ 0 ] );
1141 attr_merge_one( &rdi
->rdi_e
, ad_errCode
, &val
[ 0 ], NULL
);
1143 if ( rdi
->rdi_ref
!= NULL
) {
1144 attr_merge_normalize( &rdi
->rdi_e
, slap_schema
.si_ad_ref
,
1145 rdi
->rdi_ref
, NULL
);
1149 if ( !BER_BVISNULL( &rdi
->rdi_text
) ) {
1150 val
[ 0 ] = rdi
->rdi_text
;
1152 attr_merge_normalize_one( &rdi
->rdi_e
, ad_errText
, &val
[ 0 ], NULL
);
1156 if ( !BER_BVISNULL( &rdi
->rdi_matched
) ) {
1157 val
[ 0 ] = rdi
->rdi_matched
;
1159 attr_merge_normalize_one( &rdi
->rdi_e
, ad_errMatchedDN
, &val
[ 0 ], NULL
);
1163 if ( rdi
->rdi_sleeptime
) {
1164 snprintf( buf
, sizeof( buf
), "%d", rdi
->rdi_sleeptime
);
1165 ber_str2bv( buf
, 0, 0, &val
[ 0 ] );
1167 attr_merge_one( &rdi
->rdi_e
, ad_errSleepTime
, &val
[ 0 ], NULL
);
1171 if ( rdi
->rdi_mask
& SN_DG_OP_ADD
) {
1172 BER_BVSTR( &val
[ 0 ], "add" );
1173 attr_merge_normalize_one( &rdi
->rdi_e
, ad_errOp
, &val
[ 0 ], NULL
);
1176 if ( rdi
->rdi_mask
& SN_DG_OP_BIND
) {
1177 BER_BVSTR( &val
[ 0 ], "bind" );
1178 attr_merge_normalize_one( &rdi
->rdi_e
, ad_errOp
, &val
[ 0 ], NULL
);
1181 if ( rdi
->rdi_mask
& SN_DG_OP_COMPARE
) {
1182 BER_BVSTR( &val
[ 0 ], "compare" );
1183 attr_merge_normalize_one( &rdi
->rdi_e
, ad_errOp
, &val
[ 0 ], NULL
);
1186 if ( rdi
->rdi_mask
& SN_DG_OP_DELETE
) {
1187 BER_BVSTR( &val
[ 0 ], "delete" );
1188 attr_merge_normalize_one( &rdi
->rdi_e
, ad_errOp
, &val
[ 0 ], NULL
);
1191 if ( rdi
->rdi_mask
& SN_DG_EXTENDED
) {
1192 BER_BVSTR( &val
[ 0 ], "extended" );
1193 attr_merge_normalize_one( &rdi
->rdi_e
, ad_errOp
, &val
[ 0 ], NULL
);
1196 if ( rdi
->rdi_mask
& SN_DG_OP_MODIFY
) {
1197 BER_BVSTR( &val
[ 0 ], "modify" );
1198 attr_merge_normalize_one( &rdi
->rdi_e
, ad_errOp
, &val
[ 0 ], NULL
);
1201 if ( rdi
->rdi_mask
& SN_DG_OP_RENAME
) {
1202 BER_BVSTR( &val
[ 0 ], "rename" );
1203 attr_merge_normalize_one( &rdi
->rdi_e
, ad_errOp
, &val
[ 0 ], NULL
);
1206 if ( rdi
->rdi_mask
& SN_DG_OP_SEARCH
) {
1207 BER_BVSTR( &val
[ 0 ], "search" );
1208 attr_merge_normalize_one( &rdi
->rdi_e
, ad_errOp
, &val
[ 0 ], NULL
);
1216 retcode_db_destroy( BackendDB
*be
, ConfigReply
*cr
)
1218 slap_overinst
*on
= (slap_overinst
*)be
->bd_info
;
1219 retcode_t
*rd
= (retcode_t
*)on
->on_bi
.bi_private
;
1222 retcode_item_t
*rdi
, *next
;
1224 for ( rdi
= rd
->rd_item
; rdi
!= NULL
; rdi
= next
) {
1225 ber_memfree( rdi
->rdi_dn
.bv_val
);
1226 ber_memfree( rdi
->rdi_ndn
.bv_val
);
1228 if ( !BER_BVISNULL( &rdi
->rdi_text
) ) {
1229 ber_memfree( rdi
->rdi_text
.bv_val
);
1232 if ( !BER_BVISNULL( &rdi
->rdi_matched
) ) {
1233 ber_memfree( rdi
->rdi_matched
.bv_val
);
1236 if ( rdi
->rdi_ref
) {
1237 ber_bvarray_free( rdi
->rdi_ref
);
1240 BER_BVZERO( &rdi
->rdi_e
.e_name
);
1241 BER_BVZERO( &rdi
->rdi_e
.e_nname
);
1243 entry_clean( &rdi
->rdi_e
);
1245 next
= rdi
->rdi_next
;
1250 if ( !BER_BVISNULL( &rd
->rd_pdn
) ) {
1251 ber_memfree( rd
->rd_pdn
.bv_val
);
1254 if ( !BER_BVISNULL( &rd
->rd_npdn
) ) {
1255 ber_memfree( rd
->rd_npdn
.bv_val
);
1264 #if SLAPD_OVER_RETCODE == SLAPD_MOD_DYNAMIC
1266 #endif /* SLAPD_OVER_RETCODE == SLAPD_MOD_DYNAMIC */
1268 retcode_initialize( void )
1274 AttributeDescription
**ad
;
1276 { "( 1.3.6.1.4.1.4203.666.11.4.1.1 "
1277 "NAME ( 'errCode' ) "
1278 "DESC 'LDAP error code' "
1279 "EQUALITY integerMatch "
1280 "ORDERING integerOrderingMatch "
1281 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
1284 { "( 1.3.6.1.4.1.4203.666.11.4.1.2 "
1286 "DESC 'Operations the errObject applies to' "
1287 "EQUALITY caseIgnoreMatch "
1288 "SUBSTR caseIgnoreSubstringsMatch "
1289 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
1291 { "( 1.3.6.1.4.1.4203.666.11.4.1.3 "
1292 "NAME ( 'errText' ) "
1293 "DESC 'LDAP error textual description' "
1294 "EQUALITY caseIgnoreMatch "
1295 "SUBSTR caseIgnoreSubstringsMatch "
1296 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 "
1299 { "( 1.3.6.1.4.1.4203.666.11.4.1.4 "
1300 "NAME ( 'errSleepTime' ) "
1301 "DESC 'Time to wait before returning the error' "
1302 "EQUALITY integerMatch "
1303 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
1306 { "( 1.3.6.1.4.1.4203.666.11.4.1.5 "
1307 "NAME ( 'errMatchedDN' ) "
1308 "DESC 'Value to be returned as matched DN' "
1309 "EQUALITY distinguishedNameMatch "
1310 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 "
1313 { "( 1.3.6.1.4.1.4203.666.11.4.1.6 "
1314 "NAME ( 'errUnsolicitedOID' ) "
1315 "DESC 'OID to be returned within unsolicited response' "
1316 "EQUALITY objectIdentifierMatch "
1317 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 "
1319 &ad_errUnsolicitedOID
},
1320 { "( 1.3.6.1.4.1.4203.666.11.4.1.7 "
1321 "NAME ( 'errUnsolicitedData' ) "
1322 "DESC 'Data to be returned within unsolicited response' "
1323 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 "
1325 &ad_errUnsolicitedData
},
1326 { "( 1.3.6.1.4.1.4203.666.11.4.1.8 "
1327 "NAME ( 'errDisconnect' ) "
1328 "DESC 'Disconnect without notice' "
1329 "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 "
1331 &ad_errDisconnect
},
1339 { "( 1.3.6.1.4.1.4203.666.11.4.3.0 "
1340 "NAME ( 'errAbsObject' ) "
1350 "$ errUnsolicitedOID "
1351 "$ errUnsolicitedData "
1355 { "( 1.3.6.1.4.1.4203.666.11.4.3.1 "
1356 "NAME ( 'errObject' ) "
1357 "SUP errAbsObject STRUCTURAL "
1360 { "( 1.3.6.1.4.1.4203.666.11.4.3.2 "
1361 "NAME ( 'errAuxObject' ) "
1362 "SUP errAbsObject AUXILIARY "
1369 for ( i
= 0; retcode_at
[ i
].desc
!= NULL
; i
++ ) {
1370 code
= register_at( retcode_at
[ i
].desc
, retcode_at
[ i
].ad
, 0 );
1372 Debug( LDAP_DEBUG_ANY
,
1373 "retcode: register_at failed\n", 0, 0, 0 );
1377 (*retcode_at
[ i
].ad
)->ad_type
->sat_flags
|= SLAP_AT_HIDE
;
1380 for ( i
= 0; retcode_oc
[ i
].desc
!= NULL
; i
++ ) {
1381 code
= register_oc( retcode_oc
[ i
].desc
, retcode_oc
[ i
].oc
, 0 );
1383 Debug( LDAP_DEBUG_ANY
,
1384 "retcode: register_oc failed\n", 0, 0, 0 );
1388 (*retcode_oc
[ i
].oc
)->soc_flags
|= SLAP_OC_HIDE
;
1391 retcode
.on_bi
.bi_type
= "retcode";
1393 retcode
.on_bi
.bi_db_init
= retcode_db_init
;
1394 retcode
.on_bi
.bi_db_config
= retcode_db_config
;
1395 retcode
.on_bi
.bi_db_open
= retcode_db_open
;
1396 retcode
.on_bi
.bi_db_destroy
= retcode_db_destroy
;
1398 retcode
.on_bi
.bi_op_add
= retcode_op_func
;
1399 retcode
.on_bi
.bi_op_bind
= retcode_op_func
;
1400 retcode
.on_bi
.bi_op_compare
= retcode_op_func
;
1401 retcode
.on_bi
.bi_op_delete
= retcode_op_func
;
1402 retcode
.on_bi
.bi_op_modify
= retcode_op_func
;
1403 retcode
.on_bi
.bi_op_modrdn
= retcode_op_func
;
1404 retcode
.on_bi
.bi_op_search
= retcode_op_func
;
1406 retcode
.on_bi
.bi_extended
= retcode_op_func
;
1408 retcode
.on_response
= retcode_response
;
1410 return overlay_register( &retcode
);
1413 #if SLAPD_OVER_RETCODE == SLAPD_MOD_DYNAMIC
1415 init_module( int argc
, char *argv
[] )
1417 return retcode_initialize();
1419 #endif /* SLAPD_OVER_RETCODE == SLAPD_MOD_DYNAMIC */
1421 #endif /* SLAPD_OVER_RETCODE */