]> git.sur5r.net Git - openldap/blob - servers/slapd/result.c
fix for select_backend suggested G. Gombas (ITS 1090)
[openldap] / servers / slapd / result.c
1 /* result.c - routines to send ldap results, errors, and referrals */
2 /* $OpenLDAP$ */
3 /*
4  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
5  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
6  */
7
8 #include "portable.h"
9
10 #include <stdio.h>
11
12 #include <ac/socket.h>
13 #include <ac/errno.h>
14 #include <ac/signal.h>
15 #include <ac/string.h>
16 #include <ac/ctype.h>
17 #include <ac/time.h>
18 #include <ac/unistd.h>
19
20 #include "slap.h"
21
22 static char *v2ref( struct berval **ref, const char *text )
23 {
24         size_t len = 0, i = 0;
25         char *v2;
26
27         if(ref == NULL) {
28                 if (text) {
29                         return ch_strdup(text);
30                 } else {
31                         return NULL;
32                 }
33         }
34         
35         if ( text != NULL ) {
36                 len = strlen( text );
37                 if (text[len-1] != '\n') {
38                     i = 1;
39                 }
40         }
41
42         v2 = ch_malloc( len+i+sizeof("Referral:") );
43         if( text != NULL ) {
44                 strcpy(v2, text);
45                 if( i ) {
46                         v2[len++] = '\n';
47                 }
48         }
49         strcpy( v2+len, "Referral:" );
50         len += sizeof("Referral:");
51
52         for( i=0; ref[i] != NULL; i++ ) {
53                 v2 = ch_realloc( v2, len + ref[i]->bv_len + 1 );
54                 v2[len-1] = '\n';
55                 AC_MEMCPY(&v2[len], ref[i]->bv_val, ref[i]->bv_len );
56                 len += ref[i]->bv_len;
57                 if (ref[i]->bv_val[ref[i]->bv_len-1] != '/') {
58                         ++len;
59                 }
60         }
61
62         v2[len-1] = '\0';
63         return v2;
64 }
65
66 static ber_tag_t req2res( ber_tag_t tag )
67 {
68         switch( tag ) {
69         case LDAP_REQ_ADD:
70         case LDAP_REQ_BIND:
71         case LDAP_REQ_COMPARE:
72         case LDAP_REQ_EXTENDED:
73         case LDAP_REQ_MODIFY:
74         case LDAP_REQ_MODRDN:
75                 tag++;
76                 break;
77
78         case LDAP_REQ_DELETE:
79                 tag = LDAP_RES_DELETE;
80                 break;
81
82         case LDAP_REQ_ABANDON:
83         case LDAP_REQ_UNBIND:
84                 tag = LBER_SEQUENCE;
85                 break;
86
87         case LDAP_REQ_SEARCH:
88                 tag = LDAP_RES_SEARCH_RESULT;
89                 break;
90
91         default:
92                 tag = LBER_SEQUENCE;
93         }
94
95         return tag;
96 }
97
98 static void trim_refs_urls(
99         struct berval **refs )
100 {
101         unsigned i;
102
103         if( refs == NULL ) return;
104
105         for( i=0; refs[i] != NULL; i++ ) {
106                 if(     refs[i]->bv_len > sizeof("ldap://")-1 &&
107                         strncasecmp( refs[i]->bv_val, "ldap://",
108                                 sizeof("ldap://")-1 ) == 0 )
109                 {
110                         unsigned j;
111                         for( j=sizeof("ldap://")-1; j<refs[i]->bv_len ; j++ ) {
112                                 if( refs[i]->bv_val[j] == '/' ) {
113                                         refs[i]->bv_val[j] = '\0';
114                                         refs[i]->bv_len = j;
115                                         break;
116                                 }
117                         }
118                 }
119         }
120 }
121
122 struct berval **get_entry_referrals(
123         Backend *be,
124         Connection *conn,
125         Operation *op,
126         Entry *e )
127 {
128         Attribute *attr;
129         struct berval **refs;
130         unsigned i, j;
131
132         AttributeDescription *ad_ref = slap_schema.si_ad_ref;
133
134         attr = attr_find( e->e_attrs, ad_ref );
135
136         if( attr == NULL ) return NULL;
137
138         for( i=0; attr->a_vals[i] != NULL; i++ ) {
139                 /* count references */
140         }
141
142         if( i < 1 ) return NULL;
143
144         refs = ch_malloc( (i + 1) * sizeof(struct berval *));
145
146         for( i=0, j=0; attr->a_vals[i] != NULL; i++ ) {
147                 unsigned k;
148                 struct berval *ref = ber_bvdup( attr->a_vals[i] );
149
150                 /* trim the label */
151                 for( k=0; k<ref->bv_len; k++ ) {
152                         if( isspace(ref->bv_val[k]) ) {
153                                 ref->bv_val[k] = '\0';
154                                 ref->bv_len = k;
155                                 break;
156                         }
157                 }
158
159                 if(     ref->bv_len > 0 ) {
160                         refs[j++] = ref;
161
162                 } else {
163                         ber_bvfree( ref );
164                 }
165         }
166
167         refs[j] = NULL;
168
169         if( j == 0 ) {
170                 ber_bvecfree( refs );
171                 refs = NULL;
172         }
173
174         /* we should check that a referral value exists... */
175
176         return refs;
177 }
178
179 static long send_ldap_ber(
180         Connection *conn,
181         BerElement *ber )
182 {
183         ber_len_t bytes;
184
185         ber_get_option( ber, LBER_OPT_BER_BYTES_TO_WRITE, &bytes );
186
187         /* write only one pdu at a time - wait til it's our turn */
188         ldap_pvt_thread_mutex_lock( &conn->c_write_mutex );
189
190         /* lock the connection */ 
191         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
192
193         /* write the pdu */
194         while( 1 ) {
195                 int err;
196                 ber_socket_t    sd;
197
198                 if ( connection_state_closing( conn ) ) {
199                         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
200                         ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
201
202                         return 0;
203                 }
204
205                 if ( ber_flush( conn->c_sb, ber, 0 ) == 0 ) {
206                         break;
207                 }
208
209                 err = errno;
210
211                 /*
212                  * we got an error.  if it's ewouldblock, we need to
213                  * wait on the socket being writable.  otherwise, figure
214                  * it's a hard error and return.
215                  */
216
217 #ifdef NEW_LOGGING
218                 LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
219                            "send_ldap_ber: conn %d  ber_flush failed err=%d (%s)\n",
220                            conn ? conn->c_connid : 0, err, sock_errstr(err) ));
221 #else
222                 Debug( LDAP_DEBUG_CONNS, "ber_flush failed errno=%d reason=\"%s\"\n",
223                     err, sock_errstr(err), 0 );
224 #endif
225
226
227                 if ( err != EWOULDBLOCK && err != EAGAIN ) {
228                         connection_closing( conn );
229
230                         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
231                         ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
232
233                         return( -1 );
234                 }
235
236                 /* wait for socket to be write-ready */
237                 conn->c_writewaiter = 1;
238                 ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_GET_FD, &sd );
239                 slapd_set_write( sd, 1 );
240
241                 ldap_pvt_thread_cond_wait( &conn->c_write_cv, &conn->c_mutex );
242                 conn->c_writewaiter = 0;
243         }
244
245         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
246         ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
247
248         return bytes;
249 }
250
251 static void
252 send_ldap_response(
253     Connection  *conn,
254     Operation   *op,
255         ber_tag_t       tag,
256         ber_int_t       msgid,
257     ber_int_t   err,
258     const char  *matched,
259     const char  *text,
260         struct berval   **ref,
261         const char      *resoid,
262         struct berval   *resdata,
263         struct berval   *sasldata,
264         LDAPControl **ctrls
265 )
266 {
267         BerElement      *ber;
268         int             rc;
269         long    bytes;
270
271         assert( ctrls == NULL ); /* ctrls not implemented */
272
273         ber = ber_alloc_t( LBER_USE_DER );
274
275 #ifdef NEW_LOGGING
276         LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY,
277                    "send_ldap_response: conn %d  msgid=%ld tag=%ld err=%ld\n",
278                    conn ? conn->c_connid : 0, (long)msgid, (long)tag, (long)err ));
279 #else
280         Debug( LDAP_DEBUG_TRACE,
281                 "send_ldap_response: msgid=%ld tag=%ld err=%ld\n",
282                 (long) msgid, (long) tag, (long) err );
283 #endif
284
285
286         if( ref ) {
287 #ifdef NEW_LOGGING
288                 LDAP_LOG(( "operation", LDAP_LEVEL_ARGS,
289                            "send_ldap_response: conn %d  ref=\"%s\"\n",
290                            conn ? conn->c_connid : 0,
291                            ref[0] && ref[0]->bv_val ? ref[0]->bv_val : "NULL" ));
292 #else
293                 Debug( LDAP_DEBUG_ARGS, "send_ldap_response: ref=\"%s\"\n",
294                         ref[0] && ref[0]->bv_val ? ref[0]->bv_val : "NULL",
295                         NULL, NULL );
296 #endif
297
298         }
299
300         if ( ber == NULL ) {
301 #ifdef NEW_LOGGING
302                 LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
303                            "send_ldap_response: conn %d  ber_alloc failed\n",
304                            conn ? conn->c_connid : 0 ));
305 #else
306                 Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
307 #endif
308
309                 return;
310         }
311
312         rc = ber_printf( ber, "{it{ess",
313                 msgid, tag, err,
314                 matched == NULL ? "" : matched,
315                 text == NULL ? "" : text );
316
317         if( rc != -1 ) {
318                 if ( ref != NULL ) {
319                         assert( err == LDAP_REFERRAL );
320                         rc = ber_printf( ber, "t{V}",
321                                 LDAP_TAG_REFERRAL, ref );
322                 } else {
323                         assert( err != LDAP_REFERRAL );
324                 }
325         }
326
327         if( rc != -1 && sasldata != NULL ) {
328                 rc = ber_printf( ber, "tO",
329                         LDAP_TAG_SASL_RES_CREDS, sasldata );
330         }
331
332         if( rc != -1 && resoid != NULL ) {
333                 rc = ber_printf( ber, "ts",
334                         LDAP_TAG_EXOP_RES_OID, resoid );
335         }
336
337         if( rc != -1 && resdata != NULL ) {
338                 rc = ber_printf( ber, "tO",
339                         LDAP_TAG_EXOP_RES_VALUE, resdata );
340         }
341
342         if( rc != -1 ) {
343                 rc = ber_printf( ber, "N}N}" );
344         }
345
346         if ( rc == -1 ) {
347 #ifdef NEW_LOGGING
348                 LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
349                            "send_ldap_response: conn %d  ber_printf failed\n",
350                            conn ? conn->c_connid : 0 ));
351 #else
352                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
353 #endif
354
355                 ber_free( ber, 1 );
356                 return;
357         }
358
359         /* send BER */
360         bytes = send_ldap_ber( conn, ber );
361         ber_free( ber, 1 );
362
363         if ( bytes < 0 ) {
364 #ifdef NEW_LOGGING
365                 LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
366                            "send_ldap_response: conn %d ber write failed\n",
367                            conn ? conn->c_connid : 0 ));
368 #else
369                 Debug( LDAP_DEBUG_ANY,
370                         "send_ldap_response: ber write failed\n",
371                         0, 0, 0 );
372 #endif
373
374                 return;
375         }
376
377         ldap_pvt_thread_mutex_lock( &num_sent_mutex );
378         num_bytes_sent += bytes;
379         num_pdu_sent++;
380         ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
381         return;
382 }
383
384
385 void
386 send_ldap_disconnect(
387     Connection  *conn,
388     Operation   *op,
389     ber_int_t   err,
390     const char  *text
391 )
392 {
393         ber_tag_t tag;
394         ber_int_t msgid;
395         char *reqoid;
396
397 #define LDAP_UNSOLICITED_ERROR(e) \
398         (  (e) == LDAP_PROTOCOL_ERROR \
399         || (e) == LDAP_STRONG_AUTH_REQUIRED \
400         || (e) == LDAP_UNAVAILABLE )
401
402         assert( LDAP_UNSOLICITED_ERROR( err ) );
403
404 #ifdef NEW_LOGGING
405         LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY,
406                    "send_ldap_disconnect: conn %d  %d:%s\n",
407                    conn ? conn->c_connid : 0, err, text ? text : "" ));
408 #else
409         Debug( LDAP_DEBUG_TRACE,
410                 "send_ldap_disconnect %d:%s\n",
411                 err, text ? text : "", NULL );
412 #endif
413
414
415         if ( op->o_protocol < LDAP_VERSION3 ) {
416                 reqoid = NULL;
417                 tag = req2res( op->o_tag );
418                 msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
419
420         } else {
421                 reqoid = LDAP_NOTICE_DISCONNECT;
422                 tag = LDAP_RES_EXTENDED;
423                 msgid = 0;
424         }
425
426         send_ldap_response( conn, op, tag, msgid,
427                 err, NULL, text, NULL,
428                 reqoid, NULL, NULL, NULL );
429
430         Statslog( LDAP_DEBUG_STATS,
431             "conn=%ld op=%ld DISCONNECT err=%ld tag=%lu text=%s\n",
432                 (long) op->o_connid, (long) op->o_opid,
433                 (long) tag, (long) err, text ? text : "" );
434 }
435
436 void
437 send_ldap_result(
438     Connection  *conn,
439     Operation   *op,
440     ber_int_t   err,
441     const char  *matched,
442     const char  *text,
443         struct berval **ref,
444         LDAPControl **ctrls
445 )
446 {
447         ber_tag_t tag;
448         ber_int_t msgid;
449         char *tmp = NULL;
450
451         assert( !LDAP_API_ERROR( err ) );
452
453 #ifdef NEW_LOGGING
454         LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY,
455                    "send_ldap_result : conn %ld   op=%ld p=%d\n",
456                    (long)op->o_connid, (long)op->o_opid, op->o_protocol ));
457 #else
458         Debug( LDAP_DEBUG_TRACE,
459                 "send_ldap_result: conn=%ld op=%ld p=%d\n",
460                 (long) op->o_connid, (long) op->o_opid, op->o_protocol );
461 #endif
462
463 #ifdef NEW_LOGGING
464         LDAP_LOG(( "operation", LDAP_LEVEL_ARGS,
465                    "send_ldap_result: conn=%ld err=%d matched=\"%s\" text=\"%s\"\n",
466                    (long)op->o_connid, err, matched ? matched : "", text ? text : "" ));
467 #else
468         Debug( LDAP_DEBUG_ARGS,
469                 "send_ldap_result: err=%d matched=\"%s\" text=\"%s\"\n",
470                 err, matched ?  matched : "", text ? text : "" );
471 #endif
472
473
474         if( ref ) {
475 #ifdef NEW_LOGGING
476                 LDAP_LOG(( "operation", LDAP_LEVEL_ARGS,
477                            "send_ldap_result: referral=\"%s\"\n",
478                            ref[0] && ref[0]->bv_val ? ref[0]->bv_val : "NULL" ));
479 #else
480                 Debug( LDAP_DEBUG_ARGS,
481                         "send_ldap_result: referral=\"%s\"\n",
482                         ref[0] && ref[0]->bv_val ? ref[0]->bv_val : "NULL",
483                         NULL, NULL );
484 #endif
485
486         }
487
488         assert( err != LDAP_PARTIAL_RESULTS );
489
490         if( op->o_tag != LDAP_REQ_SEARCH ) {
491                 trim_refs_urls( ref );
492         }
493
494         if ( err == LDAP_REFERRAL ) {
495                 if( ref == NULL ) {
496                         err = LDAP_NO_SUCH_OBJECT;
497                 } else if ( op->o_protocol < LDAP_VERSION3 ) {
498                         err = LDAP_PARTIAL_RESULTS;
499                 }
500         }
501
502         if ( op->o_protocol < LDAP_VERSION3 ) {
503                 tmp = v2ref( ref, text );
504                 text = tmp;
505                 ref = NULL;
506         }
507
508         tag = req2res( op->o_tag );
509         msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
510
511         send_ldap_response( conn, op, tag, msgid,
512                 err, matched, text, ref,
513                 NULL, NULL, NULL, ctrls );
514
515         Statslog( LDAP_DEBUG_STATS,
516             "conn=%ld op=%ld RESULT tag=%lu err=%ld text=%s\n",
517                 (long) op->o_connid, (long) op->o_opid,
518                 (long) tag, (long) err, text ? text : "" );
519
520         if( tmp != NULL ) {
521                 ch_free(tmp);
522         }
523 }
524
525 void
526 send_ldap_sasl(
527     Connection  *conn,
528     Operation   *op,
529     ber_int_t   err,
530     const char  *matched,
531     const char  *text,
532         struct berval **ref,
533         LDAPControl **ctrls,
534         struct berval *cred
535 )
536 {
537         ber_tag_t tag;
538         ber_int_t msgid;
539
540 #ifdef NEW_LOGGING
541         LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY,
542                    "send_ldap_sasl: conn %d err=%ld len=%ld\n",
543                    op->o_connid, (long)err, cred ? cred->bv_len : -1 ));
544 #else
545         Debug( LDAP_DEBUG_TRACE, "send_ldap_sasl: err=%ld len=%ld\n",
546                 (long) err, cred ? cred->bv_len : -1, NULL );
547 #endif
548
549
550         tag = req2res( op->o_tag );
551         msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
552
553         send_ldap_response( conn, op, tag, msgid,
554                 err, matched, text, ref,
555                 NULL, NULL, cred, ctrls  );
556 }
557
558 void
559 send_ldap_extended(
560     Connection  *conn,
561     Operation   *op,
562     ber_int_t   err,
563     const char  *matched,
564     const char  *text,
565     struct berval **refs,
566     const char          *rspoid,
567         struct berval *rspdata,
568         LDAPControl **ctrls
569 )
570 {
571         ber_tag_t tag;
572         ber_int_t msgid;
573
574 #ifdef NEW_LOGGING
575         LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY,
576                    "send_ldap_extended: conn %d  err=%ld oid=%s len=%ld\n",
577                    op->o_connid, (long)err, rspoid ? rspoid : "",
578                    rspdata != NULL ? (long)rspdata->bv_len : (long)0 ));
579 #else
580         Debug( LDAP_DEBUG_TRACE,
581                 "send_ldap_extended err=%ld oid=%s len=%ld\n",
582                 (long) err,
583                 rspoid ? rspoid : "",
584                 rspdata != NULL ? (long) rspdata->bv_len : (long) 0 );
585 #endif
586
587
588         tag = req2res( op->o_tag );
589         msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
590
591         send_ldap_response( conn, op, tag, msgid,
592                 err, matched, text, refs,
593                 rspoid, rspdata, NULL, ctrls );
594 }
595
596
597 void
598 send_search_result(
599     Connection  *conn,
600     Operation   *op,
601     ber_int_t   err,
602     const char  *matched,
603         const char      *text,
604     struct berval **refs,
605         LDAPControl **ctrls,
606     int         nentries
607 )
608 {
609         ber_tag_t tag;
610         ber_int_t msgid;
611         char *tmp = NULL;
612         assert( !LDAP_API_ERROR( err ) );
613
614 #ifdef NEW_LOGGING
615         LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY,
616                    "send_search_result: conn %d err=%d matched=\"%s\"\n",
617                    op->o_connid, err, matched ? matched : "",
618                    text ? text : "" ));
619 #else
620         Debug( LDAP_DEBUG_TRACE,
621                 "send_search_result: err=%d matched=\"%s\" text=\"%s\"\n",
622                 err, matched ?  matched : "", text ? text : "" );
623 #endif
624
625
626         assert( err != LDAP_PARTIAL_RESULTS );
627
628         trim_refs_urls( refs );
629
630         if( op->o_protocol < LDAP_VERSION3 ) {
631                 /* send references in search results */
632                 if( err == LDAP_REFERRAL ) {
633                         err = LDAP_PARTIAL_RESULTS;
634                 }
635
636                 tmp = v2ref( refs, text );
637                 text = tmp;
638                 refs = NULL;
639
640         } else {
641                 /* don't send references in search results */
642                 assert( refs == NULL );
643                 refs = NULL;
644
645                 if( err == LDAP_REFERRAL ) {
646                         err = LDAP_SUCCESS;
647                 }
648         }
649
650         tag = req2res( op->o_tag );
651         msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
652
653         send_ldap_response( conn, op, tag, msgid,
654                 err, matched, text, refs,
655                 NULL, NULL, NULL, ctrls );
656
657         Statslog( LDAP_DEBUG_STATS,
658             "conn=%ld op=%ld SEARCH RESULT tag=%lu err=%ld text=%s\n",
659                 (long) op->o_connid, (long) op->o_opid,
660                 (long) tag, (long) err, text ? text : "" );
661
662         if (tmp != NULL) {
663             ch_free(tmp);
664         }
665 }
666
667
668 int
669 send_search_entry(
670     Backend     *be,
671     Connection  *conn,
672     Operation   *op,
673     Entry       *e,
674     char        **attrs,
675     int         attrsonly,
676         LDAPControl **ctrls
677 )
678 {
679         BerElement      *ber;
680         Attribute       *a, *aa;
681         int             i, rc=-1, bytes;
682         char            *edn;
683         int             userattrs;
684         int             opattrs;
685
686         AttributeDescription *ad_entry = slap_schema.si_ad_entry;
687
688 #ifdef NEW_LOGGING
689         LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY,
690                    "send_search_entry: conn %d  dn=\"%s\"%s\n",
691                    op->o_connid, e->e_dn,
692                    attrsonly ? " (attrsOnly)" : "" ));
693 #else
694         Debug( LDAP_DEBUG_TRACE,
695                 "=> send_search_entry: dn=\"%s\"%s\n",
696                 e->e_dn, attrsonly ? " (attrsOnly)" : "", 0 );
697 #endif
698
699
700         if ( ! access_allowed( be, conn, op, e,
701                 ad_entry, NULL, ACL_READ ) )
702         {
703 #ifdef NEW_LOGGING
704                 LDAP_LOG(( "acl", LDAP_LEVEL_INFO,
705                            "send_search_entry: conn %d access to entry (%s) not allowed\n",
706                            op->o_connid, e->e_dn ));
707 #else
708                 Debug( LDAP_DEBUG_ACL,
709                         "send_search_entry: access to entry not allowed\n",
710                     0, 0, 0 );
711 #endif
712
713                 return( 1 );
714         }
715
716         edn = e->e_ndn;
717
718         ber = ber_alloc_t( LBER_USE_DER );
719
720         if ( ber == NULL ) {
721 #ifdef NEW_LOGGING
722                 LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
723                            "send_search_entry: conn %d  ber_alloc failed\n",
724                            op->o_connid ));
725 #else
726                 Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
727 #endif
728
729                 send_ldap_result( conn, op, LDAP_OTHER,
730                         NULL, "BER allocation error", NULL, NULL );
731                 goto error_return;
732         }
733
734         rc = ber_printf( ber, "{it{s{" /*}}}*/, op->o_msgid,
735                 LDAP_RES_SEARCH_ENTRY, e->e_dn );
736
737         if ( rc == -1 ) {
738 #ifdef NEW_LOGGING
739                 LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
740                            "send_search_entry: conn %d  ber_printf failed\n",
741                            op->o_connid ));
742 #else
743                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
744 #endif
745
746                 ber_free( ber, 1 );
747                 send_ldap_result( conn, op, LDAP_OTHER,
748                     NULL, "encoding DN error", NULL, NULL );
749                 goto error_return;
750         }
751
752         /* check for special all user attributes ("*") type */
753         userattrs = ( attrs == NULL ) ? 1
754                 : charray_inlist( attrs, LDAP_ALL_USER_ATTRIBUTES );
755
756         /* check for special all operational attributes ("+") type */
757         opattrs = ( attrs == NULL ) ? 0
758                 : charray_inlist( attrs, LDAP_ALL_OPERATIONAL_ATTRIBUTES );
759
760         for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
761                 AttributeDescription *desc = a->a_desc;
762                 char *type = desc->ad_cname->bv_val;
763
764                 if ( attrs == NULL ) {
765                         /* all addrs request, skip operational attributes */
766                         if( is_at_operational( desc->ad_type ) ) {
767                                 continue;
768                         }
769
770                 } else {
771                         /* specific addrs requested */
772                         if ( is_at_operational( desc->ad_type ) ) {
773                                 if( !opattrs && !ad_inlist( desc, attrs ) ) {
774                                         continue;
775                                 }
776
777                         } else {
778                                 if (!userattrs && !ad_inlist( desc, attrs ) ) {
779                                         continue;
780                                 }
781                         }
782                 }
783
784                 if ( ! access_allowed( be, conn, op, e, desc, NULL, ACL_READ ) ) {
785 #ifdef NEW_LOGGING
786                         LDAP_LOG(( "acl", LDAP_LEVEL_INFO,
787                                    "send_search_entry: conn %d  access to attribute %s not allowed\n",
788                                    op->o_connid, desc->ad_cname->bv_val ));
789 #else
790                         Debug( LDAP_DEBUG_ACL, "acl: access to attribute %s not allowed\n",
791                             desc->ad_cname->bv_val, 0, 0 );
792 #endif
793
794                         continue;
795                 }
796
797                 if (( rc = ber_printf( ber, "{s[" /*]}*/ , type )) == -1 ) {
798 #ifdef NEW_LOGGING
799                         LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
800                                    "send_search_entry: conn %d  ber_printf failed\n",
801                                    op->o_connid ));
802 #else
803                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
804 #endif
805
806                         ber_free( ber, 1 );
807                         send_ldap_result( conn, op, LDAP_OTHER,
808                             NULL, "encoding description error", NULL, NULL );
809                         goto error_return;
810                 }
811
812                 if ( ! attrsonly ) {
813                         for ( i = 0; a->a_vals[i] != NULL; i++ ) {
814                                 if ( ! access_allowed( be, conn, op, e,
815                                         desc, a->a_vals[i], ACL_READ ) )
816                                 {
817 #ifdef NEW_LOGGING
818                                         LDAP_LOG(( "acl", LDAP_LEVEL_INFO,
819                                                    "send_search_entry: conn %d  access to attribute %s, value %d not allowed\n",
820                                                    op->o_connid, desc->ad_cname->bv_val, i ));
821 #else
822                                         Debug( LDAP_DEBUG_ACL,
823                                                 "acl: access to attribute %s, value %d not allowed\n",
824                                         desc->ad_cname->bv_val, i, 0 );
825 #endif
826
827                                         continue;
828                                 }
829
830                                 if (( rc = ber_printf( ber, "O", a->a_vals[i] )) == -1 ) {
831 #ifdef NEW_LOGGING
832                                         LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
833                                                    "send_search_entry: conn %d  ber_printf failed.\n",
834                                                    op->o_connid ));
835 #else
836                                         Debug( LDAP_DEBUG_ANY,
837                                             "ber_printf failed\n", 0, 0, 0 );
838 #endif
839
840                                         ber_free( ber, 1 );
841                                         send_ldap_result( conn, op, LDAP_OTHER,
842                                                 NULL, "encoding values error", NULL, NULL );
843                                         goto error_return;
844                                 }
845                         }
846                 }
847
848                 if (( rc = ber_printf( ber, /*{[*/ "]N}" )) == -1 ) {
849 #ifdef NEW_LOGGING
850                         LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
851                                    "send_search_entry: conn %d  ber_printf failed\n",
852                                    op->o_connid ));
853 #else
854                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
855 #endif
856
857                         ber_free( ber, 1 );
858                         send_ldap_result( conn, op, LDAP_OTHER,
859                             NULL, "encode end error", NULL, NULL );
860                         goto error_return;
861                 }
862         }
863
864         /* eventually will loop through generated operational attributes */
865         /* only have subschemaSubentry implemented */
866         aa = backend_operational( be, conn, op, e );
867         
868         for (a = aa ; a != NULL; a = a->a_next ) {
869                 AttributeDescription *desc = a->a_desc;
870
871                 if ( attrs == NULL ) {
872                         /* all addrs request, skip operational attributes */
873                         if( is_at_operational( desc->ad_type ) ) {
874                                 continue;
875                         }
876
877                 } else {
878                         /* specific addrs requested */
879                         if( is_at_operational( desc->ad_type ) ) {
880                                 if( !opattrs && !ad_inlist( desc, attrs ) ) {
881                                         continue;
882                                 }
883                         } else {
884                                 if (!userattrs && !ad_inlist( desc, attrs ) )
885                                 {
886                                         continue;
887                                 }
888                         }
889                 }
890
891                 if ( ! access_allowed( be, conn, op, e, desc, NULL, ACL_READ ) ) {
892 #ifdef NEW_LOGGING
893                         LDAP_LOG(( "acl", LDAP_LEVEL_INFO,
894                                    "send_search_entry: conn %s  access to attribute %s not allowed\n",
895                                    op->o_connid, desc->ad_cname->bv_val ));
896 #else
897                         Debug( LDAP_DEBUG_ACL, "acl: access to attribute %s not allowed\n",
898                             desc->ad_cname->bv_val, 0, 0 );
899 #endif
900
901                         continue;
902                 }
903
904                 rc = ber_printf( ber, "{s[" /*]}*/ , desc->ad_cname->bv_val );
905                 if ( rc == -1 ) {
906 #ifdef NEW_LOGGING
907                         LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
908                                    "send_search_entry: conn %d  ber_printf failed\n",
909                                    op->o_connid ));
910 #else
911                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
912 #endif
913
914                         ber_free( ber, 1 );
915                         send_ldap_result( conn, op, LDAP_OTHER,
916                             NULL, "encoding description error", NULL, NULL );
917                         goto error_return;
918                 }
919
920                 if ( ! attrsonly ) {
921                         for ( i = 0; a->a_vals[i] != NULL; i++ ) {
922                                 if ( ! access_allowed( be, conn, op, e,
923                                         desc, a->a_vals[i], ACL_READ ) )
924                                 {
925 #ifdef NEW_LOGGING
926                                         LDAP_LOG(( "acl", LDAP_LEVEL_INFO,
927                                                    "send_search_entry: conn %d access to %s, value %d not allowed\n",
928                                                    op->o_connid, desc->ad_cname->bv_val, i ));
929 #else
930                                         Debug( LDAP_DEBUG_ACL,
931                                                 "acl: access to attribute %s, value %d not allowed\n",
932                                         desc->ad_cname->bv_val, i, 0 );
933 #endif
934
935                                         continue;
936                                 }
937
938
939                                 if (( rc = ber_printf( ber, "O", a->a_vals[i] )) == -1 ) {
940 #ifdef NEW_LOGGING
941                                         LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
942                                                    "send_search_entry: conn %d  ber_printf failed\n",
943                                                    op->o_connid ));
944 #else
945                                         Debug( LDAP_DEBUG_ANY,
946                                             "ber_printf failed\n", 0, 0, 0 );
947 #endif
948
949                                         ber_free( ber, 1 );
950                                         send_ldap_result( conn, op, LDAP_OTHER,
951                                                 NULL, "encoding values error", NULL, NULL );
952                                         goto error_return;
953                                 }
954                         }
955                 }
956
957                 if (( rc = ber_printf( ber, /*{[*/ "]N}" )) == -1 ) {
958 #ifdef NEW_LOGGING
959                         LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
960                                    "send_search_entry: conn %d  ber_printf failed\n",
961                                    op->o_connid ));
962 #else
963                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
964 #endif
965
966                         ber_free( ber, 1 );
967                         send_ldap_result( conn, op, LDAP_OTHER,
968                             NULL, "encode end error", NULL, NULL );
969                         goto error_return;
970                 }
971         }
972
973         attrs_free( aa );
974
975         rc = ber_printf( ber, /*{{{*/ "}N}N}" );
976
977         if ( rc == -1 ) {
978 #ifdef NEW_LOGGING
979                 LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
980                            "send_search_entry: conn %d ber_printf failed\n",
981                            op->o_connid ));
982 #else
983                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
984 #endif
985
986                 ber_free( ber, 1 );
987                 send_ldap_result( conn, op, LDAP_OTHER,
988                         NULL, "encode entry end error", NULL, NULL );
989                 return( 1 );
990         }
991
992         bytes = send_ldap_ber( conn, ber );
993         ber_free( ber, 1 );
994
995         if ( bytes < 0 ) {
996 #ifdef NEW_LOGGING
997                 LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
998                            "send_ldap_response: conn %d  ber write failed.\n",
999                            op->o_connid ));
1000 #else
1001                 Debug( LDAP_DEBUG_ANY,
1002                         "send_ldap_response: ber write failed\n",
1003                         0, 0, 0 );
1004 #endif
1005
1006                 return -1;
1007         }
1008
1009         ldap_pvt_thread_mutex_lock( &num_sent_mutex );
1010         num_bytes_sent += bytes;
1011         num_entries_sent++;
1012         num_pdu_sent++;
1013         ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
1014
1015         Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld ENTRY dn=\"%s\"\n",
1016             (long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 );
1017
1018 #ifdef NEW_LOGGING
1019         LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY,
1020                    "send_search_entry: conn %d exit.\n",
1021                    op->o_connid ));
1022 #else
1023         Debug( LDAP_DEBUG_TRACE, "<= send_search_entry\n", 0, 0, 0 );
1024 #endif
1025
1026
1027         rc = 0;
1028
1029 error_return:;
1030         return( rc );
1031 }
1032
1033 int
1034 send_search_reference(
1035     Backend     *be,
1036     Connection  *conn,
1037     Operation   *op,
1038     Entry       *e,
1039         struct berval **refs,
1040         int scope,
1041         LDAPControl **ctrls,
1042     struct berval ***v2refs
1043 )
1044 {
1045         BerElement      *ber;
1046         int rc;
1047         int bytes;
1048
1049         AttributeDescription *ad_ref = slap_schema.si_ad_ref;
1050         AttributeDescription *ad_entry = slap_schema.si_ad_entry;
1051
1052 #ifdef NEW_LOGGING
1053         LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY,
1054                    "send_search_reference: conn %d  dn=\"%s\"\n",
1055                    op->o_connid, e->e_dn ));
1056 #else
1057         Debug( LDAP_DEBUG_TRACE,
1058                 "=> send_search_reference: dn=\"%s\"\n",
1059                 e->e_dn, 0, 0 );
1060 #endif
1061
1062
1063         if ( ! access_allowed( be, conn, op, e,
1064                 ad_entry, NULL, ACL_READ ) )
1065         {
1066 #ifdef NEW_LOGGING
1067                 LDAP_LOG(( "acl", LDAP_LEVEL_INFO,
1068                            "send_search_reference: conn %d      access to entry %s not allowed\n",
1069                            op->o_connid, e->e_dn ));
1070 #else
1071                 Debug( LDAP_DEBUG_ACL,
1072                         "send_search_reference: access to entry not allowed\n",
1073                     0, 0, 0 );
1074 #endif
1075
1076                 return( 1 );
1077         }
1078
1079         if ( ! access_allowed( be, conn, op, e,
1080                 ad_ref, NULL, ACL_READ ) )
1081         {
1082 #ifdef NEW_LOGGING
1083                 LDAP_LOG(( "acl", LDAP_LEVEL_INFO,
1084                            "send_search_reference: conn %d access to reference not allowed.\n",
1085                            op->o_connid ));
1086 #else
1087                 Debug( LDAP_DEBUG_ACL,
1088                         "send_search_reference: access to reference not allowed\n",
1089                     0, 0, 0 );
1090 #endif
1091
1092                 return( 1 );
1093         }
1094
1095         if( refs == NULL ) {
1096 #ifdef NEW_LOGGING
1097                 LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
1098                            "send_search_reference: null ref in (%s).\n",
1099                            op->o_connid, e->e_dn ));
1100 #else
1101                 Debug( LDAP_DEBUG_ANY,
1102                         "send_search_reference: null ref in (%s)\n", 
1103                         e->e_dn, 0, 0 );
1104 #endif
1105
1106                 return( 1 );
1107         }
1108
1109         if( op->o_protocol < LDAP_VERSION3 ) {
1110                 /* save the references for the result */
1111                 if( *refs != NULL ) {
1112                         value_add( v2refs, refs );
1113                 }
1114                 return 0;
1115         }
1116
1117         ber = ber_alloc_t( LBER_USE_DER );
1118
1119         if ( ber == NULL ) {
1120 #ifdef NEW_LOGGING
1121                 LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
1122                            "send_search_reference: conn %d ber_alloc failed\n",
1123                            op->o_connid ));
1124 #else
1125                 Debug( LDAP_DEBUG_ANY,
1126                         "send_search_reference: ber_alloc failed\n", 0, 0, 0 );
1127 #endif
1128
1129                 send_ldap_result( conn, op, LDAP_OTHER,
1130                         NULL, "alloc BER error", NULL, NULL );
1131                 return -1;
1132         }
1133
1134         rc = ber_printf( ber, "{it{V}N}", op->o_msgid,
1135                 LDAP_RES_SEARCH_REFERENCE, refs );
1136
1137         if ( rc == -1 ) {
1138 #ifdef NEW_LOGGING
1139                 LDAP_LOG(( "operation", LDAP_LEVEL_ERR,
1140                            "send_search_reference: conn %d      ber_printf failed.\n",
1141                            op->o_connid ));
1142 #else
1143                 Debug( LDAP_DEBUG_ANY,
1144                         "send_search_reference: ber_printf failed\n", 0, 0, 0 );
1145 #endif
1146
1147                 ber_free( ber, 1 );
1148                 send_ldap_result( conn, op, LDAP_OTHER,
1149                         NULL, "encode DN error", NULL, NULL );
1150                 return -1;
1151         }
1152
1153         bytes = send_ldap_ber( conn, ber );
1154         ber_free( ber, 1 );
1155
1156         ldap_pvt_thread_mutex_lock( &num_sent_mutex );
1157         num_bytes_sent += bytes;
1158         num_refs_sent++;
1159         num_pdu_sent++;
1160         ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
1161
1162         Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld ENTRY dn=\"%s\"\n",
1163             (long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 );
1164
1165 #ifdef NEW_LOGGING
1166         LDAP_LOG(( "operation", LDAP_LEVEL_ENTRY,
1167                    "send_search_reference: conn %d exit.\n", op->o_connid ));
1168 #else
1169         Debug( LDAP_DEBUG_TRACE, "<= send_search_reference\n", 0, 0, 0 );
1170 #endif
1171
1172
1173         return 0;
1174 }
1175
1176
1177 int
1178 str2result(
1179     char        *s,
1180     int         *code,
1181     char        **matched,
1182     char        **info
1183 )
1184 {
1185         int     rc;
1186         char    *c;
1187
1188         *code = LDAP_SUCCESS;
1189         *matched = NULL;
1190         *info = NULL;
1191
1192         if ( strncasecmp( s, "RESULT", 6 ) != 0 ) {
1193 #ifdef NEW_LOGGING
1194                 LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
1195                            "str2result: (%s), expecting \"RESULT\"\n", s ));
1196 #else
1197                 Debug( LDAP_DEBUG_ANY, "str2result (%s) expecting \"RESULT\"\n",
1198                     s, 0, 0 );
1199 #endif
1200
1201
1202                 return( -1 );
1203         }
1204
1205         rc = 0;
1206         while ( (s = strchr( s, '\n' )) != NULL ) {
1207                 *s++ = '\0';
1208                 if ( *s == '\0' ) {
1209                         break;
1210                 }
1211                 if ( (c = strchr( s, ':' )) != NULL ) {
1212                         c++;
1213                 }
1214
1215                 if ( strncasecmp( s, "code", 4 ) == 0 ) {
1216                         if ( c != NULL ) {
1217                                 *code = atoi( c );
1218                         }
1219                 } else if ( strncasecmp( s, "matched", 7 ) == 0 ) {
1220                         if ( c != NULL ) {
1221                                 *matched = c;
1222                         }
1223                 } else if ( strncasecmp( s, "info", 4 ) == 0 ) {
1224                         if ( c != NULL ) {
1225                                 *info = c;
1226                         }
1227                 } else {
1228 #ifdef NEW_LOGGING
1229                         LDAP_LOG(( "operation", LDAP_LEVEL_INFO,
1230                                    "str2result: (%s) unknown.\n", s ));
1231 #else
1232                         Debug( LDAP_DEBUG_ANY, "str2result (%s) unknown\n",
1233                             s, 0, 0 );
1234 #endif
1235
1236                         rc = -1;
1237                 }
1238         }
1239
1240         return( rc );
1241 }