]> git.sur5r.net Git - openldap/blob - clients/finger/main.c
Merge from LAMBERT branch
[openldap] / clients / finger / main.c
1 /*
2  * Copyright (c) 1990,1994 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 "lber.h"
14 #include "ldap.h"
15 #include "disptmpl.h"
16 #include <stdio.h>
17 #include <string.h>
18 #include <ctype.h>
19 #include <sys/types.h>
20 #include <sys/time.h>
21 #include <sys/socket.h>
22 #include <netinet/in.h>
23 #include <arpa/inet.h>
24 #include <netdb.h>
25 #include <syslog.h>
26 #include <sys/resource.h>
27 #include <sys/wait.h>
28 #ifdef aix
29 #include <sys/select.h>
30 #endif /* aix */
31 #include <signal.h>
32 #include "portable.h"
33 #include "ldapconfig.h"
34
35 #ifdef USE_SYSCONF
36 #include <unistd.h>
37 #endif /* USE_SYSCONF */
38
39 int     dosyslog = 1;
40 char    *ldaphost = LDAPHOST;
41 int     ldapport = LDAP_PORT;
42 char    *base = FINGER_BASE;
43 int     deref;
44 char    *filterfile = FILTERFILE;
45 char    *templatefile = TEMPLATEFILE;
46 int     rdncount = FINGER_RDNCOUNT;
47
48 static do_query();
49 static do_search();
50 static do_read();
51 static print_attr();
52
53 static usage( name )
54 char    *name;
55 {
56         fprintf( stderr, "usage: %s [-l] [-x ldaphost] [-p ldapport] [-f filterfile] [-t templatefile] [-c rdncount]\r\n", name );
57         exit( 1 );
58 }
59
60 main (argc, argv)
61 int     argc;
62 char    **argv;
63 {
64         int                     i;
65         char                    *myname;
66         unsigned long           mypeer = -1;
67         struct hostent          *hp;
68         struct sockaddr_in      peername;
69         int                     peernamelen;
70         int                     interactive = 0;
71         extern char             *optarg;
72
73         deref = FINGER_DEREF;
74         while ( (i = getopt( argc, argv, "f:ilp:t:x:p:c:" )) != EOF ) {
75                 switch( i ) {
76                 case 'f':       /* ldap filter file */
77                         filterfile = strdup( optarg );
78                         break;
79
80                 case 'i':       /* interactive */
81                         interactive = 1;
82                         break;
83
84                 case 'l':       /* don't do syslogging */
85                         dosyslog = 0;
86                         break;
87
88                 case 't':       /* ldap template file */
89                         templatefile = strdup( optarg );
90                         break;
91
92                 case 'x':       /* specify ldap host */
93                         ldaphost = strdup( optarg );
94                         break;
95
96                 case 'p':       /* specify ldap port */
97                         ldapport = atoi( optarg );
98                         break;
99
100                 case 'c':       /* specify number of DN components to show */
101                         rdncount = atoi( optarg );
102                         break;
103
104                 default:
105                         usage( argv[0] );
106                 }
107         }
108
109         if ( !interactive ) {
110                 peernamelen = sizeof(peername);
111                 if ( getpeername( 0, (struct sockaddr *)&peername,
112                     &peernamelen ) != 0 ) {
113                         perror( "getpeername" );
114                         exit( 1 );
115                 }
116                 mypeer = (unsigned long) peername.sin_addr.s_addr;
117         }
118
119 #ifdef FINGER_BANNER
120         if ( FINGER_BANNER != NULL && strcmp( FINGER_BANNER, "" ) != 0 ) {
121                 printf( FINGER_BANNER );
122                 fflush( stdout );
123         }
124 #endif
125
126         if ( (myname = strrchr( argv[0], '/' )) == NULL )
127                 myname = strdup( argv[0] );
128         else
129                 myname = strdup( myname + 1 );
130
131         if ( dosyslog ) {
132 #ifdef LOG_LOCAL4
133                 openlog( myname, OPENLOG_OPTIONS, LOG_LOCAL4 );
134 #else
135                 openlog( myname, OPENLOG_OPTIONS );
136 #endif
137         }
138
139         if ( dosyslog && mypeer != -1 ) {
140                 struct in_addr  addr;
141
142                 hp = gethostbyaddr( (char *) &mypeer, sizeof(mypeer), AF_INET );
143                 addr.s_addr = mypeer;
144                 syslog( LOG_INFO, "connection from %s (%s)", (hp == NULL) ?
145                     "unknown" : hp->h_name, inet_ntoa( addr ) );
146         }
147
148         do_query();
149
150         return( 0 );
151 }
152
153 static do_query()
154 {
155         char            buf[256];
156         int             len, rc, tblsize;
157         struct timeval  timeout;
158         fd_set          readfds;
159         LDAP            *ld;
160
161         if ( (ld = ldap_open( ldaphost, ldapport )) == NULL ) {
162                 fprintf( stderr, FINGER_UNAVAILABLE );
163                 perror( "ldap_open" );
164                 exit( 1 );
165         }
166         ld->ld_sizelimit = FINGER_SIZELIMIT;
167         ld->ld_deref = deref;
168
169         if ( ldap_simple_bind_s( ld, FINGER_BINDDN, NULL ) != LDAP_SUCCESS ) {
170                 fprintf( stderr, FINGER_UNAVAILABLE );
171                 ldap_perror( ld, "ldap_simple_bind_s" );
172                 exit( 1 );
173         }
174
175 #ifdef FD_SETSIZE
176         /*
177          * It is invalid to use a set size in excess of the type
178          * scope, as defined for the fd_set in sys/types.h.  This
179          * is true for any OS.
180          */
181         tblsize = FD_SETSIZE;
182 #else   /* !FD_SETSIZE*/
183 #ifdef USE_SYSCONF
184         tblsize = sysconf( _SC_OPEN_MAX );
185 #else /* USE_SYSCONF */
186         tblsize = getdtablesize();
187 #endif /* USE_SYSCONF */
188 #endif  /* !FD_SETSIZE*/
189
190         timeout.tv_sec = FINGER_TIMEOUT;
191         timeout.tv_usec = 0;
192         FD_ZERO( &readfds );
193         FD_SET( fileno( stdin ), &readfds );
194
195         if ( (rc = select( tblsize, &readfds, 0, 0, &timeout )) <= 0 ) {
196                 if ( rc < 0 )
197                         perror( "select" );
198                 else
199                         fprintf( stderr, "connection timed out on input\r\n" );
200                 exit( 1 );
201         }
202
203         if ( fgets( buf, sizeof(buf), stdin ) == NULL )
204                 exit( 1 );
205
206         len = strlen( buf );
207
208         /* strip off \r \n */
209         if ( buf[len - 1] == '\n' ) {
210                 buf[len - 1] = '\0';
211                 len--;
212         }
213         if ( buf[len - 1] == '\r' ) {
214                 buf[len - 1] = '\0';
215                 len--;
216         }
217
218         if ( len == 0 ) {
219                 printf( "No campus-wide login information available.  Info for this machine only:\r\n" );
220                 fflush( stdout );
221                 execl( FINGER_CMD, FINGER_CMD, NULL );
222         } else {
223                 char    *p;
224
225                 /* skip and ignore stinking /w */
226                 if ( strncmp( buf, "/W ", 2 ) == 0 ) {
227                         p = buf + 2;
228                 } else {
229                         p = buf;
230                 }
231
232                 for ( ; *p && isspace( *p ); p++ )
233                         ;       /* NULL */
234
235                 do_search( ld, p );
236         }
237 }
238
239 static void
240 spaces2dots( s )
241     char        *s;
242 {
243         for ( ; *s; s++ ) {
244                 if ( *s == ' ' ) {
245                         *s = '.';
246                 }
247         }
248 }
249
250 static do_search( ld, buf )
251 LDAP    *ld;
252 char    *buf;
253 {
254         char            *dn, *rdn;
255         char            **title;
256         int             rc, matches, i, ufn;
257         struct timeval  tv;
258         LDAPFiltInfo    *fi;
259         LDAPMessage     *result, *e;
260         static char     *attrs[] = { "cn", "title", "objectClass", "joinable",
261 #ifdef FINGER_SORT_ATTR
262                                         FINGER_SORT_ATTR,
263 #endif
264                                         0 };
265         extern int      strcasecmp();
266
267         ufn = 0;
268 #ifdef FINGER_UFN
269         if ( strchr( buf, ',' ) != NULL ) {
270                 ldap_ufn_setprefix( ld, base );
271                 tv.tv_sec = FINGER_TIMEOUT;
272                 tv.tv_usec = 0;
273                 ldap_ufn_timeout( (void *) &tv );
274
275                 if ( (rc = ldap_ufn_search_s( ld, buf, attrs, 0, &result ))
276                     != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED ) {
277                         fprintf( stderr, FINGER_UNAVAILABLE );
278                         ldap_perror( ld, "ldap_search_st" );
279                         exit( 1 );
280                 }
281
282                 matches = ldap_count_entries( ld, result );
283                 ufn = 1;
284         } else {
285 #endif
286                 if ( (ld->ld_filtd = ldap_init_getfilter( filterfile ))
287                     == NULL ) {
288                         fprintf( stderr, "Cannot open filter file (%s)\n",
289                             filterfile );
290                         exit( 1 );
291                 }
292
293                 for ( fi = ldap_getfirstfilter( ld->ld_filtd, "finger", buf );
294                     fi != NULL;
295                     fi = ldap_getnextfilter( ld->ld_filtd ) )
296                 {
297                         tv.tv_sec = FINGER_TIMEOUT;
298                         tv.tv_usec = 0;
299                         if ( (rc = ldap_search_st( ld, base, LDAP_SCOPE_SUBTREE,
300                             fi->lfi_filter, attrs, 0, &tv, &result ))
301                             != LDAP_SUCCESS && rc != LDAP_SIZELIMIT_EXCEEDED
302                             && rc != LDAP_TIMELIMIT_EXCEEDED )
303                         {
304                                 fprintf( stderr, FINGER_UNAVAILABLE );
305                                 ldap_perror( ld, "ldap_search_st" );
306                                 exit( 1 );
307                         }
308
309                         if ( (matches = ldap_count_entries( ld, result )) != 0 )
310                                 break;
311
312                         ldap_msgfree( result );
313                         result = NULL;
314                 }
315 #ifdef FINGER_UFN
316         }
317 #endif
318
319         if ( rc == LDAP_SIZELIMIT_EXCEEDED ) {
320                 printf( "(Partial results - a size limit was exceeded)\r\n" );
321         } else if ( rc == LDAP_TIMELIMIT_EXCEEDED ) {
322                 printf( "(Partial results - a time limit was exceeded)\r\n" );
323         }
324
325         if ( matches == 0 ) {
326                 printf( FINGER_NOMATCH );
327                 fflush( stdout );
328         } else if ( matches < 0 ) {
329                 fprintf( stderr, "error return from ldap_count_entries\r\n" );
330                 exit( 1 );
331         } else if ( matches <= FINGER_LISTLIMIT ) {
332                 printf( "%d %s match%s found for \"%s\":\r\n", matches,
333                     ufn ? "UFN" : fi->lfi_desc, matches > 1 ? "es" : "", buf );
334                 fflush( stdout );
335
336                 for ( e = ldap_first_entry( ld, result ); e != NULL; ) {
337                         do_read( ld, e );
338                         e = ldap_next_entry( ld, e );
339                         if ( e != NULL ) {
340                                 printf( "--------------------\r\n" );
341                         }
342                 }
343         } else {
344                 printf( "%d %s matches for \"%s\":\r\n", matches,
345                     ufn ? "UFN" : fi->lfi_desc, buf );
346                 fflush( stdout );
347
348 #ifdef FINGER_SORT_ATTR
349                 ldap_sort_entries( ld, &result, FINGER_SORT_ATTR, strcasecmp );
350 #endif
351
352                 for ( e = ldap_first_entry( ld, result ); e != NULL;
353                     e = ldap_next_entry( ld, e ) ) {
354                         char    *p;
355
356                         dn = ldap_get_dn( ld, e );
357                         rdn = dn;
358                         if ( (p = strchr( dn, ',' )) != NULL )
359                                 *p = '\0';
360                         while ( *rdn && *rdn != '=' )
361                                 rdn++;
362                         if ( *rdn )
363                                 rdn++;
364
365                         /* hack attack */
366                         for ( i = 0; buf[i] != '\0'; i++ ) {
367                                 if ( buf[i] == '.' || buf[i] == '_' )
368                                         buf[i] = ' ';
369                         }
370                         if ( strcasecmp( rdn, buf ) == 0 ) {
371                                 char    **cn;
372                                 int     i, last;
373
374                                 cn = ldap_get_values( ld, e, "cn" );
375                                 for ( i = 0; cn[i] != NULL; i++ ) {
376                                         last = strlen( cn[i] ) - 1;
377                                         if ( isdigit( cn[i][last] ) ) {
378                                                 rdn = strdup( cn[i] );
379                                                 break;
380                                         }
381                                 }
382                         }
383                                         
384                         title = ldap_get_values( ld, e, "title" );
385
386                         spaces2dots( rdn );
387                         printf( "  %-20s    %s\r\n", rdn,
388                             title ? title[0] : "" );
389                         if ( title != NULL ) {
390                                 for ( i = 1; title[i] != NULL; i++ )
391                                         printf( "  %-20s    %s\r\n", "",
392                                             title[i] );
393                         }
394                         fflush( stdout );
395
396                         if ( title != NULL )
397                                 ldap_value_free( title );
398
399                         free( dn );
400                 }
401         }
402
403         if ( result != NULL ) {
404                 ldap_msgfree( result );
405         }
406         ldap_unbind( ld );
407 }
408
409
410 static int
411 entry2textwrite( void *fp, char *buf, int len )
412 {
413         return( fwrite( buf, len, 1, (FILE *)fp ) == 0 ? -1 : len );
414 }
415
416
417 static do_read( ld, e )
418 LDAP            *ld;
419 LDAPMessage     *e;
420 {
421         static struct ldap_disptmpl *tmpllist;
422         static char     *defattrs[] = { "mail", NULL };
423         static char     *mailvals[] = FINGER_NOEMAIL;
424         static char     **defvals[] = { mailvals, NULL };
425
426         ldap_init_templates( templatefile, &tmpllist );
427
428         if ( ldap_entry2text_search( ld, NULL, base, e, tmpllist, defattrs,
429             defvals, entry2textwrite, (void *)stdout, "\r\n", rdncount,
430             LDAP_DISP_OPT_DOSEARCHACTIONS ) != LDAP_SUCCESS ) {
431                 ldap_perror( ld, "ldap_entry2text_search" );
432                 exit( 1 );
433         }
434
435         if ( tmpllist != NULL ) {
436             ldap_free_templates( tmpllist );
437         }
438 }