result.c 18.6 KB
Newer Older
Kurt Zeilenga's avatar
Kurt Zeilenga committed
1
2
3
/* result.c - routines to send ldap results, errors, and referrals */

#include "portable.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
4
5
6

#include <stdio.h>

7
#include <ac/socket.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
8
9
10
#include <ac/errno.h>
#include <ac/signal.h>
#include <ac/string.h>
Hallvard Furuseth's avatar
Hallvard Furuseth committed
11
#include <ac/ctype.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
12
#include <ac/time.h>
13
#include <ac/unistd.h>
Kurt Zeilenga's avatar
Kurt Zeilenga committed
14

15
#include "ldap_defaults.h"
Kurt Zeilenga's avatar
Kurt Zeilenga committed
16
17
#include "slap.h"

Kurt Zeilenga's avatar
Kurt Zeilenga committed
18
19
20
/* we need LBER internals */
#include "../../libraries/liblber/lber-int.h"

21
static char *v2ref( struct berval **ref )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
22
{
23
24
	size_t len, i;
	char *v2;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
25

26
	if(ref == NULL) return NULL;
27

28
29
	len = sizeof("Referral:");
	v2 = ch_strdup("Referral:");
30

31
32
33
34
35
36
	for( i=0; ref[i] != NULL; i++ ) {
		v2 = ch_realloc( v2, len + ref[i]->bv_len + 1 );
		v2[len-1] = '\n';
		memcpy(&v2[len], ref[i]->bv_val, ref[i]->bv_len );
		len += ref[i]->bv_len;
	}
37

38
39
40
	v2[len-1] = '\0';
	return v2;
}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
41

42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
static ber_tag_t req2res( ber_tag_t tag )
{
	switch( tag ) {
	case LDAP_REQ_ADD:
	case LDAP_REQ_BIND:
	case LDAP_REQ_COMPARE:
	case LDAP_REQ_EXTENDED:
	case LDAP_REQ_MODIFY:
	case LDAP_REQ_MODRDN:
		tag++;
		break;

	case LDAP_REQ_DELETE:
		tag = LDAP_RES_DELETE;
		break;

	case LDAP_REQ_ABANDON:
	case LDAP_REQ_UNBIND:
		tag = LBER_SEQUENCE;
		break;

	case LDAP_REQ_SEARCH:
		tag = LDAP_RES_SEARCH_RESULT;
		break;

	default:
		assert( 0 );
		tag = LBER_ERROR;
	}
	return tag;
}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
73

