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