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

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