]> git.sur5r.net Git - openldap/blob - servers/ldapd/request.c
Use -llber set_nonblock implementation.
[openldap] / servers / ldapd / request.c
1 /*
2  * Copyright (c) 1990 Regents of the University of Michigan.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that this notice is preserved and that due credit is given
7  * to the University of Michigan at Ann Arbor. The name of the University
8  * may not be used to endorse or promote products derived from this
9  * software without specific prior written permission. This software
10  * is provided ``as is'' without express or implied warranty.
11  */
12
13 #include "portable.h"
14
15 #include <stdio.h>
16
17 #include <ac/signal.h>
18 #include <ac/socket.h>
19 #include <ac/string.h>
20 #include <ac/syslog.h>
21 #include <ac/time.h>
22 #include <ac/wait.h>
23
24 #include <quipu/commonarg.h>
25 #include <quipu/ds_error.h>
26 #include <quipu/dap2.h>
27 #include <quipu/dua.h>
28
29 #include "lber.h"
30 #include "../../libraries/liblber/lber-int.h"   /* get struct berelement */
31 #include "ldap.h"
32 #include "common.h"
33
34 #ifdef PEPSY_DUMP
35 #ifndef DEBUG
36 #define DEBUG
37 #endif
38 #include "LDAP-types.h"
39 #if ISODEPACKAGE == IC
40 #include <compat/logger.h>
41 #else
42 #include <logger.h>
43 #endif
44 #endif
45
46 /*
47  * client_request - called by do_queries() when there is activity on the
48  * client socket.  It expects to be able to get an LDAP message from the
49  * client socket, parses the first couple of fields, and then calls
50  * do_request() to handle the request.  If do_request() (or something
51  * called by it) returns a response to the client (e.g., in the case of
52  * an error), then client_request() is done.  If the request is not
53  * responded to (and needs a response), it is added to the queue of
54  * outstanding requests.  It will be responded to later via dsa_response(),
55  * once the DSA operation completes.
56  */
57
58 void
59 client_request(
60     Sockbuf     *clientsb,
61     struct conn *dsaconn,
62     int         udp
63 )
64 {
65         unsigned long   tag;
66         unsigned long   len;
67         long            msgid;
68         BerElement      ber, *copyofber;
69         struct msg      *m;
70         static int      bound;
71 #ifdef LDAP_CONNECTIONLESS
72         struct sockaddr_in *sai;
73 #endif   
74         Debug( LDAP_DEBUG_TRACE, "client_request%s\n",
75             udp ? " udp" : "", 0, 0 );
76
77         /*
78          * Get the ldap message, which is a sequence of message id
79
80          * and then the actual request choice.
81          */
82
83         ber_init_w_nullc( &ber, 0 );
84         if ( (tag = ber_get_next( clientsb, &len, &ber )) == LBER_DEFAULT ) {
85                 Debug( LDAP_DEBUG_ANY, "ber_get_next failed\n", 0, 0, 0 );
86                 log_and_exit( 1 );
87         }
88
89 #ifdef LDAP_CONNECTIONLESS
90         if ( udp && dosyslog ) {
91                 sai = (struct sockaddr_in *)ber_pvt_sb_udp_get_src( &clientsb );
92                 syslog( LOG_INFO, "UDP request from unknown (%s)",
93                         inet_ntoa( sai->sin_addr ) );
94         }
95 #endif
96
97 #ifdef LDAP_DEBUG
98         if ( ldap_debug & LDAP_DEBUG_BER )
99                 trace_ber( tag, len, ber.ber_buf, stderr, 1, 1 );
100 #endif
101
102 #ifdef LDAP_COMPAT
103         /*
104          * This tag should be a normal SEQUENCE tag.  In release 2.0 this
105          * tag is 0x10.  In the new stuff this is 0x30.  To distinguish
106          * between 3.0 and the "correct" stuff, we look for an extra
107          * sequence tag after the bind tag.
108          */
109
110         Debug( LDAP_DEBUG_ANY, "bound %d\n", bound, 0, 0 );
111         if ( bound == 0 ) {
112                 /* check for 2.0 */
113                 if ( tag == OLD_LDAP_TAG_MESSAGE ) {
114                         Debug( LDAP_DEBUG_ANY, "version 2.0 detected\n", 0,
115                             0, 0 );
116                         if ( dosyslog ) {
117                                 syslog( LOG_INFO, "old version 2.0 detected" );
118                         }
119                         ldap_compat = 20;
120                 /* check for 3.0 */
121                 } else {
122                         BerElement      tber;
123                         unsigned long   tlen;
124                         unsigned long   ttag;
125
126                         tber = ber;     /* struct copy */
127                         /* msgid */
128                         ttag = ber_skip_tag( &tber, &tlen );
129                         tber.ber_ptr += tlen;
130                         /* bind sequence header */
131                         ttag = ber_skip_tag( &tber, &tlen );
132                         ttag = ber_peek_tag( &tber, &tlen );
133
134                         Debug( LDAP_DEBUG_ANY, "checking for 3.0 tag 0x%lx\n",
135                                ttag, 0, 0 );
136                         if ( ttag == LBER_SEQUENCE ) {
137                                 Debug( LDAP_DEBUG_ANY, "version 3.0 detected\n",
138                                     0, 0, 0 );
139                                 if ( dosyslog ) {
140                                         syslog( LOG_INFO,
141                                             "old version 3.0 detected" );
142                                 }
143                                 ldap_compat = 30;
144                         }
145                 }
146         }
147 #endif
148
149         if ( ber_get_int( &ber, &msgid ) != LDAP_TAG_MSGID ) {
150                 send_ldap_result( clientsb, LBER_DEFAULT, msgid,
151                     LDAP_PROTOCOL_ERROR, NULL, "Not an LDAP message" );
152                 free( ber.ber_buf );
153                 return;
154         }
155
156 #ifdef LDAP_CONNECTIONLESS
157         if ( udp ) {
158                 char    *logdn = NULL;
159
160                 ber_get_stringa( &ber, &logdn );
161                 if ( logdn != NULL ) {
162                     if ( dosyslog ) {
163                             syslog( LOG_INFO, "UDP requestor: %s", logdn );
164                     }
165                     Debug( LDAP_DEBUG_ANY, "UDP requestor: %s\n", logdn, 0, 0 );
166                     free( logdn );
167                 }
168         }
169 #endif /* LDAP_CONNECTIONLESS */
170
171 #ifdef LDAP_COMPAT30
172         if ( ldap_compat == 30 )
173                 tag = ber_skip_tag( &ber, &len );
174         else
175 #endif
176                 tag = ber_peek_tag( &ber, &len );
177         if ( !udp && bound == 0 && tag != LDAP_REQ_BIND
178 #ifdef LDAP_COMPAT20
179             && tag != OLD_LDAP_REQ_BIND
180 #endif
181             ) {
182                 send_ldap_result( clientsb, tag, msgid, LDAP_OPERATIONS_ERROR,
183                     NULL, "Bind operation must come first" );
184                 free( ber.ber_buf );
185                 return;
186         }
187
188 #ifdef LDAP_CONNECTIONLESS
189         if (udp && tag != LDAP_REQ_SEARCH && tag != LDAP_REQ_ABANDON ) {
190                 send_ldap_result( clientsb, tag, msgid, LDAP_OPERATIONS_ERROR,
191                     NULL, "Only search is supported over UDP/CLDAP" );
192                 free( ber.ber_buf );
193                 return;
194         }
195         sai = (struct sockaddr_in *) ber_pvt_sb_udp_get_src( &clientsb );
196    
197         if ( get_cldap_msg( msgid, tag,
198             (struct sockaddr *)sai ) != NULL ) {
199                 /*
200                  * duplicate request: toss this one
201                  */
202                 Debug( LDAP_DEBUG_TRACE,
203                     "client_request tossing dup request id %ld from %s\n",
204                     msgid, inet_ntoa( sai->sin_addr ), 0 );
205            
206                 free( ber.ber_buf );
207                 return;
208         }
209 #endif
210
211         copyofber = ber_dup( &ber );
212
213         m = add_msg( msgid, tag, copyofber, dsaconn, udp,
214 #ifdef LDAP_CONNECTIONLESS
215                 (struct sockaddr *)sai );
216 #else
217                 NULL );
218 #endif
219
220         /* 
221          * Call the appropriate routine to handle the request.  If it
222          * returns a nonzero result, the message requires a response, and
223          * so it's left in the queue of outstanding requests, otherwise
224          * it's deleted.
225          */
226
227         if ( do_request( clientsb, m, &ber, &bound ) == 0 ) {
228                 del_msg( m );
229         }
230
231         return;
232 }
233
234 /*
235  * do_request - called when a client makes a request, or when a referral
236  * error is returned.  In the latter case, a connection is made to the
237  * referred to DSA, and do_request() is called to retry the operation over
238  * that connection.  In the former case, do_request() is called to try
239  * the operation over the default association.
240  */
241
242 int
243 do_request(
244     Sockbuf     *clientsb,
245     struct msg  *m,
246     BerElement  *ber,
247     int         *bound
248 )
249 {
250         int             resp_required = 0;
251
252         Debug( LDAP_DEBUG_TRACE, "do_request\n", 0, 0, 0 );
253
254         switch ( m->m_msgtype ) {
255 #ifdef LDAP_COMPAT20
256         case OLD_LDAP_REQ_BIND:
257 #endif
258         case LDAP_REQ_BIND:
259                 resp_required = do_bind( clientsb, m, ber, bound );
260                 break;
261
262 #ifdef LDAP_COMPAT20
263         case OLD_LDAP_REQ_UNBIND:
264 #endif
265 #ifdef LDAP_COMPAT30
266         case LDAP_REQ_UNBIND_30:
267 #endif
268         case LDAP_REQ_UNBIND:
269                 conn_close();
270                 log_and_exit( 0 );
271                 break;
272
273 #ifdef LDAP_COMPAT20
274         case OLD_LDAP_REQ_ADD:
275 #endif
276         case LDAP_REQ_ADD:
277                 resp_required = do_add( clientsb, m, ber );
278                 break;
279
280 #ifdef LDAP_COMPAT20
281         case OLD_LDAP_REQ_DELETE:
282 #endif
283 #ifdef LDAP_COMPAT30
284         case LDAP_REQ_DELETE_30:
285 #endif
286         case LDAP_REQ_DELETE:
287                 resp_required = do_delete( clientsb, m, ber );
288                 break;
289
290 #ifdef LDAP_COMPAT20
291         case OLD_LDAP_REQ_MODRDN:
292 #endif
293         case LDAP_REQ_MODRDN:
294                 resp_required = do_modrdn( clientsb, m, ber );
295                 break;
296
297 #ifdef LDAP_COMPAT20
298         case OLD_LDAP_REQ_MODIFY:
299 #endif
300         case LDAP_REQ_MODIFY:
301                 resp_required = do_modify( clientsb, m, ber );
302                 break;
303
304 #ifdef LDAP_COMPAT20
305         case OLD_LDAP_REQ_COMPARE:
306 #endif
307         case LDAP_REQ_COMPARE:
308                 resp_required = do_compare( clientsb, m, ber );
309                 break;
310
311 #ifdef LDAP_COMPAT20
312         case OLD_LDAP_REQ_SEARCH:
313 #endif
314         case LDAP_REQ_SEARCH:
315                 resp_required = do_search( clientsb, m, ber );
316                 break;
317
318 #ifdef LDAP_COMPAT20
319         case OLD_LDAP_REQ_ABANDON:
320 #endif
321 #ifdef LDAP_COMPAT30
322         case LDAP_REQ_ABANDON_30:
323 #endif
324         case LDAP_REQ_ABANDON:
325                 resp_required = do_abandon( m->m_conn, ber, m->m_uniqid );
326                 break;
327
328         default:
329                 Debug( LDAP_DEBUG_ANY, "unknown operation %d\n", m->m_msgtype,
330                     0, 0 );
331
332                 send_ldap_msgresult( clientsb, m->m_msgtype, m,
333                     LDAP_PROTOCOL_ERROR, NULL, "Unknown request type" );
334                 break;
335         }
336
337         return( resp_required );
338 }
339
340 /* 
341  * initiate_dap_operation - initiate a dap operation, rebinding and retrying
342  * the request if necessary.  If the request is successfully initiated, 0 is
343  * returned.  Otherwise, an indication of the error is returned.
344  */
345
346 int
347 initiate_dap_operation(
348     int         op,
349     struct msg  *m,
350     void        *arg
351 )
352 {
353         char                    *matched;
354         int                     i, rc, bound = 0;
355         struct DAPindication    di;
356
357         Debug( LDAP_DEBUG_TRACE, "initiate_dap_operation\n", 0, 0, 0 );
358
359         if ( m->m_conn->c_ad == -1 && do_bind_real( m->m_conn, &bound,
360             &matched ) != LDAP_SUCCESS )
361                 return( LDAP_UNAVAILABLE );
362
363         for ( i = 0; i < 2; i++ ) {
364                 switch ( op ) {
365                 case OP_COMPARE:
366                         rc = DapCompare( m->m_conn->c_ad, m->m_uniqid,
367                             (struct ds_compare_arg *) arg, &di, ROS_ASYNC );
368                         break;
369
370                 case OP_SEARCH:
371                         rc = DapSearch( m->m_conn->c_ad, m->m_uniqid,
372                             (struct ds_search_arg *) arg, &di, ROS_ASYNC );
373                         break;
374
375                 case OP_ADDENTRY:
376                         rc = DapAddEntry( m->m_conn->c_ad, m->m_uniqid,
377                             (struct ds_addentry_arg *) arg, &di, ROS_ASYNC );
378                         break;
379
380                 case OP_REMOVEENTRY:
381                         rc = DapRemoveEntry( m->m_conn->c_ad, m->m_uniqid,
382                             (struct ds_removeentry_arg *) arg, &di, ROS_ASYNC );
383                         break;
384
385                 case OP_MODIFYENTRY:
386                         rc = DapModifyEntry( m->m_conn->c_ad, m->m_uniqid,
387                             (struct ds_modifyentry_arg *) arg, &di, ROS_ASYNC );
388                         break;
389
390                 case OP_READ:
391                         rc = DapRead( m->m_conn->c_ad, m->m_uniqid,
392                             (struct ds_read_arg *) arg, &di, ROS_ASYNC );
393                         break;
394
395                 case OP_MODIFYRDN:
396                         rc = DapModifyRDN( m->m_conn->c_ad, m->m_uniqid,
397                             (struct ds_modifyrdn_arg *) arg, &di, ROS_ASYNC );
398                         break;
399
400                 default:
401                         break;
402                 }
403
404                 Debug( LDAP_DEBUG_TRACE, "operation initiated %d\n", rc, 0,
405                     0 );
406
407                 if ( rc == OK )
408                         return( 0 );
409
410                 /* 
411                  * the operation was not invoked - try rebinding, then 
412                  * try it again.
413                  */
414
415                 (void) dap_unbind( m->m_conn->c_ad );
416
417                 if ( do_bind_real( m->m_conn, &bound, &matched )
418                     != LDAP_SUCCESS )
419                         break;
420         }
421
422         m->m_conn->c_ad = -1;
423
424         return( LDAP_UNAVAILABLE );     /* DSA was unreachable */
425 }
426
427 #ifdef LDAP_DEBUG
428 int
429 trace_ber(
430     int   tag,
431     int   len,
432     char  *ber,
433     FILE  *trace_file,
434     int   prepend,
435     int   read_pdu      /* If non-zero, PDU was read from client.  0 == PDU is being written */
436 )
437 {
438         unsigned char   *buf;
439         PS              input_ps  = NULLPS;
440         PE              pe;
441         int             result = -1;
442
443         Debug( LDAP_DEBUG_TRACE, "trace_ber(tag=%#x, ber=%#lx, len=%d)\n", tag,
444             (unsigned long) ber, len );
445
446         if ( (buf = (unsigned char *) malloc( len + 6 )) == NULL ) {
447                 fprintf( trace_file, "Unable to allocate memory\n" );
448         } else {
449                 if ( prepend ) {
450                         buf[0] = tag;
451                         buf[1] = 0x84;
452                         buf[2] = len >> 24;
453                         buf[3] = len >> 16;
454                         buf[4] = len >> 8;
455                         buf[5] = len;
456                         SAFEMEMCPY( buf + 6, ber, len );
457                 } else {
458                         SAFEMEMCPY( buf, ber, len );
459                 }
460                 if ( (input_ps = ps_alloc( str_open )) == NULLPS )
461                         fprintf( trace_file, "ps_alloc failed\n" );
462                 else if ( str_setup( input_ps, (char *)buf, len + 6, 1 ) != OK )
463                         fprintf( trace_file, "str_setup\n" );
464                 else if ( (pe = ps2pe( input_ps )) == NULLPE ) {
465                         fprintf(trace_file, "ps2pe: %s\n",
466                             ps_error( input_ps->ps_errno ) );
467                         ber_bprint( (char *) buf, len + 6 );
468                 } else {
469 #ifdef PEPSY_DUMP
470                         int                             failed = 0;
471                         static LLog                     log = {
472                                 "-", NULLCP, NULLCP, LLOG_PDUS,
473                                 LLOG_NONE, -1, 0, NOTOK
474                         };
475                         struct type_LDAP_LDAPMessage    *ldap_msg = NULL;
476
477                         if ( decode_LDAP_LDAPMessage(pe, 1, 0, NULL, &ldap_msg)
478                             == -1 ) {
479                                 failed = 1;
480                                 fprintf( trace_file,
481                                     "Error decoding LDAPMessage:\n  [%s]\n",
482                                     PY_pepy );
483                                 fprintf( trace_file, "Here is the PDU:\n" );
484                                 vsetfp( trace_file, NULL );
485                                 vunknown( pe );
486                         }
487                         if (log.ll_events & LLOG_PDUS) {
488                                 pvpdu (&log, print_LDAP_LDAPMessage_P, pe,
489                                     failed ?
490                                     "<Bad LDAPMessage>" : "<LDAPMessage>",
491                                     read_pdu);
492                         }
493 /*
494                         PLOGP(&log, LDAP_LDAPMessage, pe, failed ? "<Bad LDAPMessage>" : "<LDAPMessage>", read_pdu);
495 */
496                         if (ldap_msg)
497                                 free_LDAP_LDAPMessage(ldap_msg);
498 #else
499                         vsetfp( trace_file, NULL );
500                         vunknown( pe );
501 #endif
502                         pe_free( pe );
503                         result = 0;
504                 }
505                 free( buf );
506         }
507
508       if ( input_ps )
509               ps_free( input_ps );
510
511       return( result );
512 }
513 #endif