usersmtp.c
上传用户:xu_441
上传日期:2007-01-04
资源大小:1640k
文件大小:46k
源码类别:

Email客户端

开发平台:

Unix_Linux

  1. /*
  2.  * Copyright (c) 1998, 1999 Sendmail, Inc. and its suppliers.
  3.  * All rights reserved.
  4.  * Copyright (c) 1983, 1995-1997 Eric P. Allman.  All rights reserved.
  5.  * Copyright (c) 1988, 1993
  6.  * The Regents of the University of California.  All rights reserved.
  7.  *
  8.  * By using this file, you agree to the terms and conditions set
  9.  * forth in the LICENSE file which can be found at the top level of
  10.  * the sendmail distribution.
  11.  *
  12.  */
  13. #include <sendmail.h>
  14. #ifndef lint
  15. # if SMTP
  16. static char id[] = "@(#)$Id: usersmtp.c,v 8.223 1999/12/07 23:24:12 ca Exp $ (with SMTP)";
  17. # else /* SMTP */
  18. static char id[] = "@(#)$Id: usersmtp.c,v 8.223 1999/12/07 23:24:12 ca Exp $ (without SMTP)";
  19. # endif /* SMTP */
  20. #endif /* ! lint */
  21. #include <sysexits.h>
  22. #if SMTP
  23. static void datatimeout __P((void));
  24. static void esmtp_check __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
  25. static void helo_options __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
  26. /*
  27. **  USERSMTP -- run SMTP protocol from the user end.
  28. **
  29. ** This protocol is described in RFC821.
  30. */
  31. # define REPLYTYPE(r) ((r) / 100) /* first digit of reply code */
  32. # define REPLYCLASS(r) (((r) / 10) % 10) /* second digit of reply code */
  33. # define SMTPCLOSING 421 /* "Service Shutting Down" */
  34. #define ENHSCN(e, d) (e) == NULL ? (d) : newstr(e)
  35. static char SmtpMsgBuffer[MAXLINE]; /* buffer for commands */
  36. static char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */
  37. char SmtpError[MAXLINE] = ""; /* save failure error messages */
  38. static bool SmtpNeedIntro; /* need "while talking" in transcript */
  39. /*
  40. **  SMTPINIT -- initialize SMTP.
  41. **
  42. ** Opens the connection and sends the initial protocol.
  43. **
  44. ** Parameters:
  45. ** m -- mailer to create connection to.
  46. ** mci -- the mailer connection info.
  47. ** e -- the envelope.
  48. ** onlyhelo -- send only helo command?
  49. **
  50. ** Returns:
  51. ** none.
  52. **
  53. ** Side Effects:
  54. ** creates connection and sends initial protocol.
  55. */
  56. void
  57. smtpinit(m, mci, e, onlyhelo)
  58. MAILER *m;
  59. register MCI *mci;
  60. ENVELOPE *e;
  61. bool onlyhelo;
  62. {
  63. register int r;
  64. register char *p;
  65. register char *hn;
  66. char *enhsc;
  67. enhsc = NULL;
  68. if (tTd(18, 1))
  69. {
  70. dprintf("smtpinit ");
  71. mci_dump(mci, FALSE);
  72. }
  73. /*
  74. **  Open the connection to the mailer.
  75. */
  76. SmtpError[0] = '';
  77. CurHostName = mci->mci_host; /* XXX UGLY XXX */
  78. if (CurHostName == NULL)
  79. CurHostName = MyHostName;
  80. SmtpNeedIntro = TRUE;
  81. switch (mci->mci_state)
  82. {
  83.   case MCIS_ACTIVE:
  84. /* need to clear old information */
  85. smtprset(m, mci, e);
  86. /* FALLTHROUGH */
  87.   case MCIS_OPEN:
  88. if (!onlyhelo)
  89. return;
  90. break;
  91.   case MCIS_ERROR:
  92.   case MCIS_QUITING:
  93.   case MCIS_SSD:
  94. /* shouldn't happen */
  95. smtpquit(m, mci, e);
  96. /* FALLTHROUGH */
  97.   case MCIS_CLOSED:
  98. syserr("451 4.4.0 smtpinit: state CLOSED");
  99. return;
  100.   case MCIS_OPENING:
  101. break;
  102. }
  103. if (onlyhelo)
  104. goto helo;
  105. mci->mci_state = MCIS_OPENING;
  106. /*
  107. **  Get the greeting message.
  108. ** This should appear spontaneously.  Give it five minutes to
  109. ** happen.
  110. */
  111. SmtpPhase = mci->mci_phase = "client greeting";
  112. sm_setproctitle(TRUE, e, "%s %s: %s",
  113. qid_printname(e), CurHostName, mci->mci_phase);
  114. r = reply(m, mci, e, TimeOuts.to_initial, esmtp_check, NULL);
  115. if (r < 0)
  116. goto tempfail1;
  117. if (REPLYTYPE(r) == 4)
  118. goto tempfail2;
  119. if (REPLYTYPE(r) != 2)
  120. goto unavailable;
  121. /*
  122. **  Send the HELO command.
  123. ** My mother taught me to always introduce myself.
  124. */
  125. helo:
  126. if (bitnset(M_ESMTP, m->m_flags) || bitnset(M_LMTP, m->m_flags))
  127. mci->mci_flags |= MCIF_ESMTP;
  128. hn = mci->mci_heloname ? mci->mci_heloname : MyHostName;
  129. tryhelo:
  130. if (bitnset(M_LMTP, m->m_flags))
  131. {
  132. smtpmessage("LHLO %s", m, mci, hn);
  133. SmtpPhase = mci->mci_phase = "client LHLO";
  134. }
  135. else if (bitset(MCIF_ESMTP, mci->mci_flags))
  136. {
  137. smtpmessage("EHLO %s", m, mci, hn);
  138. SmtpPhase = mci->mci_phase = "client EHLO";
  139. }
  140. else
  141. {
  142. smtpmessage("HELO %s", m, mci, hn);
  143. SmtpPhase = mci->mci_phase = "client HELO";
  144. }
  145. sm_setproctitle(TRUE, e, "%s %s: %s", qid_printname(e),
  146. CurHostName, mci->mci_phase);
  147. r = reply(m, mci, e, TimeOuts.to_helo, helo_options, NULL);
  148. if (r < 0)
  149. goto tempfail1;
  150. else if (REPLYTYPE(r) == 5)
  151. {
  152. if (bitset(MCIF_ESMTP, mci->mci_flags) &&
  153.     !bitnset(M_LMTP, m->m_flags))
  154. {
  155. /* try old SMTP instead */
  156. mci->mci_flags &= ~MCIF_ESMTP;
  157. goto tryhelo;
  158. }
  159. goto unavailable;
  160. }
  161. else if (REPLYTYPE(r) != 2)
  162. goto tempfail2;
  163. /*
  164. **  Check to see if we actually ended up talking to ourself.
  165. **  This means we didn't know about an alias or MX, or we managed
  166. **  to connect to an echo server.
  167. */
  168. p = strchr(&SmtpReplyBuffer[4], ' ');
  169. if (p != NULL)
  170. *p = '';
  171. if (!bitnset(M_NOLOOPCHECK, m->m_flags) &&
  172.     !bitnset(M_LMTP, m->m_flags) &&
  173.     strcasecmp(&SmtpReplyBuffer[4], MyHostName) == 0)
  174. {
  175. syserr("553 5.3.5 %s config error: mail loops back to me (MX problem?)",
  176. CurHostName);
  177. mci_setstat(mci, EX_CONFIG, "5.3.5", "system config error");
  178. mci->mci_errno = 0;
  179. smtpquit(m, mci, e);
  180. return;
  181. }
  182. /*
  183. **  If this is expected to be another sendmail, send some internal
  184. **  commands.
  185. */
  186. if (bitnset(M_INTERNAL, m->m_flags))
  187. {
  188. /* tell it to be verbose */
  189. smtpmessage("VERB", m, mci);
  190. r = reply(m, mci, e, TimeOuts.to_miscshort, NULL, &enhsc);
  191. if (r < 0)
  192. goto tempfail1;
  193. }
  194. if (mci->mci_state != MCIS_CLOSED)
  195. {
  196. mci->mci_state = MCIS_OPEN;
  197. return;
  198. }
  199. /* got a 421 error code during startup */
  200.   tempfail1:
  201. if (mci->mci_errno == 0)
  202. mci->mci_errno = errno;
  203. mci_setstat(mci, EX_TEMPFAIL, ENHSCN(enhsc, "4.4.2"), NULL);
  204. if (mci->mci_state != MCIS_CLOSED)
  205. smtpquit(m, mci, e);
  206. return;
  207.   tempfail2:
  208. if (mci->mci_errno == 0)
  209. mci->mci_errno = errno;
  210. /* XXX should use code from other end iff ENHANCEDSTATUSCODES */
  211. mci_setstat(mci, EX_TEMPFAIL, ENHSCN(enhsc, "4.5.0"),
  212.     SmtpReplyBuffer);
  213. if (mci->mci_state != MCIS_CLOSED)
  214. smtpquit(m, mci, e);
  215. return;
  216.   unavailable:
  217. mci->mci_errno = errno;
  218. mci_setstat(mci, EX_UNAVAILABLE, "5.5.0", SmtpReplyBuffer);
  219. smtpquit(m, mci, e);
  220. return;
  221. }
  222. /*
  223. **  ESMTP_CHECK -- check to see if this implementation likes ESMTP protocol
  224. **
  225. ** Parameters:
  226. ** line -- the response line.
  227. ** firstline -- set if this is the first line of the reply.
  228. ** m -- the mailer.
  229. ** mci -- the mailer connection info.
  230. ** e -- the envelope.
  231. **
  232. ** Returns:
  233. ** none.
  234. */
  235. static void
  236. esmtp_check(line, firstline, m, mci, e)
  237. char *line;
  238. bool firstline;
  239. MAILER *m;
  240. register MCI *mci;
  241. ENVELOPE *e;
  242. {
  243. if (strstr(line, "ESMTP") != NULL)
  244. mci->mci_flags |= MCIF_ESMTP;
  245. if (strstr(line, "8BIT-OK") != NULL)
  246. mci->mci_flags |= MCIF_8BITOK;
  247. }
  248. /*
  249. **  HELO_OPTIONS -- process the options on a HELO line.
  250. **
  251. ** Parameters:
  252. ** line -- the response line.
  253. ** firstline -- set if this is the first line of the reply.
  254. ** m -- the mailer.
  255. ** mci -- the mailer connection info.
  256. ** e -- the envelope.
  257. **
  258. ** Returns:
  259. ** none.
  260. */
  261. static void
  262. helo_options(line, firstline, m, mci, e)
  263. char *line;
  264. bool firstline;
  265. MAILER *m;
  266. register MCI *mci;
  267. ENVELOPE *e;
  268. {
  269. register char *p;
  270. if (firstline)
  271. return;
  272. if (strlen(line) < (SIZE_T) 5)
  273. return;
  274. line += 4;
  275. p = strpbrk(line, " =");
  276. if (p != NULL)
  277. *p++ = '';
  278. if (strcasecmp(line, "size") == 0)
  279. {
  280. mci->mci_flags |= MCIF_SIZE;
  281. if (p != NULL)
  282. mci->mci_maxsize = atol(p);
  283. }
  284. else if (strcasecmp(line, "8bitmime") == 0)
  285. {
  286. mci->mci_flags |= MCIF_8BITMIME;
  287. mci->mci_flags &= ~MCIF_7BIT;
  288. }
  289. else if (strcasecmp(line, "expn") == 0)
  290. mci->mci_flags |= MCIF_EXPN;
  291. else if (strcasecmp(line, "dsn") == 0)
  292. mci->mci_flags |= MCIF_DSN;
  293. else if (strcasecmp(line, "enhancedstatuscodes") == 0)
  294. mci->mci_flags |= MCIF_ENHSTAT;
  295. # if SASL
  296. else if (strcasecmp(line, "auth") == 0)
  297. {
  298. if (p == NULL || *p == '')
  299. {
  300. /* no parameter? */
  301. mci->mci_saslcap = NULL;
  302. }
  303. else
  304. {
  305. int l;
  306. if (mci->mci_saslcap != NULL)
  307. free(mci->mci_saslcap);
  308. l = strlen(p) + 1;
  309. mci->mci_saslcap = (char *)malloc(l);
  310. /* XXX this may be leaked */
  311. if (mci->mci_saslcap != NULL)
  312. {
  313. (void) strlcpy(mci->mci_saslcap, p, l);
  314. mci->mci_flags |= MCIF_AUTH;
  315. }
  316. }
  317. }
  318. # endif /* SASL */
  319. }
  320. # if SASL
  321. /*
  322. **  GETSASLDATA -- process the challenges from the SASL protocol
  323. **
  324. ** This gets the relevant sasl response data out of the reply
  325. ** from the server
  326. **
  327. ** Parameters:
  328. ** line -- the response line.
  329. ** firstline -- set if this is the first line of the reply.
  330. ** m -- the mailer.
  331. ** mci -- the mailer connection info.
  332. ** e -- the envelope.
  333. **
  334. ** Returns:
  335. ** none.
  336. */
  337. void
  338. getsasldata(line, firstline, m, mci, e)
  339. char *line;
  340. bool firstline;
  341. MAILER *m;
  342. register MCI *mci;
  343. ENVELOPE *e;
  344. {
  345. int len;
  346. char *out;
  347. int result;
  348. /* if not a continue we don't care about it */
  349. if ((strlen(line) <= 4) ||
  350.     (line[0] != '3') ||
  351.     (line[1] != '3') ||
  352.     (line[2] != '4'))
  353. {
  354. mci->mci_sasl_string = NULL;
  355. return;
  356. }
  357. /* forget about "334 " */
  358. line += 4;
  359. len = strlen(line);
  360. out = xalloc(len + 1);
  361. result = sasl_decode64(line, len, out, (u_int *)&len);
  362. if (result != SASL_OK)
  363. {
  364. len = 0;
  365. *out = '';
  366. }
  367. if (mci->mci_sasl_string != NULL)
  368. {
  369. if (mci->mci_sasl_string_len <= len)
  370. {
  371. free(mci->mci_sasl_string);
  372. mci->mci_sasl_string = xalloc(len + 1);
  373. }
  374. }
  375. else
  376. mci->mci_sasl_string = xalloc(len + 1);
  377. /* XXX this is probably leaked */
  378. memcpy(mci->mci_sasl_string, out, len);
  379. mci->mci_sasl_string[len] = '';
  380. mci->mci_sasl_string_len = len;
  381. free(out);
  382. return;
  383. }
  384. /*
  385. **  READAUTH -- read auth value from a file
  386. **
  387. ** Parameters:
  388. ** l -- line to define.
  389. ** filename -- name of file to read.
  390. ** safe -- if set, this is a safe read.
  391. **
  392. ** Returns:
  393. ** line from file
  394. **
  395. */
  396. /* lines in authinfo file */
  397. # define SASL_USER 1
  398. # define SASL_AUTHID 2
  399. # define SASL_PASSWORD 3
  400. # define SASL_DEFREALM 4
  401. # define SASL_MECH 5
  402. static char *sasl_info_name[] = {
  403. "",
  404. "user id",
  405. "authorization id",
  406. "password",
  407. "realm",
  408. "mechanism"
  409. };
  410. static char *
  411. readauth(l, filename, safe)
  412. int l;
  413. char *filename;
  414. bool safe;
  415. {
  416. FILE *f;
  417. long sff;
  418. pid_t pid;
  419. int lc;
  420. char *p;
  421. static char buf[MAXLINE];
  422. if (filename == NULL || filename[0] == '')
  423. return "";
  424. if (filename[0] == '|')
  425. {
  426. auto int fd;
  427. int i;
  428. char *argv[MAXPV + 1];
  429. i = 0;
  430. for (p = strtok(&filename[1], " t"); p != NULL;
  431.      p = strtok(NULL, " t"))
  432. {
  433. if (i >= MAXPV)
  434. break;
  435. argv[i++] = p;
  436. }
  437. argv[i] = NULL;
  438. pid = prog_open(argv, &fd, CurEnv);
  439. if (pid < 0)
  440. f = NULL;
  441. else
  442. f = fdopen(fd, "r");
  443. }
  444. else
  445. {
  446. pid = -1;
  447. sff = SFF_REGONLY | SFF_SAFEDIRPATH | SFF_NOWLINK
  448.       | SFF_NOGWFILES | SFF_NOWWFILES | SFF_NORFILES;
  449. if (safe)
  450. sff |= SFF_OPENASROOT;
  451. if (DontLockReadFiles)
  452. sff |= SFF_NOLOCK;
  453. f = safefopen(filename, O_RDONLY, 0, sff);
  454. }
  455. if (f == NULL)
  456. {
  457. syserr("readauth: cannot open %s", filename);
  458. return "";
  459. }
  460. lc = 0;
  461. while (lc < l && fgets(buf, sizeof buf, f) != NULL)
  462. {
  463. if (buf[0] != '#')
  464. lc++;
  465. }
  466. (void) fclose(f);
  467. if (pid > 0)
  468. (void) waitfor(pid);
  469. if (lc < l)
  470. {
  471. if (LogLevel >= 9)
  472. sm_syslog(LOG_WARNING, NOQID, "SASL: error: can't read %s from %s",
  473.   sasl_info_name[l], filename);
  474. return "";
  475. }
  476. lc = strlen(buf) - 1;
  477. if (lc >= 0)
  478. buf[lc] = '';
  479. if (tTd(95, 6))
  480. dprintf("readauth(%s, %d) = '%s'n", filename, l, buf);
  481. return buf;
  482. }
  483. /* keep lint happy */
  484. #  ifdef lint
  485. #   ifndef __attribute__
  486. #    define __attribute__(x)
  487. #   endif /* ! __attribute__ */
  488. #  endif /* lint */
  489. static int getsimple __P((void *, int, const char **, unsigned *));
  490. static int getsecret __P((sasl_conn_t *, void *, int, sasl_secret_t **));
  491. static int saslgetrealm __P((void *, int, const char **, const char **));
  492. static sasl_callback_t callbacks[] = {
  493. { SASL_CB_GETREALM, &saslgetrealm, NULL },
  494. # define CB_GETREALM_IDX 0
  495. { SASL_CB_PASS, &getsecret, NULL },
  496. # define CB_PASS_IDX 1
  497. { SASL_CB_USER, &getsimple, NULL },
  498. # define CB_USER_IDX 2
  499. { SASL_CB_AUTHNAME, &getsimple, NULL },
  500. # define CB_AUTHNAME_IDX 3
  501. { SASL_CB_VERIFYFILE, &safesaslfile, NULL },
  502. { SASL_CB_LIST_END, NULL, NULL }
  503. };
  504. /*
  505. **  GETSIMPLE -- callback to get userid or authid
  506. **
  507. ** Parameters:
  508. ** context -- unused
  509. ** id -- what to do
  510. ** result -- (pointer to) result
  511. ** len -- (pointer to) length of result
  512. **
  513. ** Returns:
  514. ** OK/failure values
  515. */
  516. static int
  517. getsimple(context, id, result, len)
  518. void *context __attribute__((unused));
  519. int id;
  520. const char **result;
  521. unsigned *len;
  522. {
  523. char *h;
  524. #  if SASL > 10509
  525. int addrealm;
  526. static int addedrealm = FALSE;
  527. #  endif /* SASL > 10509 */
  528. static char *user = NULL;
  529. static char *authid = NULL;
  530. if (result == NULL)
  531. return SASL_BADPARAM;
  532. switch (id) {
  533.   case SASL_CB_USER:
  534. if (user == NULL)
  535. {
  536. h = readauth(SASL_USER, SASLInfo, TRUE);
  537. user = newstr(h);
  538. }
  539. *result = user;
  540. if (tTd(95, 5))
  541. dprintf("AUTH username '%s'n", *result);
  542. if (len != NULL)
  543. *len = user ? strlen(user) : 0;
  544. break;
  545.   case SASL_CB_AUTHNAME:
  546. #  if SASL > 10509
  547. /* XXX maybe other mechanisms too?! */
  548. addrealm = context != NULL &&
  549.    strcasecmp(context, "CRAM-MD5") == 0;
  550. if (addedrealm != addrealm && authid != NULL)
  551. {
  552. free(authid);
  553. authid = NULL;
  554. addedrealm = addrealm;
  555. }
  556. #  endif /* SASL > 10509 */
  557. if (authid == NULL)
  558. {
  559. h = readauth(SASL_AUTHID, SASLInfo, TRUE);
  560. #  if SASL > 10509
  561. if (addrealm && strchr(h, '@') == NULL)
  562. {
  563. size_t l;
  564. char *realm;
  565. realm = callbacks[CB_GETREALM_IDX].context;
  566. l = strlen(h) + strlen(realm) + 2;
  567. authid = xalloc(l);
  568. snprintf(authid, l, "%s@%s", h, realm);
  569. }
  570. else
  571. #  endif /* SASL > 10509 */
  572. authid = newstr(h);
  573. }
  574. *result = authid;
  575. if (tTd(95, 5))
  576. dprintf("AUTH authid '%s'n", *result);
  577. if (len != NULL)
  578. *len = authid ? strlen(authid) : 0;
  579. break;
  580.   case SASL_CB_LANGUAGE:
  581. *result = NULL;
  582. if (len != NULL)
  583. *len = 0;
  584. break;
  585.   default:
  586. return SASL_BADPARAM;
  587. }
  588. return SASL_OK;
  589. }
  590. /*
  591. **  GETSECRET -- callback to get password
  592. **
  593. ** Parameters:
  594. ** conn -- connection information
  595. ** context -- unused
  596. ** id -- what to do
  597. ** psecret -- (pointer to) result
  598. **
  599. ** Returns:
  600. ** OK/failure values
  601. */
  602. static int
  603. getsecret(conn, context, id, psecret)
  604. sasl_conn_t *conn;
  605. void *context __attribute__((unused));
  606. int id;
  607. sasl_secret_t **psecret;
  608. {
  609. char *h;
  610. int len;
  611. static char *authpass = NULL;
  612. if (conn == NULL || psecret == NULL || id != SASL_CB_PASS)
  613. return SASL_BADPARAM;
  614. if (authpass == NULL)
  615. {
  616. h = readauth(SASL_PASSWORD, SASLInfo, TRUE);
  617. authpass = newstr(h);
  618. }
  619. len = strlen(authpass);
  620. *psecret = (sasl_secret_t *) malloc(sizeof(sasl_secret_t) + len + 1);
  621. if (*psecret == NULL)
  622. return SASL_FAIL;
  623. (void) strlcpy((*psecret)->data, authpass, len + 1);
  624. (*psecret)->len = len;
  625. return SASL_OK;
  626. }
  627. /*
  628. **  SAFESASLFILE -- callback for sasl: is file safe?
  629. **
  630. ** Parameters:
  631. ** context -- pointer to context between invocations (unused)
  632. ** file -- name of file to check
  633. **
  634. ** Returns:
  635. ** SASL_OK: file can be used
  636. ** SASL_CONTINUE: don't use file
  637. ** SASL_FAIL: failure (not used here)
  638. **
  639. */
  640. int
  641. safesaslfile(context, file)
  642. void *context;
  643. char *file;
  644. {
  645. long sff;
  646. int r;
  647. char *p;
  648. if (file == NULL || *file == '')
  649. return SASL_OK;
  650. sff = SFF_SAFEDIRPATH|SFF_NOWLINK|SFF_NOGWFILES|SFF_NOWWFILES|SFF_ROOTOK;
  651. if ((p = strrchr(file, '/')) == NULL)
  652. p = file;
  653. else
  654. ++p;
  655. /* everything beside libs must not be readable */
  656. if (strncmp(p, "lib", 3) != 0)
  657. sff |= SFF_NORFILES;
  658. if ((r = safefile(file, RunAsUid, RunAsGid, RunAsUserName, sff,
  659.      S_IRUSR, NULL)) == 0)
  660. return SASL_OK;
  661. if (LogLevel >= 11 || (r != ENOENT && LogLevel >= 9))
  662. sm_syslog(LOG_WARNING, NOQID, "error: safesasl(%s) failed: %s",
  663.   file, errstring(r));
  664. return SASL_CONTINUE;
  665. }
  666. /*
  667. **  SASLGETREALM -- return the realm for SASL
  668. **
  669. ** return the realm for the client
  670. **
  671. ** Parameters:
  672. ** context -- context shared between invocations
  673. ** here: realm to return
  674. ** availrealms -- list of available realms
  675. ** {realm, realm, ...}
  676. ** result -- pointer to result
  677. **
  678. ** Returns:
  679. ** failure/success
  680. */
  681. static int
  682. saslgetrealm(context, id, availrealms, result)
  683. void *context;
  684. int id;
  685. const char **availrealms;
  686. const char **result;
  687. {
  688. if (LogLevel > 12)
  689. sm_syslog(LOG_INFO, NOQID, "saslgetrealm: realm %s available realms %s",
  690.   context,
  691.   availrealms == NULL ? "<No Realms>" : *availrealms);
  692. if (context == NULL)
  693. return SASL_FAIL;
  694. /* check whether context is in list? */
  695. if (availrealms != NULL)
  696. {
  697. if (iteminlist(context, (char *)(*availrealms + 1), " ,}") ==
  698.     NULL)
  699. {
  700. if (LogLevel > 8)
  701. sm_syslog(LOG_ERR, NOQID,
  702.   "saslgetrealm: realm %s not in list %s",
  703.   context, *availrealms);
  704. return SASL_FAIL;
  705. }
  706. }
  707. *result = (char *)context;
  708. return SASL_OK;
  709. }
  710. /*
  711. **  ITEMINLIST -- does item appear in list?
  712. **
  713. ** Check whether item appears in list (which must be separated by a
  714. ** character in delim) as a "word", i.e. it must appear at the begin
  715. ** of the list or after a space, and it must end with a space or the
  716. ** end of the list.
  717. **
  718. ** Parameters:
  719. ** item -- item to search.
  720. ** list -- list of items.
  721. ** delim -- list of delimiters.
  722. **
  723. ** Returns:
  724. ** pointer to occurrence (NULL if not found).
  725. */
  726. char *
  727. iteminlist(item, list, delim)
  728. char *item;
  729. char *list;
  730. char *delim;
  731. {
  732. char *s;
  733. int len;
  734. if (list == NULL || *list == '')
  735. return NULL;
  736. if (item == NULL || *item == '')
  737. return NULL;
  738. s = list;
  739. len = strlen(item);
  740. while (s != NULL && *s != '')
  741. {
  742. if (strncasecmp(s, item, len) == 0 &&
  743.     (s[len] == '' || strchr(delim, s[len]) != NULL))
  744. return s;
  745. s = strpbrk(s, delim);
  746. if (s != NULL)
  747. while (*++s == ' ')
  748. continue;
  749. }
  750. return NULL;
  751. }
  752. /*
  753. **  REMOVEMECH -- remove item [rem] from list [list]
  754. **
  755. ** Parameters:
  756. ** rem -- item to remove
  757. ** list -- list of items
  758. **
  759. ** Returns:
  760. ** pointer to new list (NULL in case of error).
  761. */
  762. char *
  763. removemech(rem, list)
  764. char *rem;
  765. char *list;
  766. {
  767. char *ret;
  768. char *needle;
  769. int len;
  770. if (list == NULL)
  771. return NULL;
  772. if (rem == NULL || *rem == '')
  773. {
  774. /* take out what? */
  775. return NULL;
  776. }
  777. /* find the item in the list */
  778. if ((needle = (iteminlist(rem, list, " "))) == NULL)
  779. {
  780. /* not in there: return original */
  781. return list;
  782. }
  783. /* length of string without rem */
  784. len = strlen(list) - strlen(rem);
  785. ret = xalloc(len);  /* XXX leaked */
  786. memset(ret, '', len);
  787. /* copy from start to removed item */
  788. memcpy(ret, list, needle - list);
  789. /* length of rest of string past removed item */
  790. len = strlen(needle) - strlen(rem) - 1;
  791. if (len > 0)
  792. {
  793. /* not last item -- copy into string */
  794. memcpy(ret + (needle - list),
  795.        list + (needle - list) + strlen(rem) + 1,
  796.        len);
  797. }
  798. else
  799. ret[(needle - list) - 1] = '';
  800. return ret;
  801. }
  802. /*
  803. **  INTERSECT -- create the intersection between two lists
  804. **
  805. ** Parameters:
  806. ** s1, s2 -- lists of items (separated by single blanks).
  807. **
  808. ** Returns:
  809. ** the intersection of both lists.
  810. */
  811. char *
  812. intersect(s1, s2)
  813. char *s1, *s2;
  814. {
  815. char *hr, *h1, *h, *res;
  816. int l1, l2, rl;
  817. if (s1 == NULL || s2 == NULL) /* NULL string(s) -> NULL result */
  818. return NULL;
  819. l1 = strlen(s1);
  820. l2 = strlen(s2);
  821. rl = min(l1, l2);
  822. res = (char *)malloc(rl + 1);
  823. if (res == NULL)
  824. return NULL;
  825. *res = '';
  826. if (rl == 0) /* at least one string empty? */
  827. return res;
  828. hr = res;
  829. h1 = s1;
  830. h = s1;
  831. /* walk through s1 */
  832. while (h != NULL && *h1 != '')
  833. {
  834. /* is there something after the current word? */
  835. if ((h = strchr(h1, ' ')) != NULL)
  836. *h = '';
  837. l1 = strlen(h1);
  838. /* does the current word appear in s2 ? */
  839. if (iteminlist(h1, s2, " ") != NULL)
  840. {
  841. /* add a blank if not first item */
  842. if (hr != res)
  843. *hr++ = ' ';
  844. /* copy the item */
  845. memcpy(hr, h1, l1);
  846. /* advance pointer in result list */
  847. hr += l1;
  848. *hr = '';
  849. }
  850. if (h != NULL)
  851. {
  852. /* there are more items */
  853. *h = ' ';
  854. h1 = h + 1;
  855. }
  856. }
  857. return res;
  858. }
  859. /*
  860. **  ATTEMPTAUTH -- try to AUTHenticate using one mechanism
  861. **
  862. ** Parameters:
  863. ** m -- the mailer.
  864. ** mci -- the mailer connection structure.
  865. ** e -- the envelope (including the sender to specify).
  866. ** mechused - filled in with mechanism used
  867. **
  868. ** Returns:
  869. ** EX_OK/EX_TEMPFAIL
  870. */
  871. #  define MAXOUTLEN 1024
  872. int
  873. attemptauth(m, mci, e, mechused)
  874. MAILER *m;
  875. MCI *mci;
  876. ENVELOPE *e;
  877. char **mechused;
  878. {
  879. int saslresult, smtpresult;
  880. sasl_external_properties_t ssf;
  881. sasl_interact_t *client_interact = NULL;
  882. char *out;
  883. unsigned int outlen;
  884. static char *mechusing;
  885. sasl_security_properties_t ssp;
  886. char in64[MAXOUTLEN];
  887. # if NETINET
  888. extern SOCKADDR CurHostAddr;
  889. # endif /* NETINET */
  890. *mechused = NULL;
  891. if (mci->mci_conn != NULL)
  892. free(mci->mci_conn);
  893. mci->mci_conn = NULL;
  894. /* make a new client sasl connection */
  895. saslresult = sasl_client_new("smtp", CurHostName, NULL, 0,
  896.      &mci->mci_conn);
  897. /* set properties */
  898. (void) memset(&ssp, '', sizeof ssp);
  899. saslresult = sasl_setprop(mci->mci_conn, SASL_SEC_PROPS, &ssp);
  900. if (saslresult != SASL_OK)
  901. return EX_TEMPFAIL;
  902. /* external security strength factor; we have none so zero */
  903. ssf.ssf = 0;
  904. ssf.auth_id = NULL;
  905. saslresult = sasl_setprop(mci->mci_conn, SASL_SSF_EXTERNAL, &ssf);
  906. if (saslresult != SASL_OK)
  907. return EX_TEMPFAIL;
  908. # if NETINET
  909. /* set local/remote ipv4 addresses */
  910. if (mci->mci_out != NULL && CurHostAddr.sa.sa_family == AF_INET)
  911. {
  912. SOCKADDR_LEN_T addrsize;
  913. struct sockaddr_in saddr_l;
  914. if (sasl_setprop(mci->mci_conn, SASL_IP_REMOTE,
  915.  (struct sockaddr_in *) &CurHostAddr)
  916.     != SASL_OK)
  917. return EX_TEMPFAIL;
  918. addrsize = sizeof(struct sockaddr_in);
  919. if (getsockname(fileno(mci->mci_out),
  920. (struct sockaddr *) &saddr_l, &addrsize) != 0)
  921. {
  922. if (sasl_setprop(mci->mci_conn, SASL_IP_LOCAL,
  923.  &saddr_l) != SASL_OK)
  924. return EX_TEMPFAIL;
  925. }
  926. }
  927. # endif /* NETINET */
  928. /* start client side of sasl */
  929. saslresult = sasl_client_start(mci->mci_conn, mci->mci_saslcap,
  930.        NULL, &client_interact,
  931.        &out, &outlen,
  932.        (const char **)&mechusing);
  933. callbacks[CB_AUTHNAME_IDX].context = mechusing;
  934. if (saslresult != SASL_OK && saslresult != SASL_CONTINUE)
  935. {
  936. return EX_TEMPFAIL;
  937. }
  938. *mechused = mechusing;
  939. /* send the info across the wire */
  940. if (outlen > 0)
  941. {
  942. saslresult = sasl_encode64(out, outlen, in64, MAXOUTLEN, NULL);
  943. if (saslresult != SASL_OK) /* internal error */
  944. {
  945. if (LogLevel > 8)
  946. sm_syslog(LOG_ERR, e->e_id,
  947. "encode64 for AUTH failed");
  948. return EX_TEMPFAIL;
  949. }
  950. smtpmessage("AUTH %s %s", m, mci, mechusing, in64);
  951. }
  952. else
  953. {
  954. smtpmessage("AUTH %s", m, mci, mechusing);
  955. }
  956. /* get the reply */
  957. smtpresult = reply(m, mci, e, TimeOuts.to_datafinal, getsasldata, NULL);
  958. /* which timeout? XXX */
  959. for (;;)
  960. {
  961. /* check return code from server */
  962. if (smtpresult == 235)
  963. return EX_OK;
  964. if (smtpresult == -1)
  965. return EX_IOERR;
  966. if (smtpresult != 334)
  967. return EX_TEMPFAIL;
  968. saslresult = sasl_client_step(mci->mci_conn,
  969.       mci->mci_sasl_string,
  970.       mci->mci_sasl_string_len,
  971.       &client_interact,
  972.       &out, &outlen);
  973. if (saslresult != SASL_OK && saslresult != SASL_CONTINUE)
  974. {
  975. if (tTd(95, 5))
  976. dprintf("AUTH FAIL: %s (%d)n",
  977. sasl_errstring(saslresult, NULL, NULL),
  978. saslresult);
  979. /* fail deliberately, see RFC 2254 4. */
  980. smtpmessage("*", m, mci);
  981. /*
  982. **  but we should only fail for this authentication
  983. **  mechanism; how to do that?
  984. */
  985. smtpresult = reply(m, mci, e, TimeOuts.to_datafinal,
  986.    getsasldata, NULL);
  987. return EX_TEMPFAIL;
  988. }
  989. if (outlen > 0)
  990. {
  991. saslresult = sasl_encode64(out, outlen, in64,
  992.    MAXOUTLEN, NULL);
  993. if (saslresult != SASL_OK)
  994. {
  995. /* give an error reply to the other side! */
  996. smtpmessage("*", m, mci);
  997. return EX_TEMPFAIL;
  998. }
  999. }
  1000. else
  1001. in64[0] = '';
  1002. smtpmessage(in64, m, mci);
  1003. smtpresult = reply(m, mci, e, TimeOuts.to_datafinal,
  1004.    getsasldata, NULL);
  1005. /* which timeout? XXX */
  1006. }
  1007. /* NOTREACHED */
  1008. }
  1009. /*
  1010. **  SMTPAUTH -- try to AUTHenticate
  1011. **
  1012. ** This will try mechanisms in the order the sasl library decided until:
  1013. ** - there are no more mechanisms
  1014. ** - a mechanism succeeds
  1015. ** - the sasl library fails initializing
  1016. **
  1017. ** Parameters:
  1018. ** m -- the mailer.
  1019. ** mci -- the mailer connection info.
  1020. ** e -- the envelope.
  1021. **
  1022. ** Returns:
  1023. ** EX_OK/EX_TEMPFAIL
  1024. */
  1025. int
  1026. smtpauth(m, mci, e)
  1027. MAILER *m;
  1028. MCI *mci;
  1029. ENVELOPE *e;
  1030. {
  1031. int result;
  1032. char *mechused;
  1033. char *h;
  1034. static char *defrealm = NULL;
  1035. mci->mci_sasl_auth = FALSE;
  1036. if (defrealm == NULL)
  1037. {
  1038. h = readauth(SASL_DEFREALM, SASLInfo, TRUE);
  1039. if (h != NULL && *h != '')
  1040. defrealm = newstr(h);
  1041. }
  1042. if (defrealm == NULL || *defrealm == '')
  1043. defrealm = newstr(macvalue('j', CurEnv));
  1044. callbacks[CB_GETREALM_IDX].context = defrealm;
  1045. /* initialize sasl client library */
  1046. result = sasl_client_init(callbacks);
  1047. if (result != SASL_OK)
  1048. return EX_TEMPFAIL;
  1049. do {
  1050. result = attemptauth(m, mci, e, &mechused);
  1051. if (result == EX_OK)
  1052. mci->mci_sasl_auth = TRUE;
  1053. else if (result == EX_TEMPFAIL)
  1054. {
  1055. mci->mci_saslcap = removemech(mechused,
  1056.       mci->mci_saslcap);
  1057. if (mci->mci_saslcap == NULL)
  1058. return EX_TEMPFAIL;
  1059. }
  1060. else /* all others for now */
  1061. return EX_TEMPFAIL;
  1062. } while (result != EX_OK);
  1063. return result;
  1064. }
  1065. # endif /* SASL */
  1066. /*
  1067. **  SMTPMAILFROM -- send MAIL command
  1068. **
  1069. ** Parameters:
  1070. ** m -- the mailer.
  1071. ** mci -- the mailer connection structure.
  1072. ** e -- the envelope (including the sender to specify).
  1073. */
  1074. int
  1075. smtpmailfrom(m, mci, e)
  1076. MAILER *m;
  1077. MCI *mci;
  1078. ENVELOPE *e;
  1079. {
  1080. int r;
  1081. char *bufp;
  1082. char *bodytype;
  1083. char buf[MAXNAME + 1];
  1084. char optbuf[MAXLINE];
  1085. char *enhsc;
  1086. if (tTd(18, 2))
  1087. dprintf("smtpmailfrom: CurHost=%sn", CurHostName);
  1088. enhsc = NULL;
  1089. /* set up appropriate options to include */
  1090. if (bitset(MCIF_SIZE, mci->mci_flags) && e->e_msgsize > 0)
  1091. {
  1092. snprintf(optbuf, sizeof optbuf, " SIZE=%ld", e->e_msgsize);
  1093. bufp = &optbuf[strlen(optbuf)];
  1094. }
  1095. else
  1096. {
  1097. optbuf[0] = '';
  1098. bufp = optbuf;
  1099. }
  1100. bodytype = e->e_bodytype;
  1101. if (bitset(MCIF_8BITMIME, mci->mci_flags))
  1102. {
  1103. if (bodytype == NULL &&
  1104.     bitset(MM_MIME8BIT, MimeMode) &&
  1105.     bitset(EF_HAS8BIT, e->e_flags) &&
  1106.     !bitset(EF_DONT_MIME, e->e_flags) &&
  1107.     !bitnset(M_8BITS, m->m_flags))
  1108. bodytype = "8BITMIME";
  1109. if (bodytype != NULL &&
  1110.     SPACELEFT(optbuf, bufp) > strlen(bodytype) + 7)
  1111. {
  1112. snprintf(bufp, SPACELEFT(optbuf, bufp),
  1113.  " BODY=%s", bodytype);
  1114. bufp += strlen(bufp);
  1115. }
  1116. }
  1117. else if (bitnset(M_8BITS, m->m_flags) ||
  1118.  !bitset(EF_HAS8BIT, e->e_flags) ||
  1119.  bitset(MCIF_8BITOK, mci->mci_flags))
  1120. {
  1121. /* EMPTY */
  1122. /* just pass it through */
  1123. }
  1124. # if MIME8TO7
  1125. else if (bitset(MM_CVTMIME, MimeMode) &&
  1126.  !bitset(EF_DONT_MIME, e->e_flags) &&
  1127.  (!bitset(MM_PASS8BIT, MimeMode) ||
  1128.   bitset(EF_IS_MIME, e->e_flags)))
  1129. {
  1130. /* must convert from 8bit MIME format to 7bit encoded */
  1131. mci->mci_flags |= MCIF_CVT8TO7;
  1132. }
  1133. # endif /* MIME8TO7 */
  1134. else if (!bitset(MM_PASS8BIT, MimeMode))
  1135. {
  1136. /* cannot just send a 8-bit version */
  1137. extern char MsgBuf[];
  1138. usrerrenh("5.6.3", "%s does not support 8BITMIME", CurHostName);
  1139. mci_setstat(mci, EX_NOTSTICKY, "5.6.3", MsgBuf);
  1140. return EX_DATAERR;
  1141. }
  1142. if (bitset(MCIF_DSN, mci->mci_flags))
  1143. {
  1144. if (e->e_envid != NULL &&
  1145.     SPACELEFT(optbuf, bufp) > strlen(e->e_envid) + 7)
  1146. {
  1147. snprintf(bufp, SPACELEFT(optbuf, bufp),
  1148.  " ENVID=%s", e->e_envid);
  1149. bufp += strlen(bufp);
  1150. }
  1151. /* RET= parameter */
  1152. if (bitset(EF_RET_PARAM, e->e_flags) &&
  1153.     SPACELEFT(optbuf, bufp) > 9)
  1154. {
  1155. snprintf(bufp, SPACELEFT(optbuf, bufp),
  1156.  " RET=%s",
  1157.  bitset(EF_NO_BODY_RETN, e->e_flags) ?
  1158. "HDRS" : "FULL");
  1159. bufp += strlen(bufp);
  1160. }
  1161. }
  1162. if (bitset(MCIF_AUTH, mci->mci_flags) && e->e_auth_param != NULL &&
  1163.     SPACELEFT(optbuf, bufp) > strlen(e->e_auth_param) + 7 &&
  1164.     (SASLTryAuth == SASL_TRY_AUTH
  1165. #if SASL
  1166.      || (SASLTryAuth == SASL_AUTH_AUTH && mci->mci_sasl_auth)
  1167. #else /* SASL */
  1168. #endif /* SASL */
  1169.     ))
  1170. {
  1171. snprintf(bufp, SPACELEFT(optbuf, bufp),
  1172.  " AUTH=%s", e->e_auth_param);
  1173. bufp += strlen(bufp);
  1174. }
  1175. /*
  1176. **  Send the MAIL command.
  1177. ** Designates the sender.
  1178. */
  1179. mci->mci_state = MCIS_ACTIVE;
  1180. if (bitset(EF_RESPONSE, e->e_flags) &&
  1181.     !bitnset(M_NO_NULL_FROM, m->m_flags))
  1182. buf[0] = '';
  1183. else
  1184. expand("201g", buf, sizeof buf, e);
  1185. if (buf[0] == '<')
  1186. {
  1187. /* strip off <angle brackets> (put back on below) */
  1188. bufp = &buf[strlen(buf) - 1];
  1189. if (*bufp == '>')
  1190. *bufp = '';
  1191. bufp = &buf[1];
  1192. }
  1193. else
  1194. bufp = buf;
  1195. if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) ||
  1196.     !bitnset(M_FROMPATH, m->m_flags))
  1197. {
  1198. smtpmessage("MAIL From:<%s>%s", m, mci, bufp, optbuf);
  1199. }
  1200. else
  1201. {
  1202. smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName,
  1203. *bufp == '@' ? ',' : ':', bufp, optbuf);
  1204. }
  1205. SmtpPhase = mci->mci_phase = "client MAIL";
  1206. sm_setproctitle(TRUE, e, "%s %s: %s", qid_printname(e),
  1207. CurHostName, mci->mci_phase);
  1208. r = reply(m, mci, e, TimeOuts.to_mail, NULL, &enhsc);
  1209. if (r < 0)
  1210. {
  1211. /* communications failure */
  1212. mci->mci_errno = errno;
  1213. mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL);
  1214. smtpquit(m, mci, e);
  1215. return EX_TEMPFAIL;
  1216. }
  1217. else if (r == 421)
  1218. {
  1219. /* service shutting down */
  1220. mci_setstat(mci, EX_TEMPFAIL, ENHSCN(enhsc, "4.5.0"),
  1221.     SmtpReplyBuffer);
  1222. smtpquit(m, mci, e);
  1223. return EX_TEMPFAIL;
  1224. }
  1225. else if (REPLYTYPE(r) == 4)
  1226. {
  1227. mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, smtptodsn(r)),
  1228.     SmtpReplyBuffer);
  1229. return EX_TEMPFAIL;
  1230. }
  1231. else if (REPLYTYPE(r) == 2)
  1232. {
  1233. return EX_OK;
  1234. }
  1235. else if (r == 501)
  1236. {
  1237. /* syntax error in arguments */
  1238. mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.5.2"),
  1239.     SmtpReplyBuffer);
  1240. return EX_DATAERR;
  1241. }
  1242. else if (r == 553)
  1243. {
  1244. /* mailbox name not allowed */
  1245. mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.1.3"),
  1246.     SmtpReplyBuffer);
  1247. return EX_DATAERR;
  1248. }
  1249. else if (r == 552)
  1250. {
  1251. /* exceeded storage allocation */
  1252. mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.3.4"),
  1253.     SmtpReplyBuffer);
  1254. if (bitset(MCIF_SIZE, mci->mci_flags))
  1255. e->e_flags |= EF_NO_BODY_RETN;
  1256. return EX_UNAVAILABLE;
  1257. }
  1258. else if (REPLYTYPE(r) == 5)
  1259. {
  1260. /* unknown error */
  1261. mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.0.0"),
  1262.     SmtpReplyBuffer);
  1263. return EX_UNAVAILABLE;
  1264. }
  1265. if (LogLevel > 1)
  1266. {
  1267. sm_syslog(LOG_CRIT, e->e_id,
  1268.   "%.100s: SMTP MAIL protocol error: %s",
  1269.   CurHostName,
  1270.   shortenstring(SmtpReplyBuffer, 403));
  1271. }
  1272. /* protocol error -- close up */
  1273. mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"),
  1274.     SmtpReplyBuffer);
  1275. smtpquit(m, mci, e);
  1276. return EX_PROTOCOL;
  1277. }
  1278. /*
  1279. **  SMTPRCPT -- designate recipient.
  1280. **
  1281. ** Parameters:
  1282. ** to -- address of recipient.
  1283. ** m -- the mailer we are sending to.
  1284. ** mci -- the connection info for this transaction.
  1285. ** e -- the envelope for this transaction.
  1286. **
  1287. ** Returns:
  1288. ** exit status corresponding to recipient status.
  1289. **
  1290. ** Side Effects:
  1291. ** Sends the mail via SMTP.
  1292. */
  1293. int
  1294. smtprcpt(to, m, mci, e)
  1295. ADDRESS *to;
  1296. register MAILER *m;
  1297. MCI *mci;
  1298. ENVELOPE *e;
  1299. {
  1300. register int r;
  1301. char *bufp;
  1302. char optbuf[MAXLINE];
  1303. char *enhsc;
  1304. enhsc = NULL;
  1305. optbuf[0] = '';
  1306. bufp = optbuf;
  1307. /*
  1308. **  warning: in the following it is assumed that the free space
  1309. **  in bufp is sizeof optbuf
  1310. */
  1311. if (bitset(MCIF_DSN, mci->mci_flags))
  1312. {
  1313. /* NOTIFY= parameter */
  1314. if (bitset(QHASNOTIFY, to->q_flags) &&
  1315.     bitset(QPRIMARY, to->q_flags) &&
  1316.     !bitnset(M_LOCALMAILER, m->m_flags))
  1317. {
  1318. bool firstone = TRUE;
  1319. (void) strlcat(bufp, " NOTIFY=", sizeof optbuf);
  1320. if (bitset(QPINGONSUCCESS, to->q_flags))
  1321. {
  1322. (void) strlcat(bufp, "SUCCESS", sizeof optbuf);
  1323. firstone = FALSE;
  1324. }
  1325. if (bitset(QPINGONFAILURE, to->q_flags))
  1326. {
  1327. if (!firstone)
  1328. (void) strlcat(bufp, ",",
  1329.        sizeof optbuf);
  1330. (void) strlcat(bufp, "FAILURE", sizeof optbuf);
  1331. firstone = FALSE;
  1332. }
  1333. if (bitset(QPINGONDELAY, to->q_flags))
  1334. {
  1335. if (!firstone)
  1336. (void) strlcat(bufp, ",",
  1337.        sizeof optbuf);
  1338. (void) strlcat(bufp, "DELAY", sizeof optbuf);
  1339. firstone = FALSE;
  1340. }
  1341. if (firstone)
  1342. (void) strlcat(bufp, "NEVER", sizeof optbuf);
  1343. bufp += strlen(bufp);
  1344. }
  1345. /* ORCPT= parameter */
  1346. if (to->q_orcpt != NULL &&
  1347.     SPACELEFT(optbuf, bufp) > strlen(to->q_orcpt) + 7)
  1348. {
  1349. snprintf(bufp, SPACELEFT(optbuf, bufp),
  1350.  " ORCPT=%s", to->q_orcpt);
  1351. bufp += strlen(bufp);
  1352. }
  1353. }
  1354. smtpmessage("RCPT To:<%s>%s", m, mci, to->q_user, optbuf);
  1355. SmtpPhase = mci->mci_phase = "client RCPT";
  1356. sm_setproctitle(TRUE, e, "%s %s: %s", qid_printname(e),
  1357. CurHostName, mci->mci_phase);
  1358. r = reply(m, mci, e, TimeOuts.to_rcpt, NULL, &enhsc);
  1359. to->q_rstatus = newstr(SmtpReplyBuffer);
  1360. to->q_status = ENHSCN(enhsc, smtptodsn(r));
  1361. if (!bitnset(M_LMTP, m->m_flags))
  1362. to->q_statmta = mci->mci_host;
  1363. if (r < 0 || REPLYTYPE(r) == 4)
  1364. return EX_TEMPFAIL;
  1365. else if (REPLYTYPE(r) == 2)
  1366. return EX_OK;
  1367. else if (r == 550)
  1368. {
  1369. to->q_status = ENHSCN(enhsc, "5.1.1");
  1370. return EX_NOUSER;
  1371. }
  1372. else if (r == 551)
  1373. {
  1374. to->q_status = ENHSCN(enhsc, "5.1.6");
  1375. return EX_NOUSER;
  1376. }
  1377. else if (r == 553)
  1378. {
  1379. to->q_status = ENHSCN(enhsc, "5.1.3");
  1380. return EX_NOUSER;
  1381. }
  1382. else if (REPLYTYPE(r) == 5)
  1383. {
  1384. return EX_UNAVAILABLE;
  1385. }
  1386. if (LogLevel > 1)
  1387. {
  1388. sm_syslog(LOG_CRIT, e->e_id,
  1389.   "%.100s: SMTP RCPT protocol error: %s",
  1390.   CurHostName,
  1391.   shortenstring(SmtpReplyBuffer, 403));
  1392. }
  1393. mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"),
  1394.     SmtpReplyBuffer);
  1395. return EX_PROTOCOL;
  1396. }
  1397. /*
  1398. **  SMTPDATA -- send the data and clean up the transaction.
  1399. **
  1400. ** Parameters:
  1401. ** m -- mailer being sent to.
  1402. ** mci -- the mailer connection information.
  1403. ** e -- the envelope for this message.
  1404. **
  1405. ** Returns:
  1406. ** exit status corresponding to DATA command.
  1407. **
  1408. ** Side Effects:
  1409. ** none.
  1410. */
  1411. static jmp_buf CtxDataTimeout;
  1412. int
  1413. smtpdata(m, mci, e)
  1414. MAILER *m;
  1415. register MCI *mci;
  1416. register ENVELOPE *e;
  1417. {
  1418. register int r;
  1419. register EVENT *ev;
  1420. int rstat;
  1421. int xstat;
  1422. time_t timeout;
  1423. char *enhsc;
  1424. enhsc = NULL;
  1425. /*
  1426. **  Send the data.
  1427. ** First send the command and check that it is ok.
  1428. ** Then send the data.
  1429. ** Follow it up with a dot to terminate.
  1430. ** Finally get the results of the transaction.
  1431. */
  1432. /* send the command and check ok to proceed */
  1433. smtpmessage("DATA", m, mci);
  1434. SmtpPhase = mci->mci_phase = "client DATA 354";
  1435. sm_setproctitle(TRUE, e, "%s %s: %s",
  1436. qid_printname(e), CurHostName, mci->mci_phase);
  1437. r = reply(m, mci, e, TimeOuts.to_datainit, NULL, &enhsc);
  1438. if (r < 0 || REPLYTYPE(r) == 4)
  1439. {
  1440. smtpquit(m, mci, e);
  1441. return EX_TEMPFAIL;
  1442. }
  1443. else if (REPLYTYPE(r) == 5)
  1444. {
  1445. smtprset(m, mci, e);
  1446. return EX_UNAVAILABLE;
  1447. }
  1448. else if (REPLYTYPE(r) != 3)
  1449. {
  1450. if (LogLevel > 1)
  1451. {
  1452. sm_syslog(LOG_CRIT, e->e_id,
  1453.   "%.100s: SMTP DATA-1 protocol error: %s",
  1454.   CurHostName,
  1455.   shortenstring(SmtpReplyBuffer, 403));
  1456. }
  1457. smtprset(m, mci, e);
  1458. mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"),
  1459.     SmtpReplyBuffer);
  1460. return EX_PROTOCOL;
  1461. }
  1462. /*
  1463. **  Set timeout around data writes.  Make it at least large
  1464. **  enough for DNS timeouts on all recipients plus some fudge
  1465. **  factor.  The main thing is that it should not be infinite.
  1466. */
  1467. if (setjmp(CtxDataTimeout) != 0)
  1468. {
  1469. mci->mci_errno = errno;
  1470. mci->mci_state = MCIS_ERROR;
  1471. mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL);
  1472. /*
  1473. **  If putbody() couldn't finish due to a timeout,
  1474. **  rewind it here in the timeout handler.  See
  1475. **  comments at the end of putbody() for reasoning.
  1476. */
  1477. if (e->e_dfp != NULL)
  1478. (void) bfrewind(e->e_dfp);
  1479. errno = mci->mci_errno;
  1480. syserr("451 4.4.1 timeout writing message to %s", CurHostName);
  1481. smtpquit(m, mci, e);
  1482. return EX_TEMPFAIL;
  1483. }
  1484. if (tTd(18, 101))
  1485. {
  1486. /* simulate a DATA timeout */
  1487. timeout = 1;
  1488. }
  1489. else
  1490. timeout = DATA_PROGRESS_TIMEOUT;
  1491. ev = setevent(timeout, datatimeout, 0);
  1492. if (tTd(18, 101))
  1493. {
  1494. /* simulate a DATA timeout */
  1495. (void) sleep(1);
  1496. }
  1497. /*
  1498. **  Output the actual message.
  1499. */
  1500. (*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER);
  1501. (*e->e_putbody)(mci, e, NULL);
  1502. /*
  1503. **  Cleanup after sending message.
  1504. */
  1505. clrevent(ev);
  1506. # if _FFR_CATCH_BROKEN_MTAS
  1507. {
  1508. fd_set readfds;
  1509. struct timeval timeout;
  1510. FD_ZERO(&readfds);
  1511. FD_SET(fileno(mci->mci_in), &readfds);
  1512. timeout.tv_sec = 0;
  1513. timeout.tv_usec = 0;
  1514. if (select(fileno(mci->mci_in) + 1, FDSET_CAST &readfds,
  1515.    NULL, NULL, &timeout) > 0 &&
  1516.     FD_ISSET(fileno(mci->mci_in), &readfds))
  1517. {
  1518. /* terminate the message */
  1519. fprintf(mci->mci_out, ".%s", m->m_eol);
  1520. if (TrafficLogFile != NULL)
  1521. fprintf(TrafficLogFile, "%05d >>> .n",
  1522. (int) getpid());
  1523. if (Verbose)
  1524. nmessage(">>> .");
  1525. mci->mci_errno = EIO;
  1526. mci->mci_state = MCIS_ERROR;
  1527. mci_setstat(mci, EX_PROTOCOL, "5.5.0", NULL);
  1528. smtpquit(m, mci, e);
  1529. return EX_PROTOCOL;
  1530. }
  1531. }
  1532. # endif /* _FFR_CATCH_BROKEN_MTAS */
  1533. if (ferror(mci->mci_out))
  1534. {
  1535. /* error during processing -- don't send the dot */
  1536. mci->mci_errno = EIO;
  1537. mci->mci_state = MCIS_ERROR;
  1538. mci_setstat(mci, EX_IOERR, "4.4.2", NULL);
  1539. smtpquit(m, mci, e);
  1540. return EX_IOERR;
  1541. }
  1542. /* terminate the message */
  1543. fprintf(mci->mci_out, ".%s", m->m_eol);
  1544. if (TrafficLogFile != NULL)
  1545. fprintf(TrafficLogFile, "%05d >>> .n", (int) getpid());
  1546. if (Verbose)
  1547. nmessage(">>> .");
  1548. /* check for the results of the transaction */
  1549. SmtpPhase = mci->mci_phase = "client DATA status";
  1550. sm_setproctitle(TRUE, e, "%s %s: %s", qid_printname(e),
  1551. CurHostName, mci->mci_phase);
  1552. if (bitnset(M_LMTP, m->m_flags))
  1553. return EX_OK;
  1554. r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc);
  1555. if (r < 0)
  1556. {
  1557. smtpquit(m, mci, e);
  1558. return EX_TEMPFAIL;
  1559. }
  1560. mci->mci_state = MCIS_OPEN;
  1561. xstat = EX_NOTSTICKY;
  1562. if (r == 452)
  1563. rstat = EX_TEMPFAIL;
  1564. else if (REPLYTYPE(r) == 4)
  1565. rstat = xstat = EX_TEMPFAIL;
  1566. else if (REPLYCLASS(r) != 5)
  1567. rstat = xstat = EX_PROTOCOL;
  1568. else if (REPLYTYPE(r) == 2)
  1569. rstat = xstat = EX_OK;
  1570. else if (REPLYTYPE(r) == 5)
  1571. rstat = EX_UNAVAILABLE;
  1572. else
  1573. rstat = EX_PROTOCOL;
  1574. mci_setstat(mci, xstat, ENHSCN(enhsc, smtptodsn(r)),
  1575.     SmtpReplyBuffer);
  1576. if (e->e_statmsg != NULL)
  1577. free(e->e_statmsg);
  1578. if (bitset(MCIF_ENHSTAT, mci->mci_flags) &&
  1579.     (r = isenhsc(SmtpReplyBuffer + 4, ' ')) > 0)
  1580. r += 5;
  1581. else
  1582. r = 4;
  1583. e->e_statmsg = newstr(&SmtpReplyBuffer[r]);
  1584. if (rstat != EX_PROTOCOL)
  1585. return rstat;
  1586. if (LogLevel > 1)
  1587. {
  1588. sm_syslog(LOG_CRIT, e->e_id,
  1589.   "%.100s: SMTP DATA-2 protocol error: %s",
  1590.   CurHostName,
  1591.   shortenstring(SmtpReplyBuffer, 403));
  1592. }
  1593. return rstat;
  1594. }
  1595. static void
  1596. datatimeout()
  1597. {
  1598. if (DataProgress)
  1599. {
  1600. time_t timeout;
  1601. register EVENT *ev;
  1602. /* check back again later */
  1603. if (tTd(18, 101))
  1604. {
  1605. /* simulate a DATA timeout */
  1606. timeout = 1;
  1607. }
  1608. else
  1609. timeout = DATA_PROGRESS_TIMEOUT;
  1610. DataProgress = FALSE;
  1611. ev = setevent(timeout, datatimeout, 0);
  1612. }
  1613. else
  1614. {
  1615. /* no progress, give up */
  1616. longjmp(CtxDataTimeout, 1);
  1617. }
  1618. }
  1619. /*
  1620. **  SMTPGETSTAT -- get status code from DATA in LMTP
  1621. **
  1622. ** Parameters:
  1623. ** m -- the mailer to which we are sending the message.
  1624. ** mci -- the mailer connection structure.
  1625. ** e -- the current envelope.
  1626. **
  1627. ** Returns:
  1628. ** The exit status corresponding to the reply code.
  1629. */
  1630. int
  1631. smtpgetstat(m, mci, e)
  1632. MAILER *m;
  1633. MCI *mci;
  1634. ENVELOPE *e;
  1635. {
  1636. int r;
  1637. int status;
  1638. char *enhsc;
  1639. enhsc = NULL;
  1640. /* check for the results of the transaction */
  1641. r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc);
  1642. if (r < 0)
  1643. {
  1644. smtpquit(m, mci, e);
  1645. return EX_TEMPFAIL;
  1646. }
  1647. if (REPLYTYPE(r) == 4)
  1648. status = EX_TEMPFAIL;
  1649. else if (REPLYCLASS(r) != 5)
  1650. status = EX_PROTOCOL;
  1651. else if (REPLYTYPE(r) == 2)
  1652. status = EX_OK;
  1653. else if (REPLYTYPE(r) == 5)
  1654. status = EX_UNAVAILABLE;
  1655. else
  1656. status = EX_PROTOCOL;
  1657. if (e->e_statmsg != NULL)
  1658. free(e->e_statmsg);
  1659. if (bitset(MCIF_ENHSTAT, mci->mci_flags) &&
  1660.     (r = isenhsc(SmtpReplyBuffer + 4, ' ')) > 0)
  1661. r += 5;
  1662. else
  1663. r = 4;
  1664. e->e_statmsg = newstr(&SmtpReplyBuffer[r]);
  1665. mci_setstat(mci, status, ENHSCN(enhsc, smtptodsn(r)),
  1666.     SmtpReplyBuffer);
  1667. if (LogLevel > 1 && status == EX_PROTOCOL)
  1668. {
  1669. sm_syslog(LOG_CRIT, e->e_id,
  1670.   "%.100s: SMTP DATA-3 protocol error: %s",
  1671.   CurHostName,
  1672.   shortenstring(SmtpReplyBuffer, 403));
  1673. }
  1674. return status;
  1675. }
  1676. /*
  1677. **  SMTPQUIT -- close the SMTP connection.
  1678. **
  1679. ** Parameters:
  1680. ** m -- a pointer to the mailer.
  1681. ** mci -- the mailer connection information.
  1682. ** e -- the current envelope.
  1683. **
  1684. ** Returns:
  1685. ** none.
  1686. **
  1687. ** Side Effects:
  1688. ** sends the final protocol and closes the connection.
  1689. */
  1690. void
  1691. smtpquit(m, mci, e)
  1692. register MAILER *m;
  1693. register MCI *mci;
  1694. ENVELOPE *e;
  1695. {
  1696. bool oldSuprErrs = SuprErrs;
  1697. /*
  1698. ** Suppress errors here -- we may be processing a different
  1699. ** job when we do the quit connection, and we don't want the
  1700. ** new job to be penalized for something that isn't it's
  1701. ** problem.
  1702. */
  1703. SuprErrs = TRUE;
  1704. /* send the quit message if we haven't gotten I/O error */
  1705. if (mci->mci_state != MCIS_ERROR &&
  1706.     mci->mci_state != MCIS_QUITING)
  1707. {
  1708. int origstate = mci->mci_state;
  1709. SmtpPhase = "client QUIT";
  1710. mci->mci_state = MCIS_QUITING;
  1711. smtpmessage("QUIT", m, mci);
  1712. (void) reply(m, mci, e, TimeOuts.to_quit, NULL, NULL);
  1713. SuprErrs = oldSuprErrs;
  1714. if (mci->mci_state == MCIS_CLOSED ||
  1715.     origstate == MCIS_CLOSED)
  1716. return;
  1717. }
  1718. /* now actually close the connection and pick up the zombie */
  1719. (void) endmailer(mci, e, NULL);
  1720. SuprErrs = oldSuprErrs;
  1721. }
  1722. /*
  1723. **  SMTPRSET -- send a RSET (reset) command
  1724. */
  1725. void
  1726. smtprset(m, mci, e)
  1727. register MAILER *m;
  1728. register MCI *mci;
  1729. ENVELOPE *e;
  1730. {
  1731. int r;
  1732. SmtpPhase = "client RSET";
  1733. smtpmessage("RSET", m, mci);
  1734. r = reply(m, mci, e, TimeOuts.to_rset, NULL, NULL);
  1735. if (r < 0)
  1736. mci->mci_state = MCIS_ERROR;
  1737. else
  1738. {
  1739. /*
  1740. **  Any response is deemed to be acceptable.
  1741. **  The standard does not state the proper action
  1742. **  to take when a value other than 250 is received.
  1743. */
  1744. mci->mci_state = MCIS_OPEN;
  1745. return;
  1746. }
  1747. smtpquit(m, mci, e);
  1748. }
  1749. /*
  1750. **  SMTPPROBE -- check the connection state
  1751. */
  1752. int
  1753. smtpprobe(mci)
  1754. register MCI *mci;
  1755. {
  1756. int r;
  1757. MAILER *m = mci->mci_mailer;
  1758. ENVELOPE *e;
  1759. extern ENVELOPE BlankEnvelope;
  1760. e = &BlankEnvelope;
  1761. SmtpPhase = "client probe";
  1762. smtpmessage("RSET", m, mci);
  1763. r = reply(m, mci, e, TimeOuts.to_miscshort, NULL, NULL);
  1764. if (r < 0 || REPLYTYPE(r) != 2)
  1765. smtpquit(m, mci, e);
  1766. return r;
  1767. }
  1768. /*
  1769. **  REPLY -- read arpanet reply
  1770. **
  1771. ** Parameters:
  1772. ** m -- the mailer we are reading the reply from.
  1773. ** mci -- the mailer connection info structure.
  1774. ** e -- the current envelope.
  1775. ** timeout -- the timeout for reads.
  1776. ** pfunc -- processing function called on each line of response.
  1777. ** If null, no special processing is done.
  1778. **
  1779. ** Returns:
  1780. ** reply code it reads.
  1781. **
  1782. ** Side Effects:
  1783. ** flushes the mail file.
  1784. */
  1785. int
  1786. reply(m, mci, e, timeout, pfunc, enhstat)
  1787. MAILER *m;
  1788. MCI *mci;
  1789. ENVELOPE *e;
  1790. time_t timeout;
  1791. void (*pfunc)();
  1792. char **enhstat;
  1793. {
  1794. register char *bufp;
  1795. register int r;
  1796. bool firstline = TRUE;
  1797. char junkbuf[MAXLINE];
  1798. static char enhstatcode[ENHSCLEN];
  1799. int save_errno;
  1800. if (mci->mci_out != NULL)
  1801. (void) fflush(mci->mci_out);
  1802. if (tTd(18, 1))
  1803. dprintf("replyn");
  1804. /*
  1805. **  Read the input line, being careful not to hang.
  1806. */
  1807. bufp = SmtpReplyBuffer;
  1808. for (;;)
  1809. {
  1810. register char *p;
  1811. /* actually do the read */
  1812. if (e->e_xfp != NULL)
  1813. (void) fflush(e->e_xfp); /* for debugging */
  1814. /* if we are in the process of closing just give the code */
  1815. if (mci->mci_state == MCIS_CLOSED)
  1816. return SMTPCLOSING;
  1817. if (mci->mci_out != NULL)
  1818. (void) fflush(mci->mci_out);
  1819. /* get the line from the other side */
  1820. p = sfgets(bufp, MAXLINE, mci->mci_in, timeout, SmtpPhase);
  1821. mci->mci_lastuse = curtime();
  1822. if (p == NULL)
  1823. {
  1824. bool oldholderrs;
  1825. extern char MsgBuf[];
  1826. /* if the remote end closed early, fake an error */
  1827. if (errno == 0)
  1828. # ifdef ECONNRESET
  1829. errno = ECONNRESET;
  1830. # else /* ECONNRESET */
  1831. errno = EPIPE;
  1832. # endif /* ECONNRESET */
  1833. mci->mci_errno = errno;
  1834. oldholderrs = HoldErrs;
  1835. HoldErrs = TRUE;
  1836. usrerr("451 4.4.1 reply: read error from %s",
  1837.        CurHostName);
  1838. /* errors on QUIT should not be persistent */
  1839. if (strncmp(SmtpMsgBuffer, "QUIT", 4) != 0)
  1840. mci_setstat(mci, EX_TEMPFAIL, "4.4.2", MsgBuf);
  1841. /* if debugging, pause so we can see state */
  1842. if (tTd(18, 100))
  1843. (void) pause();
  1844. mci->mci_state = MCIS_ERROR;
  1845. save_errno = errno;
  1846. smtpquit(m, mci, e);
  1847. # if XDEBUG
  1848. {
  1849. char wbuf[MAXLINE];
  1850. int wbufleft = sizeof wbuf;
  1851. p = wbuf;
  1852. if (e->e_to != NULL)
  1853. {
  1854. int plen;
  1855. snprintf(p, wbufleft, "%s... ",
  1856. shortenstring(e->e_to, MAXSHORTSTR));
  1857. plen = strlen(p);
  1858. p += plen;
  1859. wbufleft -= plen;
  1860. }
  1861. snprintf(p, wbufleft, "reply(%.100s) during %s",
  1862.  CurHostName == NULL ? "NO_HOST" : CurHostName,
  1863.  SmtpPhase);
  1864. checkfd012(wbuf);
  1865. }
  1866. # endif /* XDEBUG */
  1867. errno = save_errno;
  1868. HoldErrs = oldholderrs;
  1869. return -1;
  1870. }
  1871. fixcrlf(bufp, TRUE);
  1872. /* EHLO failure is not a real error */
  1873. if (e->e_xfp != NULL && (bufp[0] == '4' ||
  1874.     (bufp[0] == '5' && strncmp(SmtpMsgBuffer, "EHLO", 4) != 0)))
  1875. {
  1876. /* serious error -- log the previous command */
  1877. if (SmtpNeedIntro)
  1878. {
  1879. /* inform user who we are chatting with */
  1880. fprintf(CurEnv->e_xfp,
  1881. "... while talking to %s:n",
  1882. CurHostName);
  1883. SmtpNeedIntro = FALSE;
  1884. }
  1885. if (SmtpMsgBuffer[0] != '')
  1886. fprintf(e->e_xfp, ">>> %sn", SmtpMsgBuffer);
  1887. SmtpMsgBuffer[0] = '';
  1888. /* now log the message as from the other side */
  1889. fprintf(e->e_xfp, "<<< %sn", bufp);
  1890. }
  1891. /* display the input for verbose mode */
  1892. if (Verbose)
  1893. nmessage("050 %s", bufp);
  1894. /* ignore improperly formatted input */
  1895. if (!ISSMTPREPLY(bufp))
  1896. continue;
  1897. if (bitset(MCIF_ENHSTAT, mci->mci_flags) &&
  1898.     enhstat != NULL &&
  1899.     extenhsc(bufp + 4, ' ', enhstatcode) > 0)
  1900. *enhstat = enhstatcode;
  1901. /* process the line */
  1902. if (pfunc != NULL)
  1903. (*pfunc)(bufp, firstline, m, mci, e);
  1904. firstline = FALSE;
  1905. /* decode the reply code */
  1906. r = atoi(bufp);
  1907. /* extra semantics: 0xx codes are "informational" */
  1908. if (r < 100)
  1909. continue;
  1910. /* if no continuation lines, return this line */
  1911. if (bufp[3] != '-')
  1912. break;
  1913. /* first line of real reply -- ignore rest */
  1914. bufp = junkbuf;
  1915. }
  1916. /*
  1917. **  Now look at SmtpReplyBuffer -- only care about the first
  1918. **  line of the response from here on out.
  1919. */
  1920. /* save temporary failure messages for posterity */
  1921. if (SmtpReplyBuffer[0] == '4' &&
  1922.     (bitnset(M_LMTP, m->m_flags) || SmtpError[0] == ''))
  1923. snprintf(SmtpError, sizeof SmtpError, "%s", SmtpReplyBuffer);
  1924. /* reply code 421 is "Service Shutting Down" */
  1925. if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD)
  1926. {
  1927. /* send the quit protocol */
  1928. mci->mci_state = MCIS_SSD;
  1929. smtpquit(m, mci, e);
  1930. }
  1931. return r;
  1932. }
  1933. /*
  1934. **  SMTPMESSAGE -- send message to server
  1935. **
  1936. ** Parameters:
  1937. ** f -- format
  1938. ** m -- the mailer to control formatting.
  1939. ** a, b, c -- parameters
  1940. **
  1941. ** Returns:
  1942. ** none.
  1943. **
  1944. ** Side Effects:
  1945. ** writes message to mci->mci_out.
  1946. */
  1947. /*VARARGS1*/
  1948. void
  1949. # ifdef __STDC__
  1950. smtpmessage(char *f, MAILER *m, MCI *mci, ...)
  1951. # else /* __STDC__ */
  1952. smtpmessage(f, m, mci, va_alist)
  1953. char *f;
  1954. MAILER *m;
  1955. MCI *mci;
  1956. va_dcl
  1957. # endif /* __STDC__ */
  1958. {
  1959. VA_LOCAL_DECL
  1960. VA_START(mci);
  1961. (void) vsnprintf(SmtpMsgBuffer, sizeof SmtpMsgBuffer, f, ap);
  1962. VA_END;
  1963. if (tTd(18, 1) || Verbose)
  1964. nmessage(">>> %s", SmtpMsgBuffer);
  1965. if (TrafficLogFile != NULL)
  1966. fprintf(TrafficLogFile, "%05d >>> %sn",
  1967. (int) getpid(), SmtpMsgBuffer);
  1968. if (mci->mci_out != NULL)
  1969. {
  1970. fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer,
  1971. m == NULL ? "rn" : m->m_eol);
  1972. }
  1973. else if (tTd(18, 1))
  1974. {
  1975. dprintf("smtpmessage: NULL mci_outn");
  1976. }
  1977. }
  1978. #endif /* SMTP */