121554Sdist /* 221554Sdist * Copyright (c) 1980 Regents of the University of California. 321554Sdist * All rights reserved. The Berkeley software License Agreement 421554Sdist * specifies the terms and conditions for redistribution. 521554Sdist */ 621554Sdist 713619Ssam #ifndef lint 821554Sdist char copyright[] = 921554Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 1021554Sdist All rights reserved.\n"; 1121554Sdist #endif not lint 121014Sbill 1321554Sdist #ifndef lint 14*30958Sbostic static char sccsid[] = "@(#)finger.c 5.10 (Berkeley) 04/26/87"; 1521554Sdist #endif not lint 1621554Sdist 1718606Sedward /* 1818606Sedward * This is a finger program. It prints out useful information about users 1918606Sedward * by digging it up from various system files. It is not very portable 2018606Sedward * because the most useful parts of the information (the full user name, 2118606Sedward * office, and phone numbers) are all stored in the VAX-unused gecos field 2218606Sedward * of /etc/passwd, which, unfortunately, other UNIXes use for other things. 231014Sbill * 2418606Sedward * There are three output formats, all of which give login name, teletype 2518606Sedward * line number, and login time. The short output format is reminiscent 2618606Sedward * of finger on ITS, and gives one line of information per user containing 2718606Sedward * in addition to the minimum basic requirements (MBR), the full name of 2818606Sedward * the user, his idle time and office location and phone number. The 2918606Sedward * quick style output is UNIX who-like, giving only name, teletype and 3018606Sedward * login time. Finally, the long style output give the same information 3118606Sedward * as the short (in more legible format), the home directory and shell 3218606Sedward * of the user, and, if it exits, a copy of the file .plan in the users 3318606Sedward * home directory. Finger may be called with or without a list of people 3418606Sedward * to finger -- if no list is given, all the people currently logged in 3518606Sedward * are fingered. 361014Sbill * 3718606Sedward * The program is validly called by one of the following: 381014Sbill * 391014Sbill * finger {short form list of users} 401014Sbill * finger -l {long form list of users} 411014Sbill * finger -b {briefer long form list of users} 421014Sbill * finger -q {quick list of users} 431014Sbill * finger -i {quick list of users with idle times} 441014Sbill * finger namelist {long format list of specified users} 451014Sbill * finger -s namelist {short format list of specified users} 461014Sbill * finger -w namelist {narrow short format list of specified users} 471014Sbill * 4818606Sedward * where 'namelist' is a list of users login names. 4918606Sedward * The other options can all be given after one '-', or each can have its 5018606Sedward * own '-'. The -f option disables the printing of headers for short and 5118606Sedward * quick outputs. The -b option briefens long format outputs. The -p 5218606Sedward * option turns off plans for long format outputs. 531014Sbill */ 541014Sbill 5518606Sedward #include <sys/types.h> 5618606Sedward #include <sys/stat.h> 5718606Sedward #include <utmp.h> 5818606Sedward #include <sys/signal.h> 5918606Sedward #include <pwd.h> 6018606Sedward #include <stdio.h> 6118606Sedward #include <lastlog.h> 6218606Sedward #include <ctype.h> 6318606Sedward #include <sys/time.h> 6418606Sedward #include <sys/socket.h> 6518606Sedward #include <netinet/in.h> 6618606Sedward #include <netdb.h> 671014Sbill 6818606Sedward #define ASTERISK '*' /* ignore this in real name */ 6918606Sedward #define COMMA ',' /* separator in pw_gecos field */ 7018606Sedward #define COMMAND '-' /* command line flag char */ 7118606Sedward #define CORY 'C' /* cory hall office */ 7218606Sedward #define EVANS 'E' /* evans hall office */ 7318606Sedward #define SAMENAME '&' /* repeat login name in real name */ 7426869Smckusick #define TALKABLE 0220 /* tty is writable if 220 mode */ 751014Sbill 7618606Sedward struct utmp user; 7718606Sedward #define NMAX sizeof(user.ut_name) 7818606Sedward #define LMAX sizeof(user.ut_line) 7918606Sedward #define HMAX sizeof(user.ut_host) 801014Sbill 8118606Sedward struct person { /* one for each person fingered */ 8218606Sedward char *name; /* name */ 8318606Sedward char tty[LMAX+1]; /* null terminated tty line */ 8418606Sedward char host[HMAX+1]; /* null terminated remote host name */ 8518606Sedward long loginat; /* time of (last) login */ 8618606Sedward long idletime; /* how long idle (if logged in) */ 8718606Sedward char *realname; /* pointer to full name */ 8818606Sedward char *office; /* pointer to office name */ 8918606Sedward char *officephone; /* pointer to office phone no. */ 9018606Sedward char *homephone; /* pointer to home phone no. */ 9118606Sedward char *random; /* for any random stuff in pw_gecos */ 9218606Sedward struct passwd *pwd; /* structure of /etc/passwd stuff */ 9318606Sedward char loggedin; /* person is logged in */ 9418606Sedward char writable; /* tty is writable */ 9518606Sedward char original; /* this is not a duplicate entry */ 9618606Sedward struct person *link; /* link to next person */ 971014Sbill }; 981014Sbill 9918606Sedward char LASTLOG[] = "/usr/adm/lastlog"; /* last login info */ 10018606Sedward char USERLOG[] = "/etc/utmp"; /* who is logged in */ 10118606Sedward char PLAN[] = "/.plan"; /* what plan file is */ 10218606Sedward char PROJ[] = "/.project"; /* what project file */ 10318606Sedward 10418606Sedward int unbrief = 1; /* -b option default */ 10518606Sedward int header = 1; /* -f option default */ 10618606Sedward int hack = 1; /* -h option default */ 10718606Sedward int idle = 0; /* -i option default */ 10818606Sedward int large = 0; /* -l option default */ 10918606Sedward int match = 1; /* -m option default */ 11018606Sedward int plan = 1; /* -p option default */ 11118606Sedward int unquick = 1; /* -q option default */ 11218606Sedward int small = 0; /* -s option default */ 11318606Sedward int wide = 1; /* -w option default */ 1141014Sbill 11518606Sedward int unshort; 11618606Sedward int lf; /* LASTLOG file descriptor */ 11718606Sedward struct person *person1; /* list of people */ 11818606Sedward long tloc; /* current time */ 1191014Sbill 12018606Sedward struct passwd *pwdcopy(); 12118606Sedward char *strcpy(); 12218606Sedward char *malloc(); 12318606Sedward char *ctime(); 1241014Sbill 12518606Sedward main(argc, argv) 12618606Sedward int argc; 12718606Sedward register char **argv; 12818606Sedward { 12918606Sedward FILE *fp; 13018606Sedward register char *s; 1311014Sbill 13218606Sedward /* parse command line for (optional) arguments */ 13318606Sedward while (*++argv && **argv == COMMAND) 13418606Sedward for (s = *argv + 1; *s; s++) 13518606Sedward switch (*s) { 13618606Sedward case 'b': 13718606Sedward unbrief = 0; 13818606Sedward break; 13918606Sedward case 'f': 14018606Sedward header = 0; 14118606Sedward break; 14218606Sedward case 'h': 14318606Sedward hack = 0; 14418606Sedward break; 14518606Sedward case 'i': 14618606Sedward idle = 1; 14718606Sedward unquick = 0; 14818606Sedward break; 14918606Sedward case 'l': 15018606Sedward large = 1; 15118606Sedward break; 15218606Sedward case 'm': 15318606Sedward match = 0; 15418606Sedward break; 15518606Sedward case 'p': 15618606Sedward plan = 0; 15718606Sedward break; 15818606Sedward case 'q': 15918606Sedward unquick = 0; 16018606Sedward break; 16118606Sedward case 's': 16218606Sedward small = 1; 16318606Sedward break; 16418606Sedward case 'w': 16518606Sedward wide = 0; 16618606Sedward break; 16718606Sedward default: 16818606Sedward fprintf(stderr, "Usage: finger [-bfhilmpqsw] [login1 [login2 ...] ]\n"); 16918606Sedward exit(1); 17018606Sedward } 17118606Sedward if (unquick || idle) 17218606Sedward time(&tloc); 17318606Sedward /* 17418606Sedward * *argv == 0 means no names given 17518606Sedward */ 17618606Sedward if (*argv == 0) 17718606Sedward doall(); 17818606Sedward else 17918606Sedward donames(argv); 18024461Sedward if (person1) 18124461Sedward print(); 18218606Sedward exit(0); 18318606Sedward } 1841014Sbill 18518606Sedward doall() 1861014Sbill { 18718606Sedward register struct person *p; 18818606Sedward register struct passwd *pw; 18918606Sedward int uf; 19018606Sedward char name[NMAX + 1]; 1911014Sbill 19218606Sedward unshort = large; 19318606Sedward if ((uf = open(USERLOG, 0)) < 0) { 19418606Sedward fprintf(stderr, "finger: error opening %s\n", USERLOG); 19518606Sedward exit(2); 1961014Sbill } 19718606Sedward if (unquick) { 19818606Sedward extern _pw_stayopen; 1991014Sbill 2001014Sbill setpwent(); 20118606Sedward _pw_stayopen = 1; 2021014Sbill fwopen(); 20318606Sedward } 20418606Sedward while (read(uf, (char *)&user, sizeof user) == sizeof user) { 20518606Sedward if (user.ut_name[0] == 0) 20618606Sedward continue; 20718606Sedward if (person1 == 0) 20818606Sedward p = person1 = (struct person *) malloc(sizeof *p); 20918606Sedward else { 21018606Sedward p->link = (struct person *) malloc(sizeof *p); 2111014Sbill p = p->link; 2121014Sbill } 21318606Sedward bcopy(user.ut_name, name, NMAX); 21418606Sedward name[NMAX] = 0; 21518606Sedward bcopy(user.ut_line, p->tty, LMAX); 21618606Sedward p->tty[LMAX] = 0; 21718606Sedward bcopy(user.ut_host, p->host, HMAX); 21818606Sedward p->host[HMAX] = 0; 21918606Sedward p->loginat = user.ut_time; 22018606Sedward p->pwd = 0; 22118606Sedward p->loggedin = 1; 22218606Sedward if (unquick && (pw = getpwnam(name))) { 22318606Sedward p->pwd = pwdcopy(pw); 22418606Sedward decode(p); 22518606Sedward p->name = p->pwd->pw_name; 22618606Sedward } else 22718606Sedward p->name = strcpy(malloc(strlen(name) + 1), name); 22818606Sedward } 22918606Sedward if (unquick) { 2301014Sbill fwclose(); 2311014Sbill endpwent(); 2321014Sbill } 23318606Sedward close(uf); 23418606Sedward if (person1 == 0) { 23518606Sedward printf("No one logged on\n"); 23624461Sedward return; 23718606Sedward } 23818606Sedward p->link = 0; 23918606Sedward } 2401014Sbill 24118606Sedward donames(argv) 24218606Sedward char **argv; 24318606Sedward { 24418606Sedward register struct person *p; 24518606Sedward register struct passwd *pw; 24618606Sedward int uf; 2471014Sbill 24818606Sedward /* 24918606Sedward * get names from command line and check to see if they're 25018606Sedward * logged in 25118606Sedward */ 25218606Sedward unshort = !small; 25318606Sedward for (; *argv != 0; argv++) { 25418606Sedward if (netfinger(*argv)) 25518606Sedward continue; 25618606Sedward if (person1 == 0) 25718606Sedward p = person1 = (struct person *) malloc(sizeof *p); 25818606Sedward else { 25918606Sedward p->link = (struct person *) malloc(sizeof *p); 26018606Sedward p = p->link; 26116469Ssam } 26218606Sedward p->name = *argv; 2631014Sbill p->loggedin = 0; 26418606Sedward p->original = 1; 26518606Sedward p->pwd = 0; 26618606Sedward } 26724461Sedward if (person1 == 0) 26824461Sedward return; 26918606Sedward p->link = 0; 27018606Sedward /* 27118606Sedward * if we are doing it, read /etc/passwd for the useful info 27218606Sedward */ 27318606Sedward if (unquick) { 27418606Sedward setpwent(); 27518606Sedward if (!match) { 27618606Sedward extern _pw_stayopen; 2771014Sbill 27818606Sedward _pw_stayopen = 1; 27918606Sedward for (p = person1; p != 0; p = p->link) 28018606Sedward if (pw = getpwnam(p->name)) 28118606Sedward p->pwd = pwdcopy(pw); 28218606Sedward } else while ((pw = getpwent()) != 0) { 28318606Sedward for (p = person1; p != 0; p = p->link) { 28418606Sedward if (!p->original) 28518606Sedward continue; 28618606Sedward if (strcmp(p->name, pw->pw_name) != 0 && 28718606Sedward !matchcmp(pw->pw_gecos, pw->pw_name, p->name)) 28818606Sedward continue; 28918606Sedward if (p->pwd == 0) 29018606Sedward p->pwd = pwdcopy(pw); 29118606Sedward else { 29218606Sedward struct person *new; 29318606Sedward /* 29418606Sedward * handle multiple login names, insert 29518606Sedward * new "duplicate" entry behind 29618606Sedward */ 29718606Sedward new = (struct person *) 29818606Sedward malloc(sizeof *new); 29918606Sedward new->pwd = pwdcopy(pw); 30018606Sedward new->name = p->name; 30118606Sedward new->original = 1; 30218606Sedward new->loggedin = 0; 30318606Sedward new->link = p->link; 30418606Sedward p->original = 0; 30518606Sedward p->link = new; 30618606Sedward p = new; 30718606Sedward } 3081014Sbill } 3091014Sbill } 3101014Sbill endpwent(); 31118606Sedward } 31218606Sedward /* Now get login information */ 31318606Sedward if ((uf = open(USERLOG, 0)) < 0) { 31418606Sedward fprintf(stderr, "finger: error opening %s\n", USERLOG); 31518606Sedward exit(2); 31618606Sedward } 31718606Sedward while (read(uf, (char *)&user, sizeof user) == sizeof user) { 31818606Sedward if (*user.ut_name == 0) 31918606Sedward continue; 32018606Sedward for (p = person1; p != 0; p = p->link) { 32118606Sedward if (p->loggedin == 2) 32218606Sedward continue; 32318606Sedward if (strncmp(p->pwd ? p->pwd->pw_name : p->name, 32418606Sedward user.ut_name, NMAX) != 0) 32518606Sedward continue; 32618606Sedward if (p->loggedin == 0) { 32718606Sedward bcopy(user.ut_line, p->tty, LMAX); 32818606Sedward p->tty[LMAX] = 0; 32918606Sedward bcopy(user.ut_host, p->host, HMAX); 33018606Sedward p->host[HMAX] = 0; 33118606Sedward p->loginat = user.ut_time; 33218606Sedward p->loggedin = 1; 33318606Sedward } else { /* p->loggedin == 1 */ 33418606Sedward struct person *new; 33518606Sedward new = (struct person *) malloc(sizeof *new); 33618606Sedward new->name = p->name; 33718606Sedward bcopy(user.ut_line, new->tty, LMAX); 33818606Sedward new->tty[LMAX] = 0; 33918606Sedward bcopy(user.ut_host, new->host, HMAX); 34018606Sedward new->host[HMAX] = 0; 34118606Sedward new->loginat = user.ut_time; 34218606Sedward new->pwd = p->pwd; 34318606Sedward new->loggedin = 1; 34418606Sedward new->original = 0; 34518606Sedward new->link = p->link; 34618606Sedward p->loggedin = 2; 34718606Sedward p->link = new; 34818606Sedward p = new; 3491014Sbill } 3501014Sbill } 35118606Sedward } 35218606Sedward close(uf); 35318606Sedward if (unquick) { 3541014Sbill fwopen(); 35518606Sedward for (p = person1; p != 0; p = p->link) 35618606Sedward decode(p); 3571014Sbill fwclose(); 3581014Sbill } 35918606Sedward } 3601014Sbill 36118606Sedward print() 36218606Sedward { 36318606Sedward register FILE *fp; 36418606Sedward register struct person *p; 36518606Sedward register char *s; 36618606Sedward register c; 3671014Sbill 36818606Sedward /* 36918606Sedward * print out what we got 37018606Sedward */ 37118606Sedward if (header) { 37218606Sedward if (unquick) { 37318606Sedward if (!unshort) 37418606Sedward if (wide) 37518606Sedward printf("Login Name TTY Idle When Office\n"); 37618606Sedward else 37718606Sedward printf("Login TTY Idle When Office\n"); 37818606Sedward } else { 37918606Sedward printf("Login TTY When"); 38018606Sedward if (idle) 38118606Sedward printf(" Idle"); 38218606Sedward putchar('\n'); 3831014Sbill } 38418606Sedward } 38518606Sedward for (p = person1; p != 0; p = p->link) { 38618606Sedward if (!unquick) { 38718606Sedward quickprint(p); 38818606Sedward continue; 3891014Sbill } 39018606Sedward if (!unshort) { 39118606Sedward shortprint(p); 39218606Sedward continue; 39318606Sedward } 39418606Sedward personprint(p); 39518606Sedward if (p->pwd != 0) { 39618606Sedward if (hack) { 39718606Sedward s = malloc(strlen(p->pwd->pw_dir) + 39818606Sedward sizeof PROJ); 39918606Sedward strcpy(s, p->pwd->pw_dir); 40018606Sedward strcat(s, PROJ); 40118606Sedward if ((fp = fopen(s, "r")) != 0) { 40218606Sedward printf("Project: "); 40318606Sedward while ((c = getc(fp)) != EOF) { 40418606Sedward if (c == '\n') 40518606Sedward break; 40625589Sbloom if (isprint(c) || isspace(c)) 40725589Sbloom putchar(c); 40825589Sbloom else 40925589Sbloom putchar(c ^ 100); 41018606Sedward } 41118606Sedward fclose(fp); 41218606Sedward putchar('\n'); 4131014Sbill } 41418606Sedward free(s); 4151014Sbill } 41618606Sedward if (plan) { 41718606Sedward s = malloc(strlen(p->pwd->pw_dir) + 41818606Sedward sizeof PLAN); 41918606Sedward strcpy(s, p->pwd->pw_dir); 42018606Sedward strcat(s, PLAN); 42118606Sedward if ((fp = fopen(s, "r")) == 0) 42218606Sedward printf("No Plan.\n"); 42318606Sedward else { 42418606Sedward printf("Plan:\n"); 42518606Sedward while ((c = getc(fp)) != EOF) 42625589Sbloom if (isprint(c) || isspace(c)) 42725589Sbloom putchar(c); 42825589Sbloom else 42925589Sbloom putchar(c ^ 100); 43018606Sedward fclose(fp); 4311014Sbill } 43218606Sedward free(s); 4331014Sbill } 4341014Sbill } 43518606Sedward if (p->link != 0) 43618606Sedward putchar('\n'); 43718606Sedward } 4381014Sbill } 4391014Sbill 44018606Sedward /* 44118606Sedward * Duplicate a pwd entry. 44218606Sedward * Note: Only the useful things (what the program currently uses) are copied. 4431014Sbill */ 44418606Sedward struct passwd * 44518606Sedward pwdcopy(pfrom) 44618606Sedward register struct passwd *pfrom; 44718606Sedward { 44818606Sedward register struct passwd *pto; 4491014Sbill 45018606Sedward pto = (struct passwd *) malloc(sizeof *pto); 45118606Sedward #define savestr(s) strcpy(malloc(strlen(s) + 1), s) 45218606Sedward pto->pw_name = savestr(pfrom->pw_name); 4531014Sbill pto->pw_uid = pfrom->pw_uid; 45418606Sedward pto->pw_gecos = savestr(pfrom->pw_gecos); 45518606Sedward pto->pw_dir = savestr(pfrom->pw_dir); 45618606Sedward pto->pw_shell = savestr(pfrom->pw_shell); 45718606Sedward #undef savestr 45818606Sedward return pto; 4591014Sbill } 4601014Sbill 46118606Sedward /* 46218606Sedward * print out information on quick format giving just name, tty, login time 46318606Sedward * and idle time if idle is set. 4641014Sbill */ 46518606Sedward quickprint(pers) 46618606Sedward register struct person *pers; 4671014Sbill { 46818606Sedward printf("%-*.*s ", NMAX, NMAX, pers->name); 46918606Sedward if (pers->loggedin) { 47018606Sedward if (idle) { 47118606Sedward findidle(pers); 47218606Sedward printf("%c%-*s %-16.16s", pers->writable ? ' ' : '*', 47318606Sedward LMAX, pers->tty, ctime(&pers->loginat)); 47418606Sedward ltimeprint(" ", &pers->idletime, ""); 47518606Sedward } else 47618606Sedward printf(" %-*s %-16.16s", LMAX, 47718606Sedward pers->tty, ctime(&pers->loginat)); 47818606Sedward putchar('\n'); 47918606Sedward } else 48018606Sedward printf(" Not Logged In\n"); 4811014Sbill } 4821014Sbill 48318606Sedward /* 48418606Sedward * print out information in short format, giving login name, full name, 48518606Sedward * tty, idle time, login time, office location and phone. 4861014Sbill */ 48718606Sedward shortprint(pers) 48818606Sedward register struct person *pers; 4891014Sbill { 49018606Sedward char *p; 49118606Sedward char dialup; 4921014Sbill 49318606Sedward if (pers->pwd == 0) { 49418606Sedward printf("%-15s ???\n", pers->name); 49518606Sedward return; 4961014Sbill } 49718606Sedward printf("%-*s", NMAX, pers->pwd->pw_name); 4981014Sbill dialup = 0; 49918606Sedward if (wide) { 50018606Sedward if (pers->realname) 50118606Sedward printf(" %-20.20s", pers->realname); 50218606Sedward else 50318606Sedward printf(" ??? "); 5041014Sbill } 50518606Sedward putchar(' '); 50618606Sedward if (pers->loggedin && !pers->writable) 50718606Sedward putchar('*'); 50818606Sedward else 50918606Sedward putchar(' '); 51018606Sedward if (*pers->tty) { 51118606Sedward if (pers->tty[0] == 't' && pers->tty[1] == 't' && 51218606Sedward pers->tty[2] == 'y') { 51318606Sedward if (pers->tty[3] == 'd' && pers->loggedin) 51418606Sedward dialup = 1; 51518606Sedward printf("%-2.2s ", pers->tty + 3); 51618606Sedward } else 51718606Sedward printf("%-2.2s ", pers->tty); 51818606Sedward } else 51918606Sedward printf(" "); 52018606Sedward p = ctime(&pers->loginat); 52118606Sedward if (pers->loggedin) { 52218606Sedward stimeprint(&pers->idletime); 52318606Sedward printf(" %3.3s %-5.5s ", p, p + 11); 52418606Sedward } else if (pers->loginat == 0) 52518606Sedward printf(" < . . . . >"); 5268842Smckusick else if (tloc - pers->loginat >= 180 * 24 * 60 * 60) 52718606Sedward printf(" <%-6.6s, %-4.4s>", p + 4, p + 20); 5288842Smckusick else 52918606Sedward printf(" <%-12.12s>", p + 4); 53018606Sedward if (dialup && pers->homephone) 53118606Sedward printf(" %20s", pers->homephone); 53218606Sedward else { 53318606Sedward if (pers->office) 53418606Sedward printf(" %-11.11s", pers->office); 53518606Sedward else if (pers->officephone || pers->homephone) 53618606Sedward printf(" "); 53718606Sedward if (pers->officephone) 53818606Sedward printf(" %s", pers->officephone); 53918606Sedward else if (pers->homephone) 54018606Sedward printf(" %s", pers->homephone); 5411014Sbill } 54218606Sedward putchar('\n'); 5431014Sbill } 5441014Sbill 54518606Sedward /* 54618606Sedward * print out a person in long format giving all possible information. 54718606Sedward * directory and shell are inhibited if unbrief is clear. 5481014Sbill */ 54918606Sedward personprint(pers) 55018606Sedward register struct person *pers; 5511014Sbill { 55218606Sedward if (pers->pwd == 0) { 55318606Sedward printf("Login name: %-10s\t\t\tIn real life: ???\n", 55418606Sedward pers->name); 55518606Sedward return; 5561014Sbill } 55718606Sedward printf("Login name: %-10s", pers->pwd->pw_name); 55818606Sedward if (pers->loggedin && !pers->writable) 55918606Sedward printf(" (messages off) "); 56018606Sedward else 56118606Sedward printf(" "); 56218606Sedward if (pers->realname) 56318606Sedward printf("In real life: %s", pers->realname); 56418606Sedward if (pers->office) { 56518606Sedward printf("\nOffice: %-.11s", pers->office); 56618606Sedward if (pers->officephone) { 56718606Sedward printf(", %s", pers->officephone); 56818606Sedward if (pers->homephone) 56918606Sedward printf("\t\tHome phone: %s", pers->homephone); 57018606Sedward else if (pers->random) 57118606Sedward printf("\t\t%s", pers->random); 57218606Sedward } else 57318606Sedward if (pers->homephone) 57418606Sedward printf("\t\t\tHome phone: %s", pers->homephone); 57518606Sedward else if (pers->random) 57618606Sedward printf("\t\t\t%s", pers->random); 57718606Sedward } else if (pers->officephone) { 57818606Sedward printf("\nPhone: %s", pers->officephone); 57918606Sedward if (pers->homephone) 58018606Sedward printf(", %s", pers->homephone); 58118606Sedward if (pers->random) 58218606Sedward printf(", %s", pers->random); 58318606Sedward } else if (pers->homephone) { 58418606Sedward printf("\nPhone: %s", pers->homephone); 58518606Sedward if (pers->random) 58618606Sedward printf(", %s", pers->random); 58718606Sedward } else if (pers->random) 58818606Sedward printf("\n%s", pers->random); 58918606Sedward if (unbrief) { 59018606Sedward printf("\nDirectory: %-25s", pers->pwd->pw_dir); 59118606Sedward if (*pers->pwd->pw_shell) 59218606Sedward printf("\tShell: %-s", pers->pwd->pw_shell); 5931014Sbill } 59418606Sedward if (pers->loggedin) { 59518606Sedward register char *ep = ctime(&pers->loginat); 59618606Sedward if (*pers->host) { 59718606Sedward printf("\nOn since %15.15s on %s from %s", 59818606Sedward &ep[4], pers->tty, pers->host); 59918606Sedward ltimeprint("\n", &pers->idletime, " Idle Time"); 60018606Sedward } else { 60118606Sedward printf("\nOn since %15.15s on %-*s", 60218606Sedward &ep[4], LMAX, pers->tty); 60318606Sedward ltimeprint("\t", &pers->idletime, " Idle Time"); 6041014Sbill } 60518606Sedward } else if (pers->loginat == 0) 60618606Sedward printf("\nNever logged in."); 6078842Smckusick else if (tloc - pers->loginat > 180 * 24 * 60 * 60) { 60818606Sedward register char *ep = ctime(&pers->loginat); 60918606Sedward printf("\nLast login %10.10s, %4.4s on %s", 61018606Sedward ep, ep+20, pers->tty); 61118606Sedward if (*pers->host) 61218606Sedward printf(" from %s", pers->host); 61318606Sedward } else { 61418606Sedward register char *ep = ctime(&pers->loginat); 61518606Sedward printf("\nLast login %16.16s on %s", ep, pers->tty); 61618606Sedward if (*pers->host) 61718606Sedward printf(" from %s", pers->host); 6188842Smckusick } 61918606Sedward putchar('\n'); 6201014Sbill } 6211014Sbill 6221014Sbill /* 6231014Sbill * very hacky section of code to format phone numbers. filled with 6241014Sbill * magic constants like 4, 7 and 10. 6251014Sbill */ 62618606Sedward char * 62718606Sedward phone(s, len, alldigits) 62818606Sedward register char *s; 62918606Sedward int len; 63018606Sedward char alldigits; 6311014Sbill { 63218606Sedward char fonebuf[15]; 63318606Sedward register char *p = fonebuf; 63418606Sedward register i; 6351014Sbill 63618606Sedward if (!alldigits) 63718606Sedward return (strcpy(malloc(len + 1), s)); 63818606Sedward switch (len) { 63918606Sedward case 4: 64018606Sedward *p++ = ' '; 64118606Sedward *p++ = 'x'; 64218606Sedward *p++ = '2'; 64318606Sedward *p++ = '-'; 64418606Sedward for (i = 0; i < 4; i++) 64518606Sedward *p++ = *s++; 6461014Sbill break; 64724463Sbloom case 5: 64824463Sbloom *p++ = ' '; 64924463Sbloom *p++ = 'x'; 65024463Sbloom *p++ = *s++; 65124463Sbloom *p++ = '-'; 65224463Sbloom for (i = 0; i < 4; i++) 65324463Sbloom *p++ = *s++; 65424463Sbloom break; 65518606Sedward case 7: 65618606Sedward for (i = 0; i < 3; i++) 65718606Sedward *p++ = *s++; 65818606Sedward *p++ = '-'; 65918606Sedward for (i = 0; i < 4; i++) 66018606Sedward *p++ = *s++; 6611014Sbill break; 66218606Sedward case 10: 66318606Sedward for (i = 0; i < 3; i++) 66418606Sedward *p++ = *s++; 66518606Sedward *p++ = '-'; 66618606Sedward for (i = 0; i < 3; i++) 66718606Sedward *p++ = *s++; 66818606Sedward *p++ = '-'; 66918606Sedward for (i = 0; i < 4; i++) 67018606Sedward *p++ = *s++; 6711014Sbill break; 67218606Sedward case 0: 67318606Sedward return 0; 67418606Sedward default: 67518606Sedward return (strcpy(malloc(len + 1), s)); 6761014Sbill } 67718606Sedward *p++ = 0; 67818606Sedward return (strcpy(malloc(p - fonebuf), fonebuf)); 6791014Sbill } 6801014Sbill 68118606Sedward /* 68218606Sedward * decode the information in the gecos field of /etc/passwd 6831014Sbill */ 68418606Sedward decode(pers) 68518606Sedward register struct person *pers; 6861014Sbill { 68718606Sedward char buffer[256]; 68818606Sedward register char *bp, *gp, *lp; 68918606Sedward int alldigits; 69018606Sedward int hasspace; 69118606Sedward int len; 6921014Sbill 69318606Sedward pers->realname = 0; 69418606Sedward pers->office = 0; 69518606Sedward pers->officephone = 0; 69618606Sedward pers->homephone = 0; 69718606Sedward pers->random = 0; 69818606Sedward if (pers->pwd == 0) 69918606Sedward return; 70018606Sedward gp = pers->pwd->pw_gecos; 70118606Sedward bp = buffer; 70218606Sedward if (*gp == ASTERISK) 7031014Sbill gp++; 70418606Sedward while (*gp && *gp != COMMA) /* name */ 70518606Sedward if (*gp == SAMENAME) { 70618606Sedward lp = pers->pwd->pw_name; 70718606Sedward if (islower(*lp)) 70818606Sedward *bp++ = toupper(*lp++); 70918606Sedward while (*bp++ = *lp++) 71018606Sedward ; 71118606Sedward bp--; 71218606Sedward gp++; 71318606Sedward } else 71418606Sedward *bp++ = *gp++; 71518606Sedward *bp++ = 0; 71618606Sedward if ((len = bp - buffer) > 1) 71718606Sedward pers->realname = strcpy(malloc(len), buffer); 71818606Sedward if (*gp == COMMA) { /* office */ 71918606Sedward gp++; 72018606Sedward hasspace = 0; 72118606Sedward bp = buffer; 72218606Sedward while (*gp && *gp != COMMA) { 72318606Sedward *bp = *gp++; 72418606Sedward if (*bp == ' ') 72518606Sedward hasspace = 1; 72618606Sedward /* leave 5 for Cory and Evans expansion */ 72718606Sedward if (bp < buffer + sizeof buffer - 6) 72818606Sedward bp++; 7291014Sbill } 73018606Sedward *bp = 0; 73118606Sedward len = bp - buffer; 73218606Sedward bp--; /* point to last character */ 73318606Sedward if (hasspace || len == 0) 73418606Sedward len++; 73518606Sedward else if (*bp == CORY) { 73618606Sedward strcpy(bp, " Cory"); 73718606Sedward len += 5; 73818606Sedward } else if (*bp == EVANS) { 73918606Sedward strcpy(bp, " Evans"); 74018606Sedward len += 6; 74118606Sedward } else 74218606Sedward len++; 74318606Sedward if (len > 1) 74418606Sedward pers->office = strcpy(malloc(len), buffer); 74518606Sedward } 74618606Sedward if (*gp == COMMA) { /* office phone */ 74718606Sedward gp++; 74818606Sedward bp = buffer; 74918606Sedward alldigits = 1; 75018606Sedward while (*gp && *gp != COMMA) { 75118606Sedward *bp = *gp++; 75218606Sedward if (!isdigit(*bp)) 75318606Sedward alldigits = 0; 75418606Sedward if (bp < buffer + sizeof buffer - 1) 75518606Sedward bp++; 7561014Sbill } 75718606Sedward *bp = 0; 75818606Sedward pers->officephone = phone(buffer, bp - buffer, alldigits); 75918606Sedward } 76018606Sedward if (*gp == COMMA) { /* home phone */ 7611014Sbill gp++; 76218606Sedward bp = buffer; 7631014Sbill alldigits = 1; 76418606Sedward while (*gp && *gp != COMMA) { 7651014Sbill *bp = *gp++; 76618606Sedward if (!isdigit(*bp)) 76718606Sedward alldigits = 0; 76818606Sedward if (bp < buffer + sizeof buffer - 1) 7691014Sbill bp++; 7701014Sbill } 77118606Sedward *bp = 0; 77218606Sedward pers->homephone = phone(buffer, bp - buffer, alldigits); 7731014Sbill } 77418606Sedward if (pers->loggedin) 77518606Sedward findidle(pers); 77618606Sedward else 77718606Sedward findwhen(pers); 7781014Sbill } 7791014Sbill 78018606Sedward /* 78118606Sedward * find the last log in of a user by checking the LASTLOG file. 78218606Sedward * the entry is indexed by the uid, so this can only be done if 78318606Sedward * the uid is known (which it isn't in quick mode) 7841014Sbill */ 7851014Sbill 7861014Sbill fwopen() 7871014Sbill { 78818606Sedward if ((lf = open(LASTLOG, 0)) < 0) 78918606Sedward fprintf(stderr, "finger: %s open error\n", LASTLOG); 7901014Sbill } 7911014Sbill 79218606Sedward findwhen(pers) 79318606Sedward register struct person *pers; 7941014Sbill { 79518606Sedward struct lastlog ll; 79618606Sedward int i; 7971014Sbill 79818606Sedward if (lf >= 0) { 79918606Sedward lseek(lf, (long)pers->pwd->pw_uid * sizeof ll, 0); 80018606Sedward if ((i = read(lf, (char *)&ll, sizeof ll)) == sizeof ll) { 80118606Sedward bcopy(ll.ll_line, pers->tty, LMAX); 80218606Sedward pers->tty[LMAX] = 0; 80318606Sedward bcopy(ll.ll_host, pers->host, HMAX); 80418606Sedward pers->host[HMAX] = 0; 80518606Sedward pers->loginat = ll.ll_time; 80618606Sedward } else { 80718606Sedward if (i != 0) 80818606Sedward fprintf(stderr, "finger: %s read error\n", 80918606Sedward LASTLOG); 81018606Sedward pers->tty[0] = 0; 81118606Sedward pers->host[0] = 0; 81218606Sedward pers->loginat = 0L; 81318606Sedward } 81418606Sedward } else { 81518606Sedward pers->tty[0] = 0; 81618606Sedward pers->host[0] = 0; 8171014Sbill pers->loginat = 0L; 8181014Sbill } 8191014Sbill } 8201014Sbill 8211014Sbill fwclose() 8221014Sbill { 82318606Sedward if (lf >= 0) 82418606Sedward close(lf); 8251014Sbill } 8261014Sbill 82718606Sedward /* 82818606Sedward * find the idle time of a user by doing a stat on /dev/tty??, 82918606Sedward * where tty?? has been gotten from USERLOG, supposedly. 8301014Sbill */ 83118606Sedward findidle(pers) 83218606Sedward register struct person *pers; 8331014Sbill { 83418606Sedward struct stat ttystatus; 83518606Sedward static char buffer[20] = "/dev/"; 83618606Sedward long t; 83718606Sedward #define TTYLEN 5 8381014Sbill 83918606Sedward strcpy(buffer + TTYLEN, pers->tty); 84018606Sedward buffer[TTYLEN+LMAX] = 0; 84118606Sedward if (stat(buffer, &ttystatus) < 0) { 84218606Sedward fprintf(stderr, "finger: Can't stat %s\n", buffer); 84318606Sedward exit(4); 84418606Sedward } 84518606Sedward time(&t); 84618606Sedward if (t < ttystatus.st_atime) 8471014Sbill pers->idletime = 0L; 84818606Sedward else 84918606Sedward pers->idletime = t - ttystatus.st_atime; 85018606Sedward pers->writable = (ttystatus.st_mode & TALKABLE) == TALKABLE; 8511014Sbill } 8521014Sbill 85318606Sedward /* 85418606Sedward * print idle time in short format; this program always prints 4 characters; 85518606Sedward * if the idle time is zero, it prints 4 blanks. 8561014Sbill */ 85718606Sedward stimeprint(dt) 85818606Sedward long *dt; 8591014Sbill { 86018606Sedward register struct tm *delta; 8611014Sbill 86218606Sedward delta = gmtime(dt); 86318606Sedward if (delta->tm_yday == 0) 86418606Sedward if (delta->tm_hour == 0) 86518606Sedward if (delta->tm_min == 0) 86618606Sedward printf(" "); 86718606Sedward else 86818606Sedward printf(" %2d", delta->tm_min); 86918606Sedward else 87018606Sedward if (delta->tm_hour >= 10) 87118606Sedward printf("%3d:", delta->tm_hour); 87218606Sedward else 87318606Sedward printf("%1d:%02d", 87418606Sedward delta->tm_hour, delta->tm_min); 87518606Sedward else 87618606Sedward printf("%3dd", delta->tm_yday); 8771014Sbill } 8781014Sbill 87918606Sedward /* 88018606Sedward * print idle time in long format with care being taken not to pluralize 88118606Sedward * 1 minutes or 1 hours or 1 days. 88218606Sedward * print "prefix" first. 8831014Sbill */ 88418606Sedward ltimeprint(before, dt, after) 88518606Sedward long *dt; 88618606Sedward char *before, *after; 8871014Sbill { 88818606Sedward register struct tm *delta; 8891014Sbill 89018606Sedward delta = gmtime(dt); 89118606Sedward if (delta->tm_yday == 0 && delta->tm_hour == 0 && delta->tm_min == 0 && 89218606Sedward delta->tm_sec <= 10) 89318606Sedward return (0); 89418606Sedward printf("%s", before); 89518606Sedward if (delta->tm_yday >= 10) 89618606Sedward printf("%d days", delta->tm_yday); 89718606Sedward else if (delta->tm_yday > 0) 89818606Sedward printf("%d day%s %d hour%s", 89918606Sedward delta->tm_yday, delta->tm_yday == 1 ? "" : "s", 90018606Sedward delta->tm_hour, delta->tm_hour == 1 ? "" : "s"); 90118606Sedward else 90218606Sedward if (delta->tm_hour >= 10) 90318606Sedward printf("%d hours", delta->tm_hour); 90418606Sedward else if (delta->tm_hour > 0) 90518606Sedward printf("%d hour%s %d minute%s", 90618606Sedward delta->tm_hour, delta->tm_hour == 1 ? "" : "s", 90718606Sedward delta->tm_min, delta->tm_min == 1 ? "" : "s"); 90818606Sedward else 90918606Sedward if (delta->tm_min >= 10) 91018606Sedward printf("%2d minutes", delta->tm_min); 91118606Sedward else if (delta->tm_min == 0) 91218606Sedward printf("%2d seconds", delta->tm_sec); 91318606Sedward else 91418606Sedward printf("%d minute%s %d second%s", 91518606Sedward delta->tm_min, 91618606Sedward delta->tm_min == 1 ? "" : "s", 91718606Sedward delta->tm_sec, 91818606Sedward delta->tm_sec == 1 ? "" : "s"); 91918606Sedward printf("%s", after); 9201014Sbill } 9211014Sbill 92218606Sedward matchcmp(gname, login, given) 92318606Sedward register char *gname; 92418606Sedward char *login; 92518606Sedward char *given; 9261014Sbill { 92718606Sedward char buffer[100]; 92818606Sedward register char *bp, *lp; 92918606Sedward register c; 9301014Sbill 93118606Sedward if (*gname == ASTERISK) 93218606Sedward gname++; 93318606Sedward lp = 0; 93418606Sedward bp = buffer; 93518606Sedward for (;;) 93618606Sedward switch (c = *gname++) { 93718606Sedward case SAMENAME: 93818606Sedward for (lp = login; bp < buffer + sizeof buffer 93918606Sedward && (*bp++ = *lp++);) 94018606Sedward ; 94118606Sedward bp--; 94218606Sedward break; 94318606Sedward case ' ': 94418606Sedward case COMMA: 94518606Sedward case '\0': 94618606Sedward *bp = 0; 94718606Sedward if (namecmp(buffer, given)) 94818606Sedward return (1); 94918606Sedward if (c == COMMA || c == 0) 95018606Sedward return (0); 95118606Sedward bp = buffer; 95218606Sedward break; 95318606Sedward default: 95418606Sedward if (bp < buffer + sizeof buffer) 95518606Sedward *bp++ = c; 9561014Sbill } 95718606Sedward /*NOTREACHED*/ 9581014Sbill } 9591014Sbill 96018606Sedward namecmp(name1, name2) 96118606Sedward register char *name1, *name2; 9621014Sbill { 96318606Sedward register c1, c2; 9641014Sbill 96518606Sedward for (;;) { 96618606Sedward c1 = *name1++; 96718606Sedward if (islower(c1)) 96818606Sedward c1 = toupper(c1); 96918606Sedward c2 = *name2++; 97018606Sedward if (islower(c2)) 97118606Sedward c2 = toupper(c2); 97218606Sedward if (c1 != c2) 97318606Sedward break; 97418606Sedward if (c1 == 0) 97518606Sedward return (1); 9761014Sbill } 97718606Sedward if (!c1) { 97818606Sedward for (name2--; isdigit(*name2); name2++) 97918606Sedward ; 98018606Sedward if (*name2 == 0) 98118606Sedward return (1); 98218606Sedward } else if (!c2) { 98318606Sedward for (name1--; isdigit(*name1); name1++) 98418606Sedward ; 98518606Sedward if (*name2 == 0) 98618606Sedward return (1); 9871014Sbill } 98818606Sedward return (0); 9891014Sbill } 9901014Sbill 99116469Ssam netfinger(name) 99218606Sedward char *name; 99316469Ssam { 99416469Ssam char *host; 99516469Ssam char fname[100]; 99616469Ssam struct hostent *hp; 99716469Ssam struct servent *sp; 99818606Sedward struct sockaddr_in sin; 99916469Ssam int s; 100016469Ssam char *rindex(); 100116469Ssam register FILE *f; 100216469Ssam register int c; 100316469Ssam register int lastc; 100416469Ssam 100516469Ssam if (name == NULL) 100618606Sedward return (0); 100716469Ssam host = rindex(name, '@'); 100816469Ssam if (host == NULL) 100918606Sedward return (0); 101016469Ssam *host++ = 0; 101116469Ssam hp = gethostbyname(host); 101216469Ssam if (hp == NULL) { 101316469Ssam static struct hostent def; 101416469Ssam static struct in_addr defaddr; 101525240Sbloom static char *alist[1]; 101616469Ssam static char namebuf[128]; 101716469Ssam int inet_addr(); 101816469Ssam 101916469Ssam defaddr.s_addr = inet_addr(host); 102016469Ssam if (defaddr.s_addr == -1) { 102116469Ssam printf("unknown host: %s\n", host); 102218606Sedward return (1); 102316469Ssam } 102416469Ssam strcpy(namebuf, host); 102516469Ssam def.h_name = namebuf; 102625239Ssam def.h_addr_list = alist, def.h_addr = (char *)&defaddr; 102716469Ssam def.h_length = sizeof (struct in_addr); 102816469Ssam def.h_addrtype = AF_INET; 102916469Ssam def.h_aliases = 0; 103016469Ssam hp = &def; 103116469Ssam } 103216469Ssam sp = getservbyname("finger", "tcp"); 103316469Ssam if (sp == 0) { 103416469Ssam printf("tcp/finger: unknown service\n"); 103518606Sedward return (1); 103616469Ssam } 103716469Ssam sin.sin_family = hp->h_addrtype; 103816469Ssam bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length); 103916469Ssam sin.sin_port = sp->s_port; 104016469Ssam s = socket(hp->h_addrtype, SOCK_STREAM, 0); 104116469Ssam if (s < 0) { 104216469Ssam perror("socket"); 104318606Sedward return (1); 104416469Ssam } 1045*30958Sbostic printf("[%s]\n", hp->h_name); 1046*30958Sbostic fflush(stdout); 104716469Ssam if (connect(s, (char *)&sin, sizeof (sin)) < 0) { 104816469Ssam perror("connect"); 104916469Ssam close(s); 105018606Sedward return (1); 105116469Ssam } 105216469Ssam if (large) write(s, "/W ", 3); 105316469Ssam write(s, name, strlen(name)); 105416469Ssam write(s, "\r\n", 2); 105516469Ssam f = fdopen(s, "r"); 105616469Ssam while ((c = getc(f)) != EOF) { 105716469Ssam switch(c) { 105816469Ssam case 0210: 105916469Ssam case 0211: 106016469Ssam case 0212: 106116469Ssam case 0214: 106216469Ssam c -= 0200; 106316469Ssam break; 106416469Ssam case 0215: 106516469Ssam c = '\n'; 106616469Ssam break; 106716469Ssam } 106825589Sbloom lastc = c; 106925589Sbloom if (isprint(c) || isspace(c)) 107025589Sbloom putchar(c); 107125589Sbloom else 107225589Sbloom putchar(c ^ 100); 107316469Ssam } 107416469Ssam if (lastc != '\n') 107516469Ssam putchar('\n'); 107625121Sbloom (void)fclose(f); 107718606Sedward return (1); 107816469Ssam } 1079