1 /* 2 * Copyright (c) 1980 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 */ 6 7 #ifndef lint 8 char copyright[] = 9 "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 10 All rights reserved.\n"; 11 #endif not lint 12 13 #ifndef lint 14 static char sccsid[] = "@(#)finger.c 5.10 (Berkeley) 04/26/87"; 15 #endif not lint 16 17 /* 18 * This is a finger program. It prints out useful information about users 19 * by digging it up from various system files. It is not very portable 20 * because the most useful parts of the information (the full user name, 21 * office, and phone numbers) are all stored in the VAX-unused gecos field 22 * of /etc/passwd, which, unfortunately, other UNIXes use for other things. 23 * 24 * There are three output formats, all of which give login name, teletype 25 * line number, and login time. The short output format is reminiscent 26 * of finger on ITS, and gives one line of information per user containing 27 * in addition to the minimum basic requirements (MBR), the full name of 28 * the user, his idle time and office location and phone number. The 29 * quick style output is UNIX who-like, giving only name, teletype and 30 * login time. Finally, the long style output give the same information 31 * as the short (in more legible format), the home directory and shell 32 * of the user, and, if it exits, a copy of the file .plan in the users 33 * home directory. Finger may be called with or without a list of people 34 * to finger -- if no list is given, all the people currently logged in 35 * are fingered. 36 * 37 * The program is validly called by one of the following: 38 * 39 * finger {short form list of users} 40 * finger -l {long form list of users} 41 * finger -b {briefer long form list of users} 42 * finger -q {quick list of users} 43 * finger -i {quick list of users with idle times} 44 * finger namelist {long format list of specified users} 45 * finger -s namelist {short format list of specified users} 46 * finger -w namelist {narrow short format list of specified users} 47 * 48 * where 'namelist' is a list of users login names. 49 * The other options can all be given after one '-', or each can have its 50 * own '-'. The -f option disables the printing of headers for short and 51 * quick outputs. The -b option briefens long format outputs. The -p 52 * option turns off plans for long format outputs. 53 */ 54 55 #include <sys/types.h> 56 #include <sys/stat.h> 57 #include <utmp.h> 58 #include <sys/signal.h> 59 #include <pwd.h> 60 #include <stdio.h> 61 #include <lastlog.h> 62 #include <ctype.h> 63 #include <sys/time.h> 64 #include <sys/socket.h> 65 #include <netinet/in.h> 66 #include <netdb.h> 67 68 #define ASTERISK '*' /* ignore this in real name */ 69 #define COMMA ',' /* separator in pw_gecos field */ 70 #define COMMAND '-' /* command line flag char */ 71 #define CORY 'C' /* cory hall office */ 72 #define EVANS 'E' /* evans hall office */ 73 #define SAMENAME '&' /* repeat login name in real name */ 74 #define TALKABLE 0220 /* tty is writable if 220 mode */ 75 76 struct utmp user; 77 #define NMAX sizeof(user.ut_name) 78 #define LMAX sizeof(user.ut_line) 79 #define HMAX sizeof(user.ut_host) 80 81 struct person { /* one for each person fingered */ 82 char *name; /* name */ 83 char tty[LMAX+1]; /* null terminated tty line */ 84 char host[HMAX+1]; /* null terminated remote host name */ 85 long loginat; /* time of (last) login */ 86 long idletime; /* how long idle (if logged in) */ 87 char *realname; /* pointer to full name */ 88 char *office; /* pointer to office name */ 89 char *officephone; /* pointer to office phone no. */ 90 char *homephone; /* pointer to home phone no. */ 91 char *random; /* for any random stuff in pw_gecos */ 92 struct passwd *pwd; /* structure of /etc/passwd stuff */ 93 char loggedin; /* person is logged in */ 94 char writable; /* tty is writable */ 95 char original; /* this is not a duplicate entry */ 96 struct person *link; /* link to next person */ 97 }; 98 99 char LASTLOG[] = "/usr/adm/lastlog"; /* last login info */ 100 char USERLOG[] = "/etc/utmp"; /* who is logged in */ 101 char PLAN[] = "/.plan"; /* what plan file is */ 102 char PROJ[] = "/.project"; /* what project file */ 103 104 int unbrief = 1; /* -b option default */ 105 int header = 1; /* -f option default */ 106 int hack = 1; /* -h option default */ 107 int idle = 0; /* -i option default */ 108 int large = 0; /* -l option default */ 109 int match = 1; /* -m option default */ 110 int plan = 1; /* -p option default */ 111 int unquick = 1; /* -q option default */ 112 int small = 0; /* -s option default */ 113 int wide = 1; /* -w option default */ 114 115 int unshort; 116 int lf; /* LASTLOG file descriptor */ 117 struct person *person1; /* list of people */ 118 long tloc; /* current time */ 119 120 struct passwd *pwdcopy(); 121 char *strcpy(); 122 char *malloc(); 123 char *ctime(); 124 125 main(argc, argv) 126 int argc; 127 register char **argv; 128 { 129 FILE *fp; 130 register char *s; 131 132 /* parse command line for (optional) arguments */ 133 while (*++argv && **argv == COMMAND) 134 for (s = *argv + 1; *s; s++) 135 switch (*s) { 136 case 'b': 137 unbrief = 0; 138 break; 139 case 'f': 140 header = 0; 141 break; 142 case 'h': 143 hack = 0; 144 break; 145 case 'i': 146 idle = 1; 147 unquick = 0; 148 break; 149 case 'l': 150 large = 1; 151 break; 152 case 'm': 153 match = 0; 154 break; 155 case 'p': 156 plan = 0; 157 break; 158 case 'q': 159 unquick = 0; 160 break; 161 case 's': 162 small = 1; 163 break; 164 case 'w': 165 wide = 0; 166 break; 167 default: 168 fprintf(stderr, "Usage: finger [-bfhilmpqsw] [login1 [login2 ...] ]\n"); 169 exit(1); 170 } 171 if (unquick || idle) 172 time(&tloc); 173 /* 174 * *argv == 0 means no names given 175 */ 176 if (*argv == 0) 177 doall(); 178 else 179 donames(argv); 180 if (person1) 181 print(); 182 exit(0); 183 } 184 185 doall() 186 { 187 register struct person *p; 188 register struct passwd *pw; 189 int uf; 190 char name[NMAX + 1]; 191 192 unshort = large; 193 if ((uf = open(USERLOG, 0)) < 0) { 194 fprintf(stderr, "finger: error opening %s\n", USERLOG); 195 exit(2); 196 } 197 if (unquick) { 198 extern _pw_stayopen; 199 200 setpwent(); 201 _pw_stayopen = 1; 202 fwopen(); 203 } 204 while (read(uf, (char *)&user, sizeof user) == sizeof user) { 205 if (user.ut_name[0] == 0) 206 continue; 207 if (person1 == 0) 208 p = person1 = (struct person *) malloc(sizeof *p); 209 else { 210 p->link = (struct person *) malloc(sizeof *p); 211 p = p->link; 212 } 213 bcopy(user.ut_name, name, NMAX); 214 name[NMAX] = 0; 215 bcopy(user.ut_line, p->tty, LMAX); 216 p->tty[LMAX] = 0; 217 bcopy(user.ut_host, p->host, HMAX); 218 p->host[HMAX] = 0; 219 p->loginat = user.ut_time; 220 p->pwd = 0; 221 p->loggedin = 1; 222 if (unquick && (pw = getpwnam(name))) { 223 p->pwd = pwdcopy(pw); 224 decode(p); 225 p->name = p->pwd->pw_name; 226 } else 227 p->name = strcpy(malloc(strlen(name) + 1), name); 228 } 229 if (unquick) { 230 fwclose(); 231 endpwent(); 232 } 233 close(uf); 234 if (person1 == 0) { 235 printf("No one logged on\n"); 236 return; 237 } 238 p->link = 0; 239 } 240 241 donames(argv) 242 char **argv; 243 { 244 register struct person *p; 245 register struct passwd *pw; 246 int uf; 247 248 /* 249 * get names from command line and check to see if they're 250 * logged in 251 */ 252 unshort = !small; 253 for (; *argv != 0; argv++) { 254 if (netfinger(*argv)) 255 continue; 256 if (person1 == 0) 257 p = person1 = (struct person *) malloc(sizeof *p); 258 else { 259 p->link = (struct person *) malloc(sizeof *p); 260 p = p->link; 261 } 262 p->name = *argv; 263 p->loggedin = 0; 264 p->original = 1; 265 p->pwd = 0; 266 } 267 if (person1 == 0) 268 return; 269 p->link = 0; 270 /* 271 * if we are doing it, read /etc/passwd for the useful info 272 */ 273 if (unquick) { 274 setpwent(); 275 if (!match) { 276 extern _pw_stayopen; 277 278 _pw_stayopen = 1; 279 for (p = person1; p != 0; p = p->link) 280 if (pw = getpwnam(p->name)) 281 p->pwd = pwdcopy(pw); 282 } else while ((pw = getpwent()) != 0) { 283 for (p = person1; p != 0; p = p->link) { 284 if (!p->original) 285 continue; 286 if (strcmp(p->name, pw->pw_name) != 0 && 287 !matchcmp(pw->pw_gecos, pw->pw_name, p->name)) 288 continue; 289 if (p->pwd == 0) 290 p->pwd = pwdcopy(pw); 291 else { 292 struct person *new; 293 /* 294 * handle multiple login names, insert 295 * new "duplicate" entry behind 296 */ 297 new = (struct person *) 298 malloc(sizeof *new); 299 new->pwd = pwdcopy(pw); 300 new->name = p->name; 301 new->original = 1; 302 new->loggedin = 0; 303 new->link = p->link; 304 p->original = 0; 305 p->link = new; 306 p = new; 307 } 308 } 309 } 310 endpwent(); 311 } 312 /* Now get login information */ 313 if ((uf = open(USERLOG, 0)) < 0) { 314 fprintf(stderr, "finger: error opening %s\n", USERLOG); 315 exit(2); 316 } 317 while (read(uf, (char *)&user, sizeof user) == sizeof user) { 318 if (*user.ut_name == 0) 319 continue; 320 for (p = person1; p != 0; p = p->link) { 321 if (p->loggedin == 2) 322 continue; 323 if (strncmp(p->pwd ? p->pwd->pw_name : p->name, 324 user.ut_name, NMAX) != 0) 325 continue; 326 if (p->loggedin == 0) { 327 bcopy(user.ut_line, p->tty, LMAX); 328 p->tty[LMAX] = 0; 329 bcopy(user.ut_host, p->host, HMAX); 330 p->host[HMAX] = 0; 331 p->loginat = user.ut_time; 332 p->loggedin = 1; 333 } else { /* p->loggedin == 1 */ 334 struct person *new; 335 new = (struct person *) malloc(sizeof *new); 336 new->name = p->name; 337 bcopy(user.ut_line, new->tty, LMAX); 338 new->tty[LMAX] = 0; 339 bcopy(user.ut_host, new->host, HMAX); 340 new->host[HMAX] = 0; 341 new->loginat = user.ut_time; 342 new->pwd = p->pwd; 343 new->loggedin = 1; 344 new->original = 0; 345 new->link = p->link; 346 p->loggedin = 2; 347 p->link = new; 348 p = new; 349 } 350 } 351 } 352 close(uf); 353 if (unquick) { 354 fwopen(); 355 for (p = person1; p != 0; p = p->link) 356 decode(p); 357 fwclose(); 358 } 359 } 360 361 print() 362 { 363 register FILE *fp; 364 register struct person *p; 365 register char *s; 366 register c; 367 368 /* 369 * print out what we got 370 */ 371 if (header) { 372 if (unquick) { 373 if (!unshort) 374 if (wide) 375 printf("Login Name TTY Idle When Office\n"); 376 else 377 printf("Login TTY Idle When Office\n"); 378 } else { 379 printf("Login TTY When"); 380 if (idle) 381 printf(" Idle"); 382 putchar('\n'); 383 } 384 } 385 for (p = person1; p != 0; p = p->link) { 386 if (!unquick) { 387 quickprint(p); 388 continue; 389 } 390 if (!unshort) { 391 shortprint(p); 392 continue; 393 } 394 personprint(p); 395 if (p->pwd != 0) { 396 if (hack) { 397 s = malloc(strlen(p->pwd->pw_dir) + 398 sizeof PROJ); 399 strcpy(s, p->pwd->pw_dir); 400 strcat(s, PROJ); 401 if ((fp = fopen(s, "r")) != 0) { 402 printf("Project: "); 403 while ((c = getc(fp)) != EOF) { 404 if (c == '\n') 405 break; 406 if (isprint(c) || isspace(c)) 407 putchar(c); 408 else 409 putchar(c ^ 100); 410 } 411 fclose(fp); 412 putchar('\n'); 413 } 414 free(s); 415 } 416 if (plan) { 417 s = malloc(strlen(p->pwd->pw_dir) + 418 sizeof PLAN); 419 strcpy(s, p->pwd->pw_dir); 420 strcat(s, PLAN); 421 if ((fp = fopen(s, "r")) == 0) 422 printf("No Plan.\n"); 423 else { 424 printf("Plan:\n"); 425 while ((c = getc(fp)) != EOF) 426 if (isprint(c) || isspace(c)) 427 putchar(c); 428 else 429 putchar(c ^ 100); 430 fclose(fp); 431 } 432 free(s); 433 } 434 } 435 if (p->link != 0) 436 putchar('\n'); 437 } 438 } 439 440 /* 441 * Duplicate a pwd entry. 442 * Note: Only the useful things (what the program currently uses) are copied. 443 */ 444 struct passwd * 445 pwdcopy(pfrom) 446 register struct passwd *pfrom; 447 { 448 register struct passwd *pto; 449 450 pto = (struct passwd *) malloc(sizeof *pto); 451 #define savestr(s) strcpy(malloc(strlen(s) + 1), s) 452 pto->pw_name = savestr(pfrom->pw_name); 453 pto->pw_uid = pfrom->pw_uid; 454 pto->pw_gecos = savestr(pfrom->pw_gecos); 455 pto->pw_dir = savestr(pfrom->pw_dir); 456 pto->pw_shell = savestr(pfrom->pw_shell); 457 #undef savestr 458 return pto; 459 } 460 461 /* 462 * print out information on quick format giving just name, tty, login time 463 * and idle time if idle is set. 464 */ 465 quickprint(pers) 466 register struct person *pers; 467 { 468 printf("%-*.*s ", NMAX, NMAX, pers->name); 469 if (pers->loggedin) { 470 if (idle) { 471 findidle(pers); 472 printf("%c%-*s %-16.16s", pers->writable ? ' ' : '*', 473 LMAX, pers->tty, ctime(&pers->loginat)); 474 ltimeprint(" ", &pers->idletime, ""); 475 } else 476 printf(" %-*s %-16.16s", LMAX, 477 pers->tty, ctime(&pers->loginat)); 478 putchar('\n'); 479 } else 480 printf(" Not Logged In\n"); 481 } 482 483 /* 484 * print out information in short format, giving login name, full name, 485 * tty, idle time, login time, office location and phone. 486 */ 487 shortprint(pers) 488 register struct person *pers; 489 { 490 char *p; 491 char dialup; 492 493 if (pers->pwd == 0) { 494 printf("%-15s ???\n", pers->name); 495 return; 496 } 497 printf("%-*s", NMAX, pers->pwd->pw_name); 498 dialup = 0; 499 if (wide) { 500 if (pers->realname) 501 printf(" %-20.20s", pers->realname); 502 else 503 printf(" ??? "); 504 } 505 putchar(' '); 506 if (pers->loggedin && !pers->writable) 507 putchar('*'); 508 else 509 putchar(' '); 510 if (*pers->tty) { 511 if (pers->tty[0] == 't' && pers->tty[1] == 't' && 512 pers->tty[2] == 'y') { 513 if (pers->tty[3] == 'd' && pers->loggedin) 514 dialup = 1; 515 printf("%-2.2s ", pers->tty + 3); 516 } else 517 printf("%-2.2s ", pers->tty); 518 } else 519 printf(" "); 520 p = ctime(&pers->loginat); 521 if (pers->loggedin) { 522 stimeprint(&pers->idletime); 523 printf(" %3.3s %-5.5s ", p, p + 11); 524 } else if (pers->loginat == 0) 525 printf(" < . . . . >"); 526 else if (tloc - pers->loginat >= 180 * 24 * 60 * 60) 527 printf(" <%-6.6s, %-4.4s>", p + 4, p + 20); 528 else 529 printf(" <%-12.12s>", p + 4); 530 if (dialup && pers->homephone) 531 printf(" %20s", pers->homephone); 532 else { 533 if (pers->office) 534 printf(" %-11.11s", pers->office); 535 else if (pers->officephone || pers->homephone) 536 printf(" "); 537 if (pers->officephone) 538 printf(" %s", pers->officephone); 539 else if (pers->homephone) 540 printf(" %s", pers->homephone); 541 } 542 putchar('\n'); 543 } 544 545 /* 546 * print out a person in long format giving all possible information. 547 * directory and shell are inhibited if unbrief is clear. 548 */ 549 personprint(pers) 550 register struct person *pers; 551 { 552 if (pers->pwd == 0) { 553 printf("Login name: %-10s\t\t\tIn real life: ???\n", 554 pers->name); 555 return; 556 } 557 printf("Login name: %-10s", pers->pwd->pw_name); 558 if (pers->loggedin && !pers->writable) 559 printf(" (messages off) "); 560 else 561 printf(" "); 562 if (pers->realname) 563 printf("In real life: %s", pers->realname); 564 if (pers->office) { 565 printf("\nOffice: %-.11s", pers->office); 566 if (pers->officephone) { 567 printf(", %s", pers->officephone); 568 if (pers->homephone) 569 printf("\t\tHome phone: %s", pers->homephone); 570 else if (pers->random) 571 printf("\t\t%s", pers->random); 572 } else 573 if (pers->homephone) 574 printf("\t\t\tHome phone: %s", pers->homephone); 575 else if (pers->random) 576 printf("\t\t\t%s", pers->random); 577 } else if (pers->officephone) { 578 printf("\nPhone: %s", pers->officephone); 579 if (pers->homephone) 580 printf(", %s", pers->homephone); 581 if (pers->random) 582 printf(", %s", pers->random); 583 } else if (pers->homephone) { 584 printf("\nPhone: %s", pers->homephone); 585 if (pers->random) 586 printf(", %s", pers->random); 587 } else if (pers->random) 588 printf("\n%s", pers->random); 589 if (unbrief) { 590 printf("\nDirectory: %-25s", pers->pwd->pw_dir); 591 if (*pers->pwd->pw_shell) 592 printf("\tShell: %-s", pers->pwd->pw_shell); 593 } 594 if (pers->loggedin) { 595 register char *ep = ctime(&pers->loginat); 596 if (*pers->host) { 597 printf("\nOn since %15.15s on %s from %s", 598 &ep[4], pers->tty, pers->host); 599 ltimeprint("\n", &pers->idletime, " Idle Time"); 600 } else { 601 printf("\nOn since %15.15s on %-*s", 602 &ep[4], LMAX, pers->tty); 603 ltimeprint("\t", &pers->idletime, " Idle Time"); 604 } 605 } else if (pers->loginat == 0) 606 printf("\nNever logged in."); 607 else if (tloc - pers->loginat > 180 * 24 * 60 * 60) { 608 register char *ep = ctime(&pers->loginat); 609 printf("\nLast login %10.10s, %4.4s on %s", 610 ep, ep+20, pers->tty); 611 if (*pers->host) 612 printf(" from %s", pers->host); 613 } else { 614 register char *ep = ctime(&pers->loginat); 615 printf("\nLast login %16.16s on %s", ep, pers->tty); 616 if (*pers->host) 617 printf(" from %s", pers->host); 618 } 619 putchar('\n'); 620 } 621 622 /* 623 * very hacky section of code to format phone numbers. filled with 624 * magic constants like 4, 7 and 10. 625 */ 626 char * 627 phone(s, len, alldigits) 628 register char *s; 629 int len; 630 char alldigits; 631 { 632 char fonebuf[15]; 633 register char *p = fonebuf; 634 register i; 635 636 if (!alldigits) 637 return (strcpy(malloc(len + 1), s)); 638 switch (len) { 639 case 4: 640 *p++ = ' '; 641 *p++ = 'x'; 642 *p++ = '2'; 643 *p++ = '-'; 644 for (i = 0; i < 4; i++) 645 *p++ = *s++; 646 break; 647 case 5: 648 *p++ = ' '; 649 *p++ = 'x'; 650 *p++ = *s++; 651 *p++ = '-'; 652 for (i = 0; i < 4; i++) 653 *p++ = *s++; 654 break; 655 case 7: 656 for (i = 0; i < 3; i++) 657 *p++ = *s++; 658 *p++ = '-'; 659 for (i = 0; i < 4; i++) 660 *p++ = *s++; 661 break; 662 case 10: 663 for (i = 0; i < 3; i++) 664 *p++ = *s++; 665 *p++ = '-'; 666 for (i = 0; i < 3; i++) 667 *p++ = *s++; 668 *p++ = '-'; 669 for (i = 0; i < 4; i++) 670 *p++ = *s++; 671 break; 672 case 0: 673 return 0; 674 default: 675 return (strcpy(malloc(len + 1), s)); 676 } 677 *p++ = 0; 678 return (strcpy(malloc(p - fonebuf), fonebuf)); 679 } 680 681 /* 682 * decode the information in the gecos field of /etc/passwd 683 */ 684 decode(pers) 685 register struct person *pers; 686 { 687 char buffer[256]; 688 register char *bp, *gp, *lp; 689 int alldigits; 690 int hasspace; 691 int len; 692 693 pers->realname = 0; 694 pers->office = 0; 695 pers->officephone = 0; 696 pers->homephone = 0; 697 pers->random = 0; 698 if (pers->pwd == 0) 699 return; 700 gp = pers->pwd->pw_gecos; 701 bp = buffer; 702 if (*gp == ASTERISK) 703 gp++; 704 while (*gp && *gp != COMMA) /* name */ 705 if (*gp == SAMENAME) { 706 lp = pers->pwd->pw_name; 707 if (islower(*lp)) 708 *bp++ = toupper(*lp++); 709 while (*bp++ = *lp++) 710 ; 711 bp--; 712 gp++; 713 } else 714 *bp++ = *gp++; 715 *bp++ = 0; 716 if ((len = bp - buffer) > 1) 717 pers->realname = strcpy(malloc(len), buffer); 718 if (*gp == COMMA) { /* office */ 719 gp++; 720 hasspace = 0; 721 bp = buffer; 722 while (*gp && *gp != COMMA) { 723 *bp = *gp++; 724 if (*bp == ' ') 725 hasspace = 1; 726 /* leave 5 for Cory and Evans expansion */ 727 if (bp < buffer + sizeof buffer - 6) 728 bp++; 729 } 730 *bp = 0; 731 len = bp - buffer; 732 bp--; /* point to last character */ 733 if (hasspace || len == 0) 734 len++; 735 else if (*bp == CORY) { 736 strcpy(bp, " Cory"); 737 len += 5; 738 } else if (*bp == EVANS) { 739 strcpy(bp, " Evans"); 740 len += 6; 741 } else 742 len++; 743 if (len > 1) 744 pers->office = strcpy(malloc(len), buffer); 745 } 746 if (*gp == COMMA) { /* office phone */ 747 gp++; 748 bp = buffer; 749 alldigits = 1; 750 while (*gp && *gp != COMMA) { 751 *bp = *gp++; 752 if (!isdigit(*bp)) 753 alldigits = 0; 754 if (bp < buffer + sizeof buffer - 1) 755 bp++; 756 } 757 *bp = 0; 758 pers->officephone = phone(buffer, bp - buffer, alldigits); 759 } 760 if (*gp == COMMA) { /* home phone */ 761 gp++; 762 bp = buffer; 763 alldigits = 1; 764 while (*gp && *gp != COMMA) { 765 *bp = *gp++; 766 if (!isdigit(*bp)) 767 alldigits = 0; 768 if (bp < buffer + sizeof buffer - 1) 769 bp++; 770 } 771 *bp = 0; 772 pers->homephone = phone(buffer, bp - buffer, alldigits); 773 } 774 if (pers->loggedin) 775 findidle(pers); 776 else 777 findwhen(pers); 778 } 779 780 /* 781 * find the last log in of a user by checking the LASTLOG file. 782 * the entry is indexed by the uid, so this can only be done if 783 * the uid is known (which it isn't in quick mode) 784 */ 785 786 fwopen() 787 { 788 if ((lf = open(LASTLOG, 0)) < 0) 789 fprintf(stderr, "finger: %s open error\n", LASTLOG); 790 } 791 792 findwhen(pers) 793 register struct person *pers; 794 { 795 struct lastlog ll; 796 int i; 797 798 if (lf >= 0) { 799 lseek(lf, (long)pers->pwd->pw_uid * sizeof ll, 0); 800 if ((i = read(lf, (char *)&ll, sizeof ll)) == sizeof ll) { 801 bcopy(ll.ll_line, pers->tty, LMAX); 802 pers->tty[LMAX] = 0; 803 bcopy(ll.ll_host, pers->host, HMAX); 804 pers->host[HMAX] = 0; 805 pers->loginat = ll.ll_time; 806 } else { 807 if (i != 0) 808 fprintf(stderr, "finger: %s read error\n", 809 LASTLOG); 810 pers->tty[0] = 0; 811 pers->host[0] = 0; 812 pers->loginat = 0L; 813 } 814 } else { 815 pers->tty[0] = 0; 816 pers->host[0] = 0; 817 pers->loginat = 0L; 818 } 819 } 820 821 fwclose() 822 { 823 if (lf >= 0) 824 close(lf); 825 } 826 827 /* 828 * find the idle time of a user by doing a stat on /dev/tty??, 829 * where tty?? has been gotten from USERLOG, supposedly. 830 */ 831 findidle(pers) 832 register struct person *pers; 833 { 834 struct stat ttystatus; 835 static char buffer[20] = "/dev/"; 836 long t; 837 #define TTYLEN 5 838 839 strcpy(buffer + TTYLEN, pers->tty); 840 buffer[TTYLEN+LMAX] = 0; 841 if (stat(buffer, &ttystatus) < 0) { 842 fprintf(stderr, "finger: Can't stat %s\n", buffer); 843 exit(4); 844 } 845 time(&t); 846 if (t < ttystatus.st_atime) 847 pers->idletime = 0L; 848 else 849 pers->idletime = t - ttystatus.st_atime; 850 pers->writable = (ttystatus.st_mode & TALKABLE) == TALKABLE; 851 } 852 853 /* 854 * print idle time in short format; this program always prints 4 characters; 855 * if the idle time is zero, it prints 4 blanks. 856 */ 857 stimeprint(dt) 858 long *dt; 859 { 860 register struct tm *delta; 861 862 delta = gmtime(dt); 863 if (delta->tm_yday == 0) 864 if (delta->tm_hour == 0) 865 if (delta->tm_min == 0) 866 printf(" "); 867 else 868 printf(" %2d", delta->tm_min); 869 else 870 if (delta->tm_hour >= 10) 871 printf("%3d:", delta->tm_hour); 872 else 873 printf("%1d:%02d", 874 delta->tm_hour, delta->tm_min); 875 else 876 printf("%3dd", delta->tm_yday); 877 } 878 879 /* 880 * print idle time in long format with care being taken not to pluralize 881 * 1 minutes or 1 hours or 1 days. 882 * print "prefix" first. 883 */ 884 ltimeprint(before, dt, after) 885 long *dt; 886 char *before, *after; 887 { 888 register struct tm *delta; 889 890 delta = gmtime(dt); 891 if (delta->tm_yday == 0 && delta->tm_hour == 0 && delta->tm_min == 0 && 892 delta->tm_sec <= 10) 893 return (0); 894 printf("%s", before); 895 if (delta->tm_yday >= 10) 896 printf("%d days", delta->tm_yday); 897 else if (delta->tm_yday > 0) 898 printf("%d day%s %d hour%s", 899 delta->tm_yday, delta->tm_yday == 1 ? "" : "s", 900 delta->tm_hour, delta->tm_hour == 1 ? "" : "s"); 901 else 902 if (delta->tm_hour >= 10) 903 printf("%d hours", delta->tm_hour); 904 else if (delta->tm_hour > 0) 905 printf("%d hour%s %d minute%s", 906 delta->tm_hour, delta->tm_hour == 1 ? "" : "s", 907 delta->tm_min, delta->tm_min == 1 ? "" : "s"); 908 else 909 if (delta->tm_min >= 10) 910 printf("%2d minutes", delta->tm_min); 911 else if (delta->tm_min == 0) 912 printf("%2d seconds", delta->tm_sec); 913 else 914 printf("%d minute%s %d second%s", 915 delta->tm_min, 916 delta->tm_min == 1 ? "" : "s", 917 delta->tm_sec, 918 delta->tm_sec == 1 ? "" : "s"); 919 printf("%s", after); 920 } 921 922 matchcmp(gname, login, given) 923 register char *gname; 924 char *login; 925 char *given; 926 { 927 char buffer[100]; 928 register char *bp, *lp; 929 register c; 930 931 if (*gname == ASTERISK) 932 gname++; 933 lp = 0; 934 bp = buffer; 935 for (;;) 936 switch (c = *gname++) { 937 case SAMENAME: 938 for (lp = login; bp < buffer + sizeof buffer 939 && (*bp++ = *lp++);) 940 ; 941 bp--; 942 break; 943 case ' ': 944 case COMMA: 945 case '\0': 946 *bp = 0; 947 if (namecmp(buffer, given)) 948 return (1); 949 if (c == COMMA || c == 0) 950 return (0); 951 bp = buffer; 952 break; 953 default: 954 if (bp < buffer + sizeof buffer) 955 *bp++ = c; 956 } 957 /*NOTREACHED*/ 958 } 959 960 namecmp(name1, name2) 961 register char *name1, *name2; 962 { 963 register c1, c2; 964 965 for (;;) { 966 c1 = *name1++; 967 if (islower(c1)) 968 c1 = toupper(c1); 969 c2 = *name2++; 970 if (islower(c2)) 971 c2 = toupper(c2); 972 if (c1 != c2) 973 break; 974 if (c1 == 0) 975 return (1); 976 } 977 if (!c1) { 978 for (name2--; isdigit(*name2); name2++) 979 ; 980 if (*name2 == 0) 981 return (1); 982 } else if (!c2) { 983 for (name1--; isdigit(*name1); name1++) 984 ; 985 if (*name2 == 0) 986 return (1); 987 } 988 return (0); 989 } 990 991 netfinger(name) 992 char *name; 993 { 994 char *host; 995 char fname[100]; 996 struct hostent *hp; 997 struct servent *sp; 998 struct sockaddr_in sin; 999 int s; 1000 char *rindex(); 1001 register FILE *f; 1002 register int c; 1003 register int lastc; 1004 1005 if (name == NULL) 1006 return (0); 1007 host = rindex(name, '@'); 1008 if (host == NULL) 1009 return (0); 1010 *host++ = 0; 1011 hp = gethostbyname(host); 1012 if (hp == NULL) { 1013 static struct hostent def; 1014 static struct in_addr defaddr; 1015 static char *alist[1]; 1016 static char namebuf[128]; 1017 int inet_addr(); 1018 1019 defaddr.s_addr = inet_addr(host); 1020 if (defaddr.s_addr == -1) { 1021 printf("unknown host: %s\n", host); 1022 return (1); 1023 } 1024 strcpy(namebuf, host); 1025 def.h_name = namebuf; 1026 def.h_addr_list = alist, def.h_addr = (char *)&defaddr; 1027 def.h_length = sizeof (struct in_addr); 1028 def.h_addrtype = AF_INET; 1029 def.h_aliases = 0; 1030 hp = &def; 1031 } 1032 sp = getservbyname("finger", "tcp"); 1033 if (sp == 0) { 1034 printf("tcp/finger: unknown service\n"); 1035 return (1); 1036 } 1037 sin.sin_family = hp->h_addrtype; 1038 bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length); 1039 sin.sin_port = sp->s_port; 1040 s = socket(hp->h_addrtype, SOCK_STREAM, 0); 1041 if (s < 0) { 1042 perror("socket"); 1043 return (1); 1044 } 1045 printf("[%s]\n", hp->h_name); 1046 fflush(stdout); 1047 if (connect(s, (char *)&sin, sizeof (sin)) < 0) { 1048 perror("connect"); 1049 close(s); 1050 return (1); 1051 } 1052 if (large) write(s, "/W ", 3); 1053 write(s, name, strlen(name)); 1054 write(s, "\r\n", 2); 1055 f = fdopen(s, "r"); 1056 while ((c = getc(f)) != EOF) { 1057 switch(c) { 1058 case 0210: 1059 case 0211: 1060 case 0212: 1061 case 0214: 1062 c -= 0200; 1063 break; 1064 case 0215: 1065 c = '\n'; 1066 break; 1067 } 1068 lastc = c; 1069 if (isprint(c) || isspace(c)) 1070 putchar(c); 1071 else 1072 putchar(c ^ 100); 1073 } 1074 if (lastc != '\n') 1075 putchar('\n'); 1076 (void)fclose(f); 1077 return (1); 1078 } 1079