retcode.c 37.3 KB
Newer Older
Pierangelo Masarati's avatar
Pierangelo Masarati committed
1
/* retcode.c - customizable response for client testing purposes */
2
/* $OpenLDAP$ */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
3
4
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Quanah Gibson-Mount's avatar
Quanah Gibson-Mount committed
5
 * Copyright 2005-2021 The OpenLDAP Foundation.
Pierangelo Masarati's avatar
Pierangelo Masarati committed
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
 * Portions Copyright 2005 Pierangelo Masarati <ando@sys-net.it>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
 */
/* ACKNOWLEDGEMENTS:
 * This work was initially developed by Pierangelo Masarati for inclusion
 * in OpenLDAP Software.
 */

#include "portable.h"

#ifdef SLAPD_OVER_RETCODE

#include <stdio.h>

#include <ac/unistd.h>
#include <ac/string.h>
#include <ac/ctype.h>
#include <ac/socket.h>

#include "slap.h"
34
#include "config.h"
Pierangelo Masarati's avatar
Pierangelo Masarati committed
35
#include "lutil.h"
36
#include "ldif.h"
Pierangelo Masarati's avatar
Pierangelo Masarati committed
37
38
39
40
41
42
43

static slap_overinst		retcode;

static AttributeDescription	*ad_errCode;
static AttributeDescription	*ad_errText;
static AttributeDescription	*ad_errOp;
static AttributeDescription	*ad_errSleepTime;
44
static AttributeDescription	*ad_errMatchedDN;
45
46
static AttributeDescription	*ad_errUnsolicitedOID;
static AttributeDescription	*ad_errUnsolicitedData;
47
48
static AttributeDescription	*ad_errDisconnect;

49
static ObjectClass		*oc_errAbsObject;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
50
static ObjectClass		*oc_errObject;
51
static ObjectClass		*oc_errAuxObject;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

typedef enum retcode_op_e {
	SN_DG_OP_NONE		= 0x0000,
	SN_DG_OP_ADD		= 0x0001,
	SN_DG_OP_BIND		= 0x0002,
	SN_DG_OP_COMPARE	= 0x0004,
	SN_DG_OP_DELETE		= 0x0008,
	SN_DG_OP_MODIFY		= 0x0010,
	SN_DG_OP_RENAME		= 0x0020,
	SN_DG_OP_SEARCH		= 0x0040,
	SN_DG_EXTENDED		= 0x0080,
	SN_DG_OP_AUTH		= SN_DG_OP_BIND,
	SN_DG_OP_READ		= (SN_DG_OP_COMPARE|SN_DG_OP_SEARCH),
	SN_DG_OP_WRITE		= (SN_DG_OP_ADD|SN_DG_OP_DELETE|SN_DG_OP_MODIFY|SN_DG_OP_RENAME),
	SN_DG_OP_ALL		= (SN_DG_OP_AUTH|SN_DG_OP_READ|SN_DG_OP_WRITE|SN_DG_EXTENDED)
} retcode_op_e;

typedef struct retcode_item_t {
70
	struct berval		rdi_line;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
71
72
73
	struct berval		rdi_dn;
	struct berval		rdi_ndn;
	struct berval		rdi_text;
74
	struct berval		rdi_matched;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
75
76
77
78
79
	int			rdi_err;
	BerVarray		rdi_ref;
	int			rdi_sleeptime;
	Entry			rdi_e;
	slap_mask_t		rdi_mask;
80
81
	struct berval		rdi_unsolicited_oid;
	struct berval		rdi_unsolicited_data;
82
83

	unsigned		rdi_flags;
84
85
#define	RDI_PRE_DISCONNECT	(0x1U)
#define	RDI_POST_DISCONNECT	(0x2U)
86

Pierangelo Masarati's avatar
Pierangelo Masarati committed
87
88
89
90
91
92
93
	struct retcode_item_t	*rdi_next;
} retcode_item_t;

typedef struct retcode_t {
	struct berval		rd_pdn;
	struct berval		rd_npdn;

94
95
	int			rd_sleep;

Pierangelo Masarati's avatar
Pierangelo Masarati committed
96
97
	retcode_item_t		*rd_item;

98
	int			rd_indir;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
99
#define	RETCODE_FINDIR		0x01
100
#define	RETCODE_INDIR( rd )	( (rd)->rd_indir )
Pierangelo Masarati's avatar
Pierangelo Masarati committed
101
102
103
} retcode_t;

static int
Pierangelo Masarati's avatar
Pierangelo Masarati committed
104
retcode_entry_response( Operation *op, SlapReply *rs, BackendInfo *bi, Entry *e );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
105

