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

Defined functions

greettimeout defined in line 216; used 2 times
reply defined in line 371; used 9 times
smtpdata defined in line 270; used 1 times
smtpinit defined in line 71; used 1 times
smtpmessage defined in line 483; used 8 times
smtpquit defined in line 329; used 6 times
smtprcpt defined in line 235; used 1 times

Defined variables

CtxGreeting defined in line 69; used 2 times
SccsId defined in line 24; never used
SmtpError defined in line 40; used 3 times
SmtpMsgBuffer defined in line 38; used 6 times
SmtpPid defined in line 43; used 3 times
SmtpReplyBuffer defined in line 39; used 11 times
SmtpState defined in line 46; used 11 times

Defined macros

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