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

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