diff --git a/commands/Makefile b/commands/Makefile index ae8b4bcca..f731122f1 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -9,7 +9,7 @@ SUBDIR= add_route arp ash at backup basename btrace \ dd decomp16 DESCRIBE devmand devsize df dhcpd \ dhrystone diff dirname diskctl dumpcore \ eject env expand factor fbdctl \ - find finger fingerd fix fold format fortune fsck.mfs \ + find fingerd fix fold format fortune fsck.mfs \ gcore gcov-pull getty grep hexdump host \ hostaddr id ifconfig ifdef \ intr ipcrm ipcs irdpd isoread last \ diff --git a/commands/finger/Makefile b/commands/finger/Makefile deleted file mode 100644 index 34e9f8c59..000000000 --- a/commands/finger/Makefile +++ /dev/null @@ -1,4 +0,0 @@ -PROG= finger -MAN= - -.include diff --git a/commands/finger/finger.c b/commands/finger/finger.c deleted file mode 100644 index 0682ec3ea..000000000 --- a/commands/finger/finger.c +++ /dev/null @@ -1,1092 +0,0 @@ -/* - * Copyright (c) 1980 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. - */ - -#ifndef lint -static char sccsid[] = "@(#)finger.c 1.1 87/12/21 SMI"; /* from 5.8 3/13/86 */ -#endif /* not lint */ - -/* - * This is a finger program. It prints out useful information about users - * by digging it up from various system files. - * - * There are three output formats, all of which give login name, teletype - * line number, and login time. The short output format is reminiscent - * of finger on ITS, and gives one line of information per user containing - * in addition to the minimum basic requirements (MBR), the full name of - * the user, his idle time and location. The - * quick style output is UNIX who-like, giving only name, teletype and - * login time. Finally, the long style output give the same information - * as the short (in more legible format), the home directory and shell - * of the user, and, if it exits, a copy of the file .plan in the users - * home directory. Finger may be called with or without a list of people - * to finger -- if no list is given, all the people currently logged in - * are fingered. - * - * The program is validly called by one of the following: - * - * finger {short form list of users} - * finger -l {long form list of users} - * finger -b {briefer long form list of users} - * finger -q {quick list of users} - * finger -i {quick list of users with idle times} - * finger namelist {long format list of specified users} - * finger -s namelist {short format list of specified users} - * finger -w namelist {narrow short format list of specified users} - * - * where 'namelist' is a list of users login names. - * The other options can all be given after one '-', or each can have its - * own '-'. The -f option disables the printing of headers for short and - * quick outputs. The -b option briefens long format outputs. The -p - * option turns off plans for long format outputs. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define NONOTHING 1 /* don't say "No plan", or "No mail" */ - -#define NONET 0 - -#define ASTERISK '*' /* ignore this in real name */ -#define COMMA ',' /* separator in pw_gecos field */ -#define COMMAND '-' /* command line flag char */ -#define SAMENAME '&' /* repeat login name in real name */ -#define TALKABLE 0220 /* tty is writable if this mode */ - -struct utmp user; -#define NMAX sizeof(user.ut_name) -#define LMAX sizeof(user.ut_line) -#define HMAX sizeof(user.ut_host) - -struct person { /* one for each person fingered */ - char *name; /* name */ - char tty[LMAX+1]; /* null terminated tty line */ - char host[HMAX+1]; /* null terminated remote host name */ - long loginat; /* time of (last) login */ - long idletime; /* how long idle (if logged in) */ - char *realname; /* pointer to full name */ - struct passwd *pwd; /* structure of /etc/passwd stuff */ - char loggedin; /* person is logged in */ - char writable; /* tty is writable */ - char original; /* this is not a duplicate entry */ - struct person *link; /* link to next person */ - char *where; /* terminal location */ - char hostt[HMAX+1]; /* login host */ -}; - -#include - -char LASTLOG[] = _PATH_LASTLOG; /* last login info */ -char USERLOG[] = _PATH_UTMP; /* who is logged in */ -char PLAN[] = "/.plan"; /* what plan file is */ -char PROJ[] = "/.project"; /* what project file */ - -int unbrief = 1; /* -b option default */ -int header = 1; /* -f option default */ -int hack = 1; /* -h option default */ -int idle = 0; /* -i option default */ -int large = 0; /* -l option default */ -int match = 1; /* -m option default */ -int plan = 1; /* -p option default */ -int unquick = 1; /* -q option default */ -int small = 0; /* -s option default */ -int wide = 1; /* -w option default */ - -int unshort; -int lf; /* LASTLOG file descriptor */ -struct person *person1; /* list of people */ -long tloc; /* current time */ - -#if !defined(__minix) -char *strcpy(); -char *ctime(); -#endif - -char *prog_name; - -/* Already defined in stdio.h */ -#undef fwopen -#define fwopen finger_fwopen - -int main (int argc, char *argv[]); -static void doall(void); -static void donames(char **args); -static void print(void); -static void fwopen(void); -static void decode(struct person *pers); -static void fwclose(void); -static int netfinger (char *name); -static int matchcmp (char *gname, char *login, char *given); -static void quickprint (struct person *pers); -static void shortprint (struct person *pers); -static void personprint (struct person *pers); -static int AlreadyPrinted(int uid); -static int AnyMail (char *name); -static struct passwd *pwdcopy(struct passwd *pfrom); -static void findidle (struct person *pers); -static int ltimeprint (char *dt, long *before, char *after); -static void stimeprint (long *dt); -static void findwhen (struct person *pers); -static int namecmp (char *name1, char *name2); - -main(argc, argv) - int argc; - register char **argv; -{ - register char *s; - - prog_name= argv[0]; - - /* parse command line for (optional) arguments */ - while (*++argv && **argv == COMMAND) - for (s = *argv + 1; *s; s++) - switch (*s) { - case 'b': - unbrief = 0; - break; - case 'f': - header = 0; - break; - case 'h': - hack = 0; - break; - case 'i': - idle = 1; - unquick = 0; - break; - case 'l': - large = 1; - break; - case 'm': - match = 0; - break; - case 'p': - plan = 0; - break; - case 'q': - unquick = 0; - break; - case 's': - small = 1; - break; - case 'w': - wide = 0; - break; - default: - fprintf(stderr, "Usage: finger [-bfhilmpqsw] [login1 [login2 ...] ]\n"); - exit(1); - } - if (unquick || idle) - time(&tloc); - /* - * *argv == 0 means no names given - */ - if (*argv == 0) - doall(); - else - donames(argv); - if (person1) - print(); - exit(0); -} - -static void doall() -{ - register struct person *p; - register struct passwd *pw; - int uf; - char name[NMAX + 1]; - - unshort = large; - if ((uf = open(USERLOG, 0)) < 0) { - fprintf(stderr, "finger: error opening %s\n", USERLOG); - exit(2); - } - if (unquick) { - setpwent(); - fwopen(); - } - while (read(uf, (char *)&user, sizeof user) == sizeof user) { - if (user.ut_name[0] == 0) - continue; - if (person1 == 0) - p = person1 = (struct person *) malloc(sizeof *p); - else { - p->link = (struct person *) malloc(sizeof *p); - p = p->link; - } - bcopy(user.ut_name, name, NMAX); - name[NMAX] = 0; - bcopy(user.ut_line, p->tty, LMAX); - p->tty[LMAX] = 0; - bcopy(user.ut_host, p->host, HMAX); - p->host[HMAX] = 0; - p->loginat = user.ut_time; - p->pwd = 0; - p->loggedin = 1; - p->where = NULL; - if (unquick && (pw = getpwnam(name))) { - p->pwd = pwdcopy(pw); - decode(p); - p->name = p->pwd->pw_name; - } else - p->name = strcpy(malloc(strlen(name) + 1), name); - } - if (unquick) { - fwclose(); - endpwent(); - } - close(uf); - if (person1 == 0) { - printf("No one logged on\n"); - return; - } - p->link = 0; -} - -static void donames(argv) - char **argv; -{ - register struct person *p; - register struct passwd *pw; - int uf; - - /* - * get names from command line and check to see if they're - * logged in - */ - unshort = !small; - for (; *argv != 0; argv++) { - if (netfinger(*argv)) - continue; - if (person1 == 0) - p = person1 = (struct person *) malloc(sizeof *p); - else { - p->link = (struct person *) malloc(sizeof *p); - p = p->link; - } - p->name = *argv; - p->loggedin = 0; - p->original = 1; - p->pwd = 0; - } - if (person1 == 0) - return; - p->link = 0; - /* - * if we are doing it, read /etc/passwd for the useful info - */ - if (unquick) { - setpwent(); - if (!match) { - for (p = person1; p != 0; p = p->link) - if (pw = getpwnam(p->name)) - p->pwd = pwdcopy(pw); - } else while ((pw = getpwent()) != 0) { - for (p = person1; p != 0; p = p->link) { - if (!p->original) - continue; - if (strcmp(p->name, pw->pw_name) != 0 && - !matchcmp(pw->pw_gecos, pw->pw_name, p->name)) - continue; - if (p->pwd == 0) - p->pwd = pwdcopy(pw); - else { - struct person *new; - /* - * handle multiple login names, insert - * new "duplicate" entry behind - */ - new = (struct person *) - malloc(sizeof *new); - new->pwd = pwdcopy(pw); - new->name = p->name; - new->original = 1; - new->loggedin = 0; - new->link = p->link; - p->original = 0; - p->link = new; - p = new; - } - } - } - endpwent(); - } - /* Now get login information */ - if ((uf = open(USERLOG, 0)) < 0) { - fprintf(stderr, "finger: error opening %s\n", USERLOG); - exit(2); - } - while (read(uf, (char *)&user, sizeof user) == sizeof user) { - if (*user.ut_name == 0) - continue; - for (p = person1; p != 0; p = p->link) { - if (p->loggedin == 2) - continue; - if (strncmp(p->pwd ? p->pwd->pw_name : p->name, - user.ut_name, NMAX) != 0) - continue; - if (p->loggedin == 0) { - bcopy(user.ut_line, p->tty, LMAX); - p->tty[LMAX] = 0; - bcopy(user.ut_host, p->host, HMAX); - p->host[HMAX] = 0; - p->loginat = user.ut_time; - p->loggedin = 1; - } else { /* p->loggedin == 1 */ - struct person *new; - new = (struct person *) malloc(sizeof *new); - new->name = p->name; - bcopy(user.ut_line, new->tty, LMAX); - new->tty[LMAX] = 0; - bcopy(user.ut_host, new->host, HMAX); - new->host[HMAX] = 0; - new->loginat = user.ut_time; - new->pwd = p->pwd; - new->loggedin = 1; - new->original = 0; - new->link = p->link; - p->loggedin = 2; - p->link = new; - p = new; - } - } - } - close(uf); - if (unquick) { - fwopen(); - for (p = person1; p != 0; p = p->link) - decode(p); - fwclose(); - } -} - -static void print() -{ - register FILE *fp; - register struct person *p; - register char *s; - register c; - - /* - * print out what we got - */ - if (header) { - if (unquick) { - if (!unshort) - if (wide) - printf("Login Name TTY Idle When Where\n"); - else - printf("Login TTY Idle When Where\n"); - } else { - printf("Login TTY When"); - if (idle) - printf(" Idle"); - putchar('\n'); - } - } - for (p = person1; p != 0; p = p->link) { - if (!unquick) { - quickprint(p); - continue; - } - if (!unshort) { - shortprint(p); - continue; - } - personprint(p); - if (p->pwd != 0 && !AlreadyPrinted(p->pwd->pw_uid)) { - AnyMail(p->pwd->pw_name); - if (hack) { - s = malloc(strlen(p->pwd->pw_dir) + - sizeof PROJ); - strcpy(s, p->pwd->pw_dir); - strcat(s, PROJ); - if ((fp = fopen(s, "r")) != 0) { - printf("Project: "); - while ((c = getc(fp)) != EOF) { - if (c == '\n') - break; - if (isprint(c) || isspace(c)) - putchar(c); - else - putchar(c ^ 100); - } - fclose(fp); - putchar('\n'); - } - free(s); - } - if (plan) { - s = malloc(strlen(p->pwd->pw_dir) + - sizeof PLAN); - strcpy(s, p->pwd->pw_dir); - strcat(s, PLAN); - if ((fp = fopen(s, "r")) == 0) { - if (!NONOTHING) printf("No Plan.\n"); - } else { - printf("Plan:\n"); - while ((c = getc(fp)) != EOF) - if (isprint(c) || isspace(c)) - putchar(c); - else - putchar(c ^ 100); - fclose(fp); - } - free(s); - } - } - if (p->link != 0) - putchar('\n'); - } -} - -/* - * Duplicate a pwd entry. - * Note: Only the useful things (what the program currently uses) are copied. - */ -static struct passwd * -pwdcopy(pfrom) - register struct passwd *pfrom; -{ - register struct passwd *pto; - - pto = (struct passwd *) malloc(sizeof *pto); -#define savestr(s) strcpy(malloc(strlen(s) + 1), s) - pto->pw_name = savestr(pfrom->pw_name); - pto->pw_uid = pfrom->pw_uid; - pto->pw_gecos = savestr(pfrom->pw_gecos); - pto->pw_dir = savestr(pfrom->pw_dir); - pto->pw_shell = savestr(pfrom->pw_shell); -#undef savestr - return pto; -} - -/* - * print out information on quick format giving just name, tty, login time - * and idle time if idle is set. - */ -static void quickprint(pers) - register struct person *pers; -{ - printf("%-*.*s ", NMAX, NMAX, pers->name); - if (pers->loggedin) { - if (idle) { - findidle(pers); - printf("%c%-*s %-16.16s", pers->writable ? ' ' : '*', - LMAX, pers->tty, ctime(&pers->loginat)); - ltimeprint(" ", &pers->idletime, ""); - } else - printf(" %-*s %-16.16s", LMAX, - pers->tty, ctime(&pers->loginat)); - putchar('\n'); - } else - printf(" Not Logged In\n"); -} - -/* - * print out information in short format, giving login name, full name, - * tty, idle time, login time, and host. - */ -static void shortprint(pers) - register struct person *pers; -{ - char *p; - char dialup; - - if (pers->pwd == 0) { - printf("%-15s ???\n", pers->name); - return; - } - printf("%-*s", NMAX, pers->pwd->pw_name); - dialup = 0; - if (wide) { - if (pers->realname) - printf(" %-20.20s", pers->realname); - else - printf(" ??? "); - } - putchar(' '); - if (pers->loggedin && !pers->writable) - putchar('*'); - else - putchar(' '); - if (*pers->tty) { - if (pers->tty[0] == 't' && pers->tty[1] == 't' && - pers->tty[2] == 'y') { - if (pers->tty[3] == 'd' && pers->loggedin) - dialup = 1; - printf("%-2.2s ", pers->tty + 3); - } else - printf("%-2.2s ", pers->tty); - } else - printf(" "); - p = ctime(&pers->loginat); - if (pers->loggedin) { - stimeprint(&pers->idletime); - printf(" %3.3s %-5.5s ", p, p + 11); - } else if (pers->loginat == 0) - printf(" < . . . . >"); - else if (tloc - pers->loginat >= 180L * 24 * 60 * 60) - printf(" <%-6.6s, %-4.4s>", p + 4, p + 20); - else - printf(" <%-12.12s>", p + 4); - if (pers->host[0]) - printf(" %-20.20s", pers->host); - putchar('\n'); -} - - -/* - * print out a person in long format giving all possible information. - * directory and shell are inhibited if unbrief is clear. - */ -static void -personprint(pers) - register struct person *pers; -{ - if (pers->pwd == 0) { - printf("Login name: %-10s\t\t\tIn real life: ???\n", - pers->name); - return; - } - printf("Login name: %-10s", pers->pwd->pw_name); - if (pers->loggedin && !pers->writable) - printf(" (messages off) "); - else - printf(" "); - if (pers->realname) - printf("In real life: %s", pers->realname); - if (unbrief) { - printf("\nDirectory: %-25s", pers->pwd->pw_dir); - if (*pers->pwd->pw_shell) - printf("\tShell: %-s", pers->pwd->pw_shell); - } - if (pers->loggedin) { - register char *ep = ctime(&pers->loginat); - if (*pers->host) { - printf("\nOn since %15.15s on %s from %s", - &ep[4], pers->tty, pers->host); - ltimeprint("\n", &pers->idletime, " Idle Time"); - } else { - printf("\nOn since %15.15s on %-*s", - &ep[4], LMAX, pers->tty); - ltimeprint("\t", &pers->idletime, " Idle Time"); - } - } else if (pers->loginat == 0) { - if (lf >= 0) printf("\nNever logged in."); - } else if (tloc - pers->loginat > 180L * 24 * 60 * 60) { - register char *ep = ctime(&pers->loginat); - printf("\nLast login %10.10s, %4.4s on %s", - ep, ep+20, pers->tty); - if (*pers->host) - printf(" from %s", pers->host); - } else { - register char *ep = ctime(&pers->loginat); - printf("\nLast login %16.16s on %s", ep, pers->tty); - if (*pers->host) - printf(" from %s", pers->host); - } - putchar('\n'); -} - - -/* - * decode the information in the gecos field of /etc/passwd - */ -static void -decode(pers) - register struct person *pers; -{ - char buffer[256]; - register char *bp, *gp, *lp; - int len; - - pers->realname = 0; - if (pers->pwd == 0) - return; - gp = pers->pwd->pw_gecos; - bp = buffer; - if (*gp == ASTERISK) - gp++; - while (*gp && *gp != COMMA) /* name */ - if (*gp == SAMENAME) { - lp = pers->pwd->pw_name; - if (islower(*lp)) - *bp++ = toupper(*lp++); - while (*bp++ = *lp++) - ; - bp--; - gp++; - } else - *bp++ = *gp++; - *bp++ = 0; - if ((len = bp - buffer) > 1) - pers->realname = strcpy(malloc(len), buffer); - if (pers->loggedin) - findidle(pers); - else - findwhen(pers); -} - -/* - * find the last log in of a user by checking the LASTLOG file. - * the entry is indexed by the uid, so this can only be done if - * the uid is known (which it isn't in quick mode) - */ - -static void -fwopen() -{ - if ((lf = open(LASTLOG, 0)) < 0) { - if (errno == ENOENT) return; - fprintf(stderr, "finger: %s open error\n", LASTLOG); - } -} - -static void -findwhen(pers) - register struct person *pers; -{ - struct utmp ll; -#define ll_line ut_line -#define ll_host ut_host -#define ll_time ut_time - - int i; - - if (lf >= 0) { - lseek(lf, (long)pers->pwd->pw_uid * sizeof ll, 0); - if ((i = read(lf, (char *)&ll, sizeof ll)) == sizeof ll) { - bcopy(ll.ll_line, pers->tty, LMAX); - pers->tty[LMAX] = 0; - bcopy(ll.ll_host, pers->host, HMAX); - pers->host[HMAX] = 0; - pers->loginat = ll.ll_time; - } else { - if (i != 0) - fprintf(stderr, "finger: %s read error\n", - LASTLOG); - pers->tty[0] = 0; - pers->host[0] = 0; - pers->loginat = 0L; - } - } else { - pers->tty[0] = 0; - pers->host[0] = 0; - pers->loginat = 0L; - } -} - -static void fwclose() -{ - if (lf >= 0) - close(lf); -} - -/* - * find the idle time of a user by doing a stat on /dev/tty??, - * where tty?? has been gotten from USERLOG, supposedly. - */ -static void -findidle(pers) - register struct person *pers; -{ - struct stat ttystatus; - static char buffer[20] = "/dev/"; - long t; -#define TTYLEN 5 - - strcpy(buffer + TTYLEN, pers->tty); - buffer[TTYLEN+LMAX] = 0; - if (stat(buffer, &ttystatus) < 0) { - fprintf(stderr, "finger: Can't stat %s\n", buffer); - exit(4); - } - time(&t); - if (t < ttystatus.st_atime) - pers->idletime = 0L; - else - pers->idletime = t - ttystatus.st_atime; - pers->writable = (ttystatus.st_mode & TALKABLE) == TALKABLE; -} - -/* - * print idle time in short format; this program always prints 4 characters; - * if the idle time is zero, it prints 4 blanks. - */ -static void -stimeprint(dt) - long *dt; -{ - register struct tm *delta; - - delta = gmtime(dt); - if (delta->tm_yday == 0) - if (delta->tm_hour == 0) - if (delta->tm_min == 0) - printf(" "); - else - printf(" %2d", delta->tm_min); - else - if (delta->tm_hour >= 10) - printf("%3d:", delta->tm_hour); - else - printf("%1d:%02d", - delta->tm_hour, delta->tm_min); - else - printf("%3dd", delta->tm_yday); -} - -/* - * print idle time in long format with care being taken not to pluralize - * 1 minutes or 1 hours or 1 days. - * print "prefix" first. - */ -static int -ltimeprint(before, dt, after) - long *dt; - char *before, *after; -{ - register struct tm *delta; - - delta = gmtime(dt); - if (delta->tm_yday == 0 && delta->tm_hour == 0 && delta->tm_min == 0 && - delta->tm_sec <= 10) - return (0); - printf("%s", before); - if (delta->tm_yday >= 10) - printf("%d days", delta->tm_yday); - else if (delta->tm_yday > 0) - printf("%d day%s %d hour%s", - delta->tm_yday, delta->tm_yday == 1 ? "" : "s", - delta->tm_hour, delta->tm_hour == 1 ? "" : "s"); - else - if (delta->tm_hour >= 10) - printf("%d hours", delta->tm_hour); - else if (delta->tm_hour > 0) - printf("%d hour%s %d minute%s", - delta->tm_hour, delta->tm_hour == 1 ? "" : "s", - delta->tm_min, delta->tm_min == 1 ? "" : "s"); - else - if (delta->tm_min >= 10) - printf("%2d minutes", delta->tm_min); - else if (delta->tm_min == 0) - printf("%2d seconds", delta->tm_sec); - else - printf("%d minute%s %d second%s", - delta->tm_min, - delta->tm_min == 1 ? "" : "s", - delta->tm_sec, - delta->tm_sec == 1 ? "" : "s"); - printf("%s", after); -} - -static int -matchcmp(gname, login, given) - register char *gname; - char *login; - char *given; -{ - char buffer[100]; - register char *bp, *lp; - register c; - - if (*gname == ASTERISK) - gname++; - lp = 0; - bp = buffer; - for (;;) - switch (c = *gname++) { - case SAMENAME: - for (lp = login; bp < buffer + sizeof buffer - && (*bp++ = *lp++);) - ; - bp--; - break; - case ' ': - case COMMA: - case '\0': - *bp = 0; - if (namecmp(buffer, given)) - return (1); - if (c == COMMA || c == 0) - return (0); - bp = buffer; - break; - default: - if (bp < buffer + sizeof buffer) - *bp++ = c; - } - /*NOTREACHED*/ -} - -static int -namecmp(name1, name2) - register char *name1, *name2; -{ - register c1, c2; - - for (;;) { - c1 = *name1++; - if (islower(c1)) - c1 = toupper(c1); - c2 = *name2++; - if (islower(c2)) - c2 = toupper(c2); - if (c1 != c2) - break; - if (c1 == 0) - return (1); - } - if (!c1) { - for (name2--; isdigit(*name2); name2++) - ; - if (*name2 == 0) - return (1); - } else if (!c2) { - for (name1--; isdigit(*name1); name1++) - ; - if (*name2 == 0) - return (1); - } - return (0); -} - -#if NONET -static int -netfinger(name) -char *name; -{ - return 0; -} -#else -static int -netfinger(name) - char *name; -{ - char *host; - struct hostent *hp; - int s, result; -#if !defined(__minix) - char *rindex(); -#endif - register FILE *f; - register int c; - register int lastc; - nwio_tcpconf_t tcpconf; - nwio_tcpcl_t tcpconnopt; - char *tcp_device; - - if (name == NULL) - return (0); - host = rindex(name, '@'); - if (host == NULL) - return (0); - *host++ = 0; - hp = gethostbyname(host); - if (hp == NULL) { - static struct hostent def; - static ipaddr_t defaddr; - static char namebuf[128]; - - defaddr = inet_addr(host); - if (defaddr == -1) { - printf("unknown host: %s\n", host); - return (1); - } - strcpy(namebuf, host); - def.h_name = namebuf; - def.h_addr = (char *)&defaddr; - def.h_length = sizeof (ipaddr_t); - def.h_addrtype = AF_INET; - def.h_aliases = 0; - hp = &def; - } - printf("[%s] ", hp->h_name); - fflush(stdout); - - tcp_device= getenv("TCP_DEVICE"); - if (tcp_device == NULL) - tcp_device= TCP_DEVICE; - s= open (tcp_device, O_RDWR); - if (s == -1) - { - fprintf(stderr, "%s: unable to open %s (%s)\n", - prog_name, tcp_device, strerror(errno)); - exit(1); - } - tcpconf.nwtc_flags= NWTC_LP_SEL | NWTC_SET_RA | NWTC_SET_RP; - tcpconf.nwtc_remaddr= *(ipaddr_t *)hp->h_addr; - tcpconf.nwtc_remport= htons(TCPPORT_FINGER); - - result= ioctl (s, NWIOSTCPCONF, &tcpconf); - if (result<0) - { - fprintf(stderr, "%s\n", strerror(errno)); - exit(1); - } - - tcpconnopt.nwtcl_flags= 0; - - do - { - result= ioctl (s, NWIOTCPCONN, &tcpconnopt); - if (result<0 && errno== EAGAIN) - { - fprintf(stderr, "got EAGAIN error, sleeping 2s\n"); - sleep(2); - } - } while (result<0 && errno == EAGAIN); - if (result<0) - { - fprintf(stderr, "%s\n", strerror(errno)); - exit(1); - } - printf("\r\n"); - if (large) write(s, "/W ", 3); - write(s, name, strlen(name)); - write(s, "\r\n", 2); - f = fdopen(s, "r"); - while ((c = getc(f)) != EOF) { -/* - switch(c) { - case 0210: - case 0211: - case 0212: - case 0214: - c -= 0200; - break; - case 0215: - c = '\n'; - break; - } -*/ - c &= ~0200; - if (c == '\r') - { - c= getc(f) & ~0200; - if (c == '\012') - { - lastc= c; - putchar('\n'); - continue; - } - else - putchar('\r'); - } - lastc = c; - if (isprint(c) || isspace(c)) - putchar(c); - else - putchar(c ^ 100); - } - if (lastc != '\n') - putchar('\n'); - (void)fclose(f); - return (1); -} -#endif - -/* - * AnyMail - takes a username (string pointer thereto), and - * prints on standard output whether there is any unread mail, - * and if so, how old it is. (JCM@Shasta 15 March 80) - */ -#define preamble "/usr/spool/mail/" /* mailboxes are there */ -static int -AnyMail(name) -char *name; -{ - struct stat buf; /* space for file status buffer */ - char *mbxdir = preamble; /* string with path preamble */ - char *mbxpath; /* space for entire pathname */ - -#if !defined(__minix) - char *ctime(); /* convert longword time to ascii */ -#endif - char *timestr; - - mbxpath = malloc(strlen(name) + strlen(preamble) + 1); - - strcpy(mbxpath, mbxdir); /* copy preamble into path name */ - strcat(mbxpath, name); /* concatenate user name to path */ - - if (stat(mbxpath, &buf) == -1 || buf.st_size == 0) { - /* Mailbox is empty or nonexistent */ - if (!NONOTHING) printf("No unread mail\n"); - } else { - if (buf.st_mtime == buf.st_atime) { - /* There is something in the mailbox, but we can't really - * be sure whether it is mail held there by the user - * or a (single) new message that was placed in a newly - * recreated mailbox, so we punt and call it "unread mail." - */ - printf("Unread mail since "); - printf(ctime(&buf.st_mtime)); - } else { - /* New mail has definitely arrived since the last time - * mail was read. mtime is the time the most recent - * message arrived; atime is either the time the oldest - * unread message arrived, or the last time the mail - * was read. - */ - printf("New mail received "); - timestr = ctime(&buf.st_mtime); /* time last modified */ - timestr[24] = '\0'; /* suppress newline (ugh) */ - printf(timestr); - printf(";\n unread since "); - printf(ctime(&buf.st_atime)); /* time last accessed */ - } - } - - free(mbxpath); -} - -/* - * return true iff we've already printed project/plan for this uid; - * if not, enter this uid into table (so this function has a side-effect.) - */ -#define PPMAX 200 /* assume no more than 200 logged-in users */ -int PlanPrinted[PPMAX+1]; -int PPIndex = 0; /* index of next unused table entry */ - -static int -AlreadyPrinted(uid) -int uid; -{ - int i = 0; - - while (i++ < PPIndex) { - if (PlanPrinted[i] == uid) - return(1); - } - if (i < PPMAX) { - PlanPrinted[i] = uid; - PPIndex++; - } - return(0); -} diff --git a/man/man1/Makefile b/man/man1/Makefile index 090211342..d966dcc80 100644 --- a/man/man1/Makefile +++ b/man/man1/Makefile @@ -5,7 +5,7 @@ MAN= ash.1 at.1 basename.1 \ df.1 dhrystone.1 dosdir.1 dosread.1 doswrite.1 \ dumpcore.1 eject.1 \ env.1 expand.1 factor.1 \ - finger.1 flexdoc.1 fold.1 format.1 fortune.1 \ + flexdoc.1 fold.1 format.1 fortune.1 \ fsck.mfs.1 host.1 hostaddr.1 ifdef.1 \ isodir.1 isoinfo.1 isoread.1 \ last.1 loadfont.1 loadkeys.1 logger.1 \ diff --git a/man/man1/finger.1 b/man/man1/finger.1 deleted file mode 100644 index fe64472dd..000000000 --- a/man/man1/finger.1 +++ /dev/null @@ -1,84 +0,0 @@ -.\" Copyright (c) 1980 Regents of the University of California. -.\" All rights reserved. The Berkeley software License Agreement -.\" specifies the terms and conditions for redistribution. -.\" -.\" @(#)finger.1 6.4 (Berkeley) 5/10/86 -.\" -.TH FINGER 1 "May 10, 1986" -.UC 4 -.SH NAME -finger \- user information lookup program -.SH SYNOPSIS -.B finger -[ -options -] name ... -.SH DESCRIPTION -By default -.B finger -lists the login name, full name, terminal name and write status -(as a `*' before the terminal name if write permission is denied), -idle time, login time, and office location and phone number -(if they are known) for each current UNIX user. -(Idle time is minutes if it is a single integer, hours and minutes if a ':' -is present, or days and hours if a 'd' is present.) -.PP -A longer format also exists and is used by -.B finger -whenever a list of people's names is given. (Account names as well as -first and last names of users are accepted.) -This format is multi-line, and includes all the information described above -as well as the user's home -directory and login shell, any plan which the person has placed in the file -.B \&.plan -in their home -directory, and the project on which they are working from the file -.B \&.project -also in the home directory. -.PP -.B Finger -may be used to lookup users on a remote machine. The format is to specify -the user as ``user@host.'' If the user name is left off, the -standard format listing is provided on the remote machine. -.PP -.B Finger -options include: -.TP -.B \-m -Match arguments only on user name. -.TP -.B \-l -Force long output format. -.TP -.B \-p -Suppress printing of the -.B \&.plan -files -.TP -.B \-s -Force short output format. -.SH FILES -.ta 2i -/etc/utmp who file -.br -/etc/passwd for users names, offices, ... -.br -/usr/adm/lastlog last login times -.br -~/.plan plans -.br -~/.project projects -.SH "SEE ALSO" -.BR chfn (1), -.BR w (1), -.BR who (1). -.SH AUTHOR -Earl T. Cohen -.SH BUGS -Only the first line of the -.B .project -file is printed. -.PP -There is no way to pass arguments to the remote machine as -.B finger -uses an internet standard port. diff --git a/releasetools/nbsd_ports b/releasetools/nbsd_ports index 3f4b7378f..23300f91a 100644 --- a/releasetools/nbsd_ports +++ b/releasetools/nbsd_ports @@ -133,6 +133,7 @@ 2012/10/17 12:00:00,usr.bin/col 2012/10/17 12:00:00,usr.bin/ctags 2011/09/01 13:37:33,usr.bin/du +2013/05/31 12:00:00,usr.bin/finger 2013/03/22 12:00:00,usr.bin/from 2013/04/05 12:00:00,usr.bin/ftp 2013/03/18 12:00:00,usr.bin/head diff --git a/usr.bin/Makefile b/usr.bin/Makefile index a719ec5fd..c8bf4dc81 100644 --- a/usr.bin/Makefile +++ b/usr.bin/Makefile @@ -9,7 +9,7 @@ SUBDIR= \ cal chpass cksum \ col ctags \ du \ - \ + finger \ from ftp \ genassym getopt head \ indent infocmp join \ diff --git a/usr.bin/finger/Makefile b/usr.bin/finger/Makefile new file mode 100644 index 000000000..d51dee1d8 --- /dev/null +++ b/usr.bin/finger/Makefile @@ -0,0 +1,18 @@ +# $NetBSD: Makefile,v 1.11 2007/05/28 12:06:26 tls Exp $ +# from: @(#)Makefile 8.1 (Berkeley) 6/6/93 + +.include + +USE_FORT?= yes # network client + +PROG= finger +SRCS= finger.c lprint.c net.c sprint.c util.c utmpentry.c + +.PATH.c: ${NETBSDSRCDIR}/usr.bin/who +CPPFLAGS+=-I${NETBSDSRCDIR}/usr.bin/who -DSUPPORT_UTMPX -DSUPPORT_UTMP + +.if (${USE_INET6} != "no") +CPPFLAGS+=-DINET6 +.endif + +.include diff --git a/usr.bin/finger/extern.h b/usr.bin/finger/extern.h new file mode 100644 index 000000000..e55cd6192 --- /dev/null +++ b/usr.bin/finger/extern.h @@ -0,0 +1,57 @@ +/* $NetBSD: extern.h,v 1.10 2006/01/04 01:17:54 perry Exp $ */ + +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)extern.h 8.2 (Berkeley) 4/28/95 + */ + +extern time_t now; /* Current time. */ +extern char tbuf[1024]; /* Temp buffer for anybody. */ +extern int entries; /* Number of people. */ +extern DB *db; /* Database. */ +extern int lflag; +extern int oflag; +extern int gflag; +extern int eightflag; +extern int pplan; + +void enter_lastlog(PERSON *); +PERSON *enter_person(struct passwd *); +void enter_where(struct utmpentry *, PERSON *); +void expandusername(const char *, const char *, char *, int); +PERSON *find_person(char *); +int hash(char *); +void lflag_print(void); +int match(struct passwd *, char *); +void netfinger(char *); +PERSON *palloc(void); +char *prphone(char *); +int psort(const void *, const void *); +void sflag_print(void); +PERSON **sort(void); diff --git a/usr.bin/finger/finger.1 b/usr.bin/finger/finger.1 new file mode 100644 index 000000000..f2419901b --- /dev/null +++ b/usr.bin/finger/finger.1 @@ -0,0 +1,213 @@ +.\" $NetBSD: finger.1,v 1.16 2012/06/10 17:45:59 dholland Exp $ +.\" +.\" Copyright (c) 1989, 1990, 1993, 1994 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" from: @(#)finger.1 8.3 (Berkeley) 5/5/94 +.\" +.Dd June 10, 2012 +.Dt FINGER 1 +.Os +.Sh NAME +.Nm finger +.Nd user information lookup program +.Sh SYNOPSIS +.Nm +.Op Fl 8ghlmops +.Op Ar user ... +.Op Ar user@host ... +.Sh DESCRIPTION +The +.Nm +displays information about the system users. +.Pp +Options are: +.Bl -tag -width flag +.It Fl 8 +Pass through 8-bit data. +This option is intended for enabling 8-bit +data output in the +.Xr fingerd 8 +service. +Using this from the command line is +.Em dangerous , +as the output data may include control characters for your terminal. +.It Fl g +This option restricts the gecos output to only the users' real names. +.It Fl h +When used in conjunction with the +.Fl s +option, the name of the remote host is displayed instead of the office +location and office phone. +.It Fl l +Produces a multi-line format displaying all of the information +described for the +.Fl s +option as well as the user's home directory, home phone number, login +shell, mail status, and the contents of the files +.Dq Pa .forward , +.Dq Pa .plan +and +.Dq Pa .project +from the user's home directory. +.Pp +If idle time is at least a minute and less than a day, it is +presented in the form +.Dq hh:mm . +Idle times greater than a day are presented as +.Dq d day[s]hh:mm . +.Pp +Phone numbers specified as eleven digits are printed as +.Dq +N-NNN-NNN-NNNN . +Numbers specified as ten or seven digits are printed as the appropriate +subset of that string. +Numbers specified as five digits are printed as +.Dq xN-NNNN . +Numbers specified as four digits are printed as +.Dq xNNNN . +.Pp +If write permission is denied to the device, the phrase +.Dq (messages off) +is appended to the line containing the device name. +One entry per user is displayed with the +.Fl l +option; if a user is logged on multiple times, terminal information +is repeated once per login. +.Pp +Mail status is shown as +.Dq \&No Mail. +if there is no mail at all, ``Mail last read DDD MMM ## HH:MM YYYY (TZ)'' +if the person has looked at their +mailbox since new mail arriving, or +.Dq New mail received ... , +.Dq Unread since \&... +if they have new mail. +.It Fl m +Prevent matching of +.Ar user +names. +.Ar User +is usually a login name; however, matching will also be done on the +users' real names, unless the +.Fl m +option is supplied. +All name matching performed by +.Nm +is case insensitive. +.It Fl o +When used in conjunction with the +.Fl s +option, the office location and office phone information is displayed. +This is the default. +.It Fl p +Prevents +the +.Fl l +option of +.Nm +from displaying the contents of the +.Dq Pa .forward , +.Dq Pa .plan +and +.Dq Pa .project +files. +.It Fl s +.Nm +displays the user's login name, real name, terminal name and write +status (as a +.Dq * +after the terminal name if write permission is denied), idle time, +login time, and either office location and office phone number, +or the remote host. +If +.Fl h +is given, the remote is printed. +If +.Fl o +is given, the office location and phone number is printed instead +(the default). +.Pp +Idle time is in minutes if it is a single integer, hours and minutes +if a +.Dq \&: +is present, or days if a +.Dq d +is present. +Login time is displayed as the dayname if less than six days, +else month, day, hours and minutes, unless +more than six months ago, in which case the year is displayed rather +than the hours and minutes. +.Pp +Unknown devices as well as nonexistent idle and login times are +displayed as single asterisks. +.El +.Pp +If no options are specified, +.Nm +defaults to the +.Fl l +style output if operands are provided, otherwise to the +.Fl s +style. +Note that some fields may be missing, in either format, if information +is not available for them. +.Pp +If no arguments are specified, +.Nm +will print an entry for each user currently logged into the system. +.Pp +.Nm +may be used to look up users on a remote machine. +The format is to specify a +.Ar user +as +.Dq Li user@host , +or +.Dq Li @host , +where the default output +format for the former is the +.Fl l +style, and the default output format for the latter is the +.Fl s +style. +The +.Fl l +option is the only option that may be passed to a remote machine. +.Sh FILES +.Bl -tag -width /var/log/lastlog -compact +.It Pa /var/log/lastlog +last login data base +.El +.Sh SEE ALSO +.Xr chpass 1 , +.Xr w 1 , +.Xr who 1 +.Sh HISTORY +The +.Nm +command appeared in +.Bx 3.0 . diff --git a/usr.bin/finger/finger.c b/usr.bin/finger/finger.c new file mode 100644 index 000000000..e61f905e5 --- /dev/null +++ b/usr.bin/finger/finger.c @@ -0,0 +1,301 @@ +/* $NetBSD: finger.c,v 1.29 2009/04/12 06:18:54 lukem Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Luke Mewburn added the following on 961121: + * - mail status ("No Mail", "Mail read:...", or "New Mail ..., + * Unread since ...".) + * - 4 digit phone extensions (3210 is printed as x3210.) + * - host/office toggling in short format with -h & -o. + * - short day names (`Tue' printed instead of `Jun 21' if the + * login time is < 6 days. + */ + +#include +#ifndef lint +__COPYRIGHT("@(#) Copyright (c) 1989, 1993\ + The Regents of the University of California. All rights reserved."); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)finger.c 8.5 (Berkeley) 5/4/95"; +#else +__RCSID("$NetBSD: finger.c,v 1.29 2009/04/12 06:18:54 lukem Exp $"); +#endif +#endif /* not lint */ + +/* + * Finger prints out information about users. It is not portable since + * certain fields (e.g. the full user name, office, and phone numbers) are + * extracted from the gecos field of the passwd file which other UNIXes + * may not have or may use for other things. + * + * There are currently two output formats; the short format is one line + * per user and displays login name, tty, login time, real name, idle time, + * and either remote host information (default) or office location/phone + * number, depending on if -h or -o is used respectively. + * The long format gives the same information (in a more legible format) as + * well as home directory, shell, mail info, and .plan/.project files. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "utmpentry.h" + +#include "finger.h" +#include "extern.h" + +DB *db; +time_t now; +int entries, gflag, lflag, mflag, oflag, sflag, eightflag, pplan; +char tbuf[1024]; +struct utmpentry *ehead; + +static void loginlist(void); +static void userlist(int, char **); +int main(int, char **); + +int +main(int argc, char **argv) +{ + int ch; + + /* Allow user's locale settings to affect character output. */ + setlocale(LC_CTYPE, ""); + + /* + * Reset back to the C locale, unless we are using a known + * single-byte 8-bit locale. + */ + if (strncmp(nl_langinfo(CODESET), "ISO8859-", 8)) + setlocale(LC_CTYPE, "C"); + + oflag = 1; /* default to old "office" behavior */ + + while ((ch = getopt(argc, argv, "lmpshog8")) != -1) + switch(ch) { + case 'l': + lflag = 1; /* long format */ + break; + case 'm': + mflag = 1; /* force exact match of names */ + break; + case 'p': + pplan = 1; /* don't show .plan/.project */ + break; + case 's': + sflag = 1; /* short format */ + break; + case 'h': + oflag = 0; /* remote host info */ + break; + case 'o': + oflag = 1; /* office info */ + break; + case 'g': + gflag = 1; /* no gecos info, besides name */ + break; + case '8': + eightflag = 1; /* 8-bit pass-through */ + break; + case '?': + default: + (void)fprintf(stderr, + "usage: finger [-lmpshog8] [login ...]\n"); + exit(1); + } + argc -= optind; + argv += optind; + + (void)time(&now); + setpassent(1); + entries = getutentries(NULL, &ehead); + if (argc == 0) { + /* + * Assign explicit "small" format if no names given and -l + * not selected. Force the -s BEFORE we get names so proper + * screening will be done. + */ + if (!lflag) + sflag = 1; /* if -l not explicit, force -s */ + loginlist(); + if (entries == 0) + (void)printf("No one logged on.\n"); + } else { + userlist(argc, argv); + /* + * Assign explicit "large" format if names given and -s not + * explicitly stated. Force the -l AFTER we get names so any + * remote finger attempts specified won't be mishandled. + */ + if (!sflag) + lflag = 1; /* if -s not explicit, force -l */ + } + if (entries) { + if (lflag) + lflag_print(); + else + sflag_print(); + } + return (0); +} + +static void +loginlist(void) +{ + PERSON *pn; + DBT data, key; + struct passwd *pw; + int r, seqflag; + struct utmpentry *ep; + + for (ep = ehead; ep; ep = ep->next) { + if ((pn = find_person(ep->name)) == NULL) { + if ((pw = getpwnam(ep->name)) == NULL) + continue; + pn = enter_person(pw); + } + enter_where(ep, pn); + } + if (db && lflag) + for (seqflag = R_FIRST;; seqflag = R_NEXT) { + PERSON *tmp; + + r = (*db->seq)(db, &key, &data, seqflag); + if (r == -1) + err(1, "db seq"); + if (r == 1) + break; + memmove(&tmp, data.data, sizeof tmp); + enter_lastlog(tmp); + } +} + +static void +userlist(int argc, char **argv) +{ + PERSON *pn; + DBT data, key; + struct passwd *pw; + int r, seqflag, *used, *ip; + char **ap, **nargv, **np, **p; + struct utmpentry *ep; + + if ((nargv = malloc((argc+1) * sizeof(char *))) == NULL || + (used = calloc(argc, sizeof(int))) == NULL) + err(1, NULL); + + /* Pull out all network requests. */ + for (ap = p = argv, np = nargv; *p; ++p) + if (strchr(*p, '@')) + *np++ = *p; + else + *ap++ = *p; + + *np++ = NULL; + *ap++ = NULL; + + if (!*argv) + goto net; + + /* + * Traverse the list of possible login names and check the login name + * and real name against the name specified by the user. + */ + if (mflag) { + for (p = argv; *p; ++p) + if ((pw = getpwnam(*p)) != NULL) + enter_person(pw); + else + warnx("%s: no such user", *p); + } else { + while ((pw = getpwent()) != NULL) + for (p = argv, ip = used; *p; ++p, ++ip) + if (match(pw, *p)) { + enter_person(pw); + *ip = 1; + } + for (p = argv, ip = used; *p; ++p, ++ip) + if (!*ip) + warnx("%s: no such user", *p); + } + + /* Handle network requests. */ +net: + for (p = nargv; *p;) + netfinger(*p++); + + if (entries == 0) + goto done; + + /* + * Scan thru the list of users currently logged in, saving + * appropriate data whenever a match occurs. + */ + for (ep = ehead; ep; ep = ep->next) { + if ((pn = find_person(ep->name)) == NULL) + continue; + enter_where(ep, pn); + } + if (db != NULL) + for (seqflag = R_FIRST;; seqflag = R_NEXT) { + PERSON *tmp; + + r = (*db->seq)(db, &key, &data, seqflag); + if (r == -1) + err(1, "db seq"); + if (r == 1) + break; + memmove(&tmp, data.data, sizeof tmp); + enter_lastlog(tmp); + } +done: + free(nargv); + free(used); +} diff --git a/usr.bin/finger/finger.h b/usr.bin/finger/finger.h new file mode 100644 index 000000000..e310ff29e --- /dev/null +++ b/usr.bin/finger/finger.h @@ -0,0 +1,67 @@ +/* $NetBSD: finger.h,v 1.10 2007/05/05 16:55:17 christos Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * from: @(#)finger.h 8.1 (Berkeley) 6/6/93 + */ + + +/* + * All unique persons are linked in a list headed by "head" and linkd + * by the "next" field, as well as kept in a hash table. + */ + +typedef struct person { + uid_t uid; /* user id */ + char *dir; /* user's home directory */ + char *homephone; /* pointer to home phone no. */ + char *name; /* login name */ + char *office; /* pointer to office name */ + char *officephone; /* pointer to office phone no. */ + char *realname; /* pointer to full name */ + char *shell; /* user's shell */ + time_t mailread; /* last time mail was read */ + time_t mailrecv; /* last time mail was read */ + struct where *whead, *wtail; /* list of where user is or has been */ +} PERSON; + +enum status { LASTLOG, LOGGEDIN }; + +typedef struct where { + struct where *next; /* next place user is or has been */ + enum status info; /* type/status of request */ + short writable; /* tty is writable */ + time_t loginat; /* time of (last) login */ + time_t idletime; /* how long idle (if logged in) */ + char *tty; /* tty line */ + char *host; /* remote host name */ +} WHERE; diff --git a/usr.bin/finger/lprint.c b/usr.bin/finger/lprint.c new file mode 100644 index 000000000..24953323c --- /dev/null +++ b/usr.bin/finger/lprint.c @@ -0,0 +1,389 @@ +/* $NetBSD: lprint.c,v 1.23 2013/01/18 22:10:31 christos Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#ifndef lint +#if 0 +static char sccsid[] = "@(#)lprint.c 8.3 (Berkeley) 4/28/95"; +#else +__RCSID( "$NetBSD: lprint.c,v 1.23 2013/01/18 22:10:31 christos Exp $"); +#endif +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utmpentry.h" +#include "finger.h" +#include "extern.h" + +#define LINE_LEN 80 +#define TAB_LEN 8 /* 8 spaces between tabs */ +#define _PATH_FORWARD ".forward" +#define _PATH_PLAN ".plan" +#define _PATH_PROJECT ".project" + +static int demi_print(const char *, int); +static void lprint(PERSON *); +static int show_text(const char *, const char *, const char *); +static void vputc(int); + +#ifdef __SVR4 +#define TIMEZONE(a) tzname[0] +#else +#define TIMEZONE(a) (a)->tm_zone +#endif + +void +lflag_print(void) +{ + PERSON *pn; + int sflag, r; + PERSON *tmp; + DBT data, key; + + if (db == NULL) + return; + + for (sflag = R_FIRST;; sflag = R_NEXT) { + r = (*db->seq)(db, &key, &data, sflag); + if (r == -1) + err(1, "db seq"); + if (r == 1) + break; + memmove(&tmp, data.data, sizeof tmp); + pn = tmp; + if (sflag != R_FIRST) + putchar('\n'); + lprint(pn); + if (!pplan) { + (void)show_text(pn->dir, + _PATH_FORWARD, "Mail forwarded to"); + (void)show_text(pn->dir, _PATH_PROJECT, "Project"); + if (!show_text(pn->dir, _PATH_PLAN, "Plan")) + (void)printf("No Plan.\n"); + } + } +} + +static size_t +visify(char *buf, size_t blen, const char *str) +{ + int len = strnvisx(buf, blen, str, strlen(str), VIS_WHITE|VIS_CSTYLE); + if (len == -1) { + buf[0] = '\0'; + return 0; + } + return len; +} + +static void +fmt_time(char *buf, size_t blen, time_t ti, time_t n) +{ + struct tm *tp = localtime(&ti); + if (tp != NULL) { + char *t = asctime(tp); + char *tzn = TIMEZONE(tp); + if (n == (time_t)-1 || + n - ti > SECSPERDAY * DAYSPERNYEAR / 2) + snprintf(buf, blen, "%.16s %.4s (%s)", t, t + 20, tzn); + else + snprintf(buf, blen, "%.16s (%s)", t, tzn); + } else + snprintf(buf, blen, "[*bad time 0x%llx*]", (long long)ti); +} + +/* + * idle time is tough; if have one, print a comma, + * then spaces to pad out the device name, then the + * idle time. Follow with a comma if a remote login. + */ +static int +print_idle(time_t t, int maxlen, size_t hostlen, size_t ttylen) { + + int cpr; + struct tm *delta = gmtime(&t); + + if (delta == NULL) + return printf("Bad idle 0x%llx", (long long)t); + + if (delta->tm_yday == 0 && delta->tm_hour == 0 && delta->tm_min == 0) + return 0; + + cpr = printf("%-*s idle ", (int)(maxlen - ttylen + 1), ","); + if (delta->tm_yday > 0) { + cpr += printf("%d day%s ", delta->tm_yday, + delta->tm_yday == 1 ? "" : "s"); + } + cpr += printf("%d:%02d", delta->tm_hour, delta->tm_min); + if (hostlen) { + putchar(','); + ++cpr; + } + return cpr; +} + +static void +lprint(PERSON *pn) +{ + WHERE *w; + int cpr, len, maxlen; + int oddfield; + char timebuf[128], ttybuf[64], hostbuf[512]; + size_t ttylen, hostlen; + + cpr = 0; + /* + * long format -- + * login name + * real name + * home directory + * shell + * office, office phone, home phone if available + * mail status + */ + (void)printf("Login: %-15s\t\t\tName: %s\nDirectory: %-25s", + pn->name, pn->realname, pn->dir); + (void)printf("\tShell: %-s\n", *pn->shell ? pn->shell : _PATH_BSHELL); + + if (gflag) + goto no_gecos; + /* + * try and print office, office phone, and home phone on one line; + * if that fails, do line filling so it looks nice. + */ +#define OFFICE_TAG "Office" +#define OFFICE_PHONE_TAG "Office Phone" + oddfield = 0; + if (pn->office && pn->officephone && + strlen(pn->office) + strlen(pn->officephone) + + sizeof(OFFICE_TAG) + 2 <= 5 * TAB_LEN) { + (void)snprintf(timebuf, sizeof(timebuf), "%s: %s, %s", + OFFICE_TAG, pn->office, prphone(pn->officephone)); + oddfield = demi_print(timebuf, oddfield); + } else { + if (pn->office) { + (void)snprintf(timebuf, sizeof(timebuf), "%s: %s", + OFFICE_TAG, pn->office); + oddfield = demi_print(timebuf, oddfield); + } + if (pn->officephone) { + (void)snprintf(timebuf, sizeof(timebuf), "%s: %s", + OFFICE_PHONE_TAG, prphone(pn->officephone)); + oddfield = demi_print(timebuf, oddfield); + } + } + if (pn->homephone) { + (void)snprintf(timebuf, sizeof(timebuf), "%s: %s", "Home Phone", + prphone(pn->homephone)); + oddfield = demi_print(timebuf, oddfield); + } + if (oddfield) + putchar('\n'); + +no_gecos: + /* + * long format con't: + * if logged in + * terminal + * idle time + * if messages allowed + * where logged in from + * if not logged in + * when last logged in + */ + /* find out longest device name for this user for formatting */ + for (w = pn->whead, maxlen = -1; w != NULL; w = w->next) { + visify(ttybuf, sizeof(ttybuf), w->tty); + if ((len = strlen(ttybuf)) > maxlen) + maxlen = len; + } + /* find rest of entries for user */ + for (w = pn->whead; w != NULL; w = w->next) { + ttylen = visify(ttybuf, sizeof(ttybuf), w->tty); + hostlen = visify(hostbuf, sizeof(hostbuf), w->host); + switch (w->info) { + case LOGGEDIN: + fmt_time(timebuf, sizeof(timebuf), w->loginat, -1); + cpr = printf("On since %s on %s", timebuf, ttybuf); + + cpr += print_idle(w->idletime, maxlen, hostlen, + ttylen); + + if (!w->writable) + cpr += printf(" (messages off)"); + break; + case LASTLOG: + if (w->loginat == 0) { + (void)printf("Never logged in."); + break; + } + fmt_time(timebuf, sizeof(timebuf), w->loginat, now); + cpr = printf("Last login %s on %s", timebuf, ttybuf); + break; + } + if (hostlen) { + if (LINE_LEN < (cpr + 6 + hostlen)) + (void)printf("\n "); + (void)printf(" from %s", hostbuf); + } + putchar('\n'); + } + if (pn->mailrecv == -1) + printf("No Mail.\n"); + else if (pn->mailrecv > pn->mailread) { + fmt_time(timebuf, sizeof(timebuf), pn->mailrecv, -1); + printf("New mail received %s\n", timebuf); + fmt_time(timebuf, sizeof(timebuf), pn->mailread, -1); + printf(" Unread since %s\n", timebuf); + } else { + fmt_time(timebuf, sizeof(timebuf), pn->mailread, -1); + printf("Mail last read %s\n", timebuf); + } +} + +static int +demi_print(const char *str, int oddfield) +{ + static int lenlast; + int lenthis, maxlen; + + lenthis = strlen(str); + if (oddfield) { + /* + * We left off on an odd number of fields. If we haven't + * crossed the midpoint of the screen, and we have room for + * the next field, print it on the same line; otherwise, + * print it on a new line. + * + * Note: we insist on having the right hand fields start + * no less than 5 tabs out. + */ + maxlen = 5 * TAB_LEN; + if (maxlen < lenlast) + maxlen = lenlast; + if (((((maxlen / TAB_LEN) + 1) * TAB_LEN) + + lenthis) <= LINE_LEN) { + while(lenlast < (4 * TAB_LEN)) { + putchar('\t'); + lenlast += TAB_LEN; + } + (void)printf("\t%s\n", str); /* force one tab */ + } else { + (void)printf("\n%s", str); /* go to next line */ + oddfield = !oddfield; /* this'll be undone below */ + } + } else + (void)printf("%s", str); + oddfield = !oddfield; /* toggle odd/even marker */ + lenlast = lenthis; + return(oddfield); +} + +static int +show_text(const char *directory, const char *file_name, const char *header) +{ + struct stat sb; + FILE *fp; + int ch, cnt, lastc; + char *p; + int fd, nr; + + lastc = 0; + (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", directory, file_name); + if ((fd = open(tbuf, O_RDONLY)) < 0 || fstat(fd, &sb) || + sb.st_size == 0) + return(0); + + /* If short enough, and no newlines, show it on a single line.*/ + if (sb.st_size <= (off_t)(LINE_LEN - strlen(header) - 5)) { + nr = read(fd, tbuf, sizeof(tbuf)); + if (nr <= 0) { + (void)close(fd); + return(0); + } + for (p = tbuf, cnt = nr; cnt--; ++p) + if (*p == '\n') + break; + if (cnt <= 1) { + (void)printf("%s: ", header); + for (p = tbuf, cnt = nr; cnt--; ++p) + vputc(lastc = (unsigned char)*p); + if (lastc != '\n') + (void)putchar('\n'); + (void)close(fd); + return(1); + } + else + (void)lseek(fd, 0L, SEEK_SET); + } + if ((fp = fdopen(fd, "r")) == NULL) + return(0); + (void)printf("%s:\n", header); + while ((ch = getc(fp)) != EOF) + vputc(lastc = ch); + if (lastc != '\n') + (void)putchar('\n'); + (void)fclose(fp); + return(1); +} + +static void +vputc(int ch) +{ + char visout[5], *s2; + + if (eightflag || isprint(ch) || isspace(ch)) { + (void)putchar(ch); + return; + } + ch = toascii(ch); + vis(visout, ch, VIS_SAFE|VIS_NOSLASH, 0); + for (s2 = visout; *s2; s2++) + (void)putchar(*s2); +} diff --git a/usr.bin/finger/net.c b/usr.bin/finger/net.c new file mode 100644 index 000000000..d1db8c2ff --- /dev/null +++ b/usr.bin/finger/net.c @@ -0,0 +1,159 @@ +/* $NetBSD: net.c,v 1.23 2009/04/12 06:18:54 lukem Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#ifndef lint +#if 0 +static char sccsid[] = "@(#)net.c 8.4 (Berkeley) 4/28/95"; +#else +__RCSID("$NetBSD: net.c,v 1.23 2009/04/12 06:18:54 lukem Exp $"); +#endif +#endif /* not lint */ + +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utmpentry.h" + +#include "finger.h" +#include "extern.h" + +void +netfinger(char *name) +{ + FILE *fp; + int c, lastc; + int s; + char *host; + struct addrinfo hints, *res, *res0; + int error; + const char *emsg = NULL; + + lastc = 0; + if (!(host = strrchr(name, '@'))) + return; + *host++ = '\0'; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_CANONNAME; + error = getaddrinfo(host, "finger", &hints, &res0); + if (error) { + warnx("%s: %s", gai_strerror(error), host); + return; + } + + s = -1; + for (res = res0; res; res = res->ai_next) { + s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (s < 0) { + emsg = "socket"; + continue; + } + + if (connect(s, res->ai_addr, res->ai_addrlen)) { + close(s); + s = -1; + emsg = "connect"; + continue; + } + + break; + } + if (s < 0) { + if (emsg != NULL) + warn("%s", emsg); + return; + } + + /* have network connection; identify the host connected with */ + (void)printf("[%s]\n", res0->ai_canonname ? res0->ai_canonname : host); + + /* -l flag for remote fingerd */ + if (lflag) + write(s, "/W ", 3); + /* send the name followed by */ + (void)write(s, name, strlen(name)); + (void)write(s, "\r\n", 2); + + /* + * Read from the remote system; once we're connected, we assume some + * data. If none arrives, we hang until the user interrupts. + * + * If we see a followed by a newline character, only output + * one newline. + * + * If a character isn't printable and it isn't a space, we strip the + * 8th bit and set the 7th bit. Every ASCII character with bit 7 set + * is printable. + */ + if ((fp = fdopen(s, "r")) != NULL) + while ((c = getc(fp)) != EOF) { + if (c == '\r') { + if (lastc == '\r') /* ^M^M - skip dupes */ + continue; + c = '\n'; + lastc = '\r'; + } else { + if (!(eightflag || isprint(c) || isspace(c))) { + c &= 0x7f; + c |= 0x40; + } + if (lastc != '\r' || c != '\n') + lastc = c; + else { + lastc = '\n'; + continue; + } + } + putchar(c); + } + if (lastc != '\n') + putchar('\n'); + (void)fclose(fp); +} diff --git a/usr.bin/finger/sprint.c b/usr.bin/finger/sprint.c new file mode 100644 index 000000000..84102f28e --- /dev/null +++ b/usr.bin/finger/sprint.c @@ -0,0 +1,173 @@ +/* $NetBSD: sprint.c,v 1.17 2006/01/04 01:17:54 perry Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#ifndef lint +#if 0 +static char sccsid[] = "@(#)sprint.c 8.3 (Berkeley) 4/28/95"; +#else +__RCSID("$NetBSD: sprint.c,v 1.17 2006/01/04 01:17:54 perry Exp $"); +#endif +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utmpentry.h" + +#include "finger.h" +#include "extern.h" + +static void stimeprint(WHERE *); + +void +sflag_print(void) +{ + PERSON *pn; + WHERE *w; + int sflag, r; + char *p; + PERSON *tmp; + DBT data, key; + + if (db == NULL) + return; + + /* + * short format -- + * login name + * real name + * terminal name + * if terminal writable (add an '*' to the terminal name + * if not) + * if logged in show idle time and day logged in, else + * show last login date and time. If > 6 months, + * show year instead of time. If < 6 days, + * show day name instead of month & day. + * if -h given + * remote host + * else if -o given (overriding -h) (default) + * office location + * office phone + */ +#define MAXREALNAME 18 + (void)printf("%-*s %-*s %s %s\n", maxname, "Login", MAXREALNAME, + "Name", " Tty Idle Login Time ", (gflag) ? "" : + (oflag) ? "Office Office Phone" : "Where"); + + for (sflag = R_FIRST;; sflag = R_NEXT) { + r = (*db->seq)(db, &key, &data, sflag); + if (r == -1) + err(1, "db seq"); + if (r == 1) + break; + memmove(&tmp, data.data, sizeof tmp); + pn = tmp; + + for (w = pn->whead; w != NULL; w = w->next) { + (void)printf("%-*.*s %-*.*s ", (int)maxname, + (int)maxname, + pn->name, MAXREALNAME, MAXREALNAME, + pn->realname ? pn->realname : ""); + if (!w->loginat) { + (void)printf(" * * No logins "); + goto office; + } + (void)putchar(w->info == LOGGEDIN && !w->writable ? + '*' : ' '); + if (*w->tty) + (void)printf("%-7.7s ", w->tty); + else + (void)printf(" "); + if (w->info == LOGGEDIN) { + stimeprint(w); + (void)printf(" "); + } else + (void)printf(" * "); + p = ctime(&w->loginat); + if (now - w->loginat < SECSPERDAY * (DAYSPERWEEK - 1)) + (void)printf("%.3s %-8.5s", p, p + 11); + else if (now - w->loginat + < SECSPERDAY * DAYSPERNYEAR / 2) + (void)printf("%.6s %-5.5s", p + 4, p + 11); + else + (void)printf("%.6s %-5.4s", p + 4, p + 20); +office: + if (gflag) + goto no_gecos; + putchar(' '); + if (oflag) { + if (pn->office) + (void)printf("%-10.10s", pn->office); + else if (pn->officephone) + (void)printf("%-10.10s", " "); + if (pn->officephone) + (void)printf(" %-.15s", + prphone(pn->officephone)); + } else + (void)printf("%.*s", MAXHOSTNAMELEN, w->host); +no_gecos: + putchar('\n'); + } + } +} + +static void +stimeprint(WHERE *w) +{ + struct tm *delta; + + delta = gmtime(&w->idletime); + if (!delta->tm_yday) { + if (!delta->tm_hour) { + if (!delta->tm_min) + (void)printf(" -"); + else + (void)printf("%5d", delta->tm_min); + } else + (void)printf("%2d:%02d", + delta->tm_hour, delta->tm_min); + } else + (void)printf("%4dd", delta->tm_yday); +} diff --git a/usr.bin/finger/util.c b/usr.bin/finger/util.c new file mode 100644 index 000000000..03dd7614b --- /dev/null +++ b/usr.bin/finger/util.c @@ -0,0 +1,409 @@ +/* $NetBSD: util.c,v 1.28 2009/04/12 06:18:54 lukem Exp $ */ + +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Portions Copyright (c) 1983, 1995, 1996 Eric P. Allman + * + * This code is derived from software contributed to Berkeley by + * Tony Nardo of the Johns Hopkins University/Applied Physics Lab. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#ifndef lint +#if 0 +static char sccsid[] = "@(#)util.c 8.3 (Berkeley) 4/28/95"; +#else +__RCSID("$NetBSD: util.c,v 1.28 2009/04/12 06:18:54 lukem Exp $"); +#endif +#endif /* not lint */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "utmpentry.h" + +#include "finger.h" +#include "extern.h" + +static void find_idle_and_ttywrite(WHERE *); +static void userinfo(PERSON *, struct passwd *); +static WHERE *walloc(PERSON *); + +int +match(struct passwd *pw, char *user) +{ + char *p; + char *bp, name[1024]; + + if (!strcasecmp(pw->pw_name, user)) + return(1); + + (void)strlcpy(bp = tbuf, pw->pw_gecos, sizeof(tbuf)); + + /* Ampersands get replaced by the login name. */ + if (!(p = strsep(&bp, ","))) + return(0); + + expandusername(p, pw->pw_name, name, sizeof(name)); + bp = name; + while ((p = strsep(&bp, "\t "))) + if (!strcasecmp(p, user)) + return(1); + return(0); +} + +/* inspired by usr.sbin/sendmail/util.c::buildfname */ +void +expandusername(const char *gecos, const char *login, char *buf, int buflen) +{ + const char *p; + char *bp; + + /* why do we skip asterisks!?!? */ + if (*gecos == '*') + gecos++; + bp = buf; + + /* copy gecos, interpolating & to be full name */ + for (p = gecos; *p != '\0'; p++) { + if (bp >= &buf[buflen - 1]) { + /* buffer overflow - just use login name */ + snprintf(buf, buflen, "%s", login); + buf[buflen - 1] = '\0'; + return; + } + if (*p == '&') { + /* interpolate full name */ + snprintf(bp, buflen - (bp - buf), "%s", login); + *bp = toupper((unsigned char)*bp); + bp += strlen(bp); + } + else + *bp++ = *p; + } + *bp = '\0'; +} + +void +enter_lastlog(PERSON *pn) +{ + WHERE *w; + static int opened, fd; + struct lastlog ll; + char doit = 0; + + /* some systems may not maintain lastlog, don't report errors. */ + if (!opened) { + fd = open(_PATH_LASTLOG, O_RDONLY, 0); + opened = 1; + } + if (fd == -1 || + lseek(fd, (off_t)pn->uid * sizeof(ll), SEEK_SET) != + (off_t)pn->uid * (off_t)sizeof(ll) || + read(fd, (char *)&ll, sizeof(ll)) != sizeof(ll)) { + /* as if never logged in */ + ll.ll_line[0] = ll.ll_host[0] = '\0'; + ll.ll_time = 0; + } + if ((w = pn->whead) == NULL) + doit = 1; + else if (ll.ll_time != 0) { + /* if last login is earlier than some current login */ + for (; !doit && w != NULL; w = w->next) + if (w->info == LOGGEDIN && w->loginat < ll.ll_time) + doit = 1; + /* + * and if it's not any of the current logins + * can't use time comparison because there may be a small + * discrepency since login calls time() twice + */ + for (w = pn->whead; doit && w != NULL; w = w->next) + if (w->info == LOGGEDIN && + strncmp(w->tty, ll.ll_line, UT_LINESIZE) == 0) + doit = 0; + } + if (doit) { + w = walloc(pn); + w->info = LASTLOG; + if ((w->tty = malloc(UT_LINESIZE + 1)) == NULL) + err(1, NULL); + memcpy(w->tty, ll.ll_line, UT_LINESIZE); + w->tty[UT_LINESIZE] = '\0'; + if ((w->host = malloc(UT_HOSTSIZE + 1)) == NULL) + err(1, NULL); + memcpy(w->host, ll.ll_host, UT_HOSTSIZE); + w->host[UT_HOSTSIZE] = '\0'; + w->loginat = ll.ll_time; + } +} + +void +enter_where(struct utmpentry *ep, PERSON *pn) +{ + WHERE *w = walloc(pn); + + w->info = LOGGEDIN; + w->tty = ep->line; + w->host = ep->host; + w->loginat = (time_t)ep->tv.tv_sec; + find_idle_and_ttywrite(w); +} + +PERSON * +enter_person(struct passwd *pw) +{ + DBT data, key; + PERSON *pn; + + if (db == NULL && + (db = dbopen(NULL, O_RDWR, 0, DB_BTREE, NULL)) == NULL) + err(1, NULL); + + key.data = (char *)pw->pw_name; + key.size = strlen(pw->pw_name); + + switch ((*db->get)(db, &key, &data, 0)) { + case 0: + memmove(&pn, data.data, sizeof pn); + return (pn); + default: + case -1: + err(1, "db get"); + /* NOTREACHED */ + case 1: + ++entries; + pn = palloc(); + userinfo(pn, pw); + pn->whead = NULL; + + data.size = sizeof(PERSON *); + data.data = &pn; + if ((*db->put)(db, &key, &data, 0)) + err(1, "db put"); + return (pn); + } +} + +PERSON * +find_person(char *name) +{ + DBT data, key; + PERSON *p; + + if (!db) + return(NULL); + + key.data = name; + key.size = strlen(name); + + if ((*db->get)(db, &key, &data, 0)) + return (NULL); + memmove(&p, data.data, sizeof p); + return (p); +} + +PERSON * +palloc(void) +{ + PERSON *p; + + if ((p = malloc((u_int) sizeof(PERSON))) == NULL) + err(1, NULL); + return(p); +} + +static WHERE * +walloc(PERSON *pn) +{ + WHERE *w; + + if ((w = malloc((u_int) sizeof(WHERE))) == NULL) + err(1, NULL); + if (pn->whead == NULL) + pn->whead = pn->wtail = w; + else { + pn->wtail->next = w; + pn->wtail = w; + } + w->next = NULL; + return(w); +} + +char * +prphone(char *num) +{ + char *p; + int len; + static char pbuf[15]; + + /* don't touch anything if the user has their own formatting */ + for (p = num; *p; ++p) + if (!isdigit((unsigned char)*p)) + return(num); + len = p - num; + p = pbuf; + switch(len) { + case 11: /* +0-123-456-7890 */ + *p++ = '+'; + *p++ = *num++; + *p++ = '-'; + /* FALLTHROUGH */ + case 10: /* 012-345-6789 */ + *p++ = *num++; + *p++ = *num++; + *p++ = *num++; + *p++ = '-'; + /* FALLTHROUGH */ + case 7: /* 012-3456 */ + *p++ = *num++; + *p++ = *num++; + *p++ = *num++; + break; + case 5: /* x0-1234 */ + case 4: /* x1234 */ + *p++ = 'x'; + *p++ = *num++; + break; + default: + return(num); + } + if (len != 4) { + *p++ = '-'; + *p++ = *num++; + } + *p++ = *num++; + *p++ = *num++; + *p++ = *num++; + *p = '\0'; + return(pbuf); +} + +static void +find_idle_and_ttywrite(WHERE *w) +{ + struct stat sb; + + (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_DEV, w->tty); + if (stat(tbuf, &sb) < 0) { + warn("%s", tbuf); + return; + } + w->idletime = now < sb.st_atime ? 0 : now - sb.st_atime; + +#define TALKABLE 0220 /* tty is writable if 220 mode */ + w->writable = ((sb.st_mode & TALKABLE) == TALKABLE); +} + +static void +userinfo(PERSON *pn, struct passwd *pw) +{ + char *p; + char *bp, name[1024]; + struct stat sb; + + pn->realname = pn->office = pn->officephone = pn->homephone = NULL; + + pn->uid = pw->pw_uid; + pn->name = strdup(pw->pw_name); + pn->dir = strdup(pw->pw_dir); + pn->shell = strdup(pw->pw_shell); + + (void)strlcpy(bp = tbuf, pw->pw_gecos, sizeof(tbuf)); + + /* ampersands get replaced by the login name */ + if (!(p = strsep(&bp, ","))) + return; + expandusername(p, pw->pw_name, name, sizeof(name)); + pn->realname = strdup(name); + pn->office = ((p = strsep(&bp, ",")) && *p) ? + strdup(p) : NULL; + pn->officephone = ((p = strsep(&bp, ",")) && *p) ? + strdup(p) : NULL; + pn->homephone = ((p = strsep(&bp, ",")) && *p) ? + strdup(p) : NULL; + (void)snprintf(tbuf, sizeof(tbuf), "%s/%s", _PATH_MAILDIR, + pw->pw_name); + pn->mailrecv = -1; /* -1 == not_valid */ + if (stat(tbuf, &sb) < 0) { + if (errno != ENOENT) { + (void)fprintf(stderr, + "finger: %s: %s\n", tbuf, strerror(errno)); + return; + } + } else if (sb.st_size != 0) { + pn->mailrecv = sb.st_mtime; + pn->mailread = sb.st_atime; + } +}