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