|
|
1.1 ! root 1: #include <stdio.h> ! 2: #include <regexp.h> ! 3: #include <signal.h> ! 4: #include "mail.h" ! 5: #include "string.h" ! 6: #include "message.h" ! 7: #include "dest.h" ! 8: #include "aux.h" ! 9: #include "process.h" ! 10: ! 11: /* globals to all files */ ! 12: int rmail = 0; ! 13: int onatty = 0; ! 14: char *thissys; ! 15: int nflg = 0; ! 16: int debug = 0; ! 17: ! 18: #define PIPETIMELIMIT (2*60) ! 19: ! 20: /* global to this file */ ! 21: static string *errstr; ! 22: static message *mp; ! 23: static int interrupt; ! 24: static char stderrbuf[BUFSIZ]; ! 25: static int savemail; ! 26: ! 27: /* imports (other than in .h's) */ ! 28: extern int nsysfile; ! 29: extern void exit(); ! 30: extern FILE* lockopen(); ! 31: ! 32: /* interrupt handling */ ! 33: SIGRETURN ! 34: catch_int(s) ! 35: int s; ! 36: { ! 37: signal(SIGINT, catch_int); ! 38: interrupt = 1; ! 39: } ! 40: ! 41: /* save the mail and go away */ ! 42: SIGRETURN ! 43: save_on_int(s) ! 44: int s; ! 45: { ! 46: cleanlocks(); ! 47: save_mail(mp); ! 48: exit(1); ! 49: } ! 50: ! 51: /* save the mail and go away */ ! 52: SIGRETURN ! 53: die_on_quit(s) ! 54: int s; ! 55: { ! 56: cleanlocks(); ! 57: exit(1); ! 58: } ! 59: ! 60: main(ac, av) ! 61: int ac; ! 62: char *av[]; ! 63: { ! 64: int i,j; ! 65: dest *dp=NULL; ! 66: int checkforward; ! 67: SIG_TYP fint, fquit, fhup; ! 68: char *base; ! 69: int rv; ! 70: ! 71: /* process args */ ! 72: setbuf(stderr, stderrbuf); ! 73: for (i = 1; i < ac; i++) { ! 74: if (av[i][0] == '-') { ! 75: for(j=1; av[i][j]; j++) ! 76: /* option */ ! 77: switch (av[i][1]) { ! 78: case '#': ! 79: nflg = 1; ! 80: break; ! 81: case 'd': ! 82: debug = 1; ! 83: break; ! 84: default: ! 85: fprintf(stderr, "usage: mail [-#] list-of-addresses\n"); ! 86: exit(1); ! 87: } ! 88: } else ! 89: /* destination */ ! 90: d_insert(&dp, d_new(s_copy(av[i]))); ! 91: } ! 92: if (dp == NULL) { ! 93: fprintf(stderr, "usage: mail [-#] address-list\n"); ! 94: exit(1); ! 95: } ! 96: ! 97: /* ! 98: * get context: ! 99: * - whether we're rmail or mail ! 100: * - whether on a tty ! 101: */ ! 102: base = basename(av[0]); ! 103: checkforward = rmail = strcmp(base, "rmail")==0; ! 104: onatty = (!rmail) && isatty(0); ! 105: thissys = sysname_read(); ! 106: if (!nflg) { ! 107: if ((fint=signal(SIGINT, SIG_IGN))!=SIG_DFL) ! 108: signal(SIGINT, fint); ! 109: else ! 110: signal(SIGINT, fint = (SIG_TYP)catch_int); ! 111: if ((fquit=signal(SIGQUIT, SIG_IGN))!=SIG_DFL) ! 112: signal(SIGQUIT, fquit); ! 113: else ! 114: signal(SIGQUIT, die_on_quit); ! 115: if ((fhup=signal(SIGHUP, SIG_IGN))!=SIG_DFL) ! 116: signal(SIGHUP, fhup); ! 117: else ! 118: signal(SIGHUP, fhup = (SIG_TYP)catch_int); ! 119: ! 120: mp = m_read(stdin, rmail, onatty); ! 121: if (mp == NULL) ! 122: exit(0); ! 123: if (interrupt != 0) { ! 124: save_mail(mp); ! 125: exit(1); ! 126: } ! 127: ! 128: if (fint==(SIG_TYP)catch_int) ! 129: signal(SIGINT, save_on_int); ! 130: if (fhup==(SIG_TYP)catch_int) ! 131: signal(SIGHUP, save_on_int); ! 132: } else { ! 133: mp = m_new(); ! 134: default_from(mp); ! 135: } ! 136: errstr = s_new(); ! 137: (void)getrules(); ! 138: ! 139: /* ! 140: * If this is a gateway, translate the sender address into a local ! 141: * address. This only happens if mail to the local address is ! 142: * forwarded to the sender. ! 143: */ ! 144: gateway(mp); ! 145: ! 146: /* ! 147: * Protect against shell characters in the sender name for ! 148: * security reasons. ! 149: */ ! 150: s_restart(mp->sender); ! 151: if (shellchars(s_to_c(mp->sender))) ! 152: mp->replyaddr = s_copy("postmaster"); ! 153: else ! 154: mp->replyaddr = s_clone(mp->sender); ! 155: s_restart(mp->replyaddr); ! 156: ! 157: /* ! 158: * reject messages that are too long. We don't do it earlier ! 159: * in m_read since we haven't set up enough things yet. ! 160: */ ! 161: if(mp->size < 0) ! 162: return refuse(dp, mp, "message too long", 0); ! 163: ! 164: rv = send(dp, mp, checkforward); ! 165: if(savemail) ! 166: save_mail(mp); ! 167: return rv; ! 168: } ! 169: ! 170: ! 171: /* send a message to a list of sites */ ! 172: int ! 173: send(destp, mp, checkforward) ! 174: dest *destp; ! 175: message *mp; ! 176: { ! 177: dest *dp; /* destination being acted upon */ ! 178: dest *bound; /* bound destinations */ ! 179: int errors=0; ! 180: static int forked; ! 181: extern dest *up_bind(); ! 182: ! 183: /* bind the destinations to actions */ ! 184: bound = up_bind(destp, mp, checkforward); ! 185: ! 186: /* loop through and execute commands */ ! 187: for (dp = d_rm(&bound); dp != NULL; dp = d_rm(&bound)) { ! 188: switch (dp->status) { ! 189: case d_cat: ! 190: errors += cat_mail(dp, mp); ! 191: break; ! 192: case d_pipeto: ! 193: case d_pipe: ! 194: if (!rmail && !nflg && !forked) { ! 195: forked = 1; ! 196: lesstedious(); ! 197: } ! 198: errors += pipe_mail(dp, mp, dp->status==d_pipeto); ! 199: break; ! 200: default: ! 201: errors += complain_mail(dp, mp); ! 202: break; ! 203: } ! 204: } ! 205: ! 206: return errors; ! 207: } ! 208: ! 209: /* avoid user tedium (as Mike Lesk said in a previous version) */ ! 210: lesstedious() ! 211: { ! 212: int i; ! 213: ! 214: switch(fork()){ ! 215: case -1: ! 216: onatty = 0; ! 217: break; ! 218: case 0: ! 219: signal(SIGHUP, SIG_IGN); ! 220: signal(SIGINT, SIG_IGN); ! 221: signal(SIGQUIT, SIG_IGN); ! 222: signal(SIGTERM, SIG_IGN); ! 223: setpgrp(getpid()); ! 224: for(i=0; i<nsysfile; i++) ! 225: close(i); ! 226: onatty = 0; ! 227: savemail=0; ! 228: break; ! 229: default: ! 230: exit(0); ! 231: } ! 232: } ! 233: ! 234: ! 235: /* save the mail */ ! 236: save_mail(mp) ! 237: message *mp; ! 238: { ! 239: FILE *fp; ! 240: string *file=s_new(); ! 241: char *home; ! 242: static saved = 0; ! 243: int uid, gid; ! 244: extern char *getenv(); ! 245: ! 246: setuid(uid=getuid()); ! 247: setgid(gid=getgid()); ! 248: if ((home = getenv("HOME")) == NULL) ! 249: return; ! 250: s_append(file, home); ! 251: s_append(file, "/dead.letter"); ! 252: if ((fp = lockopen(s_to_c(file), "w", MBOXMODE, uid, gid)) == NULL) ! 253: return; ! 254: m_bprint(mp, fp); ! 255: lockclose(fp); ! 256: fprintf(stderr, "saved in %s\n", s_to_c(file)); ! 257: } ! 258: ! 259: /* remember the interrupt happened */ ! 260: /* dispose of incorrect addresses */ ! 261: complain_mail(dp, mp) ! 262: dest *dp; ! 263: message *mp; ! 264: { ! 265: char *msg; ! 266: ! 267: switch (dp->status) { ! 268: case d_undefined: ! 269: msg = "Invalid address"; /* a little different, for debugging */ ! 270: break; ! 271: case d_syntax: ! 272: msg = "invalid address"; ! 273: break; ! 274: case d_unknown: ! 275: msg = "unknown user"; ! 276: break; ! 277: case d_eloop: ! 278: case d_loop: ! 279: msg = "forwarding loop"; ! 280: break; ! 281: case d_noforward: ! 282: if(dp->pstat && *s_to_c(dp->repl2)) ! 283: return refuse(dp, mp, s_to_c(dp->repl2), dp->pstat); ! 284: else ! 285: msg = "destination unknown or forwarding disallowed"; ! 286: break; ! 287: case d_pipe: ! 288: msg = "broken pipe"; ! 289: break; ! 290: case d_cat: ! 291: msg = "broken cat"; ! 292: break; ! 293: case d_translate: ! 294: if(dp->pstat && *s_to_c(dp->repl2)) ! 295: return refuse(dp, mp, s_to_c(dp->repl2), dp->pstat); ! 296: else ! 297: msg = "name translation failed"; ! 298: break; ! 299: case d_alias: ! 300: msg = "broken alias"; ! 301: break; ! 302: case d_badmbox: ! 303: msg = "corrupted mailbox"; ! 304: break; ! 305: case d_resource: ! 306: msg = "out of some resource. Try again later."; ! 307: break; ! 308: } ! 309: if (nflg) { ! 310: printf("%s: %s\n", msg, s_to_c(dp->addr)); ! 311: return 1; ! 312: } ! 313: return refuse(dp, mp, msg, 0); ! 314: } ! 315: ! 316: static process *pp; ! 317: static int timedout; ! 318: ! 319: SIGRETURN ! 320: times_up() { ! 321: kill(pp->pid, SIGKILL); ! 322: timedout = 1; ! 323: } ! 324: ! 325: /* dispose of remote addresses */ ! 326: pipe_mail(dp, mp, pipeto) ! 327: dest *dp; ! 328: message *mp; ! 329: int pipeto; ! 330: { ! 331: string *file; ! 332: FILE *fp; ! 333: dest *next, *list=NULL; ! 334: string *cmd; ! 335: int status; ! 336: string *errstr=s_new(); ! 337: char *mbox; ! 338: ! 339: /* ! 340: * collect the arguments ! 341: */ ! 342: file = s_new(); ! 343: mbox = s_to_c(dp->addr); ! 344: if (strncmp (mbox, "local!", 6) == 0) ! 345: mbox += 6; ! 346: abspath(mbox, MAILROOT, file); ! 347: next = d_rm_same(&dp); ! 348: cmd = s_clone(s_restart(next->repl1)); ! 349: for(; next != NULL; next = d_rm_same(&dp)) { ! 350: if ((next->uid!=-1 || next->gid !=-1) ! 351: && shellchars(s_to_c(next->addr))){ ! 352: /* this could be a serious security violation */ ! 353: next->status=d_syntax; ! 354: complain_mail(next, mp); ! 355: continue; ! 356: } ! 357: if (next->repl2 != NULL) { ! 358: s_append(cmd, " "); ! 359: s_append(cmd, s_to_c(next->repl2)); ! 360: } ! 361: d_insert(&list, next); ! 362: } ! 363: ! 364: if (nflg) { ! 365: puts(s_to_c(cmd)); ! 366: s_free(cmd); ! 367: s_free(file); ! 368: return 0; ! 369: } ! 370: ! 371: /* ! 372: * lock the mailbox (so that `Pipe to's run sequentially) ! 373: */ ! 374: if(pipeto) ! 375: fp = lockopen(s_to_c(file), "r", 0, 0, 0); ! 376: else ! 377: fp = NULL; ! 378: s_free(file); ! 379: ! 380: /* ! 381: * run the process ! 382: */ ! 383: pp = proc_start(s_to_c(cmd), instream(), (stream *)NULL, ! 384: outstream(), list->uid); ! 385: if(pp==NULL || pp->std[0]==NULL || pp->std[2]==NULL) ! 386: return refuse(list, mp, "out of processes, pipes, or memory", 0); ! 387: m_print(mp, pp->std[0]->fp, thissys, 0); ! 388: stream_free(pp->std[0]); pp->std[0] = NULL; ! 389: timedout = 0; ! 390: if (pipeto) { ! 391: signal(SIGALRM, times_up); ! 392: alarm(PIPETIMELIMIT); /* don't let a user hold us up. */ ! 393: } ! 394: while(s_read_line(pp->std[2]->fp, errstr) != NULL) ! 395: ; ! 396: status = proc_wait(pp); ! 397: if (pipeto) { ! 398: alarm(0); ! 399: signal(SIGALRM, SIG_IGN); ! 400: } ! 401: proc_free(pp); ! 402: s_free(cmd); ! 403: ! 404: /* ! 405: * unlock the mailbox (if it was locked) ! 406: */ ! 407: if(fp!=NULL) ! 408: lockclose(fp); ! 409: ! 410: /* ! 411: * return status ! 412: */ ! 413: if (status != 0) { ! 414: if (timedout) ! 415: s_append(errstr, "'Pipe to' command took too long"); ! 416: return refuse(list, mp, s_to_c(errstr), status); ! 417: } ! 418: loglist(list, mp, "remote"); ! 419: return 0; ! 420: } ! 421: ! 422: /* dispose of local addresses */ ! 423: cat_mail(dp, mp) ! 424: dest *dp; ! 425: message *mp; ! 426: { ! 427: FILE *fp; ! 428: char *rcvr; ! 429: ! 430: if (nflg) { ! 431: printf("cat >> %s\n", s_to_c(dp->repl1)); ! 432: return 0; ! 433: } ! 434: fp=lockopen(s_to_c(dp->repl1), "a", MBOXMODE, dp->uid, dp->gid); ! 435: if (fp == NULL) ! 436: return refuse(dp, mp, "mail file cannot be opened", 0); ! 437: m_print(mp, fp, (char *)NULL, 1); ! 438: fputs("\n", fp); ! 439: fflush(fp); ! 440: if (ferror(fp)) { ! 441: lockclose(fp); ! 442: return refuse(dp, mp, "error writing mail file", 0); ! 443: } ! 444: lockclose(fp); ! 445: rcvr = basename(s_to_c(dp->repl1)); ! 446: logdelivery(dp, rcvr, mp); ! 447: notify(rcvr, mp); ! 448: return 0; ! 449: } ! 450: ! 451: static void ! 452: appaddr(sp, dp) ! 453: string *sp; ! 454: dest *dp; ! 455: { ! 456: dest *parent; ! 457: ! 458: if (dp->parent != NULL) { ! 459: for(parent=dp->parent; parent->parent!=NULL; parent=parent->parent) ! 460: ; ! 461: s_append(sp, s_to_c(parent->addr)); ! 462: s_append(sp, "' alias `"); ! 463: } ! 464: s_append(sp, s_to_c(dp->addr)); ! 465: } ! 466: ! 467: /* reject delivery */ ! 468: refuse(list, mp, cp, status) ! 469: dest *list; ! 470: message *mp; ! 471: char *cp; ! 472: int status; ! 473: { ! 474: string *errstr=s_new(); ! 475: dest *dp; ! 476: int rv=0; ! 477: ! 478: dp = d_rm(&list); ! 479: mkerrstr(errstr, mp, dp, list, cp, status); ! 480: /* ! 481: * if on a tty just report the error. Otherwise send mail ! 482: * reporting the error. N.B. To avoid mail loops, don't ! 483: * send mail reporting a failure of mail to reach the postmaster. ! 484: */ ! 485: if (onatty) { ! 486: fputs(s_to_c(errstr), stderr); ! 487: savemail = 1; ! 488: rv = 1; ! 489: } else ! 490: rv = replymsg(errstr, mp, dp); ! 491: logrefusal(dp, mp, s_to_c(errstr)); ! 492: s_free(errstr); ! 493: return rv; ! 494: } ! 495: ! 496: /* make the error message */ ! 497: mkerrstr(errstr, mp, dp, list, cp, status) ! 498: string *errstr; ! 499: message *mp; ! 500: dest *dp; ! 501: dest *list; ! 502: char *cp; ! 503: { ! 504: dest *next; ! 505: char smsg[64]; ! 506: ! 507: /* list all aliases */ ! 508: s_append(errstr, "Mail to `"); ! 509: appaddr(errstr, dp); ! 510: for(next = d_rm(&list); next != NULL; next = d_rm(&list)) { ! 511: s_append(errstr, "', '"); ! 512: appaddr(errstr, next); ! 513: d_insert(&dp, next); ! 514: } ! 515: s_append(errstr, "' from '"); ! 516: s_append(errstr, s_to_c(mp->sender)); ! 517: s_append(errstr, "' ("); ! 518: s_append(errstr, s_to_c(mp->replyaddr)); ! 519: s_append(errstr, ")"); ! 520: s_append(errstr, " failed.\n"); ! 521: ! 522: /* >> and | deserve different flavored messages */ ! 523: switch(dp->status) { ! 524: case d_pipe: ! 525: s_append(errstr, "The mailer `"); ! 526: s_append(errstr, s_to_c(dp->repl1)); ! 527: sprintf(smsg, "' returned error status %x.\n", status); ! 528: s_append(errstr, smsg); ! 529: s_append(errstr, "The error message was:\n"); ! 530: s_append(errstr, cp); ! 531: break; ! 532: default: ! 533: s_append(errstr, "The error message was:\n"); ! 534: s_append(errstr, cp); ! 535: break; ! 536: } ! 537: } ! 538: ! 539: /* ! 540: * reply with up to 1024 characters of the ! 541: * original message ! 542: */ ! 543: replymsg(errstr, mp, dp) ! 544: string *errstr; ! 545: message *mp; ! 546: dest *dp; ! 547: { ! 548: message *refp = m_new(); ! 549: dest *ndp; ! 550: char *rcvr; ! 551: int rv; ! 552: ! 553: rcvr = dp->status==d_eloop ? "postmaster" : s_to_c(mp->replyaddr); ! 554: ndp = d_new(s_copy(rcvr)); ! 555: s_append(refp->sender, "postmaster"); ! 556: s_append(refp->replyaddr, "postmaster"); ! 557: s_append(refp->date, thedate()); ! 558: s_append(refp->body, s_to_c(errstr)); ! 559: s_append(refp->body, "\nThe message began:\n"); ! 560: s_nappend(refp->body, s_to_c(mp->body), 8*1024); ! 561: refp->size = strlen(s_to_c(refp->body)); ! 562: rv = send(ndp, refp, 0); ! 563: m_free(refp); ! 564: d_free(ndp); ! 565: return rv; ! 566: } ! 567:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.