106
107
108
static unsigned int
retcode_sleep( int s )
{
Howard Chu's avatar
Howard Chu committed
109
110
	unsigned int r = 0;

111
112
	/* sleep as required */
	if ( s < 0 ) {
113
#if 0	/* use high-order bits for better randomness (Numerical Recipes in "C") */
Howard Chu's avatar
Howard Chu committed
114
		r = rand() % (-s);
115
#endif
Howard Chu's avatar
Howard Chu committed
116
117
118
		r = ((double)(-s))*rand()/(RAND_MAX + 1.0);
	} else if ( s > 0 ) {
		r = (unsigned int)s;
119
	}
Howard Chu's avatar
Howard Chu committed
120
121
	if ( r ) {
		sleep( r );
122
123
	}

Howard Chu's avatar
Howard Chu committed
124
	return r;
125
126
}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
static int
retcode_cleanup_cb( Operation *op, SlapReply *rs )
{
	rs->sr_matched = NULL;
	rs->sr_text = NULL;

	if ( rs->sr_ref != NULL ) {
		ber_bvarray_free( rs->sr_ref );
		rs->sr_ref = NULL;
	}

	ch_free( op->o_callback );
	op->o_callback = NULL;

	return SLAP_CB_CONTINUE;
}

static int
retcode_send_onelevel( Operation *op, SlapReply *rs )
{
	slap_overinst	*on = (slap_overinst *)op->o_bd->bd_info;
	retcode_t	*rd = (retcode_t *)on->on_bi.bi_private;

	retcode_item_t	*rdi;
	
	for ( rdi = rd->rd_item; rdi != NULL; rdi = rdi->rdi_next ) {
		if ( op->o_abandon ) {
			return rs->sr_err = SLAPD_ABANDON;
		}

		rs->sr_err = test_filter( op, &rdi->rdi_e, op->ors_filter );
		if ( rs->sr_err == LDAP_COMPARE_TRUE ) {
			/* safe default */
			rs->sr_attrs = op->ors_attrs;
			rs->sr_operational_attrs = NULL;
			rs->sr_ctrls = NULL;
			rs->sr_flags = 0;
			rs->sr_err = LDAP_SUCCESS;
			rs->sr_entry = &rdi->rdi_e;

167
			rs->sr_err = send_search_entry( op, rs );
168
			rs->sr_flags = 0;
169
			rs->sr_entry = NULL;
170
			rs->sr_attrs = NULL;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
171

172
173
			switch ( rs->sr_err ) {
			case LDAP_UNAVAILABLE:	/* connection closed */
Pierangelo Masarati's avatar
Pierangelo Masarati committed
174
				rs->sr_err = LDAP_OTHER;
175
176
				/* fallthru */
			case LDAP_SIZELIMIT_EXCEEDED:
177
				goto done;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
			}
		}
		rs->sr_err = LDAP_SUCCESS;
	}

done:;

	send_ldap_result( op, rs );

	return rs->sr_err;
}

static int
retcode_op_add( Operation *op, SlapReply *rs )
{
Pierangelo Masarati's avatar
Pierangelo Masarati committed
193
	return retcode_entry_response( op, rs, NULL, op->ora_e );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
194
195
196
}

typedef struct retcode_cb_t {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
197
	BackendInfo	*rdc_info;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
198
199
	unsigned	rdc_flags;
	ber_tag_t	rdc_tag;
200
	AttributeName	*rdc_attrs;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
201
202
203
204
205
206
207
} retcode_cb_t;

