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