]> git.sur5r.net Git - openldap/blob - clients/gopher/go500.c
Modified make system to support CVS instead of RCS
[openldap] / clients / gopher / go500.c
1 /*
2  * Copyright (c) 1990 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 #include <stdio.h>
14 #include <string.h>
15 #include <ctype.h>
16 #include <sys/types.h>
17 #include <sys/param.h>
18 #include <sys/time.h>
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <arpa/inet.h>
22 #include <netdb.h>
23 #include <syslog.h>
24 #include <sys/resource.h>
25 #include <sys/wait.h>
26 #ifdef aix
27 #include <sys/select.h>
28 #endif /* aix */
29 #include <signal.h>
30 #include "portable.h"
31 #include "ldapconfig.h"
32 #include "lber.h"
33 #include "ldap.h"
34 #include "disptmpl.h"
35
36 #ifdef USE_SYSCONF
37 #include <unistd.h>
38 #endif /* USE_SYSCONF */
39
40 int     debug;
41 int     dosyslog;
42 int     inetd;
43 int     dtblsize;
44
45 char    *ldaphost = LDAPHOST;
46 char    *base = GO500_BASE;
47 int     rdncount = GO500_RDNCOUNT;
48 char    *filterfile = FILTERFILE;
49 char    *templatefile = TEMPLATEFILE;
50
51 char    myhost[MAXHOSTNAMELEN];
52 int     myport;
53
54 static set_socket();
55 static SIG_FN wait4child();
56 static do_queries();
57 static do_error();
58 static do_search();
59 static do_read();
60 extern int strcasecmp();
61
62 static usage( name )
63 char    *name;
64 {
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 );
66         exit( 1 );
67 }
68
69 main (argc, argv)
70 int     argc;
71 char    **argv;
72 {
73         int                     s, ns, rc;
74         int                     port = -1;
75         int                     i, pid;
76         char                    *myname;
77         fd_set                  readfds;
78         struct hostent          *hp;
79         struct sockaddr_in      from;
80         int                     fromlen;
81         SIG_FN                  wait4child();
82         extern char             *optarg;
83         extern char             **Argv;
84         extern int              Argc;
85
86         /* for setproctitle */
87         Argv = argv;
88         Argc = argc;
89
90         while ( (i = getopt( argc, argv, "b:d:f:lp:c:t:x:I" )) != EOF ) {
91                 switch( i ) {
92                 case 'b':       /* searchbase */
93                         base = strdup( optarg );
94                         break;
95
96                 case 'd':       /* debug level */
97                         debug = atoi( optarg );
98                         break;
99
100                 case 'f':       /* ldap filter file */
101                         filterfile = strdup( optarg );
102                         break;
103
104                 case 'l':       /* log via LOG_LOCAL3 */
105                         dosyslog = 1;
106                         break;
107
108                 case 'p':       /* port to listen to */
109                         port = atoi( optarg );
110                         break;
111
112                 case 'c':       /* number of DN components to show */
113                         rdncount = atoi( optarg );
114                         break;
115
116                 case 't':       /* ldap template file */
117                         templatefile = strdup( optarg );
118                         break;
119
120                 case 'x':       /* ldap server hostname */
121                         ldaphost = strdup( optarg );
122                         break;
123
124                 case 'I':       /* run from inetd */
125                         inetd = 1;
126                         break;
127
128                 default:
129                         usage( argv[0] );
130                 }
131         }
132
133 #ifdef GO500_HOSTNAME
134         strcpy( myhost, GO500_HOSTNAME );
135 #else
136         if ( myhost[0] == '\0' && gethostname( myhost, sizeof(myhost) )
137             == -1 ) {
138                 perror( "gethostname" );
139                 exit( 1 );
140         }
141 #endif
142
143 #ifdef USE_SYSCONF
144         dtblsize = sysconf( _SC_OPEN_MAX );
145 #else /* USE_SYSCONF */
146         dtblsize = getdtablesize();
147 #endif /* USE_SYSCONF */
148
149         /* detach if stderr is redirected or no debugging */
150         if ( inetd == 0 )
151                 (void) detach( debug );
152
153         if ( (myname = strrchr( argv[0], '/' )) == NULL )
154                 myname = strdup( argv[0] );
155         else
156                 myname = strdup( myname + 1 );
157
158         if ( dosyslog ) {
159 #ifdef LOG_LOCAL3
160                 openlog( myname, OPENLOG_OPTIONS, LOG_LOCAL3 );
161 #else
162                 openlog( myname, OPENLOG_OPTIONS );
163 #endif
164         }
165         if ( dosyslog )
166                 syslog( LOG_INFO, "initializing" );
167
168         /* set up the socket to listen on */
169         if ( inetd == 0 ) {
170                 s = set_socket( port );
171
172                 /* arrange to reap children */
173                 (void) signal( SIGCHLD, (void *) wait4child );
174         } else {
175                 myport = GO500_PORT;
176
177                 fromlen = sizeof(from);
178                 if ( getpeername( 0, (struct sockaddr *) &from, &fromlen )
179                     == 0 ) {
180                         hp = gethostbyaddr( (char *) &(from.sin_addr.s_addr),
181                             sizeof(from.sin_addr.s_addr), AF_INET );
182                         Debug( LDAP_DEBUG_ARGS, "connection from %s (%s)\n",
183                             (hp == NULL) ? "unknown" : hp->h_name,
184                             inet_ntoa( from.sin_addr ), 0 );
185
186                         if ( dosyslog ) {
187                                 syslog( LOG_INFO, "connection from %s (%s)",
188                                     (hp == NULL) ? "unknown" : hp->h_name,
189                                     inet_ntoa( from.sin_addr ) );
190                         }
191
192                         setproctitle( hp == NULL ? inet_ntoa( from.sin_addr ) :
193                             hp->h_name );
194                 }
195
196                 do_queries( 0 );
197
198                 exit( 0 );
199         }
200
201         for ( ;; ) {
202                 FD_ZERO( &readfds );
203                 FD_SET( s, &readfds );
204
205                 if ( (rc = select( dtblsize, &readfds, 0, 0 ,0 )) == -1 ) {
206                         if ( debug ) perror( "select" );
207                         continue;
208                 } else if ( rc == 0 ) {
209                         continue;
210                 }
211
212                 if ( ! FD_ISSET( s, &readfds ) )
213                         continue;
214
215                 fromlen = sizeof(from);
216                 if ( (ns = accept( s, (struct sockaddr *) &from, &fromlen ))
217                     == -1 ) {
218                         if ( debug ) perror( "accept" );
219                         exit( 1 );
220                 }
221
222                 hp = gethostbyaddr( (char *) &(from.sin_addr.s_addr),
223                     sizeof(from.sin_addr.s_addr), AF_INET );
224
225                 if ( dosyslog ) {
226                         syslog( LOG_INFO, "TCP connection from %s (%s)",
227                             (hp == NULL) ? "unknown" : hp->h_name,
228                             inet_ntoa( from.sin_addr ) );
229                 }
230
231                 switch( pid = fork() ) {
232                 case 0:         /* child */
233                         close( s );
234                         do_queries( ns );
235                         break;
236
237                 case -1:        /* failed */
238                         perror( "fork" );
239                         break;
240
241                 default:        /* parent */
242                         close( ns );
243                         if ( debug )
244                                 fprintf( stderr, "forked child %d\n", pid );
245                         break;
246                 }
247         }
248         /* NOT REACHED */
249 }
250
251 static
252 set_socket( port )
253 int     port;
254 {
255         int                     s, one;
256         struct sockaddr_in      addr;
257
258         if ( port == -1 )
259                 port = GO500_PORT;
260         myport = port;
261
262         if ( (s = socket( AF_INET, SOCK_STREAM, 0 )) == -1 ) {
263                 perror( "socket" );
264                 exit( 1 );
265         }
266
267         /* set option so clients can't keep us from coming back up */
268         one = 1;
269         if ( setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
270             sizeof(one) ) < 0 ) {
271                 perror( "setsockopt" );
272                 exit( 1 );
273         }
274
275         /* bind to a name */
276         addr.sin_family = AF_INET;
277         addr.sin_addr.s_addr = INADDR_ANY;
278         addr.sin_port = htons( port );
279         if ( bind( s, (struct sockaddr *) &addr, sizeof(addr) ) ) {
280                 perror( "bind" );
281                 exit( 1 );
282         }
283
284         /* listen for connections */
285         if ( listen( s, 5 ) == -1 ) {
286                 perror( "listen" );
287                 exit( 1 );
288         }
289
290         if ( debug ) printf("tcp socket allocated, bound, and listening\n");
291
292         return( s );
293 }
294
295 static SIG_FN
296 wait4child()
297 {
298         WAITSTATUSTYPE     status;
299
300         if ( debug ) printf( "parent: catching child status\n" );
301 #ifdef USE_WAITPID
302         while (waitpid ((pid_t) -1, 0, WAIT_FLAGS) > 0)
303 #else /* USE_WAITPID */
304         while ( wait3( &status, WAIT_FLAGS, 0 ) > 0 )
305 #endif /* USE_WAITPID */
306                 ;       /* NULL */
307
308         (void) signal( SIGCHLD, (void *) wait4child );
309 }
310
311 static
312 do_queries( s )
313 int     s;
314 {
315         char            buf[1024], *query;
316         int             len;
317         FILE            *fp;
318         int             rc;
319         struct timeval  timeout;
320         fd_set          readfds;
321         LDAP            *ld;
322
323         if ( (fp = fdopen( s, "a+")) == NULL ) {
324                 exit( 1 );
325         }
326
327         timeout.tv_sec = GO500_TIMEOUT;
328         timeout.tv_usec = 0;
329         FD_ZERO( &readfds );
330         FD_SET( fileno( fp ), &readfds );
331
332         if ( (rc = select( dtblsize, &readfds, 0, 0, &timeout )) <= 0 )
333                 exit( 1 );
334
335         if ( fgets( buf, sizeof(buf), fp ) == NULL )
336                 exit( 1 );
337
338         len = strlen( buf );
339         if ( debug ) {
340                 fprintf( stderr, "got %d bytes\n", len );
341 #ifdef LDAP_DEBUG
342                 lber_bprint( buf, len );
343 #endif
344         }
345
346         /* strip of \r \n */
347         if ( buf[len - 1] == '\n' )
348                 buf[len - 1] = '\0';
349         len--;
350         if ( buf[len - 1] == '\r' )
351                 buf[len - 1] = '\0';
352         len--;
353
354         query = buf;
355
356         /* strip off leading white space */
357         while ( isspace( *query )) {
358                 ++query;
359                 --len;
360         }
361
362         rewind(fp);
363
364         if ( *query != '~' && *query != '@' ) {
365                 if ( (ld = ldap_open( ldaphost, LDAP_PORT )) == NULL ) {
366                         fprintf(fp,
367                             "0An error occurred (explanation)\t@%d\t%s\t%d\r\n",
368                             LDAP_SERVER_DOWN, myhost, myport );
369                         fprintf( fp, ".\r\n" );
370                         rewind(fp);
371                         exit( 1 );
372                 }
373
374                 ld->ld_deref = GO500_DEREF;
375                 if ( (rc = ldap_simple_bind_s( ld, GO500_BINDDN, NULL ))
376                     != LDAP_SUCCESS ) {
377                         fprintf(fp,
378                             "0An error occurred (explanation)\t@%d\t%s\t%d\r\n",
379                             rc, myhost, myport );
380                         fprintf( fp, ".\r\n" );
381                         rewind(fp);
382                         exit( 1 );
383                 }
384         }
385
386         switch ( *query ) {
387         case '~':
388                 fprintf( fp, "The query you specified was not specific enough, causing a size limit\r\n" );
389                 fprintf( fp, "to be exceeded and the first several matches found to be returned.\r\n" );
390                 fprintf( fp, "If you did not find the match you were looking for, try issuing a more\r\n" );
391                 fprintf( fp, "specific query, for example one that contains both first and last name.\r\n" );
392                 fprintf( fp, ".\r\n" );
393                 break;
394
395         case '=':
396                 do_read( ld, fp, ++query );
397                 break;
398
399         case '@':
400                 do_error( fp, ++query );
401                 break;
402
403         default:
404                 do_search( ld, fp, query );
405                 break;
406         }
407
408         fprintf( fp, ".\r\n" );
409         rewind(fp);
410         ldap_unbind( ld );
411
412         exit( 1 );
413         /* NOT REACHED */
414 }
415
416 static
417 do_error( fp, s )
418 FILE    *fp;
419 char    *s;
420 {
421         int     code;
422
423         code = atoi( s );
424
425         fprintf( fp, "An error occurred searching X.500.  The error code was %d\r\n", code );
426         fprintf( fp, "The corresponding error is: %s\r\n", ldap_err2string( code ) );
427         fprintf( fp, "No additional information is available\r\n" );
428         fprintf( fp, ".\r\n" );
429 }
430
431 static
432 do_search( ld, fp, buf )
433 LDAP    *ld;
434 FILE    *fp;
435 char    *buf;
436 {
437         char            *dn, *rdn;
438         char            **title;
439         int             rc, matches = 0;
440         struct timeval  tv;
441         LDAPFiltInfo    *fi;
442         LDAPFiltDesc    *filtd;
443         LDAPMessage     *e, *res;
444         static char     *attrs[] = { "title", 0 };
445
446 #ifdef GO500_UFN
447         if ( strchr( buf, ',' ) != NULL ) {
448                 ldap_ufn_setprefix( ld, base );
449                 tv.tv_sec = GO500_TIMEOUT;
450                 tv.tv_usec = 0;
451                 ldap_ufn_timeout( (void *) &tv );
452
453                 if ( (rc = ldap_ufn_search_s( ld, buf, attrs, 0, &res ))
454                     != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED ) {
455                         fprintf(fp,
456                             "0An error occurred (explanation)\t@%d\t%s\t%d\r\n",
457                             rc, myhost, myport );
458                         return;
459                 }
460
461                 matches = ldap_count_entries( ld, res );
462         } else {
463 #endif
464                 if ( (filtd = ldap_init_getfilter( filterfile )) == NULL ) {
465                         fprintf( stderr, "Cannot open filter file (%s)\n",
466                             filterfile );
467                         exit( 1 );
468                 }
469
470                 tv.tv_sec = GO500_TIMEOUT;
471                 tv.tv_usec = 0;
472                 for ( fi = ldap_getfirstfilter( filtd, "go500", buf );
473                     fi != NULL;
474                     fi = ldap_getnextfilter( filtd ) )
475                 {
476                         if ( (rc = ldap_search_st( ld, base, LDAP_SCOPE_SUBTREE,
477                             fi->lfi_filter, attrs, 0, &tv, &res ))
478                             != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED ) {
479                                 fprintf(fp, "0An error occurred (explanation)\t@%d\t%s\t%d\r\n",
480                                     rc, myhost, myport );
481                                 ldap_getfilter_free( filtd );
482                                 return;
483                         }
484
485                         if ( (matches = ldap_count_entries( ld, res )) != 0 )
486                                 break;
487                 }
488                 ldap_getfilter_free( filtd );
489 #ifdef GO500_UFN
490         }
491 #endif
492
493         if ( matches <= 0 ) {
494                 return;
495         }
496
497 #ifdef GO500_SORT_ATTR
498         ldap_sort_entries( ld, &res, GO500_SORT_ATTR, strcasecmp );
499 #endif
500
501         for ( e = ldap_first_entry( ld, res ); e != NULL;
502             e = ldap_next_entry( ld, e ) ) {
503                 char    *s;
504
505                 dn = ldap_get_dn( ld, e );
506                 rdn = strdup( dn );
507                 if ( (s = strchr( rdn, ',' )) != NULL )
508                         *s = '\0';
509
510                 if ( (s = strchr( rdn, '=' )) == NULL )
511                         s = rdn;
512                 else
513                         ++s;
514
515                 title = ldap_get_values( ld, e, "title" );
516
517                 if ( title != NULL ) {
518                         char    *p;
519
520                         for ( p = title[0]; *p; p++ ) {
521                                 if ( *p == '/' )
522                                         *p = '\\';
523                         }
524                 }
525
526                 fprintf( fp, "0%-20s    %s\t=%s\t%s\t%d\r\n", s,
527                     title ? title[0] : "", dn, myhost, myport );
528
529                 if ( title != NULL )
530                         ldap_value_free( title );
531
532                 free( rdn );
533                 free( dn );
534         }
535
536         if ( ldap_result2error( ld, res, 1 ) == LDAP_SIZELIMIT_EXCEEDED ) {
537                 fprintf( fp, "0A size limit was exceeded (explanation)\t~\t%s\t%d\r\n",
538                     myhost, myport );
539         }
540 }
541
542 static int
543 entry2textwrite( void *fp, char *buf, int len )
544 {
545         return( fwrite( buf, len, 1, (FILE *)fp ) == 0 ? -1 : len );
546 }
547
548 static
549 do_read( ld, fp, dn )
550 LDAP    *ld;
551 FILE    *fp;
552 char    *dn;
553 {
554         static struct ldap_disptmpl *tmpllist;
555
556         ldap_init_templates( templatefile, &tmpllist );
557
558         if ( ldap_entry2text_search( ld, dn, base, NULL, tmpllist, NULL, NULL,
559             entry2textwrite, (void *) fp, "\r\n", rdncount,
560             LDAP_DISP_OPT_DOSEARCHACTIONS ) != LDAP_SUCCESS ) {
561                 ldap_perror( ld, "ldap_entry2text_search" );
562                 exit( 1 );
563         }
564
565         if ( tmpllist != NULL ) {
566                 ldap_free_templates( tmpllist );
567         }
568 }