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.8 (Berkeley) 3/13/86";
  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:     printf("[%s]", hp->h_name);
1033:     sp = getservbyname("finger", "tcp");
1034:     if (sp == 0) {
1035:         printf("tcp/finger: unknown service\n");
1036:         return (1);
1037:     }
1038:     sin.sin_family = hp->h_addrtype;
1039:     bcopy(hp->h_addr, (char *)&sin.sin_addr, hp->h_length);
1040:     sin.sin_port = sp->s_port;
1041:     s = socket(hp->h_addrtype, SOCK_STREAM, 0);
1042:     if (s < 0) {
1043:         fflush(stdout);
1044:         perror("socket");
1045:         return (1);
1046:     }
1047:     if (connect(s, (char *)&sin, sizeof (sin)) < 0) {
1048:         fflush(stdout);
1049:         perror("connect");
1050:         close(s);
1051:         return (1);
1052:     }
1053:     printf("\n");
1054:     if (large) write(s, "/W ", 3);
1055:     write(s, name, strlen(name));
1056:     write(s, "\r\n", 2);
1057:     f = fdopen(s, "r");
1058:     while ((c = getc(f)) != EOF) {
1059:         switch(c) {
1060:         case 0210:
1061:         case 0211:
1062:         case 0212:
1063:         case 0214:
1064:             c -= 0200;
1065:             break;
1066:         case 0215:
1067:             c = '\n';
1068:             break;
1069:         }
1070:         lastc = c;
1071:         if (isprint(c) || isspace(c))
1072:             putchar(c);
1073:         else
1074:             putchar(c ^ 100);
1075:     }
1076:     if (lastc != '\n')
1077:         putchar('\n');
1078:     (void)fclose(f);
1079:     return (1);
1080: }

Defined functions

decode defined in line 684; used 2 times
doall defined in line 185; used 1 times
donames defined in line 241; used 1 times
findidle defined in line 831; used 2 times
findwhen defined in line 792; used 1 times
fwclose defined in line 821; used 2 times
fwopen defined in line 786; used 2 times
ltimeprint defined in line 884; used 3 times
main defined in line 125; never used
matchcmp defined in line 922; used 1 times
namecmp defined in line 960; used 1 times
netfinger defined in line 991; used 1 times
personprint defined in line 549; used 1 times
phone defined in line 626; used 2 times
print defined in line 361; used 1 times
pwdcopy defined in line 444; used 5 times
quickprint defined in line 465; used 1 times
shortprint defined in line 487; used 1 times
stimeprint defined in line 857; used 1 times

Defined variables

LASTLOG defined in line 99; used 3 times
PLAN defined in line 101; used 2 times
PROJ defined in line 102; used 2 times
USERLOG defined in line 100; used 4 times
copyright defined in line 8; never used
hack defined in line 106; used 2 times
header defined in line 105; used 2 times
idle defined in line 107; used 4 times
large defined in line 108; used 3 times
lf defined in line 116; used 6 times
match defined in line 109; used 2 times
person1 defined in line 117; used 12 times
plan defined in line 110; used 2 times
sccsid defined in line 14; never used
small defined in line 112; used 2 times
tloc defined in line 118; used 3 times
unbrief defined in line 104; used 2 times
unquick defined in line 111; used 10 times
unshort defined in line 115; used 4 times
user defined in line 76; used 22 times
wide defined in line 113; used 3 times

Defined struct's

person defined in line 81; used 38 times

Defined macros

ASTERISK defined in line 68; used 2 times
COMMA defined in line 69; used 8 times
COMMAND defined in line 70; used 1 times
CORY defined in line 71; used 1 times
EVANS defined in line 72; used 1 times
HMAX defined in line 79; used 9 times
LMAX defined in line 78; used 13 times
NMAX defined in line 77; used 7 times
SAMENAME defined in line 73; used 1 times
TALKABLE defined in line 74; used 2 times
  • in line 850(2)
TTYLEN defined in line 837; used 2 times
savestr defined in line 451; used 5 times
Last modified: 1986-03-14
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3160
Valid CSS Valid XHTML 1.0 Strict