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