74
75
76
77
static void trim_refs_urls(
	struct berval **refs )
{
	unsigned i;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
78

79
	if( refs == NULL ) return;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
80

81
82
83
84
85
86
87
88
89
90
91
92
93
	for( i=0; refs[i] != NULL; i++ ) {
		if(	refs[i]->bv_len > sizeof("ldap://") &&
			strncasecmp( refs[i]->bv_val, "ldap://",
				sizeof("ldap://")-1 ) == 0 )
		{
			unsigned j;
			for( j=sizeof("ldap://"); j<refs[i]->bv_len ; j++ ) {
				if( refs[i]->bv_val[j] = '/' ) {
					refs[i]->bv_val[j] = '\0';
					refs[i]->bv_len = j;
					break;
				}
			}
94
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
95
	}
96
}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
97

98
99
100
101
102
103
104
105
106
struct berval **get_entry_referrals(
	Backend *be,
	Connection *conn,
	Operation *op,
	Entry *e )
{
	Attribute *attr;
	struct berval **refs;
	unsigned i, j;
107

108
	attr = attr_find( e->e_attrs, "ref" );
109

110
111
112
113
	if( attr == NULL ) return NULL;

	for( i=0; attr->a_vals[i] != NULL; i++ ) {
		/* count references */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
114
115
	}

116
	if( i < 1 ) return NULL;
117

118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
	refs = ch_malloc( i + 1 );

	for( i=0, j=0; attr->a_vals[i] != NULL; i++ ) {
		unsigned k;
		struct berval *ref = ber_bvdup( attr->a_vals[i] );

		/* trim the label */
		for( k=0; k<ref->bv_len; k++ ) {
			if( isspace(ref->bv_val[k]) ) {
				ref->bv_val[k] = '\0';
				ref->bv_len = k;
				break;
			}
		}

		if(	ref->bv_len > 0 ) {
			refs[j++] = ref;

		} else {
			ber_bvfree( ref );
		}
139
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
140

141
142
143
144
145
	refs[j] = NULL;

	if( j == 0 ) {
		ber_bvecfree( refs );
		refs = NULL;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
146
147
	}

148
149
150
151
152
153
154
155
156
157
158
	/* we should check that a referral value exists... */

	return refs;
}

static long send_ldap_ber(
	Connection *conn,
	BerElement *ber )
{
	ber_len_t bytes = ber_pvt_ber_bytes( ber );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
159
	/* write only one pdu at a time - wait til it's our turn */
160
161
	ldap_pvt_thread_mutex_lock( &conn->c_write_mutex );

162
	/* lock the connection */ 
163
	ldap_pvt_thread_mutex_lock( &conn->c_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
164
165

	/* write the pdu */
166
	while( 1 ) {
167
168
169
170
171
		int err;

		if ( connection_state_closing( conn ) ) {
			ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
			ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
172

173
			return 0;
174
175
		}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
176
		if ( ber_flush( conn->c_sb, ber, 0 ) == 0 ) {
177
178
179
180
181
			break;
		}

		err = errno;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
182
183
184
185
186
187
		/*
		 * we got an error.  if it's ewouldblock, we need to
		 * wait on the socket being writable.  otherwise, figure
		 * it's a hard error and return.
		 */

Kurt Zeilenga's avatar
Kurt Zeilenga committed
188
		Debug( LDAP_DEBUG_CONNS, "ber_flush failed errno=%d reason=\"%s\"\n",
189
		    err, err > -1 && err < sys_nerr ? sys_errlist[err]
Kurt Zeilenga's avatar
Kurt Zeilenga committed
190
191
		    : "unknown", 0 );

192
		if ( err != EWOULDBLOCK && err != EAGAIN ) {
193
			connection_closing( conn );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
194

195
196
			ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
			ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
197

198
			return( -1 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
199
200
201
202
		}

		/* wait for socket to be write-ready */
		conn->c_writewaiter = 1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
203
		slapd_set_write( ber_pvt_sb_get_desc( conn->c_sb ), 1 );
204

205
206
		ldap_pvt_thread_cond_wait( &conn->c_write_cv, &conn->c_mutex );
		conn->c_writewaiter = 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
207
208
	}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
209
	ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
210
211
	ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );

212
213
214
215
216
217
218
219
220
221
	return bytes;
}

static void
send_ldap_response(
    Connection	*conn,
    Operation	*op,
	ber_tag_t	tag,
	ber_int_t	msgid,
    ber_int_t	err,
222
223
    const char	*matched,
    const char	*text,
224
	struct berval	**ref,
225
	const char	*resoid,
226
227
228
229
230
231
232
233
234
235
236
237
	struct berval	*resdata,
	LDAPControl **ctrls
)
{
	BerElement	*ber;
	int		rc;
	long	bytes;

	assert( ctrls == NULL ); /* ctrls not implemented */

	ber = ber_alloc_t( LBER_USE_DER );

238
239
	Debug( LDAP_DEBUG_TRACE, "send_ldap_response: msgid=%ld tag=%ld err=%ld\n",
		(long) msgid, (long) tag, (long) err );
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277

	if ( ber == NULL ) {
		Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
		return;
	}

#ifdef LDAP_CONNECTIONLESS
	if ( op->o_cldap ) {
		rc = ber_printf( ber, "{is{t{ess}}}", msgid, "", tag,
		    err, matched ? matched : "", text ? text : "" );
	} else
#endif
	{
		rc = ber_printf( ber, "{it{ess",
			msgid, tag, err,
			matched == NULL ? "" : matched,
			text == NULL ? "" : text );

		if( rc != -1 && ref != NULL ) {
			rc = ber_printf( ber, "{V}", ref );
		}

		if( rc != -1 && resoid != NULL ) {
			rc = ber_printf( ber, "s", resoid );
		}

		if( rc != -1 && resdata != NULL ) {
			rc = ber_printf( ber, "O", resdata );

		}

		if( rc != -1 ) {
			rc = ber_printf( ber, "}}" );
		}
	}

	if ( rc == -1 ) {
		Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
278
		ber_free( ber, 1 );
279
280
281
282
283
		return;
	}

	/* send BER */
	bytes = send_ldap_ber( conn, ber );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
284
	ber_free( ber, 1 );
285
286
287
288
289
290
291
292

	if ( bytes < 0 ) {
		Debug( LDAP_DEBUG_ANY,
			"send_ldap_response: ber write failed\n",
			0, 0, 0 );
		return;
	}

293
	ldap_pvt_thread_mutex_lock( &num_sent_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
294
	num_bytes_sent += bytes;
295
	num_pdu_sent++;
296
	ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
297
298
299
	return;
}

300

Kurt Zeilenga's avatar
Kurt Zeilenga committed
301
void
302
send_ldap_disconnect(
Kurt Zeilenga's avatar
Kurt Zeilenga committed
303
304
    Connection	*conn,
    Operation	*op,
305
    ber_int_t	err,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
306
    const char	*text
Kurt Zeilenga's avatar
Kurt Zeilenga committed
307
308
)
{
309
310
311
	ber_tag_t tag;
	ber_int_t msgid;
	char *reqoid;
312

313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
#define LDAP_UNSOLICITED_ERROR(e) \
	(  (e) == LDAP_PROTOCOL_ERROR \
	|| (e) == LDAP_STRONG_AUTH_REQUIRED \
	|| (e) == LDAP_UNAVAILABLE )

	assert( LDAP_UNSOLICITED_ERROR( err ) );

	Debug( LDAP_DEBUG_TRACE,
		"send_ldap_disconnect %d:%s\n",
		err, text ? text : "", NULL );

	if ( op->o_protocol < LDAP_VERSION3 ) {
		reqoid = NULL;
		tag = req2res( op->o_tag );
		msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;

	} else {
		reqoid = LDAP_NOTICE_DISCONNECT;
		tag = LDAP_RES_EXTENDED;
		msgid = 0;
	}
334

Kurt Zeilenga's avatar
Kurt Zeilenga committed
335
#ifdef LDAP_CONNECTIONLESS
Kurt Zeilenga's avatar
Kurt Zeilenga committed
336
	if ( op->o_cldap ) {
337
		ber_pvt_sb_udp_set_dst( conn->c_sb, &op->o_clientaddr );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
338
339
		Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
		    inet_ntoa(((struct sockaddr_in *)
340
341
		    &op->o_clientaddr)->sin_addr ),
		    ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
342
343
344
		    0 );
	}
#endif
345
346
347
348
349
350
	send_ldap_response( conn, op, tag, msgid,
		err, NULL, text, NULL,
		reqoid, NULL, NULL );

	Statslog( LDAP_DEBUG_STATS,
	    "conn=%ld op=%ld DISCONNECT err=%ld tag=%lu text=%s\n",
351
		(long) op->o_connid, (long) op->o_opid,
352
		(long) tag, (long) err, text ? text : "" );
353
354
355
}

void
356
send_ldap_result(
357
358
359
    Connection	*conn,
    Operation	*op,
    ber_int_t	err,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
360
361
    const char	*matched,
    const char	*text,
362
363
	struct berval **ref,
	LDAPControl **ctrls
364
365
)
{
366
367
368
369
	ber_tag_t tag;
	ber_int_t msgid;
	char *tmp = NULL;

370
371
	assert( !LDAP_API_ERROR( err ) );

372
373
374
	Debug( LDAP_DEBUG_TRACE, "send_ldap_result: conn=%ld op=%ld p=%d\n",
		(long) op->o_connid, (long) op->o_opid, op->o_protocol );
	Debug( LDAP_DEBUG_ARGS, "send_ldap_result: %d:%s:%s\n",
375
376
377
378
379
380
381
382
383
384
385
386
387
		err, matched ?  matched : "", text ? text : "" );

	assert( err != LDAP_PARTIAL_RESULTS );

	if( op->o_tag != LDAP_REQ_SEARCH ) {
		trim_refs_urls( ref );
	}

	if ( err == LDAP_REFERRAL ) {
		if( ref == NULL ) {
			err = LDAP_NO_SUCH_OBJECT;
		} else if ( op->o_protocol < LDAP_VERSION3 ) {
			err = LDAP_PARTIAL_RESULTS;
388
389
			tmp = v2ref( ref );
			text = tmp;
390
391
392
393
394
395
			ref = NULL;
		}
	}

	tag = req2res( op->o_tag );
	msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
396
397
398

#ifdef LDAP_CONNECTIONLESS
	if ( op->o_cldap ) {
399
		ber_pvt_sb_udp_set_dst( conn->c_sb, &op->o_clientaddr );
400
401
402
403
404
405
406
		Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
		    inet_ntoa(((struct sockaddr_in *)
		    &op->o_clientaddr)->sin_addr ),
		    ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
		    0 );
	}
#endif
407
408
409
410
411
412

	send_ldap_response( conn, op, tag, msgid,
		err, matched, text, ref,
		NULL, NULL, ctrls );

	Statslog( LDAP_DEBUG_STATS,
413
	    "conn=%ld op=%ld RESULT tag=%lu err=%ld text=%s\n",
414
		(long) op->o_connid, (long) op->o_opid,
415
		(long) tag, (long) err, text ? text : "" );
416
417
418
419

	if( tmp != NULL ) {
		free(tmp);
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
420
421
}

422

Kurt Zeilenga's avatar
Kurt Zeilenga committed
423
void
424
send_search_result(
Kurt Zeilenga's avatar
Kurt Zeilenga committed
425
426
    Connection	*conn,
    Operation	*op,
427
    ber_int_t	err,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
428
429
    const char	*matched,
	const char	*text,
430
431
    struct berval **refs,
	LDAPControl **ctrls,
Kurt Zeilenga's avatar
Kurt Zeilenga committed
432
433
434
    int		nentries
)
{
435
436
437
438
439
	ber_tag_t tag;
	ber_int_t msgid;
	char *tmp = NULL;
	assert( !LDAP_API_ERROR( err ) );

440
441
442
	Debug( LDAP_DEBUG_TRACE, "send_ldap_search_result %d:%s:%s\n",
		err, matched ?  matched : "", text ? text : "" );

443
444
445
446
447
448
449
450
451
452
	assert( err != LDAP_PARTIAL_RESULTS );

	trim_refs_urls( refs );

	if( op->o_protocol < LDAP_VERSION3 ) {
		/* send references in search results */
		if( err == LDAP_REFERRAL ) {
			err = LDAP_PARTIAL_RESULTS;
		}

453
454
		tmp = v2ref( refs );
		text = tmp;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
455
456
		refs = NULL;

457
458
	} else {
		/* don't send references in search results */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
459
460
461
		assert( refs == NULL );
		refs = NULL;

462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
		if( err == LDAP_REFERRAL ) {
			err = LDAP_SUCCESS;
		}
	}

	tag = req2res( op->o_tag );
	msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;

#ifdef LDAP_CONNECTIONLESS
	if ( op->o_cldap ) {
		ber_pvt_sb_udp_set_dst( &conn->c_sb, &op->o_clientaddr );
		Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
		    inet_ntoa(((struct sockaddr_in *)
		    &op->o_clientaddr)->sin_addr ),
		    ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
		    0 );
	}
#endif

	send_ldap_response( conn, op, tag, msgid,
		err, matched, text, refs,
		NULL, NULL, ctrls );

	Statslog( LDAP_DEBUG_STATS,
486
	    "conn=%ld op=%ld SEARCH RESULT tag=%lu err=%ld text=%s\n",
487
		(long) op->o_connid, (long) op->o_opid,
488
		(long) tag, (long) err, text ? text : "" );
489

Kurt Zeilenga's avatar
Kurt Zeilenga committed
490
491
}

492

Kurt Zeilenga's avatar
Kurt Zeilenga committed
493
494
495
496
497
498
499
int
send_search_entry(
    Backend	*be,
    Connection	*conn,
    Operation	*op,
    Entry	*e,
    char	**attrs,
500
    int		attrsonly,
501
	LDAPControl **ctrls
Kurt Zeilenga's avatar
Kurt Zeilenga committed
502
503
504
505
)
{
	BerElement	*ber;
	Attribute	*a;
506
	int		i, rc=-1, bytes;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
507
	AccessControl	*acl;
508
	char            *edn;
509
510
	int		userattrs;
	int		opattrs;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
511

512
	Debug( LDAP_DEBUG_TRACE, "=> send_search_entry: \"%s\"\n", e->e_dn, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
513

514
515
516
	if ( ! access_allowed( be, conn, op, e,
		"entry", NULL, ACL_READ ) )
	{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
517
518
519
520
521
		Debug( LDAP_DEBUG_ACL, "acl: access to entry not allowed\n",
		    0, 0, 0 );
		return( 1 );
	}

522
	edn = e->e_ndn;
523

524
	ber = ber_alloc_t( LBER_USE_DER );
525
526

	if ( ber == NULL ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
527
		Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
528
529
		send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
			NULL, "allocating BER error", NULL, NULL );
530
		goto error_return;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
531
532
	}

533
534
	rc = ber_printf( ber, "{it{s{", op->o_msgid,
		LDAP_RES_SEARCH_ENTRY, e->e_dn );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
535
536
537
538

	if ( rc == -1 ) {
		Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
		ber_free( ber, 1 );
539
540
		send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
		    NULL, "encoding dn error", NULL, NULL );
541
		goto error_return;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
542
543
	}

544
545
	/* check for special all user attributes ("*") type */
	userattrs = ( attrs == NULL ) ? 1
546
547
		: charray_inlist( attrs, LDAP_ALL_USER_ATTRIBUTES );

548
549
550
551
	/* check for special all operational attributes ("+") type */
	opattrs = ( attrs == NULL ) ? 0
		: charray_inlist( attrs, LDAP_ALL_OPERATIONAL_ATTRIBUTES );

Kurt Zeilenga's avatar
Kurt Zeilenga committed
552
	for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
553
554
		regmatch_t       matches[MAXREMATCHES];

555
556
		if ( attrs == NULL ) {
			/* all addrs request, skip operational attributes */
557
			if( !opattrs && oc_check_operational_attr( a->a_type ) ) {
558
559
				continue;
			}
560

561
		} else {
562
			/* specific addrs requested */
563
564
565
566
567
568
569
			if (  oc_check_operational_attr( a->a_type ) ) {
				if( !opattrs && !charray_inlist( attrs, a->a_type ) )
				{
					continue;
				}
			} else {
				if (!userattrs && !charray_inlist( attrs, a->a_type ) )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
570
571
572
				{
					continue;
				}
573
			}
574
		}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
575

576
577
578
		acl = acl_get_applicable( be, op, e, a->a_type,
			MAXREMATCHES, matches );

579
		if ( ! acl_access_allowed( acl, a->a_type, be, conn, e,
580
			NULL, op, ACL_READ, edn, matches ) ) 
581
		{
Kurt Zeilenga's avatar
Kurt Zeilenga committed
582
583
584
			continue;
		}

585
		if (( rc = ber_printf( ber, "{s[" /*]}*/ , a->a_type )) == -1 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
586
587
588
			Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
			ber_free( ber, 1 );
			send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
589
			    NULL, "encoding type error", NULL, NULL );
590
			goto error_return;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
591
592
593
594
		}

