source: trunk/athena/bin/finger/finger.c @ 22842

Revision 22842, 33.7 KB checked in by tabbott, 16 years ago (diff)
In finger: * Merged quilt patches into mainline Athena tree
Line 
1/*
2 * Copyright 1987 by the Massachusetts Institute of Technology.
3 * For copying and distribution information, see the file
4 * "mit-copyright.h".
5 *
6 * $Id: finger.c,v 1.40 2005-06-27 03:33:42 zacheiss Exp $
7 */
8
9#ifndef lint
10static char *rcsid_finger_c = "$Id: finger.c,v 1.40 2005-06-27 03:33:42 zacheiss Exp $";
11#endif /*lint*/
12
13/*
14 * Copyright (c) 1980 Regents of the University of California.
15 * All rights reserved.  The Berkeley software License Agreement
16 * specifies the terms and conditions for redistribution.
17 */
18
19#ifndef lint
20char copyright[] =
21"@(#) Copyright (c) 1980 Regents of the University of California.\n\
22 All rights reserved.\n";
23
24#endif /*not lint*/
25
26#ifndef lint
27static char sccsid[] = "@(#)finger.c    5.8 (Berkeley) 3/13/86";
28
29#endif /*not lint */
30
31/*
32 * This is a finger program.  It prints out useful information about
33 * users by digging it up from various system files.  It is not very
34 * portable because the most useful parts of the information (the full
35 * user name, office, and phone numbers) are all stored in the
36 * VAX-unused gecos field of /etc/passwd, which, unfortunately, other
37 * UNIXes use for other things.
38 *
39 * There are three output formats, all of which give login name,
40 * teletype line number, and login time.  The short output format is
41 * reminiscent of finger on ITS, and gives one line of information per
42 * user containing in addition to the minimum basic requirements
43 * (MBR), the full name of the user, his idle time and office location
44 * and phone number.  The quick style output is UNIX who-like, giving
45 * only name, teletype and login time.  Finally, the long style output
46 * give the same information as the short (in more legible format),
47 * the home directory and shell of the user, and, if it exists, copies
48 * of the files .plan and .project in the user's home directory.
49 * Finger may be called with or without a list of people to finger --
50 * if no list is given, all the people currently logged in are
51 * fingered.
52 *
53 * The program is validly called by one of the following:
54 *
55 *      finger                  {short form list of users}
56 *      finger -l               {long form list of users}
57 *      finger -b               {briefer long form list of users}
58 *      finger -q               {quick list of users}
59 *      finger -i               {quick list of users with idle times}
60 *      finger namelist         {long format list of specified users}
61 *      finger -s namelist      {short format list of specified users}
62 *      finger -w namelist      {narrow short format list of specified users}
63 *
64 * where 'namelist' is a list of users login names.
65 * The other options can all be given after one '-', or each can have its
66 * own '-'.  The -f option disables the printing of headers for short and
67 * quick outputs.  The -b option briefens long format outputs.  The -p
68 * option turns off plans for long format outputs.
69 */
70
71#define _GNU_SOURCE /* Make UTMPX_FILE etc. visible on glibc systems */
72
73#include <sys/types.h>
74#include <sys/stat.h>
75#include <unistd.h>
76#include <fcntl.h>
77#include <string.h>
78#include <utmp.h>
79#include <signal.h>
80#include <pwd.h>
81#include <stdio.h>
82#include <stdlib.h>
83#include <ctype.h>
84#include <time.h>
85#include <sys/time.h>
86#include <sys/socket.h>
87#include <netinet/in.h>
88#include <netdb.h>
89#ifdef HAVE_UTMPX_H
90#include <utmpx.h>
91#endif
92#ifdef HAVE_LASTLOG_H
93#include <lastlog.h>
94#endif
95#ifdef HAVE_PATHS_H
96#include <paths.h>
97#endif
98#include <hesiod.h>
99#include <zephyr/zephyr.h>
100#include "mit-copyright.h"
101
102#define MAXTTYS 256
103#define MAXSEARCH 750
104
105#define NOIDLE -1               /* Magic number for unavailable idle time */
106#define CAPITALIZE      0137&   /* capitalize character macro */
107#define ASTERISK        '*'     /* ignore this in real name */
108#define COMMA           ','     /* separator in pw_gecos field */
109#define COMMAND         '-'     /* command line flag char */
110#define TECHSQ          'T'     /* tech square office */
111#define MIT             'M'     /* MIT office */
112#define SAMENAME        '&'     /* repeat login name in real name */
113#define TALKABLE        0220    /* tty is writable if 220 mode */
114#define MAILDIR         "/var/mail/"    /* default mail directory */
115
116#ifdef HAVE_UTMPX_H
117struct utmpx user;
118#define UTTIME(ut) (ut).ut_tv.tv_sec
119#else
120struct utmp user;
121#define UTTIME(ut) (ut).ut_time
122#endif
123
124#define NMAX sizeof(user.ut_name)
125#define LMAX sizeof(user.ut_line)
126#define HMAX sizeof(user.ut_host)
127#ifdef MIN
128#undef MIN
129#endif
130#define MIN(a,b) ((a) < (b) ? (a) : (b))
131
132struct person {                 /* one for each person fingered */
133        char *name;             /* name */
134        char tty[BUFSIZ];       /* null terminated tty line */
135        char host[BUFSIZ];      /* null terminated remote host name */
136        char logintime[BUFSIZ]; /* null terminated login time */
137        int loginout;           /* 0 means login time, 1 logout */
138        time_t loginat;         /* time of (last) login/out */
139        time_t idletime;        /* how long idle (if logged in) */
140        char *realname;         /* pointer to full name */
141        char *nickname;         /* pointer to nickname */
142        char *office;           /* pointer to office name */
143        char *officephone;      /* pointer to office phone no. */
144        char *homephone;        /* pointer to home phone no. */
145        char *random;           /* for any random stuff in pw_gecos */
146        struct passwd *pwd;     /* structure of /etc/passwd stuff */
147        int loggedin;           /* person is logged in */
148        char writable;          /* tty is writable */
149        int original;           /* this is not a duplicate entry */
150        struct person *link;    /* link to next person */
151        int zlocation;          /* found via Zephyr */
152};
153
154#if defined(HAVE_UTMPX_H)
155char USERLOG[] = UTMPX_FILE;            /* who is logged in */
156char ACCTLOG[] = WTMPX_FILE;            /* Accounting file */
157#elif defined(UTMP_FILE)
158char USERLOG[] = UTMP_FILE;
159char ACCTLOG[] = WTMP_FILE;
160#elif defined(_PATH_UTMP)
161char USERLOG[] = _PATH_UTMP;
162char ACCTLOG[] = _PATH_WTMP;
163#else
164char USERLOG[] = "/var/adm/utmp";
165char ACCTLOG[] = "/var/adm/wtmp";
166#endif
167
168#ifdef _PATH_LASTLOG
169char LASTLOG[] = _PATH_LASTLOG;         /* last login info */
170#else
171char LASTLOG[] = "/var/adm/lastlog";
172#endif
173
174char PLAN[] = "/.plan";         /* what plan file is */
175char PROJ[] = "/.project";      /* what project file */
176char MM[] = "%MENTION-MAIL%\n"; /* if present, check for mail */
177int MMLEN = 15;
178
179int unbrief = 1;                /* -b option default */
180int header = 1;                 /* -f option default */
181int hack = 1;                   /* -h option default */
182int idlep = 0;                  /* -i option default */
183int large = 0;                  /* -l option default */
184int match = 0;                  /* -m option default */
185int plan = 1;                   /* -p option default */
186int unquick = 1;                /* -q option default */
187int small = 0;                  /* -s option default */
188int wide = 1;                   /* -w option default */
189
190int numloc = 1;                 /* number of locations from zgetlocations */
191ZLocations_t location;          /* holds Zephyr locations */
192int znloc = 0;                  /* number of locations returned via a Zephyr
193                                 * lookup */
194int unshort;
195int lf = -1;                    /* LASTLOG file descriptor */
196int lw = -1;                    /* ACCTLOG file descriptor */
197
198/* !#$%!@#$! Bezerkeley non-initializations !!! */
199struct person *person1 = (struct person *) NULL;        /* list of people */
200struct person *person2 = (struct person *) NULL;        /* 2nd list of people */
201time_t tloc;
202
203char ttnames[MAXTTYS][LMAX];    /* TTY names */
204time_t logouts[MAXTTYS];        /* Logout times */
205
206struct passwd *pwdcopy();
207
208/*ARGSUSED*/
209main(argc, argv)
210        int argc;
211        register char **argv;
212{
213        register char *s;
214
215        /* parse command line for (optional) arguments */
216        while (*++argv && **argv == COMMAND)
217                for (s = *argv + 1; *s; s++)
218                        switch (*s) {
219                        case 'b':
220                                unbrief = 0;
221                                break;
222                        case 'f':
223                                header = 0;
224                                break;
225                        case 'h':
226                                hack = 0;
227                                break;
228                        case 'i':
229                                idlep = 1;
230                                unquick = 0;
231                                break;
232                        case 'l':
233                                large = 1;
234                                break;
235                        case 'm':
236                                match = 0;
237                                break;
238                        case 'p':
239                                plan = 0;
240                                break;
241                        case 'q':
242                                unquick = 0;
243                                break;
244                        case 's':
245                                small = 1;
246                                break;
247                        case 'w':
248                                wide = 0;
249                                break;
250                        default:
251                                fprintf(stderr, "Usage: finger [-bfhilmpqsw] [login1 [login2 ...] ]\n");
252                                exit(1);
253                        }
254        if (unquick || idlep)
255                (void) time(&tloc);
256        /*
257         * *argv == 0 means no names given
258         *
259         * this procedure should not (and doesn't) use zephyr at all, because
260         * finger [no args] should NOT give you every logged-in person...
261         */
262        if (*argv == 0)
263                doall();
264        else
265                donames(argv);
266        if (person1) {
267                printf("\nLocal:\n");
268                print(person1);
269        }
270        if (person2) {
271                printf("\nAthena-wide:\n");
272                print(person2);
273        }
274        exit(0);
275}
276
277doall()
278{
279        register struct person *p;
280        register struct passwd *pw;
281        int uf;
282        char name[NMAX + 1];
283
284        unshort = large;
285        if ((uf = open(USERLOG, 0)) < 0) {
286                fprintf(stderr, "finger: error opening %s\n", USERLOG);
287                exit(2);
288        }
289        if (unquick) {
290                setpwent();
291                fw_open();
292        }
293        while (read(uf, (char *) &user, sizeof user) == sizeof user) {
294                if (user.ut_name[0] == 0)
295                        continue;
296#if defined(USER_PROCESS)
297                if (user.ut_type != USER_PROCESS)
298                        continue;
299#endif
300                if (person1 == 0)
301                        p = person1 = (struct person *) malloc(sizeof *p);
302                else {
303                        p->link = (struct person *) malloc(sizeof *p);
304                        p = p->link;
305                }
306                memcpy(name, user.ut_name, NMAX);
307                name[NMAX] = 0;
308                memcpy(p->tty, user.ut_line, LMAX);
309                p->tty[LMAX] = 0;
310                memcpy(p->host, user.ut_host, HMAX);
311                p->host[HMAX] = 0;
312                p->loginout = 0;
313                p->loginat = UTTIME(user);
314                p->pwd = 0;
315                p->loggedin = 1;
316                p->zlocation = 0;
317                p->logintime[0] = '\0';
318                if (unquick && (pw = getpwnam(name))) {
319                        p->pwd = pwdcopy(pw);
320                        decode(p);
321                        p->name = p->pwd->pw_name;
322                }
323                else
324                        p->name = strcpy(malloc((unsigned) (strlen(name) + 1)),
325                                         name);
326        }
327        if (unquick) {
328                fwclose();
329                endpwent();
330        }
331        (void) close(uf);
332        if (person1 == 0) {
333                printf("\nNo one logged on\n");
334                return;
335        }
336        p->link = 0;
337}
338
339donames(argv)
340        char **argv;
341{
342        register struct person *p;
343        register struct person *q;      /* A second chain for athena-wide
344                                         * finger */
345        register struct passwd *pw;
346        struct passwd *hes_getpwnam();
347        int uf, i;
348        Code_t state;
349
350        /*
351         * get names from command line and check to see if they're logged in
352         */
353        unshort = !small;
354        for (; *argv != 0; argv++) {
355                if (netfinger(*argv))
356                        continue;
357                if (person1 == 0) {
358                        p = person1 = (struct person *) malloc(sizeof *p);
359                        q = person2 = (struct person *) malloc(sizeof *q);
360                }
361                else {
362                        p->link = (struct person *) malloc(sizeof *p);
363                        p = p->link;
364                        q->link = (struct person *) malloc(sizeof *q);
365                        q = q->link;
366                }
367                p->name = q->name = *argv;
368                p->tty[0] = q->tty[0] = '\0';
369                p->host[0] = q->host[0] = '\0';
370                p->logintime[0] = q->logintime[0] = '\0';
371                p->loginout = q->loginout = 0;
372                p->loginat = q->loginat = 0;
373                p->idletime = q->idletime = 0;
374                p->realname = q->realname = (char *) NULL;
375                p->nickname = q->nickname = (char *) NULL;
376                p->office = q->office = (char *) NULL;
377                p->officephone = q->officephone = (char *) NULL;
378                p->homephone = q->homephone = (char *) NULL;
379                p->random = q->random = (char *) NULL;
380                p->pwd = q->pwd = (struct passwd *) NULL;
381                p->loggedin = q->loggedin = 0;
382                p->writable = q->writable = '\0';
383                p->original = q->original = 1;
384                p->zlocation = q->zlocation = 0;
385        }
386        if (person1 == 0)
387                return;
388        p->link = q->link = 0;
389        /*
390         * if we are doing it, read /etc/passwd for the useful info for p* --
391         * ask hesiod for the entries for q*.
392         */
393        if (unquick) {
394                setpwent();
395                if (!match) {
396                        for (p = person1; p != 0; p = p->link)
397                                if (pw = getpwnam(p->name))
398                                        p->pwd = pwdcopy(pw);
399
400                }
401                else
402                        while ((pw = getpwent()) != 0) {
403                                for (p = person1; p != 0; p = p->link) {
404                                        if (!p->original)
405                                                continue;
406                                        if (strcmp(p->name, pw->pw_name) != 0 &&
407                                            !matchcmp(pw->pw_gecos, pw->pw_name, p->name))
408                                                continue;
409                                        if (p->pwd == 0) {
410                                                p->pwd = pwdcopy(pw);
411                                        }
412                                        else {
413                                                struct person *new;
414
415                                                /*
416                                                 * handle multiple login
417                                                 * names, insert new
418                                                 * "duplicate" entry behind
419                                                 */
420                                                new = (struct person *)
421                                                        malloc(sizeof *new);
422                                                new->pwd = pwdcopy(pw);
423                                                new->name = p->name;
424                                                new->original = 1;
425                                                new->zlocation = 0;
426                                                new->loggedin = 0;
427                                                new->link = p->link;
428                                                p->original = 0;
429                                                p->link = new;
430                                                p = new;
431                                        }
432                                }
433                        }
434                /* now do the hesiod chain */
435                for (q = person2; q != 0; q = q->link)
436                        if (pw = hes_getpwnam(q->name))
437                                q->pwd = pwdcopy(pw);
438                endpwent();
439        }
440        /* Now get login information */
441        if ((uf = open(USERLOG, 0)) < 0) {
442                fprintf(stderr, "finger: error opening %s\n", USERLOG);
443                exit(2);
444        }
445        while (read(uf, (char *) &user, sizeof user) == sizeof user) {
446                if (*user.ut_name == 0)
447                        continue;
448#if defined(USER_PROCESS)
449                if (user.ut_type != USER_PROCESS)
450                        continue;
451#endif
452                for (p = person1; p != 0; p = p->link) {
453                        if (p->loggedin == 2)
454                                continue;
455                        if (strncmp(p->pwd ? p->pwd->pw_name : p->name,
456                                    user.ut_name, NMAX) != 0)
457                                continue;
458                        if (p->loggedin == 0) {
459                                memcpy(p->tty, user.ut_line, LMAX);
460                                p->tty[LMAX] = 0;
461                                memcpy(p->host, user.ut_host, HMAX);
462                                p->host[HMAX] = 0;
463                                p->loginat = UTTIME(user);
464                                p->loggedin = 1;
465                        }
466                        else {  /* p->loggedin == 1 */
467                                struct person *new;
468
469                                new = (struct person *) malloc(sizeof *new);
470                                new->name = p->name;
471                                memcpy(new->tty, user.ut_line, LMAX);
472                                new->tty[LMAX] = 0;
473                                memcpy(new->host, user.ut_host, HMAX);
474                                new->host[HMAX] = 0;
475                                new->loginat = UTTIME(user);
476                                new->logintime[0] = '\0';
477                                new->pwd = p->pwd;
478                                new->loggedin = 1;
479                                new->original = 0;
480                                new->zlocation = 0;
481                                new->link = p->link;
482                                p->loggedin = 2;
483                                p->link = new;
484                                p = new;
485                        }
486                }
487        }
488        /* Ask Zephyr if someone is logged in. */
489        if ((state = ZInitialize()) != ZERR_NONE) {
490                com_err("finger", state, "\nFailure in Zephyr \
491initialization");
492        }
493        else {
494                for (q = person2; q != (struct person *) NULL; q = q->link) {
495                        char curname[BUFSIZ];
496
497                        (void) strcpy(curname, q->name);
498                        (void) strcat(curname, "@");
499                        (void) strcat(curname, ZGetRealm());
500
501                        if ((state = ZLocateUser(curname, &znloc,ZAUTH)) != ZERR_NONE) {
502                                break;
503                        }
504                        q->zlocation = 1;
505                        q->loggedin = 0;
506                        for (i = 1; i <= znloc; i++) {
507                                if ((state = ZGetLocations(&location, &numloc))
508                                    != 0)
509                                        break;
510                                else {
511                                        (void) strncpy(q->host, location.host,
512                                                       sizeof(q->host));
513                                        (void) strncpy(q->logintime,
514                                                       location.time,
515                                                       sizeof(q->logintime));
516                                        (void) strncpy(q->tty,
517                                                       location.tty,
518                                                       sizeof(q->tty));
519                                        q->loggedin = 1;
520                                        /* if we can zlocate them, we can
521                                         * zwrite them -- if they're
522                                         * subscribing. */
523                                        q->writable = 1;
524
525                                }
526                        }
527                }
528        }
529        (void) close(uf);
530        if (unquick) {
531                fw_open();
532                for (p = person1, q = person2; p != 0 && q != 0;
533                     p = p->link, q = q->link) {
534                        decode(p);
535                        decode(q);
536                }
537                fwclose();
538        }
539}
540
541print(personn)
542        register struct person *personn;
543{
544        register struct person *p;
545        register FILE *fp;
546        register char *s;
547        register c;
548
549        /*
550         * print out what we got
551         */
552        if (header) {
553                if (unquick) {
554                        if (!unshort)
555                                if (wide)
556                                        printf("Login       Name               TTY Idle When        Office\n");
557                                else
558                                        printf("Login     TTY Idle When        Office\n");
559                }
560                else {
561                        printf("Login      TTY      When");
562                        if (idlep)
563                                printf("               Idle");
564                        (void) putchar('\n');
565                }
566        }
567        for (p = personn; p != 0; p = p->link) {
568                if (!unquick) {
569                        quickprint(p);
570                        continue;
571                }
572                else
573                        decode(p);
574                if (!unshort) {
575                        shortprint(p);
576                        continue;
577                }
578                personprint(p);
579                if (p->pwd != 0) {
580                        if (hack) {
581                                s = malloc(strlen(p->pwd->pw_dir) +
582                                           (unsigned) sizeof PROJ);
583                                (void) strcpy(s, p->pwd->pw_dir);
584                                (void) strcat(s, PROJ);
585                                if ((fp = fopen(s, "r")) != 0) {
586                                        printf("Project: ");
587                                        while ((c = getc(fp)) != EOF) {
588                                                if (c == '\n')
589                                                        break;
590                                                if (isprint(c) || isspace(c))
591                                                        (void) putchar(c);
592                                                else
593                                                        (void) putchar(c ^ 100);
594                                        }
595                                        (void) fclose(fp);
596                                        (void) putchar('\n');
597                                }
598                                free(s);
599                        }
600                        if (plan) {
601                                register int i = 0, j;
602                                register int okay = 1;
603                                char mailbox[100];      /* mailbox name */
604
605                                s = malloc(strlen(p->pwd->pw_dir) +
606                                           (unsigned) sizeof PLAN);
607                                (void) strcpy(s, p->pwd->pw_dir);
608                                (void) strcat(s, PLAN);
609                                if ((fp = fopen(s, "r")) == 0)
610                                        printf("No Plan.\n");
611                                else {
612                                        printf("Plan:\n");
613                                        while ((c = getc(fp)) != EOF) {
614                                                if (i < MMLEN && okay) {
615                                                        if (c != MM[i]) {
616                                                                for (j = 0; j < i; j++)
617                                                                        (void) putchar(MM[j]);
618                                                                if (isprint(c) || isspace(c))
619                                                                        (void) putchar(c);
620                                                                else
621                                                                        (void) putchar(c ^ 100);
622                                                                okay = 0;
623                                                        }
624                                                }
625                                                else if (isprint(c) || isspace(c))
626                                                        (void) putchar(c);
627                                                else
628                                                        (void) putchar(c ^ 100);
629                                                i++;
630                                        }
631                                        (void) fclose(fp);
632                                        if (okay) {
633                                                (void) strcpy(mailbox, MAILDIR);
634                                                /* start with the directory */
635                                                (void) strcat(mailbox,
636                                                         (p->pwd)->pw_name);
637                                                if (access(mailbox, F_OK) == 0) {
638                                                        struct stat statb;
639
640                                                        (void) stat(mailbox, &statb);
641                                                        if (statb.st_size) {
642                                                                printf("User %s has new mail.\n", (p->pwd)->pw_name);
643                                                        };
644                                                }
645                                        }
646                                }
647                                free(s);
648                        }
649                }
650                if (p->link != 0)
651                        (void) putchar('\n');
652        }
653}
654
655/*
656 * Duplicate a pwd entry.
657 * Note: Only the useful things (what the program currently uses) are copied.
658 */
659struct passwd *
660pwdcopy(pfrom)
661        register struct passwd *pfrom;
662{
663        register struct passwd *pto;
664
665        pto = (struct passwd *) malloc((unsigned) (sizeof *pto));
666#define savestr(s) strcpy(malloc((unsigned)(strlen(s) + 1)), s)
667        pto->pw_name = savestr(pfrom->pw_name);
668        pto->pw_uid = pfrom->pw_uid;
669        pto->pw_gecos = savestr(pfrom->pw_gecos);
670        pto->pw_dir = savestr(pfrom->pw_dir);
671        pto->pw_shell = savestr(pfrom->pw_shell);
672#undef savestr
673        return pto;
674}
675
676/*
677 * print out information on quick format giving just name, tty, login time
678 * and idle time if idle is set.
679 */
680quickprint(pers)
681        register struct person *pers;
682{
683        printf("%-8.8s  ", pers->name);
684        if (pers->loggedin) {
685                if (idlep) {
686                        findidle(pers);
687                        printf("%c%-8s %-16.16s", pers->writable ? ' ' : '*',
688                               pers->tty, ctime(&pers->loginat));
689                        (void) ltimeprint("   ", &pers->idletime, "");
690                }
691                else
692                        printf(" %-8s %-16.16s", pers->tty,
693                               ctime(&pers->loginat));
694                (void) putchar('\n');
695        }
696        else
697                printf("          Not Logged In\n");
698}
699
700/*
701 * print out information in short format, giving login name, full name,
702 * tty, idle time, login time, office location and phone.
703 */
704shortprint(pers)
705        register struct person *pers;
706{
707        char *p;
708        char dialup;
709
710        if (pers->pwd == 0) {
711                printf("%-15s       ???\n", pers->name);
712                return;
713        }
714        printf("%-8s",  pers->pwd->pw_name);
715        dialup = 0;
716        if (wide) {
717                if (pers->realname)
718                        printf(" %-20.20s", pers->realname);
719
720                else
721                        printf("        ???          ");
722        }
723        (void) putchar(' '); 
724        if (pers->loggedin && !pers->writable)
725                (void) putchar('*');
726        else
727                (void) putchar(' ');
728        if (*pers->tty) {
729                if (!strncmp(pers->tty, "tty", 3)) {
730                        if (pers->tty[3] == 'd' && pers->loggedin)
731                                dialup = 1;
732                        printf("%-3.3s ", pers->tty + 3);
733                } else
734                if (!strncmp(pers->tty, "pts/", 4)) {
735                        printf("p%-2.2s ", pers->tty + 4);
736                } else
737                        printf("%-3.3s ", pers->tty);
738        }
739        else
740                printf("   ");
741        p = ctime(&pers->loginat);
742        if (pers->loggedin) {
743                stimeprint(&pers->idletime);
744                printf(" %3.3s %-5.5s ", p, p + 11);
745        }
746        else if (pers->loginat == 0)
747                printf(" < .  .  .  . >");
748        else if (tloc - pers->loginat >= 180 * 24 * 60 * 60)
749                printf(" <%-6.6s, %-4.4s>", p + 4, p + 20);
750        else
751                printf(" <%-12.12s>", p + 4);
752        if (dialup && pers->homephone)
753                printf(" %20s", pers->homephone);
754        else {
755                (void) putchar(' ');
756                if (pers->office)
757                        printf(" %-12.12s", pers->office);
758                else if (pers->officephone || pers->homephone)
759                        printf("            ");
760                if (pers->officephone)
761                        printf(" %s", pers->officephone);
762                else if (pers->homephone)
763                        printf(" %s", pers->homephone);
764        }
765        (void) putchar('\n');
766}
767
768/*
769 * print out a person in long format giving all possible information.
770 * directory and shell are inhibited if unbrief is clear.
771 */
772personprint(pers)
773        register struct person *pers;
774{
775        if (pers->pwd == (struct passwd *) NULL) {
776                printf("Login name: %-10s\t\t\tIn real life: ???\n",
777                       pers->name);
778                return;
779        }
780        printf("Login name: %-10s", pers->pwd->pw_name);
781        if (pers->loggedin && !pers->writable)
782                printf("        (messages off)  ");
783        else
784                printf("                        ");
785        if (pers->realname)
786                printf("In real life: %s", pers->realname);
787        if (pers->nickname)
788                printf("\nNickname: %-s", pers->nickname);
789        if (pers->office) {
790                printf("\nOffice: %-.12s", pers->office);
791                if (pers->officephone) {
792                        printf(", %s", pers->officephone);
793                        if (pers->homephone)
794                                printf("\t\tHome phone: %s", pers->homephone);
795                        else if (pers->random)
796                                printf("\t\t%s", pers->random);
797                }
798                else if (pers->homephone)
799                        printf("\t\t\tHome phone: %s", pers->homephone);
800                else if (pers->random)
801                        printf("\t\t\t%s", pers->random);
802        }
803        else if (pers->officephone) {
804                printf("\nPhone: %s", pers->officephone);
805                if (pers->homephone)
806                        printf(", %s", pers->homephone);
807                if (pers->random)
808                        printf(", %s", pers->random);
809        }
810        else if (pers->homephone) {
811                printf("\nPhone: %s", pers->homephone);
812                if (pers->random)
813                        printf(", %s", pers->random);
814        }
815        else if (pers->random)
816                printf("\n%s", pers->random);
817        if (unbrief) {
818                printf("\nDirectory: %-25s", pers->pwd->pw_dir);
819                if (*pers->pwd->pw_shell)
820                        printf("\tShell: %-s", pers->pwd->pw_shell);
821        }
822        if (pers->zlocation) {
823                if (pers->loggedin)
824                        printf("\nOn since %s on %s on host %s",
825                               pers->logintime, pers->tty, pers->host);
826                else
827                        printf("\nNot currently locatable.");
828        }
829        else if (pers->loggedin) {
830                if (*pers->host) {
831                        if (*pers->logintime) {
832                                printf("\nOn since %s on %s from %s",
833                                    pers->logintime, pers->tty, pers->host);
834                        }
835                        else {
836                                register char *ep = ctime(&pers->loginat);
837
838                                printf("\nOn since %15.15s on %s from %s",
839                                       &ep[4], pers->tty, pers->host);
840                        (void) ltimeprint("\n", &pers->idletime, " Idle Time");
841                        }
842                }
843                else {
844                        register char *ep = ctime(&pers->loginat);
845
846                        printf("\nOn since %15.15s on %-*s",
847                               &ep[4], LMAX, pers->tty);
848                        (void) ltimeprint("\t", &pers->idletime, " Idle Time");
849                }
850        }
851        else if (pers->loginat == 0)
852                printf("\nNever logged in.");
853        else if (tloc - pers->loginat > 180 * 24 * 60 * 60) {
854                register char *ep = ctime(&pers->loginat);
855
856                printf("\nLast %s %10.10s, %4.4s on %s",
857                       pers->loginout ? "logout" : "login",
858                       ep, ep + 20, pers->tty);
859                if (*pers->host)
860                        printf(" from %s", pers->host);
861        }
862        else {
863                register char *ep = ctime(&pers->loginat);
864
865                printf("\nLast %s %16.16s on %s",
866                       pers->loginout ? "logout" : "login",
867                       ep, pers->tty);
868                if (*pers->host)
869                        printf(" from %s", pers->host);
870        }
871        (void) putchar('\n');
872}
873
874/*
875 *  very hacky section of code to format phone numbers.  filled with
876 *  magic constants like 4, 7 and 10.
877 */
878char *
879phone(s, len, alldigits)
880        register char *s;
881        int len;
882        char alldigits;
883{
884        char fonebuf[15];
885        register char *p = fonebuf;
886        register i;
887
888        if (!alldigits)
889                return (strcpy(malloc((unsigned) (len + 1)), s));
890        switch (len) {
891        case 4:
892                *p++ = ' ';
893                *p++ = 'x';
894                *p++ = '3';
895                *p++ = '-';
896                for (i = 0; i < 4; i++)
897                        *p++ = *s++;
898                break;
899        case 5:
900                *p++ = ' ';
901                *p++ = 'x';
902                *p++ = *s++;
903                *p++ = '-';
904                for (i = 0; i < 4; i++)
905                        *p++ = *s++;
906                break;
907        case 7:
908                for (i = 0; i < 3; i++)
909                        *p++ = *s++;
910                *p++ = '-';
911                for (i = 0; i < 4; i++)
912                        *p++ = *s++;
913                break;
914        case 10:
915                for (i = 0; i < 3; i++)
916                        *p++ = *s++;
917                *p++ = '-';
918                for (i = 0; i < 3; i++)
919                        *p++ = *s++;
920                *p++ = '-';
921                for (i = 0; i < 4; i++)
922                        *p++ = *s++;
923                break;
924        case 0:
925                return 0;
926        default:
927                return (strcpy(malloc((unsigned) (len + 1)), s));
928        }
929        *p++ = 0;
930        return (strcpy(malloc((unsigned) (p - fonebuf)), fonebuf));
931}
932
933/*
934 * decode the information in the gecos field of /etc/passwd
935 */
936decode(pers)
937        register struct person *pers;
938{
939        char buffer[256];
940        register char *bp, *gp, *lp;
941        int alldigits;
942        int hasspace;
943        int len;
944
945        pers->realname = 0;
946        pers->nickname = 0;
947        pers->office = 0;
948        pers->officephone = 0;
949        pers->homephone = 0;
950        pers->random = 0;
951        if (pers->pwd == 0)
952                return;
953        gp = pers->pwd->pw_gecos;
954        bp = buffer;
955        if (*gp == ASTERISK)
956                gp++;
957        while (*gp && *gp != COMMA)     /* name */
958                if (*gp == SAMENAME) {
959                        lp = pers->pwd->pw_name;
960                        if (islower(*lp))
961                                *bp++ = toupper(*lp++);
962                        while (*bp++ = *lp++);
963                        bp--;
964                        gp++;
965                }
966                else
967                        *bp++ = *gp++;
968        *bp++ = 0;
969        if ((len = bp - buffer) > 1)
970                pers->realname = strcpy(malloc((unsigned) len), buffer);
971        if (*gp == COMMA) {     /* nickname */
972                gp++;
973                bp = buffer;
974                while ((*gp != 0) && (*gp != COMMA)) {
975                        if (*gp == SAMENAME) {
976                                lp = pers->pwd->pw_name;
977                                *bp++ = CAPITALIZE(*lp++);
978                                while (*lp != 0) {
979                                        *bp++ = *lp++;
980                                }
981                        }
982                        else {
983                                *bp++ = *gp;
984                        }
985                        gp++;
986                }
987                *bp = 0;
988                if (strlen(buffer) > 0) {
989                        pers->nickname = malloc((unsigned) (strlen(&buffer[0])
990                                                            + 1));
991                        (void) strcpy(pers->nickname, &buffer[0]);
992                }
993        }
994        if (*gp == COMMA) {     /* office, supposedly */
995                gp++;
996                hasspace = 0;
997                bp = buffer;
998                while (*gp && *gp != COMMA) {
999                        *bp = *gp++;
1000                        if (*bp == ' ')
1001                                hasspace = 1;
1002                        /* leave 9 for Tech Sq. and MIT expansion */
1003                        if (bp < buffer + sizeof buffer - 9)
1004                                bp++;
1005                }
1006                *bp = 0;
1007                len = bp - buffer;
1008                bp--;           /* point to last character */
1009                if (hasspace || len == 0)
1010                        len++;
1011                else if (*bp == TECHSQ) {
1012                        (void) strcpy(bp, " Tech Sq.");
1013                        len += 9;
1014                }
1015                else if (*bp == MIT) {
1016                        (void) strcpy(bp, " MIT");
1017                        len += 4;
1018                }
1019                else
1020                        len++;
1021                if (len > 1)
1022                        pers->office = strcpy(malloc((unsigned) len), buffer);
1023        }
1024        if (*gp == COMMA) {     /* office phone */
1025                gp++;
1026                bp = buffer;
1027                alldigits = 1;
1028                while (*gp && *gp != COMMA) {
1029                        *bp = *gp++;
1030                        if (!isdigit(*bp))
1031                                alldigits = 0;
1032                        if (bp < buffer + sizeof buffer - 1)
1033                                bp++;
1034                }
1035                *bp = 0;
1036                pers->officephone = phone(buffer, bp - buffer, alldigits);
1037        }
1038        if (*gp == COMMA) {     /* home phone */
1039                gp++;
1040                bp = buffer;
1041                alldigits = 1;
1042                while (*gp && *gp != COMMA) {
1043                        *bp = *gp++;
1044                        if (!isdigit(*bp))
1045                                alldigits = 0;
1046                        if (bp < buffer + sizeof buffer - 1)
1047                                bp++;
1048                }
1049                *bp = 0;
1050                pers->homephone = phone(buffer, bp - buffer, alldigits);
1051        }
1052        if (pers->loggedin)
1053                findidle(pers);
1054        else if (!pers->zlocation)
1055                findwhen(pers);
1056}
1057
1058/*
1059 * find the last log in of a user by checking the LASTLOG file.
1060 * the entry is indexed by the uid, so this can only be done if
1061 * the uid is known (which it isn't in quick mode)
1062 */
1063
1064fw_open()
1065{
1066#ifndef NO_LASTLOG
1067        lf = open(LASTLOG, 0);
1068#endif
1069        lw = open(ACCTLOG, 0);
1070}
1071
1072findwhen(pers)
1073        register struct person *pers;
1074{
1075#ifndef NO_LASTLOG
1076        struct lastlog ll;
1077#endif
1078        struct stat stb;
1079#ifndef HAVE_UTMPX_H
1080        struct utmp *bp;
1081        struct utmp buf[128];
1082#else
1083        struct utmpx *bp;
1084        struct utmpx buf[128];
1085#endif
1086        int i, bl, count;
1087        off_t lseek();
1088
1089        if (lw >= 0) {
1090                (void) fstat(lw, &stb);
1091                bl = (stb.st_size + sizeof(buf) - 1) / sizeof(buf);
1092                count = 0;
1093                for (bl--; bl >= 0; bl--) {
1094                        (void) lseek(lw, (off_t) (bl * sizeof(buf)), 0);
1095                        bp = &buf[read(lw, (char *) buf, sizeof(buf))
1096                                  / sizeof(buf[0]) - 1];
1097                        for (; bp >= buf; bp--) {
1098                                if (count++ == MAXSEARCH)
1099                                        goto fudged;
1100                                if (!strncmp(bp->ut_name, pers->name,
1101                                             MIN(strlen(pers->name)+1, NMAX))) {
1102                                        (void) strncpy(pers->tty,
1103                                                       bp->ut_line, LMAX);
1104                                        (void) strncpy(pers->host,
1105                                                       bp->ut_host, HMAX);
1106                                        pers->loginout = 1;
1107                                        for (i = 0; i < MAXTTYS; i++) {
1108                                                if (!strncmp(ttnames[i],
1109                                                             bp->ut_line,
1110                                                     sizeof(bp->ut_line))) {
1111                                                        pers->loginat = logouts[i];
1112                                                        return;
1113                                                }
1114                                        }
1115                                        goto fudged;
1116                                }
1117                                else {
1118                                        for (i = 0; i < MAXTTYS; i++) {
1119                                                if (ttnames[i][0] == 0) {
1120                                                        (void) strncpy(ttnames[i],
1121                                                                bp->ut_line,
1122                                                        sizeof(bp->ut_line));
1123                                                        logouts[i] =
1124                                                            UTTIME(*bp);
1125                                                        break;
1126                                                }
1127                                                if (!strncmp(ttnames[i],
1128                                                             bp->ut_line,
1129                                                     sizeof(bp->ut_line))) {
1130                                                        logouts[i] =
1131                                                            UTTIME(*bp);
1132                                                        break;
1133                                                }
1134                                        }
1135                                }
1136                        }
1137                }
1138        }
1139fudged:
1140#ifndef NO_LASTLOG
1141        if (lf >= 0) {
1142                (void) lseek(lf, (long) pers->pwd->pw_uid * sizeof ll, 0);
1143                if ((i = read(lf, (char *) &ll, sizeof ll)) == sizeof ll) {
1144                        memcpy(pers->tty, ll.ll_line, LMAX);
1145                        pers->tty[LMAX] = 0;
1146                        memcpy(pers->host, ll.ll_host, HMAX);
1147                        pers->host[HMAX] = 0;
1148                        pers->loginat = ll.ll_time;
1149                        pers->loginout = 0;
1150                }
1151                else {
1152                        if (i != 0)
1153                                fprintf(stderr, "finger: %s read error\n",
1154                                        LASTLOG);
1155                        pers->tty[0] = 0;
1156                        pers->host[0] = 0;
1157                        pers->loginat = 0L;
1158                }
1159        } else
1160#endif
1161        {
1162                pers->tty[0] = 0;
1163                pers->host[0] = 0;
1164                pers->loginat = 0L;
1165        }
1166}
1167
1168fwclose()
1169{
1170#ifndef NO_LASTLOG
1171        if (lf >= 0) {
1172                (void) close(lf);
1173                lf = -1;
1174        }
1175#endif
1176        if (lw >= 0) {
1177                (void) close(lw);
1178                lw = -1;
1179        }
1180}
1181
1182#define TTYLEN 5
1183
1184/*
1185 * find the idle time of a user by doing a stat on /dev/tty??,
1186 * where tty?? has been gotten from USERLOG, supposedly.
1187 */
1188findidle(pers)
1189        register struct person *pers;
1190{
1191        struct stat ttystatus;
1192        static char buffer[TTYLEN + LMAX + 1] = "/dev/";
1193        time_t t;
1194
1195        if (!pers->zlocation) {
1196                (void) strcpy(buffer + TTYLEN, pers->tty);
1197                buffer[TTYLEN + LMAX] = 0;
1198                if (stat(buffer, &ttystatus) < 0) {
1199                        pers->idletime = NOIDLE;
1200                        pers->writable = 0;
1201                        return;
1202/*
1203                        fprintf(stderr, "finger: Can't stat %s\n", buffer);
1204                        exit(4);
1205*/
1206                }
1207                (void) time(&t);
1208                if (t < ttystatus.st_atime)
1209                        pers->idletime = 0L;
1210                else
1211                        pers->idletime = t - ttystatus.st_atime;
1212                pers->writable = (ttystatus.st_mode & TALKABLE) == TALKABLE;
1213        } else {
1214                pers->idletime = 0L;
1215                pers->writable = 1;
1216        }
1217}
1218
1219/*
1220 * print idle time in short format; this program always prints 4 characters;
1221 * if the idle time is zero, it prints 4 blanks.
1222 */
1223stimeprint(dt)
1224        time_t *dt;
1225{
1226        register struct tm *delta;
1227
1228        if (*dt == NOIDLE) {
1229                printf("   -");
1230                return;
1231        }
1232
1233        delta = gmtime(dt);
1234        if (delta->tm_yday == 0)
1235                if (delta->tm_hour == 0)
1236                        if (delta->tm_min == 0)
1237                                printf("    ");
1238                        else
1239                                printf("  %2d", delta->tm_min);
1240                else if (delta->tm_hour >= 10)
1241                        printf("%3d:", delta->tm_hour);
1242                else
1243                        printf("%1d:%02d",
1244                               delta->tm_hour, delta->tm_min);
1245        else
1246                printf("%3dd", delta->tm_yday);
1247}
1248
1249/*
1250 * print idle time in long format with care being taken not to pluralize
1251 * 1 minutes or 1 hours or 1 days.
1252 * print "prefix" first.
1253 */
1254ltimeprint(before, dt, after)
1255        long *dt;
1256        char *before, *after;
1257{
1258        register struct tm *delta;
1259
1260        if (*dt == NOIDLE) {
1261                printf("%sUnavailable%s", before, after);
1262                return (0);
1263        }
1264
1265        delta = gmtime(dt);
1266        if (delta->tm_yday == 0 && delta->tm_hour == 0 && delta->tm_min == 0 &&
1267            delta->tm_sec <= 10)
1268                return (0);
1269        printf("%s", before);
1270        if (delta->tm_yday >= 10)
1271                printf("%d days", delta->tm_yday);
1272        else if (delta->tm_yday > 0)
1273                printf("%d day%s %d hour%s",
1274                       delta->tm_yday, delta->tm_yday == 1 ? "" : "s",
1275                       delta->tm_hour, delta->tm_hour == 1 ? "" : "s");
1276        else if (delta->tm_hour >= 10)
1277                printf("%d hours", delta->tm_hour);
1278        else if (delta->tm_hour > 0)
1279                printf("%d hour%s %d minute%s",
1280                       delta->tm_hour, delta->tm_hour == 1 ? "" : "s",
1281                       delta->tm_min, delta->tm_min == 1 ? "" : "s");
1282        else if (delta->tm_min >= 10)
1283                printf("%2d minutes", delta->tm_min);
1284        else if (delta->tm_min == 0)
1285                printf("%2d seconds", delta->tm_sec);
1286        else
1287                printf("%d minute%s %d second%s",
1288                       delta->tm_min,
1289                       delta->tm_min == 1 ? "" : "s",
1290                       delta->tm_sec,
1291                       delta->tm_sec == 1 ? "" : "s");
1292        printf("%s", after);
1293        return (0);
1294}
1295
1296matchcmp(gname, login, given)
1297        register char *gname;
1298        char *login;
1299        char *given;
1300{
1301        char buffer[100];
1302        register char *bp, *lp;
1303        register c;
1304
1305        if (*gname == ASTERISK)
1306                gname++;
1307        lp = 0;
1308        bp = buffer;
1309        for (;;)
1310                switch (c = *gname++) {
1311                case SAMENAME:
1312                        for (lp = login; bp < buffer + sizeof buffer
1313                             && (*bp++ = *lp++););
1314                        bp--;
1315                        break;
1316                case ' ':
1317                case COMMA:
1318                case '\0':
1319                        *bp = 0;
1320                        if (namecmp(buffer, given))
1321                                return (1);
1322                        if (c == COMMA || c == 0)
1323                                return (0);
1324                        bp = buffer;
1325                        break;
1326                default:
1327                        if (bp < buffer + sizeof buffer)
1328                                *bp++ = c;
1329                }
1330        /* NOTREACHED */
1331}
1332
1333namecmp(name1, name2)
1334        register char *name1, *name2;
1335{
1336        register int c1, c2;
1337
1338        /* Do not permit matching on empty strings */
1339        if (*name1 == 0 || *name2 == 0)
1340                return (0);
1341       
1342        for (;;) {
1343                c1 = *name1++;
1344                if (islower(c1))
1345                        c1 = toupper(c1);
1346                c2 = *name2++;
1347                if (islower(c2))
1348                        c2 = toupper(c2);
1349                if (c1 != c2)
1350                        break;
1351                if (c1 == 0)
1352                        return (1);
1353        }
1354        if (!c1) {
1355                for (name2--; isdigit(*name2); name2++);
1356                if (*name2 == 0)
1357                        return (1);
1358        }
1359        if (!c2) {
1360                for (name1--; isdigit(*name1); name1++);
1361                if (*name1 == 0)
1362                        return (1);
1363        }
1364        return (0);
1365}
1366
1367netfinger(name)
1368        char *name;
1369{
1370        char *host;
1371        struct hostent *hp;
1372        struct servent *sp;
1373        struct sockaddr_in sin;
1374        int s;
1375
1376        register FILE *f;
1377        register int c;
1378        register int lastc;
1379
1380        if (name == NULL)
1381                return (0);
1382        host = strrchr(name, '@');
1383        if (host == NULL) {
1384                host = strrchr(name, '%');
1385                if (host != NULL)
1386                        *host = '@';
1387                else
1388                        return (0);
1389        }
1390        *host++ = 0;
1391        hp = gethostbyname(host);
1392        if (hp == NULL) {
1393                static struct hostent def;
1394                static struct in_addr defaddr;
1395                static char *alist[1];
1396                static char namebuf[128];
1397                u_long inet_addr();
1398
1399                defaddr.s_addr = inet_addr(host);
1400                if (defaddr.s_addr == -1) {
1401                        printf("unknown host: %s\n", host);
1402                        return (1);
1403                }
1404                (void) strcpy(namebuf, host);
1405                def.h_name = namebuf;
1406                def.h_addr_list = alist, def.h_addr = (char *) &defaddr;
1407                def.h_length = sizeof(struct in_addr);
1408                def.h_addrtype = AF_INET;
1409                def.h_aliases = 0;
1410                hp = &def;
1411        }
1412        printf("[%s]", hp->h_name);
1413        (void) fflush(stdout);
1414        sp = getservbyname("finger", "tcp");
1415        if (sp == 0) {
1416                printf("tcp/finger: unknown service\n");
1417                return (1);
1418        }
1419        sin.sin_family = hp->h_addrtype;
1420        memcpy(&sin.sin_addr, hp->h_addr, hp->h_length);
1421        sin.sin_port = sp->s_port;
1422        s = socket(hp->h_addrtype, SOCK_STREAM, 0);
1423        if (s < 0) {
1424                (void) fflush(stdout);
1425                perror("socket");
1426                return (1);
1427        }
1428        if (connect(s, (struct sockaddr *) & sin, sizeof(sin)) < 0) {
1429                (void) fflush(stdout);
1430                perror("connect");
1431                (void) close(s);
1432                return (1);
1433        }
1434        printf("\n");
1435        if (large)
1436                (void) write(s, "/W ", 3);
1437        (void) write(s, name, strlen(name));
1438        (void) write(s, "\r\n", 2);
1439        f = fdopen(s, "r");
1440        while ((c = getc(f)) != EOF) {
1441                switch (c) {
1442                case 0210:
1443                case 0211:
1444                case 0212:
1445                case 0214:
1446                        c -= 0200;
1447                        break;
1448                case 0215:
1449                        c = '\n';
1450                        break;
1451                }
1452                lastc = c;
1453                if (isprint(c) || isspace(c))
1454                        (void) putchar(c);
1455                else
1456                        (void) putchar(c ^ 100);
1457        }
1458        if (lastc != '\n')
1459                (void) putchar('\n');
1460        (void) fclose(f);
1461        return (1);
1462}
1463
1464/*
1465 * Local Variables:
1466 * mode: c
1467 * c-indent-level: 8
1468 * c-continued-statement-offset: 8
1469 * c-brace-offset: -8
1470 * c-argdecl-indent: 8
1471 * c-label-offset: -8
1472 * End:
1473 */
Note: See TracBrowser for help on using the repository browser.