]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - contrib/sendmail/src/usersmtp.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / contrib / sendmail / src / usersmtp.c
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
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
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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 *
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
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
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
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
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
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
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
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
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
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
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
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__
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 }