]> git.sur5r.net Git - openldap/blob - servers/ldapd/main.c
Removed use of paths not defined in ldapconfig.h.edit.
[openldap] / servers / ldapd / main.c
1 /*
2  * Copyright (c) 1990-1996 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  * Some code fragments to run from inetd stolen from the University
14  * of Minnesota gopher distribution, which had this copyright on it:
15  *
16  * Part of the Internet Gopher program, copyright (C) 1991
17  * University of Minnesota Microcomputer Workstation and Networks Center
18  */
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <sys/types.h>
23 #include <sys/time.h>
24 #include <sys/socket.h>
25 #include <netinet/in.h>
26 #include <arpa/inet.h>
27 #include <netdb.h>
28 #include <sys/wait.h>
29 #include <signal.h>
30 #ifdef _AIX
31 #include <sys/select.h>
32 #endif
33 #include <syslog.h>
34 #include <quipu/commonarg.h>
35 #include <quipu/ds_error.h>
36 #include "portable.h"
37 #include "lber.h"
38 #include "ldap.h"
39 #include "common.h"
40
41 #ifdef USE_SYSCONF
42 #include <unistd.h>
43 #endif /* USE_SYSCONF */
44
45 #ifdef TCP_WRAPPERS
46 #include <tcpd.h>
47
48 int allow_severity = LOG_INFO;
49 int deny_severity = LOG_NOTICE;
50 #endif /* TCP_WRAPPERS */
51
52 void log_and_exit();
53 static set_socket();
54 static do_queries();
55 static SIG_FN wait4child();
56 #ifdef CLDAP
57 static udp_init();
58 #endif
59
60 #ifdef LDAP_DEBUG
61 int     ldap_debug;
62 #endif
63 int     version;
64 #ifdef COMPAT
65 int     ldap_compat;
66 #endif
67 int     dosyslog;
68 int     do_tcp = 1;
69 #ifdef CLDAP
70 int     do_udp = 0;
71 #endif
72 int     idletime = DEFAULT_TIMEOUT;
73 int     referral_connection_timeout = DEFAULT_REFERRAL_TIMEOUT;
74 struct timeval  conn_start_tv;
75 #ifdef KERBEROS
76 char    *krb_ldap_service = "ldapserver";
77 char    *krb_x500_service = "x500dsa";
78 char    *krb_x500_instance;
79 char    *krb_x500_nonce;
80 char    *kerberos_keyfile;
81 #endif
82
83 int     dtblsize;
84 int     RunFromInetd = 0;
85
86 extern char Versionstr[];
87
88 static usage( name )
89 char    *name;
90 {
91         fprintf( stderr, "usage: %s [-d debuglvl] [-p port] [-l] [-c dsa] [-r referraltimeout]", name );
92 #ifdef CLDAP
93         fprintf( stderr, " [ -U | -t timeout ]" );
94 #else
95         fprintf( stderr, " [ -t timeout ]" );
96 #endif
97         fprintf( stderr, " [-I]" );
98 #ifdef KERBEROS
99         fprintf( stderr, " [-i dsainstance]" );
100 #endif
101         fprintf( stderr, "\n" );
102 }
103
104 main (argc, argv)
105 int     argc;
106 char    **argv;
107 {
108         int                     tcps, ns;
109 #ifdef CLDAP
110         int                     udps;
111 #endif
112         int                     myport = LDAP_PORT;
113         int                     i, pid, socktype;
114         char                    *myname;
115         fd_set                  readfds;
116         struct hostent          *hp;
117         struct sockaddr_in      from;
118         int                     len;
119         int                     dsapargc;
120         char                    **dsapargv;
121         SIG_FN                  wait4child();
122 #ifndef NOSETPROCTITLE
123         char                    title[80];
124         extern char             **Argv;
125         extern int              Argc;
126 #endif
127         extern char             *optarg;
128         extern int              optind;
129
130 #ifdef VMS
131         /* Pick up socket from inetd-type server on VMS */
132         if ( (ns = socket_from_server( NULL )) > 0 )
133                 RunFromInetd = 1;
134 #else
135         /* Socket from inetd is usually 0 */
136         ns = 0;
137 #endif
138
139         /* for dsap_init */
140         if ( (dsapargv = (char **) malloc( 4 * sizeof(char *) )) == NULL ) {
141                 perror( "malloc" );
142                 exit( 1 );
143         }
144         dsapargv[0] = argv[0];
145         dsapargv[1] = 0;
146         dsapargv[2] = 0;
147         dsapargv[3] = 0;
148         dsapargc = 1;
149 #ifdef KERBEROS
150         kerberos_keyfile = "";
151 #endif
152
153         /* process command line arguments */
154         while ( (i = getopt( argc, argv, "d:lp:f:i:c:r:t:IuU" )) != EOF ) {
155                 switch ( i ) {
156                 case 'c':       /* specify dsa to contact */
157                         dsapargv[1] = "-call";
158                         dsapargv[2] = strdup( optarg );
159                         dsapargc = 3;
160                         break;
161
162                 case 'd':       /* turn on debugging */
163 #ifdef LDAP_DEBUG
164                         ldap_debug = atoi( optarg );
165                         if ( ldap_debug & LDAP_DEBUG_PACKETS )
166                                 lber_debug = ldap_debug;
167 #else
168                         fprintf( stderr, "Not compiled with -DLDAP_DEBUG!\n" );
169 #endif
170                         break;
171
172                 case 'l':       /* do syslogging */
173                         dosyslog = 1;
174                         break;
175
176                 case 'p':       /* specify port number */
177                         myport = atoi( optarg );
178                         break;
179
180                 case 'r':       /* timeout for referral connections */
181                         referral_connection_timeout = atoi( optarg );
182                         break;
183
184                 case 't':       /* timeout for idle connections */
185                         idletime = atoi( optarg );
186                         break;
187
188 #ifdef KERBEROS
189                 case 'f':       /* kerberos key file */
190                         kerberos_keyfile = strdup( optarg );
191                         break;
192
193                 case 'i':       /* x500 dsa kerberos instance */
194                         if ( krb_x500_instance != NULL )
195                                 free( krb_x500_instance );
196                         krb_x500_instance = strdup( optarg );
197                         break;
198 #endif
199
200                 case 'I':       /* Run from inetd */
201                         RunFromInetd = 1;
202                         break;
203
204 #ifdef CLDAP
205                 case 'U':       /* UDP only (no TCP) */
206                         do_tcp = 0;
207                         do_udp = 1;
208                         break;
209
210 #ifdef NOTYET
211                 case 'u':       /* allow UDP requests (CLDAP) */
212                         do_udp = 1;
213                         break;
214 #endif /* NOTYET */
215
216 #endif /* CLDAP */
217
218                 default:
219                         usage( argv[0] );
220                         exit( 1 );
221                 }
222         }
223
224         if ( optind < argc ) {
225                 usage( argv[ 0 ] );
226                 exit( 1 );
227         }
228
229 #ifdef CLDAP
230         if ( do_udp && !do_tcp && idletime != DEFAULT_TIMEOUT ) {
231                 usage( argv[ 0 ] );
232                 exit( 1 );
233         }
234 #endif
235
236         Debug( LDAP_DEBUG_TRACE, "%s", Versionstr, 0, 0 );
237
238 #ifdef USE_SYSCONF
239         dtblsize = sysconf( _SC_OPEN_MAX );
240 #else /* USE_SYSCONF */
241         dtblsize = getdtablesize();
242 #endif /* USE_SYSCONF */
243
244 #ifdef FD_SETSIZE
245         if( dtblsize > FD_SETSIZE ) {
246                 dtblsize = FD_SETSIZE;
247         }
248 #endif /* FD_SETSIZE */
249
250 #ifndef NOSETPROCTITLE
251         /* for setproctitle */
252         Argv = argv;
253         Argc = argc;
254 #endif
255
256         if ( (myname = strrchr( argv[0], '/' )) == NULL )
257                 myname = strdup( argv[0] );
258         else
259                 myname = strdup( myname + 1 );
260
261         /* 
262          * detach from the terminal if stderr is redirected or no
263          * debugging is wanted, and then arrange to reap children
264          * that have exited
265          */
266         if (!RunFromInetd) {
267 #ifndef NOSETPROCTITLE
268                 setproctitle( "initializing" );
269 #endif
270 #ifndef VMS
271                 (void) detach();
272 #endif
273                 (void) SIGNAL( SIGCHLD, (void *) wait4child );
274                 (void) SIGNAL( SIGINT, (void *) log_and_exit );
275         }
276
277         /* 
278          * set up syslogging (if desired)
279          */
280         if ( dosyslog ) {
281 #ifdef LOG_LOCAL4
282                 openlog( myname, OPENLOG_OPTIONS, LOG_LOCAL4 );
283 #else
284                 openlog( myname, OPENLOG_OPTIONS );
285 #endif
286         }
287
288         /* 
289          * load the syntax handlers, oidtables, and initialize some stuff,
290          * then start listening
291          */
292
293         (void) quipu_syntaxes();
294 #ifdef LDAP_USE_PP
295         (void) pp_quipu_init( argv[0] );
296 #endif
297 #if ISODEPACKAGE == IC
298 #if ICRELEASE > 2
299         dsa_operation_syntaxes();
300 #endif
301 #endif
302         (void) dsap_init( &dsapargc, &dsapargv );
303         (void) get_syntaxes();
304         if (RunFromInetd) {
305                 len = sizeof( socktype );
306                 getsockopt( ns, SOL_SOCKET, SO_TYPE, &socktype, &len );
307                 if ( socktype == SOCK_DGRAM ) {
308 #ifdef CLDAP
309                         Debug( LDAP_DEBUG_ARGS,
310                             "CLDAP request from unknown (%s)\n",
311                             inet_ntoa( from.sin_addr ), 0, 0 );
312                         conn_start_tv.tv_sec = 0;
313                         udp_init( 0, 0 );
314                         do_queries( ns, 1 );
315 #else /* CLDAP */
316                         Debug( LDAP_DEBUG_ARGS,
317                             "Compile with -DCLDAP for UDP support\n",0,0,0 );
318 #endif /* CLDAP */
319                         exit( 0 );
320                 }
321
322                 len = sizeof(from);
323                 if ( getpeername( ns, (struct sockaddr *) &from, &len )
324                     == 0 ) {
325                         hp = gethostbyaddr( (char *) &(from.sin_addr.s_addr),
326                         sizeof(from.sin_addr.s_addr), AF_INET );
327                         Debug( LDAP_DEBUG_ARGS, "connection from %s (%s)\n",
328                             (hp == NULL) ? "unknown" : hp->h_name,
329                             inet_ntoa( from.sin_addr ), 0 );
330
331                         if ( dosyslog ) {
332                                 syslog( LOG_INFO, "connection from %s (%s)",
333                                     (hp == NULL) ? "unknown" : hp->h_name,
334                                     inet_ntoa( from.sin_addr ) );
335                         }
336
337 #ifndef NOSETPROCTITLE
338                         sprintf( title, "%s %d\n", hp == NULL ?
339                             inet_ntoa( from.sin_addr ) : hp->h_name, myport );
340                         setproctitle( title );
341 #endif
342                 }
343                 gettimeofday( &conn_start_tv, (struct timezone *) NULL );
344                 do_queries( ns, 0 );
345
346                 exit( 0 );
347         }
348
349         if ( do_tcp )
350             tcps = set_socket( myport, 0 );
351
352 #ifdef CLDAP
353         if ( do_udp )
354                 udps = udp_init( myport, 1 );
355 #endif
356
357         /*
358          * loop, wait for a connection, then fork off a child to handle it
359          * if we are doing CLDAP as well, handle those requests on the fly
360          */
361
362 #ifndef NOSETPROCTITLE
363 #ifdef CLDAP
364         sprintf( title, "listening %s/%s %d", do_tcp ? "tcp" : "",
365             do_udp ? "udp" : "", myport );
366 #else
367         sprintf( title, "listening %s %d", do_tcp ? "tcp" : "", myport );
368 #endif
369         setproctitle( title );
370 #endif
371
372         for ( ;; ) {
373                 FD_ZERO( &readfds );
374                 if ( do_tcp )
375                         FD_SET( tcps, &readfds );
376 #ifdef CLDAP
377                 if ( do_udp )
378                         FD_SET( udps, &readfds );
379 #endif
380
381                 if ( select( dtblsize, &readfds, 0, 0, 0 ) < 1 ) {
382 #ifdef LDAP_DEBUG
383                         if ( ldap_debug ) perror( "main select" );
384 #endif
385                         continue;
386                 }
387
388 #ifdef CLDAP
389                 if ( do_udp && FD_ISSET( udps, &readfds ) ) {
390                         do_queries( udps, 1 );
391                 }
392 #endif
393
394                 if ( !do_tcp || ! FD_ISSET( tcps, &readfds ) ) {
395                         continue;
396                 }
397
398                 len = sizeof(from);
399                 if ( (ns = accept( tcps, (struct sockaddr *) &from, &len ))
400                     == -1 ) {
401 #ifdef LDAP_DEBUG
402                         if ( ldap_debug ) perror( "accept" );
403 #endif
404                         continue;
405                 }
406
407                 hp = gethostbyaddr( (char *) &(from.sin_addr.s_addr),
408                     sizeof(from.sin_addr.s_addr), AF_INET );
409
410 #ifdef TCP_WRAPPERS
411                 if ( !hosts_ctl("ldapd", (hp == NULL) ? "unknown" : hp->h_name,
412                         inet_ntoa( from.sin_addr ), STRING_UNKNOWN ) {
413
414                         Debug( LDAP_DEBUG_ARGS, "connection from %s (%s) denied.\n",
415                                 (hp == NULL) ? "unknown" : hp->h_name,
416                                 inet_ntoa( from.sin_addr ), 0 );
417
418                         if ( dosyslog ) {
419                                 syslog( LOG_NOTICE, "connection from %s (%s) denied.",
420                                     (hp == NULL) ? "unknown" : hp->h_name,
421                                     inet_ntoa( from.sin_addr ) );
422                         }
423
424                         close(ns);
425                         continue;
426                 }
427 #endif /* TCP_WRAPPERS */
428
429                 Debug( LDAP_DEBUG_ARGS, "connection from %s (%s)\n",
430                     (hp == NULL) ? "unknown" : hp->h_name,
431                     inet_ntoa( from.sin_addr ), 0 );
432
433
434                 if ( dosyslog ) {
435                         syslog( LOG_INFO, "connection from %s (%s)",
436                             (hp == NULL) ? "unknown" : hp->h_name,
437                             inet_ntoa( from.sin_addr ) );
438                 }
439
440 #ifdef VMS
441                 /* This is for debug on terminal on VMS */
442                 close( tcps );
443 #ifndef NOSETPROCTITLE
444                 setproctitle( hp == NULL ? inet_ntoa( from.sin_addr ) :
445                     hp->h_name );
446 #endif
447                 gettimeofday( &conn_start_tv, (struct timezone *) NULL );
448                 (void) SIGNAL( SIGPIPE, (void *) log_and_exit );
449
450                 do_queries( ns, 0 );
451                 /* NOT REACHED */
452 #endif
453
454                 switch( pid = fork() ) {
455                 case 0:         /* child */
456                         close( tcps );
457 #ifndef NOSETPROCTITLE
458                         sprintf( title, "%s (%d)\n", hp == NULL ?
459                                 inet_ntoa( from.sin_addr ) : hp->h_name,
460                                 myport );
461                         setproctitle( title );
462 #endif
463                         gettimeofday( &conn_start_tv, (struct timezone *) NULL );
464                         (void) SIGNAL( SIGPIPE, (void *) log_and_exit );
465
466                         do_queries( ns, 0 );
467                         break;
468
469                 case -1:        /* failed */
470 #ifdef LDAP_DEBUG
471                         if ( ldap_debug ) perror( "fork" );
472 #endif
473                         close( ns );
474                         syslog( LOG_ERR, "fork failed %m" );
475                         /* let things cool off */
476                         sleep( 15 );
477                         break;
478
479                 default:        /* parent */
480                         close( ns );
481                         Debug( LDAP_DEBUG_TRACE, "forked child %d\n", pid, 0,
482                             0 );
483                         break;
484                 }
485         }
486         /* NOT REACHED */
487 }
488
489 static
490 do_queries(
491     int clientsock,
492     int udp             /* is this a UDP (CLDAP) request? */
493 )
494 {
495         fd_set          readfds;
496         int             rc, i;
497         struct timeval  timeout;
498         Sockbuf         sb;
499 #ifdef CLDAP
500         struct sockaddr saddr, faddr;
501         struct sockaddr *saddrlist[ 1 ];
502 #endif /* CLDAP */
503
504         Debug( LDAP_DEBUG_TRACE, "do_queries%s\n",
505             udp ? " udp" : "", 0, 0 );
506
507         /*
508          * Loop, wait for a request from the client or a response from
509          * a dsa, then handle it.  Dsap_ad is always a connection to the
510          * "default" dsa.  Other connections can be made as a result of
511          * a referral being chased down.  These association descriptors
512          * are kept track of with the message that caused the referral.
513          * The set_dsa_fds() routine traverses the list of outstanding
514          * messages, setting the appropriate bits in readfds.
515          */
516
517         if ( !udp ) {
518                 conn_init();
519         }
520
521         (void) memset( (void *) &sb, '\0', sizeof( sb ) );
522         sb.sb_sd = clientsock;
523         sb.sb_naddr = ( udp ) ? 1 : 0;
524 #ifdef CLDAP
525         sb.sb_addrs = (void **)saddrlist;
526         sb.sb_fromaddr = &faddr;
527         sb.sb_useaddr = saddrlist[ 0 ] = &saddr;
528 #endif
529         sb.sb_ber.ber_buf = NULL;
530         sb.sb_ber.ber_ptr = NULL;
531         sb.sb_ber.ber_end = NULL;
532
533         timeout.tv_sec = idletime;
534         timeout.tv_usec = 0;
535         for ( ;; ) {
536                 struct conn             *dsaconn;
537                 extern struct conn      *conns;
538
539                 FD_ZERO( &readfds );
540                 FD_SET( clientsock, &readfds );
541                 conn_setfds( &readfds );
542
543 #ifdef LDAP_DEBUG
544                 if ( ldap_debug & LDAP_DEBUG_CONNS ) {
545                         Debug( LDAP_DEBUG_CONNS, "FDLIST:", 0, 0, 0 );
546                         for ( i = 0; i < dtblsize; i++ ) {
547                                 if ( FD_ISSET( i, &readfds ) ) {
548                                         Debug( LDAP_DEBUG_CONNS, " %d", i, 0,
549                                             0);
550                                 }
551                         }
552                         Debug( LDAP_DEBUG_CONNS, "\n", 0, 0, 0 );
553                 }
554 #endif
555
556                 /* 
557                  * hack - because of lber buffering, there might be stuff
558                  * already waiting for us on the client sock.
559                  */
560
561                 if ( sb.sb_ber.ber_ptr >= sb.sb_ber.ber_end ) {
562                         if ( (rc = select( dtblsize, &readfds, 0, 0,
563                             udp ? 0 : &timeout )) < 1 ) {
564 #ifdef LDAP_DEBUG
565                                 if ( ldap_debug ) perror( "do_queries select" );
566 #endif
567                                 if ( rc == 0 )
568                                         log_and_exit( 0 ); /* idle timeout */
569
570                                 Debug( LDAP_DEBUG_ANY, "select returns %d!\n",
571                                     rc, 0, 0 );
572
573                                 /* client gone away - we can too */
574                                 if ( isclosed( clientsock ) )
575                                         log_and_exit( 0 );
576
577                                 /*
578                                  * check if a dsa conn has gone away -
579                                  * mark it bad if so
580                                  */
581                                 conn_badfds();
582
583                                 continue;
584                         }
585                 }
586
587                 if ( sb.sb_ber.ber_ptr < sb.sb_ber.ber_end ||
588                     FD_ISSET( clientsock, &readfds ) ) {
589                         client_request( &sb, conns, udp );
590                 } else {
591                         if ( (dsaconn = conn_getfd( &readfds )) == NULL ) {
592                                 Debug( LDAP_DEBUG_ANY, "No DSA activity!\n",
593                                     0, 0, 0 );
594                                 continue;
595                         }
596
597                         dsa_response( dsaconn, &sb );
598                 }
599         }
600         /* NOT REACHED */
601 }
602
603 static set_socket(
604     int port,
605     int udp     /* UDP port? */
606 )
607 {
608         int                     s, i;
609         struct sockaddr_in      addr;
610
611         if ( (s = socket( AF_INET, udp ? SOCK_DGRAM:SOCK_STREAM, 0 )) == -1 ) {
612                 perror( "socket" );
613                 exit( 1 );
614         }
615
616         /* set option so clients can't keep us from coming back up */
617         i = 1;
618         if ( setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (void *) &i, sizeof(i) )
619             < 0 ) {
620                 perror( "setsockopt" );
621                 exit( 1 );
622         }
623
624         /* bind to a name */
625         (void)memset( (void *)&addr, '\0', sizeof( addr ));
626         addr.sin_family = AF_INET;
627         addr.sin_addr.s_addr = INADDR_ANY;
628         addr.sin_port = htons( port );
629         if ( bind( s, (struct sockaddr *) &addr, sizeof(addr) ) ) {
630                 perror( "bind" );
631                 exit( 1 );
632         }
633
634         if ( !udp ) {
635                 /* listen for connections */
636                 if ( listen( s, 5 ) == -1 ) {
637                         perror( "listen" );
638                         exit( 1 );
639                 }
640         }
641  
642         Debug( LDAP_DEBUG_TRACE, "listening on %s port %d\n",
643                 udp ? "udp" : "tcp", port, 0 );
644
645         return( s );
646 }
647
648 static SIG_FN wait4child()
649 {
650         WAITSTATUSTYPE     status;
651
652         Debug( LDAP_DEBUG_TRACE, "parent: catching child status\n", 0, 0, 0 );
653
654 #ifdef USE_WAITPID
655         while( waitpid( (pid_t) -1, 0, WAIT_FLAGS ) > 0 )
656                 ;       /* NULL */
657 #else
658         while ( wait3( &status, WAIT_FLAGS, 0 ) > 0 )
659                 ;       /* NULL */
660 #endif
661
662         (void) SIGNAL( SIGCHLD, (void *) wait4child );
663 }
664
665
666 void
667 log_and_exit( int exitcode )
668 {
669         struct timeval  tv;
670
671         if ( dosyslog ) {
672                 if ( conn_start_tv.tv_sec == 0 ) {
673                         syslog( LOG_INFO, "UDP exit(%d)", exitcode );
674                 } else {
675                         gettimeofday( &tv, (struct timezone *)NULL );
676                         syslog( LOG_INFO, "TCP closed %d seconds,  exit(%d)",
677                             tv.tv_sec - conn_start_tv.tv_sec, exitcode );
678                 }
679         }
680
681         exit( exitcode );
682 }
683
684
685 #ifdef CLDAP
686 static int
687 udp_init(
688     int port,
689     int createsocket
690 )
691 {
692         int     s, bound;
693         char    *matched;
694         extern char             *dsa_address;
695         extern struct PSAPaddr  *psap_cpy();
696         extern struct conn      *conns;
697
698         if ( createsocket )
699                 s = set_socket( port, 1 );
700
701         conn_init();
702         conns->c_dn = strdup("");
703         conns->c_cred = strdup("");
704         conns->c_credlen = 0;
705         conns->c_method = LDAP_AUTH_SIMPLE;
706
707        if ( dsa_address == NULL || (conns->c_paddr = str2paddr( dsa_address ))
708             == NULLPA ) {
709                 fprintf(stderr, "Bad DSA address (%s)\n", dsa_address ?
710                     dsa_address : "NULL" );
711                 exit( 1 );
712         } else {
713                 conns->c_paddr = psap_cpy(conns->c_paddr);
714         }
715
716         if ( do_bind_real(conns, &bound, &matched) != LDAP_SUCCESS) {
717                 fprintf(stderr, "Cannot bind to directory\n");
718                 exit( 1 );
719         }
720         if ( matched != NULL )
721                 free( matched );
722
723         return( createsocket ? s : 0 );
724 }
725 #endif