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

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