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

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