]> git.sur5r.net Git - openldap/blob - clients/gopher/go500gw.c
bf25933d3fda1d61f6a4e5a060a593510e240411
[openldap] / clients / gopher / go500gw.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 #include <sys/resource.h>
29
30 #ifdef HAVE_SYS_PARAM_H
31 #include <sys/param.h>
32 #endif
33
34 #include "lber.h"
35 #include "ldap.h"
36 #include "ldap_log.h"
37 #include "lutil.h"
38
39 #include "disptmpl.h"
40
41 #include "ldapconfig.h"
42
43 int     debug;
44 int     dosyslog;
45 int     inetd;
46 int     dtblsize;
47
48 char            *ldaphost = LDAPHOST;
49 int             ldapport = LDAP_PORT;
50 int             searchaliases = 1;
51 char            *helpfile = GO500GW_HELPFILE;
52 char            *filterfile = FILTERFILE;
53 char            *templatefile = TEMPLATEFILE;
54 char            *friendlyfile = FRIENDLYFILE;
55 int             rdncount = GO500GW_RDNCOUNT;
56
57 static set_socket();
58 static RETSIGTYPE wait4child();
59 static do_queries();
60 static do_menu();
61 static do_list();
62 static do_search();
63 static do_read();
64 static do_help();
65 static do_sizelimit();
66 static do_error();
67 extern int strcasecmp();
68
69 char    myhost[MAXHOSTNAMELEN];
70 int     myport = GO500GW_PORT;
71
72 static usage( name )
73 char    *name;
74 {
75         fprintf( stderr, "usage: %s [-d debuglevel] [-I] [-p port] [-P ldapport] [-l]\r\n\t[-x ldaphost] [-a] [-h helpfile] [-f filterfile] [-t templatefile] [-c rdncount]\r\n", name );
76         exit( 1 );
77 }
78
79 main (argc, argv)
80 int     argc;
81 char    **argv;
82 {
83         int                     s, ns, rc;
84         int                     port = -1;
85         int                     i, pid;
86         char                    *myname;
87         fd_set                  readfds;
88         struct hostent          *hp;
89         struct sockaddr_in      from;
90         int                     fromlen;
91         RETSIGTYPE                      wait4child();
92         extern char             *optarg;
93
94 #if defined( LDAP_PROCTITLE ) && !defined( HAVE_SETPROCTITLE )
95         /* for setproctitle */
96         Argv = argv;
97         Argc = argc;
98 #endif
99
100         while ( (i = getopt( argc, argv, "P:ad:f:h:lp:t:x:Ic:" )) != EOF ) {
101                 switch( i ) {
102                 case 'a':       /* search aliases */
103                         searchaliases = 0;
104                         break;
105
106                 case 'd':       /* debugging level */
107                         debug = atoi( optarg );
108 #ifdef LDAP_DEBUG
109                         ldap_debug = debug;
110 #else
111                         fprintf( stderr, "warning: ldap debugging requires LDAP_DEBUG\n" );
112 #endif
113                         break;
114
115                 case 'f':       /* ldap filter file */
116                         filterfile = strdup( optarg );
117                         break;
118
119                 case 'h':       /* gopher help file */
120                         helpfile = strdup( optarg );
121                         break;
122
123                 case 'l':       /* log to LOG_LOCAL3 */
124                         dosyslog = 1;
125                         break;
126
127                 case 'p':       /* port to listen on */
128                         port = atoi( optarg );
129                         break;
130
131                 case 'P':       /* port to connect to ldap server */
132                         ldapport = atoi( optarg );
133                         break;
134
135                 case 't':       /* ldap template file */
136                         templatefile = strdup( optarg );
137                         break;
138
139                 case 'x':       /* ldap server hostname */
140                         ldaphost = strdup( optarg );
141                         break;
142
143                 case 'I':       /* run from inetd */
144                         inetd = 1;
145                         break;
146
147                 case 'c':       /* count of DN components to show */
148                         rdncount = atoi( optarg );
149                         break;
150
151                 default:
152                         usage( argv[0] );
153                 }
154         }
155
156 #ifdef HAVE_SYSCONF
157         dtblsize = sysconf( _SC_OPEN_MAX );
158 #elif HAVE_GETDTABLESIZE
159         dtblsize = getdtablesize();
160 #else
161         dtblsize = FD_SETSIZE;
162 #endif
163
164 #ifdef FD_SETSIZE
165         if ( dtblsize > FD_SETSIZE ) {
166                 dtblsize = FD_SETSIZE;
167         }
168 #endif  /* FD_SETSIZE*/
169
170
171
172 #ifdef GO500GW_HOSTNAME
173         strcpy( myhost, GO500GW_HOSTNAME );
174 #else
175         if ( myhost[0] == '\0' && gethostname( myhost, sizeof(myhost) )
176             == -1 ) {
177                 perror( "gethostname" );
178                 exit( 1 );
179         }
180 #endif
181
182         /* detach if stderr is redirected or no debugging */
183         if ( inetd == 0 )
184                 lutil_detach( debug && !isatty( 1 ), 1 );
185
186         if ( (myname = strrchr( argv[0], '/' )) == NULL )
187                 myname = strdup( argv[0] );
188         else
189                 myname = strdup( myname + 1 );
190
191         if ( dosyslog ) {
192 #ifdef LOG_LOCAL3
193                 openlog( myname, OPENLOG_OPTIONS, LOG_LOCAL3 );
194 #else
195                 openlog( myname, OPENLOG_OPTIONS );
196 #endif
197         }
198         if ( dosyslog )
199                 syslog( LOG_INFO, "initializing" );
200
201         /* set up the socket to listen on */
202         if ( inetd == 0 ) {
203                 s = set_socket( port );
204
205                 /* arrange to reap children */
206                 (void) SIGNAL( SIGCHLD, wait4child );
207         }
208
209         if ( inetd ) {
210                 fromlen = sizeof(from);
211                 if ( getpeername( 0, (struct sockaddr *) &from, &fromlen )
212                     == 0 ) {
213                         hp = gethostbyaddr( (char *) &(from.sin_addr.s_addr),
214                             sizeof(from.sin_addr.s_addr), AF_INET );
215                         Debug( LDAP_DEBUG_ARGS, "connection from %s (%s)\n",
216                             (hp == NULL) ? "unknown" : hp->h_name,
217                             inet_ntoa( from.sin_addr ), 0 );
218
219                         if ( dosyslog ) {
220                                 syslog( LOG_INFO, "connection from %s (%s)",
221                                     (hp == NULL) ? "unknown" : hp->h_name,
222                                     inet_ntoa( from.sin_addr ) );
223                         }
224
225 #ifdef LDAP_PROCTITLE
226                         setproctitle( hp == NULL ? inet_ntoa( from.sin_addr ) :
227                             hp->h_name );
228 #endif
229                 }
230
231                 do_queries( 0 );
232
233                 close( 0 );
234
235                 exit( 0 );
236         }
237
238         for ( ;; ) {
239                 FD_ZERO( &readfds );
240                 FD_SET( s, &readfds );
241
242                 if ( (rc = select( dtblsize, &readfds, 0, 0 ,0 )) == -1 ) {
243                         if ( debug ) perror( "select" );
244                         continue;
245                 } else if ( rc == 0 ) {
246                         continue;
247                 }
248
249                 if ( ! FD_ISSET( s, &readfds ) )
250                         continue;
251
252                 fromlen = sizeof(from);
253                 if ( (ns = accept( s, (struct sockaddr *) &from, &fromlen ))
254                     == -1 ) {
255                         if ( debug ) perror( "accept" );
256                         exit( 1 );
257                 }
258
259                 hp = gethostbyaddr( (char *) &(from.sin_addr.s_addr),
260                     sizeof(from.sin_addr.s_addr), AF_INET );
261
262                 if ( dosyslog ) {
263                         syslog( LOG_INFO, "TCP connection from %s (%s)",
264                             (hp == NULL) ? "unknown" : hp->h_name,
265                             inet_ntoa( from.sin_addr ) );
266                 }
267
268                 switch( pid = fork() ) {
269                 case 0:         /* child */
270                         close( s );
271                         do_queries( ns );
272                         break;
273
274                 case -1:        /* failed */
275                         perror( "fork" );
276                         break;
277
278                 default:        /* parent */
279                         close( ns );
280                         if ( debug )
281                                 fprintf( stderr, "forked child %d\n", pid );
282                         break;
283                 }
284         }
285         /* NOT REACHED */
286 }
287
288 static set_socket( port )
289 int     port;
290 {
291         int                     s, one;
292         struct sockaddr_in      addr;
293
294         if ( port == -1 )
295                 port = GO500GW_PORT;
296         myport = port;
297
298         if ( (s = socket( AF_INET, SOCK_STREAM, 0 )) == -1 ) {
299                 perror( "socket" );
300                 exit( 1 );
301         }
302
303         /* set option so clients can't keep us from coming back up */
304         one = 1;
305         if ( setsockopt( s, SOL_SOCKET, SO_REUSEADDR, (char *) &one,
306             sizeof(one) ) < 0 ) {
307                 perror( "setsockopt" );
308                 exit( 1 );
309         }
310
311         /* bind to a name */
312         addr.sin_family = AF_INET;
313         addr.sin_addr.s_addr = INADDR_ANY;
314         addr.sin_port = htons( port );
315         if ( bind( s, (struct sockaddr *) &addr, sizeof(addr) ) ) {
316                 perror( "bind" );
317                 exit( 1 );
318         }
319
320         /* listen for connections */
321         if ( listen( s, 5 ) == -1 ) {
322                 perror( "listen" );
323                 exit( 1 );
324         }
325
326         if ( debug )
327                 printf( "go500gw listening on port %d\n", port );
328
329         return( s );
330 }
331
332 static RETSIGTYPE
333 wait4child()
334 {
335 #ifndef HAVE_WAITPID
336         WAITSTATUSTYPE     status;
337 #endif
338
339         if ( debug ) printf( "parent: catching child status\n" );
340
341 #ifdef HAVE_WAITPID
342         while (waitpid ((pid_t) -1, NULL, WAIT_FLAGS) > 0)
343                 ;       /* NULL */
344 #else 
345         while (wait3( &status, WAIT_FLAGS, 0 ) > 0 )
346                 ;       /* NULL */
347 #endif
348
349         (void) SIGNAL( SIGCHLD, wait4child );
350 }
351
352 static do_queries( s )
353 int     s;
354 {
355         char            buf[1024], *query;
356         int             len;
357         FILE            *fp;
358         int             rc;
359         int             deref;
360         struct timeval  timeout;
361         fd_set          readfds;
362         LDAP            *ld;
363
364         if ( (fp = fdopen( s, "a+")) == NULL ) {
365                 perror( "fdopen" );
366                 exit( 1 );
367         }
368
369         timeout.tv_sec = GO500GW_TIMEOUT;
370         timeout.tv_usec = 0;
371         FD_ZERO( &readfds );
372         FD_SET( fileno( fp ), &readfds );
373
374         if ( (rc = select( dtblsize, &readfds, 0, 0, &timeout )) <= 0 )
375                 exit( 1 );
376
377         if ( fgets( buf, sizeof(buf), fp ) == NULL )
378                 exit( 1 );
379
380         len = strlen( buf );
381         if ( debug ) {
382                 fprintf( stderr, "got %d bytes\n", len );
383 #ifdef LDAP_DEBUG
384                 lber_bprint( buf, len );
385 #endif
386         }
387
388         /* strip of \r \n */
389         if ( buf[len - 1] == '\n' )
390                 buf[len - 1] = '\0';
391         len--;
392         if ( buf[len - 1] == '\r' )
393                 buf[len - 1] = '\0';
394         len--;
395
396         query = buf;
397
398         /* strip off leading white space */
399         while ( isspace( *query )) {
400                 ++query;
401                 --len;
402         }
403
404         rewind(fp);
405
406         if ( *query == 'H' || *query == 'L' || *query == 'E' ) {
407                 switch ( *query++ ) {
408                 case 'H':       /* help file */
409                         do_help( fp );
410                         break;
411
412                 case 'L':       /* size limit explanation */
413                         do_sizelimit( fp, *query );
414                         break;
415
416                 case 'E':       /* error explanation */
417                         do_error( fp, query );
418                         break;
419                 }
420
421                 fprintf( fp, ".\r\n" );
422                 rewind(fp);
423
424                 exit( 0 );
425                 /* NOT REACHED */
426         }
427
428         if ( (ld = ldap_open( ldaphost, ldapport )) == NULL ) {
429                 if ( debug ) perror( "ldap_open" );
430                 fprintf(fp, "0An error occurred (explanation)\tE%d\t%s\t%d\r\n",
431                     LDAP_SERVER_DOWN, myhost, myport );
432                 fprintf( fp, ".\r\n" );
433                 rewind(fp);
434                 exit( 1 );
435         }
436
437         deref = LDAP_DEREF_ALWAYS;
438         if ( !searchaliases )
439                 deref = LDAP_DEREF_FINDING;
440
441         ldap_set_option(ld, LDAP_OPT_DEREF, &deref);
442
443         if ( (rc = ldap_simple_bind_s( ld, GO500GW_BINDDN, NULL ))
444             != LDAP_SUCCESS ) {
445                 if ( debug ) ldap_perror( ld, "ldap_simple_bind_s" );
446                 fprintf(fp, "0An error occurred (explanation)\tE%d\t%s\t%d\r\n",
447                     rc, myhost, myport );
448                 fprintf( fp, ".\r\n" );
449                 rewind(fp);
450                 exit( 1 );
451         }
452
453         switch ( *query++ ) {
454         case 'R':       /* read an entry */
455                 do_read( ld, fp, query );
456                 break;
457
458         case 'S':       /* search */
459                 do_search( ld, fp, query, 1 );
460                 break;
461
462         case 'M':       /* X.500 menu */
463                 do_menu( ld, fp, query );
464                 break;
465
466         default:
467                 do_menu( ld, fp, "" );
468                 break;
469         }
470
471         fprintf( fp, ".\r\n" );
472         rewind(fp);
473
474         exit( 0 );
475         /* NOT REACHED */
476 }
477
478 static char *pick_oc( oclist )
479 char    **oclist;
480 {
481         int     i;
482
483         if ( oclist == NULL )
484                 return( "unknown" );
485
486         for ( i = 0; oclist[i] != NULL; i++ ) {
487                 if ( strcasecmp( oclist[i], "top" ) != 0 &&
488                     strcasecmp( oclist[i], "quipuObject" ) != 0 &&
489                     strcasecmp( oclist[i], "quipuNonLeafObject" ) != 0 )
490                         return( oclist[i] );
491         }
492
493         return( "unknown" );
494 }
495
496 static isnonleaf( ld, oclist, dn )
497 LDAP    *ld;
498 char    **oclist;
499 char    *dn;
500 {
501         int     i, quipuobject = 0;
502
503         if ( oclist == NULL )
504                 return( 0 );
505
506         for ( i = 0; oclist[i] != NULL; i++ ) {
507                 if ( strcasecmp( oclist[i], "quipuObject" ) == 0 )
508                         quipuobject = 1;
509                 if ( strcasecmp( oclist[i], "quipuNonLeafObject" ) == 0 ||
510                     strcasecmp( oclist[i], "externalNonLeafObject" ) == 0 )
511                         return( 1 );
512         }
513
514         /*
515          * not a quipu thang - no easy way to tell leaves from nonleaves
516          * except by trying to search or list.  ldap only lets us search.
517          */
518
519         /* expensive - just guess for now */
520         return( quipuobject ? 0 : 1 );
521
522 #ifdef notdef
523         if ( !quipuobject ) {
524                 int             rc, numentries;
525                 struct timeval  timeout;
526                 LDAPMessage     *res = NULL;
527                 static char     *attrs[] = { "objectClass", 0 };
528                 int sizelimit = 1;
529
530                 timeout.tv_sec = GO500GW_TIMEOUT;
531                 timeout.tv_usec = 0;
532                 ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &sizelimit);
533                 if ( (rc = ldap_search_st( ld, dn, LDAP_SCOPE_ONELEVEL,
534                     "(objectClass=*)", attrs, 0, &timeout, &res ))
535                     == LDAP_SUCCESS || rc == LDAP_SIZELIMIT_EXCEEDED ) {
536                         sizelimit = LDAP_NO_LIMIT;
537                         ldap_set_option(ld, LDAP_OPT_SIZELIMIT, &sizelimit);
538
539                         numentries = ldap_count_entries( ld, res );
540                         if ( res != NULL )
541                                 ldap_msgfree( res );
542                         return( numentries == 1 ? 1 : 0 );
543                 }
544         }
545
546         return( 0 );
547 #endif
548 }
549
550 static do_menu( ld, fp, dn )
551 LDAP    *ld;
552 FILE    *fp;
553 char    *dn;
554 {
555         char            **s;
556         char            *rdn = NULL;
557         FriendlyMap     *fm = NULL;
558
559         if ( strcmp( dn, "" ) != 0 ) {
560                 s = ldap_explode_dn( dn, 1 );
561
562                 if ( s[1] == NULL )
563                         rdn = ldap_friendly_name( friendlyfile, s[0], &fm );
564                 else
565                         rdn = s[0];
566                 fprintf( fp, "0Read %s entry\tR%s\t%s\t%d\r\n", rdn ? rdn: s[0],
567                     dn, myhost, myport );
568
569                 ldap_value_free( s );
570         } else {
571                 fprintf( fp, "0About the Gopher to X.500 Gateway\tH\t%s\t%d\r\n",
572                     myhost, myport );
573         }
574
575         fprintf( fp, "7Search %s\tS%s\t%s\t%d\r\n", rdn ? rdn : "root", dn,
576             myhost, myport );
577
578         do_list( ld, fp, dn );
579
580         ldap_free_friendlymap( &fm );
581 }
582
583 static do_list( ld, fp, dn )
584 LDAP    *ld;
585 FILE    *fp;
586 char    *dn;
587 {
588         int             rc;
589         LDAPMessage     *e, *res;
590         struct timeval  timeout;
591         FriendlyMap     *fm = NULL;
592         static char     *attrs[] = { "objectClass", 0 };
593         int deref = LDAP_DEREF_FINDING;
594
595         timeout.tv_sec = GO500GW_TIMEOUT;
596         timeout.tv_usec = 0;
597
598         ldap_set_option(ld, LDAP_OPT_DEREF, &deref);
599
600         if ( (rc = ldap_search_st( ld, dn, LDAP_SCOPE_ONELEVEL,
601             "(!(objectClass=dSA))", attrs, 0, &timeout, &res )) != LDAP_SUCCESS
602             && rc != LDAP_SIZELIMIT_EXCEEDED ) {
603                 fprintf(fp, "0An error occurred (explanation)\tE%d\t%s\t%d\r\n",
604                     rc, myhost, myport );
605                 return;
606         }
607
608         deref = LDAP_DEREF_ALWAYS;
609         ldap_set_option(ld, LDAP_OPT_DEREF, &deref);
610
611         if ( ldap_count_entries( ld, res ) < 1 ) {
612                 return;
613         }
614
615 #ifdef GO500GW_SORT_ATTR
616         ldap_sort_entries( ld, &res, GO500GW_SORT_ATTR, strcasecmp );
617 #endif
618
619         fm = NULL;
620         for ( e = ldap_first_entry( ld, res ); e != NULL;
621             e = ldap_next_entry( ld, e ) ) {
622                 char    **s, **oc;
623                 char    *rdn, *doc;
624
625                 dn = ldap_get_dn( ld, e );
626                 s = ldap_explode_dn( dn, 1 );
627                 oc = ldap_get_values( ld, e, "objectClass" );
628
629                 doc = pick_oc( oc );
630                 if ( strcasecmp( doc, "country" ) == 0 ) {
631                         rdn = ldap_friendly_name( friendlyfile, s[0], &fm );
632                 } else {
633                         rdn = s[0];
634                 }
635                 if ( rdn == NULL ) {
636                         rdn = s[0];
637                 }
638
639                 if ( strncasecmp( rdn, "{ASN}", 5 ) != 0 ) {
640                         if ( isnonleaf( ld, oc, dn ) ) {
641                                 fprintf( fp, "1%s (%s)\tM%s\t%s\t%d\r\n", rdn,
642                                     doc, dn, myhost, myport );
643                         } else {
644                                 fprintf( fp, "0%s (%s)\tR%s\t%s\t%d\r\n", rdn,
645                                     doc, dn, myhost, myport );
646                         }
647                 }
648
649                 free( dn );
650                 ldap_value_free( s );
651                 ldap_value_free( oc );
652         }
653         ldap_free_friendlymap( &fm );
654
655         if ( ldap_result2error( ld, res, 1 ) == LDAP_SIZELIMIT_EXCEEDED ) {
656                 fprintf( fp, "0A size limit was exceeded (explanation)\tLL\t%s\t%d\r\n",
657                     myhost, myport );
658         }
659 }
660
661 static isoc( ocl, oc )
662 char    **ocl;
663 char    *oc;
664 {
665         int     i;
666
667         for ( i = 0; ocl[i] != NULL; i++ ) {
668                 if ( strcasecmp( ocl[i], oc ) == 0 )
669                         return( 1 );
670         }
671
672         return( 0 );
673 }
674
675 static int make_scope( ld, dn )
676 LDAP    *ld;
677 char    *dn;
678 {
679         int             scope;
680         char            **oc;
681         LDAPMessage     *res;
682         struct timeval  timeout;
683         static char     *attrs[] = { "objectClass", 0 };
684
685         if ( strcmp( dn, "" ) == 0 )
686                 return( LDAP_SCOPE_ONELEVEL );
687
688         timeout.tv_sec = GO500GW_TIMEOUT;
689         timeout.tv_usec = 0;
690         if ( ldap_search_st( ld, dn, LDAP_SCOPE_BASE, "objectClass=*",
691             attrs, 0, &timeout, &res ) != LDAP_SUCCESS ) {
692                 return( -1 );
693         }
694
695         oc = ldap_get_values( ld, ldap_first_entry( ld, res ), "objectClass" );
696
697         if ( isoc( oc, "organization" ) || isoc( oc, "organizationalUnit" ) )
698                 scope = LDAP_SCOPE_SUBTREE;
699         else
700                 scope = LDAP_SCOPE_ONELEVEL;
701
702         ldap_value_free( oc );
703         ldap_msgfree( res );
704
705         return( scope );
706 }
707
708 static do_search( ld, fp, query )
709 LDAP    *ld;
710 FILE    *fp;
711 char    *query;
712 {
713         int deref;
714         int             scope;
715         char            *base, *filter;
716         char            *filtertype;
717         int             count, rc;
718         struct timeval  timeout;
719         LDAPFiltInfo    *fi;
720         LDAPMessage     *e, *res;
721         LDAPFiltDesc    *filtd;
722         static char     *attrs[] = { "objectClass", 0 };
723
724         if ( (filter = strchr( query, '\t' )) == NULL ) {
725                 fprintf( fp, "3Missing filter!\r\n" );
726                 exit( 1 );
727         }
728         *filter++ = '\0';
729         base = query;
730
731 #ifdef GO500GW_UFN
732         if ( strchr( filter, ',' ) != NULL ) {
733                 ldap_ufn_setprefix( ld, base );
734                 timeout.tv_sec = GO500GW_TIMEOUT;
735                 timeout.tv_usec = 0;
736                 ldap_ufn_timeout( (void *) &timeout );
737
738                 deref = LDAP_DEREF_FINDING;
739                 ldap_set_option(ld, LDAP_OPT_DEREF, &deref);
740
741                 if ( (rc = ldap_ufn_search_s( ld, filter, attrs, 0, &res ))
742                     != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED ) {
743                         fprintf(fp,
744                             "0An error occurred (explanation)\t@%d\t%s\t%d\r\n",
745                             rc, myhost, myport );
746                         return;
747                 }
748
749                 count = ldap_count_entries( ld, res );
750         } else {
751 #endif
752                 if ( (scope = make_scope( ld, base )) == -1 ) {
753                         fprintf( fp, "3Bad scope\r\n" );
754                         exit( 1 );
755                 }
756
757                 filtertype = (scope == LDAP_SCOPE_ONELEVEL ?
758                     "go500gw onelevel" : "go500gw subtree");
759                 deref = (scope == LDAP_SCOPE_ONELEVEL ?
760                     LDAP_DEREF_FINDING : LDAP_DEREF_ALWAYS);
761                 ldap_set_option(ld, LDAP_OPT_DEREF, &deref);
762                 timeout.tv_sec = GO500GW_TIMEOUT;
763                 timeout.tv_usec = 0;
764
765                 if ( (filtd = ldap_init_getfilter( filterfile )) == NULL ) {
766                         fprintf( stderr, "Cannot open filter file (%s)\n",
767                             filterfile );
768                         exit( 1 );
769                 }
770
771                 count = 0;
772                 res = NULL;
773                 for ( fi = ldap_getfirstfilter( filtd, filtertype, filter );
774                     fi != NULL; fi = ldap_getnextfilter( filtd ) )
775                 {
776                         if ( (rc = ldap_search_st( ld, base, scope,
777                             fi->lfi_filter, attrs, 0, &timeout, &res ))
778                             != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED ) {
779                                 fprintf(fp, "0An error occurred (explanation)\tE%d\t%s\t%d\r\n",
780                                     rc, myhost, myport );
781                                 return( 1 );
782                         }
783                         if ( (count = ldap_count_entries( ld, res )) != 0 )
784                                 break;
785                 }
786                 deref = LDAP_DEREF_ALWAYS;
787                 ldap_set_option(ld, LDAP_OPT_DEREF, &deref);
788                 ldap_getfilter_free( filtd );
789 #ifdef GO500GW_UFN
790         }
791 #endif
792
793         if ( count == 0 ) {
794                 return( 0 );
795         }
796
797         if ( count == 1 ) {
798                 char    *dn, **s, **oc;
799                 int     rc;
800
801                 e = ldap_first_entry( ld, res );
802                 oc = ldap_get_values( ld, e, "objectClass" );
803                 dn = ldap_get_dn( ld, e );
804
805                 if ( isnonleaf( ld, oc, dn ) ) {
806                         rc = do_menu( ld, fp, dn );
807
808                         free( dn );
809                         return( rc );
810                 }
811
812                 free( dn );
813                 ldap_value_free( oc );
814         }
815
816 #ifdef GO500GW_SORT_ATTR
817         ldap_sort_entries( ld, &res, GO500GW_SORT_ATTR, strcasecmp );
818 #endif
819
820         for ( e = ldap_first_entry( ld, res ); e != NULL;
821             e = ldap_next_entry( ld, e ) ) {
822                 char    **s, **oc;
823                 char    *dn;
824
825                 dn = ldap_get_dn( ld, e );
826                 s = ldap_explode_dn( dn, 1 );
827                 oc = ldap_get_values( ld, e, "objectClass" );
828
829                 if ( isnonleaf( ld, oc, dn ) )
830                         fprintf( fp, "1%s (%s)\tM%s\t%s\t%d\r\n", s[0],
831                             pick_oc( oc ), dn, myhost, myport );
832                 else
833                         fprintf( fp, "0%s (%s)\tR%s\t%s\t%d\r\n", s[0],
834                             pick_oc( oc ), dn, myhost, myport );
835
836                 free( dn );
837                 ldap_value_free( s );
838                 ldap_value_free( oc );
839         }
840
841         if ( ldap_result2error( ld, res, 1 ) == LDAP_SIZELIMIT_EXCEEDED ) {
842                 fprintf( fp, "0A size limit was exceeded (explanation)\tLS\t%s\t%d\r\n",
843                     myhost, myport );
844         }
845 }
846
847
848 static int
849 entry2textwrite( void *fp, char *buf, int len )
850 {
851         return( fwrite( buf, len, 1, (FILE *)fp ) == 0 ? -1 : len );
852 }
853
854 static do_read( ld, fp, dn )
855 LDAP    *ld;
856 FILE    *fp;
857 char    *dn;
858 {
859         static struct ldap_disptmpl *tmpllist;
860
861         ldap_init_templates( templatefile, &tmpllist );
862
863         if ( ldap_entry2text_search( ld, dn, NULL, NULL, tmpllist, NULL, NULL,
864             entry2textwrite,(void *) fp, "\r\n", rdncount, 0 )
865             != LDAP_SUCCESS ) {
866                 int ld_errno = 0;
867                 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
868
869                 fprintf(fp,
870                     "0An error occurred (explanation)\t@%d\t%s\t%d\r\n",
871                     ld_errno, myhost, myport );
872         }
873
874         if ( tmpllist != NULL ) {
875                 ldap_free_templates( tmpllist );
876         }
877 }
878
879 static do_help( op )
880 FILE    *op;
881 {
882         FILE    *fp;
883         char    line[BUFSIZ];
884
885         if ( (fp = fopen( helpfile, "r" )) == NULL ) {
886                 fprintf( op, "Cannot access helpfile (%s)\r\n", helpfile );
887                 return;
888         }
889
890         while ( fgets( line, sizeof(line), fp ) != NULL ) {
891                 line[ strlen( line ) - 1 ] = '\0';
892
893                 fprintf( op, "%s\r\n", line );
894         }
895
896         fclose( fp );
897 }
898
899 static do_sizelimit( fp, type )
900 FILE    *fp;
901 char    type;
902 {
903         if ( type == 'S' ) {
904                 fprintf( fp, "The query you specified was not specific enough, causing a size limit\r\n" );
905                 fprintf( fp, "to be exceeded and the first several matches found to be returned.\r\n" );
906                 fprintf( fp, "If you did not find the match you were looking for, try issuing a more\r\n" );
907                 fprintf( fp, "specific query, for example one that contains both first and last name.\r\n" );
908         } else {
909                 fprintf( fp, "Not all entries could be returned because a size limit was exceeded.\r\n" );
910                 fprintf( fp, "There is no way to defeat this feature, but if you know who you are\r\n" );
911                 fprintf( fp, "looking for, try choosing the \"Search\" option listed above and\r\n" );
912                 fprintf( fp, "specifying the name of the person you want.\r\n" );
913         }
914         fprintf( fp, ".\r\n" );
915 }
916
917 static do_error( fp, s )
918 FILE    *fp;
919 char    *s;
920 {
921         int     code;
922
923         code = atoi( s );
924
925         fprintf( fp, "An error occurred searching X.500.  The error code was %d\r\n", code );
926         fprintf( fp, "The corresponding error is: %s\r\n", ldap_err2string( code ) );
927         fprintf( fp, "No additional information is available\r\n" );
928         fprintf( fp, ".\r\n" );
929 }