|
|
1.1 ! root 1: #include <stdio.h> ! 2: #include <sys/types.h> ! 3: #include <signal.h> ! 4: #include <pwd.h> ! 5: #include <sys/stat.h> ! 6: #include <time.h> ! 7: #include <sys/timeb.h> ! 8: #include "letter.h" ! 9: #include "mail.h" ! 10: #include "string.h" ! 11: ! 12: ! 13: /* configuration */ ! 14: #define DEAD "dead.letter" ! 15: #define MAILMODE (~0644) /* mode of created mail */ ! 16: #define MAXFORWARD 32 ! 17: #define MAXHOP 5 ! 18: ! 19: /* imports */ ! 20: extern char *basename(); ! 21: extern int (*signal())(); ! 22: extern char *getsysname(); ! 23: extern char *stringin(); ! 24: extern char *getarg(); ! 25: extern char *getenv(); ! 26: extern char *mailpath(); ! 27: extern char *upaspath(); ! 28: extern void lock(); ! 29: extern void unlock(); ! 30: extern int rewrite(); ! 31: extern int getrules(); ! 32: extern long getunix(); ! 33: extern void putunix(); ! 34: extern void putrfunix(); ! 35: extern FILE *popen(); ! 36: extern char *getlogin(); ! 37: extern char *asctime(); ! 38: extern struct tm *localtime(); ! 39: extern char *timezone(); ! 40: ! 41: /* exported */ ! 42: char *thissys; /* name of this system */ ! 43: char *network = "uucp"; /* name of network mail is coming from */ ! 44: int onatty; ! 45: int rmail; /* true if not executed as 'mail' */ ! 46: ! 47: /* global to this module */ ! 48: #define LETTERNAME 0 ! 49: #define DEVTTY NOFILE-1 ! 50: static int error; ! 51: static char *myname; /* name of this program */ ! 52: ! 53: /* predeclared */ ! 54: static void saveletter(); ! 55: static int saveonint(), done(); ! 56: static int send(); ! 57: static int append_to_file(); ! 58: static int pipe_to_cmd(); ! 59: static long getfrom(); ! 60: ! 61: extern void ! 62: sendmail(ac, av) ! 63: int ac; ! 64: char *av[]; ! 65: { ! 66: int chkfl; /* check forward list */ ! 67: int ind=1; ! 68: int (*rc)(); ! 69: char sender[ADDRSIZE]; ! 70: char date[DATESIZE]; ! 71: long bodyoffset; ! 72: letter *lp; ! 73: ! 74: /* avoid hanging dk lines (HACK!!!!!!!!) */ ! 75: close(DEVTTY); ! 76: ! 77: myname = basename(av[0]); ! 78: rmail = chkfl = strcmp(myname, "mail") != 0; ! 79: onatty = isatty(0); ! 80: thissys = getsysname(); ! 81: ! 82: /* make temporary */ ! 83: rc = signal(SIGINT, done); ! 84: inittmp(); ! 85: ! 86: /* get network (default uucp) */ ! 87: if (av[1][0] == '-' && av[1][1] == 'N') { ! 88: if (av[1][2] == '\0') { ! 89: network = av[2]; ! 90: ind++; ! 91: } else { ! 92: network = &(av[1][2]); ! 93: } ! 94: ind++; ! 95: } ! 96: ! 97: /* read letter */ ! 98: (void)signal(SIGINT, saveonint); ! 99: lp = lopen(LETTERNAME, "w"); ! 100: copyto(stdin, lp, onatty, 1); ! 101: if (ltell(lp) == 0L) ! 102: done(); ! 103: ! 104: /* send */ ! 105: if (!error) { ! 106: (void)getrules(); ! 107: lp = lopen(LETTERNAME, "r"); ! 108: bodyoffset = getfrom(lp, sender, date); ! 109: (void)signal(SIGINT, rc); ! 110: for (; ind<ac; ind++) { ! 111: letseek(lp, bodyoffset); ! 112: error += send(lp, sender, date, av[ind], chkfl, 0); ! 113: } ! 114: } ! 115: if (error && onatty) ! 116: saveletter(lp); ! 117: (void)done(); ! 118: } ! 119: ! 120: /* come here on interrupt while reading in letter */ ! 121: static int ! 122: saveonint() { ! 123: (void)signal(SIGINT, saveonint); ! 124: error++; ! 125: } ! 126: ! 127: /* come here to finish up */ ! 128: static int ! 129: done() { ! 130: unlock(); ! 131: releasetmp(); ! 132: exit(error); ! 133: } ! 134: ! 135: /* save the letter in dead.letter */ ! 136: static void ! 137: saveletter(lp) ! 138: letter *lp; ! 139: { ! 140: FILE *malf; ! 141: char where[PATHSIZE]; ! 142: char *home = getenv("HOME"); ! 143: ! 144: (void)setgid(getgid()); ! 145: (void)setuid(getuid()); ! 146: if (home != NULL) { ! 147: strcpy(where, home); ! 148: strcat(where, "/"); ! 149: } else ! 150: *where = '\0'; ! 151: strcat(where, DEAD); ! 152: malf = fopen(where, "w"); ! 153: if (malf == NULL) { ! 154: fprintf(stderr, "mail: cannot open %s\n", where); ! 155: return; ! 156: } ! 157: letseek(lp, (long)0); ! 158: copyfrom(lp, malf); ! 159: fclose(malf); ! 160: printf("Mail saved in %s\n", where); ! 161: } ! 162: ! 163: /* ! 164: * Send a letter. Return 0 if all went well. ! 165: */ ! 166: static int ! 167: send(lp, sender, date, rcvr, chkfl, hop) ! 168: letter *lp; ! 169: char *sender, *date, *rcvr; ! 170: int chkfl; ! 171: int hop; ! 172: { ! 173: int rv, notinfl; ! 174: char dest[ADDRSIZE], rest[ADDRSIZE], cmd[CMDSIZE], format[32], sysname[64]; ! 175: ! 176: if ((notinfl = rewrite(rcvr, sender, chkfl, cmd)) < 0) { ! 177: fprintf(stderr, "mail: can't understand address %s\n", dest); ! 178: return 1; ! 179: } ! 180: if (cmd[0]=='\0') ! 181: rv = append_to_file(lp, sender, date, rcvr, chkfl, hop); ! 182: else ! 183: rv = pipe_to_cmd(lp, sender, date, rcvr, cmd, ! 184: chkfl && notinfl); ! 185: return rv; ! 186: } ! 187: ! 188: /* ! 189: * Put mail into a mail file in the standard place. ! 190: */ ! 191: static int ! 192: append_to_file(lp, sender, date, rcvr, chkfl, hop) ! 193: letter *lp; ! 194: char *sender, *date, *rcvr; ! 195: int hop; ! 196: { ! 197: register mask; ! 198: struct passwd *pw, *getpwnam(); ! 199: struct stat stbuf; ! 200: char file[PATHSIZE]; ! 201: char sendto[CMDSIZE]; ! 202: int exists; ! 203: FILE *malf; ! 204: char *p; ! 205: int i; ! 206: ! 207: if (strcmp(rcvr, "-") == 0) ! 208: return(1); ! 209: if (strchr(rcvr, '/') != NULL) { ! 210: fprintf(stderr, "mail: illegal name %s\n", rcvr); ! 211: return(0); ! 212: } ! 213: strcpy(file, mailpath(rcvr)); ! 214: switch (delivery_status(file, sendto) & MFTYPE) { ! 215: case MF_NORMAL: ! 216: /* normal message */ ! 217: break; ! 218: case MF_FORWARD: ! 219: /* look for possible forwarding loop */ ! 220: for (i = 0, p = sender-1; p != NULL; p = strchr(p+1, '!')) ! 221: if (strncmp(thissys, p+1, strlen(thissys))==0) ! 222: i++; ! 223: if (i > MAXHOP) { ! 224: logsend(rcvr, sender, date, "remote-mail-loop-err"); ! 225: fprintf(stderr, "mail: remote mail loop\n"); ! 226: break; ! 227: } ! 228: ! 229: /* forward message */ ! 230: return forward_to(lp, rcvr, sender, date, sendto, hop); ! 231: case MF_PIPE: ! 232: /* pipe to a command */ ! 233: (void)stat(file, &stbuf); ! 234: return pipe_to(lp, rcvr, sender, date, sendto, stbuf.st_uid, ! 235: stbuf.st_gid); ! 236: } ! 237: exists = stat(file, &stbuf); ! 238: if ((pw = getpwnam(rcvr)) == NULL) { ! 239: if (exists < 0) { ! 240: if (chkfl) { ! 241: refuse(lp,sender, date, rcvr, "addressee unknown."); ! 242: return(0); ! 243: } ! 244: fprintf(stderr, "mail: can't send to %s\n", rcvr); ! 245: return 1; ! 246: } ! 247: } else { ! 248: stbuf.st_uid = pw->pw_uid; ! 249: stbuf.st_gid = pw->pw_gid; ! 250: } ! 251: mask = umask(MAILMODE); ! 252: lock(file); ! 253: malf = fopen(file, "a"); ! 254: umask(mask); ! 255: if (malf == NULL) { ! 256: fprintf(stderr, "mail: cannot append to %s\n", file); ! 257: logsend(rcvr, sender, date, "append-err"); ! 258: return 1; ! 259: } ! 260: if (exists < 0) ! 261: chown(file, stbuf.st_uid, stbuf.st_gid); ! 262: fprintf(malf, "%s%s %s\n", FROM, sender, date); ! 263: copyfrom(lp, malf); ! 264: fputs("\n", malf); ! 265: fclose(malf); ! 266: unlock(); ! 267: logsend(rcvr, sender, date, "delivered"); ! 268: notify(rcvr, sender); /* let him know it right away! */ ! 269: return 0; ! 270: } ! 271: ! 272: /* ! 273: * Pipe the mail into a command. This is either for remote ! 274: * mail or specially handled mail. Remote mail is distinguished ! 275: * by a non-null string as the destination. ! 276: */ ! 277: static int ! 278: pipe_to_cmd(lp, sender, date, rcvr, cmd, chkfl) ! 279: letter *lp; ! 280: char *sender, *date, *rcvr, *cmd; ! 281: int chkfl; ! 282: { ! 283: FILE *fp; ! 284: char errbuf[CMDSIZE]; ! 285: char reason[2*CMDSIZE]; ! 286: long pos, status; ! 287: ! 288: /* check forwarding (what anti-social crap!) */ ! 289: if (chkfl) { ! 290: if (rewrite(sender, "", chkfl, (char *)NULL) != 0) { ! 291: refuse(lp, sender, date, rcvr, ! 292: "forwarding to this system disallowed."); ! 293: return(0); ! 294: } ! 295: } ! 296: ! 297: /* do it */ ! 298: if ((fp=popen(cmd, getuid(), getgid())) == NULL) { ! 299: fprintf(stderr, "mail: can't pipe to network mailer\n"); ! 300: exit(1); ! 301: } ! 302: pos = ltell(lp); ! 303: putrfunix(sender, date, thissys, fp); ! 304: copyfrom(lp, fp); ! 305: status = pclose(fp, errbuf, CMDSIZE); ! 306: if (status==0) { ! 307: logsend(rcvr, sender, date, "remote"); ! 308: return 0; ! 309: } else { ! 310: logsend(rcvr, sender, date, "remote-err"); ! 311: logsend("", cmd, "", "remote-err"); ! 312: sprintf(reason, "\"%s\"\nwas unable to send your mail. It returned the status 0x%x.\nStderr was:\n%s", ! 313: cmd, status, errbuf); ! 314: (void)letseek(lp, pos); ! 315: refuse(lp, sender, date, rcvr, reason); ! 316: return 0; ! 317: } ! 318: } ! 319: ! 320: ! 321: /* return to sender, address unknown, no such number, no such phone... */ ! 322: refuse(lp, sender, date, rcvr, reason) ! 323: letter *lp; ! 324: char *sender, *date, *rcvr, *reason; ! 325: { ! 326: FILE *pf; ! 327: char cbuf[CMDSIZE]; ! 328: ! 329: sprintf(cbuf, "PATH=/bin:/usr/bin mail %s", sender); ! 330: if ((pf = popen(cbuf, getuid(), getgid())) == NULL) ! 331: return; ! 332: fprintf(pf, "Mail to %s failed. %s\nMessage was:\n", rcvr, reason); ! 333: fprintf(pf, "%s%s %s\n", FROM, sender, date); ! 334: copyfrom(lp, pf); ! 335: pclose(pf, 0, 0); ! 336: logsend(rcvr, sender, date, "refused"); ! 337: } ! 338: ! 339: /* forward mail to a list of people */ ! 340: forward_to(lp, rcvr, sender, date, list, hop) ! 341: letter *lp; ! 342: char *rcvr, *sender, *date, *list; ! 343: int hop; ! 344: { ! 345: char dest[ADDRSIZE]; ! 346: char *p; ! 347: int rv=0; ! 348: ! 349: if (hop > MAXFORWARD) { ! 350: fprintf(stderr, "mail: forwarding loop!!\n"); ! 351: logsend(rcvr, sender, date, "forward-loop-err"); ! 352: return 1; ! 353: } ! 354: for (p = list; (p = getarg(dest, p)) != NULL; ) { ! 355: (void)letseek(lp, (long)0); ! 356: rv += send(lp, sender, date, dest, 0, ++hop); ! 357: } ! 358: return rv; ! 359: } ! 360: ! 361: #define SU 0 /* super-duper user uid */ ! 362: ! 363: /* change uid to the receiver and perform the command */ ! 364: pipe_to(lp, rcvr, sender, date, cmd, uid, gid) ! 365: letter *lp; ! 366: char *rcvr, *sender, *date, *cmd; ! 367: { ! 368: FILE *fp; ! 369: int i; ! 370: ! 371: /* do it */ ! 372: if ((fp=popen(cmd, uid, gid)) == NULL) { ! 373: fprintf(stderr, "mail: can't pipe to network mailer\n"); ! 374: return 1; ! 375: } ! 376: putunix(sender, date, fp); ! 377: copyfrom(lp, fp); ! 378: if ((i=pclose(fp, 0, 0))==0) { ! 379: logsend(rcvr, sender, date, "pipe_to"); ! 380: return 0; ! 381: } else { ! 382: logsend(rcvr, sender, date, "pipe_to_err"); ! 383: logsend("", cmd, "", "pipe_to_err"); ! 384: fprintf(stderr, "mail: Pipe to \"%s\" returns error status %d\n", ! 385: cmd, i); ! 386: return 1; ! 387: } ! 388: } ! 389: ! 390: /* default sender */ ! 391: static void ! 392: defaultsender(sender, date) ! 393: char *sender; /* filled by defaultsender */ ! 394: char *date; /* filled by defaultsender */ ! 395: { ! 396: char *tp, *dp; ! 397: struct timeb timbuf; ! 398: struct tm *bp; ! 399: long thetime; ! 400: ! 401: (void)strcpy(sender, getlogin()); ! 402: ftime(&timbuf); ! 403: thetime = timbuf.time; ! 404: bp = localtime(&thetime); ! 405: dp = asctime(bp); ! 406: tp = timezone(timbuf.timezone, bp->tm_isdst); ! 407: sprintf(date, "%.16s %.3s %.4s", dp, tp, dp+20); ! 408: } ! 409: ! 410: /* Get/parse a unix header. */ ! 411: static long ! 412: getfrom(lp, sender, date) ! 413: letter *lp; ! 414: char *sender, *date; ! 415: { ! 416: char line[FROMLINESIZE]; ! 417: long n=0; ! 418: ! 419: defaultsender(sender, date); ! 420: initgetunix(); ! 421: while (lgets(line, sizeof(line), lp) != NULL) { ! 422: if (getunix(line, sender, date) == 0) ! 423: break; ! 424: n = ltell(lp); ! 425: } ! 426: ! 427: return n; ! 428: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.