static int
retcode_cb_response( Operation *op, SlapReply *rs )
{
	retcode_cb_t	*rdc = (retcode_cb_t *)op->o_callback->sc_private;

208
	op->o_tag = rdc->rdc_tag;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
209
210
211
212
	if ( rs->sr_type == REP_SEARCH ) {
		ber_tag_t	o_tag = op->o_tag;
		int		rc;

213
214
215
		if ( op->o_tag == LDAP_REQ_SEARCH ) {
			rs->sr_attrs = rdc->rdc_attrs;
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
216
		rc = retcode_entry_response( op, rs, rdc->rdc_info, rs->sr_entry );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
217
218
219
220
221
		op->o_tag = o_tag;

		return rc;
	}

222
223
224
225
226
	switch ( rs->sr_err ) {
	case LDAP_SUCCESS:
	case LDAP_NO_SUCH_OBJECT:
		/* in case of noSuchObject, stop the internal search
		 * for in-directory error stuff */
227
228
229
		if ( !op->o_abandon ) {
			rdc->rdc_flags = SLAP_CB_CONTINUE;
		}
230
		return 0;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
231
232
	}

233
	return SLAP_CB_CONTINUE;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
}

static int
retcode_op_internal( Operation *op, SlapReply *rs )
{
	slap_overinst	*on = (slap_overinst *)op->o_bd->bd_info;

	Operation	op2 = *op;
	BackendDB	db = *op->o_bd;
	slap_callback	sc = { 0 };
	retcode_cb_t	rdc;

	int		rc;

	op2.o_tag = LDAP_REQ_SEARCH;
	op2.ors_scope = LDAP_SCOPE_BASE;
	op2.ors_deref = LDAP_DEREF_NEVER;
	op2.ors_tlimit = SLAP_NO_LIMIT;
	op2.ors_slimit = SLAP_NO_LIMIT;
	op2.ors_limit = NULL;
	op2.ors_attrsonly = 0;
	op2.ors_attrs = slap_anlist_all_attributes;

257
258
	ber_str2bv_x( "(objectClass=errAbsObject)",
		STRLENOF( "(objectClass=errAbsObject)" ),
Pierangelo Masarati's avatar
Pierangelo Masarati committed
259
260
261
		1, &op2.ors_filterstr, op2.o_tmpmemctx );
	op2.ors_filter = str2filter_x( &op2, op2.ors_filterstr.bv_val );

262
263
264
	/* errAbsObject is defined by this overlay! */
	assert( op2.ors_filter != NULL );

Pierangelo Masarati's avatar
Pierangelo Masarati committed
265
266
267
	db.bd_info = on->on_info->oi_orig;
	op2.o_bd = &db;

Pierangelo Masarati's avatar
Pierangelo Masarati committed
268
	rdc.rdc_info = on->on_info->oi_orig;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
269
	rdc.rdc_flags = RETCODE_FINDIR;
270
271
	if ( op->o_tag == LDAP_REQ_SEARCH ) {
		rdc.rdc_attrs = op->ors_attrs;
272
	}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
273
274
275
276
277
	rdc.rdc_tag = op->o_tag;
	sc.sc_response = retcode_cb_response;
	sc.sc_private = &rdc;
	op2.o_callback = &sc;

278
279
	rc = op2.o_bd->be_search( &op2, rs );
	op->o_abandon = op2.o_abandon;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
280

281
	filter_free_x( &op2, op2.ors_filter, 1 );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
	ber_memfree_x( op2.ors_filterstr.bv_val, op2.o_tmpmemctx );

	if ( rdc.rdc_flags == SLAP_CB_CONTINUE ) {
		return SLAP_CB_CONTINUE;
	}

	return rc;
}

static int
retcode_op_func( Operation *op, SlapReply *rs )
{
	slap_overinst	*on = (slap_overinst *)op->o_bd->bd_info;
	retcode_t	*rd = (retcode_t *)on->on_bi.bi_private;

	retcode_item_t	*rdi;
	struct berval		nrdn, npdn;

	slap_callback		*cb = NULL;

302
	/* sleep as required */
303
	retcode_sleep( rd->rd_sleep );
304

Pierangelo Masarati's avatar
Pierangelo Masarati committed
305
306
307
308
309
310
311
	if ( !dnIsSuffix( &op->o_req_ndn, &rd->rd_npdn ) ) {
		if ( RETCODE_INDIR( rd ) ) {
			switch ( op->o_tag ) {
			case LDAP_REQ_ADD:
				return retcode_op_add( op, rs );

			case LDAP_REQ_BIND:
312
				/* skip if rootdn */
313
				/* FIXME: better give the db a chance? */
314
				if ( be_isroot_pw( op ) ) {
315
					return LDAP_SUCCESS;
316
				}
317
318
319
320
321
				return retcode_op_internal( op, rs );

			case LDAP_REQ_SEARCH:
				if ( op->ors_scope == LDAP_SCOPE_BASE ) {
					rs->sr_err = retcode_op_internal( op, rs );
322
323
324
325
326
					switch ( rs->sr_err ) {
					case SLAP_CB_CONTINUE:
						if ( rs->sr_nentries == 0 ) {
							break;
						}
327
						rs->sr_err = LDAP_SUCCESS;
328
329
330
331
332
						/* fallthru */

					default:
						send_ldap_result( op, rs );
						break;
333
334
335
336
					}
					return rs->sr_err;
				}
				break;
337
338

			case LDAP_REQ_MODIFY:
Pierangelo Masarati's avatar
Pierangelo Masarati committed
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
			case LDAP_REQ_DELETE:
			case LDAP_REQ_MODRDN:
			case LDAP_REQ_COMPARE:
				return retcode_op_internal( op, rs );
			}
		}

		return SLAP_CB_CONTINUE;
	}

	if ( op->o_tag == LDAP_REQ_SEARCH
			&& op->ors_scope != LDAP_SCOPE_BASE
			&& op->o_req_ndn.bv_len == rd->rd_npdn.bv_len )
	{
		return retcode_send_onelevel( op, rs );
	}

	dnParent( &op->o_req_ndn, &npdn );
	if ( npdn.bv_len != rd->rd_npdn.bv_len ) {
		rs->sr_err = LDAP_NO_SUCH_OBJECT;
		rs->sr_matched = rd->rd_pdn.bv_val;
		send_ldap_result( op, rs );
		rs->sr_matched = NULL;
		return rs->sr_err;
	}

	dnRdn( &op->o_req_ndn, &nrdn );

	for ( rdi = rd->rd_item; rdi != NULL; rdi = rdi->rdi_next ) {
		struct berval	rdi_nrdn;

		dnRdn( &rdi->rdi_ndn, &rdi_nrdn );
		if ( dn_match( &nrdn, &rdi_nrdn ) ) {
			break;
		}
	}

	if ( rdi != NULL && rdi->rdi_mask != SN_DG_OP_ALL ) {
		retcode_op_e	o_tag = SN_DG_OP_NONE;

		switch ( op->o_tag ) {
		case LDAP_REQ_ADD:
			o_tag = SN_DG_OP_ADD;
			break;

		case LDAP_REQ_BIND:
			o_tag = SN_DG_OP_BIND;
			break;

		case LDAP_REQ_COMPARE:
			o_tag = SN_DG_OP_COMPARE;
			break;

		case LDAP_REQ_DELETE:
			o_tag = SN_DG_OP_DELETE;
			break;

		case LDAP_REQ_MODIFY:
			o_tag = SN_DG_OP_MODIFY;
			break;

		case LDAP_REQ_MODRDN:
			o_tag = SN_DG_OP_RENAME;
			break;

		case LDAP_REQ_SEARCH:
			o_tag = SN_DG_OP_SEARCH;
			break;

		case LDAP_REQ_EXTENDED:
			o_tag = SN_DG_EXTENDED;
			break;

		default:
			/* Should not happen */
			break;
		}

		if ( !( o_tag & rdi->rdi_mask ) ) {
			return SLAP_CB_CONTINUE;
		}
	}

	if ( rdi == NULL ) {
		rs->sr_matched = rd->rd_pdn.bv_val;
		rs->sr_err = LDAP_NO_SUCH_OBJECT;
		rs->sr_text = "retcode not found";

	} else {
428
		if ( rdi->rdi_flags & RDI_PRE_DISCONNECT ) {
429
430
431
			return rs->sr_err = SLAPD_DISCONNECT;
		}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
432
433
		rs->sr_err = rdi->rdi_err;
		rs->sr_text = rdi->rdi_text.bv_val;
434
		rs->sr_matched = rdi->rdi_matched.bv_val;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
435
436
437
438
439
440
441
442

		/* FIXME: we only honor the rdi_ref field in case rdi_err
		 * is LDAP_REFERRAL otherwise send_ldap_result() bails out */
		if ( rs->sr_err == LDAP_REFERRAL ) {
			BerVarray	ref;

			if ( rdi->rdi_ref != NULL ) {
				ref = rdi->rdi_ref;
443
			} else {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
444
445
446
447
448
449
450
451
452
453
454
455
456
				ref = default_referral;
			}

			if ( ref != NULL ) {
				rs->sr_ref = referral_rewrite( ref,
					NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT );

			} else {
				rs->sr_err = LDAP_OTHER;
				rs->sr_text = "bad referral object";
			}
		}

457
		retcode_sleep( rdi->rdi_sleeptime );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
458
459
460
461
462
463
464
465
466
467
468
469
470
471
	}

	switch ( op->o_tag ) {
	case LDAP_REQ_EXTENDED:
		if ( rdi == NULL ) {
			break;
		}
		cb = ( slap_callback * )ch_malloc( sizeof( slap_callback ) );
		memset( cb, 0, sizeof( slap_callback ) );
		cb->sc_cleanup = retcode_cleanup_cb;
		op->o_callback = cb;
		break;

	default:
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
		if ( rdi && !BER_BVISNULL( &rdi->rdi_unsolicited_oid ) ) {
			ber_int_t	msgid = op->o_msgid;

			/* RFC 4511 unsolicited response */

			op->o_msgid = 0;
			if ( strcmp( rdi->rdi_unsolicited_oid.bv_val, "0" ) == 0 ) {
				send_ldap_result( op, rs );

			} else {
				ber_tag_t	tag = op->o_tag;

				op->o_tag = LDAP_REQ_EXTENDED;
				rs->sr_rspoid = rdi->rdi_unsolicited_oid.bv_val;
				if ( !BER_BVISNULL( &rdi->rdi_unsolicited_data ) ) {
					rs->sr_rspdata = &rdi->rdi_unsolicited_data;
				}
				send_ldap_extended( op, rs );
				rs->sr_rspoid = NULL;
				rs->sr_rspdata = NULL;
				op->o_tag = tag;

			}
			op->o_msgid = msgid;

		} else {
			send_ldap_result( op, rs );
		}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
501
502
		if ( rs->sr_ref != NULL ) {
			ber_bvarray_free( rs->sr_ref );
Pierangelo Masarati's avatar
cleanup    
Pierangelo Masarati committed
503
			rs->sr_ref = NULL;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
504
505
506
		}
		rs->sr_matched = NULL;
		rs->sr_text = NULL;
507
508
509
510

		if ( rdi && rdi->rdi_flags & RDI_POST_DISCONNECT ) {
			return rs->sr_err = SLAPD_DISCONNECT;
		}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
		break;
	}

	return rs->sr_err;
}

static int
retcode_op2str( ber_tag_t op, struct berval *bv )
{
	switch ( op ) {
	case LDAP_REQ_BIND:
		BER_BVSTR( bv, "bind" );
		return 0;
	case LDAP_REQ_ADD:
		BER_BVSTR( bv, "add" );
		return 0;
	case LDAP_REQ_DELETE:
		BER_BVSTR( bv, "delete" );
		return 0;
	case LDAP_REQ_MODRDN:
		BER_BVSTR( bv, "modrdn" );
		return 0;
	case LDAP_REQ_MODIFY:
		BER_BVSTR( bv, "modify" );
		return 0;
	case LDAP_REQ_COMPARE:
		BER_BVSTR( bv, "compare" );
		return 0;
	case LDAP_REQ_SEARCH:
		BER_BVSTR( bv, "search" );
		return 0;
	case LDAP_REQ_EXTENDED:
		BER_BVSTR( bv, "extended" );
		return 0;
	}
	return -1;
}

static int
Pierangelo Masarati's avatar
Pierangelo Masarati committed
550
retcode_entry_response( Operation *op, SlapReply *rs, BackendInfo *bi, Entry *e )
Pierangelo Masarati's avatar
Pierangelo Masarati committed
551
552
553
554
{
	Attribute	*a;
	int		err;
	char		*next;
555
	int		disconnect = 0;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
556
557
558
559
560

	if ( get_manageDSAit( op ) ) {
		return SLAP_CB_CONTINUE;
	}

561
	if ( !is_entry_objectclass_or_sub( e, oc_errAbsObject ) ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
		return SLAP_CB_CONTINUE;
	}

	/* operation */
	a = attr_find( e->e_attrs, ad_errOp );
	if ( a != NULL ) {
		int		i,
				gotit = 0;
		struct berval	bv = BER_BVNULL;

		(void)retcode_op2str( op->o_tag, &bv );

		if ( BER_BVISNULL( &bv ) ) {
			return SLAP_CB_CONTINUE;
		}

		for ( i = 0; !BER_BVISNULL( &a->a_nvals[ i ] ); i++ ) {
			if ( bvmatch( &a->a_nvals[ i ], &bv ) ) {
				gotit = 1;
				break;
			}
		}

		if ( !gotit ) {
			return SLAP_CB_CONTINUE;
		}
	}

590
591
	/* disconnect */
	a = attr_find( e->e_attrs, ad_errDisconnect );
592
593
594
595
596
	if ( a != NULL ) {
		if ( bvmatch( &a->a_nvals[ 0 ], &slap_true_bv ) ) {
			return rs->sr_err = SLAPD_DISCONNECT;
		}
		disconnect = 1;
597
598
	}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
599
600
601
602
603
604
605
606
607
608
609
610
611
	/* error code */
	a = attr_find( e->e_attrs, ad_errCode );
	if ( a == NULL ) {
		return SLAP_CB_CONTINUE;
	}
	err = strtol( a->a_nvals[ 0 ].bv_val, &next, 0 );
	if ( next == a->a_nvals[ 0 ].bv_val || next[ 0 ] != '\0' ) {
		return SLAP_CB_CONTINUE;
	}
	rs->sr_err = err;

	/* sleep time */
	a = attr_find( e->e_attrs, ad_errSleepTime );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
612
	if ( a != NULL && a->a_nvals[ 0 ].bv_val[ 0 ] != '-' ) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
613
614
		int	sleepTime;

615
616
		if ( lutil_atoi( &sleepTime, a->a_nvals[ 0 ].bv_val ) == 0 ) {
			retcode_sleep( sleepTime );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
617
618
619
		}
	}

620
	if ( rs->sr_err != LDAP_SUCCESS && !LDAP_API_ERROR( rs->sr_err )) {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
621
622
		BackendDB	db = *op->o_bd,
				*o_bd = op->o_bd;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
623
624
625
626
627
628
629
630
		void		*o_callback = op->o_callback;

		/* message text */
		a = attr_find( e->e_attrs, ad_errText );
		if ( a != NULL ) {
			rs->sr_text = a->a_vals[ 0 ].bv_val;
		}

631
632
633
634
635
636
		/* matched DN */
		a = attr_find( e->e_attrs, ad_errMatchedDN );
		if ( a != NULL ) {
			rs->sr_matched = a->a_vals[ 0 ].bv_val;
		}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
637
638
639
640
641
642
643
		if ( bi == NULL ) {
			slap_overinst	*on = (slap_overinst *)op->o_bd->bd_info;

			bi = on->on_info->oi_orig;
		}

		db.bd_info = bi;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
		op->o_bd = &db;
		op->o_callback = NULL;

		/* referral */
		if ( rs->sr_err == LDAP_REFERRAL ) {
			BerVarray	refs = default_referral;

			a = attr_find( e->e_attrs, slap_schema.si_ad_ref );
			if ( a != NULL ) {
				refs = a->a_vals;
			}
			rs->sr_ref = referral_rewrite( refs,
				NULL, &op->o_req_dn, op->oq_search.rs_scope );
	
			send_search_reference( op, rs );
			ber_bvarray_free( rs->sr_ref );
			rs->sr_ref = NULL;

		} else {
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
			a = attr_find( e->e_attrs, ad_errUnsolicitedOID );
			if ( a != NULL ) {
				struct berval	oid = BER_BVNULL,
						data = BER_BVNULL;
				ber_int_t	msgid = op->o_msgid;

				/* RFC 4511 unsolicited response */

				op->o_msgid = 0;

				oid = a->a_nvals[ 0 ];

				a = attr_find( e->e_attrs, ad_errUnsolicitedData );
				if ( a != NULL ) {
					data = a->a_nvals[ 0 ];
				}

				if ( strcmp( oid.bv_val, "0" ) == 0 ) {
					send_ldap_result( op, rs );

				} else {
					ber_tag_t	tag = op->o_tag;

					op->o_tag = LDAP_REQ_EXTENDED;
					rs->sr_rspoid = oid.bv_val;
					if ( !BER_BVISNULL( &data ) ) {
						rs->sr_rspdata = &data;
					}
					send_ldap_extended( op, rs );
					rs->sr_rspoid = NULL;
					rs->sr_rspdata = NULL;
					op->o_tag = tag;
				}
				op->o_msgid = msgid;

			} else {
				send_ldap_result( op, rs );
			}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
701
702
703
		}

		rs->sr_text = NULL;
704
		rs->sr_matched = NULL;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
705
		op->o_bd = o_bd;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
706
707
		op->o_callback = o_callback;
	}
708

Pierangelo Masarati's avatar
Pierangelo Masarati committed
709
	if ( rs->sr_err != LDAP_SUCCESS ) {
710
711
712
713
		if ( disconnect ) {
			return rs->sr_err = SLAPD_DISCONNECT;
		}
	
Pierangelo Masarati's avatar
Pierangelo Masarati committed
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
		op->o_abandon = 1;
		return rs->sr_err;
	}

	return SLAP_CB_CONTINUE;
}

