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