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