2 * Copyright (c) 1990 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.
16 #include <sys/types.h>
17 #include <sys/param.h>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
24 #include <sys/resource.h>
27 #include <sys/select.h>
31 #include "ldapconfig.h"
38 #endif /* USE_SYSCONF */
45 char *ldaphost = LDAPHOST;
46 char *base = GO500_BASE;
47 int rdncount = GO500_RDNCOUNT;
48 char *filterfile = FILTERFILE;
49 char *templatefile = TEMPLATEFILE;
51 char myhost[MAXHOSTNAMELEN];
55 static SIG_FN wait4child();
60 extern int strcasecmp();
65 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 );
79 struct sockaddr_in from;
86 /* for setproctitle */
90 while ( (i = getopt( argc, argv, "b:d:f:lp:c:t:x:I" )) != EOF ) {
92 case 'b': /* searchbase */
93 base = strdup( optarg );
96 case 'd': /* debug level */
97 debug = atoi( optarg );
100 case 'f': /* ldap filter file */
101 filterfile = strdup( optarg );
104 case 'l': /* log via LOG_LOCAL3 */
108 case 'p': /* port to listen to */
109 port = atoi( optarg );
112 case 'c': /* number of DN components to show */
113 rdncount = atoi( optarg );
116 case 't': /* ldap template file */
117 templatefile = strdup( optarg );
120 case 'x': /* ldap server hostname */
121 ldaphost = strdup( optarg );
124 case 'I': /* run from inetd */
133 #ifdef GO500_HOSTNAME
134 strcpy( myhost, GO500_HOSTNAME );
136 if ( myhost[0] == '\0' && gethostname( myhost, sizeof(myhost) )
138 perror( "gethostname" );
145 * It is invalid to use a set size in excess of the type
146 * scope, as defined for the fd_set in sys/types.h. This
147 * is true for any OS.
149 dtblsize = FD_SETSIZE;
150 #else /* !FD_SETSIZE*/
152 dtblsize = sysconf( _SC_OPEN_MAX );
153 #else /* USE_SYSCONF */
154 dtblsize = getdtablesize();
155 #endif /* USE_SYSCONF */
156 #endif /* !FD_SETSIZE*/
158 /* detach if stderr is redirected or no debugging */
160 (void) detach( debug );
162 if ( (myname = strrchr( argv[0], '/' )) == NULL )
163 myname = strdup( argv[0] );
165 myname = strdup( myname + 1 );
169 openlog( myname, OPENLOG_OPTIONS, LOG_LOCAL3 );
171 openlog( myname, OPENLOG_OPTIONS );
175 syslog( LOG_INFO, "initializing" );
177 /* set up the socket to listen on */
179 s = set_socket( port );
181 /* arrange to reap children */
182 (void) signal( SIGCHLD, (void *) wait4child );
186 fromlen = sizeof(from);
187 if ( getpeername( 0, (struct sockaddr *) &from, &fromlen )
189 hp = gethostbyaddr( (char *) &(from.sin_addr.s_addr),
190 sizeof(from.sin_addr.s_addr), AF_INET );
191 Debug( LDAP_DEBUG_ARGS, "connection from %s (%s)\n",
192 (hp == NULL) ? "unknown" : hp->h_name,
193 inet_ntoa( from.sin_addr ), 0 );
196 syslog( LOG_INFO, "connection from %s (%s)",
197 (hp == NULL) ? "unknown" : hp->h_name,
198 inet_ntoa( from.sin_addr ) );
201 setproctitle( hp == NULL ? inet_ntoa( from.sin_addr ) :
212 FD_SET( s, &readfds );
214 if ( (rc = select( dtblsize, &readfds, 0, 0 ,0 )) == -1 ) {
215 if ( debug ) perror( "select" );
217 } else if ( rc == 0 ) {
221 if ( ! FD_ISSET( s, &readfds ) )
224 fromlen = sizeof(from);
225 if ( (ns = accept( s, (struct sockaddr *) &from, &fromlen ))
227 if ( debug ) perror( "accept" );
231 hp = gethostbyaddr( (char *) &(from.sin_addr.s_addr),
232 sizeof(from.sin_addr.s_addr), AF_INET );
235 syslog( LOG_INFO, "TCP connection from %s (%s)",
236 (hp == NULL) ? "unknown" : hp->h_name,
237 inet_ntoa( from.sin_addr ) );
240 switch( pid = fork() ) {
246 case -1: /* failed */
250 default: /* parent */
253 fprintf( stderr, "forked child %d\n", pid );
265 struct sockaddr_in addr;
271 if ( (s = socket( AF_INET, SOCK_STREAM, 0 )) == -1 ) {
276 /* set option so clients can't keep us from coming back up */
278 if ( setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
279 sizeof(one) ) < 0 ) {
280 perror( "setsockopt" );
285 addr.sin_family = AF_INET;
286 addr.sin_addr.s_addr = INADDR_ANY;
287 addr.sin_port = htons( port );
288 if ( bind( s, (struct sockaddr *) &addr, sizeof(addr) ) ) {
293 /* listen for connections */
294 if ( listen( s, 5 ) == -1 ) {
299 if ( debug ) printf("tcp socket allocated, bound, and listening\n");
307 WAITSTATUSTYPE status;
309 if ( debug ) printf( "parent: catching child status\n" );
311 while (waitpid ((pid_t) -1, 0, WAIT_FLAGS) > 0)
312 #else /* USE_WAITPID */
313 while ( wait3( &status, WAIT_FLAGS, 0 ) > 0 )
314 #endif /* USE_WAITPID */
317 (void) signal( SIGCHLD, (void *) wait4child );
324 char buf[1024], *query;
328 struct timeval timeout;
332 if ( (fp = fdopen( s, "a+")) == NULL ) {
336 timeout.tv_sec = GO500_TIMEOUT;
339 FD_SET( fileno( fp ), &readfds );
341 if ( (rc = select( dtblsize, &readfds, 0, 0, &timeout )) <= 0 )
344 if ( fgets( buf, sizeof(buf), fp ) == NULL )
349 fprintf( stderr, "got %d bytes\n", len );
351 lber_bprint( buf, len );
356 if ( buf[len - 1] == '\n' )
359 if ( buf[len - 1] == '\r' )
365 /* strip off leading white space */
366 while ( isspace( *query )) {
373 if ( *query != '~' && *query != '@' ) {
374 if ( (ld = ldap_open( ldaphost, LDAP_PORT )) == NULL ) {
376 "0An error occurred (explanation)\t@%d\t%s\t%d\r\n",
377 LDAP_SERVER_DOWN, myhost, myport );
378 fprintf( fp, ".\r\n" );
383 ld->ld_deref = GO500_DEREF;
384 if ( (rc = ldap_simple_bind_s( ld, GO500_BINDDN, NULL ))
387 "0An error occurred (explanation)\t@%d\t%s\t%d\r\n",
388 rc, myhost, myport );
389 fprintf( fp, ".\r\n" );
397 fprintf( fp, "The query you specified was not specific enough, causing a size limit\r\n" );
398 fprintf( fp, "to be exceeded and the first several matches found to be returned.\r\n" );
399 fprintf( fp, "If you did not find the match you were looking for, try issuing a more\r\n" );
400 fprintf( fp, "specific query, for example one that contains both first and last name.\r\n" );
401 fprintf( fp, ".\r\n" );
405 do_read( ld, fp, ++query );
409 do_error( fp, ++query );
413 do_search( ld, fp, query );
417 fprintf( fp, ".\r\n" );
434 fprintf( fp, "An error occurred searching X.500. The error code was %d\r\n", code );
435 fprintf( fp, "The corresponding error is: %s\r\n", ldap_err2string( code ) );
436 fprintf( fp, "No additional information is available\r\n" );
437 fprintf( fp, ".\r\n" );
441 do_search( ld, fp, buf )
452 LDAPMessage *e, *res;
453 static char *attrs[] = { "title", 0 };
456 if ( strchr( buf, ',' ) != NULL ) {
457 ldap_ufn_setprefix( ld, base );
458 tv.tv_sec = GO500_TIMEOUT;
460 ldap_ufn_timeout( (void *) &tv );
462 if ( (rc = ldap_ufn_search_s( ld, buf, attrs, 0, &res ))
463 != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED ) {
465 "0An error occurred (explanation)\t@%d\t%s\t%d\r\n",
466 rc, myhost, myport );
470 matches = ldap_count_entries( ld, res );
473 if ( (filtd = ldap_init_getfilter( filterfile )) == NULL ) {
474 fprintf( stderr, "Cannot open filter file (%s)\n",
479 tv.tv_sec = GO500_TIMEOUT;
481 for ( fi = ldap_getfirstfilter( filtd, "go500", buf );
483 fi = ldap_getnextfilter( filtd ) )
485 if ( (rc = ldap_search_st( ld, base, LDAP_SCOPE_SUBTREE,
486 fi->lfi_filter, attrs, 0, &tv, &res ))
487 != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED ) {
488 fprintf(fp, "0An error occurred (explanation)\t@%d\t%s\t%d\r\n",
489 rc, myhost, myport );
490 ldap_getfilter_free( filtd );
494 if ( (matches = ldap_count_entries( ld, res )) != 0 )
497 ldap_getfilter_free( filtd );
502 if ( matches <= 0 ) {
506 #ifdef GO500_SORT_ATTR
507 ldap_sort_entries( ld, &res, GO500_SORT_ATTR, strcasecmp );
510 for ( e = ldap_first_entry( ld, res ); e != NULL;
511 e = ldap_next_entry( ld, e ) ) {
514 dn = ldap_get_dn( ld, e );
516 if ( (s = strchr( rdn, ',' )) != NULL )
519 if ( (s = strchr( rdn, '=' )) == NULL )
524 title = ldap_get_values( ld, e, "title" );
526 if ( title != NULL ) {
529 for ( p = title[0]; *p; p++ ) {
535 fprintf( fp, "0%-20s %s\t=%s\t%s\t%d\r\n", s,
536 title ? title[0] : "", dn, myhost, myport );
539 ldap_value_free( title );
545 if ( ldap_result2error( ld, res, 1 ) == LDAP_SIZELIMIT_EXCEEDED ) {
546 fprintf( fp, "0A size limit was exceeded (explanation)\t~\t%s\t%d\r\n",
552 entry2textwrite( void *fp, char *buf, int len )
554 return( fwrite( buf, len, 1, (FILE *)fp ) == 0 ? -1 : len );
558 do_read( ld, fp, dn )
563 static struct ldap_disptmpl *tmpllist;
565 ldap_init_templates( templatefile, &tmpllist );
567 if ( ldap_entry2text_search( ld, dn, base, NULL, tmpllist, NULL, NULL,
568 entry2textwrite, (void *) fp, "\r\n", rdncount,
569 LDAP_DISP_OPT_DOSEARCHACTIONS ) != LDAP_SUCCESS ) {
570 ldap_perror( ld, "ldap_entry2text_search" );
574 if ( tmpllist != NULL ) {
575 ldap_free_templates( tmpllist );