121554Sdist /* 235627Sbostic * Copyright (c) 1980 The Regents of the University of California. 335627Sbostic * All rights reserved. 435627Sbostic * 535627Sbostic * Redistribution and use in source and binary forms are permitted 635627Sbostic * provided that the above copyright notice and this paragraph are 735627Sbostic * duplicated in all such forms and that any documentation, 835627Sbostic * advertising materials, and other materials related to such 935627Sbostic * distribution and use acknowledge that the software was developed 1035627Sbostic * by the University of California, Berkeley. The name of the 1135627Sbostic * University may not be used to endorse or promote products derived 1235627Sbostic * from this software without specific prior written permission. 1335627Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1435627Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1535627Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1621554Sdist */ 1721554Sdist 1813619Ssam #ifndef lint 1921554Sdist char copyright[] = 2035627Sbostic "@(#) Copyright (c) 1980 The Regents of the University of California.\n\ 2121554Sdist All rights reserved.\n"; 2235627Sbostic #endif /* not lint */ 231014Sbill 2421554Sdist #ifndef lint 25*37629Sbostic static char sccsid[] = "@(#)finger.c 5.12 (Berkeley) 05/04/89"; 2635627Sbostic #endif /* not lint */ 2721554Sdist 2818606Sedward /* 2918606Sedward * This is a finger program. It prints out useful information about users 3018606Sedward * by digging it up from various system files. It is not very portable 3118606Sedward * because the most useful parts of the information (the full user name, 3218606Sedward * office, and phone numbers) are all stored in the VAX-unused gecos field 3318606Sedward * of /etc/passwd, which, unfortunately, other UNIXes use for other things. 341014Sbill * 3518606Sedward * There are three output formats, all of which give login name, teletype 3618606Sedward * line number, and login time. The short output format is reminiscent 3718606Sedward * of finger on ITS, and gives one line of information per user containing 3818606Sedward * in addition to the minimum basic requirements (MBR), the full name of 3918606Sedward * the user, his idle time and office location and phone number. The 4018606Sedward * quick style output is UNIX who-like, giving only name, teletype and 4118606Sedward * login time. Finally, the long style output give the same information 4218606Sedward * as the short (in more legible format), the home directory and shell 4318606Sedward * of the user, and, if it exits, a copy of the file .plan in the users 4418606Sedward * home directory. Finger may be called with or without a list of people 4518606Sedward * to finger -- if no list is given, all the people currently logged in 4618606Sedward * are fingered. 471014Sbill * 4818606Sedward * The program is validly called by one of the following: 491014Sbill * 501014Sbill * finger {short form list of users} 511014Sbill * finger -l {long form list of users} 521014Sbill * finger -b {briefer long form list of users} 531014Sbill * finger -q {quick list of users} 541014Sbill * finger -i {quick list of users with idle times} 551014Sbill * finger namelist {long format list of specified users} 561014Sbill * finger -s namelist {short format list of specified users} 571014Sbill * finger -w namelist {narrow short format list of specified users} 581014Sbill * 5918606Sedward * where 'namelist' is a list of users login names. 6018606Sedward * The other options can all be given after one '-', or each can have its 6118606Sedward * own '-'. The -f option disables the printing of headers for short and 6218606Sedward * quick outputs. The -b option briefens long format outputs. The -p 6318606Sedward * option turns off plans for long format outputs. 641014Sbill */ 651014Sbill 6618606Sedward #include <sys/types.h> 6718606Sedward #include <sys/stat.h> 6818606Sedward #include <sys/signal.h> 6918606Sedward #include <sys/time.h> 7018606Sedward #include <sys/socket.h> 7118606Sedward #include <netinet/in.h> 7218606Sedward #include <netdb.h> 73*37629Sbostic #include <utmp.h> 74*37629Sbostic #include <pwd.h> 75*37629Sbostic #include <stdio.h> 76*37629Sbostic #include <ctype.h> 77*37629Sbostic #include "pathnames.h" 781014Sbill 7918606Sedward #define ASTERISK '*' /* ignore this in real name */ 8018606Sedward #define COMMA ',' /* separator in pw_gecos field */ 8118606Sedward #define COMMAND '-' /* command line flag char */ 8218606Sedward #define CORY 'C' /* cory hall office */ 8318606Sedward #define EVANS 'E' /* evans hall office */ 8418606Sedward #define SAMENAME '&' /* repeat login name in real name */ 8526869Smckusick #define TALKABLE 0220 /* tty is writable if 220 mode */ 861014Sbill 8718606Sedward struct utmp user; 8818606Sedward #define NMAX sizeof(user.ut_name) 8918606Sedward #define LMAX sizeof(user.ut_line) 9018606Sedward #define HMAX sizeof(user.ut_host) 911014Sbill 9218606Sedward struct person { /* one for each person fingered */ 9318606Sedward char *name; /* name */ 9418606Sedward char tty[LMAX+1]; /* null terminated tty line */ 9518606Sedward char host[HMAX+1]; /* null terminated remote host name */ 9618606Sedward long loginat; /* time of (last) login */ 9718606Sedward long idletime; /* how long idle (if logged in) */ 9818606Sedward char *realname; /* pointer to full name */ 9918606Sedward char *office; /* pointer to office name */ 10018606Sedward char *officephone; /* pointer to office phone no. */ 10118606Sedward char *homephone; /* pointer to home phone no. */ 10218606Sedward char *random; /* for any random stuff in pw_gecos */ 10318606Sedward struct passwd *pwd; /* structure of /etc/passwd stuff */ 10418606Sedward char loggedin; /* person is logged in */ 10518606Sedward char writable; /* tty is writable */ 10618606Sedward char original; /* this is not a duplicate entry */ 10718606Sedward struct person *link; /* link to next person */ 1081014Sbill }; 1091014Sbill 11018606Sedward char PLAN[] = "/.plan"; /* what plan file is */ 11118606Sedward char PROJ[] = "/.project"; /* what project file */ 11218606Sedward 11318606Sedward int unbrief = 1; /* -b option default */ 11418606Sedward int header = 1; /* -f option default */ 11518606Sedward int hack = 1; /* -h option default */ 11618606Sedward int idle = 0; /* -i option default */ 11718606Sedward int large = 0; /* -l option default */ 11818606Sedward int match = 1; /* -m option default */ 11918606Sedward int plan = 1; /* -p option default */ 12018606Sedward int unquick = 1; /* -q option default */ 12118606Sedward int small = 0; /* -s option default */ 12218606Sedward int wide = 1; /* -w option default */ 1231014Sbill 12418606Sedward int unshort; 125*37629Sbostic int lf; /* _PATH_LASTLOG file descriptor */ 12618606Sedward struct person *person1; /* list of people */ 12718606Sedward long tloc; /* current time */ 1281014Sbill 12918606Sedward struct passwd *pwdcopy(); 13018606Sedward char *strcpy(); 13118606Sedward char *malloc(); 13218606Sedward char *ctime(); 1331014Sbill 13418606Sedward main(argc, argv) 13518606Sedward int argc; 13618606Sedward register char **argv; 13718606Sedward { 13818606Sedward FILE *fp; 13918606Sedward register char *s; 1401014Sbill 14118606Sedward /* parse command line for (optional) arguments */ 14218606Sedward while (*++argv && **argv == COMMAND) 14318606Sedward for (s = *argv + 1; *s; s++) 14418606Sedward switch (*s) { 14518606Sedward case 'b': 14618606Sedward unbrief = 0; 14718606Sedward break; 14818606Sedward case 'f': 14918606Sedward header = 0; 15018606Sedward break; 15118606Sedward case 'h': 15218606Sedward hack = 0; 15318606Sedward break; 15418606Sedward case 'i': 15518606Sedward idle = 1; 15618606Sedward unquick = 0; 15718606Sedward break; 15818606Sedward case 'l': 15918606Sedward large = 1; 16018606Sedward break; 16118606Sedward case 'm': 16218606Sedward match = 0; 16318606Sedward break; 16418606Sedward case 'p': 16518606Sedward plan = 0; 16618606Sedward break; 16718606Sedward case 'q': 16818606Sedward unquick = 0; 16918606Sedward break; 17018606Sedward case 's': 17118606Sedward small = 1; 17218606Sedward break; 17318606Sedward case 'w': 17418606Sedward wide = 0; 17518606Sedward break; 17618606Sedward default: 17718606Sedward fprintf(stderr, "Usage: finger [-bfhilmpqsw] [login1 [login2 ...] ]\n"); 17818606Sedward exit(1); 17918606Sedward } 18018606Sedward if (unquick || idle) 18118606Sedward time(&tloc); 18218606Sedward /* 18318606Sedward * *argv == 0 means no names given 18418606Sedward */ 18518606Sedward if (*argv == 0) 18618606Sedward doall(); 18718606Sedward else 18818606Sedward donames(argv); 18924461Sedward if (person1) 19024461Sedward print(); 19118606Sedward exit(0); 19218606Sedward } 1931014Sbill 19418606Sedward doall() 1951014Sbill { 19618606Sedward register struct person *p; 19718606Sedward register struct passwd *pw; 19818606Sedward int uf; 19918606Sedward char name[NMAX + 1]; 2001014Sbill 20118606Sedward unshort = large; 202*37629Sbostic if ((uf = open(_PATH_UTMP, 0)) < 0) { 203*37629Sbostic fprintf(stderr, "finger: error opening %s\n", _PATH_UTMP); 20418606Sedward exit(2); 2051014Sbill } 20618606Sedward if (unquick) { 2071014Sbill 2081014Sbill setpwent(); 2091014Sbill fwopen(); 21018606Sedward } 21118606Sedward while (read(uf, (char *)&user, sizeof user) == sizeof user) { 21218606Sedward if (user.ut_name[0] == 0) 21318606Sedward continue; 21418606Sedward if (person1 == 0) 21518606Sedward p = person1 = (struct person *) malloc(sizeof *p); 21618606Sedward else { 21718606Sedward p->link = (struct person *) malloc(sizeof *p); 2181014Sbill p = p->link; 2191014Sbill } 22018606Sedward bcopy(user.ut_name, name, NMAX); 22118606Sedward name[NMAX] = 0; 22218606Sedward bcopy(user.ut_line, p->tty, LMAX); 22318606Sedward p->tty[LMAX] = 0; 22418606Sedward bcopy(user.ut_host, p->host, HMAX); 22518606Sedward p->host[HMAX] = 0; 22618606Sedward p->loginat = user.ut_time; 22718606Sedward p->pwd = 0; 22818606Sedward p->loggedin = 1; 22918606Sedward if (unquick && (pw = getpwnam(name))) { 23018606Sedward p->pwd = pwdcopy(pw); 23118606Sedward decode(p); 23218606Sedward p->name = p->pwd->pw_name; 23318606Sedward } else 23418606Sedward p->name = strcpy(malloc(strlen(name) + 1), name); 23518606Sedward } 23618606Sedward if (unquick) { 2371014Sbill fwclose(); 2381014Sbill endpwent(); 2391014Sbill } 24018606Sedward close(uf); 24118606Sedward if (person1 == 0) { 24218606Sedward printf("No one logged on\n"); 24324461Sedward return; 24418606Sedward } 24518606Sedward p->link = 0; 24618606Sedward } 2471014Sbill 24818606Sedward donames(argv) 24918606Sedward char **argv; 25018606Sedward { 25118606Sedward register struct person *p; 25218606Sedward register struct passwd *pw; 25318606Sedward int uf; 2541014Sbill 25518606Sedward /* 25618606Sedward * get names from command line and check to see if they're 25718606Sedward * logged in 25818606Sedward */ 25918606Sedward unshort = !small; 26018606Sedward for (; *argv != 0; argv++) { 26118606Sedward if (netfinger(*argv)) 26218606Sedward continue; 26318606Sedward if (person1 == 0) 26418606Sedward p = person1 = (struct person *) malloc(sizeof *p); 26518606Sedward else { 26618606Sedward p->link = (struct person *) malloc(sizeof *p); 26718606Sedward p = p->link; 26816469Ssam } 26918606Sedward p->name = *argv; 2701014Sbill p->loggedin = 0; 27118606Sedward p->original = 1; 27218606Sedward p->pwd = 0; 27318606Sedward } 27424461Sedward if (person1 == 0) 27524461Sedward return; 27618606Sedward p->link = 0; 27718606Sedward /* 27818606Sedward * if we are doing it, read /etc/passwd for the useful info 27918606Sedward */ 28018606Sedward if (unquick) { 28118606Sedward setpwent(); 28218606Sedward if (!match) { 28318606Sedward for (p = person1; p != 0; p = p->link) 28418606Sedward if (pw = getpwnam(p->name)) 28518606Sedward p->pwd = pwdcopy(pw); 28618606Sedward } else while ((pw = getpwent()) != 0) { 28718606Sedward for (p = person1; p != 0; p = p->link) { 28818606Sedward if (!p->original) 28918606Sedward continue; 29018606Sedward if (strcmp(p->name, pw->pw_name) != 0 && 29118606Sedward !matchcmp(pw->pw_gecos, pw->pw_name, p->name)) 29218606Sedward continue; 29318606Sedward if (p->pwd == 0) 29418606Sedward p->pwd = pwdcopy(pw); 29518606Sedward else { 29618606Sedward struct person *new; 29718606Sedward /* 29818606Sedward * handle multiple login names, insert 29918606Sedward * new "duplicate" entry behind 30018606Sedward */ 30118606Sedward new = (struct person *) 30218606Sedward malloc(sizeof *new); 30318606Sedward new->pwd = pwdcopy(pw); 30418606Sedward new->name = p->name; 30518606Sedward new->original = 1; 30618606Sedward new->loggedin = 0; 30718606Sedward new->link = p->link; 30818606Sedward p->original = 0; 30918606Sedward p->link = new; 31018606Sedward p = new; 31118606Sedward } 3121014Sbill } 3131014Sbill } 3141014Sbill endpwent(); 31518606Sedward } 31618606Sedward /* Now get login information */ 317*37629Sbostic if ((uf = open(_PATH_UTMP, 0)) < 0) { 318*37629Sbostic fprintf(stderr, "finger: error opening %s\n", _PATH_UTMP); 31918606Sedward exit(2); 32018606Sedward } 32118606Sedward while (read(uf, (char *)&user, sizeof user) == sizeof user) { 32218606Sedward if (*user.ut_name == 0) 32318606Sedward continue; 32418606Sedward for (p = person1; p != 0; p = p->link) { 32518606Sedward if (p->loggedin == 2) 32618606Sedward continue; 32718606Sedward if (strncmp(p->pwd ? p->pwd->pw_name : p->name, 32818606Sedward user.ut_name, NMAX) != 0) 32918606Sedward continue; 33018606Sedward if (p->loggedin == 0) { 33118606Sedward bcopy(user.ut_line, p->tty, LMAX); 33218606Sedward p->tty[LMAX] = 0; 33318606Sedward bcopy(user.ut_host, p->host, HMAX); 33418606Sedward p->host[HMAX] = 0; 33518606Sedward p->loginat = user.ut_time; 33618606Sedward p->loggedin = 1; 33718606Sedward } else { /* p->loggedin == 1 */ 33818606Sedward struct person *new; 33918606Sedward new = (struct person *) malloc(sizeof *new); 34018606Sedward new->name = p->name; 34118606Sedward bcopy(user.ut_line, new->tty, LMAX); 34218606Sedward new->tty[LMAX] = 0; 34318606Sedward bcopy(user.ut_host, new->host, HMAX); 34418606Sedward new->host[HMAX] = 0; 34518606Sedward new->loginat = user.ut_time; 34618606Sedward new->pwd = p->pwd; 34718606Sedward new->loggedin = 1; 34818606Sedward new->original = 0; 34918606Sedward new->link = p->link; 35018606Sedward p->loggedin = 2; 35118606Sedward p->link = new; 35218606Sedward p = new; 3531014Sbill } 3541014Sbill } 35518606Sedward } 35618606Sedward close(uf); 35718606Sedward if (unquick) { 3581014Sbill fwopen(); 35918606Sedward for (p = person1; p != 0; p = p->link) 36018606Sedward decode(p); 3611014Sbill fwclose(); 3621014Sbill } 36318606Sedward } 3641014Sbill 36518606Sedward print() 36618606Sedward { 36718606Sedward register FILE *fp; 36818606Sedward register struct person *p; 36918606Sedward register char *s; 37018606Sedward register c; 3711014Sbill 37218606Sedward /* 37318606Sedward * print out what we got 37418606Sedward */ 37518606Sedward if (header) { 37618606Sedward if (unquick) { 37718606Sedward if (!unshort) 37818606Sedward if (wide) 37918606Sedward printf("Login Name TTY Idle When Office\n"); 38018606Sedward else 38118606Sedward printf("Login TTY Idle When Office\n"); 38218606Sedward } else { 38318606Sedward printf("Login TTY When"); 38418606Sedward if (idle) 38518606Sedward printf(" Idle"); 38618606Sedward putchar('\n'); 3871014Sbill } 38818606Sedward } 38918606Sedward for (p = person1; p != 0; p = p->link) { 39018606Sedward if (!unquick) { 39118606Sedward quickprint(p); 39218606Sedward continue; 3931014Sbill } 39418606Sedward if (!unshort) { 39518606Sedward shortprint(p); 39618606Sedward continue; 39718606Sedward } 39818606Sedward personprint(p); 39918606Sedward if (p->pwd != 0) { 40018606Sedward if (hack) { 40118606Sedward s = malloc(strlen(p->pwd->pw_dir) + 40218606Sedward sizeof PROJ); 40318606Sedward strcpy(s, p->pwd->pw_dir); 40418606Sedward strcat(s, PROJ); 40518606Sedward if ((fp = fopen(s, "r")) != 0) { 40618606Sedward printf("Project: "); 40718606Sedward while ((c = getc(fp)) != EOF) { 40818606Sedward if (c == '\n') 40918606Sedward break; 41025589Sbloom if (isprint(c) || isspace(c)) 41125589Sbloom putchar(c); 41225589Sbloom else 41325589Sbloom putchar(c ^ 100); 41418606Sedward } 41518606Sedward fclose(fp); 41618606Sedward putchar('\n'); 4171014Sbill } 41818606Sedward free(s); 4191014Sbill } 42018606Sedward if (plan) { 42118606Sedward s = malloc(strlen(p->pwd->pw_dir) + 42218606Sedward sizeof PLAN); 42318606Sedward strcpy(s, p->pwd->pw_dir); 42418606Sedward strcat(s, PLAN); 42518606Sedward if ((fp = fopen(s, "r")) == 0) 42618606Sedward printf("No Plan.\n"); 42718606Sedward else { 42818606Sedward printf("Plan:\n"); 42918606Sedward while ((c = getc(fp)) != EOF) 43025589Sbloom if (isprint(c) || isspace(c)) 43125589Sbloom putchar(c); 43225589Sbloom else 43325589Sbloom putchar(c ^ 100); 43418606Sedward fclose(fp); 4351014Sbill } 43618606Sedward free(s); 4371014Sbill } 4381014Sbill } 43918606Sedward if (p->link != 0) 44018606Sedward putchar('\n'); 44118606Sedward } 4421014Sbill } 4431014Sbill 44418606Sedward /* 44518606Sedward * Duplicate a pwd entry. 44618606Sedward * Note: Only the useful things (what the program currently uses) are copied. 4471014Sbill */ 44818606Sedward struct passwd * 44918606Sedward pwdcopy(pfrom) 45018606Sedward register struct passwd *pfrom; 45118606Sedward { 45218606Sedward register struct passwd *pto; 4531014Sbill 45418606Sedward pto = (struct passwd *) malloc(sizeof *pto); 45518606Sedward #define savestr(s) strcpy(malloc(strlen(s) + 1), s) 45618606Sedward pto->pw_name = savestr(pfrom->pw_name); 4571014Sbill pto->pw_uid = pfrom->pw_uid; 45818606Sedward pto->pw_gecos = savestr(pfrom->pw_gecos); 45918606Sedward pto->pw_dir = savestr(pfrom->pw_dir); 46018606Sedward pto->pw_shell = savestr(pfrom->pw_shell); 46118606Sedward #undef savestr 46218606Sedward return pto; 4631014Sbill } 4641014Sbill 46518606Sedward /* 46618606Sedward * print out information on quick format giving just name, tty, login time 46718606Sedward * and idle time if idle is set. 4681014Sbill */ 46918606Sedward quickprint(pers) 47018606Sedward register struct person *pers; 4711014Sbill { 47218606Sedward printf("%-*.*s ", NMAX, NMAX, pers->name); 47318606Sedward if (pers->loggedin) { 47418606Sedward if (idle) { 47518606Sedward findidle(pers); 47618606Sedward printf("%c%-*s %-16.16s", pers->writable ? ' ' : '*', 47718606Sedward LMAX, pers->tty, ctime(&pers->loginat)); 47818606Sedward ltimeprint(" ", &pers->idletime, ""); 47918606Sedward } else 48018606Sedward printf(" %-*s %-16.16s", LMAX, 48118606Sedward pers->tty, ctime(&pers->loginat)); 48218606Sedward putchar('\n'); 48318606Sedward } else 48418606Sedward printf(" Not Logged In\n"); 4851014Sbill } 4861014Sbill 48718606Sedward /* 48818606Sedward * print out information in short format, giving login name, full name, 48918606Sedward * tty, idle time, login time, office location and phone. 4901014Sbill */ 49118606Sedward shortprint(pers) 49218606Sedward register struct person *pers; 4931014Sbill { 49418606Sedward char *p; 49518606Sedward char dialup; 4961014Sbill 49718606Sedward if (pers->pwd == 0) { 49818606Sedward printf("%-15s ???\n", pers->name); 49918606Sedward return; 5001014Sbill } 50118606Sedward printf("%-*s", NMAX, pers->pwd->pw_name); 5021014Sbill dialup = 0; 50318606Sedward if (wide) { 50418606Sedward if (pers->realname) 50518606Sedward printf(" %-20.20s", pers->realname); 50618606Sedward else 50718606Sedward printf(" ??? "); 5081014Sbill } 50918606Sedward putchar(' '); 51018606Sedward if (pers->loggedin && !pers->writable) 51118606Sedward putchar('*'); 51218606Sedward else 51318606Sedward putchar(' '); 51418606Sedward if (*pers->tty) { 51518606Sedward if (pers->tty[0] == 't' && pers->tty[1] == 't' && 51618606Sedward pers->tty[2] == 'y') { 51718606Sedward if (pers->tty[3] == 'd' && pers->loggedin) 51818606Sedward dialup = 1; 51918606Sedward printf("%-2.2s ", pers->tty + 3); 52018606Sedward } else 52118606Sedward printf("%-2.2s ", pers->tty); 52218606Sedward } else 52318606Sedward printf(" "); 52418606Sedward p = ctime(&pers->loginat); 52518606Sedward if (pers->loggedin) { 52618606Sedward stimeprint(&pers->idletime); 52718606Sedward printf(" %3.3s %-5.5s ", p, p + 11); 52818606Sedward } else if (pers->loginat == 0) 52918606Sedward printf(" < . . . . >"); 5308842Smckusick else if (tloc - pers->loginat >= 180 * 24 * 60 * 60) 53118606Sedward printf(" <%-6.6s, %-4.4s>", p + 4, p + 20); 5328842Smckusick else 53318606Sedward printf(" <%-12.12s>", p + 4); 53418606Sedward if (dialup && pers->homephone) 53518606Sedward printf(" %20s", pers->homephone); 53618606Sedward else { 53718606Sedward if (pers->office) 53818606Sedward printf(" %-11.11s", pers->office); 53918606Sedward else if (pers->officephone || pers->homephone) 54018606Sedward printf(" "); 54118606Sedward if (pers->officephone) 54218606Sedward printf(" %s", pers->officephone); 54318606Sedward else if (pers->homephone) 54418606Sedward printf(" %s", pers->homephone); 5451014Sbill } 54618606Sedward putchar('\n'); 5471014Sbill } 5481014Sbill 54918606Sedward /* 55018606Sedward * print out a person in long format giving all possible information. 55118606Sedward * directory and shell are inhibited if unbrief is clear. 5521014Sbill */ 55318606Sedward personprint(pers) 55418606Sedward register struct person *pers; 5551014Sbill { 55618606Sedward if (pers->pwd == 0) { 55718606Sedward printf("Login name: %-10s\t\t\tIn real life: ???\n", 55818606Sedward pers->name); 55918606Sedward return; 5601014Sbill } 56118606Sedward printf("Login name: %-10s", pers->pwd->pw_name); 56218606Sedward if (pers->loggedin && !pers->writable) 56318606Sedward printf(" (messages off) "); 56418606Sedward else 56518606Sedward printf(" "); 56618606Sedward if (pers->realname) 56718606Sedward printf("In real life: %s", pers->realname); 56818606Sedward if (pers->office) { 56918606Sedward printf("\nOffice: %-.11s", pers->office); 57018606Sedward if (pers->officephone) { 57118606Sedward printf(", %s", pers->officephone); 57218606Sedward if (pers->homephone) 57318606Sedward printf("\t\tHome phone: %s", pers->homephone); 57418606Sedward else if (pers->random) 57518606Sedward printf("\t\t%s", pers->random); 57618606Sedward } else 57718606Sedward if (pers->homephone) 57818606Sedward printf("\t\t\tHome phone: %s", pers->homephone); 57918606Sedward else if (pers->random) 58018606Sedward printf("\t\t\t%s", pers->random); 58118606Sedward } else if (pers->officephone) { 58218606Sedward printf("\nPhone: %s", pers->officephone); 58318606Sedward if (pers->homephone) 58418606Sedward printf(", %s", pers->homephone); 58518606Sedward if (pers->random) 58618606Sedward printf(", %s", pers->random); 58718606Sedward } else if (pers->homephone) { 58818606Sedward printf("\nPhone: %s", pers->homephone); 58918606Sedward if (pers->random) 59018606Sedward printf(", %s", pers->random); 59118606Sedward } else if (pers->random) 59218606Sedward printf("\n%s", pers->random); 59318606Sedward if (unbrief) { 59418606Sedward printf("\nDirectory: %-25s", pers->pwd->pw_dir); 59518606Sedward if (*pers->pwd->pw_shell) 59618606Sedward printf("\tShell: %-s", pers->pwd->pw_shell); 5971014Sbill } 59818606Sedward if (pers->loggedin) { 59918606Sedward register char *ep = ctime(&pers->loginat); 60018606Sedward if (*pers->host) { 60118606Sedward printf("\nOn since %15.15s on %s from %s", 60218606Sedward &ep[4], pers->tty, pers->host); 60318606Sedward ltimeprint("\n", &pers->idletime, " Idle Time"); 60418606Sedward } else { 60518606Sedward printf("\nOn since %15.15s on %-*s", 60618606Sedward &ep[4], LMAX, pers->tty); 60718606Sedward ltimeprint("\t", &pers->idletime, " Idle Time"); 6081014Sbill } 60918606Sedward } else if (pers->loginat == 0) 61018606Sedward printf("\nNever logged in."); 6118842Smckusick else if (tloc - pers->loginat > 180 * 24 * 60 * 60) { 61218606Sedward register char *ep = ctime(&pers->loginat); 61318606Sedward printf("\nLast login %10.10s, %4.4s on %s", 61418606Sedward ep, ep+20, pers->tty); 61518606Sedward if (*pers->host) 61618606Sedward printf(" from %s", pers->host); 61718606Sedward } else { 61818606Sedward register char *ep = ctime(&pers->loginat); 61918606Sedward printf("\nLast login %16.16s on %s", ep, pers->tty); 62018606Sedward if (*pers->host) 62118606Sedward printf(" from %s", pers->host); 6228842Smckusick } 62318606Sedward putchar('\n'); 6241014Sbill } 6251014Sbill 6261014Sbill /* 6271014Sbill * very hacky section of code to format phone numbers. filled with 6281014Sbill * magic constants like 4, 7 and 10. 6291014Sbill */ 63018606Sedward char * 63118606Sedward phone(s, len, alldigits) 63218606Sedward register char *s; 63318606Sedward int len; 63418606Sedward char alldigits; 6351014Sbill { 63618606Sedward char fonebuf[15]; 63718606Sedward register char *p = fonebuf; 63818606Sedward register i; 6391014Sbill 64018606Sedward if (!alldigits) 64118606Sedward return (strcpy(malloc(len + 1), s)); 64218606Sedward switch (len) { 64318606Sedward case 4: 64418606Sedward *p++ = ' '; 64518606Sedward *p++ = 'x'; 64618606Sedward *p++ = '2'; 64718606Sedward *p++ = '-'; 64818606Sedward for (i = 0; i < 4; i++) 64918606Sedward *p++ = *s++; 6501014Sbill break; 65124463Sbloom case 5: 65224463Sbloom *p++ = ' '; 65324463Sbloom *p++ = 'x'; 65424463Sbloom *p++ = *s++; 65524463Sbloom *p++ = '-'; 65624463Sbloom for (i = 0; i < 4; i++) 65724463Sbloom *p++ = *s++; 65824463Sbloom break; 65918606Sedward case 7: 66018606Sedward for (i = 0; i < 3; i++) 66118606Sedward *p++ = *s++; 66218606Sedward *p++ = '-'; 66318606Sedward for (i = 0; i < 4; i++) 66418606Sedward *p++ = *s++; 6651014Sbill break; 66618606Sedward case 10: 66718606Sedward for (i = 0; i < 3; i++) 66818606Sedward *p++ = *s++; 66918606Sedward *p++ = '-'; 67018606Sedward for (i = 0; i < 3; i++) 67118606Sedward *p++ = *s++; 67218606Sedward *p++ = '-'; 67318606Sedward for (i = 0; i < 4; i++) 67418606Sedward *p++ = *s++; 6751014Sbill break; 67618606Sedward case 0: 67718606Sedward return 0; 67818606Sedward default: 67918606Sedward return (strcpy(malloc(len + 1), s)); 6801014Sbill } 68118606Sedward *p++ = 0; 68218606Sedward return (strcpy(malloc(p - fonebuf), fonebuf)); 6831014Sbill } 6841014Sbill 68518606Sedward /* 68618606Sedward * decode the information in the gecos field of /etc/passwd 6871014Sbill */ 68818606Sedward decode(pers) 68918606Sedward register struct person *pers; 6901014Sbill { 69118606Sedward char buffer[256]; 69218606Sedward register char *bp, *gp, *lp; 69318606Sedward int alldigits; 69418606Sedward int hasspace; 69518606Sedward int len; 6961014Sbill 69718606Sedward pers->realname = 0; 69818606Sedward pers->office = 0; 69918606Sedward pers->officephone = 0; 70018606Sedward pers->homephone = 0; 70118606Sedward pers->random = 0; 70218606Sedward if (pers->pwd == 0) 70318606Sedward return; 70418606Sedward gp = pers->pwd->pw_gecos; 70518606Sedward bp = buffer; 70618606Sedward if (*gp == ASTERISK) 7071014Sbill gp++; 70818606Sedward while (*gp && *gp != COMMA) /* name */ 70918606Sedward if (*gp == SAMENAME) { 71018606Sedward lp = pers->pwd->pw_name; 71118606Sedward if (islower(*lp)) 71218606Sedward *bp++ = toupper(*lp++); 71318606Sedward while (*bp++ = *lp++) 71418606Sedward ; 71518606Sedward bp--; 71618606Sedward gp++; 71718606Sedward } else 71818606Sedward *bp++ = *gp++; 71918606Sedward *bp++ = 0; 72018606Sedward if ((len = bp - buffer) > 1) 72118606Sedward pers->realname = strcpy(malloc(len), buffer); 72218606Sedward if (*gp == COMMA) { /* office */ 72318606Sedward gp++; 72418606Sedward hasspace = 0; 72518606Sedward bp = buffer; 72618606Sedward while (*gp && *gp != COMMA) { 72718606Sedward *bp = *gp++; 72818606Sedward if (*bp == ' ') 72918606Sedward hasspace = 1; 73018606Sedward /* leave 5 for Cory and Evans expansion */ 73118606Sedward if (bp < buffer + sizeof buffer - 6) 73218606Sedward bp++; 7331014Sbill } 73418606Sedward *bp = 0; 73518606Sedward len = bp - buffer; 73618606Sedward bp--; /* point to last character */ 73718606Sedward if (hasspace || len == 0) 73818606Sedward len++; 73918606Sedward else if (*bp == CORY) { 74018606Sedward strcpy(bp, " Cory"); 74118606Sedward len += 5; 74218606Sedward } else if (*bp == EVANS) { 74318606Sedward strcpy(bp, " Evans"); 74418606Sedward len += 6; 74518606Sedward } else 74618606Sedward len++; 74718606Sedward if (len > 1) 74818606Sedward pers->office = strcpy(malloc(len), buffer); 74918606Sedward } 75018606Sedward if (*gp == COMMA) { /* office phone */ 75118606Sedward gp++; 75218606Sedward bp = buffer; 75318606Sedward alldigits = 1; 75418606Sedward while (*gp && *gp != COMMA) { 75518606Sedward *bp = *gp++; 75618606Sedward if (!isdigit(*bp)) 75718606Sedward alldigits = 0; 75818606Sedward if (bp < buffer + sizeof buffer - 1) 75918606Sedward bp++; 7601014Sbill } 76118606Sedward *bp = 0; 76218606Sedward pers->officephone = phone(buffer, bp - buffer, alldigits); 76318606Sedward } 76418606Sedward if (*gp == COMMA) { /* home phone */ 7651014Sbill gp++; 76618606Sedward bp = buffer; 7671014Sbill alldigits = 1; 76818606Sedward while (*gp && *gp != COMMA) { 7691014Sbill *bp = *gp++; 77018606Sedward if (!isdigit(*bp)) 77118606Sedward alldigits = 0; 77218606Sedward if (bp < buffer + sizeof buffer - 1) 7731014Sbill bp++; 7741014Sbill } 77518606Sedward *bp = 0; 77618606Sedward pers->homephone = phone(buffer, bp - buffer, alldigits); 7771014Sbill } 77818606Sedward if (pers->loggedin) 77918606Sedward findidle(pers); 78018606Sedward else 78118606Sedward findwhen(pers); 7821014Sbill } 7831014Sbill 78418606Sedward /* 785*37629Sbostic * find the last log in of a user by checking the _PATH_LASTLOG file. 78618606Sedward * the entry is indexed by the uid, so this can only be done if 78718606Sedward * the uid is known (which it isn't in quick mode) 7881014Sbill */ 7891014Sbill 7901014Sbill fwopen() 7911014Sbill { 792*37629Sbostic if ((lf = open(_PATH_LASTLOG, 0)) < 0) 793*37629Sbostic fprintf(stderr, "finger: %s open error\n", _PATH_LASTLOG); 7941014Sbill } 7951014Sbill 79618606Sedward findwhen(pers) 79718606Sedward register struct person *pers; 7981014Sbill { 79918606Sedward struct lastlog ll; 80018606Sedward int i; 8011014Sbill 80218606Sedward if (lf >= 0) { 80318606Sedward lseek(lf, (long)pers->pwd->pw_uid * sizeof ll, 0); 80418606Sedward if ((i = read(lf, (char *)&ll, sizeof ll)) == sizeof ll) { 80518606Sedward bcopy(ll.ll_line, pers->tty, LMAX); 80618606Sedward pers->tty[LMAX] = 0; 80718606Sedward bcopy(ll.ll_host, pers->host, HMAX); 80818606Sedward pers->host[HMAX] = 0; 80918606Sedward pers->loginat = ll.ll_time; 81018606Sedward } else { 81118606Sedward if (i != 0) 81218606Sedward fprintf(stderr, "finger: %s read error\n", 813*37629Sbostic _PATH_LASTLOG); 81418606Sedward pers->tty[0] = 0; 81518606Sedward pers->host[0] = 0; 81618606Sedward pers->loginat = 0L; 81718606Sedward } 81818606Sedward } else { 81918606Sedward pers->tty[0] = 0; 82018606Sedward pers->host[0] = 0; 8211014Sbill pers->loginat = 0L; 8221014Sbill } 8231014Sbill } 8241014Sbill 8251014Sbill fwclose() 8261014Sbill { 82718606Sedward if (lf >= 0) 82818606Sedward close(lf); 8291014Sbill } 8301014Sbill 83118606Sedward /* 83218606Sedward * find the idle time of a user by doing a stat on /dev/tty??, 833*37629Sbostic * where tty?? has been gotten from _PATH_UTMP, supposedly. 8341014Sbill */ 83518606Sedward findidle(pers) 83618606Sedward register struct person *pers; 8371014Sbill { 83818606Sedward struct stat ttystatus; 839*37629Sbostic static char buffer[20] = _PATH_DEV; 84018606Sedward long t; 84118606Sedward #define TTYLEN 5 8421014Sbill 84318606Sedward strcpy(buffer + TTYLEN, pers->tty); 84418606Sedward buffer[TTYLEN+LMAX] = 0; 84518606Sedward if (stat(buffer, &ttystatus) < 0) { 84618606Sedward fprintf(stderr, "finger: Can't stat %s\n", buffer); 84718606Sedward exit(4); 84818606Sedward } 84918606Sedward time(&t); 85018606Sedward if (t < ttystatus.st_atime) 8511014Sbill pers->idletime = 0L; 85218606Sedward else 85318606Sedward pers->idletime = t - ttystatus.st_atime; 85418606Sedward pers->writable = (ttystatus.st_mode & TALKABLE) == TALKABLE; 8551014Sbill } 8561014Sbill 85718606Sedward /* 85818606Sedward * print idle time in short format; this program always prints 4 characters; 85918606Sedward * if the idle time is zero, it prints 4 blanks. 8601014Sbill */ 86118606Sedward stimeprint(dt) 86218606Sedward long *dt; 8631014Sbill { 86418606Sedward register struct tm *delta; 8651014Sbill 86618606Sedward delta = gmtime(dt); 86718606Sedward if (delta->tm_yday == 0) 86818606Sedward if (delta->tm_hour == 0) 86918606Sedward if (delta->tm_min == 0) 87018606Sedward printf(" "); 87118606Sedward else 87218606Sedward printf(" %2d", delta->tm_min); 87318606Sedward else 87418606Sedward if (delta->tm_hour >= 10) 87518606Sedward printf("%3d:", delta->tm_hour); 87618606Sedward else 87718606Sedward printf("%1d:%02d", 87818606Sedward delta->tm_hour, delta->tm_min); 87918606Sedward else 88018606Sedward printf("%3dd", delta->tm_yday); 8811014Sbill } 8821014Sbill 88318606Sedward /* 88418606Sedward * print idle time in long format with care being taken not to pluralize 88518606Sedward * 1 minutes or 1 hours or 1 days. 88618606Sedward * print "prefix" first. 8871014Sbill */ 88818606Sedward ltimeprint(before, dt, after) 88918606Sedward long *dt; 89018606Sedward char *before, *after; 8911014Sbill { 89218606Sedward register struct tm *delta; 8931014Sbill 89418606Sedward delta = gmtime(dt); 89518606Sedward if (delta->tm_yday == 0 && delta->tm_hour == 0 && delta->tm_min == 0 && 89618606Sedward delta->tm_sec <= 10) 89718606Sedward return (0); 89818606Sedward printf("%s", before); 89918606Sedward if (delta->tm_yday >= 10) 90018606Sedward printf("%d days", delta->tm_yday); 90118606Sedward else if (delta->tm_yday > 0) 90218606Sedward printf("%d day%s %d hour%s", 90318606Sedward delta->tm_yday, delta->tm_yday == 1 ? "" : "s", 90418606Sedward delta->tm_hour, delta->tm_hour == 1 ? "" : "s"); 90518606Sedward else 90618606Sedward if (delta->tm_hour >= 10) 90718606Sedward printf("%d hours", delta->tm_hour); 90818606Sedward else if (delta->tm_hour > 0) 90918606Sedward printf("%d hour%s %d minute%s", 91018606Sedward delta->tm_hour, delta->tm_hour == 1 ? "" : "s", 91118606Sedward delta->tm_min, delta->tm_min == 1 ? "" : "s"); 91218606Sedward else 91318606Sedward if (delta->tm_min >= 10) 91418606Sedward printf("%2d minutes", delta->tm_min); 91518606Sedward else if (delta->tm_min == 0) 91618606Sedward printf("%2d seconds", delta->tm_sec); 91718606Sedward else 91818606Sedward printf("%d minute%s %d second%s", 91918606Sedward delta->tm_min, 92018606Sedward delta->tm_min == 1 ? "" : "s", 92118606Sedward delta->tm_sec, 92218606Sedward delta->tm_sec == 1 ? "" : "s"); 92318606Sedward printf("%s", after); 9241014Sbill } 9251014Sbill 92618606Sedward matchcmp(gname, login, given) 92718606Sedward register char *gname; 92818606Sedward char *login; 92918606Sedward char *given; 9301014Sbill { 93118606Sedward char buffer[100]; 93218606Sedward register char *bp, *lp; 93318606Sedward register c; 9341014Sbill 93518606Sedward if (*gname == ASTERISK) 93618606Sedward gname++; 93718606Sedward lp = 0; 93818606Sedward bp = buffer; 93918606Sedward for (;;) 94018606Sedward switch (c = *gname++) { 94118606Sedward case SAMENAME: 94218606Sedward for (lp = login; bp < buffer + sizeof buffer 94318606Sedward && (*bp++ = *lp++);) 94418606Sedward ; 94518606Sedward bp--; 94618606Sedward break; 94718606Sedward case ' ': 94818606Sedward case COMMA: 94918606Sedward case '\0': 95018606Sedward *bp = 0; 95118606Sedward if (namecmp(buffer, given)) 95218606Sedward return (1); 95318606Sedward if (c == COMMA || c == 0) 95418606Sedward return (0); 95518606Sedward bp = buffer; 95618606Sedward break; 95718606Sedward default: 95818606Sedward if (bp < buffer + sizeof buffer) 95918606Sedward *bp++ = c; 9601014Sbill } 96118606Sedward /*NOTREACHED*/ 9621014Sbill } 9631014Sbill 96418606Sedward namecmp(name1, name2) 96518606Sedward register char *name1, *name2; 9661014Sbill { 96718606Sedward register c1, c2; 9681014Sbill 96918606Sedward for (;;) { 97018606Sedward c1 = *name1++; 97118606Sedward if (islower(c1)) 97218606Sedward c1 = toupper(c1); 97318606Sedward c2 = *name2++; 97418606Sedward if (islower(c2)) 97518606Sedward c2 = toupper(c2); 97618606Sedward if (c1 != c2) 97718606Sedward break; 97818606Sedward if (c1 == 0) 97918606Sedward return (1); 9801014Sbill } 98118606Sedward if (!c1) { 98218606Sedward for (name2--; isdigit(*name2); name2++) 98318606Sedward ; 98418606Sedward if (*name2 == 0) 98518606Sedward return (1); 98618606Sedward } else if (!c2) { 98718606Sedward for (name1--; isdigit(*name1); name1++) 98818606Sedward ; 98918606Sedward if (*name2 == 0) 99018606Sedward return (1); 9911014Sbill } 99218606Sedward return (0); 9931014Sbill } 9941014Sbill 99516469Ssam netfinger(name) 99618606Sedward char *name; 99716469Ssam { 99816469Ssam char *host; 99916469Ssam char fname[100]; 100016469Ssam struct hostent *hp; 100116469Ssam struct servent *sp; 100218606Sedward struct sockaddr_in sin; 100316469Ssam int s; 100416469Ssam char *rindex(); 100516469Ssam register FILE *f; 100616469Ssam register int c; 100716469Ssam register int lastc; 100816469Ssam 100916469Ssam if (name == NULL) 101018606Sedward return (0); 101116469Ssam host = rindex(name, '@'); 101216469Ssam if (host == NULL) 101318606Sedward return (0); 101416469Ssam *host++ = 0; 101516469Ssam hp = gethostbyname(host); 101616469Ssam if (hp == NULL) { 101716469Ssam static struct hostent def; 101816469Ssam static struct in_addr defaddr; 101925240Sbloom static char *alist[1]; 102016469Ssam static char namebuf[128]; 102116469Ssam int inet_addr(); 102216469Ssam 102316469Ssam defaddr.s_addr = inet_addr(host); 102416469Ssam if (defaddr.s_addr == -1) { 102516469Ssam printf("unknown host: %s\n", host); 102618606Sedward return (1); 102716469Ssam } 102816469Ssam strcpy(namebuf, host); 102916469Ssam def.h_name = namebuf; 103025239Ssam def.h_addr_list = alist, def.h_addr = (char *)&defaddr; 103116469Ssam def.h_length = sizeof (struct in_addr); 103216469Ssam def.h_addrtype = AF_INET; 103316469Ssam def.h_aliases = 0; 103416469Ssam hp = &def; 103516469Ssam } 103616469Ssam sp = getservbyname("finger", "tcp"); 103716469Ssam if (sp == 0) { 103816469Ssam printf("tcp/finger: unknown service\n"); 103918606Sedward return (1); 104016469Ssam } 104116469Ssam sin.sin_family = hp->h_addrtype; 104216469Ssam bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length); 104316469Ssam sin.sin_port = sp->s_port; 104416469Ssam s = socket(hp->h_addrtype, SOCK_STREAM, 0); 104516469Ssam if (s < 0) { 104616469Ssam perror("socket"); 104718606Sedward return (1); 104816469Ssam } 104930958Sbostic printf("[%s]\n", hp->h_name); 105030958Sbostic fflush(stdout); 105116469Ssam if (connect(s, (char *)&sin, sizeof (sin)) < 0) { 105216469Ssam perror("connect"); 105316469Ssam close(s); 105418606Sedward return (1); 105516469Ssam } 105616469Ssam if (large) write(s, "/W ", 3); 105716469Ssam write(s, name, strlen(name)); 105816469Ssam write(s, "\r\n", 2); 105916469Ssam f = fdopen(s, "r"); 106016469Ssam while ((c = getc(f)) != EOF) { 106116469Ssam switch(c) { 106216469Ssam case 0210: 106316469Ssam case 0211: 106416469Ssam case 0212: 106516469Ssam case 0214: 106616469Ssam c -= 0200; 106716469Ssam break; 106816469Ssam case 0215: 106916469Ssam c = '\n'; 107016469Ssam break; 107116469Ssam } 107225589Sbloom lastc = c; 107325589Sbloom if (isprint(c) || isspace(c)) 107425589Sbloom putchar(c); 107525589Sbloom else 107625589Sbloom putchar(c ^ 100); 107716469Ssam } 107816469Ssam if (lastc != '\n') 107916469Ssam putchar('\n'); 108025121Sbloom (void)fclose(f); 108118606Sedward return (1); 108216469Ssam } 1083