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