3 * Copyright (c) 1990-1996 Regents of the University of Michigan.
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.
14 * Some code fragments to run from inetd stolen from the University
15 * of Minnesota gopher distribution, which had this copyright on it:
17 * Part of the Internet Gopher program, copyright (C) 1991
18 * University of Minnesota Microcomputer Workstation and Networks Center
25 #include <ac/signal.h>
26 #include <ac/socket.h>
27 #include <ac/string.h>
28 #include <ac/syslog.h>
30 #include <ac/unistd.h>
34 #include <ac/setproctitle.h>
37 #include <quipu/commonarg.h>
38 #include <quipu/ds_error.h>
41 #include "../../libraries/liblber/lber-int.h" /* get struct sockbuf */
44 #include "lutil.h" /* Get lutil_detach() */
49 int allow_severity = LOG_INFO;
50 int deny_severity = LOG_NOTICE;
51 #endif /* TCP_WRAPPERS */
53 static int set_socket( int port, int udp );
54 static void do_queries( int clientsock, int udp );
55 static RETSIGTYPE wait4child( int sig );
56 #ifdef LDAP_CONNECTIONLESS
57 static int udp_init( int port, int createsocket );
69 #ifdef LDAP_CONNECTIONLESS
72 int idletime = DEFAULT_TIMEOUT;
73 int referral_connection_timeout = DEFAULT_REFERRAL_TIMEOUT;
74 struct timeval conn_start_tv;
76 char *krb_ldap_service = "ldapserver";
77 char *krb_x500_service = "x500dsa";
78 char *krb_x500_instance;
80 char *kerberos_keyfile;
89 fprintf( stderr, "usage: %s [-d debuglvl] [-p port] [-l] [-c dsa] [-r referraltimeout]", name );
90 #ifdef LDAP_CONNECTIONLESS
91 fprintf( stderr, " [ -U | -t timeout ]" );
93 fprintf( stderr, " [ -t timeout ]" );
95 fprintf( stderr, " [-I]" );
97 fprintf( stderr, " [-i dsainstance]" );
99 fprintf( stderr, "\n" );
103 main( int argc, char **argv )
106 #ifdef LDAP_CONNECTIONLESS
109 int myport = LDAP_PORT;
111 int i, pid, socktype;
115 struct sockaddr_in from;
119 #ifdef LDAP_PROCTITLE
124 /* Pick up socket from inetd-type server on VMS */
125 if ( (ns = socket_from_server( NULL )) > 0 )
128 /* Socket from inetd is usually 0 */
133 if ( (dsapargv = (char **) malloc( 4 * sizeof(char *) )) == NULL ) {
137 dsapargv[0] = argv[0];
143 kerberos_keyfile = "";
146 /* process command line arguments */
147 while ( (i = getopt( argc, argv, "d:lp:f:i:c:r:t:IuU" )) != EOF ) {
149 case 'c': /* specify dsa to contact */
150 dsapargv[1] = "-call";
151 dsapargv[2] = strdup( optarg );
155 case 'd': /* set debug level and 'do not detach' flag */
158 ldap_debug = atoi( optarg );
159 if ( ldap_debug & LDAP_DEBUG_PACKETS )
160 ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &ldap_debug );
162 if ( atoi( optarg ) != 0 )
163 fputs( "Not compiled with -DLDAP_DEBUG!\n", stderr );
167 case 'l': /* do syslogging */
171 case 'p': /* specify port number */
172 myport = atoi( optarg );
175 case 'r': /* timeout for referral connections */
176 referral_connection_timeout = atoi( optarg );
179 case 't': /* timeout for idle connections */
180 idletime = atoi( optarg );
184 case 'f': /* kerberos key file */
185 kerberos_keyfile = strdup( optarg );
188 case 'i': /* x500 dsa kerberos instance */
189 if ( krb_x500_instance != NULL )
190 free( krb_x500_instance );
191 krb_x500_instance = strdup( optarg );
195 case 'I': /* Run from inetd */
199 #ifdef LDAP_CONNECTIONLESS
200 case 'U': /* UDP only (no TCP) */
206 case 'u': /* allow UDP requests (CLDAP) */
211 #endif /* LDAP_CONNECTIONLESS */
219 if ( optind < argc ) {
224 #ifdef LDAP_CONNECTIONLESS
225 if ( do_udp && !do_tcp && idletime != DEFAULT_TIMEOUT ) {
231 Debug( LDAP_DEBUG_TRACE, "%s", Versionstr, 0, 0 );
234 dtblsize = sysconf( _SC_OPEN_MAX );
235 #elif HAVE_GETDTABLESIZE
236 dtblsize = getdtablesize();
238 dtblsize = FD_SETSIZE;
242 if( dtblsize > FD_SETSIZE ) {
243 dtblsize = FD_SETSIZE;
245 #endif /* FD_SETSIZE */
247 #if defined(LDAP_PROCTITLE) && !defined( HAVE_SETPROCTITLE )
248 /* for setproctitle */
253 if ( (myname = strrchr( argv[0], '/' )) == NULL )
254 myname = strdup( argv[0] );
256 myname = strdup( myname + 1 );
259 * detach from the terminal if stderr is redirected or no
260 * debugging is wanted, and then arrange to reap children
264 #ifdef LDAP_PROCTITLE
265 setproctitle( "initializing" );
268 lutil_detach( no_detach, 1 );
270 (void) SIGNAL( SIGCHLD, wait4child );
271 (void) SIGNAL( SIGINT, log_and_exit );
275 * set up syslogging (if desired)
279 openlog( myname, OPENLOG_OPTIONS, LOG_LOCAL4 );
281 openlog( myname, OPENLOG_OPTIONS );
286 * load the syntax handlers, oidtables, and initialize some stuff,
287 * then start listening
290 (void) quipu_syntaxes();
292 (void) pp_quipu_init( argv[0] );
294 #if ISODEPACKAGE == IC
296 dsa_operation_syntaxes();
299 (void) dsap_init( &dsapargc, &dsapargv );
300 (void) get_syntaxes();
302 len = sizeof( socktype );
303 getsockopt( ns, SOL_SOCKET, SO_TYPE, (char *)&socktype, &len );
304 if ( socktype == SOCK_DGRAM ) {
305 #ifdef LDAP_CONNECTIONLESS
306 Debug( LDAP_DEBUG_ARGS,
307 "CLDAP request from unknown (%s)\n",
308 inet_ntoa( from.sin_addr ), 0, 0 );
309 conn_start_tv.tv_sec = 0;
312 #else /* LDAP_CONNECTIONLESS */
313 Debug( LDAP_DEBUG_ARGS,
314 "Compile with -DLDAP_CONNECTIONLESS for UDP support\n",0,0,0 );
315 #endif /* LDAP_CONNECTIONLESS */
320 if ( getpeername( ns, (struct sockaddr *) &from, &len )
322 hp = gethostbyaddr( (char *) &(from.sin_addr),
323 sizeof(from.sin_addr), AF_INET );
324 Debug( LDAP_DEBUG_ARGS, "connection from %s (%s)\n",
325 (hp == NULL) ? "unknown" : hp->h_name,
326 inet_ntoa( from.sin_addr ), 0 );
329 syslog( LOG_INFO, "connection from %s (%s)",
330 (hp == NULL) ? "unknown" : hp->h_name,
331 inet_ntoa( from.sin_addr ) );
334 #ifdef LDAP_PROCTITLE
335 sprintf( title, "%s %d\n", hp == NULL ?
336 inet_ntoa( from.sin_addr ) : hp->h_name, myport );
337 setproctitle( title );
340 gettimeofday( &conn_start_tv, (struct timezone *) NULL );
347 tcps = set_socket( myport, 0 );
349 #ifdef LDAP_CONNECTIONLESS
351 udps = udp_init( myport, 1 );
355 * loop, wait for a connection, then fork off a child to handle it
356 * if we are doing CLDAP as well, handle those requests on the fly
359 #ifdef LDAP_PROCTITLE
360 #ifdef LDAP_CONNECTIONLESS
361 sprintf( title, "listening %s/%s %d", do_tcp ? "tcp" : "",
362 do_udp ? "udp" : "", myport );
364 sprintf( title, "listening %s %d", do_tcp ? "tcp" : "", myport );
366 setproctitle( title );
372 FD_SET( tcps, &readfds );
373 #ifdef LDAP_CONNECTIONLESS
375 FD_SET( udps, &readfds );
378 if ( select( dtblsize, &readfds, 0, 0, 0 ) < 1 ) {
380 if ( ldap_debug ) perror( "main select" );
385 #ifdef LDAP_CONNECTIONLESS
386 if ( do_udp && FD_ISSET( udps, &readfds ) ) {
387 do_queries( udps, 1 );
391 if ( !do_tcp || ! FD_ISSET( tcps, &readfds ) ) {
396 if ( (ns = accept( tcps, (struct sockaddr *) &from, &len ))
399 if ( ldap_debug ) perror( "accept" );
404 hp = gethostbyaddr( (char *) &(from.sin_addr),
405 sizeof(from.sin_addr), AF_INET );
408 if ( !hosts_ctl("ldapd", (hp == NULL) ? "unknown" : hp->h_name,
409 inet_ntoa( from.sin_addr ), STRING_UNKNOWN) ) {
411 Debug( LDAP_DEBUG_ARGS, "connection from %s (%s) denied.\n",
412 (hp == NULL) ? "unknown" : hp->h_name,
413 inet_ntoa( from.sin_addr ), 0 );
416 syslog( LOG_NOTICE, "connection from %s (%s) denied.",
417 (hp == NULL) ? "unknown" : hp->h_name,
418 inet_ntoa( from.sin_addr ) );
424 #endif /* TCP_WRAPPERS */
426 Debug( LDAP_DEBUG_ARGS, "connection from %s (%s)\n",
427 (hp == NULL) ? "unknown" : hp->h_name,
428 inet_ntoa( from.sin_addr ), 0 );
432 syslog( LOG_INFO, "connection from %s (%s)",
433 (hp == NULL) ? "unknown" : hp->h_name,
434 inet_ntoa( from.sin_addr ) );
438 /* This is for debug on terminal on VMS */
440 #ifdef LDAP_PROCTITLE
441 setproctitle( hp == NULL ? inet_ntoa( from.sin_addr ) :
444 gettimeofday( &conn_start_tv, (struct timezone *) NULL );
445 (void) SIGNAL( SIGPIPE, log_and_exit );
451 switch( pid = fork() ) {
454 #ifdef LDAP_PROCTITLE
455 sprintf( title, "%s (%d)\n", hp == NULL ?
456 inet_ntoa( from.sin_addr ) : hp->h_name,
458 setproctitle( title );
460 gettimeofday( &conn_start_tv, (struct timezone *) NULL );
461 (void) SIGNAL( SIGPIPE, log_and_exit );
466 case -1: /* failed */
468 if ( ldap_debug ) perror( "fork" );
471 syslog( LOG_ERR, "fork failed %m" );
472 /* let things cool off */
476 default: /* parent */
478 Debug( LDAP_DEBUG_TRACE, "forked child %d\n", pid, 0,
489 int udp /* is this a UDP (CLDAP) request? */
494 struct timeval timeout;
496 #ifdef LDAP_CONNECTIONLESS
497 struct sockaddr saddr, faddr;
498 struct sockaddr *saddrlist[ 1 ];
499 #endif /* LDAP_CONNECTIONLESS */
501 Debug( LDAP_DEBUG_TRACE, "do_queries%s\n",
502 udp ? " udp" : "", 0, 0 );
505 * Loop, wait for a request from the client or a response from
506 * a dsa, then handle it. Dsap_ad is always a connection to the
507 * "default" dsa. Other connections can be made as a result of
508 * a referral being chased down. These association descriptors
509 * are kept track of with the message that caused the referral.
510 * The set_dsa_fds() routine traverses the list of outstanding
511 * messages, setting the appropriate bits in readfds.
518 ber_pvt_sb_init( &sb );
519 ber_pvt_sb_set_desc( &sb, clientsock );
520 ber_pvt_sb_set_io( &sb, (udp) ? &ber_pvt_sb_io_udp :
521 &ber_pvt_sb_io_tcp, NULL );
522 timeout.tv_sec = idletime;
525 struct conn *dsaconn;
528 FD_SET( clientsock, &readfds );
529 conn_setfds( &readfds );
532 if ( ldap_debug & LDAP_DEBUG_CONNS ) {
534 Debug( LDAP_DEBUG_CONNS, "FDLIST:", 0, 0, 0 );
535 for ( i = 0; i < dtblsize; i++ ) {
536 if ( FD_ISSET( i, &readfds ) ) {
537 Debug( LDAP_DEBUG_CONNS, " %d", i, 0,
541 Debug( LDAP_DEBUG_CONNS, "\n", 0, 0, 0 );
546 * hack - because of lber buffering, there might be stuff
547 * already waiting for us on the client sock.
550 if ( ! ber_pvt_sb_data_ready( &sb ) ) {
551 if ( (rc = select( dtblsize, &readfds, 0, 0,
552 udp ? 0 : &timeout )) < 1 ) {
554 if ( ldap_debug ) perror( "do_queries select" );
557 log_and_exit( 0 ); /* idle timeout */
559 Debug( LDAP_DEBUG_ANY, "select returns %d!\n",
562 /* client gone away - we can too */
563 if ( isclosed( clientsock ) )
567 * check if a dsa conn has gone away -
576 if ( ber_pvt_sb_data_ready( &sb ) ||
577 FD_ISSET( clientsock, &readfds ) ) {
578 client_request( &sb, conns, udp );
580 if ( (dsaconn = conn_getfd( &readfds )) == NULL ) {
581 Debug( LDAP_DEBUG_ANY, "No DSA activity!\n",
586 dsa_response( dsaconn, &sb );
595 int udp /* UDP port? */
599 struct sockaddr_in addr;
601 if ( (s = socket( AF_INET, udp ? SOCK_DGRAM:SOCK_STREAM, 0 )) == -1 ) {
607 /* set option so clients can't keep us from coming back up */
609 if ( setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (void *) &i, sizeof(i) )
612 perror( "setsockopt" );
617 /* enable keep alives */
619 if ( setsockopt( s, SOL_SOCKET, SO_KEEPALIVE, (void *) &i, sizeof(i) )
622 perror( "setsockopt" );
628 (void)memset( (void *)&addr, '\0', sizeof( addr ));
629 addr.sin_family = AF_INET;
630 addr.sin_addr.s_addr = htonl(INADDR_ANY);
631 addr.sin_port = htons( port );
632 if ( bind( s, (struct sockaddr *) &addr, sizeof(addr) ) ) {
638 /* listen for connections */
639 if ( listen( s, 5 ) == -1 ) {
645 Debug( LDAP_DEBUG_TRACE, "listening on %s port %d\n",
646 udp ? "udp" : "tcp", port, 0 );
652 wait4child( int sig )
655 WAITSTATUSTYPE status;
658 Debug( LDAP_DEBUG_TRACE, "parent: catching child status\n", 0, 0, 0 );
661 while( waitpid( (pid_t) -1, (int *) NULL, WAIT_FLAGS ) > 0 )
664 while ( wait4( (pid_t) -1, &status, WAIT_FLAGS, 0 ) > 0 )
668 (void) SIGNAL( SIGCHLD, wait4child );
673 log_and_exit( int exitcode )
678 if ( conn_start_tv.tv_sec == 0 ) {
679 syslog( LOG_INFO, "UDP exit(%d)", exitcode );
681 gettimeofday( &tv, (struct timezone *)NULL );
682 syslog( LOG_INFO, "TCP closed %d seconds, exit(%d)",
683 tv.tv_sec - conn_start_tv.tv_sec, exitcode );
691 #ifdef LDAP_CONNECTIONLESS
702 s = set_socket( port, 1 );
705 conns->c_dn = strdup("");
706 conns->c_cred = strdup("");
707 conns->c_credlen = 0;
708 conns->c_method = LDAP_AUTH_SIMPLE;
710 if ( dsa_address == NULL || (conns->c_paddr = str2paddr( dsa_address ))
712 fprintf(stderr, "Bad DSA address (%s)\n", dsa_address ?
713 dsa_address : "NULL" );
716 conns->c_paddr = psap_cpy(conns->c_paddr);
719 if ( do_bind_real(conns, &bound, &matched) != LDAP_SUCCESS) {
720 fprintf(stderr, "Cannot bind to directory\n");
723 if ( matched != NULL )
726 return( createsocket ? s : 0 );