121554Sdist /* 2*35627Sbostic * Copyright (c) 1980 The Regents of the University of California. 3*35627Sbostic * All rights reserved. 4*35627Sbostic * 5*35627Sbostic * Redistribution and use in source and binary forms are permitted 6*35627Sbostic * provided that the above copyright notice and this paragraph are 7*35627Sbostic * duplicated in all such forms and that any documentation, 8*35627Sbostic * advertising materials, and other materials related to such 9*35627Sbostic * distribution and use acknowledge that the software was developed 10*35627Sbostic * by the University of California, Berkeley. The name of the 11*35627Sbostic * University may not be used to endorse or promote products derived 12*35627Sbostic * from this software without specific prior written permission. 13*35627Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14*35627Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15*35627Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1621554Sdist */ 1721554Sdist 1813619Ssam #ifndef lint 1921554Sdist char copyright[] = 20*35627Sbostic "@(#) Copyright (c) 1980 The Regents of the University of California.\n\ 2121554Sdist All rights reserved.\n"; 22*35627Sbostic #endif /* not lint */ 231014Sbill 2421554Sdist #ifndef lint 25*35627Sbostic static char sccsid[] = "@(#)finger.c 5.11 (Berkeley) 09/20/88"; 26*35627Sbostic #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 <utmp.h> 6918606Sedward #include <sys/signal.h> 7018606Sedward #include <pwd.h> 7118606Sedward #include <stdio.h> 7218606Sedward #include <lastlog.h> 7318606Sedward #include <ctype.h> 7418606Sedward #include <sys/time.h> 7518606Sedward #include <sys/socket.h> 7618606Sedward #include <netinet/in.h> 7718606Sedward #include <netdb.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 LASTLOG[] = "/usr/adm/lastlog"; /* last login info */ 11118606Sedward char USERLOG[] = "/etc/utmp"; /* who is logged in */ 11218606Sedward char PLAN[] = "/.plan"; /* what plan file is */ 11318606Sedward char PROJ[] = "/.project"; /* what project file */ 11418606Sedward 11518606Sedward int unbrief = 1; /* -b option default */ 11618606Sedward int header = 1; /* -f option default */ 11718606Sedward int hack = 1; /* -h option default */ 11818606Sedward int idle = 0; /* -i option default */ 11918606Sedward int large = 0; /* -l option default */ 12018606Sedward int match = 1; /* -m option default */ 12118606Sedward int plan = 1; /* -p option default */ 12218606Sedward int unquick = 1; /* -q option default */ 12318606Sedward int small = 0; /* -s option default */ 12418606Sedward int wide = 1; /* -w option default */ 1251014Sbill 12618606Sedward int unshort; 12718606Sedward int lf; /* LASTLOG file descriptor */ 12818606Sedward struct person *person1; /* list of people */ 12918606Sedward long tloc; /* current time */ 1301014Sbill 13118606Sedward struct passwd *pwdcopy(); 13218606Sedward char *strcpy(); 13318606Sedward char *malloc(); 13418606Sedward char *ctime(); 1351014Sbill 13618606Sedward main(argc, argv) 13718606Sedward int argc; 13818606Sedward register char **argv; 13918606Sedward { 14018606Sedward FILE *fp; 14118606Sedward register char *s; 1421014Sbill 14318606Sedward /* parse command line for (optional) arguments */ 14418606Sedward while (*++argv && **argv == COMMAND) 14518606Sedward for (s = *argv + 1; *s; s++) 14618606Sedward switch (*s) { 14718606Sedward case 'b': 14818606Sedward unbrief = 0; 14918606Sedward break; 15018606Sedward case 'f': 15118606Sedward header = 0; 15218606Sedward break; 15318606Sedward case 'h': 15418606Sedward hack = 0; 15518606Sedward break; 15618606Sedward case 'i': 15718606Sedward idle = 1; 15818606Sedward unquick = 0; 15918606Sedward break; 16018606Sedward case 'l': 16118606Sedward large = 1; 16218606Sedward break; 16318606Sedward case 'm': 16418606Sedward match = 0; 16518606Sedward break; 16618606Sedward case 'p': 16718606Sedward plan = 0; 16818606Sedward break; 16918606Sedward case 'q': 17018606Sedward unquick = 0; 17118606Sedward break; 17218606Sedward case 's': 17318606Sedward small = 1; 17418606Sedward break; 17518606Sedward case 'w': 17618606Sedward wide = 0; 17718606Sedward break; 17818606Sedward default: 17918606Sedward fprintf(stderr, "Usage: finger [-bfhilmpqsw] [login1 [login2 ...] ]\n"); 18018606Sedward exit(1); 18118606Sedward } 18218606Sedward if (unquick || idle) 18318606Sedward time(&tloc); 18418606Sedward /* 18518606Sedward * *argv == 0 means no names given 18618606Sedward */ 18718606Sedward if (*argv == 0) 18818606Sedward doall(); 18918606Sedward else 19018606Sedward donames(argv); 19124461Sedward if (person1) 19224461Sedward print(); 19318606Sedward exit(0); 19418606Sedward } 1951014Sbill 19618606Sedward doall() 1971014Sbill { 19818606Sedward register struct person *p; 19918606Sedward register struct passwd *pw; 20018606Sedward int uf; 20118606Sedward char name[NMAX + 1]; 2021014Sbill 20318606Sedward unshort = large; 20418606Sedward if ((uf = open(USERLOG, 0)) < 0) { 20518606Sedward fprintf(stderr, "finger: error opening %s\n", USERLOG); 20618606Sedward exit(2); 2071014Sbill } 20818606Sedward if (unquick) { 20918606Sedward extern _pw_stayopen; 2101014Sbill 2111014Sbill setpwent(); 21218606Sedward _pw_stayopen = 1; 2131014Sbill fwopen(); 21418606Sedward } 21518606Sedward while (read(uf, (char *)&user, sizeof user) == sizeof user) { 21618606Sedward if (user.ut_name[0] == 0) 21718606Sedward continue; 21818606Sedward if (person1 == 0) 21918606Sedward p = person1 = (struct person *) malloc(sizeof *p); 22018606Sedward else { 22118606Sedward p->link = (struct person *) malloc(sizeof *p); 2221014Sbill p = p->link; 2231014Sbill } 22418606Sedward bcopy(user.ut_name, name, NMAX); 22518606Sedward name[NMAX] = 0; 22618606Sedward bcopy(user.ut_line, p->tty, LMAX); 22718606Sedward p->tty[LMAX] = 0; 22818606Sedward bcopy(user.ut_host, p->host, HMAX); 22918606Sedward p->host[HMAX] = 0; 23018606Sedward p->loginat = user.ut_time; 23118606Sedward p->pwd = 0; 23218606Sedward p->loggedin = 1; 23318606Sedward if (unquick && (pw = getpwnam(name))) { 23418606Sedward p->pwd = pwdcopy(pw); 23518606Sedward decode(p); 23618606Sedward p->name = p->pwd->pw_name; 23718606Sedward } else 23818606Sedward p->name = strcpy(malloc(strlen(name) + 1), name); 23918606Sedward } 24018606Sedward if (unquick) { 2411014Sbill fwclose(); 2421014Sbill endpwent(); 2431014Sbill } 24418606Sedward close(uf); 24518606Sedward if (person1 == 0) { 24618606Sedward printf("No one logged on\n"); 24724461Sedward return; 24818606Sedward } 24918606Sedward p->link = 0; 25018606Sedward } 2511014Sbill 25218606Sedward donames(argv) 25318606Sedward char **argv; 25418606Sedward { 25518606Sedward register struct person *p; 25618606Sedward register struct passwd *pw; 25718606Sedward int uf; 2581014Sbill 25918606Sedward /* 26018606Sedward * get names from command line and check to see if they're 26118606Sedward * logged in 26218606Sedward */ 26318606Sedward unshort = !small; 26418606Sedward for (; *argv != 0; argv++) { 26518606Sedward if (netfinger(*argv)) 26618606Sedward continue; 26718606Sedward if (person1 == 0) 26818606Sedward p = person1 = (struct person *) malloc(sizeof *p); 26918606Sedward else { 27018606Sedward p->link = (struct person *) malloc(sizeof *p); 27118606Sedward p = p->link; 27216469Ssam } 27318606Sedward p->name = *argv; 2741014Sbill p->loggedin = 0; 27518606Sedward p->original = 1; 27618606Sedward p->pwd = 0; 27718606Sedward } 27824461Sedward if (person1 == 0) 27924461Sedward return; 28018606Sedward p->link = 0; 28118606Sedward /* 28218606Sedward * if we are doing it, read /etc/passwd for the useful info 28318606Sedward */ 28418606Sedward if (unquick) { 28518606Sedward setpwent(); 28618606Sedward if (!match) { 28718606Sedward extern _pw_stayopen; 2881014Sbill 28918606Sedward _pw_stayopen = 1; 29018606Sedward for (p = person1; p != 0; p = p->link) 29118606Sedward if (pw = getpwnam(p->name)) 29218606Sedward p->pwd = pwdcopy(pw); 29318606Sedward } else while ((pw = getpwent()) != 0) { 29418606Sedward for (p = person1; p != 0; p = p->link) { 29518606Sedward if (!p->original) 29618606Sedward continue; 29718606Sedward if (strcmp(p->name, pw->pw_name) != 0 && 29818606Sedward !matchcmp(pw->pw_gecos, pw->pw_name, p->name)) 29918606Sedward continue; 30018606Sedward if (p->pwd == 0) 30118606Sedward p->pwd = pwdcopy(pw); 30218606Sedward else { 30318606Sedward struct person *new; 30418606Sedward /* 30518606Sedward * handle multiple login names, insert 30618606Sedward * new "duplicate" entry behind 30718606Sedward */ 30818606Sedward new = (struct person *) 30918606Sedward malloc(sizeof *new); 31018606Sedward new->pwd = pwdcopy(pw); 31118606Sedward new->name = p->name; 31218606Sedward new->original = 1; 31318606Sedward new->loggedin = 0; 31418606Sedward new->link = p->link; 31518606Sedward p->original = 0; 31618606Sedward p->link = new; 31718606Sedward p = new; 31818606Sedward } 3191014Sbill } 3201014Sbill } 3211014Sbill endpwent(); 32218606Sedward } 32318606Sedward /* Now get login information */ 32418606Sedward if ((uf = open(USERLOG, 0)) < 0) { 32518606Sedward fprintf(stderr, "finger: error opening %s\n", USERLOG); 32618606Sedward exit(2); 32718606Sedward } 32818606Sedward while (read(uf, (char *)&user, sizeof user) == sizeof user) { 32918606Sedward if (*user.ut_name == 0) 33018606Sedward continue; 33118606Sedward for (p = person1; p != 0; p = p->link) { 33218606Sedward if (p->loggedin == 2) 33318606Sedward continue; 33418606Sedward if (strncmp(p->pwd ? p->pwd->pw_name : p->name, 33518606Sedward user.ut_name, NMAX) != 0) 33618606Sedward continue; 33718606Sedward if (p->loggedin == 0) { 33818606Sedward bcopy(user.ut_line, p->tty, LMAX); 33918606Sedward p->tty[LMAX] = 0; 34018606Sedward bcopy(user.ut_host, p->host, HMAX); 34118606Sedward p->host[HMAX] = 0; 34218606Sedward p->loginat = user.ut_time; 34318606Sedward p->loggedin = 1; 34418606Sedward } else { /* p->loggedin == 1 */ 34518606Sedward struct person *new; 34618606Sedward new = (struct person *) malloc(sizeof *new); 34718606Sedward new->name = p->name; 34818606Sedward bcopy(user.ut_line, new->tty, LMAX); 34918606Sedward new->tty[LMAX] = 0; 35018606Sedward bcopy(user.ut_host, new->host, HMAX); 35118606Sedward new->host[HMAX] = 0; 35218606Sedward new->loginat = user.ut_time; 35318606Sedward new->pwd = p->pwd; 35418606Sedward new->loggedin = 1; 35518606Sedward new->original = 0; 35618606Sedward new->link = p->link; 35718606Sedward p->loggedin = 2; 35818606Sedward p->link = new; 35918606Sedward p = new; 3601014Sbill } 3611014Sbill } 36218606Sedward } 36318606Sedward close(uf); 36418606Sedward if (unquick) { 3651014Sbill fwopen(); 36618606Sedward for (p = person1; p != 0; p = p->link) 36718606Sedward decode(p); 3681014Sbill fwclose(); 3691014Sbill } 37018606Sedward } 3711014Sbill 37218606Sedward print() 37318606Sedward { 37418606Sedward register FILE *fp; 37518606Sedward register struct person *p; 37618606Sedward register char *s; 37718606Sedward register c; 3781014Sbill 37918606Sedward /* 38018606Sedward * print out what we got 38118606Sedward */ 38218606Sedward if (header) { 38318606Sedward if (unquick) { 38418606Sedward if (!unshort) 38518606Sedward if (wide) 38618606Sedward printf("Login Name TTY Idle When Office\n"); 38718606Sedward else 38818606Sedward printf("Login TTY Idle When Office\n"); 38918606Sedward } else { 39018606Sedward printf("Login TTY When"); 39118606Sedward if (idle) 39218606Sedward printf(" Idle"); 39318606Sedward putchar('\n'); 3941014Sbill } 39518606Sedward } 39618606Sedward for (p = person1; p != 0; p = p->link) { 39718606Sedward if (!unquick) { 39818606Sedward quickprint(p); 39918606Sedward continue; 4001014Sbill } 40118606Sedward if (!unshort) { 40218606Sedward shortprint(p); 40318606Sedward continue; 40418606Sedward } 40518606Sedward personprint(p); 40618606Sedward if (p->pwd != 0) { 40718606Sedward if (hack) { 40818606Sedward s = malloc(strlen(p->pwd->pw_dir) + 40918606Sedward sizeof PROJ); 41018606Sedward strcpy(s, p->pwd->pw_dir); 41118606Sedward strcat(s, PROJ); 41218606Sedward if ((fp = fopen(s, "r")) != 0) { 41318606Sedward printf("Project: "); 41418606Sedward while ((c = getc(fp)) != EOF) { 41518606Sedward if (c == '\n') 41618606Sedward break; 41725589Sbloom if (isprint(c) || isspace(c)) 41825589Sbloom putchar(c); 41925589Sbloom else 42025589Sbloom putchar(c ^ 100); 42118606Sedward } 42218606Sedward fclose(fp); 42318606Sedward putchar('\n'); 4241014Sbill } 42518606Sedward free(s); 4261014Sbill } 42718606Sedward if (plan) { 42818606Sedward s = malloc(strlen(p->pwd->pw_dir) + 42918606Sedward sizeof PLAN); 43018606Sedward strcpy(s, p->pwd->pw_dir); 43118606Sedward strcat(s, PLAN); 43218606Sedward if ((fp = fopen(s, "r")) == 0) 43318606Sedward printf("No Plan.\n"); 43418606Sedward else { 43518606Sedward printf("Plan:\n"); 43618606Sedward while ((c = getc(fp)) != EOF) 43725589Sbloom if (isprint(c) || isspace(c)) 43825589Sbloom putchar(c); 43925589Sbloom else 44025589Sbloom putchar(c ^ 100); 44118606Sedward fclose(fp); 4421014Sbill } 44318606Sedward free(s); 4441014Sbill } 4451014Sbill } 44618606Sedward if (p->link != 0) 44718606Sedward putchar('\n'); 44818606Sedward } 4491014Sbill } 4501014Sbill 45118606Sedward /* 45218606Sedward * Duplicate a pwd entry. 45318606Sedward * Note: Only the useful things (what the program currently uses) are copied. 4541014Sbill */ 45518606Sedward struct passwd * 45618606Sedward pwdcopy(pfrom) 45718606Sedward register struct passwd *pfrom; 45818606Sedward { 45918606Sedward register struct passwd *pto; 4601014Sbill 46118606Sedward pto = (struct passwd *) malloc(sizeof *pto); 46218606Sedward #define savestr(s) strcpy(malloc(strlen(s) + 1), s) 46318606Sedward pto->pw_name = savestr(pfrom->pw_name); 4641014Sbill pto->pw_uid = pfrom->pw_uid; 46518606Sedward pto->pw_gecos = savestr(pfrom->pw_gecos); 46618606Sedward pto->pw_dir = savestr(pfrom->pw_dir); 46718606Sedward pto->pw_shell = savestr(pfrom->pw_shell); 46818606Sedward #undef savestr 46918606Sedward return pto; 4701014Sbill } 4711014Sbill 47218606Sedward /* 47318606Sedward * print out information on quick format giving just name, tty, login time 47418606Sedward * and idle time if idle is set. 4751014Sbill */ 47618606Sedward quickprint(pers) 47718606Sedward register struct person *pers; 4781014Sbill { 47918606Sedward printf("%-*.*s ", NMAX, NMAX, pers->name); 48018606Sedward if (pers->loggedin) { 48118606Sedward if (idle) { 48218606Sedward findidle(pers); 48318606Sedward printf("%c%-*s %-16.16s", pers->writable ? ' ' : '*', 48418606Sedward LMAX, pers->tty, ctime(&pers->loginat)); 48518606Sedward ltimeprint(" ", &pers->idletime, ""); 48618606Sedward } else 48718606Sedward printf(" %-*s %-16.16s", LMAX, 48818606Sedward pers->tty, ctime(&pers->loginat)); 48918606Sedward putchar('\n'); 49018606Sedward } else 49118606Sedward printf(" Not Logged In\n"); 4921014Sbill } 4931014Sbill 49418606Sedward /* 49518606Sedward * print out information in short format, giving login name, full name, 49618606Sedward * tty, idle time, login time, office location and phone. 4971014Sbill */ 49818606Sedward shortprint(pers) 49918606Sedward register struct person *pers; 5001014Sbill { 50118606Sedward char *p; 50218606Sedward char dialup; 5031014Sbill 50418606Sedward if (pers->pwd == 0) { 50518606Sedward printf("%-15s ???\n", pers->name); 50618606Sedward return; 5071014Sbill } 50818606Sedward printf("%-*s", NMAX, pers->pwd->pw_name); 5091014Sbill dialup = 0; 51018606Sedward if (wide) { 51118606Sedward if (pers->realname) 51218606Sedward printf(" %-20.20s", pers->realname); 51318606Sedward else 51418606Sedward printf(" ??? "); 5151014Sbill } 51618606Sedward putchar(' '); 51718606Sedward if (pers->loggedin && !pers->writable) 51818606Sedward putchar('*'); 51918606Sedward else 52018606Sedward putchar(' '); 52118606Sedward if (*pers->tty) { 52218606Sedward if (pers->tty[0] == 't' && pers->tty[1] == 't' && 52318606Sedward pers->tty[2] == 'y') { 52418606Sedward if (pers->tty[3] == 'd' && pers->loggedin) 52518606Sedward dialup = 1; 52618606Sedward printf("%-2.2s ", pers->tty + 3); 52718606Sedward } else 52818606Sedward printf("%-2.2s ", pers->tty); 52918606Sedward } else 53018606Sedward printf(" "); 53118606Sedward p = ctime(&pers->loginat); 53218606Sedward if (pers->loggedin) { 53318606Sedward stimeprint(&pers->idletime); 53418606Sedward printf(" %3.3s %-5.5s ", p, p + 11); 53518606Sedward } else if (pers->loginat == 0) 53618606Sedward printf(" < . . . . >"); 5378842Smckusick else if (tloc - pers->loginat >= 180 * 24 * 60 * 60) 53818606Sedward printf(" <%-6.6s, %-4.4s>", p + 4, p + 20); 5398842Smckusick else 54018606Sedward printf(" <%-12.12s>", p + 4); 54118606Sedward if (dialup && pers->homephone) 54218606Sedward printf(" %20s", pers->homephone); 54318606Sedward else { 54418606Sedward if (pers->office) 54518606Sedward printf(" %-11.11s", pers->office); 54618606Sedward else if (pers->officephone || pers->homephone) 54718606Sedward printf(" "); 54818606Sedward if (pers->officephone) 54918606Sedward printf(" %s", pers->officephone); 55018606Sedward else if (pers->homephone) 55118606Sedward printf(" %s", pers->homephone); 5521014Sbill } 55318606Sedward putchar('\n'); 5541014Sbill } 5551014Sbill 55618606Sedward /* 55718606Sedward * print out a person in long format giving all possible information. 55818606Sedward * directory and shell are inhibited if unbrief is clear. 5591014Sbill */ 56018606Sedward personprint(pers) 56118606Sedward register struct person *pers; 5621014Sbill { 56318606Sedward if (pers->pwd == 0) { 56418606Sedward printf("Login name: %-10s\t\t\tIn real life: ???\n", 56518606Sedward pers->name); 56618606Sedward return; 5671014Sbill } 56818606Sedward printf("Login name: %-10s", pers->pwd->pw_name); 56918606Sedward if (pers->loggedin && !pers->writable) 57018606Sedward printf(" (messages off) "); 57118606Sedward else 57218606Sedward printf(" "); 57318606Sedward if (pers->realname) 57418606Sedward printf("In real life: %s", pers->realname); 57518606Sedward if (pers->office) { 57618606Sedward printf("\nOffice: %-.11s", pers->office); 57718606Sedward if (pers->officephone) { 57818606Sedward printf(", %s", pers->officephone); 57918606Sedward if (pers->homephone) 58018606Sedward printf("\t\tHome phone: %s", pers->homephone); 58118606Sedward else if (pers->random) 58218606Sedward printf("\t\t%s", pers->random); 58318606Sedward } else 58418606Sedward if (pers->homephone) 58518606Sedward printf("\t\t\tHome phone: %s", pers->homephone); 58618606Sedward else if (pers->random) 58718606Sedward printf("\t\t\t%s", pers->random); 58818606Sedward } else if (pers->officephone) { 58918606Sedward printf("\nPhone: %s", pers->officephone); 59018606Sedward if (pers->homephone) 59118606Sedward printf(", %s", pers->homephone); 59218606Sedward if (pers->random) 59318606Sedward printf(", %s", pers->random); 59418606Sedward } else if (pers->homephone) { 59518606Sedward printf("\nPhone: %s", pers->homephone); 59618606Sedward if (pers->random) 59718606Sedward printf(", %s", pers->random); 59818606Sedward } else if (pers->random) 59918606Sedward printf("\n%s", pers->random); 60018606Sedward if (unbrief) { 60118606Sedward printf("\nDirectory: %-25s", pers->pwd->pw_dir); 60218606Sedward if (*pers->pwd->pw_shell) 60318606Sedward printf("\tShell: %-s", pers->pwd->pw_shell); 6041014Sbill } 60518606Sedward if (pers->loggedin) { 60618606Sedward register char *ep = ctime(&pers->loginat); 60718606Sedward if (*pers->host) { 60818606Sedward printf("\nOn since %15.15s on %s from %s", 60918606Sedward &ep[4], pers->tty, pers->host); 61018606Sedward ltimeprint("\n", &pers->idletime, " Idle Time"); 61118606Sedward } else { 61218606Sedward printf("\nOn since %15.15s on %-*s", 61318606Sedward &ep[4], LMAX, pers->tty); 61418606Sedward ltimeprint("\t", &pers->idletime, " Idle Time"); 6151014Sbill } 61618606Sedward } else if (pers->loginat == 0) 61718606Sedward printf("\nNever logged in."); 6188842Smckusick else if (tloc - pers->loginat > 180 * 24 * 60 * 60) { 61918606Sedward register char *ep = ctime(&pers->loginat); 62018606Sedward printf("\nLast login %10.10s, %4.4s on %s", 62118606Sedward ep, ep+20, pers->tty); 62218606Sedward if (*pers->host) 62318606Sedward printf(" from %s", pers->host); 62418606Sedward } else { 62518606Sedward register char *ep = ctime(&pers->loginat); 62618606Sedward printf("\nLast login %16.16s on %s", ep, pers->tty); 62718606Sedward if (*pers->host) 62818606Sedward printf(" from %s", pers->host); 6298842Smckusick } 63018606Sedward putchar('\n'); 6311014Sbill } 6321014Sbill 6331014Sbill /* 6341014Sbill * very hacky section of code to format phone numbers. filled with 6351014Sbill * magic constants like 4, 7 and 10. 6361014Sbill */ 63718606Sedward char * 63818606Sedward phone(s, len, alldigits) 63918606Sedward register char *s; 64018606Sedward int len; 64118606Sedward char alldigits; 6421014Sbill { 64318606Sedward char fonebuf[15]; 64418606Sedward register char *p = fonebuf; 64518606Sedward register i; 6461014Sbill 64718606Sedward if (!alldigits) 64818606Sedward return (strcpy(malloc(len + 1), s)); 64918606Sedward switch (len) { 65018606Sedward case 4: 65118606Sedward *p++ = ' '; 65218606Sedward *p++ = 'x'; 65318606Sedward *p++ = '2'; 65418606Sedward *p++ = '-'; 65518606Sedward for (i = 0; i < 4; i++) 65618606Sedward *p++ = *s++; 6571014Sbill break; 65824463Sbloom case 5: 65924463Sbloom *p++ = ' '; 66024463Sbloom *p++ = 'x'; 66124463Sbloom *p++ = *s++; 66224463Sbloom *p++ = '-'; 66324463Sbloom for (i = 0; i < 4; i++) 66424463Sbloom *p++ = *s++; 66524463Sbloom break; 66618606Sedward case 7: 66718606Sedward for (i = 0; i < 3; i++) 66818606Sedward *p++ = *s++; 66918606Sedward *p++ = '-'; 67018606Sedward for (i = 0; i < 4; i++) 67118606Sedward *p++ = *s++; 6721014Sbill break; 67318606Sedward case 10: 67418606Sedward for (i = 0; i < 3; i++) 67518606Sedward *p++ = *s++; 67618606Sedward *p++ = '-'; 67718606Sedward for (i = 0; i < 3; i++) 67818606Sedward *p++ = *s++; 67918606Sedward *p++ = '-'; 68018606Sedward for (i = 0; i < 4; i++) 68118606Sedward *p++ = *s++; 6821014Sbill break; 68318606Sedward case 0: 68418606Sedward return 0; 68518606Sedward default: 68618606Sedward return (strcpy(malloc(len + 1), s)); 6871014Sbill } 68818606Sedward *p++ = 0; 68918606Sedward return (strcpy(malloc(p - fonebuf), fonebuf)); 6901014Sbill } 6911014Sbill 69218606Sedward /* 69318606Sedward * decode the information in the gecos field of /etc/passwd 6941014Sbill */ 69518606Sedward decode(pers) 69618606Sedward register struct person *pers; 6971014Sbill { 69818606Sedward char buffer[256]; 69918606Sedward register char *bp, *gp, *lp; 70018606Sedward int alldigits; 70118606Sedward int hasspace; 70218606Sedward int len; 7031014Sbill 70418606Sedward pers->realname = 0; 70518606Sedward pers->office = 0; 70618606Sedward pers->officephone = 0; 70718606Sedward pers->homephone = 0; 70818606Sedward pers->random = 0; 70918606Sedward if (pers->pwd == 0) 71018606Sedward return; 71118606Sedward gp = pers->pwd->pw_gecos; 71218606Sedward bp = buffer; 71318606Sedward if (*gp == ASTERISK) 7141014Sbill gp++; 71518606Sedward while (*gp && *gp != COMMA) /* name */ 71618606Sedward if (*gp == SAMENAME) { 71718606Sedward lp = pers->pwd->pw_name; 71818606Sedward if (islower(*lp)) 71918606Sedward *bp++ = toupper(*lp++); 72018606Sedward while (*bp++ = *lp++) 72118606Sedward ; 72218606Sedward bp--; 72318606Sedward gp++; 72418606Sedward } else 72518606Sedward *bp++ = *gp++; 72618606Sedward *bp++ = 0; 72718606Sedward if ((len = bp - buffer) > 1) 72818606Sedward pers->realname = strcpy(malloc(len), buffer); 72918606Sedward if (*gp == COMMA) { /* office */ 73018606Sedward gp++; 73118606Sedward hasspace = 0; 73218606Sedward bp = buffer; 73318606Sedward while (*gp && *gp != COMMA) { 73418606Sedward *bp = *gp++; 73518606Sedward if (*bp == ' ') 73618606Sedward hasspace = 1; 73718606Sedward /* leave 5 for Cory and Evans expansion */ 73818606Sedward if (bp < buffer + sizeof buffer - 6) 73918606Sedward bp++; 7401014Sbill } 74118606Sedward *bp = 0; 74218606Sedward len = bp - buffer; 74318606Sedward bp--; /* point to last character */ 74418606Sedward if (hasspace || len == 0) 74518606Sedward len++; 74618606Sedward else if (*bp == CORY) { 74718606Sedward strcpy(bp, " Cory"); 74818606Sedward len += 5; 74918606Sedward } else if (*bp == EVANS) { 75018606Sedward strcpy(bp, " Evans"); 75118606Sedward len += 6; 75218606Sedward } else 75318606Sedward len++; 75418606Sedward if (len > 1) 75518606Sedward pers->office = strcpy(malloc(len), buffer); 75618606Sedward } 75718606Sedward if (*gp == COMMA) { /* office phone */ 75818606Sedward gp++; 75918606Sedward bp = buffer; 76018606Sedward alldigits = 1; 76118606Sedward while (*gp && *gp != COMMA) { 76218606Sedward *bp = *gp++; 76318606Sedward if (!isdigit(*bp)) 76418606Sedward alldigits = 0; 76518606Sedward if (bp < buffer + sizeof buffer - 1) 76618606Sedward bp++; 7671014Sbill } 76818606Sedward *bp = 0; 76918606Sedward pers->officephone = phone(buffer, bp - buffer, alldigits); 77018606Sedward } 77118606Sedward if (*gp == COMMA) { /* home phone */ 7721014Sbill gp++; 77318606Sedward bp = buffer; 7741014Sbill alldigits = 1; 77518606Sedward while (*gp && *gp != COMMA) { 7761014Sbill *bp = *gp++; 77718606Sedward if (!isdigit(*bp)) 77818606Sedward alldigits = 0; 77918606Sedward if (bp < buffer + sizeof buffer - 1) 7801014Sbill bp++; 7811014Sbill } 78218606Sedward *bp = 0; 78318606Sedward pers->homephone = phone(buffer, bp - buffer, alldigits); 7841014Sbill } 78518606Sedward if (pers->loggedin) 78618606Sedward findidle(pers); 78718606Sedward else 78818606Sedward findwhen(pers); 7891014Sbill } 7901014Sbill 79118606Sedward /* 79218606Sedward * find the last log in of a user by checking the LASTLOG file. 79318606Sedward * the entry is indexed by the uid, so this can only be done if 79418606Sedward * the uid is known (which it isn't in quick mode) 7951014Sbill */ 7961014Sbill 7971014Sbill fwopen() 7981014Sbill { 79918606Sedward if ((lf = open(LASTLOG, 0)) < 0) 80018606Sedward fprintf(stderr, "finger: %s open error\n", LASTLOG); 8011014Sbill } 8021014Sbill 80318606Sedward findwhen(pers) 80418606Sedward register struct person *pers; 8051014Sbill { 80618606Sedward struct lastlog ll; 80718606Sedward int i; 8081014Sbill 80918606Sedward if (lf >= 0) { 81018606Sedward lseek(lf, (long)pers->pwd->pw_uid * sizeof ll, 0); 81118606Sedward if ((i = read(lf, (char *)&ll, sizeof ll)) == sizeof ll) { 81218606Sedward bcopy(ll.ll_line, pers->tty, LMAX); 81318606Sedward pers->tty[LMAX] = 0; 81418606Sedward bcopy(ll.ll_host, pers->host, HMAX); 81518606Sedward pers->host[HMAX] = 0; 81618606Sedward pers->loginat = ll.ll_time; 81718606Sedward } else { 81818606Sedward if (i != 0) 81918606Sedward fprintf(stderr, "finger: %s read error\n", 82018606Sedward LASTLOG); 82118606Sedward pers->tty[0] = 0; 82218606Sedward pers->host[0] = 0; 82318606Sedward pers->loginat = 0L; 82418606Sedward } 82518606Sedward } else { 82618606Sedward pers->tty[0] = 0; 82718606Sedward pers->host[0] = 0; 8281014Sbill pers->loginat = 0L; 8291014Sbill } 8301014Sbill } 8311014Sbill 8321014Sbill fwclose() 8331014Sbill { 83418606Sedward if (lf >= 0) 83518606Sedward close(lf); 8361014Sbill } 8371014Sbill 83818606Sedward /* 83918606Sedward * find the idle time of a user by doing a stat on /dev/tty??, 84018606Sedward * where tty?? has been gotten from USERLOG, supposedly. 8411014Sbill */ 84218606Sedward findidle(pers) 84318606Sedward register struct person *pers; 8441014Sbill { 84518606Sedward struct stat ttystatus; 84618606Sedward static char buffer[20] = "/dev/"; 84718606Sedward long t; 84818606Sedward #define TTYLEN 5 8491014Sbill 85018606Sedward strcpy(buffer + TTYLEN, pers->tty); 85118606Sedward buffer[TTYLEN+LMAX] = 0; 85218606Sedward if (stat(buffer, &ttystatus) < 0) { 85318606Sedward fprintf(stderr, "finger: Can't stat %s\n", buffer); 85418606Sedward exit(4); 85518606Sedward } 85618606Sedward time(&t); 85718606Sedward if (t < ttystatus.st_atime) 8581014Sbill pers->idletime = 0L; 85918606Sedward else 86018606Sedward pers->idletime = t - ttystatus.st_atime; 86118606Sedward pers->writable = (ttystatus.st_mode & TALKABLE) == TALKABLE; 8621014Sbill } 8631014Sbill 86418606Sedward /* 86518606Sedward * print idle time in short format; this program always prints 4 characters; 86618606Sedward * if the idle time is zero, it prints 4 blanks. 8671014Sbill */ 86818606Sedward stimeprint(dt) 86918606Sedward long *dt; 8701014Sbill { 87118606Sedward register struct tm *delta; 8721014Sbill 87318606Sedward delta = gmtime(dt); 87418606Sedward if (delta->tm_yday == 0) 87518606Sedward if (delta->tm_hour == 0) 87618606Sedward if (delta->tm_min == 0) 87718606Sedward printf(" "); 87818606Sedward else 87918606Sedward printf(" %2d", delta->tm_min); 88018606Sedward else 88118606Sedward if (delta->tm_hour >= 10) 88218606Sedward printf("%3d:", delta->tm_hour); 88318606Sedward else 88418606Sedward printf("%1d:%02d", 88518606Sedward delta->tm_hour, delta->tm_min); 88618606Sedward else 88718606Sedward printf("%3dd", delta->tm_yday); 8881014Sbill } 8891014Sbill 89018606Sedward /* 89118606Sedward * print idle time in long format with care being taken not to pluralize 89218606Sedward * 1 minutes or 1 hours or 1 days. 89318606Sedward * print "prefix" first. 8941014Sbill */ 89518606Sedward ltimeprint(before, dt, after) 89618606Sedward long *dt; 89718606Sedward char *before, *after; 8981014Sbill { 89918606Sedward register struct tm *delta; 9001014Sbill 90118606Sedward delta = gmtime(dt); 90218606Sedward if (delta->tm_yday == 0 && delta->tm_hour == 0 && delta->tm_min == 0 && 90318606Sedward delta->tm_sec <= 10) 90418606Sedward return (0); 90518606Sedward printf("%s", before); 90618606Sedward if (delta->tm_yday >= 10) 90718606Sedward printf("%d days", delta->tm_yday); 90818606Sedward else if (delta->tm_yday > 0) 90918606Sedward printf("%d day%s %d hour%s", 91018606Sedward delta->tm_yday, delta->tm_yday == 1 ? "" : "s", 91118606Sedward delta->tm_hour, delta->tm_hour == 1 ? "" : "s"); 91218606Sedward else 91318606Sedward if (delta->tm_hour >= 10) 91418606Sedward printf("%d hours", delta->tm_hour); 91518606Sedward else if (delta->tm_hour > 0) 91618606Sedward printf("%d hour%s %d minute%s", 91718606Sedward delta->tm_hour, delta->tm_hour == 1 ? "" : "s", 91818606Sedward delta->tm_min, delta->tm_min == 1 ? "" : "s"); 91918606Sedward else 92018606Sedward if (delta->tm_min >= 10) 92118606Sedward printf("%2d minutes", delta->tm_min); 92218606Sedward else if (delta->tm_min == 0) 92318606Sedward printf("%2d seconds", delta->tm_sec); 92418606Sedward else 92518606Sedward printf("%d minute%s %d second%s", 92618606Sedward delta->tm_min, 92718606Sedward delta->tm_min == 1 ? "" : "s", 92818606Sedward delta->tm_sec, 92918606Sedward delta->tm_sec == 1 ? "" : "s"); 93018606Sedward printf("%s", after); 9311014Sbill } 9321014Sbill 93318606Sedward matchcmp(gname, login, given) 93418606Sedward register char *gname; 93518606Sedward char *login; 93618606Sedward char *given; 9371014Sbill { 93818606Sedward char buffer[100]; 93918606Sedward register char *bp, *lp; 94018606Sedward register c; 9411014Sbill 94218606Sedward if (*gname == ASTERISK) 94318606Sedward gname++; 94418606Sedward lp = 0; 94518606Sedward bp = buffer; 94618606Sedward for (;;) 94718606Sedward switch (c = *gname++) { 94818606Sedward case SAMENAME: 94918606Sedward for (lp = login; bp < buffer + sizeof buffer 95018606Sedward && (*bp++ = *lp++);) 95118606Sedward ; 95218606Sedward bp--; 95318606Sedward break; 95418606Sedward case ' ': 95518606Sedward case COMMA: 95618606Sedward case '\0': 95718606Sedward *bp = 0; 95818606Sedward if (namecmp(buffer, given)) 95918606Sedward return (1); 96018606Sedward if (c == COMMA || c == 0) 96118606Sedward return (0); 96218606Sedward bp = buffer; 96318606Sedward break; 96418606Sedward default: 96518606Sedward if (bp < buffer + sizeof buffer) 96618606Sedward *bp++ = c; 9671014Sbill } 96818606Sedward /*NOTREACHED*/ 9691014Sbill } 9701014Sbill 97118606Sedward namecmp(name1, name2) 97218606Sedward register char *name1, *name2; 9731014Sbill { 97418606Sedward register c1, c2; 9751014Sbill 97618606Sedward for (;;) { 97718606Sedward c1 = *name1++; 97818606Sedward if (islower(c1)) 97918606Sedward c1 = toupper(c1); 98018606Sedward c2 = *name2++; 98118606Sedward if (islower(c2)) 98218606Sedward c2 = toupper(c2); 98318606Sedward if (c1 != c2) 98418606Sedward break; 98518606Sedward if (c1 == 0) 98618606Sedward return (1); 9871014Sbill } 98818606Sedward if (!c1) { 98918606Sedward for (name2--; isdigit(*name2); name2++) 99018606Sedward ; 99118606Sedward if (*name2 == 0) 99218606Sedward return (1); 99318606Sedward } else if (!c2) { 99418606Sedward for (name1--; isdigit(*name1); name1++) 99518606Sedward ; 99618606Sedward if (*name2 == 0) 99718606Sedward return (1); 9981014Sbill } 99918606Sedward return (0); 10001014Sbill } 10011014Sbill 100216469Ssam netfinger(name) 100318606Sedward char *name; 100416469Ssam { 100516469Ssam char *host; 100616469Ssam char fname[100]; 100716469Ssam struct hostent *hp; 100816469Ssam struct servent *sp; 100918606Sedward struct sockaddr_in sin; 101016469Ssam int s; 101116469Ssam char *rindex(); 101216469Ssam register FILE *f; 101316469Ssam register int c; 101416469Ssam register int lastc; 101516469Ssam 101616469Ssam if (name == NULL) 101718606Sedward return (0); 101816469Ssam host = rindex(name, '@'); 101916469Ssam if (host == NULL) 102018606Sedward return (0); 102116469Ssam *host++ = 0; 102216469Ssam hp = gethostbyname(host); 102316469Ssam if (hp == NULL) { 102416469Ssam static struct hostent def; 102516469Ssam static struct in_addr defaddr; 102625240Sbloom static char *alist[1]; 102716469Ssam static char namebuf[128]; 102816469Ssam int inet_addr(); 102916469Ssam 103016469Ssam defaddr.s_addr = inet_addr(host); 103116469Ssam if (defaddr.s_addr == -1) { 103216469Ssam printf("unknown host: %s\n", host); 103318606Sedward return (1); 103416469Ssam } 103516469Ssam strcpy(namebuf, host); 103616469Ssam def.h_name = namebuf; 103725239Ssam def.h_addr_list = alist, def.h_addr = (char *)&defaddr; 103816469Ssam def.h_length = sizeof (struct in_addr); 103916469Ssam def.h_addrtype = AF_INET; 104016469Ssam def.h_aliases = 0; 104116469Ssam hp = &def; 104216469Ssam } 104316469Ssam sp = getservbyname("finger", "tcp"); 104416469Ssam if (sp == 0) { 104516469Ssam printf("tcp/finger: unknown service\n"); 104618606Sedward return (1); 104716469Ssam } 104816469Ssam sin.sin_family = hp->h_addrtype; 104916469Ssam bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length); 105016469Ssam sin.sin_port = sp->s_port; 105116469Ssam s = socket(hp->h_addrtype, SOCK_STREAM, 0); 105216469Ssam if (s < 0) { 105316469Ssam perror("socket"); 105418606Sedward return (1); 105516469Ssam } 105630958Sbostic printf("[%s]\n", hp->h_name); 105730958Sbostic fflush(stdout); 105816469Ssam if (connect(s, (char *)&sin, sizeof (sin)) < 0) { 105916469Ssam perror("connect"); 106016469Ssam close(s); 106118606Sedward return (1); 106216469Ssam } 106316469Ssam if (large) write(s, "/W ", 3); 106416469Ssam write(s, name, strlen(name)); 106516469Ssam write(s, "\r\n", 2); 106616469Ssam f = fdopen(s, "r"); 106716469Ssam while ((c = getc(f)) != EOF) { 106816469Ssam switch(c) { 106916469Ssam case 0210: 107016469Ssam case 0211: 107116469Ssam case 0212: 107216469Ssam case 0214: 107316469Ssam c -= 0200; 107416469Ssam break; 107516469Ssam case 0215: 107616469Ssam c = '\n'; 107716469Ssam break; 107816469Ssam } 107925589Sbloom lastc = c; 108025589Sbloom if (isprint(c) || isspace(c)) 108125589Sbloom putchar(c); 108225589Sbloom else 108325589Sbloom putchar(c ^ 100); 108416469Ssam } 108516469Ssam if (lastc != '\n') 108616469Ssam putchar('\n'); 108725121Sbloom (void)fclose(f); 108818606Sedward return (1); 108916469Ssam } 1090