1 /*
2 * Copyright (c) 1998-2006, 2008-2010, 2014 Proofpoint, 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
14 #include <sendmail.h>
15
16 SM_RCSID("@(#)$Id: usersmtp.c,v 8.488 2013-11-22 20:51:57 ca Exp $")
17
18 #include <sm/sendmail.h>
19
20 static void esmtp_check __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
21 static void helo_options __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
22 static int smtprcptstat __P((ADDRESS *, MAILER *, MCI *, ENVELOPE *));
23
24 #if SASL
25 extern void *sm_sasl_malloc __P((unsigned long));
26 extern void sm_sasl_free __P((void *));
27 #endif
28
29 /*
30 ** USERSMTP -- run SMTP protocol from the user end.
31 **
32 ** This protocol is described in RFC821.
33 */
34
35 #define SMTPCLOSING 421 /* "Service Shutting Down" */
36
37 #define ENHSCN(e, d) ((e) == NULL ? (d) : (e))
38
39 #define ENHSCN_RPOOL(e, d, rpool) \
40 ((e) == NULL ? (d) : sm_rpool_strdup_x(rpool, e))
41
42 static char SmtpMsgBuffer[MAXLINE]; /* buffer for commands */
43 static char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */
44 static bool SmtpNeedIntro; /* need "while talking" in transcript */
45
46 /*
47 ** SMTPCCLRSE -- clear session related data in envelope
48 **
49 ** Parameters:
50 ** e -- the envelope.
51 **
52 ** Returns:
53 ** none.
54 */
55
56 void
smtpclrse(e)57 smtpclrse(e)
58 ENVELOPE *e;
59 {
60 SmtpError[0] = '\0';
61 e->e_rcode = 0;
62 e->e_renhsc[0] = '\0';
63 e->e_text = NULL;
64 #if _FFR_LOG_STAGE
65 e->e_estate = -1;
66 #endif
67
68 /*
69 ** Reset to avoid access to potentially dangling pointer
70 ** via macvalue().
71 */
72
73 e->e_mci = NULL;
74 }
75
76 /*
77 ** SMTPINIT -- initialize SMTP.
78 **
79 ** Opens the connection and sends the initial protocol.
80 **
81 ** Parameters:
82 ** m -- mailer to create connection to.
83 ** mci -- the mailer connection info.
84 ** e -- the envelope.
85 ** onlyhelo -- send only helo command?
86 **
87 ** Returns:
88 ** none.
89 **
90 ** Side Effects:
91 ** creates connection and sends initial protocol.
92 */
93
94 void
smtpinit(m,mci,e,onlyhelo)95 smtpinit(m, mci, e, onlyhelo)
96 MAILER *m;
97 register MCI *mci;
98 ENVELOPE *e;
99 bool onlyhelo;
100 {
101 register int r;
102 int state;
103 register char *p;
104 register char *hn;
105 #if _FFR_EXPAND_HELONAME
106 char hnbuf[MAXNAME + 1]; /* EAI:ok:EHLO name must be ASCII */
107 #endif
108 char *enhsc;
109
110 enhsc = NULL;
111 if (tTd(18, 1))
112 {
113 sm_dprintf("smtpinit ");
114 mci_dump(sm_debug_file(), mci, false);
115 }
116
117 /*
118 ** Open the connection to the mailer.
119 */
120
121 SmtpError[0] = '\0';
122 SmtpMsgBuffer[0] = '\0';
123 CurHostName = mci->mci_host; /* XXX UGLY XXX */
124 if (CurHostName == NULL)
125 CurHostName = MyHostName;
126 SmtpNeedIntro = true;
127 state = mci->mci_state;
128 e->e_rcode = 0;
129 e->e_renhsc[0] = '\0';
130 e->e_text = NULL;
131 maps_reset_chged("client:smtpinit");
132 switch (state)
133 {
134 case MCIS_MAIL:
135 case MCIS_RCPT:
136 case MCIS_DATA:
137 /* need to clear old information */
138 smtprset(m, mci, e);
139 /* FALLTHROUGH */
140
141 case MCIS_OPEN:
142 if (!onlyhelo)
143 return;
144 break;
145
146 case MCIS_ERROR:
147 case MCIS_QUITING:
148 case MCIS_SSD:
149 /* shouldn't happen */
150 smtpquit(m, mci, e);
151 /* FALLTHROUGH */
152
153 case MCIS_CLOSED:
154 syserr("451 4.4.0 smtpinit: state CLOSED (was %d)", state);
155 return;
156
157 case MCIS_OPENING:
158 break;
159 }
160 if (onlyhelo)
161 goto helo;
162
163 mci->mci_state = MCIS_OPENING;
164 clrsessenvelope(e);
165
166 /*
167 ** Get the greeting message.
168 ** This should appear spontaneously. Give it five minutes to
169 ** happen.
170 */
171
172 SmtpPhase = mci->mci_phase = "client greeting";
173 sm_setproctitle(true, e, "%s %s: %s",
174 qid_printname(e), CurHostName, mci->mci_phase);
175 r = reply(m, mci, e, TimeOuts.to_initial, esmtp_check, NULL, XS_GREET,
176 NULL);
177 if (r < 0)
178 goto tempfail1;
179 if (REPLYTYPE(r) == 4)
180 goto tempfail2;
181 if (REPLYTYPE(r) != 2)
182 goto unavailable;
183
184 /*
185 ** Send the HELO command.
186 ** My mother taught me to always introduce myself.
187 */
188
189 helo:
190 if (bitnset(M_ESMTP, m->m_flags) || bitnset(M_LMTP, m->m_flags))
191 mci->mci_flags |= MCIF_ESMTP;
192 if (mci->mci_heloname != NULL)
193 {
194 #if _FFR_EXPAND_HELONAME
195 expand(mci->mci_heloname, hnbuf, sizeof(hnbuf), e);
196 hn = hnbuf;
197 #else
198 hn = mci->mci_heloname;
199 #endif
200 }
201 else
202 hn = MyHostName;
203
204 tryhelo:
205 #if _FFR_IGNORE_EXT_ON_HELO
206 mci->mci_flags &= ~MCIF_HELO;
207 #endif
208 if (bitnset(M_LMTP, m->m_flags))
209 {
210 smtpmessage("LHLO %s", m, mci, hn);
211 SmtpPhase = mci->mci_phase = "client LHLO";
212 }
213 else if (bitset(MCIF_ESMTP, mci->mci_flags) &&
214 !bitnset(M_FSMTP, m->m_flags))
215 {
216 smtpmessage("EHLO %s", m, mci, hn);
217 SmtpPhase = mci->mci_phase = "client EHLO";
218 }
219 else
220 {
221 smtpmessage("HELO %s", m, mci, hn);
222 SmtpPhase = mci->mci_phase = "client HELO";
223 #if _FFR_IGNORE_EXT_ON_HELO
224 mci->mci_flags |= MCIF_HELO;
225 #endif
226 }
227 sm_setproctitle(true, e, "%s %s: %s", qid_printname(e),
228 CurHostName, mci->mci_phase);
229 r = reply(m, mci, e,
230 bitnset(M_LMTP, m->m_flags) ? TimeOuts.to_lhlo
231 : TimeOuts.to_helo,
232 helo_options, NULL, XS_EHLO, NULL);
233 if (r < 0)
234 goto tempfail1;
235 else if (REPLYTYPE(r) == 5)
236 {
237 if (bitset(MCIF_ESMTP, mci->mci_flags) &&
238 !bitnset(M_LMTP, m->m_flags))
239 {
240 /* try old SMTP instead */
241 mci->mci_flags &= ~MCIF_ESMTP;
242 goto tryhelo;
243 }
244 goto unavailable;
245 }
246 else if (REPLYTYPE(r) != 2)
247 goto tempfail2;
248
249 /*
250 ** Check to see if we actually ended up talking to ourself.
251 ** This means we didn't know about an alias or MX, or we managed
252 ** to connect to an echo server.
253 */
254
255 p = strchr(&SmtpReplyBuffer[4], ' ');
256 if (p != NULL)
257 *p = '\0';
258 if (!bitnset(M_NOLOOPCHECK, m->m_flags) &&
259 !bitnset(M_LMTP, m->m_flags) &&
260 SM_STRCASEEQ(&SmtpReplyBuffer[4], MyHostName))
261 {
262 syserr("553 5.3.5 %s config error: mail loops back to me (MX problem?)",
263 CurHostName);
264 mci_setstat(mci, EX_CONFIG, "5.3.5",
265 "553 5.3.5 system config error");
266 mci->mci_errno = 0;
267 smtpquit(m, mci, e);
268 return;
269 }
270
271 /*
272 ** If this is expected to be another sendmail, send some internal
273 ** commands.
274 ** If we're running as MSP, "propagate" -v flag if possible.
275 */
276
277 if ((UseMSP && Verbose && bitset(MCIF_VERB, mci->mci_flags))
278 || bitnset(M_INTERNAL, m->m_flags))
279 {
280 /* tell it to be verbose */
281 smtpmessage("VERB", m, mci);
282 r = reply(m, mci, e, TimeOuts.to_miscshort, NULL, &enhsc,
283 XS_DEFAULT, NULL);
284 if (r < 0)
285 goto tempfail1;
286 }
287
288 if (mci->mci_state != MCIS_CLOSED)
289 {
290 mci->mci_state = MCIS_OPEN;
291 return;
292 }
293
294 /* got a 421 error code during startup */
295
296 tempfail1:
297 mci_setstat(mci, EX_TEMPFAIL, ENHSCN(enhsc, "4.4.2"), NULL);
298 if (mci->mci_state != MCIS_CLOSED)
299 smtpquit(m, mci, e);
300 return;
301
302 tempfail2:
303 /* XXX should use code from other end iff ENHANCEDSTATUSCODES */
304 mci_setstat(mci, EX_TEMPFAIL, ENHSCN(enhsc, "4.5.0"),
305 SmtpReplyBuffer);
306 if (mci->mci_state != MCIS_CLOSED)
307 smtpquit(m, mci, e);
308 return;
309
310 unavailable:
311 mci_setstat(mci, EX_UNAVAILABLE, "5.5.0", SmtpReplyBuffer);
312 smtpquit(m, mci, e);
313 return;
314 }
315 /*
316 ** ESMTP_CHECK -- check to see if this implementation likes ESMTP protocol
317 **
318 ** Parameters:
319 ** line -- the response line.
320 ** firstline -- set if this is the first line of the reply.
321 ** m -- the mailer.
322 ** mci -- the mailer connection info.
323 ** e -- the envelope.
324 **
325 ** Returns:
326 ** none.
327 */
328
329 static void
esmtp_check(line,firstline,m,mci,e)330 esmtp_check(line, firstline, m, mci, e)
331 char *line;
332 bool firstline;
333 MAILER *m;
334 register MCI *mci;
335 ENVELOPE *e;
336 {
337 if (strstr(line, "ESMTP") != NULL)
338 mci->mci_flags |= MCIF_ESMTP;
339
340 /*
341 ** Dirty hack below. Quoting the author:
342 ** This was a response to people who wanted SMTP transmission to be
343 ** just-send-8 by default. Essentially, you could put this tag into
344 ** your greeting message to behave as though the F=8 flag was set on
345 ** the mailer.
346 */
347
348 if (strstr(line, "8BIT-OK") != NULL)
349 mci->mci_flags |= MCIF_8BITOK;
350 }
351
352 #if SASL
353 /* specify prototype so compiler can check calls */
354 static char *str_union __P((char *, char *, SM_RPOOL_T *));
355
356 /*
357 ** STR_UNION -- create the union of two lists
358 **
359 ** Parameters:
360 ** s1, s2 -- lists of items (separated by single blanks).
361 ** rpool -- resource pool from which result is allocated.
362 **
363 ** Returns:
364 ** the union of both lists.
365 */
366
367 static char *
str_union(s1,s2,rpool)368 str_union(s1, s2, rpool)
369 char *s1, *s2;
370 SM_RPOOL_T *rpool;
371 {
372 char *hr, *h1, *h, *res;
373 int l1, l2, rl;
374
375 if (SM_IS_EMPTY(s1))
376 return s2;
377 if (SM_IS_EMPTY(s2))
378 return s1;
379 l1 = strlen(s1);
380 l2 = strlen(s2);
381 rl = l1 + l2;
382 if (rl <= 0)
383 {
384 sm_syslog(LOG_WARNING, NOQID,
385 "str_union: stringlen1=%d, stringlen2=%d, sum=%d, status=overflow",
386 l1, l2, rl);
387 res = NULL;
388 }
389 else
390 res = (char *) sm_rpool_malloc(rpool, rl + 2);
391 if (res == NULL)
392 {
393 if (l1 > l2)
394 return s1;
395 return s2;
396 }
397 (void) sm_strlcpy(res, s1, rl);
398 hr = res + l1;
399 h1 = s2;
400 h = s2;
401
402 /* walk through s2 */
403 while (h != NULL && *h1 != '\0')
404 {
405 /* is there something after the current word? */
406 if ((h = strchr(h1, ' ')) != NULL)
407 *h = '\0';
408 l1 = strlen(h1);
409
410 /* does the current word appear in s1 ? */
411 if (iteminlist(h1, s1, " ") == NULL)
412 {
413 /* add space as delimiter */
414 *hr++ = ' ';
415
416 /* copy the item */
417 memcpy(hr, h1, l1);
418
419 /* advance pointer in result list */
420 hr += l1;
421 *hr = '\0';
422 }
423 if (h != NULL)
424 {
425 /* there are more items */
426 *h = ' ';
427 h1 = h + 1;
428 }
429 }
430 return res;
431 }
432 #endif /* SASL */
433
434 /*
435 ** HELO_OPTIONS -- process the options on a HELO line.
436 **
437 ** Parameters:
438 ** line -- the response line.
439 ** firstline -- set if this is the first line of the reply.
440 ** m -- the mailer.
441 ** mci -- the mailer connection info.
442 ** e -- the envelope (unused).
443 **
444 ** Returns:
445 ** none.
446 */
447
448 static void
helo_options(line,firstline,m,mci,e)449 helo_options(line, firstline, m, mci, e)
450 char *line;
451 bool firstline;
452 MAILER *m;
453 register MCI *mci;
454 ENVELOPE *e;
455 {
456 register char *p;
457 #if _FFR_IGNORE_EXT_ON_HELO
458 static bool logged = false;
459 #endif
460
461 if (firstline)
462 {
463 mci_clr_extensions(mci);
464 #if _FFR_IGNORE_EXT_ON_HELO
465 logged = false;
466 #endif
467 return;
468 }
469 #if _FFR_IGNORE_EXT_ON_HELO
470 else if (bitset(MCIF_HELO, mci->mci_flags))
471 {
472 if (LogLevel > 8 && !logged)
473 {
474 sm_syslog(LOG_WARNING, NOQID,
475 "server=%s [%s] returned extensions despite HELO command",
476 macvalue(macid("{server_name}"), e),
477 macvalue(macid("{server_addr}"), e));
478 logged = true;
479 }
480 return;
481 }
482 #endif /* _FFR_IGNORE_EXT_ON_HELO */
483
484 if (strlen(line) < 5)
485 return;
486 line += 4;
487 p = strpbrk(line, " =");
488 if (p != NULL)
489 *p++ = '\0';
490 if (SM_STRCASEEQ(line, "size"))
491 {
492 mci->mci_flags |= MCIF_SIZE;
493 if (p != NULL)
494 mci->mci_maxsize = atol(p);
495 }
496 else if (SM_STRCASEEQ(line, "8bitmime"))
497 {
498 mci->mci_flags |= MCIF_8BITMIME;
499 mci->mci_flags &= ~MCIF_7BIT;
500 }
501 else if (SM_STRCASEEQ(line, "expn"))
502 mci->mci_flags |= MCIF_EXPN;
503 else if (SM_STRCASEEQ(line, "dsn"))
504 mci->mci_flags |= MCIF_DSN;
505 else if (SM_STRCASEEQ(line, "enhancedstatuscodes"))
506 mci->mci_flags |= MCIF_ENHSTAT;
507 else if (SM_STRCASEEQ(line, "pipelining"))
508 mci->mci_flags |= MCIF_PIPELINED;
509 else if (SM_STRCASEEQ(line, "verb"))
510 mci->mci_flags |= MCIF_VERB;
511 #if USE_EAI
512 else if (SM_STRCASEEQ(line, "smtputf8"))
513 mci->mci_flags |= MCIF_EAI;
514 #endif
515 #if STARTTLS
516 else if (SM_STRCASEEQ(line, "starttls"))
517 mci->mci_flags |= MCIF_TLS;
518 #endif
519 else if (SM_STRCASEEQ(line, "deliverby"))
520 {
521 mci->mci_flags |= MCIF_DLVR_BY;
522 if (p != NULL)
523 mci->mci_min_by = atol(p);
524 }
525 #if SASL
526 else if (SM_STRCASEEQ(line, "auth"))
527 {
528 if (p != NULL && *p != '\0' &&
529 !bitset(MCIF_AUTH2, mci->mci_flags))
530 {
531 if (mci->mci_saslcap != NULL)
532 {
533 /*
534 ** Create the union with previous auth
535 ** offerings because we recognize "auth "
536 ** and "auth=" (old format).
537 */
538
539 mci->mci_saslcap = str_union(mci->mci_saslcap,
540 p, mci->mci_rpool);
541 mci->mci_flags |= MCIF_AUTH2;
542 }
543 else
544 {
545 int l;
546
547 l = strlen(p) + 1;
548 mci->mci_saslcap = (char *)
549 sm_rpool_malloc(mci->mci_rpool, l);
550 if (mci->mci_saslcap != NULL)
551 {
552 (void) sm_strlcpy(mci->mci_saslcap, p,
553 l);
554 mci->mci_flags |= MCIF_AUTH;
555 }
556 }
557 }
558 if (tTd(95, 5))
559 sm_syslog(LOG_DEBUG, NOQID, "AUTH flags=%lx, mechs=%s",
560 mci->mci_flags, mci->mci_saslcap);
561 }
562 #endif /* SASL */
563 }
564 #if SASL
565
566 static int getsimple __P((void *, int, const char **, unsigned *));
567 static int getsecret __P((sasl_conn_t *, void *, int, sasl_secret_t **));
568 static int saslgetrealm __P((void *, int, const char **, const char **));
569 static int readauth __P((char *, bool, SASL_AI_T *m, SM_RPOOL_T *));
570 static int getauth __P((MCI *, ENVELOPE *, SASL_AI_T *));
571 static char *removemech __P((char *, char *, SM_RPOOL_T *));
572 static int attemptauth __P((MAILER *, MCI *, ENVELOPE *, SASL_AI_T *));
573
574 static sasl_callback_t callbacks[] =
575 {
576 { SASL_CB_GETREALM, (sasl_callback_ft)&saslgetrealm, NULL },
577 #define CB_GETREALM_IDX 0
578 { SASL_CB_PASS, (sasl_callback_ft)&getsecret, NULL },
579 #define CB_PASS_IDX 1
580 { SASL_CB_USER, (sasl_callback_ft)&getsimple, NULL },
581 #define CB_USER_IDX 2
582 { SASL_CB_AUTHNAME, (sasl_callback_ft)&getsimple, NULL },
583 #define CB_AUTHNAME_IDX 3
584 { SASL_CB_VERIFYFILE, (sasl_callback_ft)&safesaslfile, NULL },
585 #define CB_SAFESASL_IDX 4
586 { SASL_CB_LIST_END, NULL, NULL }
587 };
588
589 /*
590 ** INIT_SASL_CLIENT -- initialize client side of Cyrus-SASL
591 **
592 ** Parameters:
593 ** none.
594 **
595 ** Returns:
596 ** SASL_OK -- if successful.
597 ** SASL error code -- otherwise.
598 **
599 ** Side Effects:
600 ** checks/sets sasl_clt_init.
601 **
602 ** Note:
603 ** Callbacks are ignored if sasl_client_init() has
604 ** been called before (by a library such as libnss_ldap)
605 */
606
607 static bool sasl_clt_init = false;
608
609 static int
init_sasl_client()610 init_sasl_client()
611 {
612 int result;
613
614 if (sasl_clt_init)
615 return SASL_OK;
616 result = sasl_client_init(callbacks);
617
618 /* should we retry later again or just remember that it failed? */
619 if (result == SASL_OK)
620 sasl_clt_init = true;
621 return result;
622 }
623 /*
624 ** STOP_SASL_CLIENT -- shutdown client side of Cyrus-SASL
625 **
626 ** Parameters:
627 ** none.
628 **
629 ** Returns:
630 ** none.
631 **
632 ** Side Effects:
633 ** checks/sets sasl_clt_init.
634 */
635
636 void
stop_sasl_client()637 stop_sasl_client()
638 {
639 if (!sasl_clt_init)
640 return;
641 sasl_clt_init = false;
642 sasl_done();
643 }
644 /*
645 ** GETSASLDATA -- process the challenges from the SASL protocol
646 **
647 ** This gets the relevant sasl response data out of the reply
648 ** from the server.
649 **
650 ** Parameters:
651 ** line -- the response line.
652 ** firstline -- set if this is the first line of the reply.
653 ** m -- the mailer.
654 ** mci -- the mailer connection info.
655 ** e -- the envelope (unused).
656 **
657 ** Returns:
658 ** none.
659 */
660
661 static void getsasldata __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
662
663 static void
getsasldata(line,firstline,m,mci,e)664 getsasldata(line, firstline, m, mci, e)
665 char *line;
666 bool firstline;
667 MAILER *m;
668 register MCI *mci;
669 ENVELOPE *e;
670 {
671 int len;
672 int result;
673 # if SASL < 20000
674 char *out;
675 # endif
676
677 /* if not a continue we don't care about it */
678 len = strlen(line);
679 if ((len <= 4) ||
680 (line[0] != '3') ||
681 !isascii(line[1]) || !isdigit(line[1]) ||
682 !isascii(line[2]) || !isdigit(line[2]))
683 {
684 SM_FREE(mci->mci_sasl_string);
685 return;
686 }
687
688 /* forget about "334 " */
689 line += 4;
690 len -= 4;
691 # if SASL >= 20000
692 /* XXX put this into a macro/function? It's duplicated below */
693 if (mci->mci_sasl_string != NULL)
694 {
695 if (mci->mci_sasl_string_len <= len)
696 {
697 sm_free(mci->mci_sasl_string); /* XXX */
698 mci->mci_sasl_string = xalloc(len + 1);
699 }
700 }
701 else
702 mci->mci_sasl_string = xalloc(len + 1);
703
704 result = sasl_decode64(line, len, mci->mci_sasl_string, len + 1,
705 (unsigned int *) &mci->mci_sasl_string_len);
706 if (result != SASL_OK)
707 {
708 mci->mci_sasl_string_len = 0;
709 *mci->mci_sasl_string = '\0';
710 }
711 # else /* SASL >= 20000 */
712 out = (char *) sm_rpool_malloc_x(mci->mci_rpool, len + 1);
713 result = sasl_decode64(line, len, out, (unsigned int *) &len);
714 if (result != SASL_OK)
715 {
716 len = 0;
717 *out = '\0';
718 }
719
720 /*
721 ** mci_sasl_string is "shared" with Cyrus-SASL library; hence
722 ** it can't be in an rpool unless we use the same memory
723 ** management mechanism (with same rpool!) for Cyrus SASL.
724 */
725
726 if (mci->mci_sasl_string != NULL)
727 {
728 if (mci->mci_sasl_string_len <= len)
729 {
730 sm_free(mci->mci_sasl_string); /* XXX */
731 mci->mci_sasl_string = xalloc(len + 1);
732 }
733 }
734 else
735 mci->mci_sasl_string = xalloc(len + 1);
736
737 memcpy(mci->mci_sasl_string, out, len);
738 mci->mci_sasl_string[len] = '\0';
739 mci->mci_sasl_string_len = len;
740 # endif /* SASL >= 20000 */
741 return;
742 }
743 /*
744 ** READAUTH -- read auth values from a file
745 **
746 ** Parameters:
747 ** filename -- name of file to read.
748 ** safe -- if set, this is a safe read.
749 ** sai -- where to store auth_info.
750 ** rpool -- resource pool for sai.
751 **
752 ** Returns:
753 ** EX_OK -- data successfully read.
754 ** EX_UNAVAILABLE -- no valid filename.
755 ** EX_TEMPFAIL -- temporary failure.
756 */
757
758 static char *sasl_info_name[] =
759 {
760 "user id",
761 "authentication id",
762 "password",
763 "realm",
764 "mechlist"
765 };
766 static int
readauth(filename,safe,sai,rpool)767 readauth(filename, safe, sai, rpool)
768 char *filename;
769 bool safe;
770 SASL_AI_T *sai;
771 SM_RPOOL_T *rpool;
772 {
773 SM_FILE_T *f;
774 long sff;
775 pid_t pid;
776 int lc;
777 char *s;
778 char buf[MAXLINE];
779
780 if (SM_IS_EMPTY(filename))
781 return EX_UNAVAILABLE;
782
783 # if !_FFR_ALLOW_SASLINFO
784 /*
785 ** make sure we don't use a program that is not
786 ** accessible to the user who specified a different authinfo file.
787 ** However, currently we don't pass this info (authinfo file
788 ** specified by user) around, so we just turn off program access.
789 */
790
791 if (filename[0] == '|')
792 {
793 auto int fd;
794 int i;
795 char *p;
796 char *argv[MAXPV + 1];
797
798 i = 0;
799 for (p = strtok(&filename[1], " \t"); p != NULL;
800 p = strtok(NULL, " \t"))
801 {
802 if (i >= MAXPV)
803 break;
804 argv[i++] = p;
805 }
806 argv[i] = NULL;
807 pid = prog_open(argv, &fd, CurEnv);
808 if (pid < 0)
809 f = NULL;
810 else
811 f = sm_io_open(SmFtStdiofd, SM_TIME_DEFAULT,
812 (void *) &fd, SM_IO_RDONLY, NULL);
813 }
814 else
815 # endif /* !_FFR_ALLOW_SASLINFO */
816 /* "else" in #if code above */
817 {
818 pid = -1;
819 sff = SFF_REGONLY|SFF_SAFEDIRPATH|SFF_NOWLINK
820 |SFF_NOGWFILES|SFF_NOWWFILES|SFF_NOWRFILES;
821 if (!bitnset(DBS_GROUPREADABLEAUTHINFOFILE, DontBlameSendmail))
822 sff |= SFF_NOGRFILES;
823 if (DontLockReadFiles)
824 sff |= SFF_NOLOCK;
825
826 # if _FFR_ALLOW_SASLINFO
827 /*
828 ** XXX: make sure we don't read or open files that are not
829 ** accessible to the user who specified a different authinfo
830 ** file.
831 */
832
833 sff |= SFF_MUSTOWN;
834 # else /* _FFR_ALLOW_SASLINFO */
835 if (safe)
836 sff |= SFF_OPENASROOT;
837 # endif /* _FFR_ALLOW_SASLINFO */
838
839 f = safefopen(filename, O_RDONLY, 0, sff);
840 }
841 if (f == NULL)
842 {
843 if (LogLevel > 5)
844 sm_syslog(LOG_ERR, NOQID,
845 "AUTH=client, error: can't open %s: %s",
846 filename, sm_errstring(errno));
847 return EX_TEMPFAIL;
848 }
849
850 lc = 0;
851 while (lc <= SASL_MECHLIST &&
852 sm_io_fgets(f, SM_TIME_DEFAULT, buf, sizeof(buf)) >= 0)
853 {
854 if (buf[0] != '#')
855 {
856 (*sai)[lc] = sm_rpool_strdup_x(rpool, buf);
857 if ((s = strchr((*sai)[lc], '\n')) != NULL)
858 *s = '\0';
859 lc++;
860 }
861 }
862
863 (void) sm_io_close(f, SM_TIME_DEFAULT);
864 if (pid > 0)
865 (void) waitfor(pid);
866 if (lc < SASL_PASSWORD)
867 {
868 if (LogLevel > 8)
869 sm_syslog(LOG_ERR, NOQID,
870 "AUTH=client, error: can't read %s from %s",
871 sasl_info_name[lc + 1], filename);
872 return EX_TEMPFAIL;
873 }
874 return EX_OK;
875 }
876
877 /*
878 ** GETAUTH -- get authinfo from ruleset call
879 **
880 ** {server_name}, {server_addr} must be set
881 **
882 ** Parameters:
883 ** mci -- the mailer connection structure.
884 ** e -- the envelope (including the sender to specify).
885 ** sai -- pointer to authinfo (result).
886 **
887 ** Returns:
888 ** EX_OK -- ruleset was successfully called, data may not
889 ** be available, sai must be checked.
890 ** EX_UNAVAILABLE -- ruleset unavailable (or failed).
891 ** EX_TEMPFAIL -- temporary failure (from ruleset).
892 **
893 ** Side Effects:
894 ** Fills in sai if successful.
895 */
896
897 static int
getauth(mci,e,sai)898 getauth(mci, e, sai)
899 MCI *mci;
900 ENVELOPE *e;
901 SASL_AI_T *sai;
902 {
903 int i, r, l, got, ret;
904 char **pvp;
905 char pvpbuf[PSBUFSIZE];
906
907 r = rscap("authinfo", macvalue(macid("{server_name}"), e),
908 macvalue(macid("{server_addr}"), e), e,
909 &pvp, pvpbuf, sizeof(pvpbuf));
910
911 if (r != EX_OK)
912 return EX_UNAVAILABLE;
913
914 /* other than expected return value: ok (i.e., no auth) */
915 if (pvp == NULL || pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
916 return EX_OK;
917 if (pvp[1] != NULL && sm_strncasecmp(pvp[1], "temp", 4) == 0)
918 return EX_TEMPFAIL;
919
920 /*
921 ** parse the data, put it into sai
922 ** format: "TDstring" (including the '"' !)
923 ** where T is a tag: 'U', ...
924 ** D is a delimiter: ':' or '='
925 */
926
927 ret = EX_OK; /* default return value */
928 i = 0;
929 got = 0;
930 while (i < SASL_ENTRIES)
931 {
932 if (pvp[i + 1] == NULL)
933 break;
934 if (pvp[i + 1][0] != '"')
935 break;
936 switch (pvp[i + 1][1])
937 {
938 case 'U':
939 case 'u':
940 r = SASL_USER;
941 break;
942 case 'I':
943 case 'i':
944 r = SASL_AUTHID;
945 break;
946 case 'P':
947 case 'p':
948 r = SASL_PASSWORD;
949 break;
950 case 'R':
951 case 'r':
952 r = SASL_DEFREALM;
953 break;
954 case 'M':
955 case 'm':
956 r = SASL_MECHLIST;
957 break;
958 default:
959 goto fail;
960 }
961 l = strlen(pvp[i + 1]);
962
963 /* check syntax */
964 if (l <= 3 || pvp[i + 1][l - 1] != '"')
965 goto fail;
966
967 /* remove closing quote */
968 pvp[i + 1][l - 1] = '\0';
969
970 /* remove "TD and " */
971 l -= 4;
972 (*sai)[r] = (char *) sm_rpool_malloc(mci->mci_rpool, l + 1);
973 if ((*sai)[r] == NULL)
974 goto tempfail;
975 if (pvp[i + 1][2] == ':')
976 {
977 /* ':text' (just copy) */
978 (void) sm_strlcpy((*sai)[r], pvp[i + 1] + 3, l + 1);
979 got |= 1 << r;
980 }
981 else if (pvp[i + 1][2] == '=')
982 {
983 unsigned int len;
984
985 /* '=base64' (decode) */
986 # if SASL >= 20000
987 ret = sasl_decode64(pvp[i + 1] + 3,
988 (unsigned int) l, (*sai)[r],
989 (unsigned int) l + 1, &len);
990 # else /* SASL >= 20000 */
991 ret = sasl_decode64(pvp[i + 1] + 3,
992 (unsigned int) l, (*sai)[r], &len);
993 # endif /* SASL >= 20000 */
994 if (ret != SASL_OK)
995 goto fail;
996 got |= 1 << r;
997 }
998 else
999 goto fail;
1000 if (tTd(95, 5))
1001 sm_syslog(LOG_DEBUG, NOQID, "getauth %s=%s",
1002 sasl_info_name[r], (*sai)[r]);
1003 ++i;
1004 }
1005
1006 /* did we get the expected data? */
1007 /* XXX: EXTERNAL mechanism only requires (and only uses) SASL_USER */
1008 if (!(bitset(SASL_USER_BIT|SASL_AUTHID_BIT, got) &&
1009 bitset(SASL_PASSWORD_BIT, got)))
1010 goto fail;
1011
1012 /* no authid? copy uid */
1013 if (!bitset(SASL_AUTHID_BIT, got))
1014 {
1015 l = strlen((*sai)[SASL_USER]) + 1;
1016 (*sai)[SASL_AUTHID] = (char *) sm_rpool_malloc(mci->mci_rpool,
1017 l + 1);
1018 if ((*sai)[SASL_AUTHID] == NULL)
1019 goto tempfail;
1020 (void) sm_strlcpy((*sai)[SASL_AUTHID], (*sai)[SASL_USER], l);
1021 }
1022
1023 /* no uid? copy authid */
1024 if (!bitset(SASL_USER_BIT, got))
1025 {
1026 l = strlen((*sai)[SASL_AUTHID]) + 1;
1027 (*sai)[SASL_USER] = (char *) sm_rpool_malloc(mci->mci_rpool,
1028 l + 1);
1029 if ((*sai)[SASL_USER] == NULL)
1030 goto tempfail;
1031 (void) sm_strlcpy((*sai)[SASL_USER], (*sai)[SASL_AUTHID], l);
1032 }
1033 return EX_OK;
1034
1035 tempfail:
1036 ret = EX_TEMPFAIL;
1037 fail:
1038 if (LogLevel > 8)
1039 sm_syslog(LOG_WARNING, NOQID,
1040 "AUTH=client, relay=%.64s [%.16s], authinfo %sfailed",
1041 macvalue(macid("{server_name}"), e),
1042 macvalue(macid("{server_addr}"), e),
1043 ret == EX_TEMPFAIL ? "temp" : "");
1044 for (i = 0; i <= SASL_MECHLIST; i++)
1045 (*sai)[i] = NULL; /* just clear; rpool */
1046 return ret;
1047 }
1048
1049 # if SASL >= 20000
1050 /*
1051 ** GETSIMPLE -- callback to get userid or authid
1052 **
1053 ** Parameters:
1054 ** context -- sai
1055 ** id -- what to do
1056 ** result -- (pointer to) result
1057 ** len -- (pointer to) length of result
1058 **
1059 ** Returns:
1060 ** OK/failure values
1061 */
1062
1063 static int
getsimple(context,id,result,len)1064 getsimple(context, id, result, len)
1065 void *context;
1066 int id;
1067 const char **result;
1068 unsigned *len;
1069 {
1070 SASL_AI_T *sai;
1071
1072 if (result == NULL || context == NULL)
1073 return SASL_BADPARAM;
1074 sai = (SASL_AI_T *) context;
1075
1076 switch (id)
1077 {
1078 case SASL_CB_USER:
1079 *result = (*sai)[SASL_USER];
1080 if (tTd(95, 5))
1081 sm_syslog(LOG_DEBUG, NOQID, "AUTH username '%s'",
1082 *result);
1083 if (len != NULL)
1084 *len = *result != NULL ? strlen(*result) : 0;
1085 break;
1086
1087 case SASL_CB_AUTHNAME:
1088 *result = (*sai)[SASL_AUTHID];
1089 if (tTd(95, 5))
1090 sm_syslog(LOG_DEBUG, NOQID, "AUTH authid '%s'",
1091 *result);
1092 if (len != NULL)
1093 *len = *result != NULL ? strlen(*result) : 0;
1094 break;
1095
1096 case SASL_CB_LANGUAGE:
1097 *result = NULL;
1098 if (len != NULL)
1099 *len = 0;
1100 break;
1101
1102 default:
1103 return SASL_BADPARAM;
1104 }
1105 return SASL_OK;
1106 }
1107 /*
1108 ** GETSECRET -- callback to get password
1109 **
1110 ** Parameters:
1111 ** conn -- connection information
1112 ** context -- sai
1113 ** id -- what to do
1114 ** psecret -- (pointer to) result
1115 **
1116 ** Returns:
1117 ** OK/failure values
1118 */
1119
1120 static int
getsecret(conn,context,id,psecret)1121 getsecret(conn, context, id, psecret)
1122 sasl_conn_t *conn;
1123 SM_UNUSED(void *context);
1124 int id;
1125 sasl_secret_t **psecret;
1126 {
1127 int len;
1128 char *authpass;
1129 MCI *mci;
1130
1131 if (conn == NULL || psecret == NULL || id != SASL_CB_PASS)
1132 return SASL_BADPARAM;
1133
1134 mci = (MCI *) context;
1135 authpass = mci->mci_sai[SASL_PASSWORD];
1136 len = strlen(authpass);
1137
1138 /*
1139 ** use an rpool because we are responsible for free()ing the secret,
1140 ** but we can't free() it until after the auth completes
1141 */
1142
1143 *psecret = (sasl_secret_t *) sm_rpool_malloc(mci->mci_rpool,
1144 sizeof(sasl_secret_t) +
1145 len + 1);
1146 if (*psecret == NULL)
1147 return SASL_FAIL;
1148 (void) sm_strlcpy((char *) (*psecret)->data, authpass, len + 1);
1149 (*psecret)->len = (unsigned long) len;
1150 return SASL_OK;
1151 }
1152 # else /* SASL >= 20000 */
1153 /*
1154 ** GETSIMPLE -- callback to get userid or authid
1155 **
1156 ** Parameters:
1157 ** context -- sai
1158 ** id -- what to do
1159 ** result -- (pointer to) result
1160 ** len -- (pointer to) length of result
1161 **
1162 ** Returns:
1163 ** OK/failure values
1164 */
1165
1166 static int
getsimple(context,id,result,len)1167 getsimple(context, id, result, len)
1168 void *context;
1169 int id;
1170 const char **result;
1171 unsigned *len;
1172 {
1173 char *h, *s;
1174 # if SASL > 10509
1175 bool addrealm;
1176 # endif
1177 size_t l;
1178 SASL_AI_T *sai;
1179 char *authid = NULL;
1180
1181 if (result == NULL || context == NULL)
1182 return SASL_BADPARAM;
1183 sai = (SASL_AI_T *) context;
1184
1185 /*
1186 ** Unfortunately it is not clear whether this routine should
1187 ** return a copy of a string or just a pointer to a string.
1188 ** The Cyrus-SASL plugins treat these return values differently, e.g.,
1189 ** plugins/cram.c free()s authid, plugings/digestmd5.c does not.
1190 ** The best solution to this problem is to fix Cyrus-SASL, but it
1191 ** seems there is nobody who creates patches... Hello CMU!?
1192 ** The second best solution is to have flags that tell this routine
1193 ** whether to return an malloc()ed copy.
1194 ** The next best solution is to always return an malloc()ed copy,
1195 ** and suffer from some memory leak, which is ugly for persistent
1196 ** queue runners.
1197 ** For now we go with the last solution...
1198 ** We can't use rpools (which would avoid this particular problem)
1199 ** as explained in sasl.c.
1200 */
1201
1202 switch (id)
1203 {
1204 case SASL_CB_USER:
1205 l = strlen((*sai)[SASL_USER]) + 1;
1206 s = sm_sasl_malloc(l);
1207 if (s == NULL)
1208 {
1209 if (len != NULL)
1210 *len = 0;
1211 *result = NULL;
1212 return SASL_NOMEM;
1213 }
1214 (void) sm_strlcpy(s, (*sai)[SASL_USER], l);
1215 *result = s;
1216 if (tTd(95, 5))
1217 sm_syslog(LOG_DEBUG, NOQID, "AUTH username '%s'",
1218 *result);
1219 if (len != NULL)
1220 *len = *result != NULL ? strlen(*result) : 0;
1221 break;
1222
1223 case SASL_CB_AUTHNAME:
1224 h = (*sai)[SASL_AUTHID];
1225 # if SASL > 10509
1226 /* XXX maybe other mechanisms too?! */
1227 addrealm = (*sai)[SASL_MECH] != NULL &&
1228 SM_STRCASEEQ((*sai)[SASL_MECH], "cram-md5");
1229
1230 /*
1231 ** Add realm to authentication id unless authid contains
1232 ** '@' (i.e., a realm) or the default realm is empty.
1233 */
1234
1235 if (addrealm && h != NULL && strchr(h, '@') == NULL)
1236 {
1237 /* has this been done before? */
1238 if ((*sai)[SASL_ID_REALM] == NULL)
1239 {
1240 char *realm;
1241
1242 realm = (*sai)[SASL_DEFREALM];
1243
1244 /* do not add an empty realm */
1245 if (*realm == '\0')
1246 {
1247 authid = h;
1248 (*sai)[SASL_ID_REALM] = NULL;
1249 }
1250 else
1251 {
1252 l = strlen(h) + strlen(realm) + 2;
1253
1254 /* should use rpool, but from where? */
1255 authid = sm_sasl_malloc(l);
1256 if (authid != NULL)
1257 {
1258 (void) sm_snprintf(authid, l,
1259 "%s@%s",
1260 h, realm);
1261 (*sai)[SASL_ID_REALM] = authid;
1262 }
1263 else
1264 {
1265 authid = h;
1266 (*sai)[SASL_ID_REALM] = NULL;
1267 }
1268 }
1269 }
1270 else
1271 authid = (*sai)[SASL_ID_REALM];
1272 }
1273 else
1274 # endif /* SASL > 10509 */
1275 authid = h;
1276 l = strlen(authid) + 1;
1277 s = sm_sasl_malloc(l);
1278 if (s == NULL)
1279 {
1280 if (len != NULL)
1281 *len = 0;
1282 *result = NULL;
1283 return SASL_NOMEM;
1284 }
1285 (void) sm_strlcpy(s, authid, l);
1286 *result = s;
1287 if (tTd(95, 5))
1288 sm_syslog(LOG_DEBUG, NOQID, "AUTH authid '%s'",
1289 *result);
1290 if (len != NULL)
1291 *len = authid ? strlen(authid) : 0;
1292 break;
1293
1294 case SASL_CB_LANGUAGE:
1295 *result = NULL;
1296 if (len != NULL)
1297 *len = 0;
1298 break;
1299
1300 default:
1301 return SASL_BADPARAM;
1302 }
1303 return SASL_OK;
1304 }
1305 /*
1306 ** GETSECRET -- callback to get password
1307 **
1308 ** Parameters:
1309 ** conn -- connection information
1310 ** context -- sai
1311 ** id -- what to do
1312 ** psecret -- (pointer to) result
1313 **
1314 ** Returns:
1315 ** OK/failure values
1316 */
1317
1318 static int
getsecret(conn,context,id,psecret)1319 getsecret(conn, context, id, psecret)
1320 sasl_conn_t *conn;
1321 SM_UNUSED(void *context);
1322 int id;
1323 sasl_secret_t **psecret;
1324 {
1325 int len;
1326 char *authpass;
1327 SASL_AI_T *sai;
1328
1329 if (conn == NULL || psecret == NULL || id != SASL_CB_PASS)
1330 return SASL_BADPARAM;
1331
1332 sai = (SASL_AI_T *) context;
1333 authpass = (*sai)[SASL_PASSWORD];
1334 len = strlen(authpass);
1335 *psecret = (sasl_secret_t *) sm_sasl_malloc(sizeof(sasl_secret_t) +
1336 len + 1);
1337 if (*psecret == NULL)
1338 return SASL_FAIL;
1339 (void) sm_strlcpy((*psecret)->data, authpass, len + 1);
1340 (*psecret)->len = (unsigned long) len;
1341 return SASL_OK;
1342 }
1343 # endif /* SASL >= 20000 */
1344
1345 /*
1346 ** SAFESASLFILE -- callback for sasl: is file safe?
1347 **
1348 ** Parameters:
1349 ** context -- pointer to context between invocations (unused)
1350 ** file -- name of file to check
1351 ** type -- type of file to check
1352 **
1353 ** Returns:
1354 ** SASL_OK -- file can be used
1355 ** SASL_CONTINUE -- don't use file
1356 ** SASL_FAIL -- failure (not used here)
1357 **
1358 */
1359
1360 int
1361 # if SASL > 10515
safesaslfile(context,file,type)1362 safesaslfile(context, file, type)
1363 # else
1364 safesaslfile(context, file)
1365 # endif
1366 void *context;
1367 # if SASL >= 20000
1368 const char *file;
1369 # else
1370 char *file;
1371 # endif
1372 # if SASL > 10515
1373 # if SASL >= 20000
1374 sasl_verify_type_t type;
1375 # else
1376 int type;
1377 # endif
1378 # endif
1379 {
1380 long sff;
1381 int r;
1382 # if SASL <= 10515
1383 size_t len;
1384 # endif
1385 char *p;
1386
1387 if (SM_IS_EMPTY(file))
1388 return SASL_OK;
1389 if (tTd(95, 16))
1390 sm_dprintf("safesaslfile=%s\n", file);
1391 sff = SFF_SAFEDIRPATH|SFF_NOWLINK|SFF_NOWWFILES|SFF_ROOTOK;
1392 # if SASL <= 10515
1393 if ((p = strrchr(file, '/')) == NULL)
1394 p = file;
1395 else
1396 ++p;
1397
1398 /* everything beside libs and .conf files must not be readable */
1399 len = strlen(p);
1400 if ((len <= 3 || strncmp(p, "lib", 3) != 0) &&
1401 (len <= 5 || strncmp(p + len - 5, ".conf", 5) != 0))
1402 {
1403 if (!bitnset(DBS_GROUPREADABLESASLDBFILE, DontBlameSendmail))
1404 sff |= SFF_NORFILES;
1405 if (!bitnset(DBS_GROUPWRITABLESASLDBFILE, DontBlameSendmail))
1406 sff |= SFF_NOGWFILES;
1407 }
1408 # else /* SASL <= 10515 */
1409 /* files containing passwords should be not readable */
1410 if (type == SASL_VRFY_PASSWD)
1411 {
1412 if (bitnset(DBS_GROUPREADABLESASLDBFILE, DontBlameSendmail))
1413 sff |= SFF_NOWRFILES;
1414 else
1415 sff |= SFF_NORFILES;
1416 if (!bitnset(DBS_GROUPWRITABLESASLDBFILE, DontBlameSendmail))
1417 sff |= SFF_NOGWFILES;
1418 }
1419 # endif /* SASL <= 10515 */
1420
1421 p = (char *) file;
1422 if ((r = safefile(p, RunAsUid, RunAsGid, RunAsUserName, sff,
1423 S_IRUSR, NULL)) == 0)
1424 return SASL_OK;
1425 if (LogLevel > (r != ENOENT ? 8 : 10))
1426 sm_syslog(LOG_WARNING, NOQID, "error: safesasl(%s) failed: %s",
1427 p, sm_errstring(r));
1428 return SASL_CONTINUE;
1429 }
1430
1431 /*
1432 ** SASLGETREALM -- return the realm for SASL
1433 **
1434 ** return the realm for the client
1435 **
1436 ** Parameters:
1437 ** context -- context shared between invocations
1438 ** availrealms -- list of available realms
1439 ** {realm, realm, ...}
1440 ** result -- pointer to result
1441 **
1442 ** Returns:
1443 ** failure/success
1444 */
1445
1446 static int
saslgetrealm(context,id,availrealms,result)1447 saslgetrealm(context, id, availrealms, result)
1448 void *context;
1449 int id;
1450 const char **availrealms;
1451 const char **result;
1452 {
1453 char *r;
1454 SASL_AI_T *sai;
1455
1456 sai = (SASL_AI_T *) context;
1457 if (sai == NULL)
1458 return SASL_FAIL;
1459 r = (*sai)[SASL_DEFREALM];
1460
1461 if (LogLevel > 12)
1462 sm_syslog(LOG_INFO, NOQID,
1463 "AUTH=client, realm=%s, available realms=%s",
1464 r == NULL ? "<No Realm>" : r,
1465 (NULL == availrealms || SM_IS_EMPTY(*availrealms))
1466 ? "<No Realms>" : *availrealms);
1467
1468 /* check whether context is in list */
1469 if (availrealms != NULL && *availrealms != NULL)
1470 {
1471 if (iteminlist(context, (char *)(*availrealms + 1), " ,}") ==
1472 NULL)
1473 {
1474 if (LogLevel > 8)
1475 sm_syslog(LOG_ERR, NOQID,
1476 "AUTH=client, realm=%s not in list=%s",
1477 r, *availrealms);
1478 return SASL_FAIL;
1479 }
1480 }
1481 *result = r;
1482 return SASL_OK;
1483 }
1484 /*
1485 ** ITEMINLIST -- does item appear in list?
1486 **
1487 ** Check whether item appears in list (which must be separated by a
1488 ** character in delim) as a "word", i.e. it must appear at the begin
1489 ** of the list or after a space, and it must end with a space or the
1490 ** end of the list.
1491 **
1492 ** Parameters:
1493 ** item -- item to search.
1494 ** list -- list of items.
1495 ** delim -- list of delimiters.
1496 **
1497 ** Returns:
1498 ** pointer to occurrence (NULL if not found).
1499 */
1500
1501 char *
iteminlist(item,list,delim)1502 iteminlist(item, list, delim)
1503 char *item;
1504 char *list;
1505 char *delim;
1506 {
1507 char *s;
1508 int len;
1509
1510 if (SM_IS_EMPTY(list))
1511 return NULL;
1512 if (SM_IS_EMPTY(item))
1513 return NULL;
1514 s = list;
1515 len = strlen(item);
1516 while (s != NULL && *s != '\0')
1517 {
1518 if (sm_strncasecmp(s, item, len) == 0 &&
1519 (s[len] == '\0' || strchr(delim, s[len]) != NULL))
1520 return s;
1521 s = strpbrk(s, delim);
1522 if (s != NULL)
1523 while (*++s == ' ')
1524 continue;
1525 }
1526 return NULL;
1527 }
1528 /*
1529 ** REMOVEMECH -- remove item [rem] from list [list]
1530 **
1531 ** Parameters:
1532 ** rem -- item to remove
1533 ** list -- list of items
1534 ** rpool -- resource pool from which result is allocated.
1535 **
1536 ** Returns:
1537 ** pointer to new list (NULL in case of error).
1538 */
1539
1540 static char *
removemech(rem,list,rpool)1541 removemech(rem, list, rpool)
1542 char *rem;
1543 char *list;
1544 SM_RPOOL_T *rpool;
1545 {
1546 char *ret;
1547 char *needle;
1548 int len;
1549
1550 if (list == NULL)
1551 return NULL;
1552 if (SM_IS_EMPTY(rem))
1553 {
1554 /* take out what? */
1555 return NULL;
1556 }
1557
1558 /* find the item in the list */
1559 if ((needle = iteminlist(rem, list, " ")) == NULL)
1560 {
1561 /* not in there: return original */
1562 return list;
1563 }
1564
1565 /* length of string without rem */
1566 len = strlen(list) - strlen(rem);
1567 if (len <= 0)
1568 {
1569 ret = (char *) sm_rpool_malloc_x(rpool, 1);
1570 *ret = '\0';
1571 return ret;
1572 }
1573 ret = (char *) sm_rpool_malloc_x(rpool, len);
1574 memset(ret, '\0', len);
1575
1576 /* copy from start to removed item */
1577 memcpy(ret, list, needle - list);
1578
1579 /* length of rest of string past removed item */
1580 len = strlen(needle) - strlen(rem) - 1;
1581 if (len > 0)
1582 {
1583 /* not last item -- copy into string */
1584 memcpy(ret + (needle - list),
1585 list + (needle - list) + strlen(rem) + 1,
1586 len);
1587 }
1588 else
1589 ret[(needle - list) - 1] = '\0';
1590 return ret;
1591 }
1592 /*
1593 ** ATTEMPTAUTH -- try to AUTHenticate using one mechanism
1594 **
1595 ** Parameters:
1596 ** m -- the mailer.
1597 ** mci -- the mailer connection structure.
1598 ** e -- the envelope (including the sender to specify).
1599 ** sai - sasl authinfo
1600 **
1601 ** Returns:
1602 ** EX_OK -- authentication was successful.
1603 ** EX_NOPERM -- authentication failed.
1604 ** EX_IOERR -- authentication dialogue failed (I/O problem?).
1605 ** EX_TEMPFAIL -- temporary failure.
1606 **
1607 */
1608
1609 static int
attemptauth(m,mci,e,sai)1610 attemptauth(m, mci, e, sai)
1611 MAILER *m;
1612 MCI *mci;
1613 ENVELOPE *e;
1614 SASL_AI_T *sai;
1615 {
1616 int saslresult, smtpresult;
1617 # if SASL >= 20000
1618 sasl_ssf_t ssf;
1619 const char *auth_id;
1620 const char *out;
1621 # else /* SASL >= 20000 */
1622 sasl_external_properties_t ssf;
1623 char *out;
1624 # endif /* SASL >= 20000 */
1625 unsigned int outlen;
1626 sasl_interact_t *client_interact = NULL;
1627 char *mechusing;
1628 sasl_security_properties_t ssp;
1629
1630 /* MUST NOT be a multiple of 4: bug in some sasl_encode64() versions */
1631 char in64[MAXOUTLEN + 1];
1632 # if NETINET || (NETINET6 && SASL >= 20000)
1633 extern SOCKADDR CurHostAddr;
1634 # endif
1635
1636 /* no mechanism selected (yet) */
1637 (*sai)[SASL_MECH] = NULL;
1638
1639 /* dispose old connection */
1640 if (mci->mci_conn != NULL)
1641 sasl_dispose(&(mci->mci_conn));
1642
1643 /* make a new client sasl connection */
1644 # if SASL >= 20000
1645 /*
1646 ** We provide the callbacks again because global callbacks in
1647 ** sasl_client_init() are ignored if SASL has been initialized
1648 ** before, for example, by a library such as libnss-ldap.
1649 */
1650
1651 saslresult = sasl_client_new(bitnset(M_LMTP, m->m_flags) ? "lmtp"
1652 : "smtp",
1653 CurHostName, NULL, NULL, callbacks, 0,
1654 &mci->mci_conn);
1655 # else /* SASL >= 20000 */
1656 saslresult = sasl_client_new(bitnset(M_LMTP, m->m_flags) ? "lmtp"
1657 : "smtp",
1658 CurHostName, NULL, 0, &mci->mci_conn);
1659 # endif /* SASL >= 20000 */
1660 if (saslresult != SASL_OK)
1661 return EX_TEMPFAIL;
1662
1663 /* set properties */
1664 (void) memset(&ssp, '\0', sizeof(ssp));
1665
1666 /* XXX should these be options settable via .cf ? */
1667 ssp.max_ssf = MaxSLBits;
1668 ssp.maxbufsize = MAXOUTLEN;
1669 # if 0
1670 ssp.security_flags = SASL_SEC_NOPLAINTEXT;
1671 # endif
1672 saslresult = sasl_setprop(mci->mci_conn, SASL_SEC_PROPS, &ssp);
1673 if (saslresult != SASL_OK)
1674 return EX_TEMPFAIL;
1675
1676 # if SASL >= 20000
1677 /* external security strength factor, authentication id */
1678 ssf = 0;
1679 auth_id = NULL;
1680 # if STARTTLS
1681 out = macvalue(macid("{cert_subject}"), e);
1682 if (out != NULL && *out != '\0')
1683 auth_id = out;
1684 out = macvalue(macid("{cipher_bits}"), e);
1685 if (out != NULL && *out != '\0')
1686 ssf = atoi(out);
1687 # endif /* STARTTLS */
1688 saslresult = sasl_setprop(mci->mci_conn, SASL_SSF_EXTERNAL, &ssf);
1689 if (saslresult != SASL_OK)
1690 return EX_TEMPFAIL;
1691 saslresult = sasl_setprop(mci->mci_conn, SASL_AUTH_EXTERNAL, auth_id);
1692 if (saslresult != SASL_OK)
1693 return EX_TEMPFAIL;
1694
1695 # if NETINET || NETINET6
1696 /* set local/remote ipv4 addresses */
1697 if (mci->mci_out != NULL && (
1698 # if NETINET6
1699 CurHostAddr.sa.sa_family == AF_INET6 ||
1700 # endif
1701 CurHostAddr.sa.sa_family == AF_INET))
1702 {
1703 SOCKADDR_LEN_T addrsize;
1704 SOCKADDR saddr_l;
1705 char localip[60], remoteip[60];
1706
1707 switch (CurHostAddr.sa.sa_family)
1708 {
1709 case AF_INET:
1710 addrsize = sizeof(struct sockaddr_in);
1711 break;
1712 # if NETINET6
1713 case AF_INET6:
1714 addrsize = sizeof(struct sockaddr_in6);
1715 break;
1716 # endif
1717 default:
1718 break;
1719 }
1720 if (iptostring(&CurHostAddr, addrsize,
1721 remoteip, sizeof(remoteip)))
1722 {
1723 if (sasl_setprop(mci->mci_conn, SASL_IPREMOTEPORT,
1724 remoteip) != SASL_OK)
1725 return EX_TEMPFAIL;
1726 }
1727 addrsize = sizeof(saddr_l);
1728 if (getsockname(sm_io_getinfo(mci->mci_out, SM_IO_WHAT_FD,
1729 NULL),
1730 (struct sockaddr *) &saddr_l, &addrsize) == 0)
1731 {
1732 if (iptostring(&saddr_l, addrsize,
1733 localip, sizeof(localip)))
1734 {
1735 if (sasl_setprop(mci->mci_conn,
1736 SASL_IPLOCALPORT,
1737 localip) != SASL_OK)
1738 return EX_TEMPFAIL;
1739 }
1740 }
1741 }
1742 # endif /* NETINET || NETINET6 */
1743
1744 /* start client side of sasl */
1745 saslresult = sasl_client_start(mci->mci_conn, mci->mci_saslcap,
1746 &client_interact,
1747 &out, &outlen,
1748 (const char **) &mechusing);
1749 # else /* SASL >= 20000 */
1750 /* external security strength factor, authentication id */
1751 ssf.ssf = 0;
1752 ssf.auth_id = NULL;
1753 # if STARTTLS
1754 out = macvalue(macid("{cert_subject}"), e);
1755 if (out != NULL && *out != '\0')
1756 ssf.auth_id = out;
1757 out = macvalue(macid("{cipher_bits}"), e);
1758 if (out != NULL && *out != '\0')
1759 ssf.ssf = atoi(out);
1760 # endif /* STARTTLS */
1761 saslresult = sasl_setprop(mci->mci_conn, SASL_SSF_EXTERNAL, &ssf);
1762 if (saslresult != SASL_OK)
1763 return EX_TEMPFAIL;
1764
1765 # if NETINET
1766 /* set local/remote ipv4 addresses */
1767 if (mci->mci_out != NULL && CurHostAddr.sa.sa_family == AF_INET)
1768 {
1769 SOCKADDR_LEN_T addrsize;
1770 struct sockaddr_in saddr_l;
1771
1772 if (sasl_setprop(mci->mci_conn, SASL_IP_REMOTE,
1773 (struct sockaddr_in *) &CurHostAddr)
1774 != SASL_OK)
1775 return EX_TEMPFAIL;
1776 addrsize = sizeof(struct sockaddr_in);
1777 if (getsockname(sm_io_getinfo(mci->mci_out, SM_IO_WHAT_FD,
1778 NULL),
1779 (struct sockaddr *) &saddr_l, &addrsize) == 0)
1780 {
1781 if (sasl_setprop(mci->mci_conn, SASL_IP_LOCAL,
1782 &saddr_l) != SASL_OK)
1783 return EX_TEMPFAIL;
1784 }
1785 }
1786 # endif /* NETINET */
1787
1788 /* start client side of sasl */
1789 saslresult = sasl_client_start(mci->mci_conn, mci->mci_saslcap,
1790 NULL, &client_interact,
1791 &out, &outlen,
1792 (const char **) &mechusing);
1793 # endif /* SASL >= 20000 */
1794
1795 if (saslresult != SASL_OK && saslresult != SASL_CONTINUE)
1796 {
1797 if (saslresult == SASL_NOMECH && LogLevel > 8)
1798 {
1799 sm_syslog(LOG_NOTICE, e->e_id,
1800 "AUTH=client, available mechanisms=%s do not fulfill requirements", mci->mci_saslcap);
1801 }
1802 return EX_TEMPFAIL;
1803 }
1804
1805 /* just point current mechanism to the data in the sasl library */
1806 (*sai)[SASL_MECH] = mechusing;
1807
1808 /* send the info across the wire */
1809 if (out == NULL
1810 /* login and digest-md5 up to 1.5.28 set out="" */
1811 || (outlen == 0 &&
1812 (SM_STRCASEEQ(mechusing, "login") ||
1813 SM_STRCASEEQ(mechusing, "digest-md5")))
1814 )
1815 {
1816 /* no initial response */
1817 smtpmessage("AUTH %s", m, mci, mechusing);
1818 }
1819 else if (outlen == 0)
1820 {
1821 /*
1822 ** zero-length initial response, per RFC 2554 4.:
1823 ** "Unlike a zero-length client answer to a 334 reply, a zero-
1824 ** length initial response is sent as a single equals sign"
1825 */
1826
1827 smtpmessage("AUTH %s =", m, mci, mechusing);
1828 }
1829 else
1830 {
1831 saslresult = sasl_encode64(out, outlen, in64, sizeof(in64),
1832 NULL);
1833 if (saslresult != SASL_OK) /* internal error */
1834 {
1835 if (LogLevel > 8)
1836 sm_syslog(LOG_ERR, e->e_id,
1837 "encode64 for AUTH failed");
1838 return EX_TEMPFAIL;
1839 }
1840 smtpmessage("AUTH %s %s", m, mci, mechusing, in64);
1841 }
1842 # if SASL < 20000
1843 sm_sasl_free(out); /* XXX only if no rpool is used */
1844 # endif
1845
1846 /* get the reply */
1847 smtpresult = reply(m, mci, e, TimeOuts.to_auth, getsasldata, NULL,
1848 XS_AUTH, NULL);
1849
1850 for (;;)
1851 {
1852 /* check return code from server */
1853 if (smtpresult == 235)
1854 {
1855 macdefine(&mci->mci_macro, A_TEMP, macid("{auth_type}"),
1856 mechusing);
1857 return EX_OK;
1858 }
1859 if (smtpresult == -1)
1860 return EX_IOERR;
1861 if (REPLYTYPE(smtpresult) == 5)
1862 return EX_NOPERM; /* ugly, but ... */
1863 if (REPLYTYPE(smtpresult) != 3)
1864 {
1865 /* should we fail deliberately, see RFC 2554 4. ? */
1866 /* smtpmessage("*", m, mci); */
1867 return EX_TEMPFAIL;
1868 }
1869
1870 saslresult = sasl_client_step(mci->mci_conn,
1871 mci->mci_sasl_string,
1872 mci->mci_sasl_string_len,
1873 &client_interact,
1874 &out, &outlen);
1875
1876 if (saslresult != SASL_OK && saslresult != SASL_CONTINUE)
1877 {
1878 if (tTd(95, 5))
1879 sm_dprintf("AUTH FAIL=%s (%d)\n",
1880 sasl_errstring(saslresult, NULL, NULL),
1881 saslresult);
1882
1883 /* fail deliberately, see RFC 2554 4. */
1884 smtpmessage("*", m, mci);
1885
1886 /*
1887 ** but we should only fail for this authentication
1888 ** mechanism; how to do that?
1889 */
1890
1891 smtpresult = reply(m, mci, e, TimeOuts.to_auth,
1892 getsasldata, NULL, XS_AUTH, NULL);
1893 return EX_NOPERM;
1894 }
1895
1896 if (outlen > 0)
1897 {
1898 saslresult = sasl_encode64(out, outlen, in64,
1899 sizeof(in64), NULL);
1900 if (saslresult != SASL_OK)
1901 {
1902 /* give an error reply to the other side! */
1903 smtpmessage("*", m, mci);
1904 return EX_TEMPFAIL;
1905 }
1906 }
1907 else
1908 in64[0] = '\0';
1909 # if SASL < 20000
1910 sm_sasl_free(out); /* XXX only if no rpool is used */
1911 # endif
1912 smtpmessage("%s", m, mci, in64);
1913 smtpresult = reply(m, mci, e, TimeOuts.to_auth,
1914 getsasldata, NULL, XS_AUTH, NULL);
1915 }
1916 /* NOTREACHED */
1917 }
1918 /*
1919 ** SMTPAUTH -- try to AUTHenticate
1920 **
1921 ** This will try mechanisms in the order the sasl library decided until:
1922 ** - there are no more mechanisms
1923 ** - a mechanism succeeds
1924 ** - the sasl library fails initializing
1925 **
1926 ** Parameters:
1927 ** m -- the mailer.
1928 ** mci -- the mailer connection info.
1929 ** e -- the envelope.
1930 **
1931 ** Returns:
1932 ** EX_OK -- authentication was successful
1933 ** EX_UNAVAILABLE -- authentication not possible, e.g.,
1934 ** no data available.
1935 ** EX_NOPERM -- authentication failed.
1936 ** EX_TEMPFAIL -- temporary failure.
1937 **
1938 ** Notice: AuthInfo is used for all connections, hence we must
1939 ** return EX_TEMPFAIL only if we really want to retry, i.e.,
1940 ** iff getauth() tempfailed or getauth() was used and
1941 ** authentication tempfailed.
1942 */
1943
1944 int
smtpauth(m,mci,e)1945 smtpauth(m, mci, e)
1946 MAILER *m;
1947 MCI *mci;
1948 ENVELOPE *e;
1949 {
1950 int result;
1951 int i;
1952 bool usedgetauth;
1953
1954 mci->mci_sasl_auth = false;
1955 for (i = 0; i < SASL_MECH ; i++)
1956 mci->mci_sai[i] = NULL;
1957
1958 result = getauth(mci, e, &(mci->mci_sai));
1959 if (result == EX_TEMPFAIL)
1960 return result;
1961 usedgetauth = true;
1962
1963 /* no data available: don't try to authenticate */
1964 if (result == EX_OK && mci->mci_sai[SASL_AUTHID] == NULL)
1965 return result;
1966 if (result != EX_OK)
1967 {
1968 if (SASLInfo == NULL)
1969 return EX_UNAVAILABLE;
1970
1971 /* read authinfo from file */
1972 result = readauth(SASLInfo, true, &(mci->mci_sai),
1973 mci->mci_rpool);
1974 if (result != EX_OK)
1975 return result;
1976 usedgetauth = false;
1977 }
1978
1979 /* check whether sufficient data is available */
1980 if (mci->mci_sai[SASL_PASSWORD] == NULL ||
1981 *(mci->mci_sai)[SASL_PASSWORD] == '\0')
1982 return EX_UNAVAILABLE;
1983 if ((mci->mci_sai[SASL_AUTHID] == NULL ||
1984 *(mci->mci_sai)[SASL_AUTHID] == '\0') &&
1985 (mci->mci_sai[SASL_USER] == NULL ||
1986 *(mci->mci_sai)[SASL_USER] == '\0'))
1987 return EX_UNAVAILABLE;
1988
1989 /* set the context for the callback function to sai */
1990 # if SASL >= 20000
1991 callbacks[CB_PASS_IDX].context = (void *) mci;
1992 # else
1993 callbacks[CB_PASS_IDX].context = (void *) &mci->mci_sai;
1994 # endif
1995 callbacks[CB_USER_IDX].context = (void *) &mci->mci_sai;
1996 callbacks[CB_AUTHNAME_IDX].context = (void *) &mci->mci_sai;
1997 callbacks[CB_GETREALM_IDX].context = (void *) &mci->mci_sai;
1998 # if 0
1999 callbacks[CB_SAFESASL_IDX].context = (void *) &mci->mci_sai;
2000 # endif
2001
2002 /* set default value for realm */
2003 if ((mci->mci_sai)[SASL_DEFREALM] == NULL)
2004 (mci->mci_sai)[SASL_DEFREALM] = sm_rpool_strdup_x(e->e_rpool,
2005 macvalue('j', CurEnv));
2006
2007 /* set default value for list of mechanism to use */
2008 if ((mci->mci_sai)[SASL_MECHLIST] == NULL ||
2009 *(mci->mci_sai)[SASL_MECHLIST] == '\0')
2010 (mci->mci_sai)[SASL_MECHLIST] = AuthMechanisms;
2011
2012 /* create list of mechanisms to try */
2013 mci->mci_saslcap = intersect((mci->mci_sai)[SASL_MECHLIST],
2014 mci->mci_saslcap, mci->mci_rpool);
2015
2016 /* initialize sasl client library */
2017 result = init_sasl_client();
2018 if (result != SASL_OK)
2019 return usedgetauth ? EX_TEMPFAIL : EX_UNAVAILABLE;
2020 do
2021 {
2022 result = attemptauth(m, mci, e, &(mci->mci_sai));
2023 if (result == EX_OK)
2024 mci->mci_sasl_auth = true;
2025 else if (result == EX_TEMPFAIL || result == EX_NOPERM)
2026 {
2027 mci->mci_saslcap = removemech((mci->mci_sai)[SASL_MECH],
2028 mci->mci_saslcap,
2029 mci->mci_rpool);
2030 if (mci->mci_saslcap == NULL ||
2031 *(mci->mci_saslcap) == '\0')
2032 return usedgetauth ? result
2033 : EX_UNAVAILABLE;
2034 }
2035 else
2036 return result;
2037 } while (result != EX_OK);
2038 return result;
2039 }
2040 #endif /* SASL */
2041
2042 /*
2043 ** SMTPMAILFROM -- send MAIL command
2044 **
2045 ** Parameters:
2046 ** m -- the mailer.
2047 ** mci -- the mailer connection structure.
2048 ** e -- the envelope (including the sender to specify).
2049 **
2050 ** Returns:
2051 ** exit status corresponding to mail status.
2052 */
2053
2054 int
smtpmailfrom(m,mci,e)2055 smtpmailfrom(m, mci, e)
2056 MAILER *m;
2057 MCI *mci;
2058 ENVELOPE *e;
2059 {
2060 int r;
2061 char *bufp;
2062 char *bodytype;
2063 char *enhsc;
2064 char buf[MAXNAME_I + 1];
2065 char optbuf[MAXLINE];
2066 #if _FFR_8BITENVADDR
2067 int len, nlen;
2068 #endif
2069
2070 if (tTd(18, 2))
2071 sm_dprintf("smtpmailfrom: CurHost=%s\n", CurHostName);
2072 enhsc = NULL;
2073
2074 /*
2075 ** Check if connection is gone, if so
2076 ** it's a tempfail and we use mci_errno
2077 ** for the reason.
2078 */
2079
2080 if (mci->mci_state == MCIS_CLOSED)
2081 {
2082 errno = mci->mci_errno;
2083 return EX_TEMPFAIL;
2084 }
2085
2086 #if USE_EAI
2087 if (bitset(EF_RESPONSE, e->e_flags) &&
2088 !bitnset(M_NO_NULL_FROM, m->m_flags))
2089 buf[0] = '\0';
2090 else
2091 {
2092 expand("\201g", buf, sizeof(buf), e);
2093 if (!addr_is_ascii(buf) && !e->e_smtputf8)
2094 e->e_smtputf8 = true;
2095 }
2096
2097 if (e->e_smtputf8 && !SMTP_UTF8)
2098 {
2099 extern char MsgBuf[];
2100
2101 /* XREF: format must be coordinated with giveresponse() */
2102 usrerrenh("5.6.7", "504 SMTPUTF8 required but not enabled");
2103 mci_setstat(mci, EX_NOTSTICKY, "5.6.7", MsgBuf);
2104 return EX_DATAERR;
2105 }
2106
2107 /*
2108 ** Abort right away if the message needs SMTPUTF8
2109 ** but the server does not advertise it.
2110 */
2111
2112 if (e->e_smtputf8 && !bitset(MCIF_EAI, mci->mci_flags))
2113 {
2114 extern char MsgBuf[];
2115
2116 /* XREF: format must be coordinated with giveresponse() */
2117 usrerrenh("5.6.7", "504 SMTPUTF8 required but not offered");
2118 mci_setstat(mci, EX_NOTSTICKY, "5.6.7", MsgBuf);
2119 return EX_DATAERR;
2120 }
2121 #endif /* USE_EAI */
2122
2123 /* set up appropriate options to include */
2124 if (bitset(MCIF_SIZE, mci->mci_flags) && e->e_msgsize > 0)
2125 {
2126 (void) sm_snprintf(optbuf, sizeof(optbuf), " SIZE=%ld",
2127 e->e_msgsize);
2128 bufp = &optbuf[strlen(optbuf)];
2129 }
2130 else
2131 {
2132 optbuf[0] = '\0';
2133 bufp = optbuf;
2134 }
2135
2136 #if USE_EAI
2137 if (e->e_smtputf8)
2138 {
2139 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
2140 " SMTPUTF8");
2141 bufp += strlen(bufp);
2142 }
2143 #endif /* USE_EAI */
2144
2145 bodytype = e->e_bodytype;
2146 if (bitset(MCIF_8BITMIME, mci->mci_flags))
2147 {
2148 if (bodytype == NULL &&
2149 bitset(MM_MIME8BIT, MimeMode) &&
2150 bitset(EF_HAS8BIT, e->e_flags) &&
2151 !bitset(EF_DONT_MIME, e->e_flags) &&
2152 !bitnset(M_8BITS, m->m_flags))
2153 bodytype = "8BITMIME";
2154 if (bodytype != NULL &&
2155 SPACELEFT(optbuf, bufp) > strlen(bodytype) + 7)
2156 {
2157 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
2158 " BODY=%s", bodytype);
2159 bufp += strlen(bufp);
2160 }
2161 }
2162 else if (bitnset(M_8BITS, m->m_flags) ||
2163 !bitset(EF_HAS8BIT, e->e_flags) ||
2164 bitset(MCIF_8BITOK, mci->mci_flags))
2165 {
2166 /* EMPTY */
2167 /* just pass it through */
2168 }
2169 #if MIME8TO7
2170 else if (bitset(MM_CVTMIME, MimeMode) &&
2171 !bitset(EF_DONT_MIME, e->e_flags) &&
2172 (!bitset(MM_PASS8BIT, MimeMode) ||
2173 bitset(EF_IS_MIME, e->e_flags)))
2174 {
2175 /* must convert from 8bit MIME format to 7bit encoded */
2176 mci->mci_flags |= MCIF_CVT8TO7;
2177 }
2178 #endif /* MIME8TO7 */
2179 else if (!bitset(MM_PASS8BIT, MimeMode))
2180 {
2181 /* cannot just send a 8-bit version */
2182 extern char MsgBuf[];
2183
2184 usrerrenh("5.6.3", "%s does not support 8BITMIME", CurHostName);
2185 mci_setstat(mci, EX_NOTSTICKY, "5.6.3", MsgBuf);
2186 return EX_DATAERR;
2187 }
2188
2189 if (bitset(MCIF_DSN, mci->mci_flags))
2190 {
2191 if (e->e_envid != NULL &&
2192 SPACELEFT(optbuf, bufp) > strlen(e->e_envid) + 7)
2193 {
2194 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
2195 " ENVID=%s", e->e_envid);
2196 bufp += strlen(bufp);
2197 }
2198
2199 /* RET= parameter */
2200 if (bitset(EF_RET_PARAM, e->e_flags) &&
2201 SPACELEFT(optbuf, bufp) > 9)
2202 {
2203 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
2204 " RET=%s",
2205 bitset(EF_NO_BODY_RETN, e->e_flags) ?
2206 "HDRS" : "FULL");
2207 bufp += strlen(bufp);
2208 }
2209 }
2210
2211 if (bitset(MCIF_AUTH, mci->mci_flags) && e->e_auth_param != NULL &&
2212 SPACELEFT(optbuf, bufp) > strlen(e->e_auth_param) + 7
2213 #if SASL
2214 && (!bitset(SASL_AUTH_AUTH, SASLOpts) || mci->mci_sasl_auth)
2215 #endif
2216 )
2217 {
2218 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
2219 " AUTH=%s", e->e_auth_param);
2220 bufp += strlen(bufp);
2221 }
2222
2223 /*
2224 ** 17 is the max length required, we could use log() to compute
2225 ** the exact length (and check IS_DLVR_TRACE())
2226 */
2227
2228 if (bitset(MCIF_DLVR_BY, mci->mci_flags) &&
2229 IS_DLVR_BY(e) && SPACELEFT(optbuf, bufp) > 17)
2230 {
2231 long dby;
2232
2233 /*
2234 ** Avoid problems with delays (for R) since the check
2235 ** in deliver() whether min-deliver-time is sufficient.
2236 ** Alternatively we could pass the computed time to this
2237 ** function.
2238 */
2239
2240 dby = e->e_deliver_by - (curtime() - e->e_ctime);
2241 if (dby <= 0 && IS_DLVR_RETURN(e))
2242 dby = mci->mci_min_by <= 0 ? 1 : mci->mci_min_by;
2243 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
2244 " BY=%ld;%c%s",
2245 dby,
2246 IS_DLVR_RETURN(e) ? 'R' : 'N',
2247 IS_DLVR_TRACE(e) ? "T" : "");
2248 bufp += strlen(bufp);
2249 }
2250
2251 /*
2252 ** Send the MAIL command.
2253 ** Designates the sender.
2254 */
2255
2256 maps_reset_chged("client:MAIL");
2257 mci->mci_state = MCIS_MAIL;
2258
2259 #if !USE_EAI
2260 if (bitset(EF_RESPONSE, e->e_flags) &&
2261 !bitnset(M_NO_NULL_FROM, m->m_flags))
2262 buf[0] = '\0';
2263 else
2264 expand("\201g", buf, sizeof(buf), e);
2265 #endif /* !USE_EAI */
2266 #if _FFR_8BITENVADDR
2267 if (tTd(18, 11))
2268 sm_dprintf("mail_expand=%s\n", buf);
2269 len = sizeof(buf);
2270 nlen = dequote_internal_chars(buf, buf, len);
2271 /* check length! but that's a bit late... */
2272 if (nlen > MAXNAME)
2273 sm_syslog(LOG_ERR, e->e_id, "MAIL too long: %d", nlen);
2274 if (tTd(18, 11))
2275 sm_dprintf("mail2=%s\n", buf);
2276 #endif /* _FFR_8BITENVADDR */
2277 if (buf[0] == '<')
2278 {
2279 /* strip off <angle brackets> (put back on below) */
2280 bufp = &buf[strlen(buf) - 1];
2281 if (*bufp == '>')
2282 *bufp = '\0';
2283 bufp = &buf[1];
2284 }
2285 else
2286 bufp = buf;
2287 if (bitnset(M_LOCALMAILER, e->e_from.q_mailer->m_flags) ||
2288 !bitnset(M_FROMPATH, m->m_flags))
2289 {
2290 smtpmessage("MAIL From:<%s>%s", m, mci, bufp, optbuf);
2291 }
2292 else
2293 {
2294 smtpmessage("MAIL From:<@%s%c%s>%s", m, mci, MyHostName,
2295 *bufp == '@' ? ',' : ':', bufp, optbuf);
2296 }
2297 SmtpPhase = mci->mci_phase = "client MAIL";
2298 sm_setproctitle(true, e, "%s %s: %s", qid_printname(e),
2299 CurHostName, mci->mci_phase);
2300 r = reply(m, mci, e, TimeOuts.to_mail, NULL, &enhsc, XS_MAIL, NULL);
2301 if (r < 0)
2302 {
2303 /* communications failure */
2304 mci_setstat(mci, EX_TEMPFAIL, "4.4.2", NULL);
2305 return EX_TEMPFAIL;
2306 }
2307 else if (r == SMTPCLOSING)
2308 {
2309 /* service shutting down: handled by reply() */
2310 return EX_TEMPFAIL;
2311 }
2312 else if (REPLYTYPE(r) == 4)
2313 {
2314 mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, smtptodsn(r)),
2315 SmtpReplyBuffer);
2316 return EX_TEMPFAIL;
2317 }
2318 else if (REPLYTYPE(r) == 2)
2319 {
2320 return EX_OK;
2321 }
2322 else if (r == 501)
2323 {
2324 /* syntax error in arguments */
2325 mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.5.2"),
2326 SmtpReplyBuffer);
2327 return EX_DATAERR;
2328 }
2329 else if (r == 553)
2330 {
2331 /* mailbox name not allowed */
2332 mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.1.3"),
2333 SmtpReplyBuffer);
2334 return EX_DATAERR;
2335 }
2336 else if (r == 552)
2337 {
2338 /* exceeded storage allocation */
2339 mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.3.4"),
2340 SmtpReplyBuffer);
2341 if (bitset(MCIF_SIZE, mci->mci_flags))
2342 e->e_flags |= EF_NO_BODY_RETN;
2343 return EX_UNAVAILABLE;
2344 }
2345 else if (REPLYTYPE(r) == 5)
2346 {
2347 /* unknown error */
2348 mci_setstat(mci, EX_NOTSTICKY, ENHSCN(enhsc, "5.0.0"),
2349 SmtpReplyBuffer);
2350 return EX_UNAVAILABLE;
2351 }
2352
2353 if (LogLevel > 1)
2354 {
2355 sm_syslog(LOG_CRIT, e->e_id,
2356 "%.100s: SMTP MAIL protocol error: %s",
2357 CurHostName,
2358 shortenstring(SmtpReplyBuffer, 403));
2359 }
2360
2361 /* protocol error -- close up */
2362 mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"),
2363 SmtpReplyBuffer);
2364 smtpquit(m, mci, e);
2365 return EX_PROTOCOL;
2366 }
2367 /*
2368 ** SMTPRCPT -- designate recipient.
2369 **
2370 ** Parameters:
2371 ** to -- address of recipient.
2372 ** m -- the mailer we are sending to.
2373 ** mci -- the connection info for this transaction.
2374 ** e -- the envelope for this transaction.
2375 **
2376 ** Returns:
2377 ** exit status corresponding to recipient status.
2378 **
2379 ** Side Effects:
2380 ** Sends the mail via SMTP.
2381 */
2382
2383 int
smtprcpt(to,m,mci,e,ctladdr,xstart)2384 smtprcpt(to, m, mci, e, ctladdr, xstart)
2385 ADDRESS *to;
2386 register MAILER *m;
2387 MCI *mci;
2388 ENVELOPE *e;
2389 ADDRESS *ctladdr;
2390 time_t xstart;
2391 {
2392 char *bufp;
2393 char optbuf[MAXLINE];
2394 char *rcpt;
2395 #if _FFR_8BITENVADDR
2396 char buf[MAXNAME + 1]; /* EAI:ok */
2397 int len, nlen;
2398 #endif
2399 #if PIPELINING
2400 char *oldto;
2401 #endif
2402
2403 #if PIPELINING
2404 /*
2405 ** If there is status waiting from the other end, read it.
2406 ** This should normally happen because of SMTP pipelining.
2407 */
2408
2409 oldto = e->e_to;
2410 while (mci->mci_nextaddr != NULL &&
2411 sm_io_getinfo(mci->mci_in, SM_IO_IS_READABLE, NULL) > 0)
2412 {
2413 int r;
2414
2415 e->e_to = mci->mci_nextaddr->q_paddr;
2416 r = smtprcptstat(mci->mci_nextaddr, m, mci, e);
2417 if (r != EX_OK)
2418 {
2419 markfailure(e, mci->mci_nextaddr, mci, r, false);
2420 giveresponse(r, mci->mci_nextaddr->q_status, m, mci,
2421 ctladdr, xstart, e, mci->mci_nextaddr);
2422 }
2423 mci->mci_nextaddr = mci->mci_nextaddr->q_pchain;
2424 e->e_to = oldto;
2425 }
2426 e->e_to = oldto;
2427 #endif /* PIPELINING */
2428
2429 /*
2430 ** Check if connection is gone, if so
2431 ** it's a tempfail and we use mci_errno
2432 ** for the reason.
2433 */
2434
2435 if (mci->mci_state == MCIS_CLOSED)
2436 {
2437 errno = mci->mci_errno;
2438 return EX_TEMPFAIL;
2439 }
2440
2441 optbuf[0] = '\0';
2442 bufp = optbuf;
2443
2444 /*
2445 ** Warning: in the following it is assumed that the free space
2446 ** in bufp is sizeof(optbuf)
2447 */
2448
2449 if (bitset(MCIF_DSN, mci->mci_flags))
2450 {
2451 if (IS_DLVR_NOTIFY(e) &&
2452 !bitset(MCIF_DLVR_BY, mci->mci_flags))
2453 {
2454 /* RFC 2852: 4.1.4.2 */
2455 if (!bitset(QHASNOTIFY, to->q_flags))
2456 to->q_flags |= QPINGONFAILURE|QPINGONDELAY|QHASNOTIFY;
2457 else if (bitset(QPINGONSUCCESS, to->q_flags) ||
2458 bitset(QPINGONFAILURE, to->q_flags) ||
2459 bitset(QPINGONDELAY, to->q_flags))
2460 to->q_flags |= QPINGONDELAY;
2461 }
2462
2463 /* NOTIFY= parameter */
2464 if (bitset(QHASNOTIFY, to->q_flags) &&
2465 bitset(QPRIMARY, to->q_flags) &&
2466 !bitnset(M_LOCALMAILER, m->m_flags))
2467 {
2468 bool firstone = true;
2469
2470 (void) sm_strlcat(bufp, " NOTIFY=", sizeof(optbuf));
2471 if (bitset(QPINGONSUCCESS, to->q_flags))
2472 {
2473 (void) sm_strlcat(bufp, "SUCCESS", sizeof(optbuf));
2474 firstone = false;
2475 }
2476 if (bitset(QPINGONFAILURE, to->q_flags))
2477 {
2478 if (!firstone)
2479 (void) sm_strlcat(bufp, ",",
2480 sizeof(optbuf));
2481 (void) sm_strlcat(bufp, "FAILURE", sizeof(optbuf));
2482 firstone = false;
2483 }
2484 if (bitset(QPINGONDELAY, to->q_flags))
2485 {
2486 if (!firstone)
2487 (void) sm_strlcat(bufp, ",",
2488 sizeof(optbuf));
2489 (void) sm_strlcat(bufp, "DELAY", sizeof(optbuf));
2490 firstone = false;
2491 }
2492 if (firstone)
2493 (void) sm_strlcat(bufp, "NEVER", sizeof(optbuf));
2494 bufp += strlen(bufp);
2495 }
2496
2497 /* ORCPT= parameter */
2498 if (to->q_orcpt != NULL &&
2499 SPACELEFT(optbuf, bufp) > strlen(to->q_orcpt) + 7)
2500 {
2501 (void) sm_snprintf(bufp, SPACELEFT(optbuf, bufp),
2502 " ORCPT=%s", to->q_orcpt);
2503 bufp += strlen(bufp);
2504 }
2505 }
2506
2507 rcpt = to->q_user;
2508 #if _FFR_8BITENVADDR
2509 if (tTd(18, 11))
2510 sm_dprintf("rcpt=%s\n", rcpt);
2511 len = sizeof(buf);
2512 nlen = dequote_internal_chars(rcpt, buf, len);
2513 rcpt = buf;
2514 /* check length! but that's a bit late... */
2515 if (nlen > MAXNAME)
2516 sm_syslog(LOG_ERR, e->e_id, "RCPT too long: %d", nlen);
2517 if (tTd(18, 11))
2518 sm_dprintf("rcpt2=%s\n", rcpt);
2519 #endif /* _FFR_8BITENVADDR */
2520
2521 smtpmessage("RCPT To:<%s>%s", m, mci, rcpt, optbuf);
2522 mci->mci_state = MCIS_RCPT;
2523
2524 SmtpPhase = mci->mci_phase = "client RCPT";
2525 sm_setproctitle(true, e, "%s %s: %s", qid_printname(e),
2526 CurHostName, mci->mci_phase);
2527
2528 #if PIPELINING
2529 /*
2530 ** If running SMTP pipelining, we will pick up status later
2531 */
2532
2533 if (bitset(MCIF_PIPELINED, mci->mci_flags))
2534 return EX_OK;
2535 #endif /* PIPELINING */
2536
2537 return smtprcptstat(to, m, mci, e);
2538 }
2539 /*
2540 ** SMTPRCPTSTAT -- get recipient status
2541 **
2542 ** This is only called during SMTP pipelining
2543 **
2544 ** Parameters:
2545 ** to -- address of recipient.
2546 ** m -- mailer being sent to.
2547 ** mci -- the mailer connection information.
2548 ** e -- the envelope for this message.
2549 **
2550 ** Returns:
2551 ** EX_* -- protocol status
2552 */
2553
2554 static int
smtprcptstat(to,m,mci,e)2555 smtprcptstat(to, m, mci, e)
2556 ADDRESS *to;
2557 MAILER *m;
2558 register MCI *mci;
2559 register ENVELOPE *e;
2560 {
2561 int r;
2562 int save_errno;
2563 char *enhsc;
2564
2565 /*
2566 ** Check if connection is gone, if so
2567 ** it's a tempfail and we use mci_errno
2568 ** for the reason.
2569 */
2570
2571 if (mci->mci_state == MCIS_CLOSED)
2572 {
2573 errno = mci->mci_errno;
2574 return EX_TEMPFAIL;
2575 }
2576
2577 enhsc = NULL;
2578 r = reply(m, mci, e, TimeOuts.to_rcpt, NULL, &enhsc, XS_RCPT,
2579 &to->q_rstatus);
2580 save_errno = errno;
2581 to->q_status = ENHSCN_RPOOL(enhsc, smtptodsn(r), e->e_rpool);
2582 if (!bitnset(M_LMTP, m->m_flags))
2583 to->q_statmta = mci->mci_host;
2584 if (r < 0 || REPLYTYPE(r) == 4)
2585 {
2586 mci->mci_retryrcpt = true;
2587 errno = save_errno;
2588 return EX_TEMPFAIL;
2589 }
2590 else if (REPLYTYPE(r) == 2)
2591 {
2592 char *t;
2593
2594 if ((t = mci->mci_tolist) != NULL)
2595 {
2596 char *p;
2597
2598 *t++ = ',';
2599 for (p = to->q_paddr; *p != '\0'; *t++ = *p++)
2600 continue;
2601 *t = '\0';
2602 mci->mci_tolist = t;
2603 }
2604 mci->mci_okrcpts++;
2605 return EX_OK;
2606 }
2607 else if (r == 550)
2608 {
2609 to->q_status = ENHSCN_RPOOL(enhsc, "5.1.1", e->e_rpool);
2610 return EX_NOUSER;
2611 }
2612 else if (r == 551)
2613 {
2614 to->q_status = ENHSCN_RPOOL(enhsc, "5.1.6", e->e_rpool);
2615 return EX_NOUSER;
2616 }
2617 else if (r == 553)
2618 {
2619 to->q_status = ENHSCN_RPOOL(enhsc, "5.1.3", e->e_rpool);
2620 return EX_NOUSER;
2621 }
2622 else if (REPLYTYPE(r) == 5)
2623 {
2624 return EX_UNAVAILABLE;
2625 }
2626
2627 if (LogLevel > 1)
2628 {
2629 sm_syslog(LOG_CRIT, e->e_id,
2630 "%.100s: SMTP RCPT protocol error: %s",
2631 CurHostName,
2632 shortenstring(SmtpReplyBuffer, 403));
2633 }
2634
2635 mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"),
2636 SmtpReplyBuffer);
2637 return EX_PROTOCOL;
2638 }
2639 /*
2640 ** SMTPDATA -- send the data and clean up the transaction.
2641 **
2642 ** Parameters:
2643 ** m -- mailer being sent to.
2644 ** mci -- the mailer connection information.
2645 ** e -- the envelope for this message.
2646 **
2647 ** Returns:
2648 ** exit status corresponding to DATA command.
2649 */
2650
2651 int
smtpdata(m,mci,e,ctladdr,xstart)2652 smtpdata(m, mci, e, ctladdr, xstart)
2653 MAILER *m;
2654 register MCI *mci;
2655 register ENVELOPE *e;
2656 ADDRESS *ctladdr;
2657 time_t xstart;
2658 {
2659 register int r;
2660 int rstat;
2661 int xstat;
2662 int timeout;
2663 char *enhsc;
2664
2665 /*
2666 ** Check if connection is gone, if so
2667 ** it's a tempfail and we use mci_errno
2668 ** for the reason.
2669 */
2670
2671 if (mci->mci_state == MCIS_CLOSED)
2672 {
2673 errno = mci->mci_errno;
2674 return EX_TEMPFAIL;
2675 }
2676
2677 enhsc = NULL;
2678
2679 /*
2680 ** Send the data.
2681 ** First send the command and check that it is ok.
2682 ** Then send the data (if there are valid recipients).
2683 ** Follow it up with a dot to terminate.
2684 ** Finally get the results of the transaction.
2685 */
2686
2687 /* send the command and check ok to proceed */
2688 smtpmessage("DATA", m, mci);
2689
2690 #if PIPELINING
2691 if (mci->mci_nextaddr != NULL)
2692 {
2693 char *oldto = e->e_to;
2694
2695 /* pick up any pending RCPT responses for SMTP pipelining */
2696 while (mci->mci_nextaddr != NULL)
2697 {
2698 e->e_to = mci->mci_nextaddr->q_paddr;
2699 r = smtprcptstat(mci->mci_nextaddr, m, mci, e);
2700 if (r != EX_OK)
2701 {
2702 markfailure(e, mci->mci_nextaddr, mci, r,
2703 false);
2704 giveresponse(r, mci->mci_nextaddr->q_status, m,
2705 mci, ctladdr, xstart, e,
2706 mci->mci_nextaddr);
2707 if (r == EX_TEMPFAIL)
2708 mci->mci_nextaddr->q_state = QS_RETRY;
2709 }
2710 mci->mci_nextaddr = mci->mci_nextaddr->q_pchain;
2711 }
2712 e->e_to = oldto;
2713
2714 /*
2715 ** Connection might be closed in response to a RCPT command,
2716 ** i.e., the server responded with 421. In that case (at
2717 ** least) one RCPT has a temporary failure, hence we don't
2718 ** need to check mci_okrcpts (as it is done below) to figure
2719 ** out which error to return.
2720 */
2721
2722 if (mci->mci_state == MCIS_CLOSED)
2723 {
2724 errno = mci->mci_errno;
2725 return EX_TEMPFAIL;
2726 }
2727 }
2728 #endif /* PIPELINING */
2729
2730 /* now proceed with DATA phase */
2731 SmtpPhase = mci->mci_phase = "client DATA 354";
2732 mci->mci_state = MCIS_DATA;
2733 sm_setproctitle(true, e, "%s %s: %s",
2734 qid_printname(e), CurHostName, mci->mci_phase);
2735 r = reply(m, mci, e, TimeOuts.to_datainit, NULL, &enhsc, XS_DATA, NULL);
2736 if (r < 0 || REPLYTYPE(r) == 4)
2737 {
2738 if (r >= 0)
2739 smtpquit(m, mci, e);
2740 errno = mci->mci_errno;
2741 return EX_TEMPFAIL;
2742 }
2743 else if (REPLYTYPE(r) == 5)
2744 {
2745 smtprset(m, mci, e);
2746 if (mci->mci_okrcpts <= 0 && mci->mci_retryrcpt)
2747 return EX_TEMPFAIL;
2748 return EX_UNAVAILABLE;
2749 }
2750 else if (REPLYTYPE(r) != 3)
2751 {
2752 if (LogLevel > 1)
2753 {
2754 sm_syslog(LOG_CRIT, e->e_id,
2755 "%.100s: SMTP DATA-1 protocol error: %s",
2756 CurHostName,
2757 shortenstring(SmtpReplyBuffer, 403));
2758 }
2759 smtprset(m, mci, e);
2760 mci_setstat(mci, EX_PROTOCOL, ENHSCN(enhsc, "5.5.1"),
2761 SmtpReplyBuffer);
2762 if (mci->mci_okrcpts <= 0 && mci->mci_retryrcpt)
2763 return EX_TEMPFAIL;
2764 return EX_PROTOCOL;
2765 }
2766
2767 if (mci->mci_okrcpts > 0)
2768 {
2769 /*
2770 ** Set timeout around data writes. Make it at least
2771 ** large enough for DNS timeouts on all recipients
2772 ** plus some fudge factor. The main thing is
2773 ** that it should not be infinite.
2774 */
2775
2776 if (tTd(18, 101))
2777 {
2778 /* simulate a DATA timeout */
2779 timeout = 10;
2780 }
2781 else
2782 timeout = DATA_PROGRESS_TIMEOUT * 1000;
2783 sm_io_setinfo(mci->mci_out, SM_IO_WHAT_TIMEOUT, &timeout);
2784
2785 /*
2786 ** Output the actual message.
2787 */
2788
2789 if (!(*e->e_puthdr)(mci, e->e_header, e, M87F_OUTER))
2790 goto writeerr;
2791
2792 if (tTd(18, 101))
2793 {
2794 /* simulate a DATA timeout */
2795 (void) sleep(2);
2796 }
2797
2798 if (!(*e->e_putbody)(mci, e, NULL))
2799 goto writeerr;
2800
2801 /*
2802 ** Cleanup after sending message.
2803 */
2804 }
2805
2806 #if _FFR_CATCH_BROKEN_MTAS
2807 if (sm_io_getinfo(mci->mci_in, SM_IO_IS_READABLE, NULL) > 0)
2808 {
2809 /* terminate the message */
2810 (void) sm_io_fprintf(mci->mci_out, SM_TIME_DEFAULT, ".%s",
2811 m->m_eol);
2812 if (TrafficLogFile != NULL)
2813 (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
2814 "%05d >>> .\n", (int) CurrentPid);
2815 if (Verbose)
2816 nmessage(">>> .");
2817
2818 sm_syslog(LOG_CRIT, e->e_id,
2819 "%.100s: SMTP DATA-1 protocol error: remote server returned response before final dot",
2820 CurHostName);
2821 mci->mci_errno = EIO;
2822 mci->mci_state = MCIS_ERROR;
2823 mci_setstat(mci, EX_PROTOCOL, "5.5.0", NULL);
2824 smtpquit(m, mci, e);
2825 return EX_PROTOCOL;
2826 }
2827 #endif /* _FFR_CATCH_BROKEN_MTAS */
2828
2829 if (sm_io_error(mci->mci_out))
2830 {
2831 /* error during processing -- don't send the dot */
2832 mci->mci_errno = EIO;
2833 mci->mci_state = MCIS_ERROR;
2834 mci_setstat(mci, EX_IOERR, "4.4.2", NULL);
2835 smtpquit(m, mci, e);
2836 return EX_IOERR;
2837 }
2838
2839 /* terminate the message */
2840 if (sm_io_fprintf(mci->mci_out, SM_TIME_DEFAULT, "%s.%s",
2841 bitset(MCIF_INLONGLINE, mci->mci_flags) ? m->m_eol : "",
2842 m->m_eol) == SM_IO_EOF)
2843 goto writeerr;
2844 if (TrafficLogFile != NULL)
2845 (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
2846 "%05d >>> .\n", (int) CurrentPid);
2847 if (Verbose)
2848 nmessage(">>> .");
2849
2850 /* check for the results of the transaction */
2851 SmtpPhase = mci->mci_phase = "client DATA status";
2852 sm_setproctitle(true, e, "%s %s: %s", qid_printname(e),
2853 CurHostName, mci->mci_phase);
2854 if (bitnset(M_LMTP, m->m_flags))
2855 return EX_OK;
2856 r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc, XS_EOM, NULL);
2857 if (r < 0)
2858 return EX_TEMPFAIL;
2859 if (mci->mci_state == MCIS_DATA)
2860 mci->mci_state = MCIS_OPEN;
2861 xstat = EX_NOTSTICKY;
2862 if (r == 452)
2863 rstat = EX_TEMPFAIL;
2864 else if (REPLYTYPE(r) == 4)
2865 rstat = xstat = EX_TEMPFAIL;
2866 else if (REPLYTYPE(r) == 2)
2867 rstat = xstat = EX_OK;
2868 else if (REPLYCLASS(r) != 5)
2869 rstat = xstat = EX_PROTOCOL;
2870 else if (REPLYTYPE(r) == 5)
2871 rstat = EX_UNAVAILABLE;
2872 else
2873 rstat = EX_PROTOCOL;
2874 mci_setstat(mci, xstat, ENHSCN(enhsc, smtptodsn(r)),
2875 SmtpReplyBuffer);
2876 if (bitset(MCIF_ENHSTAT, mci->mci_flags) &&
2877 (r = isenhsc(SmtpReplyBuffer + 4, ' ')) > 0)
2878 r += 5;
2879 else
2880 r = 4;
2881 e->e_statmsg = sm_rpool_strdup_x(e->e_rpool, &SmtpReplyBuffer[r]);
2882 SmtpPhase = mci->mci_phase = "idle";
2883 sm_setproctitle(true, e, "%s: %s", CurHostName, mci->mci_phase);
2884 if (rstat != EX_PROTOCOL)
2885 return rstat;
2886 if (LogLevel > 1)
2887 {
2888 sm_syslog(LOG_CRIT, e->e_id,
2889 "%.100s: SMTP DATA-2 protocol error: %s",
2890 CurHostName,
2891 shortenstring(SmtpReplyBuffer, 403));
2892 }
2893 return rstat;
2894
2895 writeerr:
2896 mci->mci_errno = errno;
2897 mci->mci_state = MCIS_ERROR;
2898 mci_setstat(mci, bitset(MCIF_NOTSTICKY, mci->mci_flags)
2899 ? EX_NOTSTICKY: EX_TEMPFAIL,
2900 "4.4.2", NULL);
2901 mci->mci_flags &= ~MCIF_NOTSTICKY;
2902
2903 /*
2904 ** If putbody() couldn't finish due to a timeout,
2905 ** rewind it here in the timeout handler. See
2906 ** comments at the end of putbody() for reasoning.
2907 */
2908
2909 if (e->e_dfp != NULL)
2910 (void) bfrewind(e->e_dfp);
2911
2912 errno = mci->mci_errno;
2913 syserr("+451 4.4.1 timeout writing message to %s", CurHostName);
2914 smtpquit(m, mci, e);
2915 return EX_TEMPFAIL;
2916 }
2917
2918 /*
2919 ** SMTPGETSTAT -- get status code from DATA in LMTP
2920 **
2921 ** Parameters:
2922 ** m -- the mailer to which we are sending the message.
2923 ** mci -- the mailer connection structure.
2924 ** e -- the current envelope.
2925 **
2926 ** Returns:
2927 ** The exit status corresponding to the reply code.
2928 */
2929
2930 int
smtpgetstat(m,mci,e)2931 smtpgetstat(m, mci, e)
2932 MAILER *m;
2933 MCI *mci;
2934 ENVELOPE *e;
2935 {
2936 int r;
2937 int off;
2938 int status, xstat;
2939 char *enhsc;
2940
2941 enhsc = NULL;
2942
2943 /* check for the results of the transaction */
2944 r = reply(m, mci, e, TimeOuts.to_datafinal, NULL, &enhsc, XS_DATA2,
2945 NULL);
2946 if (r < 0)
2947 return EX_TEMPFAIL;
2948 xstat = EX_NOTSTICKY;
2949 if (REPLYTYPE(r) == 4)
2950 status = EX_TEMPFAIL;
2951 else if (REPLYTYPE(r) == 2)
2952 status = xstat = EX_OK;
2953 else if (REPLYCLASS(r) != 5)
2954 status = xstat = EX_PROTOCOL;
2955 else if (REPLYTYPE(r) == 5)
2956 status = EX_UNAVAILABLE;
2957 else
2958 status = EX_PROTOCOL;
2959 if (bitset(MCIF_ENHSTAT, mci->mci_flags) &&
2960 (off = isenhsc(SmtpReplyBuffer + 4, ' ')) > 0)
2961 off += 5;
2962 else
2963 off = 4;
2964 e->e_statmsg = sm_rpool_strdup_x(e->e_rpool, &SmtpReplyBuffer[off]);
2965 mci_setstat(mci, xstat, ENHSCN(enhsc, smtptodsn(r)), SmtpReplyBuffer);
2966 if (LogLevel > 1 && status == EX_PROTOCOL)
2967 {
2968 sm_syslog(LOG_CRIT, e->e_id,
2969 "%.100s: SMTP DATA-3 protocol error: %s",
2970 CurHostName,
2971 shortenstring(SmtpReplyBuffer, 403));
2972 }
2973 return status;
2974 }
2975 /*
2976 ** SMTPQUIT -- close the SMTP connection.
2977 **
2978 ** Parameters:
2979 ** m -- a pointer to the mailer.
2980 ** mci -- the mailer connection information.
2981 ** e -- the current envelope.
2982 **
2983 ** Returns:
2984 ** none.
2985 **
2986 ** Side Effects:
2987 ** sends the final protocol and closes the connection.
2988 */
2989
2990 void
smtpquit(m,mci,e)2991 smtpquit(m, mci, e)
2992 register MAILER *m;
2993 register MCI *mci;
2994 ENVELOPE *e;
2995 {
2996 bool oldSuprErrs = SuprErrs;
2997 int rcode;
2998 char *oldcurhost;
2999
3000 if (mci->mci_state == MCIS_CLOSED)
3001 {
3002 mci_close(mci, "smtpquit:1");
3003 return;
3004 }
3005
3006 oldcurhost = CurHostName;
3007 CurHostName = mci->mci_host; /* XXX UGLY XXX */
3008 if (CurHostName == NULL)
3009 CurHostName = MyHostName;
3010
3011 /*
3012 ** Suppress errors here -- we may be processing a different
3013 ** job when we do the quit connection, and we don't want the
3014 ** new job to be penalized for something that isn't it's
3015 ** problem.
3016 */
3017
3018 SuprErrs = true;
3019
3020 /* send the quit message if we haven't gotten I/O error */
3021 if (mci->mci_state != MCIS_ERROR &&
3022 mci->mci_state != MCIS_QUITING)
3023 {
3024 SmtpPhase = "client QUIT";
3025 mci->mci_state = MCIS_QUITING;
3026 smtpmessage("QUIT", m, mci);
3027 (void) reply(m, mci, e, TimeOuts.to_quit, NULL, NULL, XS_QUIT,
3028 NULL);
3029 SuprErrs = oldSuprErrs;
3030 if (mci->mci_state == MCIS_CLOSED)
3031 goto end;
3032 }
3033
3034 /* now actually close the connection and pick up the zombie */
3035 rcode = endmailer(mci, e, NULL);
3036 if (rcode != EX_OK)
3037 {
3038 char *mailer = NULL;
3039
3040 if (mci->mci_mailer != NULL &&
3041 mci->mci_mailer->m_name != NULL)
3042 mailer = mci->mci_mailer->m_name;
3043
3044 /* look for naughty mailers */
3045 sm_syslog(LOG_ERR, e->e_id,
3046 "smtpquit: mailer%s%s exited with exit value %d",
3047 mailer == NULL ? "" : " ",
3048 mailer == NULL ? "" : mailer,
3049 rcode);
3050 }
3051
3052 SuprErrs = oldSuprErrs;
3053
3054 end:
3055 CurHostName = oldcurhost;
3056 return;
3057 }
3058 /*
3059 ** SMTPRSET -- send a RSET (reset) command
3060 **
3061 ** Parameters:
3062 ** m -- a pointer to the mailer.
3063 ** mci -- the mailer connection information.
3064 ** e -- the current envelope.
3065 **
3066 ** Returns:
3067 ** none.
3068 **
3069 ** Side Effects:
3070 ** closes the connection if there is no reply to RSET.
3071 */
3072
3073 void
smtprset(m,mci,e)3074 smtprset(m, mci, e)
3075 register MAILER *m;
3076 register MCI *mci;
3077 ENVELOPE *e;
3078 {
3079 int r;
3080
3081 CurHostName = mci->mci_host; /* XXX UGLY XXX */
3082 if (CurHostName == NULL)
3083 CurHostName = MyHostName;
3084
3085 /*
3086 ** Check if connection is gone, if so
3087 ** it's a tempfail and we use mci_errno
3088 ** for the reason.
3089 */
3090
3091 if (mci->mci_state == MCIS_CLOSED)
3092 {
3093 errno = mci->mci_errno;
3094 return;
3095 }
3096
3097 SmtpPhase = "client RSET";
3098 smtpmessage("RSET", m, mci);
3099 r = reply(m, mci, e, TimeOuts.to_rset, NULL, NULL, XS_DEFAULT, NULL);
3100 if (r < 0)
3101 return;
3102
3103 /*
3104 ** Any response is deemed to be acceptable.
3105 ** The standard does not state the proper action
3106 ** to take when a value other than 250 is received.
3107 **
3108 ** However, if 421 is returned for the RSET, leave
3109 ** mci_state alone (MCIS_SSD can be set in reply()
3110 ** and MCIS_CLOSED can be set in smtpquit() if
3111 ** reply() gets a 421 and calls smtpquit()).
3112 */
3113
3114 if (mci->mci_state != MCIS_SSD && mci->mci_state != MCIS_CLOSED)
3115 mci->mci_state = MCIS_OPEN;
3116 else if (mci->mci_exitstat == EX_OK)
3117 mci_setstat(mci, EX_TEMPFAIL, "4.5.0", NULL);
3118 }
3119 /*
3120 ** SMTPPROBE -- check the connection state
3121 **
3122 ** Parameters:
3123 ** mci -- the mailer connection information.
3124 **
3125 ** Returns:
3126 ** none.
3127 **
3128 ** Side Effects:
3129 ** closes the connection if there is no reply to RSET.
3130 */
3131
3132 int
smtpprobe(mci)3133 smtpprobe(mci)
3134 register MCI *mci;
3135 {
3136 int r;
3137 MAILER *m = mci->mci_mailer;
3138 ENVELOPE *e;
3139 extern ENVELOPE BlankEnvelope;
3140
3141 CurHostName = mci->mci_host; /* XXX UGLY XXX */
3142 if (CurHostName == NULL)
3143 CurHostName = MyHostName;
3144
3145 e = &BlankEnvelope;
3146 SmtpPhase = "client probe";
3147 smtpmessage("RSET", m, mci);
3148 r = reply(m, mci, e, TimeOuts.to_miscshort, NULL, NULL, XS_DEFAULT,
3149 NULL);
3150 if (REPLYTYPE(r) != 2)
3151 smtpquit(m, mci, e);
3152 return r;
3153 }
3154 /*
3155 ** REPLY -- read arpanet reply
3156 **
3157 ** Parameters:
3158 ** m -- the mailer we are reading the reply from.
3159 ** mci -- the mailer connection info structure.
3160 ** e -- the current envelope.
3161 ** timeout -- the timeout for reads.
3162 ** pfunc -- processing function called on each line of response.
3163 ** If null, no special processing is done.
3164 ** enhstat -- optional, returns enhanced error code string (if set)
3165 ** rtype -- type of SmtpMsgBuffer: does it contains secret data?
3166 ** rtext -- pointer to where to save first line of reply (if set)
3167 **
3168 ** Returns:
3169 ** reply code it reads.
3170 ** -1 on I/O errors etc.
3171 **
3172 ** Side Effects:
3173 ** flushes the mail file.
3174 */
3175
3176 int
reply(m,mci,e,timeout,pfunc,enhstat,rtype,rtext)3177 reply(m, mci, e, timeout, pfunc, enhstat, rtype, rtext)
3178 MAILER *m;
3179 MCI *mci;
3180 ENVELOPE *e;
3181 time_t timeout;
3182 void (*pfunc) __P((char *, bool, MAILER *, MCI *, ENVELOPE *));
3183 char **enhstat;
3184 int rtype;
3185 char **rtext;
3186 {
3187 register char *bufp;
3188 register int r;
3189 bool firstline = true;
3190 char junkbuf[MAXLINE];
3191 static char enhstatcode[ENHSCLEN];
3192 int save_errno;
3193
3194 /*
3195 ** Flush the output before reading response.
3196 **
3197 ** For SMTP pipelining, it would be better if we didn't do
3198 ** this if there was already data waiting to be read. But
3199 ** to do it properly means pushing it to the I/O library,
3200 ** since it really needs to be done below the buffer layer.
3201 */
3202
3203 if (mci->mci_out != NULL)
3204 (void) sm_io_flush(mci->mci_out, SM_TIME_DEFAULT);
3205
3206 if (tTd(18, 1))
3207 {
3208 char *what;
3209
3210 if (SmtpMsgBuffer[0] != '\0')
3211 what = SmtpMsgBuffer;
3212 else if (SmtpPhase != NULL && SmtpPhase[0] != '\0')
3213 what = SmtpPhase;
3214 else if (XS_GREET == rtype)
3215 what = "greeting";
3216 else
3217 what = "unknown";
3218 #if PIPELINING
3219 if (mci->mci_flags & MCIF_PIPELINED)
3220 sm_dprintf("reply to %s:%d [but PIPELINED]\n", what, rtype);
3221 else
3222 #endif
3223 /* "else" in #if code above */
3224 sm_dprintf("reply to %s:%d\n", what, rtype);
3225 }
3226
3227 /*
3228 ** Read the input line, being careful not to hang.
3229 */
3230
3231 bufp = SmtpReplyBuffer;
3232 (void) set_tls_rd_tmo(timeout);
3233 for (;;)
3234 {
3235 register char *p;
3236
3237 /* actually do the read */
3238 if (e->e_xfp != NULL) /* for debugging */
3239 (void) sm_io_flush(e->e_xfp, SM_TIME_DEFAULT);
3240
3241 /* if we are in the process of closing just give the code */
3242 if (mci->mci_state == MCIS_CLOSED)
3243 return SMTPCLOSING;
3244
3245 /* don't try to read from a non-existent fd */
3246 if (mci->mci_in == NULL)
3247 {
3248 if (mci->mci_errno == 0)
3249 mci->mci_errno = EBADF;
3250
3251 /* errors on QUIT should be ignored */
3252 if (strncmp(SmtpMsgBuffer, "QUIT", 4) == 0)
3253 {
3254 errno = mci->mci_errno;
3255 mci_close(mci, "reply:1");
3256 return -1;
3257 }
3258 mci->mci_state = MCIS_ERROR;
3259 smtpquit(m, mci, e);
3260 errno = mci->mci_errno;
3261 return -1;
3262 }
3263
3264 if (mci->mci_out != NULL)
3265 (void) sm_io_flush(mci->mci_out, SM_TIME_DEFAULT);
3266
3267 /* get the line from the other side */
3268 p = sfgets(bufp, MAXLINE, mci->mci_in, timeout, SmtpPhase);
3269 save_errno = errno;
3270 mci->mci_lastuse = curtime();
3271
3272 if (p == NULL)
3273 {
3274 bool oldholderrs;
3275 extern char MsgBuf[];
3276
3277 /* errors on QUIT should be ignored */
3278 if (strncmp(SmtpMsgBuffer, "QUIT", 4) == 0)
3279 {
3280 mci_close(mci, "reply:2");
3281 return -1;
3282 }
3283
3284 /* if the remote end closed early, fake an error */
3285 errno = save_errno;
3286 if (errno == 0)
3287 {
3288 (void) sm_snprintf(SmtpReplyBuffer,
3289 sizeof(SmtpReplyBuffer),
3290 "421 4.4.1 Connection reset by %s",
3291 CURHOSTNAME);
3292 #ifdef ECONNRESET
3293 errno = ECONNRESET;
3294 #else
3295 errno = EPIPE;
3296 #endif
3297 }
3298
3299 mci->mci_errno = errno;
3300 oldholderrs = HoldErrs;
3301 HoldErrs = true;
3302 usrerr("451 4.4.2 reply: read error from %s",
3303 CURHOSTNAME);
3304 mci_setstat(mci, EX_TEMPFAIL, "4.4.2", MsgBuf);
3305
3306 /* if debugging, pause so we can see state */
3307 if (tTd(18, 100))
3308 (void) pause();
3309 mci->mci_state = MCIS_ERROR;
3310 smtpquit(m, mci, e);
3311 #if XDEBUG
3312 {
3313 char wbuf[MAXLINE];
3314
3315 p = wbuf;
3316 if (e->e_to != NULL)
3317 {
3318 (void) sm_snprintf(p,
3319 SPACELEFT(wbuf, p),
3320 "%s... ",
3321 shortenstring(e->e_to, MAXSHORTSTR));
3322 p += strlen(p);
3323 }
3324 (void) sm_snprintf(p, SPACELEFT(wbuf, p),
3325 "reply(%.100s) during %s",
3326 CURHOSTNAME, SmtpPhase);
3327 checkfd012(wbuf);
3328 }
3329 #endif /* XDEBUG */
3330 HoldErrs = oldholderrs;
3331 errno = save_errno;
3332 return -1;
3333 }
3334 fixcrlf(bufp, true);
3335 if (tTd(18, 4))
3336 sm_dprintf("received=%s\n", bufp);
3337
3338 /* EHLO failure is not a real error */
3339 if (e->e_xfp != NULL && (bufp[0] == '4' ||
3340 (bufp[0] == '5' && strncmp(SmtpMsgBuffer, "EHLO", 4) != 0)))
3341 {
3342 /* serious error -- log the previous command */
3343 if (SmtpNeedIntro)
3344 {
3345 /* inform user who we are chatting with */
3346 (void) sm_io_fprintf(CurEnv->e_xfp,
3347 SM_TIME_DEFAULT,
3348 "... while talking to %s:\n",
3349 CURHOSTNAME);
3350 SmtpNeedIntro = false;
3351 }
3352 if (SmtpMsgBuffer[0] != '\0')
3353 {
3354 (void) sm_io_fprintf(e->e_xfp,
3355 SM_TIME_DEFAULT,
3356 ">>> %s\n",
3357 (rtype == XS_STARTTLS)
3358 ? "STARTTLS dialogue"
3359 : ((rtype == XS_AUTH)
3360 ? "AUTH dialogue"
3361 : SmtpMsgBuffer));
3362 SmtpMsgBuffer[0] = '\0';
3363 }
3364
3365 /* now log the message as from the other side */
3366 (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
3367 "<<< %s\n", bufp);
3368 }
3369
3370 /* display the input for verbose mode */
3371 if (Verbose)
3372 nmessage("050 %s", bufp);
3373
3374 /* ignore improperly formatted input */
3375 if (!ISSMTPREPLY(bufp))
3376 continue;
3377
3378 if (NULL != rtext && firstline)
3379 *rtext = sm_rpool_strdup_x(e->e_rpool, SmtpReplyBuffer);
3380
3381 if (bitset(MCIF_ENHSTAT, mci->mci_flags) &&
3382 enhstat != NULL &&
3383 extenhsc(bufp + 4, ' ', enhstatcode) > 0)
3384 *enhstat = enhstatcode;
3385
3386 /* process the line */
3387 if (pfunc != NULL)
3388 (*pfunc)(bufp, firstline, m, mci, e);
3389
3390 /* decode the reply code */
3391 r = atoi(bufp);
3392
3393 /* extra semantics: 0xx codes are "informational" */
3394 if (r < 100)
3395 {
3396 firstline = false;
3397 continue;
3398 }
3399 if (REPLYTYPE(r) > 3 && firstline
3400 #if _FFR_PROXY
3401 &&
3402 (e->e_sendmode != SM_PROXY
3403 || (e->e_sendmode == SM_PROXY
3404 && (e->e_rcode == 0 || REPLYTYPE(e->e_rcode) < 5))
3405 )
3406 #endif
3407 )
3408 {
3409 int o = -1;
3410 /*
3411 ** ignore error iff: DATA, 5xy error, but we had
3412 ** "retryable" recipients. XREF: smtpdata()
3413 */
3414
3415 if (!(rtype == XS_DATA && REPLYTYPE(r) == 5 &&
3416 mci->mci_okrcpts <= 0 && mci->mci_retryrcpt))
3417 {
3418 o = extenhsc(bufp + 4, ' ', enhstatcode);
3419 if (o > 0)
3420 {
3421 sm_strlcpy(e->e_renhsc, enhstatcode,
3422 sizeof(e->e_renhsc));
3423
3424 /* skip SMTP reply code, delimiters */
3425 o += 5;
3426 }
3427 else
3428 o = 4;
3429
3430 /*
3431 ** Don't use this for reply= logging
3432 ** if it was for QUIT.
3433 ** (Note: use the debug option to
3434 ** reproduce the original error.)
3435 */
3436
3437 if (rtype != XS_QUIT || tTd(87, 101))
3438 {
3439 e->e_rcode = r;
3440 e->e_text = sm_rpool_strdup_x(
3441 e->e_rpool, bufp + o);
3442 #if _FFR_LOG_STAGE
3443 e->e_estate = rtype;
3444 #endif
3445 }
3446 }
3447 if (tTd(87, 2))
3448 {
3449 sm_dprintf("user: e=%p, offset=%d, bufp=%s, rcode=%d, enhstat=%s, rtype=%d, text=%s\n"
3450 , (void *)e, o, bufp, r, e->e_renhsc
3451 , rtype, e->e_text);
3452 }
3453 }
3454 #if _FFR_REPLY_MULTILINE
3455 # if _FFR_REPLY_MULTILINE > 200
3456 # define MLLIMIT _FFR_REPLY_MULTILINE
3457 # else
3458 # define MLLIMIT 1024
3459 # endif
3460 if ((REPLYTYPE(r) > 3 && !firstline && e->e_text != NULL &&
3461 rtype != XS_QUIT) || tTd(87, 101))
3462 {
3463 int len;
3464 char *new;
3465
3466 /* skip the same stuff or use o? */
3467 /* but o is a local variable in the block above */
3468 len = strlen(e->e_text) + strlen(bufp) + 3;
3469 if (len < MLLIMIT &&
3470 (new = (char *) sm_rpool_malloc(e->e_rpool, len))
3471 != NULL)
3472 {
3473 sm_strlcpyn(new, len, 3, e->e_text, "; ",
3474 bufp /* + o */);
3475 e->e_text = new;
3476 }
3477 }
3478 #endif /* _FFR_REPLY_MULTILINE */
3479
3480 firstline = false;
3481
3482 /* if no continuation lines, return this line */
3483 if (bufp[3] != '-')
3484 break;
3485
3486 /* first line of real reply -- ignore rest */
3487 bufp = junkbuf;
3488 }
3489
3490 /*
3491 ** Now look at SmtpReplyBuffer -- only care about the first
3492 ** line of the response from here on out.
3493 */
3494
3495 /* save temporary failure messages for posterity */
3496 if (SmtpReplyBuffer[0] == '4')
3497 (void) sm_strlcpy(SmtpError, SmtpReplyBuffer, sizeof(SmtpError));
3498
3499 /* reply code 421 is "Service Shutting Down" */
3500 if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD &&
3501 mci->mci_state != MCIS_QUITING)
3502 {
3503 /* send the quit protocol */
3504 mci->mci_state = MCIS_SSD;
3505 smtpquit(m, mci, e);
3506 }
3507
3508 return r;
3509 }
3510 /*
3511 ** SMTPMESSAGE -- send message to server
3512 **
3513 ** Parameters:
3514 ** f -- format
3515 ** m -- the mailer to control formatting.
3516 ** a, b, c -- parameters
3517 **
3518 ** Returns:
3519 ** none.
3520 **
3521 ** Side Effects:
3522 ** writes message to mci->mci_out.
3523 */
3524
3525 /*VARARGS1*/
3526 void
3527 #ifdef __STDC__
smtpmessage(char * f,MAILER * m,MCI * mci,...)3528 smtpmessage(char *f, MAILER *m, MCI *mci, ...)
3529 #else /* __STDC__ */
3530 smtpmessage(f, m, mci, va_alist)
3531 char *f;
3532 MAILER *m;
3533 MCI *mci;
3534 va_dcl
3535 #endif /* __STDC__ */
3536 {
3537 SM_VA_LOCAL_DECL
3538
3539 SM_VA_START(ap, mci);
3540 (void) sm_vsnprintf(SmtpMsgBuffer, sizeof(SmtpMsgBuffer), f, ap);
3541 SM_VA_END(ap);
3542
3543 if (tTd(18, 1) || Verbose)
3544 nmessage(">>> %s", SmtpMsgBuffer);
3545 if (TrafficLogFile != NULL)
3546 (void) sm_io_fprintf(TrafficLogFile, SM_TIME_DEFAULT,
3547 "%05d >>> %s\n", (int) CurrentPid,
3548 SmtpMsgBuffer);
3549 if (mci->mci_out != NULL)
3550 {
3551 (void) sm_io_fprintf(mci->mci_out, SM_TIME_DEFAULT, "%s%s",
3552 SmtpMsgBuffer, m == NULL ? "\r\n"
3553 : m->m_eol);
3554 }
3555 else if (tTd(18, 1))
3556 sm_dprintf("smtpmessage: NULL mci_out\n");
3557 }
3558