1: # include <errno.h>
   2: # include "sendmail.h"
   3: # include <signal.h>
   4: 
   5: # ifndef SMTP
   6: SCCSID(@(#)srvrsmtp.c	4.3		8/28/83	(no SMTP));
   7: # else SMTP
   8: 
   9: SCCSID(@(#)srvrsmtp.c	4.3		8/28/83);
  10: 
  11: /*
  12: **  SMTP -- run the SMTP protocol.
  13: **
  14: **	Parameters:
  15: **		none.
  16: **
  17: **	Returns:
  18: **		never.
  19: **
  20: **	Side Effects:
  21: **		Reads commands from the input channel and processes
  22: **			them.
  23: */
  24: 
  25: struct cmd
  26: {
  27:     char    *cmdname;   /* command name */
  28:     int cmdcode;    /* internal code, see below */
  29: };
  30: 
  31: /* values for cmdcode */
  32: # define CMDERROR   0   /* bad command */
  33: # define CMDMAIL    1   /* mail -- designate sender */
  34: # define CMDRCPT    2   /* rcpt -- designate recipient */
  35: # define CMDDATA    3   /* data -- send message text */
  36: # define CMDRSET    4   /* rset -- reset state */
  37: # define CMDVRFY    5   /* vrfy -- verify address */
  38: # define CMDHELP    6   /* help -- give usage info */
  39: # define CMDNOOP    7   /* noop -- do nothing */
  40: # define CMDQUIT    8   /* quit -- close connection and die */
  41: # define CMDHELO    9   /* helo -- be polite */
  42: # define CMDDBGQSHOW    10  /* showq -- show send queue (DEBUG) */
  43: # define CMDDBGDEBUG    11  /* debug -- set debug mode */
  44: # define CMDVERB    12  /* verb -- go into verbose mode */
  45: # define CMDDBGKILL 13  /* kill -- kill sendmail */
  46: # define CMDDBGWIZ  14  /* wiz -- become a wizard */
  47: # define CMDONEX    15  /* onex -- sending one transaction only */
  48: # define CMDDBGSHELL    16  /* shell -- give us a shell */
  49: 
  50: static struct cmd   CmdTab[] =
  51: {
  52:     "mail",     CMDMAIL,
  53:     "rcpt",     CMDRCPT,
  54:     "data",     CMDDATA,
  55:     "rset",     CMDRSET,
  56:     "vrfy",     CMDVRFY,
  57:     "expn",     CMDVRFY,
  58:     "help",     CMDHELP,
  59:     "noop",     CMDNOOP,
  60:     "quit",     CMDQUIT,
  61:     "helo",     CMDHELO,
  62:     "verb",     CMDVERB,
  63:     "onex",     CMDONEX,
  64: # ifdef DEBUG
  65:     "showq",    CMDDBGQSHOW,
  66:     "debug",    CMDDBGDEBUG,
  67:     "kill",     CMDDBGKILL,
  68:     "wiz",      CMDDBGWIZ,
  69:     "shell",    CMDDBGSHELL,
  70: # endif DEBUG
  71:     NULL,       CMDERROR,
  72: };
  73: 
  74: # ifdef DEBUG
  75: bool    IsWiz = FALSE;          /* set if we are a wizard */
  76: char    *WizWord = NULL;        /* the wizard word to compare against */
  77: # endif DEBUG
  78: bool    InChild = FALSE;        /* true if running in a subprocess */
  79: bool    OneXact = FALSE;        /* one xaction only this run */
  80: char    *RealHostName = NULL;       /* verified hostname, set in daemon.c */
  81: 
  82: #define EX_QUIT     22      /* special code for QUIT command */
  83: 
  84: smtp()
  85: {
  86:     register char *p;
  87:     register struct cmd *c;
  88:     char *cmd;
  89:     extern char *skipword();
  90:     extern bool sameword();
  91:     bool hasmail;           /* mail command received */
  92:     int rcps;           /* number of recipients */
  93:     auto ADDRESS *vrfyqueue;
  94:     ADDRESS *a;
  95:     char inp[MAXLINE];
  96:     extern char Version[];
  97:     extern tick();
  98:     extern bool iswiz();
  99:     extern char *arpadate();
 100:     extern char *macvalue();
 101:     extern ADDRESS *recipient();
 102: 
 103:     hasmail = FALSE;
 104:     rcps = 0;
 105:     if (OutChannel != stdout)
 106:     {
 107:         /* arrange for debugging output to go to remote host */
 108:         (void) close(1);
 109:         (void) dup(fileno(OutChannel));
 110:     }
 111:     settime();
 112:     expand("$e", inp, &inp[sizeof inp], CurEnv);
 113:     message("220", inp);
 114:     for (;;)
 115:     {
 116:         /* arrange for backout */
 117:         if (setjmp(TopFrame) > 0 && InChild)
 118:             finis();
 119:         QuickAbort = FALSE;
 120:         HoldErrs = FALSE;
 121: 
 122:         /* setup for the read */
 123:         CurEnv->e_to = NULL;
 124:         Errors = 0;
 125:         (void) fflush(stdout);
 126: 
 127:         /* read the input line */
 128:         p = sfgets(inp, sizeof inp, InChannel);
 129: 
 130:         /* handle errors */
 131:         if (p == NULL)
 132:         {
 133:             /* end of file, just die */
 134:             message("421", "%s Lost input channel", HostName);
 135:             finis();
 136:         }
 137: 
 138:         /* clean up end of line */
 139:         fixcrlf(inp, TRUE);
 140: 
 141:         /* echo command to transcript */
 142:         if (CurEnv->e_xfp != NULL)
 143:             fprintf(CurEnv->e_xfp, "<<< %s\n", inp);
 144: 
 145:         /* break off command */
 146:         for (p = inp; isspace(*p); p++)
 147:             continue;
 148:         cmd = p;
 149:         while (*++p != '\0' && !isspace(*p))
 150:             continue;
 151:         if (*p != '\0')
 152:             *p++ = '\0';
 153: 
 154:         /* decode command */
 155:         for (c = CmdTab; c->cmdname != NULL; c++)
 156:         {
 157:             if (sameword(c->cmdname, cmd))
 158:                 break;
 159:         }
 160: 
 161:         /* process command */
 162:         switch (c->cmdcode)
 163:         {
 164:           case CMDHELO:     /* hello -- introduce yourself */
 165:             if (sameword(p, HostName))
 166:             {
 167:                 /* connected to an echo server */
 168:                 message("553", "%s I refuse to talk to myself",
 169:                     HostName);
 170:                 break;
 171:             }
 172:             if (RealHostName != NULL && !sameword(p, RealHostName))
 173:             {
 174:                 char buf[MAXNAME];
 175: 
 176:                 (void) sprintf(buf, "%s (%s)", p, RealHostName);
 177:                 define('s', newstr(buf), CurEnv);
 178:             }
 179:             else
 180:                 define('s', newstr(p), CurEnv);
 181:             message("250", "%s Hello %s, pleased to meet you",
 182:                 HostName, p);
 183:             break;
 184: 
 185:           case CMDMAIL:     /* mail -- designate sender */
 186:             /* force a sending host even if no HELO given */
 187:             if (RealHostName != NULL && macvalue('s', CurEnv) == NULL)
 188:                 define('s', RealHostName, CurEnv);
 189: 
 190:             /* check for validity of this command */
 191:             if (hasmail)
 192:             {
 193:                 message("503", "Sender already specified");
 194:                 break;
 195:             }
 196:             if (InChild)
 197:             {
 198:                 syserr("Nested MAIL command");
 199:                 exit(0);
 200:             }
 201: 
 202:             /* fork a subprocess to process this command */
 203:             if (runinchild("SMTP-MAIL") > 0)
 204:                 break;
 205:             initsys();
 206: 
 207:             /* child -- go do the processing */
 208:             p = skipword(p, "from");
 209:             if (p == NULL)
 210:                 break;
 211:             setsender(p);
 212:             if (Errors == 0)
 213:             {
 214:                 message("250", "Sender ok");
 215:                 hasmail = TRUE;
 216:             }
 217:             else if (InChild)
 218:                 finis();
 219:             break;
 220: 
 221:           case CMDRCPT:     /* rcpt -- designate recipient */
 222:             if (setjmp(TopFrame) > 0)
 223:             {
 224:                 CurEnv->e_flags &= ~EF_FATALERRS;
 225:                 break;
 226:             }
 227:             QuickAbort = TRUE;
 228:             p = skipword(p, "to");
 229:             if (p == NULL)
 230:                 break;
 231:             a = parseaddr(p, (ADDRESS *) NULL, 1, '\0');
 232:             if (a == NULL)
 233:                 break;
 234:             a = recipient(a, &CurEnv->e_sendqueue);
 235:             if (Errors != 0)
 236:                 break;
 237: 
 238:             /* no errors during parsing, but might be a duplicate */
 239:             CurEnv->e_to = p;
 240:             if (!bitset(QBADADDR, a->q_flags))
 241:                 message("250", "Recipient ok");
 242:             else
 243:             {
 244:                 /* punt -- should keep message in ADDRESS.... */
 245:                 message("550", "Addressee unknown");
 246:             }
 247:             CurEnv->e_to = NULL;
 248:             rcps++;
 249:             break;
 250: 
 251:           case CMDDATA:     /* data -- text of mail */
 252:             if (!hasmail)
 253:             {
 254:                 message("503", "Need MAIL command");
 255:                 break;
 256:             }
 257:             else if (rcps <= 0)
 258:             {
 259:                 message("503", "Need RCPT (recipient)");
 260:                 break;
 261:             }
 262: 
 263:             /* collect the text of the message */
 264:             collect(TRUE);
 265:             if (Errors != 0)
 266:                 break;
 267: 
 268:             /*
 269: 			**  Arrange to send to everyone.
 270: 			**	If sending to multiple people, mail back
 271: 			**		errors rather than reporting directly.
 272: 			**	In any case, don't mail back errors for
 273: 			**		anything that has happened up to
 274: 			**		now (the other end will do this).
 275: 			**	Truncate our transcript -- the mail has gotten
 276: 			**		to us successfully, and if we have
 277: 			**		to mail this back, it will be easier
 278: 			**		on the reader.
 279: 			**	Then send to everyone.
 280: 			**	Finally give a reply code.  If an error has
 281: 			**		already been given, don't mail a
 282: 			**		message back.
 283: 			**	We goose error returns by clearing error bit.
 284: 			*/
 285: 
 286:             if (rcps != 1)
 287:             {
 288:                 HoldErrs = TRUE;
 289:                 ErrorMode = EM_MAIL;
 290:             }
 291:             CurEnv->e_flags &= ~EF_FATALERRS;
 292:             CurEnv->e_xfp = freopen(queuename(CurEnv, 'x'), "w", CurEnv->e_xfp);
 293: 
 294:             /* send to all recipients */
 295:             sendall(CurEnv, SM_DEFAULT);
 296:             CurEnv->e_to = NULL;
 297: 
 298:             /* issue success if appropriate and reset */
 299:             if (Errors == 0 || HoldErrs)
 300:                 message("250", "Ok");
 301:             else
 302:                 CurEnv->e_flags &= ~EF_FATALERRS;
 303: 
 304:             /* if in a child, pop back to our parent */
 305:             if (InChild)
 306:                 finis();
 307:             break;
 308: 
 309:           case CMDRSET:     /* rset -- reset state */
 310:             message("250", "Reset state");
 311:             if (InChild)
 312:                 finis();
 313:             break;
 314: 
 315:           case CMDVRFY:     /* vrfy -- verify address */
 316:             if (runinchild("SMTP-VRFY") > 0)
 317:                 break;
 318:             vrfyqueue = NULL;
 319:             QuickAbort = TRUE;
 320:             sendtolist(p, (ADDRESS *) NULL, &vrfyqueue);
 321:             if (Errors != 0)
 322:             {
 323:                 if (InChild)
 324:                     finis();
 325:                 break;
 326:             }
 327:             while (vrfyqueue != NULL)
 328:             {
 329:                 register ADDRESS *a = vrfyqueue->q_next;
 330:                 char *code;
 331: 
 332:                 while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags))
 333:                     a = a->q_next;
 334: 
 335:                 if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags))
 336:                 {
 337:                     if (a != NULL)
 338:                         code = "250-";
 339:                     else
 340:                         code = "250";
 341:                     if (vrfyqueue->q_fullname == NULL)
 342:                         message(code, "<%s>", vrfyqueue->q_paddr);
 343:                     else
 344:                         message(code, "%s <%s>",
 345:                             vrfyqueue->q_fullname, vrfyqueue->q_paddr);
 346:                 }
 347:                 else if (a == NULL)
 348:                     message("554", "Self destructive alias loop");
 349:                 vrfyqueue = a;
 350:             }
 351:             if (InChild)
 352:                 finis();
 353:             break;
 354: 
 355:           case CMDHELP:     /* help -- give user info */
 356:             if (*p == '\0')
 357:                 p = "SMTP";
 358:             help(p);
 359:             break;
 360: 
 361:           case CMDNOOP:     /* noop -- do nothing */
 362:             message("200", "OK");
 363:             break;
 364: 
 365:           case CMDQUIT:     /* quit -- leave mail */
 366:             message("221", "%s closing connection", HostName);
 367:             if (InChild)
 368:                 ExitStat = EX_QUIT;
 369:             finis();
 370: 
 371:           case CMDVERB:     /* set verbose mode */
 372:             Verbose = TRUE;
 373:             message("200", "Verbose mode");
 374:             break;
 375: 
 376:           case CMDONEX:     /* doing one transaction only */
 377:             OneXact = TRUE;
 378:             message("200", "Only one transaction");
 379:             break;
 380: 
 381: # ifdef DEBUG
 382:           case CMDDBGQSHOW: /* show queues */
 383:             printf("Send Queue=");
 384:             printaddr(CurEnv->e_sendqueue, TRUE);
 385:             break;
 386: 
 387:           case CMDDBGDEBUG: /* set debug mode */
 388:             tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
 389:             tTflag(p);
 390:             message("200", "Debug set");
 391:             break;
 392: 
 393:           case CMDDBGKILL:  /* kill the parent */
 394:             if (!iswiz())
 395:                 break;
 396:             if (kill(MotherPid, SIGTERM) >= 0)
 397:                 message("200", "Mother is dead");
 398:             else
 399:                 message("500", "Can't kill Mom");
 400:             break;
 401: 
 402:           case CMDDBGSHELL: /* give us an interactive shell */
 403:             if (!iswiz())
 404:                 break;
 405:             if (fileno(InChannel) != 0)
 406:             {
 407:                 (void) close(0);
 408:                 (void) dup(fileno(InChannel));
 409:                 if (fileno(InChannel) != fileno(OutChannel))
 410:                     (void) fclose(InChannel);
 411:                 InChannel = stdin;
 412:             }
 413:             if (fileno(OutChannel) != 1)
 414:             {
 415:                 (void) close(1);
 416:                 (void) dup(fileno(OutChannel));
 417:                 (void) fclose(OutChannel);
 418:                 OutChannel = stdout;
 419:             }
 420:             (void) close(2);
 421:             (void) dup(1);
 422:             execl("/bin/csh", "sendmail", 0);
 423:             execl("/bin/sh", "sendmail", 0);
 424:             message("500", "Can't");
 425:             exit(EX_UNAVAILABLE);
 426: 
 427:           case CMDDBGWIZ:   /* become a wizard */
 428:             if (WizWord != NULL)
 429:             {
 430:                 char seed[3];
 431:                 extern char *crypt();
 432: 
 433:                 strncpy(seed, WizWord, 2);
 434:                 if (strcmp(WizWord, crypt(p, seed)) != 0)
 435:                 {
 436:                     message("500", "You are no wizard!");
 437:                     break;
 438:                 }
 439:             }
 440:             IsWiz = TRUE;
 441:             message("200", "Please pass, oh mighty wizard");
 442:             break;
 443: # endif DEBUG
 444: 
 445:           case CMDERROR:    /* unknown command */
 446:             message("500", "Command unrecognized");
 447:             break;
 448: 
 449:           default:
 450:             syserr("smtp: unknown code %d", c->cmdcode);
 451:             break;
 452:         }
 453:     }
 454: }
 455: /*
 456: **  SKIPWORD -- skip a fixed word.
 457: **
 458: **	Parameters:
 459: **		p -- place to start looking.
 460: **		w -- word to skip.
 461: **
 462: **	Returns:
 463: **		p following w.
 464: **		NULL on error.
 465: **
 466: **	Side Effects:
 467: **		clobbers the p data area.
 468: */
 469: 
 470: static char *
 471: skipword(p, w)
 472:     register char *p;
 473:     char *w;
 474: {
 475:     register char *q;
 476:     extern bool sameword();
 477: 
 478:     /* find beginning of word */
 479:     while (isspace(*p))
 480:         p++;
 481:     q = p;
 482: 
 483:     /* find end of word */
 484:     while (*p != '\0' && *p != ':' && !isspace(*p))
 485:         p++;
 486:     while (isspace(*p))
 487:         *p++ = '\0';
 488:     if (*p != ':')
 489:     {
 490:       syntax:
 491:         message("501", "Syntax error");
 492:         Errors++;
 493:         return (NULL);
 494:     }
 495:     *p++ = '\0';
 496:     while (isspace(*p))
 497:         p++;
 498: 
 499:     /* see if the input word matches desired word */
 500:     if (!sameword(q, w))
 501:         goto syntax;
 502: 
 503:     return (p);
 504: }
 505: /*
 506: **  HELP -- implement the HELP command.
 507: **
 508: **	Parameters:
 509: **		topic -- the topic we want help for.
 510: **
 511: **	Returns:
 512: **		none.
 513: **
 514: **	Side Effects:
 515: **		outputs the help file to message output.
 516: */
 517: 
 518: help(topic)
 519:     char *topic;
 520: {
 521:     register FILE *hf;
 522:     int len;
 523:     char buf[MAXLINE];
 524:     bool noinfo;
 525: 
 526:     if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL)
 527:     {
 528:         /* no help */
 529:         errno = 0;
 530:         message("502", "HELP not implemented");
 531:         return;
 532:     }
 533: 
 534:     len = strlen(topic);
 535:     makelower(topic);
 536:     noinfo = TRUE;
 537: 
 538:     while (fgets(buf, sizeof buf, hf) != NULL)
 539:     {
 540:         if (strncmp(buf, topic, len) == 0)
 541:         {
 542:             register char *p;
 543: 
 544:             p = index(buf, '\t');
 545:             if (p == NULL)
 546:                 p = buf;
 547:             else
 548:                 p++;
 549:             fixcrlf(p, TRUE);
 550:             message("214-", p);
 551:             noinfo = FALSE;
 552:         }
 553:     }
 554: 
 555:     if (noinfo)
 556:         message("504", "HELP topic unknown");
 557:     else
 558:         message("214", "End of HELP info");
 559:     (void) fclose(hf);
 560: }
 561: /*
 562: **  ISWIZ -- tell us if we are a wizard
 563: **
 564: **	If not, print a nasty message.
 565: **
 566: **	Parameters:
 567: **		none.
 568: **
 569: **	Returns:
 570: **		TRUE if we are a wizard.
 571: **		FALSE if we are not a wizard.
 572: **
 573: **	Side Effects:
 574: **		Prints a 500 exit stat if we are not a wizard.
 575: */
 576: 
 577: bool
 578: iswiz()
 579: {
 580:     if (!IsWiz)
 581:         message("500", "Mere mortals musn't mutter that mantra");
 582:     return (IsWiz);
 583: }
 584: /*
 585: **  RUNINCHILD -- return twice -- once in the child, then in the parent again
 586: **
 587: **	Parameters:
 588: **		label -- a string used in error messages
 589: **
 590: **	Returns:
 591: **		zero in the child
 592: **		one in the parent
 593: **
 594: **	Side Effects:
 595: **		none.
 596: */
 597: 
 598: runinchild(label)
 599:     char *label;
 600: {
 601:     int childpid;
 602: 
 603:     if (OneXact)
 604:         return (0);
 605: 
 606:     childpid = dofork();
 607:     if (childpid < 0)
 608:     {
 609:         syserr("%s: cannot fork", label);
 610:         return (1);
 611:     }
 612:     if (childpid > 0)
 613:     {
 614:         auto int st;
 615: 
 616:         /* parent -- wait for child to complete */
 617:         st = waitfor(childpid);
 618:         if (st == -1)
 619:             syserr("%s: lost child", label);
 620: 
 621:         /* if we exited on a QUIT command, complete the process */
 622:         if (st == (EX_QUIT << 8))
 623:             finis();
 624: 
 625:         return (1);
 626:     }
 627:     else
 628:     {
 629:         /* child */
 630:         InChild = TRUE;
 631:         clearenvelope(CurEnv);
 632:         return (0);
 633:     }
 634: }
 635: 
 636: # endif SMTP

