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