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