static int
retcode_response( Operation *op, SlapReply *rs )
{
	slap_overinst	*on = (slap_overinst *)op->o_bd->bd_info;
	retcode_t	*rd = (retcode_t *)on->on_bi.bi_private;

	if ( rs->sr_type != REP_SEARCH || !RETCODE_INDIR( rd ) ) {
		return SLAP_CB_CONTINUE;
	}

Pierangelo Masarati's avatar
Pierangelo Masarati committed
731
	return retcode_entry_response( op, rs, NULL, rs->sr_entry );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
732
733
734
}

static int
735
retcode_db_init( BackendDB *be, ConfigReply *cr )
Pierangelo Masarati's avatar
Pierangelo Masarati committed
736
737
738
739
{
	slap_overinst	*on = (slap_overinst *)be->bd_info;
	retcode_t	*rd;

740
741
	srand( getpid() );

Pierangelo Masarati's avatar
Pierangelo Masarati committed
742
743
744
745
746
747
748
749
	rd = (retcode_t *)ch_malloc( sizeof( retcode_t ) );
	memset( rd, 0, sizeof( retcode_t ) );

	on->on_bi.bi_private = (void *)rd;

	return 0;
}

750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
static void
retcode_item_destroy( retcode_item_t *rdi )
{
	ber_memfree( rdi->rdi_line.bv_val );

	ber_memfree( rdi->rdi_dn.bv_val );
	ber_memfree( rdi->rdi_ndn.bv_val );

	if ( !BER_BVISNULL( &rdi->rdi_text ) ) {
		ber_memfree( rdi->rdi_text.bv_val );
	}

	if ( !BER_BVISNULL( &rdi->rdi_matched ) ) {
		ber_memfree( rdi->rdi_matched.bv_val );
	}

	if ( rdi->rdi_ref ) {
		ber_bvarray_free( rdi->rdi_ref );
	}

	BER_BVZERO( &rdi->rdi_e.e_name );
	BER_BVZERO( &rdi->rdi_e.e_nname );

	entry_clean( &rdi->rdi_e );

Hallvard Furuseth's avatar
Hallvard Furuseth committed
775
776
777
778
779
780
	if ( !BER_BVISNULL( &rdi->rdi_unsolicited_oid ) ) {
		ber_memfree( rdi->rdi_unsolicited_oid.bv_val );
		if ( !BER_BVISNULL( &rdi->rdi_unsolicited_data ) )
			ber_memfree( rdi->rdi_unsolicited_data.bv_val );
	}

781
782
	ch_free( rdi );
}
783
784
785