		if ( ! attrsonly ) {
			for ( i = 0; a->a_vals[i] != NULL; i++ ) {
595
				if ( a->a_syntax & SYNTAX_DN && 
596
					! acl_access_allowed( acl, a->a_type, be, conn, e, a->a_vals[i], op,
597
						ACL_READ, edn, matches) )
Kurt Zeilenga's avatar
Kurt Zeilenga committed
598
599
600
601
				{
					continue;
				}

602
				if (( rc = ber_printf( ber, "O", a->a_vals[i] )) == -1 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
603
604
605
					Debug( LDAP_DEBUG_ANY,
					    "ber_printf failed\n", 0, 0, 0 );
					ber_free( ber, 1 );
606
607
					send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
						NULL, "encoding value error", NULL, NULL );
608
					goto error_return;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
609
610
611
612
				}
			}
		}

613
		if (( rc = ber_printf( ber, /*{[*/ "]}" )) == -1 ) {
Kurt Zeilenga's avatar
Kurt Zeilenga committed
614
615
616
			Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
			ber_free( ber, 1 );
			send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
617
			    NULL, "encode end error", NULL, NULL );
618
			goto error_return;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
619
620
621
		}
	}

622
#ifdef SLAPD_SCHEMA_DN
623
624
	/* eventually will loop through generated operational attributes */
	/* only have subschemaSubentry implemented */
