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