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