|
|
1.1 ! root 1: /* ! 2: * Do the necessary commands for a smtp transfer. Start by waiting for the ! 3: * connection to open, then send HELO, MAIL, RCPT, and DATA. Check the ! 4: * reply codes and give up if needed. ! 5: * ! 6: * This code modified from the MIT UNIX TCP implementation: ! 7: * Copyright 1984 Massachusetts Institute of Technology ! 8: * ! 9: * Permission to use, copy, modify, and distribute this file ! 10: * for any purpose and without fee is hereby granted, provided ! 11: * that this copyright and permission notice appear on all copies ! 12: * and supporting documentation, the name of M.I.T. not be used ! 13: * in advertising or publicity pertaining to distribution of the ! 14: * program without specific prior permission, and notice be given ! 15: * in supporting documentation that copying and distribution is ! 16: * by permission of M.I.T. M.I.T. makes no representations about ! 17: * the suitability of this software for any purpose. It is provided ! 18: * "as is" without express or implied warranty. ! 19: */ ! 20: ! 21: #include <stdio.h> ! 22: #include <signal.h> ! 23: #include <sysexits.h> ! 24: #include "mail.h" ! 25: #include "smtp.h" ! 26: #include "string.h" ! 27: ! 28: #define TRUE 1 ! 29: #define FALSE 0 ! 30: #define MINUTES * 60 ! 31: #define HOURS * 60 MINUTES ! 32: #define DAYS * 24 HOURS ! 33: ! 34: char *strcat(), *strcpy(); ! 35: ! 36: SIGRETURN ignore_signal(); ! 37: SIGRETURN death(); ! 38: char *timemsg; ! 39: int timelim; ! 40: int timeerror; ! 41: long nbytes; ! 42: extern int debug; ! 43: FILE *fi; ! 44: FILE *fo; ! 45: ! 46: converse(unixformat, from, rcpts, domain, sfi, sfo, mlfd) ! 47: char *from; /* from address */ ! 48: namelist *rcpts; /* to addresses */ ! 49: char *domain; ! 50: FILE *sfi; /* smtp input */ ! 51: FILE *sfo; /* smtp output */ ! 52: FILE *mlfd; /* mail file descriptor */ ! 53: { ! 54: extern char *helohost; ! 55: char buf[MAXSTR]; ! 56: namelist *np; ! 57: extern int kludgepause; ! 58: ! 59: fi = sfi; fo = sfo; ! 60: ! 61: (void) signal(SIGALRM, death); ! 62: ! 63: setalarm(5 MINUTES, "initial handshake", EX_TEMPFAIL); ! 64: expect(220, sfi, sfo, EX_PROTOCOL); /* expect a service ready msg */ ! 65: ! 66: /* ! 67: * This pause is needed when an smtp call gets redialed ! 68: * (the research version of the Datakit splice.) Because of ! 69: * a race condition inherent in both features, -inet- must ! 70: * not be too eager to send HELO until the connection is set up ! 71: * completely. Unfortunately, the other guy's 220 response ! 72: * (above) can arrive before the redialed connection ! 73: * is completely processed locally. Hence, the brief delay. ! 74: * We can't fix this without changing (read ``fixing'') Datakit ! 75: * everywhere. This kludge is slightly easier. ! 76: */ ! 77: if (kludgepause) ! 78: sleep(kludgepause); ! 79: ! 80: sprintf(buf, "HELO %s\n", helohost); ! 81: csend(buf); ! 82: expect(250, sfi, sfo, EX_PROTOCOL); /* expect an OK */ ! 83: ! 84: strcpy(buf, "MAIL FROM:<"); ! 85: strcat(buf, from); ! 86: strcat(buf, ">\n"); ! 87: csend(buf); ! 88: setalarm(10 MINUTES, "response to MAIL FROM/RCPT TO", EX_TEMPFAIL); ! 89: expect(250, sfi, sfo, EX_PROTOCOL); /* expect OK */ ! 90: ! 91: for (np=rcpts; np!=NULL; np=np->next) { ! 92: strcpy(buf, "RCPT TO:<"); ! 93: strcat(buf, np->name); ! 94: strcat(buf, ">\n"); ! 95: csend(buf); ! 96: expect(250, sfi, sfo, EX_NOUSER); /* expect OK */ ! 97: } ! 98: setalarm(10 MINUTES, "response to DATA", EX_TEMPFAIL); ! 99: csend("DATA\n"); ! 100: expect(354, sfi, sfo, EX_PROTOCOL); ! 101: setalarm(10 MINUTES, "sending mail data", EX_TEMPFAIL); ! 102: do_data(unixformat, mlfd, sfo, from, rcpts, domain); ! 103: setalarm(1 HOURS, "expecting delivery ack", EX_TEMPFAIL); ! 104: expect(250, sfi, sfo, EX_PROTOCOL); ! 105: ! 106: setalarm(5 MINUTES, "response to QUIT", 0); ! 107: csend("QUIT\n"); ! 108: expect(221, sfi, sfo, 0); /* who cares? (Some do)*/ ! 109: exit(0); ! 110: } ! 111: ! 112: /* ! 113: * escape '.'s at the beginning of lines and turn newlines into ! 114: * /r/n's. ! 115: */ ! 116: static char smlastchar; ! 117: ! 118: smfputs(str, fp) ! 119: char *str; ! 120: FILE *fp; ! 121: { ! 122: register char *cp; ! 123: ! 124: /* ! 125: * escape a leading dot ! 126: */ ! 127: if(smlastchar=='\n' && str[0]=='.') { ! 128: nbytes++; ! 129: fputc('.', fp); ! 130: } ! 131: ! 132: /* ! 133: * output the line ! 134: */ ! 135: for(cp=str; *cp; cp++){ ! 136: if(*cp=='\n') { ! 137: nbytes++; ! 138: putc('\r', fp); ! 139: } ! 140: nbytes++; ! 141: putc(*cp, fp); ! 142: } ! 143: if(cp!=str) ! 144: smlastchar = *(cp-1); ! 145: } ! 146: ! 147: ! 148: /* ! 149: * Send the data from the specified mail file out on the current smtp ! 150: * connection. Do the appropriate netascii conversion and hidden '.' ! 151: * padding. Send the <CRLF>.<CRLF> at completion. ! 152: */ ! 153: do_data(unixformat, sfi, sfo, from, rcpts, domain) ! 154: register FILE *sfi; /* mail file descriptor */ ! 155: register FILE *sfo; /* smtp files */ ! 156: char *from; ! 157: namelist *rcpts; ! 158: char *domain; ! 159: { ! 160: static string *rcvr; ! 161: char buf[4096]; ! 162: namelist *p; ! 163: long nchars; ! 164: ! 165: /* ! 166: * turn rcpts into a , list of receivers ! 167: */ ! 168: rcvr = s_reset(rcvr); ! 169: for(p = rcpts; p; p = p->next){ ! 170: s_append(rcvr, p->name); ! 171: if(p->next) ! 172: s_append(rcvr, ", "); ! 173: } ! 174: ! 175: /* ! 176: * send data to output ! 177: */ ! 178: setalarm(5 MINUTES, "start sending mail data", EX_TEMPFAIL); ! 179: nbytes = 0; ! 180: smlastchar = '\n'; ! 181: if(unixformat){ ! 182: nchars = 0; ! 183: while(fgets(buf, sizeof(buf), sfi)!=NULL) { ! 184: smfputs(buf, sfo); ! 185: nchars += strlen(buf)+1; ! 186: if (nchars>1024) { ! 187: if (debug) ! 188: fprintf(stderr, "."); ! 189: nchars -= 1024; ! 190: setalarm(5 MINUTES, "sending mail data", EX_TEMPFAIL); ! 191: } ! 192: } ! 193: } else { ! 194: if(to822(smfputs, sfi, sfo, from, domain, s_to_c(rcvr))<0){ ! 195: Syslog(LOG_INFO, "bad input file to %s\n", ! 196: s_to_c(rcvr)); ! 197: bomb(EX_DATAERR); ! 198: } ! 199: } ! 200: ! 201: /* ! 202: * terminate the DATA command with \r\n.\r\n ! 203: */ ! 204: if(smlastchar != '\n'){ ! 205: fputs("\r\n", sfo); ! 206: nbytes += 2; ! 207: } ! 208: fputs(".\r\n", sfo); ! 209: nbytes += 3; ! 210: Syslog(LOG_INFO, "%s sent %d bytes to %s\n", ! 211: from, nbytes, s_to_c(rcvr)); ! 212: ! 213: /* ! 214: * see if we screwed up ! 215: */ ! 216: setalarm(30 MINUTES, "finishing data", EX_TEMPFAIL); ! 217: fflush(sfo); ! 218: if (ferror(sfo)) { ! 219: Syslog(LOG_INFO, "write error finishing data to %s", ! 220: s_to_c(rcvr)); ! 221: bomb(EX_IOERR); ! 222: } ! 223: } ! 224: ! 225: /* ! 226: * Expect a reply message with the specified code. If the specified code ! 227: * is received return TRUE; otherwise print the error message out on the ! 228: * standard output and give up. Note that the reply can be a multiline ! 229: * message. ! 230: */ ! 231: expect(code, sfi, sfo, error) ! 232: int code; ! 233: FILE *sfi, *sfo; ! 234: int error; ! 235: { ! 236: int retcd; ! 237: char cmdbuf[BUFSIZ]; ! 238: char cbuf[6144]; ! 239: extern int debug; ! 240: ! 241: cbuf[0] = '\0'; ! 242: ! 243: /* get whole reply */ ! 244: more: ! 245: while (tgets(cmdbuf, sizeof cmdbuf, sfi) > 0) { ! 246: cmdbuf[131] = '\n'; ! 247: cmdbuf[132] = '\0'; /* not too long */ ! 248: Syslog(LOG_DEBUG, "---> %s", cmdbuf); ! 249: if (cmdbuf[3] != '-') /* continuation line? */ ! 250: break; /* no, last line */ ! 251: else if (strlen(cmdbuf) + strlen(cbuf) + 4 < sizeof(cbuf)) { ! 252: strcat(cbuf, "<<< "); ! 253: strcat(cbuf, cmdbuf); ! 254: } ! 255: } ! 256: if (sscanf(cmdbuf, "%d", &retcd) != 1 ){ ! 257: int l=strlen(cmdbuf)-1; ! 258: if (l>=0 && cmdbuf[l]=='\n') ! 259: cmdbuf[l]='\0'; ! 260: (void) fprintf(stderr, "non-numeric command reply (%s)\n", cmdbuf); ! 261: if (error) ! 262: bomb(EX_PROTOCOL); ! 263: else ! 264: return 1; ! 265: } ! 266: if (retcd == code) { ! 267: return 1; ! 268: } ! 269: if (retcd/100 == code/100) { ! 270: return 1; ! 271: } ! 272: Syslog(LOG_NOTICE, "Failed, expecting %d, got %d\n", code, retcd); ! 273: /* print the error line */ ! 274: (void) fprintf(stderr, "%s<<< %s", cbuf, cmdbuf); ! 275: csend("QUIT\n"); ! 276: if (error) ! 277: if (retcd/100 == 4) ! 278: bomb(EX_TEMPFAIL); /* 4xx make temp fails, no matter what*/ ! 279: else ! 280: bomb(error); /* map smtp errors to mailsys errors */ ! 281: return 1; ! 282: } ! 283: ! 284: setalarm(limit, message, error) ! 285: char *message; ! 286: { ! 287: timelim = limit; ! 288: timemsg = message; ! 289: timeerror = error; ! 290: alarm(limit); ! 291: } ! 292: ! 293: /* Maximum time to live elapsed. Die right now. */ ! 294: SIGRETURN ! 295: death() ! 296: { ! 297: Syslog(LOG_NOTICE, "Timer (%d sec) expired: %s.\n", timelim, timemsg); ! 298: exit(timeerror); ! 299: } ! 300: ! 301: SIGRETURN ! 302: ignore_signal(){} ! 303: ! 304: csend(buf) ! 305: char *buf; ! 306: { ! 307: Syslog(LOG_DEBUG, "<--- %s", buf); ! 308: tputs(buf, fo); ! 309: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.