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