|
|
1.1 ! root 1: #include <stdio.h> ! 2: #include <pwd.h> ! 3: #include <utmp.h> ! 4: #include <signal.h> ! 5: #include <sys/types.h> ! 6: #include <sys/stat.h> ! 7: #include <time.h> ! 8: #include <sys/timeb.h> ! 9: #include <setjmp.h> ! 10: #include <ctype.h> ! 11: #include <dir.h> ! 12: ! 13: ! 14: #define SMTP "/usr/lib/uucp/smtp" ! 15: ! 16: /*copylet flags */ ! 17: /*remote mail, add rmtmsg */ ! 18: #define REMOTE 1 ! 19: #define INTERNET 4 ! 20: /* zap header and trailing empty line */ ! 21: #define ZAP 3 ! 22: #define ORDINARY 2 ! 23: #define SENDING 5 ! 24: #define LSIZE 256 ! 25: #define MAXLET 1000 /* maximum number of letters */ ! 26: #define MAILMODE (~0644) /* mode of created mail */ ! 27: #define FLIST "/etc/forwardlist" ! 28: #define TMPNAME "/tmp/maXXXXX" ! 29: ! 30: /* definitions for inet gateways */ ! 31: struct igateway { ! 32: char *id; /* network identifier */ ! 33: char *addr; /* address translation */ ! 34: char *via; /* machine that talks to gateway */ ! 35: char *cmd; /* command for gateway */ ! 36: }; ! 37: struct igateway igates[] = { ! 38: "arpa_or_csnet", ".csnet-relay", "research", "/usr/mmdf/lib/mail", ! 39: "csnet", ".csnet.csnet-relay", "research", "/usr/mmdf/lib/mail", ! 40: "arpa", ".arpa.csnet-relay", "research", "/usr/mmdf/lib/mail", ! 41: "acsnet", "", "research", "/usr/ACSnet/bin/inject", ! 42: }; ! 43: #define NIGATES 4 ! 44: unsigned int igate; /* offset into igates (csnet by default) */ ! 45: ! 46: ! 47: char line[LSIZE]; ! 48: char resp[LSIZE]; ! 49: struct let { ! 50: long adr; ! 51: char change; ! 52: } let[MAXLET]; ! 53: int nlet = 0; ! 54: char lfil[50]; ! 55: char *stringin(); ! 56: FILE *popen(); ! 57: char *getenv(); ! 58: char tmpname[] = TMPNAME; ! 59: char lettmp[sizeof(TMPNAME)]; ! 60: char maildir[] = "/usr/spool/mail/"; ! 61: char mailfile[] = "/usr/spool/mail/xxxxxxxxxxxxxxxxxxxxxxx"; ! 62: char dead[] = "dead.letter"; ! 63: char whoami[] = "/etc/whoami"; ! 64: #define FRWRD "Forward to " ! 65: char *thissys = ""; ! 66: FILE *tmpf; ! 67: FILE *malf; ! 68: char *my_name; ! 69: char real_name[512]; ! 70: char *getlogin(); ! 71: struct passwd *getpwuid(); ! 72: char *strchr(); ! 73: int error; ! 74: int changed; ! 75: int forward; ! 76: int onatty; ! 77: char from[] = "From "; ! 78: long ftell(); ! 79: int delete(); ! 80: int savdead(); ! 81: int (*saveint)(); ! 82: int (*setsig())(); ! 83: char *strcpy(); ! 84: char *strcat(); ! 85: char *mktemp(); ! 86: char *ctime(); ! 87: long time(); ! 88: int flgf; ! 89: int flgp; ! 90: int delflg = 1; ! 91: int rflg; ! 92: int frominet; ! 93: int normtf; ! 94: jmp_buf sjbuf; ! 95: char dev[] = "/dev/"; ! 96: ! 97: void lock(), unlock(); ! 98: ! 99: main(argc, argv) ! 100: char **argv; ! 101: { ! 102: static char sobuf[BUFSIZ]; ! 103: char wsysname[32]; ! 104: int f; ! 105: char *prog; ! 106: char *basename(); ! 107: ! 108: if (argc == 2 && (argv[1][0] == '-' && argv[1][1]=='n')) { ! 109: struct stat s; ! 110: char *ttyname(); ! 111: char *p; ! 112: ! 113: fstat(2,&s); ! 114: setgid(getgid()); ! 115: setuid(getuid()); ! 116: if ((p = ttyname(2)) && *p) ! 117: chmod(p, s.st_mode ^ S_IEXEC); ! 118: exit(0); ! 119: } ! 120: prog = basename(argv[0]); ! 121: normtf = prog[0]=='r'; ! 122: frominet = prog[0]=='c'; ! 123: rflg = prog[0]=='r' || frominet; ! 124: setbuf(stdout, sobuf); ! 125: strcpy(lettmp, tmpname); ! 126: mktemp(lettmp); ! 127: unlink(lettmp); ! 128: my_name = getlogin(); ! 129: if (my_name==NULL) ! 130: my_name = "daemon"; ! 131: f = open(whoami, 0); ! 132: if (f>=0) { ! 133: wsysname[0] = '\0'; ! 134: read(f, wsysname, 32); ! 135: if (strchr(wsysname, '\n')) { ! 136: *strchr(wsysname, '\n') = '\0'; ! 137: thissys = wsysname; ! 138: } ! 139: close(f); ! 140: } ! 141: if(*thissys == 0) ! 142: fprintf(stderr, "mail: bad data from %s\n", whoami); ! 143: if(setjmp(sjbuf)) ! 144: done(); ! 145: setsig(SIGINT, delete); ! 146: setsig(SIGHUP, delete); ! 147: setsig(SIGKILL, delete); ! 148: tmpf = fopen(lettmp, "w"); ! 149: if (tmpf == NULL) { ! 150: fprintf(stderr, "mail: cannot open %s for writing\n", lettmp); ! 151: done(); ! 152: } ! 153: chmod(lettmp, 0600); ! 154: chown(lettmp, getuid(), getgid()); ! 155: if( !rflg && /* no favors for rmail*/ ! 156: (argc == 1 || (argv[1][0] == '-' && argv[1][1]!='R'))) ! 157: printmail(argc, argv); ! 158: else ! 159: sendmail(argc, argv); ! 160: done(); ! 161: } ! 162: ! 163: char * ! 164: basename(file) ! 165: char *file; ! 166: { ! 167: char *base; ! 168: char *strrchr(); ! 169: ! 170: if ((base = strrchr(file, '/')) != NULL) ! 171: base++; /* past '/' */ ! 172: else ! 173: base = file; ! 174: return (base); ! 175: } ! 176: ! 177: int (*setsig(i, f))() ! 178: int i; ! 179: int (*f)(); ! 180: { ! 181: register int (*rc)(); ! 182: ! 183: if ((rc = signal(i, SIG_IGN))!=SIG_IGN) ! 184: signal(i, f); ! 185: return(rc); ! 186: } ! 187: ! 188: sig_ign() ! 189: { ! 190: signal(SIGHUP, SIG_IGN); ! 191: signal(SIGINT, SIG_IGN); ! 192: signal(SIGQUIT, SIG_IGN); ! 193: signal(SIGTERM, SIG_IGN); ! 194: } ! 195: ! 196: printmail(argc, argv) ! 197: char **argv; ! 198: { ! 199: int flg, i, j, print; ! 200: struct stat stbuf; ! 201: char *p, *getarg(); ! 202: char fbuf[256]; ! 203: FILE *pipf; ! 204: ! 205: setgid(getgid()); ! 206: setuid(getuid()); ! 207: cat(mailfile, maildir, my_name); ! 208: for (; argc>1; argv++, argc--) { ! 209: if (argv[1][0]=='-') { ! 210: if (argv[1][1]=='p') { ! 211: flgp++; ! 212: delflg = 0; ! 213: } else if (argv[1][1]=='f') { ! 214: if (argc>=3) { ! 215: strcpy(mailfile, argv[2]); ! 216: argv++; ! 217: argc--; ! 218: } ! 219: } else if (argv[1][1]=='r') { ! 220: forward = 1; ! 221: } else { ! 222: fprintf(stderr, "mail: unknown option %c\n", argv[1][1]); ! 223: done(); ! 224: } ! 225: } else ! 226: break; ! 227: } ! 228: if (stat(mailfile, &stbuf) < 0 || stbuf.st_size == 0L) { ! 229: printf("No mail.\n"); ! 230: return; ! 231: } ! 232: malf = fopen(mailfile, "r"); ! 233: if (malf == NULL) { ! 234: fprintf(stderr, "mail: cannot read %s.\n", mailfile); ! 235: return; ! 236: } ! 237: lock(mailfile); ! 238: if(areforwarding(mailfile, fbuf)) { ! 239: printf("Your mail is being forwarded to "); ! 240: fseek(malf, (long)(sizeof(FRWRD) - 1), 0); ! 241: fgets(fbuf, sizeof(fbuf), malf); ! 242: printf("%s", fbuf); ! 243: if(getc(malf) != EOF) ! 244: printf("and your mailbox contains extra stuff\n"); ! 245: unlock(); ! 246: return; ! 247: } ! 248: copymt(malf, tmpf); ! 249: fclose(malf); ! 250: fclose(tmpf); ! 251: unlock(); ! 252: tmpf = fopen(lettmp, "r"); ! 253: ! 254: changed = 0; ! 255: print = 1; ! 256: for (i = 0; i < nlet; ) { ! 257: j = forward ? i : nlet - i - 1; ! 258: if(setjmp(sjbuf) == 0) { ! 259: if (print) ! 260: copylet(j, stdout, ORDINARY, (char *)NULL); ! 261: print = 1; ! 262: } ! 263: if (flgp) { ! 264: i++; ! 265: continue; ! 266: } ! 267: setjmp(sjbuf); ! 268: printf("? "); ! 269: fflush(stdout); ! 270: if (fgets(resp, LSIZE, stdin) == NULL) ! 271: break; ! 272: switch (resp[0]) { ! 273: ! 274: default: ! 275: printf("usage\n"); ! 276: case '?': ! 277: print = 0; ! 278: printf("q\tquit\n"); ! 279: printf("x\texit without changing mail\n"); ! 280: printf("p\tprint\n"); ! 281: printf("s[file]\tsave (default mbox)\n"); ! 282: printf("-\tprint previous\n"); ! 283: printf("d\tdelete\n"); ! 284: printf("+\tnext (no delete)\n"); ! 285: printf("m user\tmail to user\n"); ! 286: printf("! cmd\texecute cmd\n"); ! 287: break; ! 288: ! 289: case '+': ! 290: case 'n': ! 291: case '\n': ! 292: i++; ! 293: break; ! 294: case 'x': ! 295: changed = 0; ! 296: case 'q': ! 297: goto donep; ! 298: case 'p': ! 299: break; ! 300: case '^': ! 301: case '-': ! 302: if (--i < 0) ! 303: i = 0; ! 304: break; ! 305: case 'y': ! 306: case 'w': ! 307: case 's': ! 308: flg = 0; ! 309: if (resp[1] != '\n' && resp[1] != ' ') { ! 310: printf("invalid\n"); ! 311: flg++; ! 312: print = 0; ! 313: continue; ! 314: } ! 315: if (resp[1] == '\n' || resp[1] == '\0') { ! 316: p = getenv("HOME"); ! 317: if(p != 0) ! 318: cat(resp+1, p, "/mbox"); ! 319: else ! 320: cat(resp+1, "", "mbox"); ! 321: } ! 322: for (p = resp+1; (p = getarg(lfil, p)) != NULL; ) { ! 323: malf = fopen(lfil, "a"); ! 324: if (malf == NULL) { ! 325: fprintf(stderr, "mail: cannot append to %s\n", lfil); ! 326: flg++; ! 327: continue; ! 328: } ! 329: copylet(j, malf, resp[0]=='w'? ZAP: ORDINARY, ! 330: (char *)NULL); ! 331: fclose(malf); ! 332: } ! 333: if (flg) ! 334: print = 0; ! 335: else { ! 336: let[j].change = 'd'; ! 337: changed++; ! 338: i++; ! 339: } ! 340: break; ! 341: case 'm': ! 342: flg = 0; ! 343: if (resp[1] == '\n' || resp[1] == '\0') { ! 344: i++; ! 345: continue; ! 346: } ! 347: if (resp[1] != ' ') { ! 348: printf("invalid\n"); ! 349: flg++; ! 350: print = 0; ! 351: continue; ! 352: } ! 353: strcpy(fbuf, "mail "); ! 354: strcat(fbuf, resp+1); ! 355: /* fork so that mail becomes super-user again */ ! 356: pipf = popen(fbuf, "w"); ! 357: if(pipf == NULL) { ! 358: fprintf(stderr, "mail: can't fork to remail\n"); ! 359: flg++; ! 360: continue; ! 361: } ! 362: copylet(j, pipf, SENDING, (char *)NULL); ! 363: flg |= pclose(pipf); ! 364: if (flg) ! 365: print = 0; ! 366: else { ! 367: let[j].change = 'd'; ! 368: changed++; ! 369: i++; ! 370: } ! 371: break; ! 372: case '!': ! 373: system(resp+1); ! 374: printf("!\n"); ! 375: print = 0; ! 376: break; ! 377: case 'd': ! 378: let[j].change = 'd'; ! 379: changed++; ! 380: i++; ! 381: if (resp[1] == 'q') ! 382: goto donep; ! 383: break; ! 384: } ! 385: } ! 386: donep: ! 387: if (changed) ! 388: copyback(); ! 389: } ! 390: ! 391: copyback() /* copy temp or whatever back to /usr/spool/mail */ ! 392: { ! 393: register i, c; ! 394: register int new = 0; ! 395: struct stat stbuf; ! 396: ! 397: sig_ign(); ! 398: lock(mailfile); ! 399: stat(mailfile, &stbuf); ! 400: if (stbuf.st_size != let[nlet].adr) { /* new mail has arrived */ ! 401: malf = fopen(mailfile, "r"); ! 402: if (malf == NULL) { ! 403: fprintf(stderr, "mail: can't re-read %s\n", mailfile); ! 404: done(); ! 405: } ! 406: fseek(malf, let[nlet].adr, 0); ! 407: fclose(tmpf); ! 408: tmpf = fopen(lettmp, "a"); ! 409: fseek(tmpf, let[nlet].adr, 0); ! 410: while ((c = fgetc(malf)) != EOF) ! 411: fputc(c, tmpf); ! 412: fclose(malf); ! 413: fclose(tmpf); ! 414: tmpf = fopen(lettmp, "r"); ! 415: let[++nlet].adr = stbuf.st_size; ! 416: new = 1; ! 417: } ! 418: malf = fopen(mailfile, "w"); ! 419: if (malf == NULL) { ! 420: fprintf(stderr, "mail: can't rewrite %s\n", mailfile); ! 421: done(); ! 422: } ! 423: for (i = 0; i < nlet; i++) ! 424: if (let[i].change != 'd') { ! 425: copylet(i, malf, ORDINARY, (char *)NULL); ! 426: } ! 427: fclose(malf); ! 428: if (new) ! 429: printf("new mail arrived\n"); ! 430: unlock(); ! 431: } ! 432: ! 433: copymt(f1, f2) /* copy mail (f1) to temp (f2) */ ! 434: FILE *f1, *f2; ! 435: { ! 436: long nextadr; ! 437: ! 438: nlet = nextadr = 0; ! 439: let[0].adr = 0; ! 440: while (fgets(line, LSIZE, f1) != NULL) { ! 441: if (isfrom(line)) { ! 442: let[nlet++].adr = nextadr; ! 443: if (nlet > MAXLET) { ! 444: fprintf (stderr, "mail: too many letters\n"); ! 445: unlock(); ! 446: exit(1); ! 447: } ! 448: } ! 449: nextadr += strlen(line); ! 450: fputs(line, f2); ! 451: } ! 452: let[nlet].adr = nextadr; /* last plus 1 */ ! 453: } ! 454: ! 455: copylet(n, f, type, postmark) ! 456: FILE *f; ! 457: char *postmark; ! 458: { ! 459: long k; ! 460: register ch; ! 461: char *inetheader(); ! 462: ! 463: fseek(tmpf, let[n].adr, 0); ! 464: k = let[n+1].adr - let[n].adr; ! 465: if (postmark && type != ZAP) { ! 466: if (type == INTERNET) ! 467: postmark = inetheader (postmark); ! 468: fputs(postmark, f); ! 469: if (type==REMOTE) ! 470: fprintf(f, " remote from %s", thissys); ! 471: fputc('\n', f); ! 472: } ! 473: while (k>0) { ! 474: ch = fgetc(tmpf); ! 475: if (ch == EOF) ! 476: break; ! 477: fputc(ch, f); ! 478: k--; ! 479: } ! 480: } ! 481: ! 482: areforwarding(s, sendto) ! 483: char *s, *sendto; ! 484: { ! 485: FILE *fd; ! 486: char fbuf[64], *p, *sp; ! 487: ! 488: fd = fopen(s, "r"); ! 489: if(fd == NULL) ! 490: return(0); ! 491: fbuf[0] = '\0'; ! 492: fgets(fbuf, sizeof(fbuf), fd); ! 493: if (p = stringin(FRWRD, fbuf)) { ! 494: while (*p == ' ') ! 495: p++; ! 496: sp = sendto; ! 497: while (*p && *p!='\n') ! 498: *sp++ = *p++; ! 499: *sp = '\0'; ! 500: fclose(fd); ! 501: return(*sendto != 0); ! 502: } ! 503: fclose(fd); ! 504: return(0); ! 505: } ! 506: ! 507: isfrom(lp) ! 508: register char *lp; ! 509: { ! 510: return(strncmp(lp, from, 5)==0); ! 511: } ! 512: ! 513: sendmail(argc, argv) ! 514: char **argv; ! 515: { ! 516: char *asctime(); ! 517: struct timeb timbuf; ! 518: struct tm *bp, *localtime(); ! 519: char *tp, *zp, postmark[512]; ! 520: char *timezone(); ! 521: int rrrflg=0; ! 522: long newpost(); ! 523: ! 524: while (argv[1][0]=='-') { ! 525: switch(argv[1][1]) { ! 526: case 'R': /* return receipt */ ! 527: rrrflg = 1; ! 528: } ! 529: argc--; argv++; ! 530: } ! 531: ftime(&timbuf); ! 532: bp = localtime(&timbuf.time); ! 533: tp = asctime(bp); ! 534: zp = timezone(timbuf.timezone, bp->tm_isdst); ! 535: onatty = isatty(0); ! 536: sprintf(postmark, "%s%s %.16s %.3s %.4s%s",from, my_name, tp, zp, tp+20, ! 537: rrrflg?" (RRR)":""); ! 538: flgf = 1; ! 539: saveint = setsig(SIGINT, savdead); ! 540: while (fgets(line, LSIZE, stdin) != NULL) { ! 541: if (line[0] == '.' && line[1] == '\n' && onatty) ! 542: break; ! 543: if (isfrom(line)) ! 544: fputs(">", tmpf); ! 545: fputs(line, tmpf); ! 546: flgf = 0; ! 547: } ! 548: setsig(SIGINT, saveint); ! 549: if (line[0]!='\n' && error==0) ! 550: fputs("\n", tmpf); ! 551: nlet = 1; ! 552: let[0].adr = 0; ! 553: let[1].adr = ftell(tmpf); ! 554: fclose(tmpf); ! 555: if (flgf) ! 556: return; ! 557: tmpf = fopen(lettmp, "r"); ! 558: if (tmpf == NULL) { ! 559: fprintf(stderr, "mail: cannot reopen %s for reading\n", lettmp); ! 560: return; ! 561: } ! 562: let[0].adr = newpost(postmark); ! 563: if (error == 0) ! 564: while (--argc > 0) { ! 565: if (!send(0, *++argv, 0, postmark)) ! 566: error++; ! 567: } ! 568: if (error && onatty) { ! 569: setgid(getgid()); ! 570: setuid(getuid()); ! 571: malf = fopen(dead, "w"); ! 572: if (malf == NULL) { ! 573: fprintf(stderr, "mail: cannot open %s\n", dead); ! 574: fclose(tmpf); ! 575: return; ! 576: } ! 577: copylet(0, malf, ZAP, (char *)NULL); ! 578: fclose(malf); ! 579: printf("Mail saved in %s\n", dead); ! 580: } ! 581: fclose(tmpf); ! 582: } ! 583: ! 584: long ! 585: newpost(pm) ! 586: char *pm; ! 587: { ! 588: long inetpost(), unixpost(); ! 589: if (frominet) ! 590: return inetpost(pm); ! 591: else ! 592: return unixpost(pm); ! 593: } ! 594: ! 595: long ! 596: inetpost(pm) ! 597: char *pm; ! 598: { ! 599: char line[512], date[64], *lp; ! 600: ! 601: /* get default source and date */ ! 602: lp = strchr(pm+5, ' '); ! 603: strcpy(date, lp); ! 604: ! 605: /* RFC 822 (or similar) */ ! 606: /* construct the "From " line from the "From: " line */ ! 607: while (fgets(line, sizeof(line), tmpf) != NULL) { ! 608: line[strlen(line)-1] = '\0'; ! 609: ! 610: /* pick up from field */ ! 611: if (strncmp("From: ", line, 6) == 0) { ! 612: lp = strchr(line+6, ' '); ! 613: if (lp) ! 614: *lp = '\0'; ! 615: sprintf(pm, "From %s", line+6); ! 616: } ! 617: ! 618: /* pick up date field */ ! 619: if (strncmp("Date: ", line, 6) == 0) ! 620: strcpy(date, line+5); ! 621: ! 622: /* stop if we're out of header */ ! 623: if (strchr(line, ':') == NULL && line[0] != ' ' ! 624: && line[0] != '\t') ! 625: break; ! 626: } ! 627: strcpy(real_name, pm+5); ! 628: strcat(pm, date); ! 629: return(0); ! 630: } ! 631: ! 632: long ! 633: unixpost(pm) ! 634: char *pm; ! 635: { ! 636: long n = 0; ! 637: char line[512], *cp, *lp; ! 638: char rmtlist[512]; ! 639: ! 640: /* UNIX mail */ ! 641: /* construct the "From " line from the existing ones */ ! 642: rmtlist[0] = '\0'; ! 643: while (fgets(line, sizeof(line), tmpf) != NULL) { ! 644: ! 645: /* stop if we run out of header */ ! 646: if (stringin("From ", line)==NULL ! 647: && stringin(">From ", line)==NULL) ! 648: break; ! 649: if ((cp = stringin(" remote from ", line))==NULL) ! 650: break; ! 651: ! 652: /* get name of remote system and add to rmtlist */ ! 653: line[strlen(line)-1] = '\0'; ! 654: if (okrmt(cp) && n==0) ! 655: normtf = 0; ! 656: *(cp - sizeof(" remote from ") + 1) = '\0'; ! 657: strcpy(pm, line[0] == '>' ? line + 1 : line); ! 658: strcat(rmtlist, cp); ! 659: strcat(rmtlist, "!"); ! 660: n = ftell(tmpf); ! 661: } ! 662: ! 663: /* tack sender's name and date onto the list of remote machines */ ! 664: strcpy(line, pm); ! 665: sprintf(pm, "From %s%s", rmtlist, line+5); ! 666: if ((cp = strchr(line+5, ' ')) != NULL) ! 667: *cp = '\0'; ! 668: sprintf(real_name, "%s%s", rmtlist, line+5); ! 669: return(n); ! 670: } ! 671: ! 672: char * ! 673: stringin(str, line) ! 674: char *str, *line; ! 675: { ! 676: register char *sp, *lp; ! 677: ! 678: while (*line) { ! 679: sp = str; ! 680: lp = line++; ! 681: for (;;) { ! 682: if (*sp != *lp) { ! 683: if (*sp=='\0') ! 684: return(lp); ! 685: break; ! 686: } ! 687: sp++; ! 688: lp++; ! 689: } ! 690: } ! 691: return(NULL); ! 692: } ! 693: ! 694: /* ! 695: * Return nonzero if forwarding is allowed to the system ! 696: * named in the string at "cp". If we can't read the file ! 697: * which contains the systems, assume blanket forwarding. ! 698: */ ! 699: okrmt(cp) ! 700: char *cp; ! 701: { ! 702: register FILE *fp; ! 703: char buf[20]; ! 704: ! 705: /* try to open the file; allow forwarding on failure */ ! 706: fp = fopen (FLIST, "r"); ! 707: if (fp == NULL) ! 708: return 1; ! 709: ! 710: /* one iteration per system name in the file */ ! 711: while (fgets (buf, sizeof buf, fp) != NULL) { ! 712: buf[strlen(buf)-1] = '\0'; ! 713: if (strcmp (buf, cp) == 0) { ! 714: /* found it, allow forwarding */ ! 715: fclose (fp); ! 716: return 1; ! 717: } ! 718: } ! 719: ! 720: /* didn't find it, prohibit forwarding */ ! 721: fclose (fp); ! 722: return 0; ! 723: } ! 724: ! 725: savdead() ! 726: { ! 727: setsig(SIGINT, saveint); ! 728: error++; ! 729: } ! 730: ! 731: sendrmt(n, name, postmark) ! 732: char *name, *postmark; ! 733: { ! 734: FILE *rmf; ! 735: register char *p, *q, *rmtid; ! 736: char cmd[512], buf[512]; ! 737: static forked; ! 738: ! 739: strcpy(buf, name); ! 740: rmtid = strchr(name, '!'); ! 741: if (rmtid == NULL || rmtid[1]=='\0') { ! 742: fprintf(stderr, "mail: bad remote name\n"); ! 743: return(0); ! 744: } ! 745: *rmtid++ = '\0'; ! 746: if (normtf) ! 747: for (p = q = &buf[0]; (p = strchr(q, '!')) && p[1] != '\0'; ! 748: q = p + 1) { ! 749: *p = '\0'; ! 750: if (!okrmt(q)) { ! 751: *--rmtid = '!'; ! 752: refuse(n, name, postmark, ! 753: "forwarding to this system disallowed"); ! 754: return(1); ! 755: } ! 756: } ! 757: if(onatty & !forked) { /* fork off remote send to avoid user tedium */ ! 758: int p = fork(); ! 759: if(p == 0) { ! 760: sig_ign(); ! 761: forked = 1; ! 762: } else if(p != -1) ! 763: exit(0); ! 764: } ! 765: if(access(SMTP, 0) != -1){ ! 766: sprintf(cmd, "exec %s %s %s", SMTP, name, rmtid); ! 767: if((rmf = popen(cmd, "w")) != NULL){ ! 768: copylet(n, rmf, REMOTE, postmark); ! 769: if(pclose(rmf) == 0) return(1); ! 770: } ! 771: } ! 772: sprintf(cmd, "exec /usr/bin/uux - -a %s %s!rmail \\(%s\\)", ! 773: real_name, name, rmtid); ! 774: if ((rmf=popen(cmd, "w")) == NULL) { ! 775: fprintf(stderr, "mail: can't pipe to uux\n"); ! 776: exit(1); ! 777: } ! 778: copylet(n, rmf, REMOTE, postmark); ! 779: *--rmtid = '!'; ! 780: logsend(name, postmark, "remote"); ! 781: return(pclose(rmf)==0); ! 782: } ! 783: ! 784: ! 785: ! 786: send(n, name, level, postmark) /* send letter n to name */ ! 787: int n; ! 788: char *name, *postmark; ! 789: { ! 790: char file[512]; ! 791: register mask; ! 792: struct passwd *pw, *getpwnam(); ! 793: struct stat stbuf; ! 794: char sendto[256]; ! 795: char inetaddr[256]; ! 796: int exists; ! 797: ! 798: ! 799: if(level > 20) { ! 800: fprintf(stderr, "mail: unbounded forwarding\n"); ! 801: return(0); ! 802: } ! 803: if (strcmp(name, "-") == 0) ! 804: return(1); ! 805: if (strchr(name, '!')) ! 806: return(sendrmt(n, name, postmark)); ! 807: if (strchr(name, '/')) { ! 808: fprintf(stderr, "mail: illegal name %s\n", name); ! 809: return(0); ! 810: } ! 811: cat(file, maildir, name); ! 812: if(areforwarding(file, sendto)) { ! 813: int rf, sval; ! 814: rf = normtf; ! 815: normtf = 0; /* to permit transshipping */ ! 816: sval = send(n, sendto, level+1, postmark); ! 817: normtf = rf; ! 818: return(sval); ! 819: } ! 820: exists = stat(file, &stbuf); ! 821: if ((pw = getpwnam(name)) == NULL) { ! 822: if (exists < 0) { ! 823: (void)strcpy (inetaddr, name); ! 824: if (isinet(inetaddr)) { ! 825: if (strcmp (thissys, igates[igate].via) == 0) { ! 826: (void)inetgateaddr(inetaddr); ! 827: return(sendinet(n,inetaddr,postmark)); ! 828: } else { ! 829: (void)strcpy (sendto, igates[igate].via); ! 830: (void)strcat (sendto, "!"); ! 831: (void)strcat (sendto, name); ! 832: return(sendrmt(n, sendto, postmark)); ! 833: } ! 834: } ! 835: if (rflg) { ! 836: refuse(n, name, postmark, ! 837: "addressee unknown"); ! 838: return(1); ! 839: } ! 840: fprintf(stderr, "mail: can't send to %s\n", name); ! 841: return(0); ! 842: } ! 843: } else { ! 844: stbuf.st_uid = pw->pw_uid; ! 845: stbuf.st_gid = pw->pw_gid; ! 846: } ! 847: mask = umask(MAILMODE); ! 848: lock(file); ! 849: malf = fopen(file, "a"); ! 850: umask(mask); ! 851: if (malf == NULL) { ! 852: fprintf(stderr, "mail: cannot append to %s\n", file); ! 853: return(0); ! 854: } ! 855: if (exists < 0) ! 856: chown(file, stbuf.st_uid, stbuf.st_gid); ! 857: copylet(n, malf, SENDING, postmark); ! 858: fclose(malf); ! 859: unlock(); ! 860: logsend(name, postmark, "delivered"); ! 861: notify(name); /* let him know it right away! */ ! 862: return(1); ! 863: } ! 864: ! 865: notify(name) ! 866: char *name; ! 867: { ! 868: struct utmp entry; ! 869: FILE *f; ! 870: ! 871: if ((f = fopen("/etc/utmp", "r")) == NULL) ! 872: return; ! 873: while (fread((char *)&entry, sizeof(entry), 1, f) == 1) { ! 874: if (strncmp(name, entry.ut_name, sizeof(entry.ut_name)) == 0) ! 875: blurb(entry.ut_line); ! 876: } ! 877: fclose(f); ! 878: } ! 879: ! 880: blurb(tty) ! 881: char *tty; ! 882: { ! 883: FILE *f = NULL; ! 884: struct stat s; ! 885: int blurbtime(); ! 886: char devtty[32]; ! 887: ! 888: cat(devtty, dev, tty); ! 889: signal(SIGALRM, blurbtime); ! 890: alarm(30); ! 891: stat(devtty, &s); ! 892: if (s.st_mode & S_IEXEC) /* notify only if enabled */ ! 893: if ((f = fopen(devtty, "w")) != NULL) { ! 894: fprintf(f, "\r\n[%s: mail from %s]\r\n\7", thissys, ! 895: real_name[0]?real_name: my_name); ! 896: } ! 897: if (f) ! 898: fclose(f); ! 899: alarm(0); ! 900: } ! 901: ! 902: blurbtime() ! 903: { ! 904: } ! 905: ! 906: refuse(n, name, postmark, reason) ! 907: char *name, *postmark, *reason; ! 908: { ! 909: FILE *pf; ! 910: char cbuf[256], *cp; ! 911: ! 912: cp = strchr(postmark+5, ' '); ! 913: if (cp == NULL) ! 914: return; ! 915: *cp = '\0'; ! 916: sprintf(cbuf, "PATH=/bin:/usr/bin mail %s", postmark+5); ! 917: *cp = ' '; ! 918: if ((pf = popen(cbuf, "w")) == NULL) ! 919: return; ! 920: fprintf(pf, "Mail to %s failed: %s. Message was:\n", name, reason); ! 921: copylet(n, pf, SENDING, postmark); ! 922: pclose(pf); ! 923: } ! 924: ! 925: delete(i) ! 926: { ! 927: setsig(i, delete); ! 928: fprintf(stderr, "\n"); ! 929: if(delflg) ! 930: longjmp(sjbuf, 1); ! 931: done(); ! 932: } ! 933: ! 934: done() ! 935: { ! 936: unlock(); ! 937: unlink(lettmp); ! 938: exit(error); ! 939: } ! 940: ! 941: ! 942: #define LOCKPREFIX "/tmp/L." ! 943: char lockname[DIRSIZ+sizeof(LOCKPREFIX)]; ! 944: ! 945: /* Lock the given file. The parameter "file" must contain at least one '/'. */ ! 946: void ! 947: lock(file) ! 948: char *file; ! 949: { ! 950: # define TMPLNAME "/tmp/mlXXXXX" ! 951: # define LOCKPREFIX "/tmp/L." ! 952: char tmplname[sizeof(TMPLNAME)]; ! 953: struct stat stbuf; ! 954: int fd; ! 955: ! 956: /* return if we are already in the middle of a lock */ ! 957: if (*lockname != '\0' || flgf) ! 958: return; ! 959: ! 960: /* create a temporary file */ ! 961: strcpy(tmplname, TMPLNAME); ! 962: mktemp(tmplname); ! 963: if ((fd=creat(tmplname, 0444))<0) ! 964: return; ! 965: close(fd); ! 966: ! 967: /* Make a link to it with the lock file name. This will fail only ! 968: * if it already exists. ! 969: */ ! 970: strcpy(lockname, LOCKPREFIX); ! 971: strcat(lockname, strrchr(file, '/')+1); ! 972: lockname[DIRSIZ+sizeof("/tmp/")-1] = '\0'; ! 973: while (link(tmplname, lockname) < 0) { ! 974: long now; ! 975: ! 976: /* File is already locked. Break it if the lock is old. */ ! 977: sleep(2); ! 978: now = time((long *)0); ! 979: if (stat(lockname, &stbuf)==0 && stbuf.st_ctime+60 < now) { ! 980: if (stat(file, &stbuf)==0 && stbuf.st_mtime+60 >= now) ! 981: continue; ! 982: fprintf(stderr, "mail: breaking lock\n"); ! 983: unlink(lockname); ! 984: } ! 985: } ! 986: unlink(tmplname); ! 987: return; ! 988: } ! 989: ! 990: void ! 991: unlock() ! 992: { ! 993: if (*lockname != '\0') ! 994: unlink(lockname); ! 995: *lockname = '\0'; ! 996: } ! 997: ! 998: cat(to, from1, from2) ! 999: char *to, *from1, *from2; ! 1000: { ! 1001: strcpy(to, from1); ! 1002: strcat(to, from2); ! 1003: } ! 1004: ! 1005: char *getarg(s, p) /* copy p... into s, update p */ ! 1006: register char *s, *p; ! 1007: { ! 1008: while (*p == ' ' || *p == '\t') ! 1009: p++; ! 1010: if (*p == '\n' || *p == '\0') ! 1011: return(NULL); ! 1012: while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') ! 1013: *s++ = *p++; ! 1014: *s = '\0'; ! 1015: return(p); ! 1016: } ! 1017: ! 1018: ! 1019: /* is this an internet address (characterized by "@" or ".") */ ! 1020: isinet(string) ! 1021: char *string; ! 1022: { ! 1023: char *rindex(); ! 1024: ! 1025: return rindex(string, '@') != 0 || rindex(string, '.') != 0; ! 1026: } ! 1027: ! 1028: /* add any gateway info to the address */ ! 1029: inetgateaddr(string) ! 1030: char *string; ! 1031: { ! 1032: char *at, *dot; ! 1033: char *rindex(); ! 1034: ! 1035: /* find last "." or "@" */ ! 1036: at = rindex (string, '@'); ! 1037: if (at != 0) ! 1038: dot = rindex (at + 1, '.'); ! 1039: else ! 1040: dot = rindex (string, '.'); ! 1041: if (dot != 0) ! 1042: at = dot; ! 1043: ! 1044: for (igate=0; igate<NIGATES; igate++) { ! 1045: if (istrcmp(at+1, igates[igate].id) == 0) { ! 1046: strcpy(at, igates[igate].addr); ! 1047: break; ! 1048: } ! 1049: } ! 1050: if (igate == NIGATES) { ! 1051: igate = 0; /* csnet or arpa, we really don't know */ ! 1052: strcat(string, igates[igate].addr); ! 1053: } ! 1054: } ! 1055: ! 1056: /* case insensitive strcmp */ ! 1057: istrcmp(p1, p2) ! 1058: char *p1, *p2; ! 1059: { ! 1060: do { ! 1061: if (tolower(*p1) != tolower(*p2)) ! 1062: return *p1 - *p2; ! 1063: p2++; ! 1064: } while (*p1++ != 0); ! 1065: ! 1066: return 0; ! 1067: } ! 1068: ! 1069: /* log a mail transmission */ ! 1070: logsend (to, pm, tag) ! 1071: char *to; /* receiver */ ! 1072: char *pm; /* the postmark */ ! 1073: char *tag; /* type of mail */ ! 1074: { ! 1075: # include <grp.h> ! 1076: # define LOGFILE "/usr/spool/mail/mail.log" ! 1077: # define LOGTEMP "/usr/spool/mail/mail.tmp" ! 1078: char buf[BUFSIZ]; ! 1079: int out, in; ! 1080: long len; ! 1081: struct stat sbuf; ! 1082: struct group sysgroup; ! 1083: struct group *getgrnam(); ! 1084: ! 1085: lock(LOGFILE); ! 1086: ! 1087: /* append to log */ ! 1088: if (stat(LOGFILE, &sbuf) < 0) { ! 1089: out = creat(LOGFILE, 0660); ! 1090: } else if (sbuf.st_size < 32000) { ! 1091: out = open(LOGFILE, 2); ! 1092: } else { ! 1093: out = creat(LOGTEMP, 0660); ! 1094: in = open(LOGFILE, 0); ! 1095: if (out >= 0 && in >= 0 && lseek(in, -4000L, 2) >= 0) { ! 1096: while ((len = read(in, buf, BUFSIZ)) > 0) ! 1097: (void)write(out, buf, len); ! 1098: close(in); ! 1099: close(out); ! 1100: unlink(LOGFILE); ! 1101: link(LOGTEMP, LOGFILE); ! 1102: unlink(LOGTEMP); ! 1103: } else { ! 1104: close(in); ! 1105: close(out); ! 1106: } ! 1107: ! 1108: out = open(LOGFILE, 2); ! 1109: } ! 1110: sprintf (buf, "%s %s %s\n", tag, to, pm); ! 1111: (void)lseek(out, 0, 2); ! 1112: (void)write(out, buf, strlen(buf)); ! 1113: close(out); ! 1114: ! 1115: unlock (); ! 1116: } ! 1117: ! 1118: /* ! 1119: * Stuff for INTERNET headers ! 1120: */ ! 1121: ! 1122: char * ! 1123: inetheader (pm) ! 1124: char *pm; ! 1125: { ! 1126: static char buf[256]; ! 1127: char *sender, *date; ! 1128: char *field[6]; ! 1129: int i; ! 1130: ! 1131: /* skip the old from field */ ! 1132: pm += strlen (from); ! 1133: ! 1134: /* skip over the sender */ ! 1135: for(sender=pm; !isspace(*sender) && *sender!=NULL; sender++) ! 1136: ; ! 1137: date = *sender == '\0' ? sender : sender+1; ! 1138: ! 1139: /* reverse the path and replace '!'s with '.'s */ ! 1140: (void)strcpy (buf, "From: "); ! 1141: while (sender >= pm) { ! 1142: for (*sender = NULL; sender >= pm && *sender != '!'; sender--) ! 1143: ; ! 1144: (void)strcat (buf, sender + 1); ! 1145: (void)strcat (buf, "."); ! 1146: } ! 1147: (void)strcat (buf, "btl."); ! 1148: ! 1149: /* change an asctime date to an INTERNET style one (yech!) */ ! 1150: /* parse the old date */ ! 1151: for (i = 0; i < 6; i++) { ! 1152: for (; isspace(*date) || *date==',' || *date=='-'; date++) ! 1153: ; ! 1154: field[i] = date; ! 1155: for (; !isspace(*date) && *date!=',' && *date!='-' && *date!='\0'; date++) ! 1156: ; ! 1157: if (*date != '\0') ! 1158: *date++ = '\0'; ! 1159: } ! 1160: ! 1161: /* output the arpa type format */ ! 1162: pm = buf + strlen (buf) - 1; ! 1163: sprintf (pm, "\nDate: %s %s %s %s %s\n", field[2], field[1], ! 1164: field[5], field[3], field[4]); ! 1165: return buf; ! 1166: } ! 1167: ! 1168: sendinet(n, name, postmark) ! 1169: char *name, *postmark; ! 1170: { ! 1171: FILE *rmf; ! 1172: char cmd[512], buf[512]; ! 1173: static forked; ! 1174: ! 1175: if (normtf) { ! 1176: refuse(n, name, postmark, "forwarding to this system disallowed"); ! 1177: return(1); ! 1178: } ! 1179: if(onatty & !forked) { ! 1180: int p = fork(); ! 1181: if(p == 0) { ! 1182: sig_ign(); ! 1183: forked = 1; ! 1184: } else if(p != -1) ! 1185: exit(0); ! 1186: } ! 1187: #ifndef DEBUG ! 1188: sprintf(cmd, "exec %s %s", igates[igate].cmd, name); ! 1189: #else ! 1190: sprintf(cmd, "echo %s %s; cat", igates[igate].cmd, name); ! 1191: #endif DEBUG ! 1192: if ((rmf=popen(cmd, "w")) == NULL) { ! 1193: fprintf(stderr, "mail: can't pipe to %s\n", igates[igate].cmd); ! 1194: exit(1); ! 1195: } ! 1196: copylet(n, rmf, INTERNET, postmark); ! 1197: logsend(name, postmark, igates[igate].id); ! 1198: return(pclose(rmf)==0); ! 1199: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.