enum {
	RC_PARENT = 1,
786
	RC_ITEM
787
788
789
790
791
792
793
794
795
};

static ConfigDriver rc_cf_gen;

static ConfigTable rccfg[] = {
	{ "retcode-parent", "dn",
		2, 2, 0, ARG_MAGIC|ARG_DN|RC_PARENT, rc_cf_gen,
		"( OLcfgOvAt:20.1 NAME 'olcRetcodeParent' "
			"DESC '' "
796
			"EQUALITY distinguishedNameMatch "
797
			"SYNTAX OMsDN SINGLE-VALUE )", NULL, NULL },
798
	{ "retcode-item", "rdn> <retcode> <...",
799
800
801
		3, 0, 0, ARG_MAGIC|RC_ITEM, rc_cf_gen,
		"( OLcfgOvAt:20.2 NAME 'olcRetcodeItem' "
			"DESC '' "
802
	  		"EQUALITY caseIgnoreMatch "
803
			"SYNTAX OMsDirectoryString "
804
			"X-ORDERED 'VALUES' )", NULL, NULL },
805
806
807
808
809
	{ "retcode-indir", "on|off",
		1, 2, 0, ARG_OFFSET|ARG_ON_OFF,
			(void *)offsetof(retcode_t, rd_indir),
		"( OLcfgOvAt:20.3 NAME 'olcRetcodeInDir' "
			"DESC '' "
810
			"EQUALITY booleanMatch "
811
812
813
			"SYNTAX OMsBoolean SINGLE-VALUE )", NULL, NULL },

	{ "retcode-sleep", "sleeptime",
814
		2, 2, 0, ARG_OFFSET|ARG_INT,
815
816
817
			(void *)offsetof(retcode_t, rd_sleep),
		"( OLcfgOvAt:20.4 NAME 'olcRetcodeSleep' "
			"DESC '' "
818
			"EQUALITY integerMatch "
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
			"SYNTAX OMsInteger SINGLE-VALUE )", NULL, NULL },

	{ NULL, NULL, 0, 0, 0, ARG_IGNORED }
};

