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

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