3 * Copyright (c) 1990 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.
18 #include <ac/stdlib.h>
21 #include <ac/signal.h>
22 #include <ac/socket.h>
23 #include <ac/string.h>
24 #include <ac/syslog.h>
26 #include <ac/unistd.h>
29 #include <ac/setproctitle.h>
31 #ifdef HAVE_SYS_PARAM_H
32 #include <sys/param.h>
35 #ifdef HAVE_SYS_RESOURCE_H
36 #include <sys/resource.h>
42 #include "ldap_defaults.h"
44 #define ldap_debug debug
53 int ldap_syslog_level;
57 char *ldaphost = NULL;
59 int rdncount = GO500_RDNCOUNT;
60 char *filterfile = FILTERFILE;
61 char *templatefile = TEMPLATEFILE;
63 char myhost[MAXHOSTNAMELEN];
66 static void usage ( char *name ) LDAP_GCCATTR((noreturn));
67 static int set_socket (int port);
68 static RETSIGTYPE wait4child(int sig);
69 static void do_queries (int s) LDAP_GCCATTR((noreturn));
70 static void do_error (FILE *fp, char *s);
71 static void do_search (LDAP *ld, FILE *fp, char *buf);
72 static void do_read (LDAP *ld, FILE *fp, char *dn);
77 fprintf( stderr, "usage: %s [-d debuglevel] [-f filterfile] [-t templatefile]\r\n\t[-a] [-l] [-p port] [-x ldaphost] [-b searchbase] [-c rdncount]\r\n", name );
82 main( int argc, char **argv )
90 struct sockaddr_in from;
93 #if defined( LDAP_PROCTITLE ) && !defined( HAVE_SETPROCTITLE )
94 /* for setproctitle */
99 while ( (i = getopt( argc, argv, "b:d:f:lp:c:t:x:I" )) != EOF ) {
101 case 'b': /* searchbase */
102 base = strdup( optarg );
105 case 'd': /* debug level */
106 debug |= atoi( optarg );
109 case 'f': /* ldap filter file */
110 filterfile = strdup( optarg );
113 case 'l': /* log via LOG_LOCAL3 */
117 case 'p': /* port to listen to */
118 port = atoi( optarg );
121 case 'c': /* number of DN components to show */
122 rdncount = atoi( optarg );
125 case 't': /* ldap template file */
126 templatefile = strdup( optarg );
129 case 'x': /* ldap server hostname */
130 ldaphost = strdup( optarg );
133 case 'I': /* run from inetd */
142 #ifdef GO500_HOSTNAME
143 strcpy( myhost, GO500_HOSTNAME );
145 if ( myhost[0] == '\0' && gethostname( myhost, sizeof(myhost) )
147 perror( "gethostname" );
148 exit( EXIT_FAILURE );
153 dtblsize = sysconf( _SC_OPEN_MAX );
154 #elif HAVE_GETDTABLESIZE
155 dtblsize = getdtablesize();
157 dtblsize = FD_SETSIZE;
161 if (dtblsize > FD_SETSIZE) {
162 dtblsize = FD_SETSIZE;
164 #endif /* FD_SETSIZE*/
166 /* detach if stderr is redirected or no debugging */
168 lutil_detach( debug && !isatty( 1 ), 1 );
170 if ( (myname = strrchr( argv[0], '/' )) == NULL )
171 myname = strdup( argv[0] );
173 myname = strdup( myname + 1 );
176 ber_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &debug);
177 ldap_set_option(NULL, LDAP_OPT_DEBUG_LEVEL, &debug);
181 (void) SIGNAL( SIGPIPE, SIG_IGN );
186 openlog( myname, OPENLOG_OPTIONS, LOG_LOCAL3 );
188 openlog( myname, OPENLOG_OPTIONS );
192 syslog( LOG_INFO, "initializing" );
194 /* set up the socket to listen on */
196 s = set_socket( port );
198 /* arrange to reap children */
199 (void) SIGNAL( SIGCHLD, wait4child );
203 fromlen = sizeof(from);
204 if ( getpeername( 0, (struct sockaddr *) &from, &fromlen )
206 hp = gethostbyaddr( (char *) &(from.sin_addr.s_addr),
207 sizeof(from.sin_addr.s_addr), AF_INET );
208 Debug( LDAP_DEBUG_ARGS, "connection from %s (%s)\n",
209 (hp == NULL) ? "unknown" : hp->h_name,
210 inet_ntoa( from.sin_addr ), 0 );
213 syslog( LOG_INFO, "connection from %s (%s)",
214 (hp == NULL) ? "unknown" : hp->h_name,
215 inet_ntoa( from.sin_addr ) );
218 #ifdef LDAP_PROCTITLE
219 setproctitle( hp == NULL ? inet_ntoa( from.sin_addr ) :
226 exit( EXIT_SUCCESS );
231 FD_SET( s, &readfds );
233 if ( (rc = select( dtblsize, &readfds, 0, 0 ,0 )) == -1 ) {
234 if ( debug ) perror( "select" );
236 } else if ( rc == 0 ) {
240 if ( ! FD_ISSET( s, &readfds ) )
243 fromlen = sizeof(from);
244 if ( (ns = accept( s, (struct sockaddr *) &from, &fromlen ))
246 if ( debug ) perror( "accept" );
247 exit( EXIT_FAILURE );
250 hp = gethostbyaddr( (char *) &(from.sin_addr.s_addr),
251 sizeof(from.sin_addr.s_addr), AF_INET );
254 syslog( LOG_INFO, "TCP connection from %s (%s)",
255 (hp == NULL) ? "unknown" : hp->h_name,
256 inet_ntoa( from.sin_addr ) );
259 switch( pid = fork() ) {
265 case -1: /* failed */
269 default: /* parent */
272 fprintf( stderr, "forked child %d\n", pid );
280 set_socket( int port )
283 struct sockaddr_in addr;
289 if ( (s = socket( AF_INET, SOCK_STREAM, 0 )) == -1 ) {
291 exit( EXIT_FAILURE );
295 /* set option so clients can't keep us from coming back up */
297 if ( setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
298 sizeof(one) ) < 0 ) {
299 perror( "setsockopt" );
300 exit( EXIT_FAILURE );
304 /* enable keep alives */
306 if ( setsockopt( s, SOL_SOCKET, SO_KEEPALIVE, (char *) &one,
307 sizeof(one) ) < 0 ) {
308 perror( "setsockopt" );
309 exit( EXIT_FAILURE );
314 addr.sin_family = AF_INET;
315 addr.sin_addr.s_addr = htonl(INADDR_ANY);
316 addr.sin_port = htons( port );
317 if ( bind( s, (struct sockaddr *) &addr, sizeof(addr) ) ) {
319 exit( EXIT_FAILURE );
322 /* listen for connections */
323 if ( listen( s, 5 ) == -1 ) {
325 exit( EXIT_FAILURE );
328 if ( debug ) printf("tcp socket allocated, bound, and listening\n");
334 wait4child( int sig )
337 WAITSTATUSTYPE status;
340 if ( debug ) printf( "parent: catching child status\n" );
343 while (waitpid ((pid_t) -1, (int *) NULL, WAIT_FLAGS) > 0)
346 while ( wait4((pid_t) -1, &status, WAIT_FLAGS, 0 ) > 0 )
350 (void) SIGNAL( SIGCHLD, wait4child );
356 char buf[1024], *query;
360 struct timeval timeout;
364 if ( (fp = fdopen( s, "a+")) == NULL ) {
365 exit( EXIT_FAILURE );
368 timeout.tv_sec = GO500_TIMEOUT;
371 FD_SET( fileno( fp ), &readfds );
373 if ( (rc = select( dtblsize, &readfds, 0, 0, &timeout )) <= 0 )
374 exit( EXIT_FAILURE );
376 if ( fgets( buf, sizeof(buf), fp ) == NULL )
377 exit( EXIT_FAILURE );
381 fprintf( stderr, "got %d bytes\n", len );
383 ber_bprint( buf, len );
388 if ( buf[len - 1] == '\n' )
391 if ( buf[len - 1] == '\r' )
397 /* strip off leading white space */
398 while ( isspace( (unsigned char) *query )) {
405 if ( *query == '~' || *query == '@' ) {
407 } else if ( (ld = ldap_init( ldaphost, 0 )) == NULL ) {
409 "0An error occurred (explanation)\t@%d\t%s\t%d\r\n",
410 LDAP_SERVER_DOWN, myhost, myport );
411 fprintf( fp, ".\r\n" );
413 exit( EXIT_FAILURE );
415 int deref = GO500_DEREF;
416 ldap_set_option(ld, LDAP_OPT_DEREF, &deref);
418 rc = ldap_simple_bind_s( ld, NULL, NULL );
419 if ( rc != LDAP_SUCCESS ) {
421 "0An error occurred (explanation)\t@%d\t%s\t%d\r\n",
422 rc, myhost, myport );
423 fprintf( fp, ".\r\n" );
425 exit( EXIT_FAILURE );
431 fprintf( fp, "The query you specified was not specific enough, causing a size limit\r\n" );
432 fprintf( fp, "to be exceeded and the first several matches found to be returned.\r\n" );
433 fprintf( fp, "If you did not find the match you were looking for, try issuing a more\r\n" );
434 fprintf( fp, "specific query, for example one that contains both first and last name.\r\n" );
435 fprintf( fp, ".\r\n" );
439 do_read( ld, fp, ++query );
443 do_error( fp, ++query );
447 do_search( ld, fp, query );
451 fprintf( fp, ".\r\n" );
458 exit( EXIT_FAILURE );
463 do_error( FILE *fp, char *s )
469 fprintf( fp, "An error occurred searching X.500. The error code was %d\r\n", code );
470 fprintf( fp, "The corresponding error is: %s\r\n", ldap_err2string( code ) );
471 fprintf( fp, "No additional information is available\r\n" );
472 fprintf( fp, ".\r\n" );
476 do_search( LDAP *ld, FILE *fp, char *buf )
484 LDAPMessage *e, *res;
485 static char *attrs[] = { "title", 0 };
488 if ( strchr( buf, ',' ) != NULL ) {
489 ldap_ufn_setprefix( ld, base );
490 tv.tv_sec = GO500_TIMEOUT;
492 ldap_ufn_timeout( (void *) &tv );
494 if ( (rc = ldap_ufn_search_s( ld, buf, attrs, 0, &res ))
495 != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED ) {
497 "0An error occurred (explanation)\t@%d\t%s\t%d\r\n",
498 rc, myhost, myport );
502 matches = ldap_count_entries( ld, res );
505 if ( (filtd = ldap_init_getfilter( filterfile )) == NULL ) {
506 fprintf( stderr, "Cannot open filter file (%s)\n",
508 exit( EXIT_FAILURE );
511 tv.tv_sec = GO500_TIMEOUT;
513 for ( fi = ldap_getfirstfilter( filtd, "go500", buf );
515 fi = ldap_getnextfilter( filtd ) )
517 if ( (rc = ldap_search_st( ld, base, LDAP_SCOPE_SUBTREE,
518 fi->lfi_filter, attrs, 0, &tv, &res ))
519 != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED ) {
520 fprintf(fp, "0An error occurred (explanation)\t@%d\t%s\t%d\r\n",
521 rc, myhost, myport );
522 ldap_getfilter_free( filtd );
526 if ( (matches = ldap_count_entries( ld, res )) != 0 )
529 ldap_getfilter_free( filtd );
534 if ( matches <= 0 ) {
538 #ifdef GO500_SORT_ATTR
539 ldap_sort_entries( ld, &res, GO500_SORT_ATTR, strcasecmp );
542 for ( e = ldap_first_entry( ld, res ); e != NULL;
543 e = ldap_next_entry( ld, e ) ) {
546 dn = ldap_get_dn( ld, e );
548 if ( (s = strchr( rdn, ',' )) != NULL )
551 if ( (s = strchr( rdn, '=' )) == NULL )
556 title = ldap_get_values( ld, e, "title" );
558 if ( title != NULL ) {
561 for ( p = title[0]; *p; p++ ) {
567 fprintf( fp, "0%-20s %s\t=%s\t%s\t%d\r\n", s,
568 title ? title[0] : "", dn, myhost, myport );
571 ldap_value_free( title );
577 if ( ldap_result2error( ld, res, 1 ) == LDAP_SIZELIMIT_EXCEEDED ) {
578 fprintf( fp, "0A size limit was exceeded (explanation)\t~\t%s\t%d\r\n",
584 entry2textwrite( void *fp, char *buf, ber_len_t len )
586 return( fwrite( buf, len, 1, (FILE *)fp ) == 0 ? -1 : len );
590 do_read( LDAP *ld, FILE *fp, char *dn )
592 static struct ldap_disptmpl *tmpllist;
594 ldap_init_templates( templatefile, &tmpllist );
596 if ( ldap_entry2text_search( ld, dn, base, NULL, tmpllist, NULL, NULL,
597 entry2textwrite, (void *) fp, "\r\n", rdncount,
598 LDAP_DISP_OPT_DOSEARCHACTIONS ) != LDAP_SUCCESS ) {
599 ldap_perror( ld, "ldap_entry2text_search" );
600 exit( EXIT_FAILURE );
603 if ( tmpllist != NULL ) {
604 ldap_free_templates( tmpllist );