static ConfigOCs rcocs[] = {
	{ "( OLcfgOvOc:20.1 "
		"NAME 'olcRetcodeConfig' "
		"DESC 'Retcode configuration' "
		"SUP olcOverlayConfig "
		"MAY ( olcRetcodeParent "
			"$ olcRetcodeItem "
			"$ olcRetcodeInDir "
			"$ olcRetcodeSleep "
		") )",
		Cft_Overlay, rccfg, NULL, NULL },
	{ NULL, 0, NULL }
};

Pierangelo Masarati's avatar
Pierangelo Masarati committed
838
static int
839
rc_cf_gen( ConfigArgs *c )
Pierangelo Masarati's avatar
Pierangelo Masarati committed
840
{
841
	slap_overinst	*on = (slap_overinst *)c->bi;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
842
	retcode_t	*rd = (retcode_t *)on->on_bi.bi_private;
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
	int		rc = ARG_BAD_CONF;

	if ( c->op == SLAP_CONFIG_EMIT ) {
		switch( c->type ) {
		case RC_PARENT:
			if ( !BER_BVISEMPTY( &rd->rd_pdn )) {
				rc = value_add_one( &c->rvalue_vals,
						    &rd->rd_pdn );
				if ( rc == 0 ) {
					rc = value_add_one( &c->rvalue_nvals,
							    &rd->rd_npdn );
				}
				return rc;
			}
			rc = 0;
			break;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
859

860
861
		case RC_ITEM: {
			retcode_item_t *rdi;
862
863
864
865
866
867
868
869
870
871
872
873
874
			int i;

			for ( rdi = rd->rd_item, i = 0; rdi; rdi = rdi->rdi_next, i++ ) {
				char buf[4096];
				struct berval bv;
				char *ptr;

				bv.bv_len = snprintf( buf, sizeof( buf ), SLAP_X_ORDERED_FMT, i );
				bv.bv_len += rdi->rdi_line.bv_len;
				ptr = bv.bv_val = ch_malloc( bv.bv_len + 1 );
				ptr = lutil_strcopy( ptr, buf );
				ptr = lutil_strncopy( ptr, rdi->rdi_line.bv_val, rdi->rdi_line.bv_len );
				ber_bvarray_add( &c->rvalue_vals, &bv );
875
876
877
			}
			rc = 0;
			} break;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
878

879
880
881
		default:
			assert( 0 );
			break;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
882
883
		}

884
		return rc;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
885

886
	} else if ( c->op == LDAP_MOD_DELETE ) {
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
		switch( c->type ) {
		case RC_PARENT:
			if ( rd->rd_pdn.bv_val ) {
				ber_memfree ( rd->rd_pdn.bv_val );
				rc = 0;
			}
			if ( rd->rd_npdn.bv_val ) {
				ber_memfree ( rd->rd_npdn.bv_val );
			}
			break;

		case RC_ITEM:
			if ( c->valx == -1 ) {
				retcode_item_t *rdi, *next;

				for ( rdi = rd->rd_item; rdi != NULL; rdi = next ) {
					next = rdi->rdi_next;
					retcode_item_destroy( rdi );
				}

			} else {
				retcode_item_t **rdip, *rdi;
				int i;

				for ( rdip = &rd->rd_item, i = 0; i <= c->valx && *rdip; i++, rdip = &(*rdip)->rdi_next )
					;
				if ( *rdip == NULL ) {
					return 1;
				}
				rdi = *rdip;
				*rdip = rdi->rdi_next;

				retcode_item_destroy( rdi );
			}
			rc = 0;
			break;

		default:
			assert( 0 );
			break;
		}
		return rc;	/* FIXME */
929
	}
Pierangelo Masarati's avatar
Pierangelo Masarati committed
930

931
932
933
934
935
936
937
	switch( c->type ) {
	case RC_PARENT:
		if ( rd->rd_pdn.bv_val ) {
			ber_memfree ( rd->rd_pdn.bv_val );
		}
		if ( rd->rd_npdn.bv_val ) {
			ber_memfree ( rd->rd_npdn.bv_val );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
938
		}
939
940
941
942
		rd->rd_pdn = c->value_dn;
		rd->rd_npdn = c->value_ndn;
		rc = 0;
		break;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
943

944
	case RC_ITEM: {
Pierangelo Masarati's avatar
Pierangelo Masarati committed
945
946
947
		retcode_item_t	rdi = { BER_BVNULL }, **rdip;
		struct berval		bv, rdn, nrdn;
		char			*next = NULL;
948
		int			i;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
949

950
951
		if ( c->argc < 3 ) {
			snprintf( c->cr_msg, sizeof(c->cr_msg),
Pierangelo Masarati's avatar
Pierangelo Masarati committed
952
				"\"retcode-item <RDN> <retcode> [<text>]\": "
953
954
				"missing args" );
			Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n",
955
				c->log, c->cr_msg );
956
			return ARG_BAD_CONF;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
957
958
		}

959
		ber_str2bv( c->argv[ 1 ], 0, 0, &bv );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
960
961
962
		
		rc = dnPrettyNormal( NULL, &bv, &rdn, &nrdn, NULL );
		if ( rc != LDAP_SUCCESS ) {
963
964
965
966
			snprintf( c->cr_msg, sizeof(c->cr_msg),
				"unable to normalize RDN \"%s\": %d",
				c->argv[ 1 ], rc );
			Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n",
967
				c->log, c->cr_msg );
968
			return ARG_BAD_CONF;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
969
970
971
		}

		if ( !dnIsOneLevelRDN( &nrdn ) ) {
972
973
974
975
			snprintf( c->cr_msg, sizeof(c->cr_msg),
				"value \"%s\" is not a RDN",
				c->argv[ 1 ] );
			Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n",
976
				c->log, c->cr_msg );
977
			return ARG_BAD_CONF;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
978
979
980
981
		}

		if ( BER_BVISNULL( &rd->rd_npdn ) ) {
			/* FIXME: we use the database suffix */
982
983
			if ( c->be->be_nsuffix == NULL ) {
				snprintf( c->cr_msg, sizeof(c->cr_msg),
Pierangelo Masarati's avatar
Pierangelo Masarati committed
984
					"either \"retcode-parent\" "
985
986
					"or \"suffix\" must be defined" );
				Debug( LDAP_DEBUG_CONFIG, "%s: retcode: %s\n",
987
					c->log, c->cr_msg );
988
				return ARG_BAD_CONF;
Pierangelo Masarati's avatar
Pierangelo Masarati committed
989
990
			}

991
992
			ber_dupbv( &rd->rd_pdn, &c->be->be_suffix[ 0 ] );
			ber_dupbv( &rd->rd_npdn, &c->be->be_nsuffix[ 0 ] );
Pierangelo Masarati's avatar
Pierangelo Masarati committed
993
994
995
996
997
998
999
1000
		}

		build_new_dn( &rdi.rdi_dn, &rd->rd_pdn, &rdn, NULL );
		build_new_dn( &rdi.rdi_ndn, &rd->rd_npdn, &nrdn, NULL );

		ch_free( rdn.bv_val );
		ch_free( nrdn.bv_val );

For faster browsing, not all history is shown. View entire blame