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