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

Defined functions

greettimeout defined in line 220; used 2 times
reply defined in line 376; used 9 times
smtpdata defined in line 275; used 1 times
smtpinit defined in line 75; used 1 times
smtpmessage defined in line 487; used 8 times
smtpquit defined in line 334; used 6 times
smtprcpt defined in line 240; used 1 times

Defined variables

CtxGreeting defined in line 73; used 2 times
SmtpError defined in line 44; used 3 times
SmtpMsgBuffer defined in line 42; used 6 times
SmtpPid defined in line 47; used 3 times
SmtpReplyBuffer defined in line 43; used 11 times
SmtpState defined in line 50; used 11 times
sccsid defined in line 23; never used

Defined macros

REPLYCLASS defined in line 39; never used
REPLYTYPE defined in line 38; used 8 times
SMTPCLOSING defined in line 40; used 2 times
SMTP_CLOSED defined in line 52; used 5 times
SMTP_OPEN defined in line 53; used 3 times
SMTP_SSD defined in line 54; used 3 times
Last modified: 1997-10-03
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4345
Valid CSS Valid XHTML 1.0 Strict