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