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