1: /*
   2: **  Sendmail
   3: **  Copyright (c) 1983  Eric P. Allman
   4: **  Berkeley, California
   5: **
   6: **  Copyright (c) 1983 Regents of the University of California.
   7: **  All rights reserved.  The Berkeley software License Agreement
   8: **  specifies the terms and conditions for redistribution.
   9: */
  10: 
  11: 
  12: # include <ctype.h>
  13: # include <sysexits.h>
  14: # include <errno.h>
  15: # include "sendmail.h"
  16: 
  17: # ifndef SMTP
  18: # ifndef lint
  19: static char SccsId[] = "@(#)usersmtp.c	5.7 (Berkeley) 4/2/86	(no SMTP)";
  20: # endif not lint
  21: # else SMTP
  22: 
  23: # ifndef lint
  24: static char SccsId[] = "@(#)usersmtp.c	5.7 (Berkeley) 4/2/86";
  25: # endif not lint
  26: 
  27: 
  28: 
  29: /*
  30: **  USERSMTP -- run SMTP protocol from the user end.
  31: **
  32: **	This protocol is described in RFC821.
  33: */
  34: 
  35: #define REPLYTYPE(r)    ((r) / 100)     /* first digit of reply code */
  36: #define REPLYCLASS(r)   (((r) / 10) % 10)   /* second digit of reply code */
  37: #define SMTPCLOSING 421         /* "Service Shutting Down" */
  38: 
  39: char    SmtpMsgBuffer[MAXLINE];     /* buffer for commands */
  40: char    SmtpReplyBuffer[MAXLINE];   /* buffer for replies */
  41: char    SmtpError[MAXLINE] = "";    /* save failure error messages */
  42: FILE    *SmtpOut;           /* output file */
  43: FILE    *SmtpIn;            /* input file */
  44: int SmtpPid;            /* pid of mailer */
  45: 
  46: /* following represents the state of the SMTP connection */
  47: int SmtpState;          /* connection state, see below */
  48: 
  49: #define SMTP_CLOSED 0       /* connection is closed */
  50: #define SMTP_OPEN   1       /* connection is open for business */
  51: #define SMTP_SSD    2       /* service shutting down */
  52: /*
  53: **  SMTPINIT -- initialize SMTP.
  54: **
  55: **	Opens the connection and sends the initial protocol.
  56: **
  57: **	Parameters:
  58: **		m -- mailer to create connection to.
  59: **		pvp -- pointer to parameter vector to pass to
  60: **			the mailer.
  61: **
  62: **	Returns:
  63: **		appropriate exit status -- EX_OK on success.
  64: **		If not EX_OK, it should close the connection.
  65: **
  66: **	Side Effects:
  67: **		creates connection and sends initial protocol.
  68: */
  69: 
  70: jmp_buf CtxGreeting;
  71: 
  72: smtpinit(m, pvp)
  73:     struct mailer *m;
  74:     char **pvp;
  75: {
  76:     register int r;
  77:     EVENT *gte;
  78:     char buf[MAXNAME];
  79:     extern greettimeout();
  80: 
  81:     /*
  82: 	**  Open the connection to the mailer.
  83: 	*/
  84: 
  85: #ifdef DEBUG
  86:     if (SmtpState == SMTP_OPEN)
  87:         syserr("smtpinit: already open");
  88: #endif DEBUG
  89: 
  90:     SmtpIn = SmtpOut = NULL;
  91:     SmtpState = SMTP_CLOSED;
  92:     SmtpError[0] = '\0';
  93:     SmtpPhase = "user open";
  94:     SmtpPid = openmailer(m, pvp, (ADDRESS *) NULL, TRUE, &SmtpOut, &SmtpIn);
  95:     if (SmtpPid < 0)
  96:     {
  97: # ifdef DEBUG
  98:         if (tTd(18, 1))
  99:             printf("smtpinit: cannot open %s: stat %d errno %d\n",
 100:                pvp[0], ExitStat, errno);
 101: # endif DEBUG
 102:         if (CurEnv->e_xfp != NULL)
 103:         {
 104:             register char *p;
 105:             extern char *errstring();
 106:             extern char *statstring();
 107: 
 108:             if (errno == 0)
 109:             {
 110:                 p = statstring(ExitStat);
 111:                 fprintf(CurEnv->e_xfp,
 112:                     "%.3s %s.%s... %s\n",
 113:                     p, pvp[1], m->m_name, p);
 114:             }
 115:             else
 116:             {
 117:                 fprintf(CurEnv->e_xfp,
 118:                     "421 %s.%s... Deferred: %s\n",
 119:                     pvp[1], m->m_name, errstring(errno));
 120:             }
 121:         }
 122:         return (ExitStat);
 123:     }
 124:     SmtpState = SMTP_OPEN;
 125: 
 126:     /*
 127: 	**  Get the greeting message.
 128: 	**	This should appear spontaneously.  Give it five minutes to
 129: 	**	happen.
 130: 	*/
 131: 
 132:     if (setjmp(CtxGreeting) != 0)
 133:         goto tempfail;
 134:     gte = setevent((time_t) 300, greettimeout, 0);
 135:     SmtpPhase = "greeting wait";
 136:     r = reply(m);
 137:     clrevent(gte);
 138:     if (r < 0 || REPLYTYPE(r) != 2)
 139:         goto tempfail;
 140: 
 141:     /*
 142: 	**  Send the HELO command.
 143: 	**	My mother taught me to always introduce myself.
 144: 	*/
 145: 
 146:     smtpmessage("HELO %s", m, MyHostName);
 147:     SmtpPhase = "HELO wait";
 148:     r = reply(m);
 149:     if (r < 0)
 150:         goto tempfail;
 151:     else if (REPLYTYPE(r) == 5)
 152:         goto unavailable;
 153:     else if (REPLYTYPE(r) != 2)
 154:         goto tempfail;
 155: 
 156:     /*
 157: 	**  If this is expected to be another sendmail, send some internal
 158: 	**  commands.
 159: 	*/
 160: 
 161:     if (bitnset(M_INTERNAL, m->m_flags))
 162:     {
 163:         /* tell it to be verbose */
 164:         smtpmessage("VERB", m);
 165:         r = reply(m);
 166:         if (r < 0)
 167:             goto tempfail;
 168: 
 169:         /* tell it we will be sending one transaction only */
 170:         smtpmessage("ONEX", m);
 171:         r = reply(m);
 172:         if (r < 0)
 173:             goto tempfail;
 174:     }
 175: 
 176:     /*
 177: 	**  Send the MAIL command.
 178: 	**	Designates the sender.
 179: 	*/
 180: 
 181:     expand("\001g", buf, &buf[sizeof buf - 1], CurEnv);
 182:     if (CurEnv->e_from.q_mailer == LocalMailer ||
 183:         !bitnset(M_FROMPATH, m->m_flags))
 184:     {
 185:         smtpmessage("MAIL From:<%s>", m, buf);
 186:     }
 187:     else
 188:     {
 189:         smtpmessage("MAIL From:<@%s%c%s>", m, MyHostName,
 190:             buf[0] == '@' ? ',' : ':', buf);
 191:     }
 192:     SmtpPhase = "MAIL wait";
 193:     r = reply(m);
 194:     if (r < 0 || REPLYTYPE(r) == 4)
 195:         goto tempfail;
 196:     else if (r == 250)
 197:         return (EX_OK);
 198:     else if (r == 552)
 199:         goto unavailable;
 200: 
 201:     /* protocol error -- close up */
 202:     smtpquit(m);
 203:     return (EX_PROTOCOL);
 204: 
 205:     /* signal a temporary failure */
 206:   tempfail:
 207:     smtpquit(m);
 208:     return (EX_TEMPFAIL);
 209: 
 210:     /* signal service unavailable */
 211:   unavailable:
 212:     smtpquit(m);
 213:     return (EX_UNAVAILABLE);
 214: }
 215: 
 216: 
 217: static
 218: greettimeout()
 219: {
 220:     /* timeout reading the greeting message */
 221:     longjmp(CtxGreeting, 1);
 222: }
 223: /*
 224: **  SMTPRCPT -- designate recipient.
 225: **
 226: **	Parameters:
 227: **		to -- address of recipient.
 228: **		m -- the mailer we are sending to.
 229: **
 230: **	Returns:
 231: **		exit status corresponding to recipient status.
 232: **
 233: **	Side Effects:
 234: **		Sends the mail via SMTP.
 235: */
 236: 
 237: smtprcpt(to, m)
 238:     ADDRESS *to;
 239:     register MAILER *m;
 240: {
 241:     register int r;
 242:     extern char *remotename();
 243: 
 244:     smtpmessage("RCPT To:<%s>", m, remotename(to->q_user, m, FALSE, TRUE));
 245: 
 246:     SmtpPhase = "RCPT wait";
 247:     r = reply(m);
 248:     if (r < 0 || REPLYTYPE(r) == 4)
 249:         return (EX_TEMPFAIL);
 250:     else if (REPLYTYPE(r) == 2)
 251:         return (EX_OK);
 252:     else if (r == 550 || r == 551 || r == 553)
 253:         return (EX_NOUSER);
 254:     else if (r == 552 || r == 554)
 255:         return (EX_UNAVAILABLE);
 256:     return (EX_PROTOCOL);
 257: }
 258: /*
 259: **  SMTPDATA -- send the data and clean up the transaction.
 260: **
 261: **	Parameters:
 262: **		m -- mailer being sent to.
 263: **		e -- the envelope for this message.
 264: **
 265: **	Returns:
 266: **		exit status corresponding to DATA command.
 267: **
 268: **	Side Effects:
 269: **		none.
 270: */
 271: 
 272: smtpdata(m, e)
 273:     struct mailer *m;
 274:     register ENVELOPE *e;
 275: {
 276:     register int r;
 277: 
 278:     /*
 279: 	**  Send the data.
 280: 	**	First send the command and check that it is ok.
 281: 	**	Then send the data.
 282: 	**	Follow it up with a dot to terminate.
 283: 	**	Finally get the results of the transaction.
 284: 	*/
 285: 
 286:     /* send the command and check ok to proceed */
 287:     smtpmessage("DATA", m);
 288:     SmtpPhase = "DATA wait";
 289:     r = reply(m);
 290:     if (r < 0 || REPLYTYPE(r) == 4)
 291:         return (EX_TEMPFAIL);
 292:     else if (r == 554)
 293:         return (EX_UNAVAILABLE);
 294:     else if (r != 354)
 295:         return (EX_PROTOCOL);
 296: 
 297:     /* now output the actual message */
 298:     (*e->e_puthdr)(SmtpOut, m, CurEnv);
 299:     putline("\n", SmtpOut, m);
 300:     (*e->e_putbody)(SmtpOut, m, CurEnv);
 301: 
 302:     /* terminate the message */
 303:     fprintf(SmtpOut, ".%s", m->m_eol);
 304:     if (Verbose && !HoldErrs)
 305:         nmessage(Arpa_Info, ">>> .");
 306: 
 307:     /* check for the results of the transaction */
 308:     SmtpPhase = "result wait";
 309:     r = reply(m);
 310:     if (r < 0 || REPLYTYPE(r) == 4)
 311:         return (EX_TEMPFAIL);
 312:     else if (r == 250)
 313:         return (EX_OK);
 314:     else if (r == 552 || r == 554)
 315:         return (EX_UNAVAILABLE);
 316:     return (EX_PROTOCOL);
 317: }
 318: /*
 319: **  SMTPQUIT -- close the SMTP connection.
 320: **
 321: **	Parameters:
 322: **		m -- a pointer to the mailer.
 323: **
 324: **	Returns:
 325: **		none.
 326: **
 327: **	Side Effects:
 328: **		sends the final protocol and closes the connection.
 329: */
 330: 
 331: smtpquit(m)
 332:     register MAILER *m;
 333: {
 334:     int i;
 335: 
 336:     /* if the connection is already closed, don't bother */
 337:     if (SmtpIn == NULL)
 338:         return;
 339: 
 340:     /* send the quit message if not a forced quit */
 341:     if (SmtpState == SMTP_OPEN || SmtpState == SMTP_SSD)
 342:     {
 343:         smtpmessage("QUIT", m);
 344:         (void) reply(m);
 345:         if (SmtpState == SMTP_CLOSED)
 346:             return;
 347:     }
 348: 
 349:     /* now actually close the connection */
 350:     (void) fclose(SmtpIn);
 351:     (void) fclose(SmtpOut);
 352:     SmtpIn = SmtpOut = NULL;
 353:     SmtpState = SMTP_CLOSED;
 354: 
 355:     /* and pick up the zombie */
 356:     i = endmailer(SmtpPid, m->m_argv[0]);
 357:     if (i != EX_OK)
 358:         syserr("smtpquit %s: stat %d", m->m_argv[0], i);
 359: }
 360: /*
 361: **  REPLY -- read arpanet reply
 362: **
 363: **	Parameters:
 364: **		m -- the mailer we are reading the reply from.
 365: **
 366: **	Returns:
 367: **		reply code it reads.
 368: **
 369: **	Side Effects:
 370: **		flushes the mail file.
 371: */
 372: 
 373: reply(m)
 374:     MAILER *m;
 375: {
 376:     (void) fflush(SmtpOut);
 377: 
 378:     if (tTd(18, 1))
 379:         printf("reply\n");
 380: 
 381:     /*
 382: 	**  Read the input line, being careful not to hang.
 383: 	*/
 384: 
 385:     for (;;)
 386:     {
 387:         register int r;
 388:         register char *p;
 389: 
 390:         /* actually do the read */
 391:         if (CurEnv->e_xfp != NULL)
 392:             (void) fflush(CurEnv->e_xfp);   /* for debugging */
 393: 
 394:         /* if we are in the process of closing just give the code */
 395:         if (SmtpState == SMTP_CLOSED)
 396:             return (SMTPCLOSING);
 397: 
 398:         /* get the line from the other side */
 399:         p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, SmtpIn);
 400:         if (p == NULL)
 401:         {
 402:             extern char MsgBuf[];       /* err.c */
 403:             extern char Arpa_TSyserr[]; /* conf.c */
 404: 
 405:             /* if the remote end closed early, fake an error */
 406:             if (errno == 0)
 407: # ifdef ECONNRESET
 408:                 errno = ECONNRESET;
 409: # else ECONNRESET
 410:                 errno = EPIPE;
 411: # endif ECONNRESET
 412: 
 413:             message(Arpa_TSyserr, "reply: read error");
 414: # ifdef DEBUG
 415:             /* if debugging, pause so we can see state */
 416:             if (tTd(18, 100))
 417:                 pause();
 418: # endif DEBUG
 419: # ifdef LOG
 420:             syslog(LOG_ERR, "%s", &MsgBuf[4]);
 421: # endif LOG
 422:             SmtpState = SMTP_CLOSED;
 423:             smtpquit(m);
 424:             return (-1);
 425:         }
 426:         fixcrlf(SmtpReplyBuffer, TRUE);
 427: 
 428:         if (CurEnv->e_xfp != NULL && index("45", SmtpReplyBuffer[0]) != NULL)
 429:         {
 430:             /* serious error -- log the previous command */
 431:             if (SmtpMsgBuffer[0] != '\0')
 432:                 fprintf(CurEnv->e_xfp, ">>> %s\n", SmtpMsgBuffer);
 433:             SmtpMsgBuffer[0] = '\0';
 434: 
 435:             /* now log the message as from the other side */
 436:             fprintf(CurEnv->e_xfp, "<<< %s\n", SmtpReplyBuffer);
 437:         }
 438: 
 439:         /* display the input for verbose mode */
 440:         if (Verbose && !HoldErrs)
 441:             nmessage(Arpa_Info, "%s", SmtpReplyBuffer);
 442: 
 443:         /* if continuation is required, we can go on */
 444:         if (SmtpReplyBuffer[3] == '-' || !isdigit(SmtpReplyBuffer[0]))
 445:             continue;
 446: 
 447:         /* decode the reply code */
 448:         r = atoi(SmtpReplyBuffer);
 449: 
 450:         /* extra semantics: 0xx codes are "informational" */
 451:         if (r < 100)
 452:             continue;
 453: 
 454:         /* reply code 421 is "Service Shutting Down" */
 455:         if (r == SMTPCLOSING && SmtpState != SMTP_SSD)
 456:         {
 457:             /* send the quit protocol */
 458:             SmtpState = SMTP_SSD;
 459:             smtpquit(m);
 460:         }
 461: 
 462:         /* save temporary failure messages for posterity */
 463:         if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0')
 464:             (void) strcpy(SmtpError, &SmtpReplyBuffer[4]);
 465: 
 466:         return (r);
 467:     }
 468: }
 469: /*
 470: **  SMTPMESSAGE -- send message to server
 471: **
 472: **	Parameters:
 473: **		f -- format
 474: **		m -- the mailer to control formatting.
 475: **		a, b, c -- parameters
 476: **
 477: **	Returns:
 478: **		none.
 479: **
 480: **	Side Effects:
 481: **		writes message to SmtpOut.
 482: */
 483: 
 484: /*VARARGS1*/
 485: smtpmessage(f, m, a, b, c)
 486:     char *f;
 487:     MAILER *m;
 488: {
 489:     (void) sprintf(SmtpMsgBuffer, f, a, b, c);
 490:     if (tTd(18, 1) || (Verbose && !HoldErrs))
 491:         nmessage(Arpa_Info, ">>> %s", SmtpMsgBuffer);
 492:     if (SmtpOut != NULL)
 493:         fprintf(SmtpOut, "%s%s", SmtpMsgBuffer, m->m_eol);
 494: }
 495: 
 496: # endif SMTP

Defined functions

greettimeout defined in line 217; used 2 times
reply defined in line 373; used 9 times
smtpdata defined in line 272; used 1 times
smtpinit defined in line 72; used 1 times
smtpmessage defined in line 485; used 8 times
smtpquit defined in line 331; used 6 times
smtprcpt defined in line 237; used 1 times

Defined variables

CtxGreeting defined in line 70; used 2 times
SccsId defined in line 24; never used
SmtpError defined in line 41; used 3 times
SmtpMsgBuffer defined in line 39; used 6 times
SmtpPid defined in line 44; used 3 times
SmtpReplyBuffer defined in line 40; used 11 times
SmtpState defined in line 47; used 11 times

Defined macros

REPLYCLASS defined in line 36; never used
REPLYTYPE defined in line 35; used 8 times
SMTPCLOSING defined in line 37; used 2 times
SMTP_CLOSED defined in line 49; used 5 times
SMTP_OPEN defined in line 50; used 3 times
SMTP_SSD defined in line 51; used 3 times
Last modified: 1986-04-03
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2048
Valid CSS Valid XHTML 1.0 Strict