]> git.sur5r.net Git - openldap/blob - servers/slapd/result.c
Add support for unsolicited notifications.
[openldap] / servers / slapd / result.c
1 /* result.c - routines to send ldap results, errors, and referrals */
2
3 #include "portable.h"
4
5 #include <stdio.h>
6
7 #include <ac/socket.h>
8 #include <ac/errno.h>
9 #include <ac/signal.h>
10 #include <ac/string.h>
11 #include <ac/time.h>
12 #include <ac/unistd.h>          /* get close() */
13
14 #include "slap.h"
15
16 /* we need LBER internals */
17 #include "../../libraries/liblber/lber-int.h"
18
19 static void
20 send_ldap_result2(
21     Connection  *conn,
22     Operation   *op,
23         int             disconnect,
24     ber_int_t   err,
25     char        *matched,
26     char        *text,
27     int         nentries
28 )
29 {
30         BerElement      *ber;
31         int             rc;
32         ber_tag_t       tag;
33         ber_len_t       bytes;
34         int     msgid;
35
36         assert( !LDAP_API_ERROR( err ) );
37
38         if ( err == LDAP_PARTIAL_RESULTS && (text == NULL || *text == '\0') )
39                 err = LDAP_NO_SUCH_OBJECT;
40
41         if( disconnect ) {
42                 msgid = 0;      /* unsolicited */
43                 if ( op->o_protocol > LDAP_VERSION3 ) {
44                         tag = LDAP_RES_EXTENDED;
45                 }
46
47 #define LDAP_UNSOLICITED_ERROR(e) \
48         (  (e) == LDAP_PROTOCOL_ERROR \
49         || (e) == LDAP_STRONG_AUTH_REQUIRED \
50         || (e) == LDAP_UNAVAILABLE )
51
52                 assert( LDAP_UNSOLICITED_ERROR( err ) );
53
54         } else {
55                 msgid = op->o_msgid;
56
57                 switch ( op->o_tag ) {
58                 case LDAP_REQ_ABANDON:
59                 case LDAP_REQ_UNBIND:
60                 case LBER_ERROR:
61                         tag = LBER_SEQUENCE;
62                         msgid = 0;
63                         assert( LDAP_UNSOLICITED_ERROR( err ) );
64                         break;
65
66                 case LDAP_REQ_SEARCH:
67                         tag = LDAP_RES_SEARCH_RESULT;
68                         break;
69
70                 case LDAP_REQ_DELETE:
71                         tag = LDAP_RES_DELETE;
72                         break;
73
74                 default:
75                         tag = op->o_tag + 1;
76                         break;
77                 }
78         }
79
80
81         ber = ber_alloc_t( LBER_USE_DER );
82
83         if ( ber == NULL ) {
84                 Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
85                 return;
86         }
87
88 #ifdef LDAP_CONNECTIONLESS
89         if ( op->o_cldap ) {
90                 rc = ber_printf( ber, "{is{t{ess}}}", msgid, "", tag,
91                     err, matched ? matched : "", text ? text : "" );
92         } else
93 #endif
94         if( tag == LDAP_RES_EXTENDED ) {
95                 rc = ber_printf( ber, "{it{esss}}",
96                         msgid, tag, err,
97                         "", text ? text : "",
98                         LDAP_NOTICE_DISCONNECT );
99
100         } else {
101                 rc = ber_printf( ber, "{it{ess}}",
102                         msgid, tag, err,
103                         matched ? matched : "", text ? text : "" );
104         }
105
106         if ( rc == -1 ) {
107                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
108                 return;
109         }
110
111         /* write only one pdu at a time - wait til it's our turn */
112         ldap_pvt_thread_mutex_lock( &conn->c_write_mutex );
113
114         /* lock the connection */
115         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
116
117         /* write the pdu */
118         bytes = ber_pvt_ber_bytes( ber );
119
120         while ( 1 ) {
121                 int err;
122
123                 if ( connection_state_closing( conn ) ) {
124                         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
125                         ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
126                         return;
127                 }
128
129                 if ( ber_flush( conn->c_sb, ber, 1 ) == 0 ) {
130                         break;
131                 }
132
133                 err = errno;
134
135                 /*
136                  * we got an error.  if it's ewouldblock, we need to
137                  * wait on the socket being writable.  otherwise, figure
138                  * it's a hard error and return.
139                  */
140
141                 Debug( LDAP_DEBUG_CONNS, "ber_flush failed errno %d msg (%s)\n",
142                     err, err > -1 && err < sys_nerr ? sys_errlist[err]
143                     : "unknown", 0 );
144
145                 if ( err != EWOULDBLOCK && err != EAGAIN ) {
146                         connection_closing( conn );
147
148                         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
149                         ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
150                         return;
151                 }
152
153                 /* wait for socket to be write-ready */
154                 conn->c_writewaiter = 1;
155                 slapd_set_write( ber_pvt_sb_get_desc( conn->c_sb ), 1 );
156
157                 ldap_pvt_thread_cond_wait( &conn->c_write_cv, &conn->c_mutex );
158                 conn->c_writewaiter = 0;
159         }
160
161         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
162         ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
163
164         ldap_pvt_thread_mutex_lock( &num_sent_mutex );
165         num_bytes_sent += bytes;
166         ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
167
168         Statslog( LDAP_DEBUG_STATS,
169             "conn=%ld op=%ld RESULT err=%ld tag=%lu nentries=%d\n",
170                 (long) conn->c_connid, (long) op->o_opid,
171                 (long) err, (long) tag, nentries );
172
173         return;
174 }
175
176 void
177 send_ldap_result(
178     Connection  *conn,
179     Operation   *op,
180     ber_int_t   err,
181     char        *matched,
182     char        *text
183 )
184 {
185         assert( !LDAP_API_ERROR( err ) );
186
187         Debug( LDAP_DEBUG_TRACE, "send_ldap_result %d:%s:%s\n",
188                 err, matched ?  matched : "", text ? text : "" );
189
190 #ifdef LDAP_CONNECTIONLESS
191         if ( op->o_cldap ) {
192                 ber_pvt_sb_udp_set_dst( &conn->c_sb, &op->o_clientaddr );
193                 Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
194                     inet_ntoa(((struct sockaddr_in *)
195                     &op->o_clientaddr)->sin_addr ),
196                     ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
197                     0 );
198         }
199 #endif
200         send_ldap_result2( conn, op, 0, err, matched, text, 0 );
201 }
202
203 void
204 send_ldap_disconnect(
205     Connection  *conn,
206     Operation   *op,
207     ber_int_t   err,
208     char        *text
209 )
210 {
211         assert( !LDAP_API_ERROR( err ) );
212
213         Debug( LDAP_DEBUG_TRACE,
214                 "send_ldap_disconnect %d:%s\n",
215                 err, text ? text : "", NULL );
216
217 #ifdef LDAP_CONNECTIONLESS
218         if ( op->o_cldap ) {
219                 ber_pvt_sb_udp_set_dst( &conn->c_sb, &op->o_clientaddr );
220                 Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
221                     inet_ntoa(((struct sockaddr_in *)
222                     &op->o_clientaddr)->sin_addr ),
223                     ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
224                     0 );
225         }
226 #endif
227         send_ldap_result2( conn, op, 0, err, NULL, text, 0 );
228 }
229
230 void
231 send_ldap_search_result(
232     Connection  *conn,
233     Operation   *op,
234     ber_int_t   err,
235     char        *matched,
236     char        *text,
237     int         nentries
238 )
239 {
240         Debug( LDAP_DEBUG_TRACE, "send_ldap_search_result %d:%s:%s\n",
241                 err, matched ?  matched : "", text ? text : "" );
242
243         send_ldap_result2( conn, op, 0, err, matched, text, nentries );
244 }
245
246 int
247 send_search_entry(
248     Backend     *be,
249     Connection  *conn,
250     Operation   *op,
251     Entry       *e,
252     char        **attrs,
253     int         attrsonly,
254         int             opattrs
255 )
256 {
257         BerElement      *ber;
258         Attribute       *a;
259         int             i, rc=-1, bytes;
260         struct acl      *acl;
261         char            *edn;
262
263         Debug( LDAP_DEBUG_TRACE, "=> send_search_entry (%s)\n", e->e_dn, 0, 0 );
264
265 #if defined( SLAPD_SCHEMA_DN )
266         {
267                 /* this could be backend specific */
268                 struct  berval  val;
269                 val.bv_val = SLAPD_SCHEMA_DN;
270                 val.bv_len = strlen( val.bv_val );
271                 attr_merge( e, "subschemaSubentry", vals );
272                 ldap_memfree( val.bv_val );
273         }
274 #endif
275
276         if ( ! access_allowed( be, conn, op, e,
277                 "entry", NULL, ACL_READ ) )
278         {
279                 Debug( LDAP_DEBUG_ACL, "acl: access to entry not allowed\n",
280                     0, 0, 0 );
281                 return( 1 );
282         }
283
284         edn = e->e_ndn;
285
286         ber = ber_alloc_t( LBER_USE_DER );
287
288         if ( ber == NULL ) {
289                 Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
290                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL,
291                         "ber_alloc" );
292                 goto error_return;
293         }
294
295         rc = ber_printf( ber, "{it{s{", op->o_msgid,
296                 LDAP_RES_SEARCH_ENTRY, e->e_dn );
297
298         if ( rc == -1 ) {
299                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
300                 ber_free( ber, 1 );
301                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL,
302                     "ber_printf dn" );
303                 goto error_return;
304         }
305
306         for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
307                 regmatch_t       matches[MAXREMATCHES];
308
309                 if ( attrs == NULL ) {
310                         /* all addrs request, skip operational attributes */
311                         if( !opattrs && oc_check_operational_attr( a->a_type )) {
312                                 continue;
313                         }
314
315                 } else {
316                         /* specific addrs requested */
317                         if ( !charray_inlist( attrs, a->a_type )
318                                 && !charray_inlist( attrs, LDAP_ALL_USER_ATTRIBUTES ) )
319                         {
320                                 continue;
321                         }
322                 }
323
324                 acl = acl_get_applicable( be, op, e, a->a_type,
325                         MAXREMATCHES, matches );
326
327                 if ( ! acl_access_allowed( acl, be, conn, e,
328                         NULL, op, ACL_READ, edn, matches ) ) 
329                 {
330                         continue;
331                 }
332
333                 if (( rc = ber_printf( ber, "{s[" /*]}*/ , a->a_type )) == -1 ) {
334                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
335                         ber_free( ber, 1 );
336                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
337                             NULL, "ber_printf type" );
338                         goto error_return;
339                 }
340
341                 if ( ! attrsonly ) {
342                         for ( i = 0; a->a_vals[i] != NULL; i++ ) {
343                                 if ( a->a_syntax & SYNTAX_DN && 
344                                         ! acl_access_allowed( acl, be, conn, e, a->a_vals[i], op,
345                                                 ACL_READ, edn, matches) )
346                                 {
347                                         continue;
348                                 }
349
350                                 if (( rc = ber_printf( ber, "O", a->a_vals[i] )) == -1 ) {
351                                         Debug( LDAP_DEBUG_ANY,
352                                             "ber_printf failed\n", 0, 0, 0 );
353                                         ber_free( ber, 1 );
354                                         send_ldap_result( conn, op,
355                                             LDAP_OPERATIONS_ERROR, NULL,
356                                             "ber_printf value" );
357                                         goto error_return;
358                                 }
359                         }
360                 }
361
362                 if (( rc = ber_printf( ber, /*{[*/ "]}" )) == -1 ) {
363                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
364                         ber_free( ber, 1 );
365                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
366                             NULL, "ber_printf type end" );
367                         goto error_return;
368                 }
369         }
370
371         rc = ber_printf( ber, /*{{{*/ "}}}" );
372
373         if ( rc == -1 ) {
374                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
375                 ber_free( ber, 1 );
376                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL,
377                     "ber_printf entry end" );
378                 return( 1 );
379         }
380
381         bytes = ber_pvt_ber_bytes( ber );
382
383         /* write only one pdu at a time - wait til it's our turn */
384         ldap_pvt_thread_mutex_lock( &conn->c_write_mutex );
385
386         /* lock the connection */ 
387         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
388
389         /* write the pdu */
390         while( 1 ) {
391                 int err;
392
393                 if ( connection_state_closing( conn ) ) {
394                         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
395                         ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
396                         return 0;
397                 }
398
399                 if ( ber_flush( conn->c_sb, ber, 1 ) == 0 ) {
400                         break;
401                 }
402
403                 err = errno;
404
405                 /*
406                  * we got an error.  if it's ewouldblock, we need to
407                  * wait on the socket being writable.  otherwise, figure
408                  * it's a hard error and return.
409                  */
410
411                 Debug( LDAP_DEBUG_CONNS, "ber_flush failed errno %d msg (%s)\n",
412                     err, err > -1 && err < sys_nerr ? sys_errlist[err]
413                     : "unknown", 0 );
414
415                 if ( err != EWOULDBLOCK && err != EAGAIN ) {
416                         connection_closing( conn );
417
418                         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
419                         ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
420                         return( -1 );
421                 }
422
423                 /* wait for socket to be write-ready */
424                 conn->c_writewaiter = 1;
425                 slapd_set_write( ber_pvt_sb_get_desc( conn->c_sb ), 1 );
426
427                 ldap_pvt_thread_cond_wait( &conn->c_write_cv, &conn->c_mutex );
428                 conn->c_writewaiter = 0;
429         }
430
431         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
432         ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
433
434         ldap_pvt_thread_mutex_lock( &num_sent_mutex );
435         num_bytes_sent += bytes;
436         num_entries_sent++;
437         ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
438
439         Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld ENTRY dn=\"%s\"\n",
440             (long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 );
441
442         Debug( LDAP_DEBUG_TRACE, "<= send_search_entry\n", 0, 0, 0 );
443
444         rc = 0;
445
446 error_return:;
447         return( rc );
448 }
449
450 int
451 str2result(
452     char        *s,
453     int         *code,
454     char        **matched,
455     char        **info
456 )
457 {
458         int     rc;
459         char    *c;
460
461         *code = LDAP_SUCCESS;
462         *matched = NULL;
463         *info = NULL;
464
465         if ( strncasecmp( s, "RESULT", 6 ) != 0 ) {
466                 Debug( LDAP_DEBUG_ANY, "str2result (%s) expecting \"RESULT\"\n",
467                     s, 0, 0 );
468
469                 return( -1 );
470         }
471
472         rc = 0;
473         while ( (s = strchr( s, '\n' )) != NULL ) {
474                 *s++ = '\0';
475                 if ( *s == '\0' ) {
476                         break;
477                 }
478                 if ( (c = strchr( s, ':' )) != NULL ) {
479                         c++;
480                 }
481
482                 if ( strncasecmp( s, "code", 4 ) == 0 ) {
483                         if ( c != NULL ) {
484                                 *code = atoi( c );
485                         }
486                 } else if ( strncasecmp( s, "matched", 7 ) == 0 ) {
487                         if ( c != NULL ) {
488                                 *matched = c;
489                         }
490                 } else if ( strncasecmp( s, "info", 4 ) == 0 ) {
491                         if ( c != NULL ) {
492                                 *info = c;
493                         }
494                 } else {
495                         Debug( LDAP_DEBUG_ANY, "str2result (%s) unknown\n",
496                             s, 0, 0 );
497                         rc = -1;
498                 }
499         }
500
501         return( rc );
502 }