]> git.sur5r.net Git - openldap/blob - servers/slapd/result.c
Remove old U-Mich v3.0 and OLD_LDAP_* crud.
[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     ber_int_t   err,
24     char        *matched,
25     char        *text,
26     int         nentries
27 )
28 {
29         BerElement      *ber;
30         int             rc;
31         ber_tag_t       tag;
32         ber_len_t       bytes;
33
34         if ( err == LDAP_PARTIAL_RESULTS && (text == NULL || *text == '\0') )
35                 err = LDAP_NO_SUCH_OBJECT;
36
37         Debug( LDAP_DEBUG_TRACE, "send_ldap_result %d:%s:%s\n", err,
38                 matched ?  matched : "",
39                 text ? text : "" );
40
41         switch ( op->o_tag ) {
42         case LBER_DEFAULT:
43                 tag = LBER_SEQUENCE;
44                 break;
45
46         case LDAP_REQ_SEARCH:
47                 tag = LDAP_RES_SEARCH_RESULT;
48                 break;
49
50         case LDAP_REQ_DELETE:
51                 tag = LDAP_RES_DELETE;
52                 break;
53
54         default:
55                 tag = op->o_tag + 1;
56                 break;
57         }
58
59
60         ber = ber_alloc_t( LBER_USE_DER );
61
62         if ( ber == NULL ) {
63                 Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
64                 return;
65         }
66
67 #ifdef LDAP_CONNECTIONLESS
68         if ( op->o_cldap ) {
69                 rc = ber_printf( ber, "{is{t{ess}}}", op->o_msgid, "", tag,
70                     err, matched ? matched : "", text ? text : "" );
71         } else
72 #endif
73         {
74                 rc = ber_printf( ber, "{it{ess}}", op->o_msgid, tag, err,
75                     matched ? matched : "", text ? text : "" );
76         }
77
78         if ( rc == -1 ) {
79                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
80                 return;
81         }
82
83         /* write only one pdu at a time - wait til it's our turn */
84         ldap_pvt_thread_mutex_lock( &conn->c_write_mutex );
85
86         /* lock the connection */
87         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
88
89         /* write the pdu */
90         bytes = ber_pvt_ber_bytes( ber );
91
92         while ( 1 ) {
93                 int err;
94
95                 if ( connection_state_closing( conn ) ) {
96                         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
97                         ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
98                         return;
99                 }
100
101                 if ( ber_flush( conn->c_sb, ber, 1 ) == 0 ) {
102                         break;
103                 }
104
105                 err = errno;
106
107                 /*
108                  * we got an error.  if it's ewouldblock, we need to
109                  * wait on the socket being writable.  otherwise, figure
110                  * it's a hard error and return.
111                  */
112
113                 Debug( LDAP_DEBUG_CONNS, "ber_flush failed errno %d msg (%s)\n",
114                     err, err > -1 && err < sys_nerr ? sys_errlist[err]
115                     : "unknown", 0 );
116
117                 if ( err != EWOULDBLOCK && err != EAGAIN ) {
118                         connection_closing( conn );
119
120                         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
121                         ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
122                         return;
123                 }
124
125                 /* wait for socket to be write-ready */
126                 conn->c_writewaiter = 1;
127                 slapd_set_write( ber_pvt_sb_get_desc( conn->c_sb ), 1 );
128
129                 ldap_pvt_thread_cond_wait( &conn->c_write_cv, &conn->c_mutex );
130                 conn->c_writewaiter = 0;
131         }
132
133         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
134         ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
135
136         ldap_pvt_thread_mutex_lock( &num_sent_mutex );
137         num_bytes_sent += bytes;
138         ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
139
140         Statslog( LDAP_DEBUG_STATS,
141             "conn=%ld op=%ld RESULT err=%ld tag=%lu nentries=%d\n",
142                 (long) conn->c_connid, (long) op->o_opid,
143                 (long) err, (long) tag, nentries );
144
145         return;
146 }
147
148 void
149 send_ldap_result(
150     Connection  *conn,
151     Operation   *op,
152     ber_int_t   err,
153     char        *matched,
154     char        *text
155 )
156 {
157 #ifdef LDAP_CONNECTIONLESS
158         if ( op->o_cldap ) {
159                 ber_pvt_sb_udp_set_dst( &conn->c_sb, &op->o_clientaddr );
160                 Debug( LDAP_DEBUG_TRACE, "UDP response to %s port %d\n", 
161                     inet_ntoa(((struct sockaddr_in *)
162                     &op->o_clientaddr)->sin_addr ),
163                     ((struct sockaddr_in *) &op->o_clientaddr)->sin_port,
164                     0 );
165         }
166 #endif
167         send_ldap_result2( conn, op, err, matched, text, 0 );
168 }
169
170 void
171 send_ldap_search_result(
172     Connection  *conn,
173     Operation   *op,
174     ber_int_t   err,
175     char        *matched,
176     char        *text,
177     int         nentries
178 )
179 {
180         send_ldap_result2( conn, op, err, matched, text, nentries );
181 }
182
183 int
184 send_search_entry(
185     Backend     *be,
186     Connection  *conn,
187     Operation   *op,
188     Entry       *e,
189     char        **attrs,
190     int         attrsonly
191 )
192 {
193         BerElement      *ber;
194         Attribute       *a;
195         int             i, rc=-1, bytes;
196         struct acl      *acl;
197         char            *edn;
198
199         Debug( LDAP_DEBUG_TRACE, "=> send_search_entry (%s)\n", e->e_dn, 0, 0 );
200
201         if ( ! access_allowed( be, conn, op, e,
202                 "entry", NULL, ACL_READ ) )
203         {
204                 Debug( LDAP_DEBUG_ACL, "acl: access to entry not allowed\n",
205                     0, 0, 0 );
206                 return( 1 );
207         }
208
209         edn = e->e_ndn;
210
211         ber = ber_alloc_t( LBER_USE_DER );
212
213         if ( ber == NULL ) {
214                 Debug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
215                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL,
216                         "ber_alloc" );
217                 goto error_return;
218         }
219
220         rc = ber_printf( ber, "{it{s{", op->o_msgid,
221                 LDAP_RES_SEARCH_ENTRY, e->e_dn );
222
223         if ( rc == -1 ) {
224                 Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
225                 ber_free( ber, 1 );
226                 send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR, NULL,
227                     "ber_printf dn" );
228                 goto error_return;
229         }
230
231         for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
232                 regmatch_t       matches[MAXREMATCHES];
233
234                 if ( attrs != NULL && ! charray_inlist( attrs, a->a_type ) ) {
235                         continue;
236                 }
237
238                 /* the lastmod attributes are ignored by ACL checking */
239                 if ( strcasecmp( a->a_type, "modifiersname" ) == 0 ||
240                         strcasecmp( a->a_type, "modifytimestamp" ) == 0 ||
241                         strcasecmp( a->a_type, "creatorsname" ) == 0 ||
242                         strcasecmp( a->a_type, "createtimestamp" ) == 0 ) 
243                 {
244                         Debug( LDAP_DEBUG_ACL, "LASTMOD attribute: %s access DEFAULT\n",
245                                 a->a_type, 0, 0 );
246                         acl = NULL;
247                 } else {
248                         acl = acl_get_applicable( be, op, e, a->a_type,
249                                 MAXREMATCHES, matches );
250                 }
251
252                 if ( ! acl_access_allowed( acl, be, conn, e,
253                         NULL, op, ACL_READ, edn, matches ) ) 
254                 {
255                         continue;
256                 }
257
258                 if (( rc = ber_printf( ber, "{s[" /*]}*/ , a->a_type )) == -1 ) {
259                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
260                         ber_free( ber, 1 );
261                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
262                             NULL, "ber_printf type" );
263                         goto error_return;
264                 }
265
266                 if ( ! attrsonly ) {
267                         for ( i = 0; a->a_vals[i] != NULL; i++ ) {
268                                 if ( a->a_syntax & SYNTAX_DN && 
269                                         ! acl_access_allowed( acl, be, conn, e, a->a_vals[i], op,
270                                                 ACL_READ, edn, matches) )
271                                 {
272                                         continue;
273                                 }
274
275                                 if (( rc = ber_printf( ber, "O", a->a_vals[i] )) == -1 ) {
276                                         Debug( LDAP_DEBUG_ANY,
277                                             "ber_printf failed\n", 0, 0, 0 );
278                                         ber_free( ber, 1 );
279                                         send_ldap_result( conn, op,
280                                             LDAP_OPERATIONS_ERROR, NULL,
281                                             "ber_printf value" );
282                                         goto error_return;
283                                 }
284                         }
285                 }
286
287                 if (( rc = ber_printf( ber, /*{[*/ "]}" )) == -1 ) {
288                         Debug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
289                         ber_free( ber, 1 );
290                         send_ldap_result( conn, op, LDAP_OPERATIONS_ERROR,
291                             NULL, "ber_printf type end" );
292                         goto error_return;
293                 }
294         }
295
296         rc = ber_printf( ber, /*{{{*/ "}}}" );
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 entry end" );
303                 return( 1 );
304         }
305
306         bytes = ber_pvt_ber_bytes( ber );
307
308         /* write only one pdu at a time - wait til it's our turn */
309         ldap_pvt_thread_mutex_lock( &conn->c_write_mutex );
310
311         /* lock the connection */ 
312         ldap_pvt_thread_mutex_lock( &conn->c_mutex );
313
314         /* write the pdu */
315         while( 1 ) {
316                 int err;
317
318                 if ( connection_state_closing( conn ) ) {
319                         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
320                         ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
321                         return 0;
322                 }
323
324                 if ( ber_flush( conn->c_sb, ber, 1 ) == 0 ) {
325                         break;
326                 }
327
328                 err = errno;
329
330                 /*
331                  * we got an error.  if it's ewouldblock, we need to
332                  * wait on the socket being writable.  otherwise, figure
333                  * it's a hard error and return.
334                  */
335
336                 Debug( LDAP_DEBUG_CONNS, "ber_flush failed errno %d msg (%s)\n",
337                     err, err > -1 && err < sys_nerr ? sys_errlist[err]
338                     : "unknown", 0 );
339
340                 if ( err != EWOULDBLOCK && err != EAGAIN ) {
341                         connection_closing( conn );
342
343                         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
344                         ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
345                         return( -1 );
346                 }
347
348                 /* wait for socket to be write-ready */
349                 conn->c_writewaiter = 1;
350                 slapd_set_write( ber_pvt_sb_get_desc( conn->c_sb ), 1 );
351
352                 ldap_pvt_thread_cond_wait( &conn->c_write_cv, &conn->c_mutex );
353                 conn->c_writewaiter = 0;
354         }
355
356         ldap_pvt_thread_mutex_unlock( &conn->c_mutex );
357         ldap_pvt_thread_mutex_unlock( &conn->c_write_mutex );
358
359         ldap_pvt_thread_mutex_lock( &num_sent_mutex );
360         num_bytes_sent += bytes;
361         num_entries_sent++;
362         ldap_pvt_thread_mutex_unlock( &num_sent_mutex );
363
364         Statslog( LDAP_DEBUG_STATS2, "conn=%ld op=%ld ENTRY dn=\"%s\"\n",
365             (long) conn->c_connid, (long) op->o_opid, e->e_dn, 0, 0 );
366
367         Debug( LDAP_DEBUG_TRACE, "<= send_search_entry\n", 0, 0, 0 );
368
369         rc = 0;
370
371 error_return:;
372         return( rc );
373 }
374
375 int
376 str2result(
377     char        *s,
378     int         *code,
379     char        **matched,
380     char        **info
381 )
382 {
383         int     rc;
384         char    *c;
385
386         *code = LDAP_SUCCESS;
387         *matched = NULL;
388         *info = NULL;
389
390         if ( strncasecmp( s, "RESULT", 6 ) != 0 ) {
391                 Debug( LDAP_DEBUG_ANY, "str2result (%s) expecting \"RESULT\"\n",
392                     s, 0, 0 );
393
394                 return( -1 );
395         }
396
397         rc = 0;
398         while ( (s = strchr( s, '\n' )) != NULL ) {
399                 *s++ = '\0';
400                 if ( *s == '\0' ) {
401                         break;
402                 }
403                 if ( (c = strchr( s, ':' )) != NULL ) {
404                         c++;
405                 }
406
407                 if ( strncasecmp( s, "code", 4 ) == 0 ) {
408                         if ( c != NULL ) {
409                                 *code = atoi( c );
410                         }
411                 } else if ( strncasecmp( s, "matched", 7 ) == 0 ) {
412                         if ( c != NULL ) {
413                                 *matched = c;
414                         }
415                 } else if ( strncasecmp( s, "info", 4 ) == 0 ) {
416                         if ( c != NULL ) {
417                                 *info = c;
418                         }
419                 } else {
420                         Debug( LDAP_DEBUG_ANY, "str2result (%s) unknown\n",
421                             s, 0, 0 );
422                         rc = -1;
423                 }
424         }
425
426         return( rc );
427 }