113619Ssam #ifndef lint 2*18606Sedward static char sccsid[] = "@(#)finger.c 4.9 (Berkeley) 04/09/85"; 313619Ssam #endif 41014Sbill 5*18606Sedward /* 6*18606Sedward * This is a finger program. It prints out useful information about users 7*18606Sedward * by digging it up from various system files. It is not very portable 8*18606Sedward * because the most useful parts of the information (the full user name, 9*18606Sedward * office, and phone numbers) are all stored in the VAX-unused gecos field 10*18606Sedward * of /etc/passwd, which, unfortunately, other UNIXes use for other things. 111014Sbill * 12*18606Sedward * There are three output formats, all of which give login name, teletype 13*18606Sedward * line number, and login time. The short output format is reminiscent 14*18606Sedward * of finger on ITS, and gives one line of information per user containing 15*18606Sedward * in addition to the minimum basic requirements (MBR), the full name of 16*18606Sedward * the user, his idle time and office location and phone number. The 17*18606Sedward * quick style output is UNIX who-like, giving only name, teletype and 18*18606Sedward * login time. Finally, the long style output give the same information 19*18606Sedward * as the short (in more legible format), the home directory and shell 20*18606Sedward * of the user, and, if it exits, a copy of the file .plan in the users 21*18606Sedward * home directory. Finger may be called with or without a list of people 22*18606Sedward * to finger -- if no list is given, all the people currently logged in 23*18606Sedward * are fingered. 241014Sbill * 25*18606Sedward * The program is validly called by one of the following: 261014Sbill * 271014Sbill * finger {short form list of users} 281014Sbill * finger -l {long form list of users} 291014Sbill * finger -b {briefer long form list of users} 301014Sbill * finger -q {quick list of users} 311014Sbill * finger -i {quick list of users with idle times} 321014Sbill * finger namelist {long format list of specified users} 331014Sbill * finger -s namelist {short format list of specified users} 341014Sbill * finger -w namelist {narrow short format list of specified users} 351014Sbill * 36*18606Sedward * where 'namelist' is a list of users login names. 37*18606Sedward * The other options can all be given after one '-', or each can have its 38*18606Sedward * own '-'. The -f option disables the printing of headers for short and 39*18606Sedward * quick outputs. The -b option briefens long format outputs. The -p 40*18606Sedward * option turns off plans for long format outputs. 411014Sbill */ 421014Sbill 43*18606Sedward #include <sys/types.h> 44*18606Sedward #include <sys/stat.h> 45*18606Sedward #include <utmp.h> 46*18606Sedward #include <sys/signal.h> 47*18606Sedward #include <pwd.h> 48*18606Sedward #include <stdio.h> 49*18606Sedward #include <lastlog.h> 50*18606Sedward #include <ctype.h> 51*18606Sedward #include <sys/time.h> 52*18606Sedward #include <sys/socket.h> 53*18606Sedward #include <netinet/in.h> 54*18606Sedward #include <netdb.h> 551014Sbill 56*18606Sedward #define ASTERISK '*' /* ignore this in real name */ 57*18606Sedward #define COMMA ',' /* separator in pw_gecos field */ 58*18606Sedward #define COMMAND '-' /* command line flag char */ 59*18606Sedward #define CORY 'C' /* cory hall office */ 60*18606Sedward #define EVANS 'E' /* evans hall office */ 61*18606Sedward #define SAMENAME '&' /* repeat login name in real name */ 62*18606Sedward #define TALKABLE 0222 /* tty is writable if 222 mode */ 631014Sbill 64*18606Sedward struct utmp user; 65*18606Sedward #define NMAX sizeof(user.ut_name) 66*18606Sedward #define LMAX sizeof(user.ut_line) 67*18606Sedward #define HMAX sizeof(user.ut_host) 681014Sbill 69*18606Sedward struct person { /* one for each person fingered */ 70*18606Sedward char *name; /* name */ 71*18606Sedward char tty[LMAX+1]; /* null terminated tty line */ 72*18606Sedward char host[HMAX+1]; /* null terminated remote host name */ 73*18606Sedward long loginat; /* time of (last) login */ 74*18606Sedward long idletime; /* how long idle (if logged in) */ 75*18606Sedward char *realname; /* pointer to full name */ 76*18606Sedward char *office; /* pointer to office name */ 77*18606Sedward char *officephone; /* pointer to office phone no. */ 78*18606Sedward char *homephone; /* pointer to home phone no. */ 79*18606Sedward char *random; /* for any random stuff in pw_gecos */ 80*18606Sedward struct passwd *pwd; /* structure of /etc/passwd stuff */ 81*18606Sedward char loggedin; /* person is logged in */ 82*18606Sedward char writable; /* tty is writable */ 83*18606Sedward char original; /* this is not a duplicate entry */ 84*18606Sedward struct person *link; /* link to next person */ 851014Sbill }; 861014Sbill 87*18606Sedward char LASTLOG[] = "/usr/adm/lastlog"; /* last login info */ 88*18606Sedward char USERLOG[] = "/etc/utmp"; /* who is logged in */ 89*18606Sedward char PLAN[] = "/.plan"; /* what plan file is */ 90*18606Sedward char PROJ[] = "/.project"; /* what project file */ 91*18606Sedward 92*18606Sedward int unbrief = 1; /* -b option default */ 93*18606Sedward int header = 1; /* -f option default */ 94*18606Sedward int hack = 1; /* -h option default */ 95*18606Sedward int idle = 0; /* -i option default */ 96*18606Sedward int large = 0; /* -l option default */ 97*18606Sedward int match = 1; /* -m option default */ 98*18606Sedward int plan = 1; /* -p option default */ 99*18606Sedward int unquick = 1; /* -q option default */ 100*18606Sedward int small = 0; /* -s option default */ 101*18606Sedward int wide = 1; /* -w option default */ 1021014Sbill 103*18606Sedward int unshort; 104*18606Sedward int lf; /* LASTLOG file descriptor */ 105*18606Sedward struct person *person1; /* list of people */ 106*18606Sedward long tloc; /* current time */ 1071014Sbill 108*18606Sedward struct passwd *pwdcopy(); 109*18606Sedward char *strcpy(); 110*18606Sedward char *malloc(); 111*18606Sedward char *ctime(); 1121014Sbill 113*18606Sedward main(argc, argv) 114*18606Sedward int argc; 115*18606Sedward register char **argv; 116*18606Sedward { 117*18606Sedward FILE *fp; 118*18606Sedward register char *s; 1191014Sbill 120*18606Sedward /* parse command line for (optional) arguments */ 121*18606Sedward while (*++argv && **argv == COMMAND) 122*18606Sedward for (s = *argv + 1; *s; s++) 123*18606Sedward switch (*s) { 124*18606Sedward case 'b': 125*18606Sedward unbrief = 0; 126*18606Sedward break; 127*18606Sedward case 'f': 128*18606Sedward header = 0; 129*18606Sedward break; 130*18606Sedward case 'h': 131*18606Sedward hack = 0; 132*18606Sedward break; 133*18606Sedward case 'i': 134*18606Sedward idle = 1; 135*18606Sedward unquick = 0; 136*18606Sedward break; 137*18606Sedward case 'l': 138*18606Sedward large = 1; 139*18606Sedward break; 140*18606Sedward case 'm': 141*18606Sedward match = 0; 142*18606Sedward break; 143*18606Sedward case 'p': 144*18606Sedward plan = 0; 145*18606Sedward break; 146*18606Sedward case 'q': 147*18606Sedward unquick = 0; 148*18606Sedward break; 149*18606Sedward case 's': 150*18606Sedward small = 1; 151*18606Sedward break; 152*18606Sedward case 'w': 153*18606Sedward wide = 0; 154*18606Sedward break; 155*18606Sedward default: 156*18606Sedward fprintf(stderr, "Usage: finger [-bfhilmpqsw] [login1 [login2 ...] ]\n"); 157*18606Sedward exit(1); 158*18606Sedward } 159*18606Sedward if (unquick || idle) 160*18606Sedward time(&tloc); 161*18606Sedward /* 162*18606Sedward * *argv == 0 means no names given 163*18606Sedward */ 164*18606Sedward if (*argv == 0) 165*18606Sedward doall(); 166*18606Sedward else 167*18606Sedward donames(argv); 168*18606Sedward print(); 169*18606Sedward exit(0); 170*18606Sedward } 1711014Sbill 172*18606Sedward doall() 1731014Sbill { 174*18606Sedward register struct person *p; 175*18606Sedward register struct passwd *pw; 176*18606Sedward int uf; 177*18606Sedward char name[NMAX + 1]; 1781014Sbill 179*18606Sedward unshort = large; 180*18606Sedward if ((uf = open(USERLOG, 0)) < 0) { 181*18606Sedward fprintf(stderr, "finger: error opening %s\n", USERLOG); 182*18606Sedward exit(2); 1831014Sbill } 184*18606Sedward if (unquick) { 185*18606Sedward extern _pw_stayopen; 1861014Sbill 1871014Sbill setpwent(); 188*18606Sedward _pw_stayopen = 1; 1891014Sbill fwopen(); 190*18606Sedward } 191*18606Sedward while (read(uf, (char *)&user, sizeof user) == sizeof user) { 192*18606Sedward if (user.ut_name[0] == 0) 193*18606Sedward continue; 194*18606Sedward if (person1 == 0) 195*18606Sedward p = person1 = (struct person *) malloc(sizeof *p); 196*18606Sedward else { 197*18606Sedward p->link = (struct person *) malloc(sizeof *p); 1981014Sbill p = p->link; 1991014Sbill } 200*18606Sedward bcopy(user.ut_name, name, NMAX); 201*18606Sedward name[NMAX] = 0; 202*18606Sedward bcopy(user.ut_line, p->tty, LMAX); 203*18606Sedward p->tty[LMAX] = 0; 204*18606Sedward bcopy(user.ut_host, p->host, HMAX); 205*18606Sedward p->host[HMAX] = 0; 206*18606Sedward p->loginat = user.ut_time; 207*18606Sedward p->pwd = 0; 208*18606Sedward p->loggedin = 1; 209*18606Sedward if (unquick && (pw = getpwnam(name))) { 210*18606Sedward p->pwd = pwdcopy(pw); 211*18606Sedward decode(p); 212*18606Sedward p->name = p->pwd->pw_name; 213*18606Sedward } else 214*18606Sedward p->name = strcpy(malloc(strlen(name) + 1), name); 215*18606Sedward } 216*18606Sedward if (unquick) { 2171014Sbill fwclose(); 2181014Sbill endpwent(); 2191014Sbill } 220*18606Sedward close(uf); 221*18606Sedward if (person1 == 0) { 222*18606Sedward printf("No one logged on\n"); 223*18606Sedward exit(0); 224*18606Sedward } 225*18606Sedward p->link = 0; 226*18606Sedward } 2271014Sbill 228*18606Sedward donames(argv) 229*18606Sedward char **argv; 230*18606Sedward { 231*18606Sedward register struct person *p; 232*18606Sedward register struct passwd *pw; 233*18606Sedward int uf; 2341014Sbill 235*18606Sedward /* 236*18606Sedward * get names from command line and check to see if they're 237*18606Sedward * logged in 238*18606Sedward */ 239*18606Sedward unshort = !small; 240*18606Sedward for (; *argv != 0; argv++) { 241*18606Sedward if (netfinger(*argv)) 242*18606Sedward continue; 243*18606Sedward if (person1 == 0) 244*18606Sedward p = person1 = (struct person *) malloc(sizeof *p); 245*18606Sedward else { 246*18606Sedward p->link = (struct person *) malloc(sizeof *p); 247*18606Sedward p = p->link; 24816469Ssam } 249*18606Sedward p->name = *argv; 2501014Sbill p->loggedin = 0; 251*18606Sedward p->original = 1; 252*18606Sedward p->pwd = 0; 253*18606Sedward } 254*18606Sedward p->link = 0; 255*18606Sedward /* 256*18606Sedward * if we are doing it, read /etc/passwd for the useful info 257*18606Sedward */ 258*18606Sedward if (unquick) { 259*18606Sedward setpwent(); 260*18606Sedward if (!match) { 261*18606Sedward extern _pw_stayopen; 2621014Sbill 263*18606Sedward _pw_stayopen = 1; 264*18606Sedward for (p = person1; p != 0; p = p->link) 265*18606Sedward if (pw = getpwnam(p->name)) 266*18606Sedward p->pwd = pwdcopy(pw); 267*18606Sedward } else while ((pw = getpwent()) != 0) { 268*18606Sedward for (p = person1; p != 0; p = p->link) { 269*18606Sedward if (!p->original) 270*18606Sedward continue; 271*18606Sedward if (strcmp(p->name, pw->pw_name) != 0 && 272*18606Sedward !matchcmp(pw->pw_gecos, pw->pw_name, p->name)) 273*18606Sedward continue; 274*18606Sedward if (p->pwd == 0) 275*18606Sedward p->pwd = pwdcopy(pw); 276*18606Sedward else { 277*18606Sedward struct person *new; 278*18606Sedward /* 279*18606Sedward * handle multiple login names, insert 280*18606Sedward * new "duplicate" entry behind 281*18606Sedward */ 282*18606Sedward new = (struct person *) 283*18606Sedward malloc(sizeof *new); 284*18606Sedward new->pwd = pwdcopy(pw); 285*18606Sedward new->name = p->name; 286*18606Sedward new->original = 1; 287*18606Sedward new->loggedin = 0; 288*18606Sedward new->link = p->link; 289*18606Sedward p->original = 0; 290*18606Sedward p->link = new; 291*18606Sedward p = new; 292*18606Sedward } 2931014Sbill } 2941014Sbill } 2951014Sbill endpwent(); 296*18606Sedward } 297*18606Sedward /* Now get login information */ 298*18606Sedward if ((uf = open(USERLOG, 0)) < 0) { 299*18606Sedward fprintf(stderr, "finger: error opening %s\n", USERLOG); 300*18606Sedward exit(2); 301*18606Sedward } 302*18606Sedward while (read(uf, (char *)&user, sizeof user) == sizeof user) { 303*18606Sedward if (*user.ut_name == 0) 304*18606Sedward continue; 305*18606Sedward for (p = person1; p != 0; p = p->link) { 306*18606Sedward if (p->loggedin == 2) 307*18606Sedward continue; 308*18606Sedward if (strncmp(p->pwd ? p->pwd->pw_name : p->name, 309*18606Sedward user.ut_name, NMAX) != 0) 310*18606Sedward continue; 311*18606Sedward if (p->loggedin == 0) { 312*18606Sedward bcopy(user.ut_line, p->tty, LMAX); 313*18606Sedward p->tty[LMAX] = 0; 314*18606Sedward bcopy(user.ut_host, p->host, HMAX); 315*18606Sedward p->host[HMAX] = 0; 316*18606Sedward p->loginat = user.ut_time; 317*18606Sedward p->loggedin = 1; 318*18606Sedward } else { /* p->loggedin == 1 */ 319*18606Sedward struct person *new; 320*18606Sedward new = (struct person *) malloc(sizeof *new); 321*18606Sedward new->name = p->name; 322*18606Sedward bcopy(user.ut_line, new->tty, LMAX); 323*18606Sedward new->tty[LMAX] = 0; 324*18606Sedward bcopy(user.ut_host, new->host, HMAX); 325*18606Sedward new->host[HMAX] = 0; 326*18606Sedward new->loginat = user.ut_time; 327*18606Sedward new->pwd = p->pwd; 328*18606Sedward new->loggedin = 1; 329*18606Sedward new->original = 0; 330*18606Sedward new->link = p->link; 331*18606Sedward p->loggedin = 2; 332*18606Sedward p->link = new; 333*18606Sedward p = new; 3341014Sbill } 3351014Sbill } 336*18606Sedward } 337*18606Sedward close(uf); 338*18606Sedward if (unquick) { 3391014Sbill fwopen(); 340*18606Sedward for (p = person1; p != 0; p = p->link) 341*18606Sedward decode(p); 3421014Sbill fwclose(); 3431014Sbill } 344*18606Sedward } 3451014Sbill 346*18606Sedward print() 347*18606Sedward { 348*18606Sedward register FILE *fp; 349*18606Sedward register struct person *p; 350*18606Sedward register char *s; 351*18606Sedward register c; 3521014Sbill 353*18606Sedward /* 354*18606Sedward * print out what we got 355*18606Sedward */ 356*18606Sedward if (header) { 357*18606Sedward if (unquick) { 358*18606Sedward if (!unshort) 359*18606Sedward if (wide) 360*18606Sedward printf("Login Name TTY Idle When Office\n"); 361*18606Sedward else 362*18606Sedward printf("Login TTY Idle When Office\n"); 363*18606Sedward } else { 364*18606Sedward printf("Login TTY When"); 365*18606Sedward if (idle) 366*18606Sedward printf(" Idle"); 367*18606Sedward putchar('\n'); 3681014Sbill } 369*18606Sedward } 370*18606Sedward for (p = person1; p != 0; p = p->link) { 371*18606Sedward if (!unquick) { 372*18606Sedward quickprint(p); 373*18606Sedward continue; 3741014Sbill } 375*18606Sedward if (!unshort) { 376*18606Sedward shortprint(p); 377*18606Sedward continue; 378*18606Sedward } 379*18606Sedward personprint(p); 380*18606Sedward if (p->pwd != 0) { 381*18606Sedward if (hack) { 382*18606Sedward s = malloc(strlen(p->pwd->pw_dir) + 383*18606Sedward sizeof PROJ); 384*18606Sedward strcpy(s, p->pwd->pw_dir); 385*18606Sedward strcat(s, PROJ); 386*18606Sedward if ((fp = fopen(s, "r")) != 0) { 387*18606Sedward printf("Project: "); 388*18606Sedward while ((c = getc(fp)) != EOF) { 389*18606Sedward if (c == '\n') 390*18606Sedward break; 391*18606Sedward putchar(c); 392*18606Sedward } 393*18606Sedward fclose(fp); 394*18606Sedward putchar('\n'); 3951014Sbill } 396*18606Sedward free(s); 3971014Sbill } 398*18606Sedward if (plan) { 399*18606Sedward s = malloc(strlen(p->pwd->pw_dir) + 400*18606Sedward sizeof PLAN); 401*18606Sedward strcpy(s, p->pwd->pw_dir); 402*18606Sedward strcat(s, PLAN); 403*18606Sedward if ((fp = fopen(s, "r")) == 0) 404*18606Sedward printf("No Plan.\n"); 405*18606Sedward else { 406*18606Sedward printf("Plan:\n"); 407*18606Sedward while ((c = getc(fp)) != EOF) 408*18606Sedward putchar(c); 409*18606Sedward fclose(fp); 4101014Sbill } 411*18606Sedward free(s); 4121014Sbill } 4131014Sbill } 414*18606Sedward if (p->link != 0) 415*18606Sedward putchar('\n'); 416*18606Sedward } 4171014Sbill } 4181014Sbill 419*18606Sedward /* 420*18606Sedward * Duplicate a pwd entry. 421*18606Sedward * Note: Only the useful things (what the program currently uses) are copied. 4221014Sbill */ 423*18606Sedward struct passwd * 424*18606Sedward pwdcopy(pfrom) 425*18606Sedward register struct passwd *pfrom; 426*18606Sedward { 427*18606Sedward register struct passwd *pto; 4281014Sbill 429*18606Sedward pto = (struct passwd *) malloc(sizeof *pto); 430*18606Sedward #define savestr(s) strcpy(malloc(strlen(s) + 1), s) 431*18606Sedward pto->pw_name = savestr(pfrom->pw_name); 4321014Sbill pto->pw_uid = pfrom->pw_uid; 433*18606Sedward pto->pw_gecos = savestr(pfrom->pw_gecos); 434*18606Sedward pto->pw_dir = savestr(pfrom->pw_dir); 435*18606Sedward pto->pw_shell = savestr(pfrom->pw_shell); 436*18606Sedward #undef savestr 437*18606Sedward return pto; 4381014Sbill } 4391014Sbill 440*18606Sedward /* 441*18606Sedward * print out information on quick format giving just name, tty, login time 442*18606Sedward * and idle time if idle is set. 4431014Sbill */ 444*18606Sedward quickprint(pers) 445*18606Sedward register struct person *pers; 4461014Sbill { 447*18606Sedward printf("%-*.*s ", NMAX, NMAX, pers->name); 448*18606Sedward if (pers->loggedin) { 449*18606Sedward if (idle) { 450*18606Sedward findidle(pers); 451*18606Sedward printf("%c%-*s %-16.16s", pers->writable ? ' ' : '*', 452*18606Sedward LMAX, pers->tty, ctime(&pers->loginat)); 453*18606Sedward ltimeprint(" ", &pers->idletime, ""); 454*18606Sedward } else 455*18606Sedward printf(" %-*s %-16.16s", LMAX, 456*18606Sedward pers->tty, ctime(&pers->loginat)); 457*18606Sedward putchar('\n'); 458*18606Sedward } else 459*18606Sedward printf(" Not Logged In\n"); 4601014Sbill } 4611014Sbill 462*18606Sedward /* 463*18606Sedward * print out information in short format, giving login name, full name, 464*18606Sedward * tty, idle time, login time, office location and phone. 4651014Sbill */ 466*18606Sedward shortprint(pers) 467*18606Sedward register struct person *pers; 4681014Sbill { 469*18606Sedward char *p; 470*18606Sedward char dialup; 4711014Sbill 472*18606Sedward if (pers->pwd == 0) { 473*18606Sedward printf("%-15s ???\n", pers->name); 474*18606Sedward return; 4751014Sbill } 476*18606Sedward printf("%-*s", NMAX, pers->pwd->pw_name); 4771014Sbill dialup = 0; 478*18606Sedward if (wide) { 479*18606Sedward if (pers->realname) 480*18606Sedward printf(" %-20.20s", pers->realname); 481*18606Sedward else 482*18606Sedward printf(" ??? "); 4831014Sbill } 484*18606Sedward putchar(' '); 485*18606Sedward if (pers->loggedin && !pers->writable) 486*18606Sedward putchar('*'); 487*18606Sedward else 488*18606Sedward putchar(' '); 489*18606Sedward if (*pers->tty) { 490*18606Sedward if (pers->tty[0] == 't' && pers->tty[1] == 't' && 491*18606Sedward pers->tty[2] == 'y') { 492*18606Sedward if (pers->tty[3] == 'd' && pers->loggedin) 493*18606Sedward dialup = 1; 494*18606Sedward printf("%-2.2s ", pers->tty + 3); 495*18606Sedward } else 496*18606Sedward printf("%-2.2s ", pers->tty); 497*18606Sedward } else 498*18606Sedward printf(" "); 499*18606Sedward p = ctime(&pers->loginat); 500*18606Sedward if (pers->loggedin) { 501*18606Sedward stimeprint(&pers->idletime); 502*18606Sedward printf(" %3.3s %-5.5s ", p, p + 11); 503*18606Sedward } else if (pers->loginat == 0) 504*18606Sedward printf(" < . . . . >"); 5058842Smckusick else if (tloc - pers->loginat >= 180 * 24 * 60 * 60) 506*18606Sedward printf(" <%-6.6s, %-4.4s>", p + 4, p + 20); 5078842Smckusick else 508*18606Sedward printf(" <%-12.12s>", p + 4); 509*18606Sedward if (dialup && pers->homephone) 510*18606Sedward printf(" %20s", pers->homephone); 511*18606Sedward else { 512*18606Sedward if (pers->office) 513*18606Sedward printf(" %-11.11s", pers->office); 514*18606Sedward else if (pers->officephone || pers->homephone) 515*18606Sedward printf(" "); 516*18606Sedward if (pers->officephone) 517*18606Sedward printf(" %s", pers->officephone); 518*18606Sedward else if (pers->homephone) 519*18606Sedward printf(" %s", pers->homephone); 5201014Sbill } 521*18606Sedward putchar('\n'); 5221014Sbill } 5231014Sbill 524*18606Sedward /* 525*18606Sedward * print out a person in long format giving all possible information. 526*18606Sedward * directory and shell are inhibited if unbrief is clear. 5271014Sbill */ 528*18606Sedward personprint(pers) 529*18606Sedward register struct person *pers; 5301014Sbill { 531*18606Sedward if (pers->pwd == 0) { 532*18606Sedward printf("Login name: %-10s\t\t\tIn real life: ???\n", 533*18606Sedward pers->name); 534*18606Sedward return; 5351014Sbill } 536*18606Sedward printf("Login name: %-10s", pers->pwd->pw_name); 537*18606Sedward if (pers->loggedin && !pers->writable) 538*18606Sedward printf(" (messages off) "); 539*18606Sedward else 540*18606Sedward printf(" "); 541*18606Sedward if (pers->realname) 542*18606Sedward printf("In real life: %s", pers->realname); 543*18606Sedward if (pers->office) { 544*18606Sedward printf("\nOffice: %-.11s", pers->office); 545*18606Sedward if (pers->officephone) { 546*18606Sedward printf(", %s", pers->officephone); 547*18606Sedward if (pers->homephone) 548*18606Sedward printf("\t\tHome phone: %s", pers->homephone); 549*18606Sedward else if (pers->random) 550*18606Sedward printf("\t\t%s", pers->random); 551*18606Sedward } else 552*18606Sedward if (pers->homephone) 553*18606Sedward printf("\t\t\tHome phone: %s", pers->homephone); 554*18606Sedward else if (pers->random) 555*18606Sedward printf("\t\t\t%s", pers->random); 556*18606Sedward } else if (pers->officephone) { 557*18606Sedward printf("\nPhone: %s", pers->officephone); 558*18606Sedward if (pers->homephone) 559*18606Sedward printf(", %s", pers->homephone); 560*18606Sedward if (pers->random) 561*18606Sedward printf(", %s", pers->random); 562*18606Sedward } else if (pers->homephone) { 563*18606Sedward printf("\nPhone: %s", pers->homephone); 564*18606Sedward if (pers->random) 565*18606Sedward printf(", %s", pers->random); 566*18606Sedward } else if (pers->random) 567*18606Sedward printf("\n%s", pers->random); 568*18606Sedward if (unbrief) { 569*18606Sedward printf("\nDirectory: %-25s", pers->pwd->pw_dir); 570*18606Sedward if (*pers->pwd->pw_shell) 571*18606Sedward printf("\tShell: %-s", pers->pwd->pw_shell); 5721014Sbill } 573*18606Sedward if (pers->loggedin) { 574*18606Sedward register char *ep = ctime(&pers->loginat); 575*18606Sedward if (*pers->host) { 576*18606Sedward printf("\nOn since %15.15s on %s from %s", 577*18606Sedward &ep[4], pers->tty, pers->host); 578*18606Sedward ltimeprint("\n", &pers->idletime, " Idle Time"); 579*18606Sedward } else { 580*18606Sedward printf("\nOn since %15.15s on %-*s", 581*18606Sedward &ep[4], LMAX, pers->tty); 582*18606Sedward ltimeprint("\t", &pers->idletime, " Idle Time"); 5831014Sbill } 584*18606Sedward } else if (pers->loginat == 0) 585*18606Sedward printf("\nNever logged in."); 5868842Smckusick else if (tloc - pers->loginat > 180 * 24 * 60 * 60) { 587*18606Sedward register char *ep = ctime(&pers->loginat); 588*18606Sedward printf("\nLast login %10.10s, %4.4s on %s", 589*18606Sedward ep, ep+20, pers->tty); 590*18606Sedward if (*pers->host) 591*18606Sedward printf(" from %s", pers->host); 592*18606Sedward } else { 593*18606Sedward register char *ep = ctime(&pers->loginat); 594*18606Sedward printf("\nLast login %16.16s on %s", ep, pers->tty); 595*18606Sedward if (*pers->host) 596*18606Sedward printf(" from %s", pers->host); 5978842Smckusick } 598*18606Sedward putchar('\n'); 5991014Sbill } 6001014Sbill 6011014Sbill /* 6021014Sbill * very hacky section of code to format phone numbers. filled with 6031014Sbill * magic constants like 4, 7 and 10. 6041014Sbill */ 605*18606Sedward char * 606*18606Sedward phone(s, len, alldigits) 607*18606Sedward register char *s; 608*18606Sedward int len; 609*18606Sedward char alldigits; 6101014Sbill { 611*18606Sedward char fonebuf[15]; 612*18606Sedward register char *p = fonebuf; 613*18606Sedward register i; 6141014Sbill 615*18606Sedward if (!alldigits) 616*18606Sedward return (strcpy(malloc(len + 1), s)); 617*18606Sedward switch (len) { 618*18606Sedward case 4: 619*18606Sedward *p++ = ' '; 620*18606Sedward *p++ = 'x'; 621*18606Sedward *p++ = '2'; 622*18606Sedward *p++ = '-'; 623*18606Sedward for (i = 0; i < 4; i++) 624*18606Sedward *p++ = *s++; 6251014Sbill break; 626*18606Sedward case 7: 627*18606Sedward for (i = 0; i < 3; i++) 628*18606Sedward *p++ = *s++; 629*18606Sedward *p++ = '-'; 630*18606Sedward for (i = 0; i < 4; i++) 631*18606Sedward *p++ = *s++; 6321014Sbill break; 633*18606Sedward case 10: 634*18606Sedward for (i = 0; i < 3; i++) 635*18606Sedward *p++ = *s++; 636*18606Sedward *p++ = '-'; 637*18606Sedward for (i = 0; i < 3; i++) 638*18606Sedward *p++ = *s++; 639*18606Sedward *p++ = '-'; 640*18606Sedward for (i = 0; i < 4; i++) 641*18606Sedward *p++ = *s++; 6421014Sbill break; 643*18606Sedward case 0: 644*18606Sedward return 0; 645*18606Sedward default: 646*18606Sedward return (strcpy(malloc(len + 1), s)); 6471014Sbill } 648*18606Sedward *p++ = 0; 649*18606Sedward return (strcpy(malloc(p - fonebuf), fonebuf)); 6501014Sbill } 6511014Sbill 652*18606Sedward /* 653*18606Sedward * decode the information in the gecos field of /etc/passwd 6541014Sbill */ 655*18606Sedward decode(pers) 656*18606Sedward register struct person *pers; 6571014Sbill { 658*18606Sedward char buffer[256]; 659*18606Sedward register char *bp, *gp, *lp; 660*18606Sedward int alldigits; 661*18606Sedward int hasspace; 662*18606Sedward int len; 6631014Sbill 664*18606Sedward pers->realname = 0; 665*18606Sedward pers->office = 0; 666*18606Sedward pers->officephone = 0; 667*18606Sedward pers->homephone = 0; 668*18606Sedward pers->random = 0; 669*18606Sedward if (pers->pwd == 0) 670*18606Sedward return; 671*18606Sedward gp = pers->pwd->pw_gecos; 672*18606Sedward bp = buffer; 673*18606Sedward if (*gp == ASTERISK) 6741014Sbill gp++; 675*18606Sedward while (*gp && *gp != COMMA) /* name */ 676*18606Sedward if (*gp == SAMENAME) { 677*18606Sedward lp = pers->pwd->pw_name; 678*18606Sedward if (islower(*lp)) 679*18606Sedward *bp++ = toupper(*lp++); 680*18606Sedward while (*bp++ = *lp++) 681*18606Sedward ; 682*18606Sedward bp--; 683*18606Sedward gp++; 684*18606Sedward } else 685*18606Sedward *bp++ = *gp++; 686*18606Sedward *bp++ = 0; 687*18606Sedward if ((len = bp - buffer) > 1) 688*18606Sedward pers->realname = strcpy(malloc(len), buffer); 689*18606Sedward if (*gp == COMMA) { /* office */ 690*18606Sedward gp++; 691*18606Sedward hasspace = 0; 692*18606Sedward bp = buffer; 693*18606Sedward while (*gp && *gp != COMMA) { 694*18606Sedward *bp = *gp++; 695*18606Sedward if (*bp == ' ') 696*18606Sedward hasspace = 1; 697*18606Sedward /* leave 5 for Cory and Evans expansion */ 698*18606Sedward if (bp < buffer + sizeof buffer - 6) 699*18606Sedward bp++; 7001014Sbill } 701*18606Sedward *bp = 0; 702*18606Sedward len = bp - buffer; 703*18606Sedward bp--; /* point to last character */ 704*18606Sedward if (hasspace || len == 0) 705*18606Sedward len++; 706*18606Sedward else if (*bp == CORY) { 707*18606Sedward strcpy(bp, " Cory"); 708*18606Sedward len += 5; 709*18606Sedward } else if (*bp == EVANS) { 710*18606Sedward strcpy(bp, " Evans"); 711*18606Sedward len += 6; 712*18606Sedward } else 713*18606Sedward len++; 714*18606Sedward if (len > 1) 715*18606Sedward pers->office = strcpy(malloc(len), buffer); 716*18606Sedward } 717*18606Sedward if (*gp == COMMA) { /* office phone */ 718*18606Sedward gp++; 719*18606Sedward bp = buffer; 720*18606Sedward alldigits = 1; 721*18606Sedward while (*gp && *gp != COMMA) { 722*18606Sedward *bp = *gp++; 723*18606Sedward if (!isdigit(*bp)) 724*18606Sedward alldigits = 0; 725*18606Sedward if (bp < buffer + sizeof buffer - 1) 726*18606Sedward bp++; 7271014Sbill } 728*18606Sedward *bp = 0; 729*18606Sedward pers->officephone = phone(buffer, bp - buffer, alldigits); 730*18606Sedward } 731*18606Sedward if (*gp == COMMA) { /* home phone */ 7321014Sbill gp++; 733*18606Sedward bp = buffer; 7341014Sbill alldigits = 1; 735*18606Sedward while (*gp && *gp != COMMA) { 7361014Sbill *bp = *gp++; 737*18606Sedward if (!isdigit(*bp)) 738*18606Sedward alldigits = 0; 739*18606Sedward if (bp < buffer + sizeof buffer - 1) 7401014Sbill bp++; 7411014Sbill } 742*18606Sedward *bp = 0; 743*18606Sedward pers->homephone = phone(buffer, bp - buffer, alldigits); 7441014Sbill } 745*18606Sedward if (pers->loggedin) 746*18606Sedward findidle(pers); 747*18606Sedward else 748*18606Sedward findwhen(pers); 7491014Sbill } 7501014Sbill 751*18606Sedward /* 752*18606Sedward * find the last log in of a user by checking the LASTLOG file. 753*18606Sedward * the entry is indexed by the uid, so this can only be done if 754*18606Sedward * the uid is known (which it isn't in quick mode) 7551014Sbill */ 7561014Sbill 7571014Sbill fwopen() 7581014Sbill { 759*18606Sedward if ((lf = open(LASTLOG, 0)) < 0) 760*18606Sedward fprintf(stderr, "finger: %s open error\n", LASTLOG); 7611014Sbill } 7621014Sbill 763*18606Sedward findwhen(pers) 764*18606Sedward register struct person *pers; 7651014Sbill { 766*18606Sedward struct lastlog ll; 767*18606Sedward int i; 7681014Sbill 769*18606Sedward if (lf >= 0) { 770*18606Sedward lseek(lf, (long)pers->pwd->pw_uid * sizeof ll, 0); 771*18606Sedward if ((i = read(lf, (char *)&ll, sizeof ll)) == sizeof ll) { 772*18606Sedward bcopy(ll.ll_line, pers->tty, LMAX); 773*18606Sedward pers->tty[LMAX] = 0; 774*18606Sedward bcopy(ll.ll_host, pers->host, HMAX); 775*18606Sedward pers->host[HMAX] = 0; 776*18606Sedward pers->loginat = ll.ll_time; 777*18606Sedward } else { 778*18606Sedward if (i != 0) 779*18606Sedward fprintf(stderr, "finger: %s read error\n", 780*18606Sedward LASTLOG); 781*18606Sedward pers->tty[0] = 0; 782*18606Sedward pers->host[0] = 0; 783*18606Sedward pers->loginat = 0L; 784*18606Sedward } 785*18606Sedward } else { 786*18606Sedward pers->tty[0] = 0; 787*18606Sedward pers->host[0] = 0; 7881014Sbill pers->loginat = 0L; 7891014Sbill } 7901014Sbill } 7911014Sbill 7921014Sbill fwclose() 7931014Sbill { 794*18606Sedward if (lf >= 0) 795*18606Sedward close(lf); 7961014Sbill } 7971014Sbill 798*18606Sedward /* 799*18606Sedward * find the idle time of a user by doing a stat on /dev/tty??, 800*18606Sedward * where tty?? has been gotten from USERLOG, supposedly. 8011014Sbill */ 802*18606Sedward findidle(pers) 803*18606Sedward register struct person *pers; 8041014Sbill { 805*18606Sedward struct stat ttystatus; 806*18606Sedward static char buffer[20] = "/dev/"; 807*18606Sedward long t; 808*18606Sedward #define TTYLEN 5 8091014Sbill 810*18606Sedward strcpy(buffer + TTYLEN, pers->tty); 811*18606Sedward buffer[TTYLEN+LMAX] = 0; 812*18606Sedward if (stat(buffer, &ttystatus) < 0) { 813*18606Sedward fprintf(stderr, "finger: Can't stat %s\n", buffer); 814*18606Sedward exit(4); 815*18606Sedward } 816*18606Sedward time(&t); 817*18606Sedward if (t < ttystatus.st_atime) 8181014Sbill pers->idletime = 0L; 819*18606Sedward else 820*18606Sedward pers->idletime = t - ttystatus.st_atime; 821*18606Sedward pers->writable = (ttystatus.st_mode & TALKABLE) == TALKABLE; 8221014Sbill } 8231014Sbill 824*18606Sedward /* 825*18606Sedward * print idle time in short format; this program always prints 4 characters; 826*18606Sedward * if the idle time is zero, it prints 4 blanks. 8271014Sbill */ 828*18606Sedward stimeprint(dt) 829*18606Sedward long *dt; 8301014Sbill { 831*18606Sedward register struct tm *delta; 8321014Sbill 833*18606Sedward delta = gmtime(dt); 834*18606Sedward if (delta->tm_yday == 0) 835*18606Sedward if (delta->tm_hour == 0) 836*18606Sedward if (delta->tm_min == 0) 837*18606Sedward printf(" "); 838*18606Sedward else 839*18606Sedward printf(" %2d", delta->tm_min); 840*18606Sedward else 841*18606Sedward if (delta->tm_hour >= 10) 842*18606Sedward printf("%3d:", delta->tm_hour); 843*18606Sedward else 844*18606Sedward printf("%1d:%02d", 845*18606Sedward delta->tm_hour, delta->tm_min); 846*18606Sedward else 847*18606Sedward printf("%3dd", delta->tm_yday); 8481014Sbill } 8491014Sbill 850*18606Sedward /* 851*18606Sedward * print idle time in long format with care being taken not to pluralize 852*18606Sedward * 1 minutes or 1 hours or 1 days. 853*18606Sedward * print "prefix" first. 8541014Sbill */ 855*18606Sedward ltimeprint(before, dt, after) 856*18606Sedward long *dt; 857*18606Sedward char *before, *after; 8581014Sbill { 859*18606Sedward register struct tm *delta; 8601014Sbill 861*18606Sedward delta = gmtime(dt); 862*18606Sedward if (delta->tm_yday == 0 && delta->tm_hour == 0 && delta->tm_min == 0 && 863*18606Sedward delta->tm_sec <= 10) 864*18606Sedward return (0); 865*18606Sedward printf("%s", before); 866*18606Sedward if (delta->tm_yday >= 10) 867*18606Sedward printf("%d days", delta->tm_yday); 868*18606Sedward else if (delta->tm_yday > 0) 869*18606Sedward printf("%d day%s %d hour%s", 870*18606Sedward delta->tm_yday, delta->tm_yday == 1 ? "" : "s", 871*18606Sedward delta->tm_hour, delta->tm_hour == 1 ? "" : "s"); 872*18606Sedward else 873*18606Sedward if (delta->tm_hour >= 10) 874*18606Sedward printf("%d hours", delta->tm_hour); 875*18606Sedward else if (delta->tm_hour > 0) 876*18606Sedward printf("%d hour%s %d minute%s", 877*18606Sedward delta->tm_hour, delta->tm_hour == 1 ? "" : "s", 878*18606Sedward delta->tm_min, delta->tm_min == 1 ? "" : "s"); 879*18606Sedward else 880*18606Sedward if (delta->tm_min >= 10) 881*18606Sedward printf("%2d minutes", delta->tm_min); 882*18606Sedward else if (delta->tm_min == 0) 883*18606Sedward printf("%2d seconds", delta->tm_sec); 884*18606Sedward else 885*18606Sedward printf("%d minute%s %d second%s", 886*18606Sedward delta->tm_min, 887*18606Sedward delta->tm_min == 1 ? "" : "s", 888*18606Sedward delta->tm_sec, 889*18606Sedward delta->tm_sec == 1 ? "" : "s"); 890*18606Sedward printf("%s", after); 8911014Sbill } 8921014Sbill 893*18606Sedward matchcmp(gname, login, given) 894*18606Sedward register char *gname; 895*18606Sedward char *login; 896*18606Sedward char *given; 8971014Sbill { 898*18606Sedward char buffer[100]; 899*18606Sedward register char *bp, *lp; 900*18606Sedward register c; 9011014Sbill 902*18606Sedward if (*gname == ASTERISK) 903*18606Sedward gname++; 904*18606Sedward lp = 0; 905*18606Sedward bp = buffer; 906*18606Sedward for (;;) 907*18606Sedward switch (c = *gname++) { 908*18606Sedward case SAMENAME: 909*18606Sedward for (lp = login; bp < buffer + sizeof buffer 910*18606Sedward && (*bp++ = *lp++);) 911*18606Sedward ; 912*18606Sedward bp--; 913*18606Sedward break; 914*18606Sedward case ' ': 915*18606Sedward case COMMA: 916*18606Sedward case '\0': 917*18606Sedward *bp = 0; 918*18606Sedward if (namecmp(buffer, given)) 919*18606Sedward return (1); 920*18606Sedward if (c == COMMA || c == 0) 921*18606Sedward return (0); 922*18606Sedward bp = buffer; 923*18606Sedward break; 924*18606Sedward default: 925*18606Sedward if (bp < buffer + sizeof buffer) 926*18606Sedward *bp++ = c; 9271014Sbill } 928*18606Sedward /*NOTREACHED*/ 9291014Sbill } 9301014Sbill 931*18606Sedward namecmp(name1, name2) 932*18606Sedward register char *name1, *name2; 9331014Sbill { 934*18606Sedward register c1, c2; 9351014Sbill 936*18606Sedward for (;;) { 937*18606Sedward c1 = *name1++; 938*18606Sedward if (islower(c1)) 939*18606Sedward c1 = toupper(c1); 940*18606Sedward c2 = *name2++; 941*18606Sedward if (islower(c2)) 942*18606Sedward c2 = toupper(c2); 943*18606Sedward if (c1 != c2) 944*18606Sedward break; 945*18606Sedward if (c1 == 0) 946*18606Sedward return (1); 9471014Sbill } 948*18606Sedward if (!c1) { 949*18606Sedward for (name2--; isdigit(*name2); name2++) 950*18606Sedward ; 951*18606Sedward if (*name2 == 0) 952*18606Sedward return (1); 953*18606Sedward } else if (!c2) { 954*18606Sedward for (name1--; isdigit(*name1); name1++) 955*18606Sedward ; 956*18606Sedward if (*name2 == 0) 957*18606Sedward return (1); 9581014Sbill } 959*18606Sedward return (0); 9601014Sbill } 9611014Sbill 96216469Ssam netfinger(name) 963*18606Sedward char *name; 96416469Ssam { 96516469Ssam char *host; 96616469Ssam char fname[100]; 96716469Ssam struct hostent *hp; 96816469Ssam struct servent *sp; 969*18606Sedward struct sockaddr_in sin; 97016469Ssam int s; 97116469Ssam char *rindex(); 97216469Ssam register FILE *f; 97316469Ssam register int c; 97416469Ssam register int lastc; 97516469Ssam 97616469Ssam if (name == NULL) 977*18606Sedward return (0); 97816469Ssam host = rindex(name, '@'); 97916469Ssam if (host == NULL) 980*18606Sedward return (0); 98116469Ssam *host++ = 0; 98216469Ssam hp = gethostbyname(host); 98316469Ssam if (hp == NULL) { 98416469Ssam static struct hostent def; 98516469Ssam static struct in_addr defaddr; 98616469Ssam static char namebuf[128]; 98716469Ssam int inet_addr(); 98816469Ssam 98916469Ssam defaddr.s_addr = inet_addr(host); 99016469Ssam if (defaddr.s_addr == -1) { 99116469Ssam printf("unknown host: %s\n", host); 992*18606Sedward return (1); 99316469Ssam } 99416469Ssam strcpy(namebuf, host); 99516469Ssam def.h_name = namebuf; 99616469Ssam def.h_addr = (char *)&defaddr; 99716469Ssam def.h_length = sizeof (struct in_addr); 99816469Ssam def.h_addrtype = AF_INET; 99916469Ssam def.h_aliases = 0; 100016469Ssam hp = &def; 100116469Ssam } 100216469Ssam printf("[%s]", hp->h_name); 100316469Ssam sp = getservbyname("finger", "tcp"); 100416469Ssam if (sp == 0) { 100516469Ssam printf("tcp/finger: unknown service\n"); 1006*18606Sedward return (1); 100716469Ssam } 100816469Ssam sin.sin_family = hp->h_addrtype; 100916469Ssam bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length); 101016469Ssam sin.sin_port = sp->s_port; 101116469Ssam s = socket(hp->h_addrtype, SOCK_STREAM, 0); 101216469Ssam if (s < 0) { 101316469Ssam fflush(stdout); 101416469Ssam perror("socket"); 1015*18606Sedward return (1); 101616469Ssam } 101716469Ssam if (connect(s, (char *)&sin, sizeof (sin)) < 0) { 101816469Ssam fflush(stdout); 101916469Ssam perror("connect"); 102016469Ssam close(s); 1021*18606Sedward return (1); 102216469Ssam } 102316469Ssam printf("\n"); 102416469Ssam if (large) write(s, "/W ", 3); 102516469Ssam write(s, name, strlen(name)); 102616469Ssam write(s, "\r\n", 2); 102716469Ssam f = fdopen(s, "r"); 102816469Ssam while ((c = getc(f)) != EOF) { 102916469Ssam switch(c) { 103016469Ssam case 0210: 103116469Ssam case 0211: 103216469Ssam case 0212: 103316469Ssam case 0214: 103416469Ssam c -= 0200; 103516469Ssam break; 103616469Ssam case 0215: 103716469Ssam c = '\n'; 103816469Ssam break; 103916469Ssam } 104016469Ssam putchar(lastc = c); 104116469Ssam } 104216469Ssam if (lastc != '\n') 104316469Ssam putchar('\n'); 1044*18606Sedward return (1); 104516469Ssam } 1046