625
626
627
628
629
630
631
632
633
634
635
636
637
	a = backend_subschemasubentry( be );
	
	do {
		regmatch_t       matches[MAXREMATCHES];

		if ( attrs == NULL ) {
			/* all addrs request, skip operational attributes */
			if( !opattrs && oc_check_operational_attr( a->a_type ) ) {
				continue;
			}

		} else {
			/* specific addrs requested */
638
639
640
641
642
643
644
			if (  oc_check_operational_attr( a->a_type ) ) {
				if( !opattrs && !charray_inlist( attrs, a->a_type ) )
				{
					continue;
				}
			} else {
				if (!userattrs && !charray_inlist( attrs, a->a_type ) )
645
646
647
648
649
650
651
652
653
				{
					continue;
				}
			}
		}

		acl = acl_get_applicable( be, op, e, a->a_type,
			MAXREMATCHES, matches );

654
		if ( ! acl_access_allowed( acl, a->a_type, be, conn, e,
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
			NULL, op, ACL_READ, edn, matches ) ) 
		{
			continue;
		}

		if (( rc = ber_printf( ber, "{s[" /*]}*/ , a->a_type )) == -1 ) {
			Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
			ber_free( ber, 1 );
			send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
			    NULL, "encoding type error", NULL, NULL );
			goto error_return;
		}

		if ( ! attrsonly ) {
			for ( i = 0; a->a_vals[i] != NULL; i++ ) {
				if ( a->a_syntax & SYNTAX_DN && 
671
					! acl_access_allowed( acl, a->a_type, be, conn, e, a->a_vals[i], op,
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
						ACL_READ, edn, matches) )
				{
					continue;
				}

				if (( rc = ber_printf( ber, "O", a->a_vals[i] )) == -1 ) {
					Debug( LDAP_DEBUG_ANY,
					    "ber_printf failed\n", 0, 0, 0 );
					ber_free( ber, 1 );
					send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
						NULL, "encoding value error", NULL, NULL );
					goto error_return;
				}
			}
		}

		if (( rc = ber_printf( ber, /*{[*/ "]}" )) == -1 ) {
			Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
			ber_free( ber, 1 );
			send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
			    NULL, "encode end error", NULL, NULL );
			goto error_return;
		}
	} while (0);
