]> git.sur5r.net Git - openldap/blob - servers/slapd/result.c
Use #ifdef, not #if
[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 #ifdef SLAPD_SCHEMA_NOT_COMPAT
129         AttributeDescription *ad_ref = slap_schema.si_ad_ref;
130 #else
131         static const char *ad_ref = "ref";
132 #endif
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                 Debug( LDAP_DEBUG_CONNS, "ber_flush failed errno=%d reason=\"%s\"\n",
218                     err, sock_errstr(err), 0 );
219
220                 if ( err != EWOULDBLOCK && err != EAGAIN ) {
221                         connection_closing( conn );
222
223                         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
224                         ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
225
226                         return( -1 );
227                 }
228
229                 /* wait for socket to be write-ready */
230                 conn->c_writewaiter = 1;
231                 ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_GET_FD, &sd );
232                 slapd_set_write( sd, 1 );
233
234                 ldap_pvt_thread_cond_wait( &conn->c_write_cv, &conn->c_mutex );
235                 conn->c_writewaiter = 0;
236         }
237
238         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
239         ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
240
241         return bytes;
242 }
243
244 static void
245 send_ldap_response(
246     Connection  *conn,
247     Operation   *op,
248         ber_tag_t       tag,
249         ber_int_t       msgid,
250     ber_int_t   err,
251     const char  *matched,
252     const char  *text,
253         struct berval   **ref,
254         const char      *resoid,
255         struct berval   *resdata,
256         struct berval   *sasldata,
257         LDAPControl **ctrls
258 )
259 {
260         BerElement      *ber;
261         int             rc;
262         long    bytes;
263
264         assert( ctrls == NULL ); /* ctrls not implemented */
265
266         ber = ber_alloc_t( LBER_USE_DER );
267
268         Debug( LDAP_DEBUG_TRACE, "send_ldap_response: msgid=%ld tag=%ld err=%ld\n",
269                 (long) msgid, (long) tag, (long) err );
270         if( ref ) {
271                 Debug( LDAP_DEBUG_ARGS, "send_ldap_response: ref=%s\n",
272                         ref[0] && ref[0]->bv_val ? ref[0]->bv_val : "NULL",
273                         NULL, NULL );
274         }
275
276         if ( ber == NULL ) {
277                 Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
278                 return;
279         }
280
281 #ifdef LDAP_CONNECTIONLESS
282         if ( op->o_cldap ) {
283                 rc = ber_printf( ber, "{is{t{ess}}}", msgid, "", tag,
284                     err, matched ? matched : "", text ? text : "" );
285         } else
286 #endif
287         {
288                 rc = ber_printf( ber, "{it{ess",
289                         msgid, tag, err,
290                         matched == NULL ? "" : matched,
291                         text == NULL ? "" : text );
292
293                 if( rc != -1 ) {
294                         if ( ref != NULL ) {
295                                 assert( err == LDAP_REFERRAL );
296                                 rc = ber_printf( ber, "t{V}",
297                                         LDAP_TAG_REFERRAL, ref );
298                         } else {
299                                 assert( err != LDAP_REFERRAL );
300                         }
301                 }
302
303                 if( rc != -1 && sasldata != NULL ) {
304                         rc = ber_printf( ber, "tO",
305                                 LDAP_TAG_SASL_RES_CREDS, sasldata );
306                 }
307
308                 if( rc != -1 && resoid != NULL ) {
309                         rc = ber_printf( ber, "ts",
310                                 LDAP_TAG_EXOP_RES_OID, resoid );
311                 }
312
313                 if( rc != -1 && resdata != NULL ) {
314                         rc = ber_printf( ber, "tO",
315                                 LDAP_TAG_EXOP_RES_VALUE, resdata );
316                 }
317
318                 if( rc != -1 ) {
319                         rc = ber_printf( ber, "}}" );
320                 }
321         }
322
323         if ( rc == -1 ) {
324                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
325                 ber_free( ber, 1 );
326                 return;
327         }
328
329         /* send BER */
330         bytes = send_ldap_ber( conn, ber );
331         ber_free( ber, 1 );
332
333         if ( bytes < 0 ) {
334                 Debug( LDAP_DEBUG_ANY,
335                         "send_ldap_response: ber write failed\n",
336                         0, 0, 0 );
337                 return;
338         }
339
340         ldap_pvt_thread_mutex_lock( &num_sent_mutex );
341         num_bytes_sent += bytes;
342         num_pdu_sent++;
343         ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
344         return;
345 }
346
347
348 void
349 send_ldap_disconnect(
350     Connection  *conn,
351     Operation   *op,
352     ber_int_t   err,
353     const char  *text
354 )
355 {
356         ber_tag_t tag;
357         ber_int_t msgid;
358         char *reqoid;
359
360 #define LDAP_UNSOLICITED_ERROR(e) \
361         (  (e) == LDAP_PROTOCOL_ERROR \
362         || (e) == LDAP_STRONG_AUTH_REQUIRED \
363         || (e) == LDAP_UNAVAILABLE )
364
365         assert( LDAP_UNSOLICITED_ERROR( err ) );
366
367         Debug( LDAP_DEBUG_TRACE,
368                 "send_ldap_disconnect %d:%s\n",
369                 err, text ? text : "", NULL );
370
371         if ( op->o_protocol < LDAP_VERSION3 ) {
372                 reqoid = NULL;
373                 tag = req2res( op->o_tag );
374                 msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
375
376         } else {
377                 reqoid = LDAP_NOTICE_DISCONNECT;
378                 tag = LDAP_RES_EXTENDED;
379                 msgid = 0;
380         }
381
382 #ifdef LDAP_CONNECTIONLESS
383         if ( op->o_cldap ) {
384                 ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_UDP_SET_DST,
385                     (void *)&op->o_clientaddr );
386                 Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
387                     inet_ntoa(((struct sockaddr_in *)
388                     &op->o_clientaddr)->sin_addr ),
389                     ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
390                     0 );
391         }
392 #endif
393
394         send_ldap_response( conn, op, tag, msgid,
395                 err, NULL, text, NULL,
396                 reqoid, NULL, NULL, NULL );
397
398         Statslog( LDAP_DEBUG_STATS,
399             "conn=%ld op=%ld DISCONNECT err=%ld tag=%lu text=%s\n",
400                 (long) op->o_connid, (long) op->o_opid,
401                 (long) tag, (long) err, text ? text : "" );
402 }
403
404 void
405 send_ldap_result(
406     Connection  *conn,
407     Operation   *op,
408     ber_int_t   err,
409     const char  *matched,
410     const char  *text,
411         struct berval **ref,
412         LDAPControl **ctrls
413 )
414 {
415         ber_tag_t tag;
416         ber_int_t msgid;
417         char *tmp = NULL;
418
419         assert( !LDAP_API_ERROR( err ) );
420
421         Debug( LDAP_DEBUG_TRACE, "send_ldap_result: conn=%ld op=%ld p=%d\n",
422                 (long) op->o_connid, (long) op->o_opid, op->o_protocol );
423         Debug( LDAP_DEBUG_ARGS, "send_ldap_result: %d:%s:%s\n",
424                 err, matched ?  matched : "", text ? text : "" );
425         if( ref ) {
426         Debug( LDAP_DEBUG_ARGS, "send_ldap_result: referral: %s\n",
427                 ref[0] && ref[0]->bv_val ? ref[0]->bv_val : "NULL",
428                 NULL, NULL );
429         }
430
431         assert( err != LDAP_PARTIAL_RESULTS );
432
433         if( op->o_tag != LDAP_REQ_SEARCH ) {
434                 trim_refs_urls( ref );
435         }
436
437         if ( err == LDAP_REFERRAL ) {
438                 if( ref == NULL ) {
439                         err = LDAP_NO_SUCH_OBJECT;
440                 } else if ( op->o_protocol < LDAP_VERSION3 ) {
441                         err = LDAP_PARTIAL_RESULTS;
442                 }
443         }
444
445         if ( op->o_protocol < LDAP_VERSION3 ) {
446                 tmp = v2ref( ref, text );
447                 text = tmp;
448                 ref = NULL;
449         }
450
451         tag = req2res( op->o_tag );
452         msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
453
454 #ifdef LDAP_CONNECTIONLESS
455         if ( op->o_cldap ) {
456                 ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_UDP_SET_DST,
457                     (void *)&op->o_clientaddr );
458                 Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
459                     inet_ntoa(((struct sockaddr_in *)
460                     &op->o_clientaddr)->sin_addr ),
461                     ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
462                     0 );
463         }
464 #endif
465
466         send_ldap_response( conn, op, tag, msgid,
467                 err, matched, text, ref,
468                 NULL, NULL, NULL, ctrls );
469
470         Statslog( LDAP_DEBUG_STATS,
471             "conn=%ld op=%ld RESULT tag=%lu err=%ld text=%s\n",
472                 (long) op->o_connid, (long) op->o_opid,
473                 (long) tag, (long) err, text ? text : "" );
474
475         if( tmp != NULL ) {
476                 ch_free(tmp);
477         }
478 }
479
480 void
481 send_ldap_sasl(
482     Connection  *conn,
483     Operation   *op,
484     ber_int_t   err,
485     const char  *matched,
486     const char  *text,
487         struct berval **ref,
488         LDAPControl **ctrls,
489         struct berval *cred
490 )
491 {
492         ber_tag_t tag;
493         ber_int_t msgid;
494
495         Debug( LDAP_DEBUG_TRACE, "send_ldap_sasl %ld\n",
496                 (long) err, NULL, NULL );
497
498         tag = req2res( op->o_tag );
499         msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
500
501 #ifdef LDAP_CONNECTIONLESS
502         if ( op->o_cldap ) {
503                 ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_UDP_SET_DST,
504                     (void *)&op->o_clientaddr );
505                 Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
506                     inet_ntoa(((struct sockaddr_in *)
507                     &op->o_clientaddr)->sin_addr ),
508                     ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
509                     0 );
510         }
511 #endif
512
513         send_ldap_response( conn, op, tag, msgid,
514                 err, matched, text, ref,
515                 NULL, NULL, cred, ctrls  );
516 }
517
518 void
519 send_ldap_extended(
520     Connection  *conn,
521     Operation   *op,
522     ber_int_t   err,
523     const char  *matched,
524     const char  *text,
525     struct berval **refs,
526     const char          *rspoid,
527         struct berval *rspdata,
528         LDAPControl **ctrls
529 )
530 {
531         ber_tag_t tag;
532         ber_int_t msgid;
533
534         Debug( LDAP_DEBUG_TRACE,
535                 "send_ldap_extended %ld:%s (%ld)\n",
536                 (long) err,
537                 rspoid ? rspoid : "",
538                 rspdata != NULL ? (long) rspdata->bv_len : (long) 0 );
539
540         tag = req2res( op->o_tag );
541         msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
542
543 #ifdef LDAP_CONNECTIONLESS
544         if ( op->o_cldap ) {
545                 ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_UDP_SET_DST,
546                     (void *)&op->o_clientaddr );
547                 Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
548                     inet_ntoa(((struct sockaddr_in *)
549                     &op->o_clientaddr)->sin_addr ),
550                     ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
551                     0 );
552         }
553 #endif
554
555         send_ldap_response( conn, op, tag, msgid,
556                 err, matched, text, refs,
557                 rspoid, rspdata, NULL, ctrls );
558 }
559
560
561 void
562 send_search_result(
563     Connection  *conn,
564     Operation   *op,
565     ber_int_t   err,
566     const char  *matched,
567         const char      *text,
568     struct berval **refs,
569         LDAPControl **ctrls,
570     int         nentries
571 )
572 {
573         ber_tag_t tag;
574         ber_int_t msgid;
575         char *tmp = NULL;
576         assert( !LDAP_API_ERROR( err ) );
577
578         Debug( LDAP_DEBUG_TRACE, "send_ldap_search_result %d:%s:%s\n",
579                 err, matched ?  matched : "", text ? text : "" );
580
581         assert( err != LDAP_PARTIAL_RESULTS );
582
583         trim_refs_urls( refs );
584
585         if( op->o_protocol < LDAP_VERSION3 ) {
586                 /* send references in search results */
587                 if( err == LDAP_REFERRAL ) {
588                         err = LDAP_PARTIAL_RESULTS;
589                 }
590
591                 tmp = v2ref( refs, text );
592                 text = tmp;
593                 refs = NULL;
594         } else {
595                 /* don't send references in search results */
596                 assert( refs == NULL );
597                 refs = NULL;
598
599                 if( err == LDAP_REFERRAL ) {
600                         err = LDAP_SUCCESS;
601                 }
602         }
603
604         tag = req2res( op->o_tag );
605         msgid = (tag != LBER_SEQUENCE) ? op->o_msgid : 0;
606
607 #ifdef LDAP_CONNECTIONLESS
608         if ( op->o_cldap ) {
609                 ber_sockbuf_ctrl( conn->c_sb, LBER_SB_OPT_UDP_SET_DST,
610                     (void *)&op->o_clientaddr );
611                 Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
612                     inet_ntoa(((struct sockaddr_in *)
613                     &op->o_clientaddr)->sin_addr ),
614                     ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
615                     0 );
616         }
617 #endif
618
619         send_ldap_response( conn, op, tag, msgid,
620                 err, matched, text, refs,
621                 NULL, NULL, NULL, ctrls );
622
623         Statslog( LDAP_DEBUG_STATS,
624             "conn=%ld op=%ld SEARCH RESULT tag=%lu err=%ld text=%s\n",
625                 (long) op->o_connid, (long) op->o_opid,
626                 (long) tag, (long) err, text ? text : "" );
627
628         if (tmp != NULL)
629             ch_free(tmp);
630 }
631
632
633 int
634 send_search_entry(
635     Backend     *be,
636     Connection  *conn,
637     Operation   *op,
638     Entry       *e,
639     char        **attrs,
640     int         attrsonly,
641         LDAPControl **ctrls
642 )
643 {
644         BerElement      *ber;
645         Attribute       *a, *aa;
646         int             i, rc=-1, bytes;
647         char            *edn;
648         int             userattrs;
649         int             opattrs;
650
651 #ifdef SLAPD_SCHEMA_NOT_COMPAT
652         AttributeDescription *ad_entry = slap_schema.si_ad_entry;
653 #else
654         static const char *ad_entry = "entry";
655 #endif
656
657         Debug( LDAP_DEBUG_TRACE, "=> send_search_entry: \"%s\"\n", e->e_dn, 0, 0 );
658
659         if ( ! access_allowed( be, conn, op, e,
660                 ad_entry, NULL, ACL_READ ) )
661         {
662                 Debug( LDAP_DEBUG_ACL, "acl: access to entry not allowed\n",
663                     0, 0, 0 );
664                 return( 1 );
665         }
666
667         edn = e->e_ndn;
668
669         ber = ber_alloc_t( LBER_USE_DER );
670
671         if ( ber == NULL ) {
672                 Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
673                 send_ldap_result( conn, op, LDAP_OTHER,
674                         NULL, "BER allocation error", NULL, NULL );
675                 goto error_return;
676         }
677
678         rc = ber_printf( ber, "{it{s{" /*}}}*/, op->o_msgid,
679                 LDAP_RES_SEARCH_ENTRY, e->e_dn );
680
681         if ( rc == -1 ) {
682                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
683                 ber_free( ber, 1 );
684                 send_ldap_result( conn, op, LDAP_OTHER,
685                     NULL, "encoding DN error", NULL, NULL );
686                 goto error_return;
687         }
688
689         /* check for special all user attributes ("*") type */
690         userattrs = ( attrs == NULL ) ? 1
691                 : charray_inlist( attrs, LDAP_ALL_USER_ATTRIBUTES );
692
693         /* check for special all operational attributes ("+") type */
694         opattrs = ( attrs == NULL ) ? 0
695                 : charray_inlist( attrs, LDAP_ALL_OPERATIONAL_ATTRIBUTES );
696
697         for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
698 #ifdef SLAPD_SCHEMA_NOT_COMPAT
699                 AttributeDescription *desc = a->a_desc;
700                 char *type = desc->ad_cname->bv_val;
701 #else
702                 char *desc = a->a_type;
703                 char *type = a->a_type;
704 #endif
705
706                 if ( attrs == NULL ) {
707                         /* all addrs request, skip operational attributes */
708 #ifdef SLAPD_SCHEMA_NOT_COMPAT
709                         if( is_at_operational( desc->ad_type ) )
710 #else
711                         if( oc_check_op_attr( desc ) )
712 #endif
713                         {
714                                 continue;
715                         }
716
717                 } else {
718                         /* specific addrs requested */
719 #ifdef SLAPD_SCHEMA_NOT_COMPAT
720                         if ( is_at_operational( desc->ad_type ) )
721 #else
722                         if ( oc_check_op_attr( desc ) )
723 #endif
724                         {
725                                 if( !opattrs && !ad_inlist( desc, attrs ) ) {
726                                         continue;
727                                 }
728                         } else {
729                                 if (!userattrs && !ad_inlist( desc, attrs ) ) {
730                                         continue;
731                                 }
732                         }
733                 }
734
735                 if ( ! access_allowed( be, conn, op, e, desc, NULL, ACL_READ ) ) {
736                         Debug( LDAP_DEBUG_ACL, "acl: access to attribute %s not allowed\n",
737                             desc, 0, 0 );
738                         continue;
739                 }
740
741                 if (( rc = ber_printf( ber, "{s[" /*]}*/ , type )) == -1 ) {
742                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
743                         ber_free( ber, 1 );
744                         send_ldap_result( conn, op, LDAP_OTHER,
745                             NULL, "encoding description error", NULL, NULL );
746                         goto error_return;
747                 }
748
749                 if ( ! attrsonly ) {
750                         for ( i = 0; a->a_vals[i] != NULL; i++ ) {
751                                 if ( ! access_allowed( be, conn, op, e,
752                                         desc, a->a_vals[i], ACL_READ ) )
753                                 {
754                                         Debug( LDAP_DEBUG_ACL,
755                                                 "acl: access to attribute %s, value %d not allowed\n",
756                                         desc, i, 0 );
757                                         continue;
758                                 }
759
760                                 if (( rc = ber_printf( ber, "O", a->a_vals[i] )) == -1 ) {
761                                         Debug( LDAP_DEBUG_ANY,
762                                             "ber_printf failed\n", 0, 0, 0 );
763                                         ber_free( ber, 1 );
764                                         send_ldap_result( conn, op, LDAP_OTHER,
765                                                 NULL, "encoding values error", NULL, NULL );
766                                         goto error_return;
767                                 }
768                         }
769                 }
770
771                 if (( rc = ber_printf( ber, /*{[*/ "]}" )) == -1 ) {
772                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
773                         ber_free( ber, 1 );
774                         send_ldap_result( conn, op, LDAP_OTHER,
775                             NULL, "encode end error", NULL, NULL );
776                         goto error_return;
777                 }
778         }
779
780         /* eventually will loop through generated operational attributes */
781         /* only have subschemaSubentry implemented */
782         aa = backend_operational( be, e );
783         
784         for (a = aa ; a == NULL; a = a->a_next ) {
785 #ifdef SLAPD_SCHEMA_NOT_COMPAT
786                 AttributeDescription *desc = a->a_desc;
787 #else
788                 char *desc = a->a_type;
789 #endif
790
791                 if ( attrs == NULL ) {
792                         /* all addrs request, skip operational attributes */
793 #ifdef SLAPD_SCHEMA_NOT_COMPAT
794                         if( is_at_operational( desc->ad_type ) )
795 #else
796                         if( oc_check_op_attr( desc ) )
797 #endif
798                         {
799                                 continue;
800                         }
801
802                 } else {
803                         /* specific addrs requested */
804 #ifdef SLAPD_SCHEMA_NOT_COMPAT
805                         if( is_at_operational( desc->ad_type ) )
806 #else
807                         if( oc_check_op_attr( desc ) )
808 #endif
809                         {
810                                 if( !opattrs && !ad_inlist( desc, attrs ) )
811                                 {
812                                         continue;
813                                 }
814                         } else {
815                                 if (!userattrs && !ad_inlist( desc, attrs ) )
816                                 {
817                                         continue;
818                                 }
819                         }
820                 }
821
822                 if ( ! access_allowed( be, conn, op, e, desc, NULL, ACL_READ ) ) {
823                         Debug( LDAP_DEBUG_ACL, "acl: access to attribute %s not allowed\n",
824                             desc, 0, 0 );
825                         continue;
826                 }
827
828                 if (( rc = ber_printf( ber, "{s[" /*]}*/ , desc )) == -1 ) {
829                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
830                         ber_free( ber, 1 );
831                         send_ldap_result( conn, op, LDAP_OTHER,
832                             NULL, "encoding description error", NULL, NULL );
833                         goto error_return;
834                 }
835
836                 if ( ! attrsonly ) {
837                         for ( i = 0; a->a_vals[i] != NULL; i++ ) {
838                                 if ( ! access_allowed( be, conn, op, e,
839                                         desc, a->a_vals[i], ACL_READ ) )
840                                 {
841                                         Debug( LDAP_DEBUG_ACL,
842                                                 "acl: access to attribute %s, value %d not allowed\n",
843                                         desc, i, 0 );
844                                         continue;
845                                 }
846
847
848                                 if (( rc = ber_printf( ber, "O", a->a_vals[i] )) == -1 ) {
849                                         Debug( LDAP_DEBUG_ANY,
850                                             "ber_printf failed\n", 0, 0, 0 );
851                                         ber_free( ber, 1 );
852                                         send_ldap_result( conn, op, LDAP_OTHER,
853                                                 NULL, "encoding values error", NULL, NULL );
854                                         goto error_return;
855                                 }
856                         }
857                 }
858
859                 if (( rc = ber_printf( ber, /*{[*/ "]}" )) == -1 ) {
860                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
861                         ber_free( ber, 1 );
862                         send_ldap_result( conn, op, LDAP_OTHER,
863                             NULL, "encode end error", NULL, NULL );
864                         goto error_return;
865                 }
866         }
867
868         attrs_free( aa );
869
870         rc = ber_printf( ber, /*{{{*/ "}}}" );
871
872         if ( rc == -1 ) {
873                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
874                 ber_free( ber, 1 );
875                 send_ldap_result( conn, op, LDAP_OTHER,
876                         NULL, "encode entry end error", NULL, NULL );
877                 return( 1 );
878         }
879
880         bytes = send_ldap_ber( conn, ber );
881         ber_free( ber, 1 );
882
883         if ( bytes < 0 ) {
884                 Debug( LDAP_DEBUG_ANY,
885                         "send_ldap_response: ber write failed\n",
886                         0, 0, 0 );
887                 return -1;
888         }
889
890         ldap_pvt_thread_mutex_lock( &num_sent_mutex );
891         num_bytes_sent += bytes;
892         num_entries_sent++;
893         num_pdu_sent++;
894         ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
895
896         Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld ENTRY dn=\"%s\"\n",
897             (long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 );
898
899         Debug( LDAP_DEBUG_TRACE, "<= send_search_entry\n", 0, 0, 0 );
900
901         rc = 0;
902
903 error_return:;
904         return( rc );
905 }
906
907 int
908 send_search_reference(
909     Backend     *be,
910     Connection  *conn,
911     Operation   *op,
912     Entry       *e,
913         struct berval **refs,
914         int scope,
915         LDAPControl **ctrls,
916     struct berval ***v2refs
917 )
918 {
919         BerElement      *ber;
920         int rc;
921         int bytes;
922
923 #ifdef SLAPD_SCHEMA_NOT_COMPAT
924         AttributeDescription *ad_ref = slap_schema.si_ad_ref;
925         AttributeDescription *ad_entry = slap_schema.si_ad_entry;
926 #else
927         static const char *ad_ref = "ref";
928         static const char *ad_entry = "entry";
929 #endif
930
931         Debug( LDAP_DEBUG_TRACE, "=> send_search_reference (%s)\n", e->e_dn, 0, 0 );
932
933         if ( ! access_allowed( be, conn, op, e,
934                 ad_entry, NULL, ACL_READ ) )
935         {
936                 Debug( LDAP_DEBUG_ACL,
937                         "send_search_reference: access to entry not allowed\n",
938                     0, 0, 0 );
939                 return( 1 );
940         }
941
942         if ( ! access_allowed( be, conn, op, e,
943                 ad_ref, NULL, ACL_READ ) )
944         {
945                 Debug( LDAP_DEBUG_ACL,
946                         "send_search_reference: access to reference not allowed\n",
947                     0, 0, 0 );
948                 return( 1 );
949         }
950
951         if( refs == NULL ) {
952                 Debug( LDAP_DEBUG_ANY,
953                         "send_search_reference: null ref in (%s)\n", 
954                         e->e_dn, 0, 0 );
955                 return( 1 );
956         }
957
958         if( op->o_protocol < LDAP_VERSION3 ) {
959                 /* save the references for the result */
960                 if( *refs != NULL ) {
961                         value_add( v2refs, refs );
962                 }
963                 return 0;
964         }
965
966         ber = ber_alloc_t( LBER_USE_DER );
967
968         if ( ber == NULL ) {
969                 Debug( LDAP_DEBUG_ANY,
970                         "send_search_reference: ber_alloc failed\n", 0, 0, 0 );
971                 send_ldap_result( conn, op, LDAP_OTHER,
972                         NULL, "alloc BER error", NULL, NULL );
973                 return -1;
974         }
975
976         rc = ber_printf( ber, "{it{V}}", op->o_msgid,
977                 LDAP_RES_SEARCH_REFERENCE, refs );
978
979         if ( rc == -1 ) {
980                 Debug( LDAP_DEBUG_ANY,
981                         "send_search_reference: ber_printf failed\n", 0, 0, 0 );
982                 ber_free( ber, 1 );
983                 send_ldap_result( conn, op, LDAP_OTHER,
984                         NULL, "encode DN error", NULL, NULL );
985                 return -1;
986         }
987
988         bytes = send_ldap_ber( conn, ber );
989         ber_free( ber, 1 );
990
991         ldap_pvt_thread_mutex_lock( &num_sent_mutex );
992         num_bytes_sent += bytes;
993         num_refs_sent++;
994         num_pdu_sent++;
995         ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
996
997         Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld ENTRY dn=\"%s\"\n",
998             (long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 );
999
1000         Debug( LDAP_DEBUG_TRACE, "<= send_search_reference\n", 0, 0, 0 );
1001
1002         return 0;
1003 }
1004
1005
1006 int
1007 str2result(
1008     char        *s,
1009     int         *code,
1010     char        **matched,
1011     char        **info
1012 )
1013 {
1014         int     rc;
1015         char    *c;
1016
1017         *code = LDAP_SUCCESS;
1018         *matched = NULL;
1019         *info = NULL;
1020
1021         if ( strncasecmp( s, "RESULT", 6 ) != 0 ) {
1022                 Debug( LDAP_DEBUG_ANY, "str2result (%s) expecting \"RESULT\"\n",
1023                     s, 0, 0 );
1024
1025                 return( -1 );
1026         }
1027
1028         rc = 0;
1029         while ( (s = strchr( s, '\n' )) != NULL ) {
1030                 *s++ = '\0';
1031                 if ( *s == '\0' ) {
1032                         break;
1033                 }
1034                 if ( (c = strchr( s, ':' )) != NULL ) {
1035                         c++;
1036                 }
1037
1038                 if ( strncasecmp( s, "code", 4 ) == 0 ) {
1039                         if ( c != NULL ) {
1040                                 *code = atoi( c );
1041                         }
1042                 } else if ( strncasecmp( s, "matched", 7 ) == 0 ) {
1043                         if ( c != NULL ) {
1044                                 *matched = c;
1045                         }
1046                 } else if ( strncasecmp( s, "info", 4 ) == 0 ) {
1047                         if ( c != NULL ) {
1048                                 *info = c;
1049                         }
1050                 } else {
1051                         Debug( LDAP_DEBUG_ANY, "str2result (%s) unknown\n",
1052                             s, 0, 0 );
1053                         rc = -1;
1054                 }
1055         }
1056
1057         return( rc );
1058 }