2 * Copyright (c) 1990-1996 Regents of the University of Michigan.
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.
13 * Some code fragments to run from inetd stolen from the University
14 * of Minnesota gopher distribution, which had this copyright on it:
16 * Part of the Internet Gopher program, copyright (C) 1991
17 * University of Minnesota Microcomputer Workstation and Networks Center
24 #include <ac/signal.h>
25 #include <ac/socket.h>
26 #include <ac/string.h>
27 #include <ac/syslog.h>
29 #include <ac/unistd.h>
33 #include <ac/setproctitle.h>
36 #include <quipu/commonarg.h>
37 #include <quipu/ds_error.h>
46 int allow_severity = LOG_INFO;
47 int deny_severity = LOG_NOTICE;
48 #endif /* TCP_WRAPPERS */
53 static RETSIGTYPE wait4child();
54 #ifdef LDAP_CONNECTIONLESS
67 #ifdef LDAP_CONNECTIONLESS
70 int idletime = DEFAULT_TIMEOUT;
71 int referral_connection_timeout = DEFAULT_REFERRAL_TIMEOUT;
72 struct timeval conn_start_tv;
74 char *krb_ldap_service = "ldapserver";
75 char *krb_x500_service = "x500dsa";
76 char *krb_x500_instance;
78 char *kerberos_keyfile;
84 extern char Versionstr[];
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" );
107 #ifdef LDAP_CONNECTIONLESS
110 int myport = LDAP_PORT;
111 int i, pid, socktype;
115 struct sockaddr_in from;
119 RETSIGTYPE wait4child();
120 #ifdef LDAP_PROCTITLE
127 /* Pick up socket from inetd-type server on VMS */
128 if ( (ns = socket_from_server( NULL )) > 0 )
131 /* Socket from inetd is usually 0 */
136 if ( (dsapargv = (char **) malloc( 4 * sizeof(char *) )) == NULL ) {
140 dsapargv[0] = argv[0];
146 kerberos_keyfile = "";
149 /* process command line arguments */
150 while ( (i = getopt( argc, argv, "d:lp:f:i:c:r:t:IuU" )) != EOF ) {
152 case 'c': /* specify dsa to contact */
153 dsapargv[1] = "-call";
154 dsapargv[2] = strdup( optarg );
158 case 'd': /* turn on debugging */
160 ldap_debug = atoi( optarg );
161 if ( ldap_debug & LDAP_DEBUG_PACKETS )
162 lber_debug = ldap_debug;
164 fprintf( stderr, "Not compiled with -DLDAP_DEBUG!\n" );
168 case 'l': /* do syslogging */
172 case 'p': /* specify port number */
173 myport = atoi( optarg );
176 case 'r': /* timeout for referral connections */
177 referral_connection_timeout = atoi( optarg );
180 case 't': /* timeout for idle connections */
181 idletime = atoi( optarg );
185 case 'f': /* kerberos key file */
186 kerberos_keyfile = strdup( optarg );
189 case 'i': /* x500 dsa kerberos instance */
190 if ( krb_x500_instance != NULL )
191 free( krb_x500_instance );
192 krb_x500_instance = strdup( optarg );
196 case 'I': /* Run from inetd */
200 #ifdef LDAP_CONNECTIONLESS
201 case 'U': /* UDP only (no TCP) */
207 case 'u': /* allow UDP requests (CLDAP) */
212 #endif /* LDAP_CONNECTIONLESS */
220 if ( optind < argc ) {
225 #ifdef LDAP_CONNECTIONLESS
226 if ( do_udp && !do_tcp && idletime != DEFAULT_TIMEOUT ) {
232 Debug( LDAP_DEBUG_TRACE, "%s", Versionstr, 0, 0 );
235 dtblsize = sysconf( _SC_OPEN_MAX );
236 #elif HAVE_GETDTABLESIZE
237 dtblsize = getdtablesize();
239 dtblsize = FD_SETSIZE;
243 if( dtblsize > FD_SETSIZE ) {
244 dtblsize = FD_SETSIZE;
246 #endif /* FD_SETSIZE */
248 #if defined(LDAP_PROCTITLE) && !defined( HAVE_SETPROCTITLE )
249 /* for setproctitle */
254 if ( (myname = strrchr( argv[0], '/' )) == NULL )
255 myname = strdup( argv[0] );
257 myname = strdup( myname + 1 );
260 * detach from the terminal if stderr is redirected or no
261 * debugging is wanted, and then arrange to reap children
265 #ifdef LDAP_SETPROCTITLE
266 setproctitle( "initializing" );
271 (void) SIGNAL( SIGCHLD, (void *) wait4child );
272 (void) SIGNAL( SIGINT, (void *) log_and_exit );
276 * set up syslogging (if desired)
280 openlog( myname, OPENLOG_OPTIONS, LOG_LOCAL4 );
282 openlog( myname, OPENLOG_OPTIONS );
287 * load the syntax handlers, oidtables, and initialize some stuff,
288 * then start listening
291 (void) quipu_syntaxes();
293 (void) pp_quipu_init( argv[0] );
295 #if ISODEPACKAGE == IC
297 dsa_operation_syntaxes();
300 (void) dsap_init( &dsapargc, &dsapargv );
301 (void) get_syntaxes();
303 len = sizeof( socktype );
304 getsockopt( ns, SOL_SOCKET, SO_TYPE, &socktype, &len );
305 if ( socktype == SOCK_DGRAM ) {
306 #ifdef LDAP_CONNECTIONLESS
307 Debug( LDAP_DEBUG_ARGS,
308 "CLDAP request from unknown (%s)\n",
309 inet_ntoa( from.sin_addr ), 0, 0 );
310 conn_start_tv.tv_sec = 0;
313 #else /* LDAP_CONNECTIONLESS */
314 Debug( LDAP_DEBUG_ARGS,
315 "Compile with -DLDAP_CONNECTIONLESS for UDP support\n",0,0,0 );
316 #endif /* LDAP_CONNECTIONLESS */
321 if ( getpeername( ns, (struct sockaddr *) &from, &len )
323 hp = gethostbyaddr( (char *) &(from.sin_addr.s_addr),
324 sizeof(from.sin_addr.s_addr), AF_INET );
325 Debug( LDAP_DEBUG_ARGS, "connection from %s (%s)\n",
326 (hp == NULL) ? "unknown" : hp->h_name,
327 inet_ntoa( from.sin_addr ), 0 );
330 syslog( LOG_INFO, "connection from %s (%s)",
331 (hp == NULL) ? "unknown" : hp->h_name,
332 inet_ntoa( from.sin_addr ) );
335 #ifdef LDAP_SETPROCTITLE
336 sprintf( title, "%s %d\n", hp == NULL ?
337 inet_ntoa( from.sin_addr ) : hp->h_name, myport );
338 setproctitle( title );
341 gettimeofday( &conn_start_tv, (struct timezone *) NULL );
348 tcps = set_socket( myport, 0 );
350 #ifdef LDAP_CONNECTIONLESS
352 udps = udp_init( myport, 1 );
356 * loop, wait for a connection, then fork off a child to handle it
357 * if we are doing CLDAP as well, handle those requests on the fly
360 #ifdef LDAP_SETPROCTITLE
361 #ifdef LDAP_CONNECTIONLESS
362 sprintf( title, "listening %s/%s %d", do_tcp ? "tcp" : "",
363 do_udp ? "udp" : "", myport );
365 sprintf( title, "listening %s %d", do_tcp ? "tcp" : "", myport );
367 setproctitle( title );
373 FD_SET( tcps, &readfds );
374 #ifdef LDAP_CONNECTIONLESS
376 FD_SET( udps, &readfds );
379 if ( select( dtblsize, &readfds, 0, 0, 0 ) < 1 ) {
381 if ( ldap_debug ) perror( "main select" );
386 #ifdef LDAP_CONNECTIONLESS
387 if ( do_udp && FD_ISSET( udps, &readfds ) ) {
388 do_queries( udps, 1 );
392 if ( !do_tcp || ! FD_ISSET( tcps, &readfds ) ) {
397 if ( (ns = accept( tcps, (struct sockaddr *) &from, &len ))
400 if ( ldap_debug ) perror( "accept" );
405 hp = gethostbyaddr( (char *) &(from.sin_addr.s_addr),
406 sizeof(from.sin_addr.s_addr), AF_INET );
409 if ( !hosts_ctl("ldapd", (hp == NULL) ? "unknown" : hp->h_name,
410 inet_ntoa( from.sin_addr ), STRING_UNKNOWN ) {
412 Debug( LDAP_DEBUG_ARGS, "connection from %s (%s) denied.\n",
413 (hp == NULL) ? "unknown" : hp->h_name,
414 inet_ntoa( from.sin_addr ), 0 );
417 syslog( LOG_NOTICE, "connection from %s (%s) denied.",
418 (hp == NULL) ? "unknown" : hp->h_name,
419 inet_ntoa( from.sin_addr ) );
425 #endif /* TCP_WRAPPERS */
427 Debug( LDAP_DEBUG_ARGS, "connection from %s (%s)\n",
428 (hp == NULL) ? "unknown" : hp->h_name,
429 inet_ntoa( from.sin_addr ), 0 );
433 syslog( LOG_INFO, "connection from %s (%s)",
434 (hp == NULL) ? "unknown" : hp->h_name,
435 inet_ntoa( from.sin_addr ) );
439 /* This is for debug on terminal on VMS */
441 #ifdef LDAP_SETPROCTITLE
442 setproctitle( hp == NULL ? inet_ntoa( from.sin_addr ) :
445 gettimeofday( &conn_start_tv, (struct timezone *) NULL );
446 (void) SIGNAL( SIGPIPE, (void *) log_and_exit );
452 switch( pid = fork() ) {
455 #ifdef LDAP_SETPROCTITLE
456 sprintf( title, "%s (%d)\n", hp == NULL ?
457 inet_ntoa( from.sin_addr ) : hp->h_name,
459 setproctitle( title );
461 gettimeofday( &conn_start_tv, (struct timezone *) NULL );
462 (void) SIGNAL( SIGPIPE, (void *) log_and_exit );
467 case -1: /* failed */
469 if ( ldap_debug ) perror( "fork" );
472 syslog( LOG_ERR, "fork failed %m" );
473 /* let things cool off */
477 default: /* parent */
479 Debug( LDAP_DEBUG_TRACE, "forked child %d\n", pid, 0,
490 int udp /* is this a UDP (CLDAP) request? */
495 struct timeval timeout;
497 #ifdef LDAP_CONNECTIONLESS
498 struct sockaddr saddr, faddr;
499 struct sockaddr *saddrlist[ 1 ];
500 #endif /* LDAP_CONNECTIONLESS */
502 Debug( LDAP_DEBUG_TRACE, "do_queries%s\n",
503 udp ? " udp" : "", 0, 0 );
506 * Loop, wait for a request from the client or a response from
507 * a dsa, then handle it. Dsap_ad is always a connection to the
508 * "default" dsa. Other connections can be made as a result of
509 * a referral being chased down. These association descriptors
510 * are kept track of with the message that caused the referral.
511 * The set_dsa_fds() routine traverses the list of outstanding
512 * messages, setting the appropriate bits in readfds.
519 (void) memset( (void *) &sb, '\0', sizeof( sb ) );
520 sb.sb_sd = clientsock;
521 sb.sb_naddr = ( udp ) ? 1 : 0;
522 #ifdef LDAP_CONNECTIONLESS
523 sb.sb_addrs = (void **)saddrlist;
524 sb.sb_fromaddr = &faddr;
525 sb.sb_useaddr = saddrlist[ 0 ] = &saddr;
527 sb.sb_ber.ber_buf = NULL;
528 sb.sb_ber.ber_ptr = NULL;
529 sb.sb_ber.ber_end = NULL;
531 timeout.tv_sec = idletime;
534 struct conn *dsaconn;
535 extern struct conn *conns;
538 FD_SET( clientsock, &readfds );
539 conn_setfds( &readfds );
542 if ( ldap_debug & LDAP_DEBUG_CONNS ) {
543 Debug( LDAP_DEBUG_CONNS, "FDLIST:", 0, 0, 0 );
544 for ( i = 0; i < dtblsize; i++ ) {
545 if ( FD_ISSET( i, &readfds ) ) {
546 Debug( LDAP_DEBUG_CONNS, " %d", i, 0,
550 Debug( LDAP_DEBUG_CONNS, "\n", 0, 0, 0 );
555 * hack - because of lber buffering, there might be stuff
556 * already waiting for us on the client sock.
559 if ( sb.sb_ber.ber_ptr >= sb.sb_ber.ber_end ) {
560 if ( (rc = select( dtblsize, &readfds, 0, 0,
561 udp ? 0 : &timeout )) < 1 ) {
563 if ( ldap_debug ) perror( "do_queries select" );
566 log_and_exit( 0 ); /* idle timeout */
568 Debug( LDAP_DEBUG_ANY, "select returns %d!\n",
571 /* client gone away - we can too */
572 if ( isclosed( clientsock ) )
576 * check if a dsa conn has gone away -
585 if ( sb.sb_ber.ber_ptr < sb.sb_ber.ber_end ||
586 FD_ISSET( clientsock, &readfds ) ) {
587 client_request( &sb, conns, udp );
589 if ( (dsaconn = conn_getfd( &readfds )) == NULL ) {
590 Debug( LDAP_DEBUG_ANY, "No DSA activity!\n",
595 dsa_response( dsaconn, &sb );
603 int udp /* UDP port? */
607 struct sockaddr_in addr;
609 if ( (s = socket( AF_INET, udp ? SOCK_DGRAM:SOCK_STREAM, 0 )) == -1 ) {
614 /* set option so clients can't keep us from coming back up */
616 if ( setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (void *) &i, sizeof(i) )
618 perror( "setsockopt" );
623 (void)memset( (void *)&addr, '\0', sizeof( addr ));
624 addr.sin_family = AF_INET;
625 addr.sin_addr.s_addr = INADDR_ANY;
626 addr.sin_port = htons( port );
627 if ( bind( s, (struct sockaddr *) &addr, sizeof(addr) ) ) {
633 /* listen for connections */
634 if ( listen( s, 5 ) == -1 ) {
640 Debug( LDAP_DEBUG_TRACE, "listening on %s port %d\n",
641 udp ? "udp" : "tcp", port, 0 );
646 static RETSIGTYPE wait4child()
649 WAITSTATUSTYPE status;
652 Debug( LDAP_DEBUG_TRACE, "parent: catching child status\n", 0, 0, 0 );
655 while( waitpid( (pid_t) -1, NULL, WAIT_FLAGS ) > 0 )
658 while ( wait3( &status, WAIT_FLAGS, 0 ) > 0 )
662 (void) SIGNAL( SIGCHLD, (void *) wait4child );
667 log_and_exit( int exitcode )
672 if ( conn_start_tv.tv_sec == 0 ) {
673 syslog( LOG_INFO, "UDP exit(%d)", exitcode );
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 );
685 #ifdef LDAP_CONNECTIONLESS
694 extern char *dsa_address;
695 extern struct PSAPaddr *psap_cpy();
696 extern struct conn *conns;
699 s = set_socket( port, 1 );
702 conns->c_dn = strdup("");
703 conns->c_cred = strdup("");
704 conns->c_credlen = 0;
705 conns->c_method = LDAP_AUTH_SIMPLE;
707 if ( dsa_address == NULL || (conns->c_paddr = str2paddr( dsa_address ))
709 fprintf(stderr, "Bad DSA address (%s)\n", dsa_address ?
710 dsa_address : "NULL" );
713 conns->c_paddr = psap_cpy(conns->c_paddr);
716 if ( do_bind_real(conns, &bound, &matched) != LDAP_SUCCESS) {
717 fprintf(stderr, "Cannot bind to directory\n");
720 if ( matched != NULL )
723 return( createsocket ? s : 0 );