Defined functions

help defined in line 518; used 1 times
iswiz defined in line 577; used 3 times
runinchild defined in line 598; used 2 times
skipword defined in line 470; used 3 times
smtp defined in line 84; used 1 times

Defined variables

CmdTab defined in line 50; used 1 times
RealHostName defined in line 80; used 5 times
WizWord defined in line 76; used 4 times

Defined struct's

cmd defined in line 25; used 4 times
  • in line 50(2), 87(2)

Defined macros

CMDDATA defined in line 35; used 1 times
  • in line 54
CMDDBGDEBUG defined in line 43; used 1 times
  • in line 66
CMDDBGKILL defined in line 45; used 1 times
  • in line 67
CMDDBGQSHOW defined in line 42; used 1 times
  • in line 65
CMDDBGSHELL defined in line 48; used 1 times
  • in line 69
CMDDBGWIZ defined in line 46; used 1 times
  • in line 68
CMDERROR defined in line 32; used 1 times
  • in line 71
CMDHELO defined in line 41; used 1 times
  • in line 61
CMDHELP defined in line 38; used 1 times
  • in line 58
CMDMAIL defined in line 33; used 1 times
  • in line 52
CMDNOOP defined in line 39; used 1 times
  • in line 59
CMDONEX defined in line 47; used 1 times
  • in line 63
CMDQUIT defined in line 40; used 1 times
  • in line 60
CMDRCPT defined in line 34; used 1 times
  • in line 53
CMDRSET defined in line 36; used 1 times
  • in line 55
CMDVERB defined in line 44; used 1 times
  • in line 62
CMDVRFY defined in line 37; used 2 times
EX_QUIT defined in line 82; used 2 times
Last modified: 1984-03-19
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1986
Valid CSS Valid XHTML 1.0 Strict