#endif

698
	rc = ber_printf( ber, /*{{{*/ "}}}" );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
699
700
701
702

	if ( rc == -1 ) {
		Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
		ber_free( ber, 1 );
703
704
		send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
			NULL, "encode entry end error", NULL, NULL );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
705
706
707
		return( 1 );
	}

708
	bytes = send_ldap_ber( conn, ber );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
709
	ber_free( ber, 1 );
710

711
712
713
714
715
716
	if ( bytes < 0 ) {
		Debug( LDAP_DEBUG_ANY,
			"send_ldap_response: ber write failed\n",
			0, 0, 0 );
		return -1;
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
717

718
719
720
721
722
	ldap_pvt_thread_mutex_lock( &num_sent_mutex );
	num_bytes_sent += bytes;
	num_entries_sent++;
	num_pdu_sent++;
	ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
723

724
725
	Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld ENTRY dn=\"%s\"\n",
	    (long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 );
726

727
	Debug( LDAP_DEBUG_TRACE, "<= send_search_entry\n", 0, 0, 0 );
728

729
	rc = 0;
730

731
732
733
error_return:;
	return( rc );
}
734

735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
int
send_search_reference(
    Backend	*be,
    Connection	*conn,
    Operation	*op,
    Entry	*e,
	struct berval **refs,
	int scope,
	LDAPControl **ctrls,
    struct berval ***v2refs
)
{
	BerElement	*ber;
	int rc;
	int bytes;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
750

751
	Debug( LDAP_DEBUG_TRACE, "=> send_search_reference (%s)\n", e->e_dn, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
752

753
754
755
756
757
758
759
760
	if ( ! access_allowed( be, conn, op, e,
		"entry", NULL, ACL_READ ) )
	{
		Debug( LDAP_DEBUG_ACL,
			"send_search_reference: access to entry not allowed\n",
		    0, 0, 0 );
		return( 1 );
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
761

762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
	if ( ! access_allowed( be, conn, op, e,
		"ref", NULL, ACL_READ ) )
	{
		Debug( LDAP_DEBUG_ACL,
			"send_search_reference: access to reference not allowed\n",
		    0, 0, 0 );
		return( 1 );
	}

	if( refs == NULL ) {
		Debug( LDAP_DEBUG_ANY,
			"send_search_reference: null ref in (%s)\n", 
			e->e_dn, 0, 0 );
		return( 1 );
	}

	if( op->o_protocol < LDAP_VERSION3 ) {
		/* save the references for the result */
		if( *refs == NULL ) {
			value_add( v2refs, refs );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
782
		}
783
784
		return 0;
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
785

786
	ber = ber_alloc_t( LBER_USE_DER );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
787

788
789
790
791
792
793
	if ( ber == NULL ) {
		Debug( LDAP_DEBUG_ANY,
			"send_search_reference: ber_alloc failed\n", 0, 0, 0 );
		send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
			NULL, "alloc BER error", NULL, NULL );
		return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
794
795
	}

796
797
798
799
800
801
802
803
804
805
806
807
808
	rc = ber_printf( ber, "{it{V}}", op->o_msgid,
		LDAP_RES_SEARCH_REFERENCE, refs );

	if ( rc == -1 ) {
		Debug( LDAP_DEBUG_ANY,
			"send_search_reference: ber_printf failed\n", 0, 0, 0 );
		ber_free( ber, 1 );
		send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
			NULL, "encode dn error", NULL, NULL );
		return -1;
	}

	bytes = send_ldap_ber( conn, ber );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
809
	ber_free( ber, 1 );
810

811
	ldap_pvt_thread_mutex_lock( &num_sent_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
812
	num_bytes_sent += bytes;
813
814
	num_refs_sent++;
	num_pdu_sent++;
815
	ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
816

817
818
	Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld ENTRY dn=\"%s\"\n",
	    (long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
819

820
	Debug( LDAP_DEBUG_TRACE, "<= send_search_reference\n", 0, 0, 0 );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
821

822
	return 0;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
823
824
}

825

Kurt Zeilenga's avatar
Kurt Zeilenga committed
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
int
str2result(
    char	*s,
    int		*code,
    char	**matched,
    char	**info
)
{
	int	rc;
	char	*c;

	*code = LDAP_SUCCESS;
	*matched = NULL;
	*info = NULL;

	if ( strncasecmp( s, "RESULT", 6 ) != 0 ) {
		Debug( LDAP_DEBUG_ANY, "str2result (%s) expecting \"RESULT\"\n",
		    s, 0, 0 );

		return( -1 );
	}

	rc = 0;
	while ( (s = strchr( s, '\n' )) != NULL ) {
		*s++ = '\0';
		if ( *s == '\0' ) {
			break;
		}
		if ( (c = strchr( s, ':' )) != NULL ) {
			c++;
		}

		if ( strncasecmp( s, "code", 4 ) == 0 ) {
			if ( c != NULL ) {
				*code = atoi( c );
			}
		} else if ( strncasecmp( s, "matched", 7 ) == 0 ) {
			if ( c != NULL ) {
				*matched = c;
			}
		} else if ( strncasecmp( s, "info", 4 ) == 0 ) {
			if ( c != NULL ) {
				*info = c;
			}
		} else {
			Debug( LDAP_DEBUG_ANY, "str2result (%s) unknown\n",
			    s, 0, 0 );
			rc = -1;
		}
	}

	return( rc );
}