1c2aa98e2SPeter Wemm /*
2*d39bd2c1SGregory Neil Shapiro * Copyright (c) 1998-2010, 2012-2014,2021-2024 Proofpoint, Inc. and its suppliers.
306f25ae9SGregory Neil Shapiro * All rights reserved.
4c2aa98e2SPeter Wemm * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved.
5c2aa98e2SPeter Wemm * Copyright (c) 1988, 1993
6c2aa98e2SPeter Wemm * The Regents of the University of California. All rights reserved.
7c2aa98e2SPeter Wemm *
8c2aa98e2SPeter Wemm * By using this file, you agree to the terms and conditions set
9c2aa98e2SPeter Wemm * forth in the LICENSE file which can be found at the top level of
10c2aa98e2SPeter Wemm * the sendmail distribution.
11c2aa98e2SPeter Wemm *
12c2aa98e2SPeter Wemm */
13c2aa98e2SPeter Wemm
1406f25ae9SGregory Neil Shapiro #include <sendmail.h>
1540266059SGregory Neil Shapiro #if MILTER
16e92d3f3fSGregory Neil Shapiro # include <libmilter/mfapi.h>
1740266059SGregory Neil Shapiro # include <libmilter/mfdef.h>
185b0945b5SGregory Neil Shapiro #endif
19c2aa98e2SPeter Wemm
204313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: srvrsmtp.c,v 8.1016 2013-11-22 20:51:56 ca Exp $")
21e92d3f3fSGregory Neil Shapiro
222fb4f839SGregory Neil Shapiro #include <sm/sendmail.h>
232fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR
242fb4f839SGregory Neil Shapiro # include <sm/ixlen.h>
252fb4f839SGregory Neil Shapiro #endif
264e4196cbSGregory Neil Shapiro #include <sm/time.h>
27e92d3f3fSGregory Neil Shapiro #include <sm/fdset.h>
28c2aa98e2SPeter Wemm
2942e5d165SGregory Neil Shapiro #if SASL || STARTTLS
305b0945b5SGregory Neil Shapiro # include <tls.h>
3106f25ae9SGregory Neil Shapiro # include "sfsasl.h"
325b0945b5SGregory Neil Shapiro #endif
3306f25ae9SGregory Neil Shapiro #if SASL
3406f25ae9SGregory Neil Shapiro # define ENC64LEN(l) (((l) + 2) * 4 / 3 + 1)
3506f25ae9SGregory Neil Shapiro static int saslmechs __P((sasl_conn_t *, char **));
365b0945b5SGregory Neil Shapiro #endif
3706f25ae9SGregory Neil Shapiro #if STARTTLS
38ba00ec3dSGregory Neil Shapiro # include <openssl/err.h>
3906f25ae9SGregory Neil Shapiro
4040266059SGregory Neil Shapiro static SSL_CTX *srv_ctx = NULL; /* TLS server context */
4140266059SGregory Neil Shapiro static SSL *srv_ssl = NULL; /* per connection context */
425b0945b5SGregory Neil Shapiro static tlsi_ctx_T tlsi_ctx; /* TLS information context */
4340266059SGregory Neil Shapiro
4440266059SGregory Neil Shapiro static bool tls_ok_srv = false;
4540266059SGregory Neil Shapiro
4640266059SGregory Neil Shapiro # define TLS_VERIFY_CLIENT() tls_set_verify(srv_ctx, srv_ssl, \
4740266059SGregory Neil Shapiro bitset(SRV_VRFY_CLT, features))
4806f25ae9SGregory Neil Shapiro #endif /* STARTTLS */
4906f25ae9SGregory Neil Shapiro
50d0cef73dSGregory Neil Shapiro #if _FFR_DM_ONE
51d0cef73dSGregory Neil Shapiro static bool NotFirstDelivery = false;
525b0945b5SGregory Neil Shapiro #endif
53d0cef73dSGregory Neil Shapiro
5440266059SGregory Neil Shapiro /* server features */
55*d39bd2c1SGregory Neil Shapiro #define SRV_NONE 0x00000000 /* none... */
56*d39bd2c1SGregory Neil Shapiro #define SRV_OFFER_TLS 0x00000001 /* offer STARTTLS */
57*d39bd2c1SGregory Neil Shapiro #define SRV_VRFY_CLT 0x00000002 /* request a cert */
58*d39bd2c1SGregory Neil Shapiro #define SRV_OFFER_AUTH 0x00000004 /* offer AUTH */
59*d39bd2c1SGregory Neil Shapiro #define SRV_OFFER_ETRN 0x00000008 /* offer ETRN */
60*d39bd2c1SGregory Neil Shapiro #define SRV_OFFER_VRFY 0x00000010 /* offer VRFY (not yet used) */
61*d39bd2c1SGregory Neil Shapiro #define SRV_OFFER_EXPN 0x00000020 /* offer EXPN */
62*d39bd2c1SGregory Neil Shapiro #define SRV_OFFER_VERB 0x00000040 /* offer VERB */
63*d39bd2c1SGregory Neil Shapiro #define SRV_OFFER_DSN 0x00000080 /* offer DSN */
6440266059SGregory Neil Shapiro #if PIPELINING
65*d39bd2c1SGregory Neil Shapiro # define SRV_OFFER_PIPE 0x00000100 /* offer PIPELINING */
6640266059SGregory Neil Shapiro # if _FFR_NO_PIPE
67*d39bd2c1SGregory Neil Shapiro # define SRV_NO_PIPE 0x00000200 /* disable PIPELINING, sleep if used */
685b0945b5SGregory Neil Shapiro # endif
6940266059SGregory Neil Shapiro #endif /* PIPELINING */
70*d39bd2c1SGregory Neil Shapiro #define SRV_REQ_AUTH 0x00000400 /* require AUTH */
71*d39bd2c1SGregory Neil Shapiro #define SRV_REQ_SEC 0x00000800 /* require security - equiv to AuthOptions=p */
72*d39bd2c1SGregory Neil Shapiro #define SRV_TMP_FAIL 0x00001000 /* ruleset caused a temporary failure */
732fb4f839SGregory Neil Shapiro #if USE_EAI
74*d39bd2c1SGregory Neil Shapiro # define SRV_OFFER_EAI 0x00002000 /* offer SMTPUTF8 */
755b0945b5SGregory Neil Shapiro #endif
76*d39bd2c1SGregory Neil Shapiro #define SRV_NO_HTTP_CMD 0x00004000 /* always reject HTTP commands */
77*d39bd2c1SGregory Neil Shapiro #define SRV_BAD_PIPELINE 0x00008000 /* reject bad pipelining (see comment below) */
78*d39bd2c1SGregory Neil Shapiro #define SRV_REQ_CRLF 0x00010000 /* require CRLF as EOL */
79*d39bd2c1SGregory Neil Shapiro #define SRV_BARE_LF_421 0x00020000 /* bare LF - drop connection */
80*d39bd2c1SGregory Neil Shapiro #define SRV_BARE_CR_421 0x00040000 /* bare CR - drop connection */
81*d39bd2c1SGregory Neil Shapiro #define SRV_BARE_LF_SP 0x00080000
82*d39bd2c1SGregory Neil Shapiro #define SRV_BARE_CR_SP 0x00100000
8340266059SGregory Neil Shapiro
84*d39bd2c1SGregory Neil Shapiro static unsigned long srvfeatures __P((ENVELOPE *, char *, unsigned long));
8540266059SGregory Neil Shapiro
86e92d3f3fSGregory Neil Shapiro #define STOP_ATTACK ((time_t) -1)
87e92d3f3fSGregory Neil Shapiro static time_t checksmtpattack __P((volatile unsigned int *, unsigned int,
88e92d3f3fSGregory Neil Shapiro bool, char *, ENVELOPE *));
8906f25ae9SGregory Neil Shapiro static void printvrfyaddr __P((ADDRESS *, bool, bool));
9006f25ae9SGregory Neil Shapiro static char *skipword __P((char *volatile, char *));
9140266059SGregory Neil Shapiro static void setup_smtpd_io __P((void));
92*d39bd2c1SGregory Neil Shapiro static struct timeval *channel_readable __P((SM_FILE_T *, int));
93a7ec597cSGregory Neil Shapiro
94a7ec597cSGregory Neil Shapiro #if SASL
955b0945b5SGregory Neil Shapiro # ifndef MAX_AUTH_USER_LEN
965b0945b5SGregory Neil Shapiro # define MAX_AUTH_USER_LEN 256
975b0945b5SGregory Neil Shapiro # endif
985b0945b5SGregory Neil Shapiro # ifndef MAX_AUTH_LOG_LEN
995b0945b5SGregory Neil Shapiro # define MAX_AUTH_LOG_LEN 64
1005b0945b5SGregory Neil Shapiro # endif
1015b0945b5SGregory Neil Shapiro static void get_sasl_user __P((char *, unsigned int, const char *, char *out, size_t));
1025b0945b5SGregory Neil Shapiro # define RESET_AUTH_FAIL_LOG_USER \
1035b0945b5SGregory Neil Shapiro do \
1045b0945b5SGregory Neil Shapiro { \
1055b0945b5SGregory Neil Shapiro (void) memset(auth_user, 0, sizeof(auth_user)); \
1065b0945b5SGregory Neil Shapiro (void) memset(auth_user_tmp, 0, sizeof(auth_user_tmp)); \
1075b0945b5SGregory Neil Shapiro auth_user_len = 0; \
1085b0945b5SGregory Neil Shapiro } while (0)
1095b0945b5SGregory Neil Shapiro # define SET_AUTH_USER_TMP(s, len) \
1105b0945b5SGregory Neil Shapiro do \
1115b0945b5SGregory Neil Shapiro { \
1125b0945b5SGregory Neil Shapiro auth_user_len = SM_MIN(len, MAX_AUTH_USER_LEN-1); \
1135b0945b5SGregory Neil Shapiro (void) memcpy(auth_user_tmp, s, auth_user_len); \
1145b0945b5SGregory Neil Shapiro } while (0)
1155b0945b5SGregory Neil Shapiro # define SET_AUTH_USER \
1165b0945b5SGregory Neil Shapiro get_sasl_user(auth_user_tmp, auth_user_len, auth_type, auth_user, sizeof(auth_user))
1175b0945b5SGregory Neil Shapiro # define SET_AUTH_USER_CONDITIONALLY \
1185b0945b5SGregory Neil Shapiro if ('\0' == auth_user[0]) \
1195b0945b5SGregory Neil Shapiro SET_AUTH_USER;
1205b0945b5SGregory Neil Shapiro # define LOG_AUTH_FAIL_USER ", user=", (int)MAX_AUTH_LOG_LEN, auth_user
121a7ec597cSGregory Neil Shapiro # if SASL >= 20000
122a7ec597cSGregory Neil Shapiro static int reset_saslconn __P((sasl_conn_t **_conn, char *_hostname,
123a7ec597cSGregory Neil Shapiro char *_remoteip, char *_localip,
124a7ec597cSGregory Neil Shapiro char *_auth_id, sasl_ssf_t *_ext_ssf));
125a7ec597cSGregory Neil Shapiro
126a7ec597cSGregory Neil Shapiro # define RESET_SASLCONN \
12713d88268SGregory Neil Shapiro do \
128a7ec597cSGregory Neil Shapiro { \
1295b0945b5SGregory Neil Shapiro RESET_AUTH_FAIL_LOG_USER; \
13013d88268SGregory Neil Shapiro result = reset_saslconn(&conn, AuthRealm, remoteip, \
13113d88268SGregory Neil Shapiro localip, auth_id, &ext_ssf); \
13213d88268SGregory Neil Shapiro if (result != SASL_OK) \
13313d88268SGregory Neil Shapiro sasl_ok = false; \
13413d88268SGregory Neil Shapiro } while (0)
135a7ec597cSGregory Neil Shapiro
136a7ec597cSGregory Neil Shapiro # else /* SASL >= 20000 */
137a7ec597cSGregory Neil Shapiro static int reset_saslconn __P((sasl_conn_t **_conn, char *_hostname,
138a7ec597cSGregory Neil Shapiro struct sockaddr_in *_saddr_r,
139a7ec597cSGregory Neil Shapiro struct sockaddr_in *_saddr_l,
140a7ec597cSGregory Neil Shapiro sasl_external_properties_t *_ext_ssf));
141a7ec597cSGregory Neil Shapiro # define RESET_SASLCONN \
14213d88268SGregory Neil Shapiro do \
143a7ec597cSGregory Neil Shapiro { \
1445b0945b5SGregory Neil Shapiro RESET_AUTH_FAIL_LOG_USER; \
14513d88268SGregory Neil Shapiro result = reset_saslconn(&conn, AuthRealm, &saddr_r, \
14613d88268SGregory Neil Shapiro &saddr_l, &ext_ssf); \
14713d88268SGregory Neil Shapiro if (result != SASL_OK) \
14813d88268SGregory Neil Shapiro sasl_ok = false; \
14913d88268SGregory Neil Shapiro } while (0)
150a7ec597cSGregory Neil Shapiro
151a7ec597cSGregory Neil Shapiro # endif /* SASL >= 20000 */
152a7ec597cSGregory Neil Shapiro #endif /* SASL */
153a7ec597cSGregory Neil Shapiro
1545b0945b5SGregory Neil Shapiro #if !defined(RESET_AUTH_FAIL_LOG_USER)
1555b0945b5SGregory Neil Shapiro # define RESET_AUTH_FAIL_LOG_USER
1565b0945b5SGregory Neil Shapiro #endif
1575b0945b5SGregory Neil Shapiro
15806f25ae9SGregory Neil Shapiro extern ENVELOPE BlankEnvelope;
159c2aa98e2SPeter Wemm
160e92d3f3fSGregory Neil Shapiro #define NBADRCPTS \
161e92d3f3fSGregory Neil Shapiro do \
162e92d3f3fSGregory Neil Shapiro { \
163e92d3f3fSGregory Neil Shapiro char buf[16]; \
164d0cef73dSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "%d", \
165e92d3f3fSGregory Neil Shapiro BadRcptThrottle > 0 && n_badrcpts > BadRcptThrottle \
166e92d3f3fSGregory Neil Shapiro ? n_badrcpts - 1 : n_badrcpts); \
167e92d3f3fSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, macid("{nbadrcpts}"), buf); \
168e92d3f3fSGregory Neil Shapiro } while (0)
169e92d3f3fSGregory Neil Shapiro
1705b0945b5SGregory Neil Shapiro #define SKIP_SPACE(s) while (SM_ISSPACE(*s)) \
17140266059SGregory Neil Shapiro (s)++
17240266059SGregory Neil Shapiro
1732fb4f839SGregory Neil Shapiro #if USE_EAI
174c2aa98e2SPeter Wemm /*
175*d39bd2c1SGregory Neil Shapiro ** ADDR_IS_ASCII -- check whether a string (address) is ASCII
1765b0945b5SGregory Neil Shapiro **
1775b0945b5SGregory Neil Shapiro ** Parameters:
178*d39bd2c1SGregory Neil Shapiro ** str -- a string
1795b0945b5SGregory Neil Shapiro **
1805b0945b5SGregory Neil Shapiro ** Returns:
181*d39bd2c1SGregory Neil Shapiro ** TRUE iff str is non-NULL and points to only ASCII
1825b0945b5SGregory Neil Shapiro */
1835b0945b5SGregory Neil Shapiro
1845b0945b5SGregory Neil Shapiro bool
addr_is_ascii(str)185*d39bd2c1SGregory Neil Shapiro addr_is_ascii(str)
186*d39bd2c1SGregory Neil Shapiro const char *str;
1875b0945b5SGregory Neil Shapiro {
188*d39bd2c1SGregory Neil Shapiro while (str != NULL && *str != '\0' && isascii((unsigned char)*str))
189*d39bd2c1SGregory Neil Shapiro str++;
190*d39bd2c1SGregory Neil Shapiro return (str != NULL && *str == '\0');
1915b0945b5SGregory Neil Shapiro }
1922fb4f839SGregory Neil Shapiro
193*d39bd2c1SGregory Neil Shapiro /*
194*d39bd2c1SGregory Neil Shapiro ** STR_IS_PRINT -- check whether a string is printable ASCII
195*d39bd2c1SGregory Neil Shapiro **
196*d39bd2c1SGregory Neil Shapiro ** Parameters:
197*d39bd2c1SGregory Neil Shapiro ** str -- a string
198*d39bd2c1SGregory Neil Shapiro **
199*d39bd2c1SGregory Neil Shapiro ** Returns:
200*d39bd2c1SGregory Neil Shapiro ** TRUE iff str is non-NULL and points to only printable ASCII
201*d39bd2c1SGregory Neil Shapiro */
202*d39bd2c1SGregory Neil Shapiro
203*d39bd2c1SGregory Neil Shapiro bool
str_is_print(str)204*d39bd2c1SGregory Neil Shapiro str_is_print(str)
205*d39bd2c1SGregory Neil Shapiro const char *str;
206*d39bd2c1SGregory Neil Shapiro {
207*d39bd2c1SGregory Neil Shapiro while (str != NULL && *str != '\0' && *str >= ' ' && (unsigned char)*str < 127)
208*d39bd2c1SGregory Neil Shapiro str++;
209*d39bd2c1SGregory Neil Shapiro return (str != NULL && *str == '\0');
210*d39bd2c1SGregory Neil Shapiro }
211*d39bd2c1SGregory Neil Shapiro
212*d39bd2c1SGregory Neil Shapiro
2132fb4f839SGregory Neil Shapiro # define CHECK_UTF8_ADDR(a, q) \
2142fb4f839SGregory Neil Shapiro do \
2152fb4f839SGregory Neil Shapiro { \
2162fb4f839SGregory Neil Shapiro q = NULL; \
2172fb4f839SGregory Neil Shapiro if (addr_is_ascii(a)) \
2182fb4f839SGregory Neil Shapiro break; \
219*d39bd2c1SGregory Neil Shapiro if (!SMTP_UTF8) \
2202fb4f839SGregory Neil Shapiro break; \
2212fb4f839SGregory Neil Shapiro if (!e->e_smtputf8) \
2222fb4f839SGregory Neil Shapiro q = "553 5.6.7 Address requires SMTPUTF8"; \
2232fb4f839SGregory Neil Shapiro else \
2242fb4f839SGregory Neil Shapiro { \
2252fb4f839SGregory Neil Shapiro char str[MAXNAME]; \
2262fb4f839SGregory Neil Shapiro dequote_internal_chars(a, str, sizeof(str)); \
227*d39bd2c1SGregory Neil Shapiro if (!utf8_valid(str, strlen(str)) && SMTP_UTF8 <= 1) \
2282fb4f839SGregory Neil Shapiro q = "553 5.6.7 Address not valid UTF8"; \
2292fb4f839SGregory Neil Shapiro } \
2302fb4f839SGregory Neil Shapiro } while (0)
2312fb4f839SGregory Neil Shapiro #endif /* USE_EAI */
2325b0945b5SGregory Neil Shapiro
2335b0945b5SGregory Neil Shapiro /*
2345b0945b5SGregory Neil Shapiro ** PARSE_ESMTP_ARGS -- parse ESMTP arguments (for MAIL, RCPT)
235d0cef73dSGregory Neil Shapiro **
236d0cef73dSGregory Neil Shapiro ** Parameters:
237d0cef73dSGregory Neil Shapiro ** e -- the envelope
238d0cef73dSGregory Neil Shapiro ** addr_st -- address (RCPT only)
239d0cef73dSGregory Neil Shapiro ** p -- read buffer
240d0cef73dSGregory Neil Shapiro ** delimptr -- current position in read buffer
241d0cef73dSGregory Neil Shapiro ** which -- MAIL/RCPT
242d0cef73dSGregory Neil Shapiro ** args -- arguments (output)
243d0cef73dSGregory Neil Shapiro ** esmtp_args -- function to process a single ESMTP argument
244d0cef73dSGregory Neil Shapiro **
245d0cef73dSGregory Neil Shapiro ** Returns:
246d0cef73dSGregory Neil Shapiro ** none
247d0cef73dSGregory Neil Shapiro */
248d0cef73dSGregory Neil Shapiro
249d0cef73dSGregory Neil Shapiro void
parse_esmtp_args(e,addr_st,p,delimptr,which,args,esmtp_args)250d0cef73dSGregory Neil Shapiro parse_esmtp_args(e, addr_st, p, delimptr, which, args, esmtp_args)
251d0cef73dSGregory Neil Shapiro ENVELOPE *e;
252d0cef73dSGregory Neil Shapiro ADDRESS *addr_st;
253d0cef73dSGregory Neil Shapiro char *p;
254d0cef73dSGregory Neil Shapiro char *delimptr;
255d0cef73dSGregory Neil Shapiro char *which;
256d0cef73dSGregory Neil Shapiro char *args[];
257d0cef73dSGregory Neil Shapiro esmtp_args_F esmtp_args;
258d0cef73dSGregory Neil Shapiro {
259d0cef73dSGregory Neil Shapiro int argno;
260d0cef73dSGregory Neil Shapiro
261d0cef73dSGregory Neil Shapiro argno = 0;
262d0cef73dSGregory Neil Shapiro if (args != NULL)
263d0cef73dSGregory Neil Shapiro args[argno++] = p;
264d0cef73dSGregory Neil Shapiro p = delimptr;
265d0cef73dSGregory Neil Shapiro while (p != NULL && *p != '\0')
266d0cef73dSGregory Neil Shapiro {
267d0cef73dSGregory Neil Shapiro char *kp;
268d0cef73dSGregory Neil Shapiro char *vp = NULL;
269d0cef73dSGregory Neil Shapiro char *equal = NULL;
270d0cef73dSGregory Neil Shapiro
271d0cef73dSGregory Neil Shapiro /* locate the beginning of the keyword */
272d0cef73dSGregory Neil Shapiro SKIP_SPACE(p);
273d0cef73dSGregory Neil Shapiro if (*p == '\0')
274d0cef73dSGregory Neil Shapiro break;
275d0cef73dSGregory Neil Shapiro kp = p;
276d0cef73dSGregory Neil Shapiro
277d0cef73dSGregory Neil Shapiro /* skip to the value portion */
278d0cef73dSGregory Neil Shapiro while ((isascii(*p) && isalnum(*p)) || *p == '-')
279d0cef73dSGregory Neil Shapiro p++;
280d0cef73dSGregory Neil Shapiro if (*p == '=')
281d0cef73dSGregory Neil Shapiro {
282d0cef73dSGregory Neil Shapiro equal = p;
283d0cef73dSGregory Neil Shapiro *p++ = '\0';
284d0cef73dSGregory Neil Shapiro vp = p;
285d0cef73dSGregory Neil Shapiro
286d0cef73dSGregory Neil Shapiro /* skip to the end of the value */
287d0cef73dSGregory Neil Shapiro while (*p != '\0' && *p != ' ' &&
288d0cef73dSGregory Neil Shapiro !(isascii(*p) && iscntrl(*p)) &&
289d0cef73dSGregory Neil Shapiro *p != '=')
290d0cef73dSGregory Neil Shapiro p++;
291d0cef73dSGregory Neil Shapiro }
292d0cef73dSGregory Neil Shapiro
293d0cef73dSGregory Neil Shapiro if (*p != '\0')
294d0cef73dSGregory Neil Shapiro *p++ = '\0';
295d0cef73dSGregory Neil Shapiro
296d0cef73dSGregory Neil Shapiro if (tTd(19, 1))
297d0cef73dSGregory Neil Shapiro sm_dprintf("%s: got arg %s=\"%s\"\n", which, kp,
298d0cef73dSGregory Neil Shapiro vp == NULL ? "<null>" : vp);
299d0cef73dSGregory Neil Shapiro
300d0cef73dSGregory Neil Shapiro esmtp_args(addr_st, kp, vp, e);
301d0cef73dSGregory Neil Shapiro if (equal != NULL)
302d0cef73dSGregory Neil Shapiro *equal = '=';
303d0cef73dSGregory Neil Shapiro if (args != NULL)
304d0cef73dSGregory Neil Shapiro args[argno] = kp;
305d0cef73dSGregory Neil Shapiro argno++;
306d0cef73dSGregory Neil Shapiro if (argno >= MAXSMTPARGS - 1)
307d0cef73dSGregory Neil Shapiro usrerr("501 5.5.4 Too many parameters");
308d0cef73dSGregory Neil Shapiro if (Errors > 0)
309d0cef73dSGregory Neil Shapiro break;
310d0cef73dSGregory Neil Shapiro }
311d0cef73dSGregory Neil Shapiro if (args != NULL)
312d0cef73dSGregory Neil Shapiro args[argno] = NULL;
313d0cef73dSGregory Neil Shapiro }
314d0cef73dSGregory Neil Shapiro
315da7d7b9cSGregory Neil Shapiro #if _FFR_ADD_BCC
316da7d7b9cSGregory Neil Shapiro
317da7d7b9cSGregory Neil Shapiro /*
318da7d7b9cSGregory Neil Shapiro ** ADDRCPT -- Add a rcpt to sendq list
319da7d7b9cSGregory Neil Shapiro **
320da7d7b9cSGregory Neil Shapiro ** Parameters:
3212fb4f839SGregory Neil Shapiro ** rcpt -- rcpt [i]
322da7d7b9cSGregory Neil Shapiro ** sendq -- a pointer to the head of a queue to put
323da7d7b9cSGregory Neil Shapiro ** these people into.
324da7d7b9cSGregory Neil Shapiro ** e -- the envelope in which to add these recipients.
325da7d7b9cSGregory Neil Shapiro **
326da7d7b9cSGregory Neil Shapiro ** Returns:
327da7d7b9cSGregory Neil Shapiro ** The number of addresses added to the list.
328da7d7b9cSGregory Neil Shapiro */
329da7d7b9cSGregory Neil Shapiro
330da7d7b9cSGregory Neil Shapiro static int
addrcpt(rcpt,sendq,e)331da7d7b9cSGregory Neil Shapiro addrcpt(rcpt, sendq, e)
332da7d7b9cSGregory Neil Shapiro char *rcpt;
333da7d7b9cSGregory Neil Shapiro ADDRESS **sendq;
334da7d7b9cSGregory Neil Shapiro ENVELOPE *e;
335da7d7b9cSGregory Neil Shapiro {
336da7d7b9cSGregory Neil Shapiro int r;
337da7d7b9cSGregory Neil Shapiro char *oldto;
338da7d7b9cSGregory Neil Shapiro ADDRESS *a;
339da7d7b9cSGregory Neil Shapiro
340da7d7b9cSGregory Neil Shapiro SM_REQUIRE(rcpt != NULL);
341da7d7b9cSGregory Neil Shapiro SM_REQUIRE(sendq != NULL);
342da7d7b9cSGregory Neil Shapiro SM_REQUIRE(e != NULL);
343da7d7b9cSGregory Neil Shapiro oldto = e->e_to;
344da7d7b9cSGregory Neil Shapiro if (tTd(25, 1))
345da7d7b9cSGregory Neil Shapiro sm_dprintf("addrcpt: rcpt=%s\n", rcpt);
346da7d7b9cSGregory Neil Shapiro r = Errors;
347da7d7b9cSGregory Neil Shapiro a = NULL;
348da7d7b9cSGregory Neil Shapiro SM_TRY
349da7d7b9cSGregory Neil Shapiro {
350da7d7b9cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e b");
3512fb4f839SGregory Neil Shapiro /* XXX rcpt must be [i] */
352da7d7b9cSGregory Neil Shapiro a = parseaddr(rcpt, NULLADDR, RF_COPYALL, ' ', NULL, e, true);
353da7d7b9cSGregory Neil Shapiro if (a == NULL)
354da7d7b9cSGregory Neil Shapiro return 0;
355da7d7b9cSGregory Neil Shapiro
356da7d7b9cSGregory Neil Shapiro a->q_flags &= ~Q_PINGFLAGS;
357da7d7b9cSGregory Neil Shapiro a->q_flags |= QINTBCC;
358da7d7b9cSGregory Neil Shapiro a->q_owner = "<>";
359da7d7b9cSGregory Neil Shapiro
360da7d7b9cSGregory Neil Shapiro /* disable alias expansion? */
361da7d7b9cSGregory Neil Shapiro a = recipient(a, sendq, 0, e);
362da7d7b9cSGregory Neil Shapiro }
363da7d7b9cSGregory Neil Shapiro SM_FINALLY
364da7d7b9cSGregory Neil Shapiro {
365da7d7b9cSGregory Neil Shapiro e->e_to = oldto;
366da7d7b9cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), NULL);
367da7d7b9cSGregory Neil Shapiro }
368da7d7b9cSGregory Neil Shapiro SM_END_TRY
369da7d7b9cSGregory Neil Shapiro if (tTd(25, 1))
370da7d7b9cSGregory Neil Shapiro sm_dprintf("addrcpt: rcpt=%s, flags=%#lx\n", rcpt,
371da7d7b9cSGregory Neil Shapiro a != NULL ? a->q_flags : 0);
372da7d7b9cSGregory Neil Shapiro Errors = r;
373da7d7b9cSGregory Neil Shapiro return 1;
374da7d7b9cSGregory Neil Shapiro }
375da7d7b9cSGregory Neil Shapiro
376da7d7b9cSGregory Neil Shapiro /*
377da7d7b9cSGregory Neil Shapiro ** ADDBCC -- Maybe create a copy of an e-mail
378da7d7b9cSGregory Neil Shapiro **
379da7d7b9cSGregory Neil Shapiro ** Parameters:
380da7d7b9cSGregory Neil Shapiro ** a -- current RCPT
381da7d7b9cSGregory Neil Shapiro ** e -- the envelope.
382da7d7b9cSGregory Neil Shapiro **
383da7d7b9cSGregory Neil Shapiro ** Returns:
384da7d7b9cSGregory Neil Shapiro ** nothing
385da7d7b9cSGregory Neil Shapiro **
386da7d7b9cSGregory Neil Shapiro ** Side Effects:
387da7d7b9cSGregory Neil Shapiro ** rscheck() can trigger an "exception"
388da7d7b9cSGregory Neil Shapiro */
389da7d7b9cSGregory Neil Shapiro
390da7d7b9cSGregory Neil Shapiro static void
addbcc(a,e)391da7d7b9cSGregory Neil Shapiro addbcc(a, e)
392da7d7b9cSGregory Neil Shapiro ADDRESS *a;
393da7d7b9cSGregory Neil Shapiro ENVELOPE *e;
394da7d7b9cSGregory Neil Shapiro {
395da7d7b9cSGregory Neil Shapiro int nobcc;
396da7d7b9cSGregory Neil Shapiro char *newrcpt, empty[1];
397da7d7b9cSGregory Neil Shapiro
398da7d7b9cSGregory Neil Shapiro if (!AddBcc)
399da7d7b9cSGregory Neil Shapiro return;
400da7d7b9cSGregory Neil Shapiro
401da7d7b9cSGregory Neil Shapiro nobcc = false;
402da7d7b9cSGregory Neil Shapiro empty[0] = '\0';
403da7d7b9cSGregory Neil Shapiro newrcpt = empty;
404da7d7b9cSGregory Neil Shapiro
405da7d7b9cSGregory Neil Shapiro nobcc = rscheck("bcc", a->q_paddr, NULL, e, RSF_ADDR, 12, NULL, NOQID,
406da7d7b9cSGregory Neil Shapiro NULL, &newrcpt);
407da7d7b9cSGregory Neil Shapiro if (tTd(25, 1))
408da7d7b9cSGregory Neil Shapiro sm_dprintf("addbcc: nobcc=%d, Errors=%d, newrcpt=<%s>\n", nobcc, Errors, newrcpt);
409da7d7b9cSGregory Neil Shapiro if (nobcc != EX_OK || Errors > 0 || *newrcpt == '\0')
410da7d7b9cSGregory Neil Shapiro return;
411da7d7b9cSGregory Neil Shapiro
412da7d7b9cSGregory Neil Shapiro (void) addrcpt(newrcpt, &e->e_sendqueue, e);
413da7d7b9cSGregory Neil Shapiro return;
414da7d7b9cSGregory Neil Shapiro }
415da7d7b9cSGregory Neil Shapiro #else /* _FFR_ADD_BCC */
416da7d7b9cSGregory Neil Shapiro # define addbcc(a, e)
417da7d7b9cSGregory Neil Shapiro #endif /* _FFR_ADD_BCC */
418da7d7b9cSGregory Neil Shapiro
419da7d7b9cSGregory Neil Shapiro #if _FFR_RCPTFLAGS
420da7d7b9cSGregory Neil Shapiro /*
421da7d7b9cSGregory Neil Shapiro ** RCPTMODS -- Perform rcpt modifications if requested
422da7d7b9cSGregory Neil Shapiro **
423da7d7b9cSGregory Neil Shapiro ** Parameters:
424da7d7b9cSGregory Neil Shapiro ** rcpt -- current RCPT
425da7d7b9cSGregory Neil Shapiro ** e -- the envelope.
426da7d7b9cSGregory Neil Shapiro **
427da7d7b9cSGregory Neil Shapiro ** Returns:
428da7d7b9cSGregory Neil Shapiro ** nothing.
429da7d7b9cSGregory Neil Shapiro */
430da7d7b9cSGregory Neil Shapiro
431da7d7b9cSGregory Neil Shapiro void
rcptmods(rcpt,e)432da7d7b9cSGregory Neil Shapiro rcptmods(rcpt, e)
433da7d7b9cSGregory Neil Shapiro ADDRESS *rcpt;
434da7d7b9cSGregory Neil Shapiro ENVELOPE *e;
435da7d7b9cSGregory Neil Shapiro {
436da7d7b9cSGregory Neil Shapiro char *fl;
437da7d7b9cSGregory Neil Shapiro
438da7d7b9cSGregory Neil Shapiro SM_REQUIRE(rcpt != NULL);
439da7d7b9cSGregory Neil Shapiro SM_REQUIRE(e != NULL);
440da7d7b9cSGregory Neil Shapiro
441da7d7b9cSGregory Neil Shapiro fl = macvalue(macid("{rcpt_flags}"), e);
4422fb4f839SGregory Neil Shapiro if (SM_IS_EMPTY(fl))
443da7d7b9cSGregory Neil Shapiro return;
444da7d7b9cSGregory Neil Shapiro if (tTd(25, 1))
445da7d7b9cSGregory Neil Shapiro sm_dprintf("rcptmods: rcpt=%s, flags=%s\n", rcpt->q_paddr, fl);
446da7d7b9cSGregory Neil Shapiro
447da7d7b9cSGregory Neil Shapiro /* parse flags */
448da7d7b9cSGregory Neil Shapiro for ( ; *fl != '\0'; ++fl)
449da7d7b9cSGregory Neil Shapiro {
450da7d7b9cSGregory Neil Shapiro switch (*fl)
451da7d7b9cSGregory Neil Shapiro {
452da7d7b9cSGregory Neil Shapiro case 'n':
453da7d7b9cSGregory Neil Shapiro rcpt->q_flags &= ~Q_PINGFLAGS;
454da7d7b9cSGregory Neil Shapiro rcpt->q_flags |= QINTBCC;
455da7d7b9cSGregory Neil Shapiro rcpt->q_owner = "<>";
456da7d7b9cSGregory Neil Shapiro break;
457da7d7b9cSGregory Neil Shapiro
458da7d7b9cSGregory Neil Shapiro case 'N':
459da7d7b9cSGregory Neil Shapiro rcpt->q_flags &= ~Q_PINGFLAGS;
460da7d7b9cSGregory Neil Shapiro rcpt->q_owner = "<>";
461da7d7b9cSGregory Neil Shapiro break;
462da7d7b9cSGregory Neil Shapiro
463da7d7b9cSGregory Neil Shapiro case QDYNMAILFLG:
464da7d7b9cSGregory Neil Shapiro rcpt->q_flags |= QDYNMAILER;
465da7d7b9cSGregory Neil Shapiro newmodmailer(rcpt, *fl);
466da7d7b9cSGregory Neil Shapiro break;
467da7d7b9cSGregory Neil Shapiro
468da7d7b9cSGregory Neil Shapiro default:
469da7d7b9cSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
470da7d7b9cSGregory Neil Shapiro "rcpt=%s, rcpt_flags=%s, status=unknown",
471da7d7b9cSGregory Neil Shapiro rcpt->q_paddr, fl);
472da7d7b9cSGregory Neil Shapiro break;
473da7d7b9cSGregory Neil Shapiro }
474da7d7b9cSGregory Neil Shapiro }
475da7d7b9cSGregory Neil Shapiro
476da7d7b9cSGregory Neil Shapiro /* reset macro to avoid confusion later on */
477da7d7b9cSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{rcpt_flags}"), NULL);
478da7d7b9cSGregory Neil Shapiro
479da7d7b9cSGregory Neil Shapiro }
480da7d7b9cSGregory Neil Shapiro #else /* _FFR_RCPTFLAGS */
481da7d7b9cSGregory Neil Shapiro # define rcptmods(a, e)
482da7d7b9cSGregory Neil Shapiro #endif /* _FFR_RCPTFLAGS */
483da7d7b9cSGregory Neil Shapiro
484*d39bd2c1SGregory Neil Shapiro #if _FFR_8BITENVADDR
485*d39bd2c1SGregory Neil Shapiro
486*d39bd2c1SGregory Neil Shapiro /*
487*d39bd2c1SGregory Neil Shapiro ** SEP_ARGS -- separate address and argument string for MAIL/RCPT command
488*d39bd2c1SGregory Neil Shapiro **
489*d39bd2c1SGregory Neil Shapiro ** Parameters:
490*d39bd2c1SGregory Neil Shapiro ** args -- arguments (converted to and from internal format)
491*d39bd2c1SGregory Neil Shapiro ** orig -- string after command (original data)
492*d39bd2c1SGregory Neil Shapiro ** id -- envelope id (for logging only)
493*d39bd2c1SGregory Neil Shapiro ** addr -- for logging only: address (original data)
494*d39bd2c1SGregory Neil Shapiro **
495*d39bd2c1SGregory Neil Shapiro ** Returns:
496*d39bd2c1SGregory Neil Shapiro ** nothing
497*d39bd2c1SGregory Neil Shapiro */
498*d39bd2c1SGregory Neil Shapiro
499*d39bd2c1SGregory Neil Shapiro static void sep_args __P((char *, char *, const char *, const char *));
500*d39bd2c1SGregory Neil Shapiro
501*d39bd2c1SGregory Neil Shapiro static void
sep_args(args,orig,id,addr)502*d39bd2c1SGregory Neil Shapiro sep_args(args, orig, id, addr)
503*d39bd2c1SGregory Neil Shapiro char *args;
504*d39bd2c1SGregory Neil Shapiro char *orig;
505*d39bd2c1SGregory Neil Shapiro const char *id;
506*d39bd2c1SGregory Neil Shapiro const char *addr;
507*d39bd2c1SGregory Neil Shapiro {
508*d39bd2c1SGregory Neil Shapiro int lr, lo;
509*d39bd2c1SGregory Neil Shapiro char *q;
510*d39bd2c1SGregory Neil Shapiro
511*d39bd2c1SGregory Neil Shapiro lr = strlen(args);
512*d39bd2c1SGregory Neil Shapiro lo = strlen(orig);
513*d39bd2c1SGregory Neil Shapiro if (lr >= lo)
514*d39bd2c1SGregory Neil Shapiro {
515*d39bd2c1SGregory Neil Shapiro sm_syslog(LOG_ERR, id,
516*d39bd2c1SGregory Neil Shapiro "ERROR=ARGS_NOT_FOUND, address='%s', rest='%s', orig='%s', strlen(rest)=%d, strlen(orig)=%d",
517*d39bd2c1SGregory Neil Shapiro addr, args, orig, lr, lo);
518*d39bd2c1SGregory Neil Shapiro return;
519*d39bd2c1SGregory Neil Shapiro }
520*d39bd2c1SGregory Neil Shapiro
521*d39bd2c1SGregory Neil Shapiro q = orig + (lo - lr);
522*d39bd2c1SGregory Neil Shapiro if (!(q > orig && *--q == ' '))
523*d39bd2c1SGregory Neil Shapiro {
524*d39bd2c1SGregory Neil Shapiro sm_syslog(LOG_INFO, id,
525*d39bd2c1SGregory Neil Shapiro "ERROR=ARGS_DO_NOT_MATCH, address='%s', rest='%s', orig='%s', q='%s', strlen(rest)=%d, strlen(orig)=%d, cmp=%d",
526*d39bd2c1SGregory Neil Shapiro addr, args, orig, q, lr, lo, strcmp(args, q));
527*d39bd2c1SGregory Neil Shapiro return;
528*d39bd2c1SGregory Neil Shapiro }
529*d39bd2c1SGregory Neil Shapiro
530*d39bd2c1SGregory Neil Shapiro for (; q > orig && *q == ' '; q--)
531*d39bd2c1SGregory Neil Shapiro *q = '\0';
532*d39bd2c1SGregory Neil Shapiro }
533*d39bd2c1SGregory Neil Shapiro #endif /* _FFR_8BITENVADDR */
534*d39bd2c1SGregory Neil Shapiro
535*d39bd2c1SGregory Neil Shapiro /*
536*d39bd2c1SGregory Neil Shapiro ** CHANNEL_READBLE -- determine if data is readable from the SMTP channel
537*d39bd2c1SGregory Neil Shapiro **
538*d39bd2c1SGregory Neil Shapiro ** Parameters:
539*d39bd2c1SGregory Neil Shapiro ** channel -- connect channel for reading
540*d39bd2c1SGregory Neil Shapiro ** timeout -- how long to pause for data in milliseconds
541*d39bd2c1SGregory Neil Shapiro **
542*d39bd2c1SGregory Neil Shapiro ** Returns:
543*d39bd2c1SGregory Neil Shapiro ** timeval contained how long we waited if data detected,
544*d39bd2c1SGregory Neil Shapiro ** NULL otherwise
545*d39bd2c1SGregory Neil Shapiro */
546*d39bd2c1SGregory Neil Shapiro
547*d39bd2c1SGregory Neil Shapiro static struct timeval *
channel_readable(channel,timeout)548*d39bd2c1SGregory Neil Shapiro channel_readable(channel, timeout)
549*d39bd2c1SGregory Neil Shapiro SM_FILE_T *channel;
550*d39bd2c1SGregory Neil Shapiro int timeout;
551*d39bd2c1SGregory Neil Shapiro {
552*d39bd2c1SGregory Neil Shapiro struct timeval bp, ep; /* {begin,end} pause */
553*d39bd2c1SGregory Neil Shapiro static struct timeval tp; /* total pause */
554*d39bd2c1SGregory Neil Shapiro int eoftest;
555*d39bd2c1SGregory Neil Shapiro
556*d39bd2c1SGregory Neil Shapiro /* check if data is on the channel during the pause */
557*d39bd2c1SGregory Neil Shapiro gettimeofday(&bp, NULL);
558*d39bd2c1SGregory Neil Shapiro if ((eoftest = sm_io_getc(channel, timeout)) != SM_IO_EOF)
559*d39bd2c1SGregory Neil Shapiro {
560*d39bd2c1SGregory Neil Shapiro gettimeofday(&ep, NULL);
561*d39bd2c1SGregory Neil Shapiro sm_io_ungetc(channel, SM_TIME_DEFAULT, eoftest);
562*d39bd2c1SGregory Neil Shapiro timersub(&ep, &bp, &tp);
563*d39bd2c1SGregory Neil Shapiro return &tp;
564*d39bd2c1SGregory Neil Shapiro }
565*d39bd2c1SGregory Neil Shapiro return NULL;
566*d39bd2c1SGregory Neil Shapiro }
567*d39bd2c1SGregory Neil Shapiro
568d0cef73dSGregory Neil Shapiro /*
569c2aa98e2SPeter Wemm ** SMTP -- run the SMTP protocol.
570c2aa98e2SPeter Wemm **
571c2aa98e2SPeter Wemm ** Parameters:
572c2aa98e2SPeter Wemm ** nullserver -- if non-NULL, rejection message for
57340266059SGregory Neil Shapiro ** (almost) all SMTP commands.
57440266059SGregory Neil Shapiro ** d_flags -- daemon flags
575c2aa98e2SPeter Wemm ** e -- the envelope.
576c2aa98e2SPeter Wemm **
577c2aa98e2SPeter Wemm ** Returns:
578c2aa98e2SPeter Wemm ** never.
579c2aa98e2SPeter Wemm **
580c2aa98e2SPeter Wemm ** Side Effects:
58140266059SGregory Neil Shapiro ** Reads commands from the input channel and processes them.
58240266059SGregory Neil Shapiro */
58340266059SGregory Neil Shapiro
58440266059SGregory Neil Shapiro /*
58540266059SGregory Neil Shapiro ** Notice: The smtp server doesn't have a session context like the client
58640266059SGregory Neil Shapiro ** side has (mci). Therefore some data (session oriented) is allocated
58740266059SGregory Neil Shapiro ** or assigned to the "wrong" structure (esp. STARTTLS, AUTH).
58840266059SGregory Neil Shapiro ** This should be fixed in a successor version.
589c2aa98e2SPeter Wemm */
590c2aa98e2SPeter Wemm
591c2aa98e2SPeter Wemm struct cmd
592c2aa98e2SPeter Wemm {
59306f25ae9SGregory Neil Shapiro char *cmd_name; /* command name */
59406f25ae9SGregory Neil Shapiro int cmd_code; /* internal code, see below */
595c2aa98e2SPeter Wemm };
596c2aa98e2SPeter Wemm
59706f25ae9SGregory Neil Shapiro /* values for cmd_code */
598c2aa98e2SPeter Wemm #define CMDERROR 0 /* bad command */
599c2aa98e2SPeter Wemm #define CMDMAIL 1 /* mail -- designate sender */
600c2aa98e2SPeter Wemm #define CMDRCPT 2 /* rcpt -- designate recipient */
601c2aa98e2SPeter Wemm #define CMDDATA 3 /* data -- send message text */
602c2aa98e2SPeter Wemm #define CMDRSET 4 /* rset -- reset state */
603c2aa98e2SPeter Wemm #define CMDVRFY 5 /* vrfy -- verify address */
604c2aa98e2SPeter Wemm #define CMDEXPN 6 /* expn -- expand address */
605c2aa98e2SPeter Wemm #define CMDNOOP 7 /* noop -- do nothing */
606c2aa98e2SPeter Wemm #define CMDQUIT 8 /* quit -- close connection and die */
607c2aa98e2SPeter Wemm #define CMDHELO 9 /* helo -- be polite */
608c2aa98e2SPeter Wemm #define CMDHELP 10 /* help -- give usage info */
609c2aa98e2SPeter Wemm #define CMDEHLO 11 /* ehlo -- extended helo (RFC 1425) */
610c2aa98e2SPeter Wemm #define CMDETRN 12 /* etrn -- flush queue */
61106f25ae9SGregory Neil Shapiro #if SASL
61206f25ae9SGregory Neil Shapiro # define CMDAUTH 13 /* auth -- SASL authenticate */
6135b0945b5SGregory Neil Shapiro #endif
61406f25ae9SGregory Neil Shapiro #if STARTTLS
61506f25ae9SGregory Neil Shapiro # define CMDSTLS 14 /* STARTTLS -- start TLS session */
6165b0945b5SGregory Neil Shapiro #endif
617c2aa98e2SPeter Wemm /* non-standard commands */
618c2aa98e2SPeter Wemm #define CMDVERB 17 /* verb -- go into verbose mode */
61906f25ae9SGregory Neil Shapiro /* unimplemented commands from RFC 821 */
62006f25ae9SGregory Neil Shapiro #define CMDUNIMPL 19 /* unimplemented rfc821 commands */
621c2aa98e2SPeter Wemm /* use this to catch and log "door handle" attempts on your system */
622c2aa98e2SPeter Wemm #define CMDLOGBOGUS 23 /* bogus command that should be logged */
623c2aa98e2SPeter Wemm /* debugging-only commands, only enabled if SMTPDEBUG is defined */
624c2aa98e2SPeter Wemm #define CMDDBGQSHOW 24 /* showq -- show send queue */
625c2aa98e2SPeter Wemm #define CMDDBGDEBUG 25 /* debug -- set debug mode */
626c2aa98e2SPeter Wemm
62742e5d165SGregory Neil Shapiro /*
62840266059SGregory Neil Shapiro ** Note: If you change this list, remember to update 'helpfile'
62942e5d165SGregory Neil Shapiro */
63042e5d165SGregory Neil Shapiro
631c2aa98e2SPeter Wemm static struct cmd CmdTab[] =
632c2aa98e2SPeter Wemm {
633c2aa98e2SPeter Wemm { "mail", CMDMAIL },
634c2aa98e2SPeter Wemm { "rcpt", CMDRCPT },
635c2aa98e2SPeter Wemm { "data", CMDDATA },
636c2aa98e2SPeter Wemm { "rset", CMDRSET },
637c2aa98e2SPeter Wemm { "vrfy", CMDVRFY },
638c2aa98e2SPeter Wemm { "expn", CMDEXPN },
639c2aa98e2SPeter Wemm { "help", CMDHELP },
640c2aa98e2SPeter Wemm { "noop", CMDNOOP },
641c2aa98e2SPeter Wemm { "quit", CMDQUIT },
642c2aa98e2SPeter Wemm { "helo", CMDHELO },
643c2aa98e2SPeter Wemm { "ehlo", CMDEHLO },
644c2aa98e2SPeter Wemm { "etrn", CMDETRN },
645c2aa98e2SPeter Wemm { "verb", CMDVERB },
64606f25ae9SGregory Neil Shapiro { "send", CMDUNIMPL },
64706f25ae9SGregory Neil Shapiro { "saml", CMDUNIMPL },
64806f25ae9SGregory Neil Shapiro { "soml", CMDUNIMPL },
64906f25ae9SGregory Neil Shapiro { "turn", CMDUNIMPL },
65006f25ae9SGregory Neil Shapiro #if SASL
65106f25ae9SGregory Neil Shapiro { "auth", CMDAUTH, },
6525b0945b5SGregory Neil Shapiro #endif
65306f25ae9SGregory Neil Shapiro #if STARTTLS
65406f25ae9SGregory Neil Shapiro { "starttls", CMDSTLS, },
6555b0945b5SGregory Neil Shapiro #endif
656c2aa98e2SPeter Wemm /* remaining commands are here only to trap and log attempts to use them */
657c2aa98e2SPeter Wemm { "showq", CMDDBGQSHOW },
658c2aa98e2SPeter Wemm { "debug", CMDDBGDEBUG },
659c2aa98e2SPeter Wemm { "wiz", CMDLOGBOGUS },
660c2aa98e2SPeter Wemm
661c2aa98e2SPeter Wemm { NULL, CMDERROR }
662c2aa98e2SPeter Wemm };
663c2aa98e2SPeter Wemm
66406f25ae9SGregory Neil Shapiro static char *CurSmtpClient; /* who's at the other end of channel */
665c2aa98e2SPeter Wemm
66640266059SGregory Neil Shapiro #ifndef MAXBADCOMMANDS
667c2aa98e2SPeter Wemm # define MAXBADCOMMANDS 25 /* maximum number of bad commands */
6685b0945b5SGregory Neil Shapiro #endif
66940266059SGregory Neil Shapiro #ifndef MAXHELOCOMMANDS
670c2aa98e2SPeter Wemm # define MAXHELOCOMMANDS 3 /* max HELO/EHLO commands before slowdown */
6715b0945b5SGregory Neil Shapiro #endif
67240266059SGregory Neil Shapiro #ifndef MAXVRFYCOMMANDS
673c2aa98e2SPeter Wemm # define MAXVRFYCOMMANDS 6 /* max VRFY/EXPN commands before slowdown */
6745b0945b5SGregory Neil Shapiro #endif
67540266059SGregory Neil Shapiro #ifndef MAXETRNCOMMANDS
676c2aa98e2SPeter Wemm # define MAXETRNCOMMANDS 8 /* max ETRN commands before slowdown */
6775b0945b5SGregory Neil Shapiro #endif
67840266059SGregory Neil Shapiro #ifndef MAXTIMEOUT
67906f25ae9SGregory Neil Shapiro # define MAXTIMEOUT (4 * 60) /* max timeout for bad commands */
6805b0945b5SGregory Neil Shapiro #endif
68106f25ae9SGregory Neil Shapiro
682e92d3f3fSGregory Neil Shapiro /*
683e92d3f3fSGregory Neil Shapiro ** Maximum shift value to compute timeout for bad commands.
684e92d3f3fSGregory Neil Shapiro ** This introduces an upper limit of 2^MAXSHIFT for the timeout.
685e92d3f3fSGregory Neil Shapiro */
686e92d3f3fSGregory Neil Shapiro
687e92d3f3fSGregory Neil Shapiro #ifndef MAXSHIFT
688e92d3f3fSGregory Neil Shapiro # define MAXSHIFT 8
6895b0945b5SGregory Neil Shapiro #endif
690e92d3f3fSGregory Neil Shapiro #if MAXSHIFT > 31
691*d39bd2c1SGregory Neil Shapiro # error "MAXSHIFT > 31 is invalid"
6925b0945b5SGregory Neil Shapiro #endif
693e92d3f3fSGregory Neil Shapiro
694e92d3f3fSGregory Neil Shapiro
695e92d3f3fSGregory Neil Shapiro #if MAXBADCOMMANDS > 0
696e92d3f3fSGregory Neil Shapiro # define STOP_IF_ATTACK(r) do \
697e92d3f3fSGregory Neil Shapiro { \
698e92d3f3fSGregory Neil Shapiro if ((r) == STOP_ATTACK) \
699e92d3f3fSGregory Neil Shapiro goto stopattack; \
700e92d3f3fSGregory Neil Shapiro } while (0)
701e92d3f3fSGregory Neil Shapiro
702e92d3f3fSGregory Neil Shapiro #else /* MAXBADCOMMANDS > 0 */
703e92d3f3fSGregory Neil Shapiro # define STOP_IF_ATTACK(r) r
704e92d3f3fSGregory Neil Shapiro #endif /* MAXBADCOMMANDS > 0 */
705e92d3f3fSGregory Neil Shapiro
706e92d3f3fSGregory Neil Shapiro
70740266059SGregory Neil Shapiro #if SM_HEAP_CHECK
70840266059SGregory Neil Shapiro static SM_DEBUG_T DebugLeakSmtp = SM_DEBUG_INITIALIZER("leak_smtp",
70940266059SGregory Neil Shapiro "@(#)$Debug: leak_smtp - trace memory leaks during SMTP processing $");
7105b0945b5SGregory Neil Shapiro #endif
71140266059SGregory Neil Shapiro
71240266059SGregory Neil Shapiro typedef struct
71340266059SGregory Neil Shapiro {
71440266059SGregory Neil Shapiro bool sm_gotmail; /* mail command received */
71540266059SGregory Neil Shapiro unsigned int sm_nrcpts; /* number of successful RCPT commands */
71640266059SGregory Neil Shapiro bool sm_discard;
71740266059SGregory Neil Shapiro #if MILTER
71840266059SGregory Neil Shapiro bool sm_milterize;
71940266059SGregory Neil Shapiro bool sm_milterlist; /* any filters in the list? */
720ffb83623SGregory Neil Shapiro milters_T sm_milters;
721ffb83623SGregory Neil Shapiro
722ffb83623SGregory Neil Shapiro /* e_nrcpts from envelope before recipient() call */
723ffb83623SGregory Neil Shapiro unsigned int sm_e_nrcpts_orig;
72440266059SGregory Neil Shapiro #endif /* MILTER */
72540266059SGregory Neil Shapiro char *sm_quarmsg; /* carry quarantining across messages */
72640266059SGregory Neil Shapiro } SMTP_T;
72740266059SGregory Neil Shapiro
728*d39bd2c1SGregory Neil Shapiro static bool smtp_data __P((SMTP_T *, ENVELOPE *, bool));
72940266059SGregory Neil Shapiro
730e92d3f3fSGregory Neil Shapiro #define MSG_TEMPFAIL "451 4.3.2 Please try again later"
73140266059SGregory Neil Shapiro
73240266059SGregory Neil Shapiro #if MILTER
73340266059SGregory Neil Shapiro # define MILTER_ABORT(e) milter_abort((e))
73413bd1963SGregory Neil Shapiro
73540266059SGregory Neil Shapiro # define MILTER_REPLY(str) \
73640266059SGregory Neil Shapiro { \
73740266059SGregory Neil Shapiro int savelogusrerrs = LogUsrErrs; \
73840266059SGregory Neil Shapiro \
739d0cef73dSGregory Neil Shapiro milter_cmd_fail = true; \
74040266059SGregory Neil Shapiro switch (state) \
74140266059SGregory Neil Shapiro { \
7424e4196cbSGregory Neil Shapiro case SMFIR_SHUTDOWN: \
7434e4196cbSGregory Neil Shapiro if (MilterLogLevel > 3) \
7444e4196cbSGregory Neil Shapiro { \
7454e4196cbSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, \
7464e4196cbSGregory Neil Shapiro "Milter: %s=%s, reject=421, errormode=4", \
7474e4196cbSGregory Neil Shapiro str, addr); \
7484e4196cbSGregory Neil Shapiro LogUsrErrs = false; \
7494e4196cbSGregory Neil Shapiro } \
7504e4196cbSGregory Neil Shapiro { \
7514e4196cbSGregory Neil Shapiro bool tsave = QuickAbort; \
7524e4196cbSGregory Neil Shapiro \
7534e4196cbSGregory Neil Shapiro QuickAbort = false; \
7544e4196cbSGregory Neil Shapiro usrerr("421 4.3.0 closing connection"); \
7554e4196cbSGregory Neil Shapiro QuickAbort = tsave; \
7564e4196cbSGregory Neil Shapiro e->e_sendqueue = NULL; \
7574e4196cbSGregory Neil Shapiro goto doquit; \
7584e4196cbSGregory Neil Shapiro } \
7594e4196cbSGregory Neil Shapiro break; \
76040266059SGregory Neil Shapiro case SMFIR_REPLYCODE: \
76140266059SGregory Neil Shapiro if (MilterLogLevel > 3) \
76240266059SGregory Neil Shapiro { \
76340266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, \
76440266059SGregory Neil Shapiro "Milter: %s=%s, reject=%s", \
76540266059SGregory Neil Shapiro str, addr, response); \
76640266059SGregory Neil Shapiro LogUsrErrs = false; \
76740266059SGregory Neil Shapiro } \
7684e4196cbSGregory Neil Shapiro if (strncmp(response, "421 ", 4) == 0 \
7694e4196cbSGregory Neil Shapiro || strncmp(response, "421-", 4) == 0) \
770e92d3f3fSGregory Neil Shapiro { \
771e92d3f3fSGregory Neil Shapiro bool tsave = QuickAbort; \
772e92d3f3fSGregory Neil Shapiro \
773e92d3f3fSGregory Neil Shapiro QuickAbort = false; \
77440266059SGregory Neil Shapiro usrerr(response); \
775e92d3f3fSGregory Neil Shapiro QuickAbort = tsave; \
776e92d3f3fSGregory Neil Shapiro e->e_sendqueue = NULL; \
777e92d3f3fSGregory Neil Shapiro goto doquit; \
778e92d3f3fSGregory Neil Shapiro } \
779e92d3f3fSGregory Neil Shapiro else \
780e92d3f3fSGregory Neil Shapiro usrerr(response); \
78140266059SGregory Neil Shapiro break; \
78240266059SGregory Neil Shapiro \
78340266059SGregory Neil Shapiro case SMFIR_REJECT: \
78440266059SGregory Neil Shapiro if (MilterLogLevel > 3) \
78540266059SGregory Neil Shapiro { \
78640266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, \
78740266059SGregory Neil Shapiro "Milter: %s=%s, reject=550 5.7.1 Command rejected", \
78840266059SGregory Neil Shapiro str, addr); \
78940266059SGregory Neil Shapiro LogUsrErrs = false; \
79040266059SGregory Neil Shapiro } \
79140266059SGregory Neil Shapiro usrerr("550 5.7.1 Command rejected"); \
79240266059SGregory Neil Shapiro break; \
79340266059SGregory Neil Shapiro \
79440266059SGregory Neil Shapiro case SMFIR_DISCARD: \
79540266059SGregory Neil Shapiro if (MilterLogLevel > 3) \
79640266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, \
79740266059SGregory Neil Shapiro "Milter: %s=%s, discard", \
79840266059SGregory Neil Shapiro str, addr); \
79940266059SGregory Neil Shapiro e->e_flags |= EF_DISCARD; \
800d0cef73dSGregory Neil Shapiro milter_cmd_fail = false; \
80140266059SGregory Neil Shapiro break; \
80240266059SGregory Neil Shapiro \
80340266059SGregory Neil Shapiro case SMFIR_TEMPFAIL: \
80440266059SGregory Neil Shapiro if (MilterLogLevel > 3) \
80540266059SGregory Neil Shapiro { \
80640266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, \
80740266059SGregory Neil Shapiro "Milter: %s=%s, reject=%s", \
80840266059SGregory Neil Shapiro str, addr, MSG_TEMPFAIL); \
80940266059SGregory Neil Shapiro LogUsrErrs = false; \
81040266059SGregory Neil Shapiro } \
81140266059SGregory Neil Shapiro usrerr(MSG_TEMPFAIL); \
81240266059SGregory Neil Shapiro break; \
813d0cef73dSGregory Neil Shapiro default: \
814d0cef73dSGregory Neil Shapiro milter_cmd_fail = false; \
815d0cef73dSGregory Neil Shapiro break; \
81640266059SGregory Neil Shapiro } \
81740266059SGregory Neil Shapiro LogUsrErrs = savelogusrerrs; \
81840266059SGregory Neil Shapiro if (response != NULL) \
81940266059SGregory Neil Shapiro sm_free(response); /* XXX */ \
82040266059SGregory Neil Shapiro }
82140266059SGregory Neil Shapiro
82240266059SGregory Neil Shapiro #else /* MILTER */
82340266059SGregory Neil Shapiro # define MILTER_ABORT(e)
82440266059SGregory Neil Shapiro #endif /* MILTER */
82540266059SGregory Neil Shapiro
82640266059SGregory Neil Shapiro /* clear all SMTP state (for HELO/EHLO/RSET) */
82740266059SGregory Neil Shapiro #define CLEAR_STATE(cmd) \
828e92d3f3fSGregory Neil Shapiro do \
82940266059SGregory Neil Shapiro { \
83040266059SGregory Neil Shapiro /* abort milter filters */ \
83140266059SGregory Neil Shapiro MILTER_ABORT(e); \
83240266059SGregory Neil Shapiro \
83340266059SGregory Neil Shapiro if (smtp.sm_nrcpts > 0) \
83440266059SGregory Neil Shapiro { \
83540266059SGregory Neil Shapiro logundelrcpts(e, cmd, 10, false); \
83640266059SGregory Neil Shapiro smtp.sm_nrcpts = 0; \
83740266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, \
83840266059SGregory Neil Shapiro macid("{nrcpts}"), "0"); \
83940266059SGregory Neil Shapiro } \
84040266059SGregory Neil Shapiro \
84140266059SGregory Neil Shapiro e->e_sendqueue = NULL; \
84240266059SGregory Neil Shapiro e->e_flags |= EF_CLRQUEUE; \
84340266059SGregory Neil Shapiro \
8449bd497b8SGregory Neil Shapiro if (tTd(92, 2)) \
8459bd497b8SGregory Neil Shapiro sm_dprintf("CLEAR_STATE: e_id=%s, EF_LOGSENDER=%d, LogLevel=%d\n",\
8469bd497b8SGregory Neil Shapiro e->e_id, bitset(EF_LOGSENDER, e->e_flags), LogLevel);\
84740266059SGregory Neil Shapiro if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags)) \
84840266059SGregory Neil Shapiro logsender(e, NULL); \
84940266059SGregory Neil Shapiro e->e_flags &= ~EF_LOGSENDER; \
85040266059SGregory Neil Shapiro \
85140266059SGregory Neil Shapiro /* clean up a bit */ \
85240266059SGregory Neil Shapiro smtp.sm_gotmail = false; \
85340266059SGregory Neil Shapiro SuprErrs = true; \
8549bd497b8SGregory Neil Shapiro (void) dropenvelope(e, true, false); \
85540266059SGregory Neil Shapiro sm_rpool_free(e->e_rpool); \
85640266059SGregory Neil Shapiro e = newenvelope(e, CurEnv, sm_rpool_new_x(NULL)); \
85740266059SGregory Neil Shapiro CurEnv = e; \
858d0cef73dSGregory Neil Shapiro e->e_features = features; \
859e92d3f3fSGregory Neil Shapiro \
860e92d3f3fSGregory Neil Shapiro /* put back discard bit */ \
861e92d3f3fSGregory Neil Shapiro if (smtp.sm_discard) \
862e92d3f3fSGregory Neil Shapiro e->e_flags |= EF_DISCARD; \
863e92d3f3fSGregory Neil Shapiro \
864e92d3f3fSGregory Neil Shapiro /* restore connection quarantining */ \
865e92d3f3fSGregory Neil Shapiro if (smtp.sm_quarmsg == NULL) \
866e92d3f3fSGregory Neil Shapiro { \
867e92d3f3fSGregory Neil Shapiro e->e_quarmsg = NULL; \
868e92d3f3fSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, \
869e92d3f3fSGregory Neil Shapiro macid("{quarantine}"), ""); \
870e92d3f3fSGregory Neil Shapiro } \
871e92d3f3fSGregory Neil Shapiro else \
872e92d3f3fSGregory Neil Shapiro { \
873e92d3f3fSGregory Neil Shapiro e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, \
874e92d3f3fSGregory Neil Shapiro smtp.sm_quarmsg); \
875e92d3f3fSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), \
876e92d3f3fSGregory Neil Shapiro e->e_quarmsg); \
877e92d3f3fSGregory Neil Shapiro } \
878e92d3f3fSGregory Neil Shapiro } while (0)
87940266059SGregory Neil Shapiro
88040266059SGregory Neil Shapiro /* sleep to flatten out connection load */
88140266059SGregory Neil Shapiro #define MIN_DELAY_LOG 15 /* wait before logging this again */
88240266059SGregory Neil Shapiro
88340266059SGregory Neil Shapiro /* is it worth setting the process title for 1s? */
88440266059SGregory Neil Shapiro #define DELAY_CONN(cmd) \
88540266059SGregory Neil Shapiro if (DelayLA > 0 && (CurrentLA = getla()) >= DelayLA) \
88640266059SGregory Neil Shapiro { \
88740266059SGregory Neil Shapiro time_t dnow; \
88840266059SGregory Neil Shapiro \
88940266059SGregory Neil Shapiro sm_setproctitle(true, e, \
89040266059SGregory Neil Shapiro "%s: %s: delaying %s: load average: %d", \
89140266059SGregory Neil Shapiro qid_printname(e), CurSmtpClient, \
89240266059SGregory Neil Shapiro cmd, DelayLA); \
89340266059SGregory Neil Shapiro if (LogLevel > 8 && (dnow = curtime()) > log_delay) \
89440266059SGregory Neil Shapiro { \
89540266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, \
89640266059SGregory Neil Shapiro "delaying=%s, load average=%d >= %d", \
89740266059SGregory Neil Shapiro cmd, CurrentLA, DelayLA); \
89840266059SGregory Neil Shapiro log_delay = dnow + MIN_DELAY_LOG; \
89940266059SGregory Neil Shapiro } \
90040266059SGregory Neil Shapiro (void) sleep(1); \
90140266059SGregory Neil Shapiro sm_setproctitle(true, e, "%s %s: %.80s", \
90240266059SGregory Neil Shapiro qid_printname(e), CurSmtpClient, inp); \
90340266059SGregory Neil Shapiro }
90440266059SGregory Neil Shapiro
905da7d7b9cSGregory Neil Shapiro /*
906da7d7b9cSGregory Neil Shapiro ** Determine the correct protocol keyword to use in the
907da7d7b9cSGregory Neil Shapiro ** Received: header, following RFC 3848.
908da7d7b9cSGregory Neil Shapiro */
909da7d7b9cSGregory Neil Shapiro
910da7d7b9cSGregory Neil Shapiro #if !STARTTLS
911da7d7b9cSGregory Neil Shapiro # define tls_active false
912da7d7b9cSGregory Neil Shapiro #endif
913da7d7b9cSGregory Neil Shapiro #if SASL
914da7d7b9cSGregory Neil Shapiro # define auth_active (authenticating == SASL_IS_AUTH)
915da7d7b9cSGregory Neil Shapiro #else
916da7d7b9cSGregory Neil Shapiro # define auth_active false
917da7d7b9cSGregory Neil Shapiro #endif
9182fb4f839SGregory Neil Shapiro #if USE_EAI
9195b0945b5SGregory Neil Shapiro #define GET_PROTOCOL() \
9205b0945b5SGregory Neil Shapiro (e->e_smtputf8 \
9215b0945b5SGregory Neil Shapiro ? (auth_active \
9225b0945b5SGregory Neil Shapiro ? (tls_active ? "UTF8SMTPSA" : "UTF8SMTPA") \
9235b0945b5SGregory Neil Shapiro : (tls_active ? "UTF8SMTPS" : "UTF8SMTP")) \
9245b0945b5SGregory Neil Shapiro : (auth_active \
9255b0945b5SGregory Neil Shapiro ? (tls_active ? "ESMTPSA" : "ESMTPA") \
9265b0945b5SGregory Neil Shapiro : (tls_active ? "ESMTPS" : "ESMTP")))
9272fb4f839SGregory Neil Shapiro #else /* USE_EAI */
928da7d7b9cSGregory Neil Shapiro #define GET_PROTOCOL() \
929da7d7b9cSGregory Neil Shapiro (auth_active \
930da7d7b9cSGregory Neil Shapiro ? (tls_active ? "ESMTPSA" : "ESMTPA") \
931da7d7b9cSGregory Neil Shapiro : (tls_active ? "ESMTPS" : "ESMTP"))
9322fb4f839SGregory Neil Shapiro #endif /* USE_EAI */
933da7d7b9cSGregory Neil Shapiro
9342fb4f839SGregory Neil Shapiro #if _FFR_NOREFLECT
9352fb4f839SGregory Neil Shapiro # define SHOWCMDINREPLY(inp) (bitset(PRIV_NOREFLECTION, PrivacyFlags) ? \
9362fb4f839SGregory Neil Shapiro "(suppressed)" : inp)
9372fb4f839SGregory Neil Shapiro # define SHOWSHRTCMDINREPLY(inp) (bitset(PRIV_NOREFLECTION, PrivacyFlags) ? \
9382fb4f839SGregory Neil Shapiro "(suppressed)" : shortenstring(inp, MAXSHORTSTR))
9392fb4f839SGregory Neil Shapiro #else
9402fb4f839SGregory Neil Shapiro # define SHOWCMDINREPLY(inp) inp
9412fb4f839SGregory Neil Shapiro # define SHOWSHRTCMDINREPLY(inp) shortenstring(inp, MAXSHORTSTR)
9422fb4f839SGregory Neil Shapiro #endif
9432fb4f839SGregory Neil Shapiro
944c2aa98e2SPeter Wemm void
smtp(nullserver,d_flags,e)94506f25ae9SGregory Neil Shapiro smtp(nullserver, d_flags, e)
94606f25ae9SGregory Neil Shapiro char *volatile nullserver;
94706f25ae9SGregory Neil Shapiro BITMAP256 d_flags;
948c2aa98e2SPeter Wemm register ENVELOPE *volatile e;
949c2aa98e2SPeter Wemm {
950c2aa98e2SPeter Wemm register char *volatile p;
95106f25ae9SGregory Neil Shapiro register struct cmd *volatile c = NULL;
952c2aa98e2SPeter Wemm char *cmd;
953c2aa98e2SPeter Wemm auto ADDRESS *vrfyqueue;
954c2aa98e2SPeter Wemm ADDRESS *a;
955c2aa98e2SPeter Wemm volatile bool gothello; /* helo command received */
956c2aa98e2SPeter Wemm bool vrfy; /* set if this is a vrfy command */
957c2aa98e2SPeter Wemm char *volatile protocol; /* sending protocol */
958c2aa98e2SPeter Wemm char *volatile sendinghost; /* sending hostname */
959c2aa98e2SPeter Wemm char *volatile peerhostname; /* name of SMTP peer or "localhost" */
960c2aa98e2SPeter Wemm auto char *delimptr;
961c2aa98e2SPeter Wemm char *id;
96240266059SGregory Neil Shapiro volatile unsigned int n_badcmds = 0; /* count of bad commands */
96340266059SGregory Neil Shapiro volatile unsigned int n_badrcpts = 0; /* number of rejected RCPT */
96440266059SGregory Neil Shapiro volatile unsigned int n_verifies = 0; /* count of VRFY/EXPN */
96540266059SGregory Neil Shapiro volatile unsigned int n_etrn = 0; /* count of ETRN */
96640266059SGregory Neil Shapiro volatile unsigned int n_noop = 0; /* count of NOOP/VERB/etc */
96740266059SGregory Neil Shapiro volatile unsigned int n_helo = 0; /* count of HELO/EHLO */
968c2aa98e2SPeter Wemm bool ok;
96940266059SGregory Neil Shapiro volatile bool first;
97040266059SGregory Neil Shapiro volatile bool tempfail = false;
97106f25ae9SGregory Neil Shapiro volatile time_t wt; /* timeout after too many commands */
97206f25ae9SGregory Neil Shapiro volatile time_t previous; /* time after checksmtpattack() */
97340266059SGregory Neil Shapiro volatile bool lognullconnection = true;
974c2aa98e2SPeter Wemm register char *q;
97540266059SGregory Neil Shapiro SMTP_T smtp;
97606f25ae9SGregory Neil Shapiro char *addr;
97706f25ae9SGregory Neil Shapiro char *greetcode = "220";
978da7d7b9cSGregory Neil Shapiro const char *greetmsg = "not accepting messages";
97940266059SGregory Neil Shapiro char *hostname; /* my hostname ($j) */
980c2aa98e2SPeter Wemm QUEUE_CHAR *new;
98106f25ae9SGregory Neil Shapiro char *args[MAXSMTPARGS];
982d0cef73dSGregory Neil Shapiro char inp[MAXINPLINE];
983d0cef73dSGregory Neil Shapiro #if MAXINPLINE < MAXLINE
984*d39bd2c1SGregory Neil Shapiro # error "MAXINPLINE must NOT be less than MAXLINE"
9855b0945b5SGregory Neil Shapiro #endif
986c2aa98e2SPeter Wemm char cmdbuf[MAXLINE];
98706f25ae9SGregory Neil Shapiro #if SASL
98806f25ae9SGregory Neil Shapiro sasl_conn_t *conn;
98906f25ae9SGregory Neil Shapiro volatile bool sasl_ok;
99040266059SGregory Neil Shapiro volatile unsigned int n_auth = 0; /* count of AUTH commands */
99106f25ae9SGregory Neil Shapiro bool ismore;
99206f25ae9SGregory Neil Shapiro int result;
99306f25ae9SGregory Neil Shapiro volatile int authenticating;
99406f25ae9SGregory Neil Shapiro char *user;
99594c01205SGregory Neil Shapiro char *in, *out2;
9965b0945b5SGregory Neil Shapiro char auth_user[MAX_AUTH_USER_LEN], auth_user_tmp[MAX_AUTH_USER_LEN];
9975b0945b5SGregory Neil Shapiro unsigned int auth_user_len;
99894c01205SGregory Neil Shapiro # if SASL >= 20000
999d0cef73dSGregory Neil Shapiro char *auth_id = NULL;
100094c01205SGregory Neil Shapiro const char *out;
100194c01205SGregory Neil Shapiro sasl_ssf_t ext_ssf;
1002a7ec597cSGregory Neil Shapiro char localip[60], remoteip[60];
100394c01205SGregory Neil Shapiro # else /* SASL >= 20000 */
100494c01205SGregory Neil Shapiro char *out;
100506f25ae9SGregory Neil Shapiro const char *errstr;
100694c01205SGregory Neil Shapiro sasl_external_properties_t ext_ssf;
1007a7ec597cSGregory Neil Shapiro struct sockaddr_in saddr_l;
1008a7ec597cSGregory Neil Shapiro struct sockaddr_in saddr_r;
100994c01205SGregory Neil Shapiro # endif /* SASL >= 20000 */
101094c01205SGregory Neil Shapiro sasl_security_properties_t ssp;
101194c01205SGregory Neil Shapiro sasl_ssf_t *ssf;
101240266059SGregory Neil Shapiro unsigned int inlen, out2len;
101306f25ae9SGregory Neil Shapiro unsigned int outlen;
101406f25ae9SGregory Neil Shapiro char *volatile auth_type;
101506f25ae9SGregory Neil Shapiro char *mechlist;
101640266059SGregory Neil Shapiro volatile unsigned int n_mechs;
101740266059SGregory Neil Shapiro unsigned int len;
101806f25ae9SGregory Neil Shapiro #endif /* SASL */
101906f25ae9SGregory Neil Shapiro int r;
1020e92d3f3fSGregory Neil Shapiro #if STARTTLS
102142e5d165SGregory Neil Shapiro int rfd, wfd;
102240266059SGregory Neil Shapiro volatile bool tls_active = false;
1023e92d3f3fSGregory Neil Shapiro volatile bool smtps = bitnset(D_SMTPS, d_flags);
1024*d39bd2c1SGregory Neil Shapiro bool gotostarttls = false;
102506f25ae9SGregory Neil Shapiro bool saveQuickAbort;
102606f25ae9SGregory Neil Shapiro bool saveSuprErrs;
102740266059SGregory Neil Shapiro time_t tlsstart;
10285b0945b5SGregory Neil Shapiro int ssl_err, tlsret;
10295b0945b5SGregory Neil Shapiro int save_errno;
10305b0945b5SGregory Neil Shapiro extern int TLSsslidx;
103106f25ae9SGregory Neil Shapiro #endif /* STARTTLS */
1032*d39bd2c1SGregory Neil Shapiro volatile unsigned long features;
1033*d39bd2c1SGregory Neil Shapiro #if PIPELINING && _FFR_NO_PIPE
103440266059SGregory Neil Shapiro int np_log = 0;
10355b0945b5SGregory Neil Shapiro #endif
103640266059SGregory Neil Shapiro volatile time_t log_delay = (time_t) 0;
1037d0cef73dSGregory Neil Shapiro #if MILTER
1038d0cef73dSGregory Neil Shapiro volatile bool milter_cmd_done, milter_cmd_safe;
1039d0cef73dSGregory Neil Shapiro volatile bool milter_rcpt_added, milter_cmd_fail;
1040d0cef73dSGregory Neil Shapiro ADDRESS addr_st;
1041d0cef73dSGregory Neil Shapiro # define p_addr_st &addr_st
1042d0cef73dSGregory Neil Shapiro #else /* MILTER */
1043d0cef73dSGregory Neil Shapiro # define p_addr_st NULL
1044d0cef73dSGregory Neil Shapiro #endif /* MILTER */
1045d0cef73dSGregory Neil Shapiro size_t inplen;
1046e3793f76SGregory Neil Shapiro #if _FFR_BADRCPT_SHUTDOWN
1047e3793f76SGregory Neil Shapiro int n_badrcpts_adj;
10485b0945b5SGregory Neil Shapiro #endif
1049*d39bd2c1SGregory Neil Shapiro bool gotodoquit = false;
1050c2aa98e2SPeter Wemm
10515b0945b5SGregory Neil Shapiro RESET_AUTH_FAIL_LOG_USER;
105240266059SGregory Neil Shapiro smtp.sm_nrcpts = 0;
105340266059SGregory Neil Shapiro #if MILTER
105440266059SGregory Neil Shapiro smtp.sm_milterize = (nullserver == NULL);
105540266059SGregory Neil Shapiro smtp.sm_milterlist = false;
1056d0cef73dSGregory Neil Shapiro addr = NULL;
10575b0945b5SGregory Neil Shapiro #endif
105840266059SGregory Neil Shapiro
105940266059SGregory Neil Shapiro /* setup I/O fd correctly for the SMTP server */
106040266059SGregory Neil Shapiro setup_smtpd_io();
106140266059SGregory Neil Shapiro
106240266059SGregory Neil Shapiro #if SM_HEAP_CHECK
106340266059SGregory Neil Shapiro if (sm_debug_active(&DebugLeakSmtp, 1))
1064c2aa98e2SPeter Wemm {
106540266059SGregory Neil Shapiro sm_heap_newgroup();
106640266059SGregory Neil Shapiro sm_dprintf("smtp() heap group #%d\n", sm_heap_group());
1067c2aa98e2SPeter Wemm }
106840266059SGregory Neil Shapiro #endif /* SM_HEAP_CHECK */
106940266059SGregory Neil Shapiro
107040266059SGregory Neil Shapiro /* XXX the rpool should be set when e is initialized in main() */
107140266059SGregory Neil Shapiro e->e_rpool = sm_rpool_new_x(NULL);
107240266059SGregory Neil Shapiro e->e_macro.mac_rpool = e->e_rpool;
107306f25ae9SGregory Neil Shapiro
1074c2aa98e2SPeter Wemm settime(e);
107540266059SGregory Neil Shapiro sm_getla();
1076c2aa98e2SPeter Wemm peerhostname = RealHostName;
1077c2aa98e2SPeter Wemm if (peerhostname == NULL)
1078c2aa98e2SPeter Wemm peerhostname = "localhost";
1079c2aa98e2SPeter Wemm CurHostName = peerhostname;
1080c2aa98e2SPeter Wemm CurSmtpClient = macvalue('_', e);
1081c2aa98e2SPeter Wemm if (CurSmtpClient == NULL)
1082c2aa98e2SPeter Wemm CurSmtpClient = CurHostName;
1083c2aa98e2SPeter Wemm
1084c2aa98e2SPeter Wemm /* check_relay may have set discard bit, save for later */
108540266059SGregory Neil Shapiro smtp.sm_discard = bitset(EF_DISCARD, e->e_flags);
1086c2aa98e2SPeter Wemm
108740266059SGregory Neil Shapiro #if PIPELINING
108840266059SGregory Neil Shapiro /* auto-flush output when reading input */
108940266059SGregory Neil Shapiro (void) sm_io_autoflush(InChannel, OutChannel);
10902fb4f839SGregory Neil Shapiro #endif
109140266059SGregory Neil Shapiro
109240266059SGregory Neil Shapiro sm_setproctitle(true, e, "server %s startup", CurSmtpClient);
109340266059SGregory Neil Shapiro
1094*d39bd2c1SGregory Neil Shapiro maps_reset_chged("server:smtp");
1095*d39bd2c1SGregory Neil Shapiro
1096*d39bd2c1SGregory Neil Shapiro /*
1097*d39bd2c1SGregory Neil Shapiro ** Set default features for server.
1098*d39bd2c1SGregory Neil Shapiro **
1099*d39bd2c1SGregory Neil Shapiro ** Changing SRV_BARE_LF_421 | SRV_BARE_CR_421 below also
1100*d39bd2c1SGregory Neil Shapiro ** requires changing srvfeatures() variant code.
1101*d39bd2c1SGregory Neil Shapiro */
1102*d39bd2c1SGregory Neil Shapiro
110340266059SGregory Neil Shapiro features = ((bitset(PRIV_NOETRN, PrivacyFlags) ||
110440266059SGregory Neil Shapiro bitnset(D_NOETRN, d_flags)) ? SRV_NONE : SRV_OFFER_ETRN)
110540266059SGregory Neil Shapiro | (bitnset(D_AUTHREQ, d_flags) ? SRV_REQ_AUTH : SRV_NONE)
110640266059SGregory Neil Shapiro | (bitset(PRIV_NOEXPN, PrivacyFlags) ? SRV_NONE
110740266059SGregory Neil Shapiro : (SRV_OFFER_EXPN
110840266059SGregory Neil Shapiro | (bitset(PRIV_NOVERB, PrivacyFlags)
110940266059SGregory Neil Shapiro ? SRV_NONE : SRV_OFFER_VERB)))
1110af9557fdSGregory Neil Shapiro | ((bitset(PRIV_NORECEIPTS, PrivacyFlags) || !SendMIMEErrors)
1111af9557fdSGregory Neil Shapiro ? SRV_NONE : SRV_OFFER_DSN)
111240266059SGregory Neil Shapiro #if SASL
111340266059SGregory Neil Shapiro | (bitnset(D_NOAUTH, d_flags) ? SRV_NONE : SRV_OFFER_AUTH)
1114e92d3f3fSGregory Neil Shapiro | (bitset(SASL_SEC_NOPLAINTEXT, SASLOpts) ? SRV_REQ_SEC
1115e92d3f3fSGregory Neil Shapiro : SRV_NONE)
111640266059SGregory Neil Shapiro #endif /* SASL */
111740266059SGregory Neil Shapiro #if PIPELINING
111840266059SGregory Neil Shapiro | SRV_OFFER_PIPE
11195b0945b5SGregory Neil Shapiro #endif
1120*d39bd2c1SGregory Neil Shapiro | SRV_BAD_PIPELINE
112140266059SGregory Neil Shapiro #if STARTTLS
112240266059SGregory Neil Shapiro | (bitnset(D_NOTLS, d_flags) ? SRV_NONE : SRV_OFFER_TLS)
112340266059SGregory Neil Shapiro | (bitset(TLS_I_NO_VRFY, TLS_Srv_Opts) ? SRV_NONE
112440266059SGregory Neil Shapiro : SRV_VRFY_CLT)
11255b0945b5SGregory Neil Shapiro #endif
11262fb4f839SGregory Neil Shapiro #if USE_EAI
1127*d39bd2c1SGregory Neil Shapiro | (SMTP_UTF8 ? SRV_OFFER_EAI : 0)
11282fb4f839SGregory Neil Shapiro #endif
1129*d39bd2c1SGregory Neil Shapiro | SRV_REQ_CRLF | SRV_BARE_LF_421 | SRV_BARE_CR_421
113040266059SGregory Neil Shapiro ;
113140266059SGregory Neil Shapiro if (nullserver == NULL)
113240266059SGregory Neil Shapiro {
113340266059SGregory Neil Shapiro features = srvfeatures(e, CurSmtpClient, features);
113440266059SGregory Neil Shapiro if (bitset(SRV_TMP_FAIL, features))
113540266059SGregory Neil Shapiro {
113640266059SGregory Neil Shapiro if (LogLevel > 4)
113740266059SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID,
113840266059SGregory Neil Shapiro "ERROR: srv_features=tempfail, relay=%.100s, access temporarily disabled",
113940266059SGregory Neil Shapiro CurSmtpClient);
114040266059SGregory Neil Shapiro nullserver = "450 4.3.0 Please try again later.";
114140266059SGregory Neil Shapiro }
1142e92d3f3fSGregory Neil Shapiro else
1143e92d3f3fSGregory Neil Shapiro {
1144*d39bd2c1SGregory Neil Shapiro #if PIPELINING && _FFR_NO_PIPE
1145e92d3f3fSGregory Neil Shapiro if (bitset(SRV_NO_PIPE, features))
114640266059SGregory Neil Shapiro {
114740266059SGregory Neil Shapiro /* for consistency */
114840266059SGregory Neil Shapiro features &= ~SRV_OFFER_PIPE;
114940266059SGregory Neil Shapiro }
1150*d39bd2c1SGregory Neil Shapiro #endif /* PIPELINING && _FFR_NO_PIPE */
1151e92d3f3fSGregory Neil Shapiro #if SASL
1152e92d3f3fSGregory Neil Shapiro if (bitset(SRV_REQ_SEC, features))
1153e92d3f3fSGregory Neil Shapiro SASLOpts |= SASL_SEC_NOPLAINTEXT;
1154e92d3f3fSGregory Neil Shapiro else
1155e92d3f3fSGregory Neil Shapiro SASLOpts &= ~SASL_SEC_NOPLAINTEXT;
1156e92d3f3fSGregory Neil Shapiro #endif /* SASL */
1157e92d3f3fSGregory Neil Shapiro }
1158e92d3f3fSGregory Neil Shapiro }
1159e92d3f3fSGregory Neil Shapiro else if (strncmp(nullserver, "421 ", 4) == 0)
1160e92d3f3fSGregory Neil Shapiro {
11615b0945b5SGregory Neil Shapiro /* Can't use ("%s", ...) due to message() requirements */
1162e92d3f3fSGregory Neil Shapiro message(nullserver);
1163*d39bd2c1SGregory Neil Shapiro gotodoquit = true;
1164*d39bd2c1SGregory Neil Shapiro goto cmdloop;
116540266059SGregory Neil Shapiro }
116640266059SGregory Neil Shapiro
1167d0cef73dSGregory Neil Shapiro e->e_features = features;
116840266059SGregory Neil Shapiro hostname = macvalue('j', e);
116906f25ae9SGregory Neil Shapiro #if SASL
1170e92d3f3fSGregory Neil Shapiro if (AuthRealm == NULL)
1171e92d3f3fSGregory Neil Shapiro AuthRealm = hostname;
117240266059SGregory Neil Shapiro sasl_ok = bitset(SRV_OFFER_AUTH, features);
117306f25ae9SGregory Neil Shapiro n_mechs = 0;
117440266059SGregory Neil Shapiro authenticating = SASL_NOT_AUTH;
117506f25ae9SGregory Neil Shapiro
117606f25ae9SGregory Neil Shapiro /* SASL server new connection */
117740266059SGregory Neil Shapiro if (sasl_ok)
117840266059SGregory Neil Shapiro {
117994c01205SGregory Neil Shapiro # if SASL >= 20000
1180e92d3f3fSGregory Neil Shapiro result = sasl_server_new("smtp", AuthRealm, NULL, NULL, NULL,
118194c01205SGregory Neil Shapiro NULL, 0, &conn);
118294c01205SGregory Neil Shapiro # elif SASL > 10505
118306f25ae9SGregory Neil Shapiro /* use empty realm: only works in SASL > 1.5.5 */
1184e92d3f3fSGregory Neil Shapiro result = sasl_server_new("smtp", AuthRealm, "", NULL, 0, &conn);
118594c01205SGregory Neil Shapiro # else /* SASL >= 20000 */
118606f25ae9SGregory Neil Shapiro /* use no realm -> realm is set to hostname by SASL lib */
1187e92d3f3fSGregory Neil Shapiro result = sasl_server_new("smtp", AuthRealm, NULL, NULL, 0,
118840266059SGregory Neil Shapiro &conn);
118994c01205SGregory Neil Shapiro # endif /* SASL >= 20000 */
119040266059SGregory Neil Shapiro sasl_ok = result == SASL_OK;
119140266059SGregory Neil Shapiro if (!sasl_ok)
1192c2aa98e2SPeter Wemm {
119340266059SGregory Neil Shapiro if (LogLevel > 9)
119440266059SGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID,
119540266059SGregory Neil Shapiro "AUTH error: sasl_server_new failed=%d",
119640266059SGregory Neil Shapiro result);
119740266059SGregory Neil Shapiro }
119840266059SGregory Neil Shapiro }
119940266059SGregory Neil Shapiro if (sasl_ok)
120040266059SGregory Neil Shapiro {
120106f25ae9SGregory Neil Shapiro /*
120206f25ae9SGregory Neil Shapiro ** SASL set properties for sasl
120306f25ae9SGregory Neil Shapiro ** set local/remote IP
120494c01205SGregory Neil Shapiro ** XXX Cyrus SASL v1 only supports IPv4
120506f25ae9SGregory Neil Shapiro **
120606f25ae9SGregory Neil Shapiro ** XXX where exactly are these used/required?
120706f25ae9SGregory Neil Shapiro ** Kerberos_v4
120806f25ae9SGregory Neil Shapiro */
120906f25ae9SGregory Neil Shapiro
121094c01205SGregory Neil Shapiro # if SASL >= 20000
121113d88268SGregory Neil Shapiro localip[0] = remoteip[0] = '\0';
121294c01205SGregory Neil Shapiro # if NETINET || NETINET6
121394c01205SGregory Neil Shapiro in = macvalue(macid("{daemon_family}"), e);
121494c01205SGregory Neil Shapiro if (in != NULL && (
121594c01205SGregory Neil Shapiro # if NETINET6
121694c01205SGregory Neil Shapiro strcmp(in, "inet6") == 0 ||
12175b0945b5SGregory Neil Shapiro # endif
121894c01205SGregory Neil Shapiro strcmp(in, "inet") == 0))
121994c01205SGregory Neil Shapiro {
122094c01205SGregory Neil Shapiro SOCKADDR_LEN_T addrsize;
122194c01205SGregory Neil Shapiro SOCKADDR saddr_l;
122294c01205SGregory Neil Shapiro SOCKADDR saddr_r;
122394c01205SGregory Neil Shapiro
122494c01205SGregory Neil Shapiro addrsize = sizeof(saddr_r);
122594c01205SGregory Neil Shapiro if (getpeername(sm_io_getinfo(InChannel, SM_IO_WHAT_FD,
122694c01205SGregory Neil Shapiro NULL),
122794c01205SGregory Neil Shapiro (struct sockaddr *) &saddr_r,
122894c01205SGregory Neil Shapiro &addrsize) == 0)
122994c01205SGregory Neil Shapiro {
123094c01205SGregory Neil Shapiro if (iptostring(&saddr_r, addrsize,
1231d0cef73dSGregory Neil Shapiro remoteip, sizeof(remoteip)))
123294c01205SGregory Neil Shapiro {
123394c01205SGregory Neil Shapiro sasl_setprop(conn, SASL_IPREMOTEPORT,
123494c01205SGregory Neil Shapiro remoteip);
123594c01205SGregory Neil Shapiro }
123694c01205SGregory Neil Shapiro addrsize = sizeof(saddr_l);
123794c01205SGregory Neil Shapiro if (getsockname(sm_io_getinfo(InChannel,
123894c01205SGregory Neil Shapiro SM_IO_WHAT_FD,
123994c01205SGregory Neil Shapiro NULL),
124094c01205SGregory Neil Shapiro (struct sockaddr *) &saddr_l,
124194c01205SGregory Neil Shapiro &addrsize) == 0)
124294c01205SGregory Neil Shapiro {
124394c01205SGregory Neil Shapiro if (iptostring(&saddr_l, addrsize,
124494c01205SGregory Neil Shapiro localip,
1245d0cef73dSGregory Neil Shapiro sizeof(localip)))
124694c01205SGregory Neil Shapiro {
124794c01205SGregory Neil Shapiro sasl_setprop(conn,
124894c01205SGregory Neil Shapiro SASL_IPLOCALPORT,
124994c01205SGregory Neil Shapiro localip);
125094c01205SGregory Neil Shapiro }
125194c01205SGregory Neil Shapiro }
125294c01205SGregory Neil Shapiro }
125394c01205SGregory Neil Shapiro }
125494c01205SGregory Neil Shapiro # endif /* NETINET || NETINET6 */
125594c01205SGregory Neil Shapiro # else /* SASL >= 20000 */
125606f25ae9SGregory Neil Shapiro # if NETINET
125740266059SGregory Neil Shapiro in = macvalue(macid("{daemon_family}"), e);
125806f25ae9SGregory Neil Shapiro if (in != NULL && strcmp(in, "inet") == 0)
125906f25ae9SGregory Neil Shapiro {
126006f25ae9SGregory Neil Shapiro SOCKADDR_LEN_T addrsize;
126106f25ae9SGregory Neil Shapiro
126206f25ae9SGregory Neil Shapiro addrsize = sizeof(struct sockaddr_in);
126340266059SGregory Neil Shapiro if (getpeername(sm_io_getinfo(InChannel, SM_IO_WHAT_FD,
126440266059SGregory Neil Shapiro NULL),
126506f25ae9SGregory Neil Shapiro (struct sockaddr *)&saddr_r,
126606f25ae9SGregory Neil Shapiro &addrsize) == 0)
126706f25ae9SGregory Neil Shapiro {
126806f25ae9SGregory Neil Shapiro sasl_setprop(conn, SASL_IP_REMOTE, &saddr_r);
126906f25ae9SGregory Neil Shapiro addrsize = sizeof(struct sockaddr_in);
127040266059SGregory Neil Shapiro if (getsockname(sm_io_getinfo(InChannel,
127140266059SGregory Neil Shapiro SM_IO_WHAT_FD,
127240266059SGregory Neil Shapiro NULL),
127306f25ae9SGregory Neil Shapiro (struct sockaddr *)&saddr_l,
127406f25ae9SGregory Neil Shapiro &addrsize) == 0)
127506f25ae9SGregory Neil Shapiro sasl_setprop(conn, SASL_IP_LOCAL,
127606f25ae9SGregory Neil Shapiro &saddr_l);
1277c2aa98e2SPeter Wemm }
127806f25ae9SGregory Neil Shapiro }
127906f25ae9SGregory Neil Shapiro # endif /* NETINET */
128094c01205SGregory Neil Shapiro # endif /* SASL >= 20000 */
128106f25ae9SGregory Neil Shapiro
128206f25ae9SGregory Neil Shapiro auth_type = NULL;
128306f25ae9SGregory Neil Shapiro mechlist = NULL;
128406f25ae9SGregory Neil Shapiro user = NULL;
128506f25ae9SGregory Neil Shapiro # if 0
128640266059SGregory Neil Shapiro macdefine(&BlankEnvelope.e_macro, A_PERM,
128740266059SGregory Neil Shapiro macid("{auth_author}"), NULL);
12885b0945b5SGregory Neil Shapiro # endif
128906f25ae9SGregory Neil Shapiro
129006f25ae9SGregory Neil Shapiro /* set properties */
1291d0cef73dSGregory Neil Shapiro (void) memset(&ssp, '\0', sizeof(ssp));
129240266059SGregory Neil Shapiro
129306f25ae9SGregory Neil Shapiro /* XXX should these be options settable via .cf ? */
129406f25ae9SGregory Neil Shapiro /* ssp.min_ssf = 0; is default due to memset() */
129540266059SGregory Neil Shapiro ssp.max_ssf = MaxSLBits;
129606f25ae9SGregory Neil Shapiro ssp.maxbufsize = MAXOUTLEN;
129706f25ae9SGregory Neil Shapiro ssp.security_flags = SASLOpts & SASL_SEC_MASK;
129806f25ae9SGregory Neil Shapiro sasl_ok = sasl_setprop(conn, SASL_SEC_PROPS, &ssp) == SASL_OK;
129906f25ae9SGregory Neil Shapiro
130006f25ae9SGregory Neil Shapiro if (sasl_ok)
130106f25ae9SGregory Neil Shapiro {
130206f25ae9SGregory Neil Shapiro /*
130306f25ae9SGregory Neil Shapiro ** external security strength factor;
130440266059SGregory Neil Shapiro ** currently we have none so zero
130506f25ae9SGregory Neil Shapiro */
130640266059SGregory Neil Shapiro
130794c01205SGregory Neil Shapiro # if SASL >= 20000
130894c01205SGregory Neil Shapiro ext_ssf = 0;
130994c01205SGregory Neil Shapiro auth_id = NULL;
131094c01205SGregory Neil Shapiro sasl_ok = ((sasl_setprop(conn, SASL_SSF_EXTERNAL,
131194c01205SGregory Neil Shapiro &ext_ssf) == SASL_OK) &&
131294c01205SGregory Neil Shapiro (sasl_setprop(conn, SASL_AUTH_EXTERNAL,
131394c01205SGregory Neil Shapiro auth_id) == SASL_OK));
131494c01205SGregory Neil Shapiro # else /* SASL >= 20000 */
131506f25ae9SGregory Neil Shapiro ext_ssf.ssf = 0;
131606f25ae9SGregory Neil Shapiro ext_ssf.auth_id = NULL;
131706f25ae9SGregory Neil Shapiro sasl_ok = sasl_setprop(conn, SASL_SSF_EXTERNAL,
131806f25ae9SGregory Neil Shapiro &ext_ssf) == SASL_OK;
131994c01205SGregory Neil Shapiro # endif /* SASL >= 20000 */
132006f25ae9SGregory Neil Shapiro }
132106f25ae9SGregory Neil Shapiro if (sasl_ok)
132206f25ae9SGregory Neil Shapiro n_mechs = saslmechs(conn, &mechlist);
132306f25ae9SGregory Neil Shapiro }
132406f25ae9SGregory Neil Shapiro #endif /* SASL */
132506f25ae9SGregory Neil Shapiro
1326da7d7b9cSGregory Neil Shapiro (void) set_tls_rd_tmo(TimeOuts.to_nextcommand);
1327a7ec597cSGregory Neil Shapiro
132840266059SGregory Neil Shapiro #if MILTER
132940266059SGregory Neil Shapiro if (smtp.sm_milterize)
133006f25ae9SGregory Neil Shapiro {
133106f25ae9SGregory Neil Shapiro char state;
133206f25ae9SGregory Neil Shapiro
133306f25ae9SGregory Neil Shapiro /* initialize mail filter connection */
1334ffb83623SGregory Neil Shapiro smtp.sm_milterlist = milter_init(e, &state, &smtp.sm_milters);
133506f25ae9SGregory Neil Shapiro switch (state)
133606f25ae9SGregory Neil Shapiro {
133706f25ae9SGregory Neil Shapiro case SMFIR_REJECT:
133840266059SGregory Neil Shapiro if (MilterLogLevel > 3)
133940266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
1340605302a5SGregory Neil Shapiro "Milter: initialization failed, rejecting commands");
134106f25ae9SGregory Neil Shapiro greetcode = "554";
134206f25ae9SGregory Neil Shapiro nullserver = "Command rejected";
134340266059SGregory Neil Shapiro smtp.sm_milterize = false;
134406f25ae9SGregory Neil Shapiro break;
134506f25ae9SGregory Neil Shapiro
134606f25ae9SGregory Neil Shapiro case SMFIR_TEMPFAIL:
134740266059SGregory Neil Shapiro if (MilterLogLevel > 3)
134840266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
1349605302a5SGregory Neil Shapiro "Milter: initialization failed, temp failing commands");
135040266059SGregory Neil Shapiro tempfail = true;
135140266059SGregory Neil Shapiro smtp.sm_milterize = false;
135206f25ae9SGregory Neil Shapiro break;
13534e4196cbSGregory Neil Shapiro
13544e4196cbSGregory Neil Shapiro case SMFIR_SHUTDOWN:
13554e4196cbSGregory Neil Shapiro if (MilterLogLevel > 3)
13564e4196cbSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
13574e4196cbSGregory Neil Shapiro "Milter: initialization failed, closing connection");
13584e4196cbSGregory Neil Shapiro tempfail = true;
13594e4196cbSGregory Neil Shapiro smtp.sm_milterize = false;
13604e4196cbSGregory Neil Shapiro message("421 4.7.0 %s closing connection",
13614e4196cbSGregory Neil Shapiro MyHostName);
13624e4196cbSGregory Neil Shapiro
13634e4196cbSGregory Neil Shapiro /* arrange to ignore send list */
13644e4196cbSGregory Neil Shapiro e->e_sendqueue = NULL;
1365e3793f76SGregory Neil Shapiro lognullconnection = false;
1366*d39bd2c1SGregory Neil Shapiro gotodoquit = true;
1367*d39bd2c1SGregory Neil Shapiro goto cmdloop;
136806f25ae9SGregory Neil Shapiro }
136906f25ae9SGregory Neil Shapiro }
137006f25ae9SGregory Neil Shapiro
137140266059SGregory Neil Shapiro if (smtp.sm_milterlist && smtp.sm_milterize &&
137240266059SGregory Neil Shapiro !bitset(EF_DISCARD, e->e_flags))
137306f25ae9SGregory Neil Shapiro {
137406f25ae9SGregory Neil Shapiro char state;
137540266059SGregory Neil Shapiro char *response;
137606f25ae9SGregory Neil Shapiro
13773a3ef73dSGregory Neil Shapiro q = macvalue(macid("{client_name}"), e);
1378d0cef73dSGregory Neil Shapiro SM_ASSERT(q != NULL || OpMode == MD_SMTP);
1379d0cef73dSGregory Neil Shapiro if (q == NULL)
1380d0cef73dSGregory Neil Shapiro q = "localhost";
13813a3ef73dSGregory Neil Shapiro response = milter_connect(q, RealHostAddr, e, &state);
138206f25ae9SGregory Neil Shapiro switch (state)
138306f25ae9SGregory Neil Shapiro {
1384da7d7b9cSGregory Neil Shapiro # if _FFR_MILTER_CONNECT_REPLYCODE
1385da7d7b9cSGregory Neil Shapiro case SMFIR_REPLYCODE:
1386da7d7b9cSGregory Neil Shapiro if (*response == '5')
1387da7d7b9cSGregory Neil Shapiro {
1388da7d7b9cSGregory Neil Shapiro if (MilterLogLevel > 3)
1389da7d7b9cSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
1390da7d7b9cSGregory Neil Shapiro "Milter: connect: host=%s, addr=%s, reject=%s",
1391da7d7b9cSGregory Neil Shapiro peerhostname,
1392da7d7b9cSGregory Neil Shapiro anynet_ntoa(&RealHostAddr),
1393da7d7b9cSGregory Neil Shapiro response);
1394da7d7b9cSGregory Neil Shapiro greetcode = "554"; /* Required by 2821 3.1 */
1395da7d7b9cSGregory Neil Shapiro nullserver = newstr(response);
1396da7d7b9cSGregory Neil Shapiro if (strlen(nullserver) > 4)
1397da7d7b9cSGregory Neil Shapiro {
1398da7d7b9cSGregory Neil Shapiro int skip;
1399da7d7b9cSGregory Neil Shapiro
1400da7d7b9cSGregory Neil Shapiro greetmsg = nullserver + 4;
1401da7d7b9cSGregory Neil Shapiro
1402da7d7b9cSGregory Neil Shapiro /* skip over enhanced status code */
1403da7d7b9cSGregory Neil Shapiro skip = isenhsc(greetmsg, ' ');
1404da7d7b9cSGregory Neil Shapiro if (skip > 0)
1405da7d7b9cSGregory Neil Shapiro greetmsg += skip + 1;
1406da7d7b9cSGregory Neil Shapiro }
1407da7d7b9cSGregory Neil Shapiro smtp.sm_milterize = false;
1408da7d7b9cSGregory Neil Shapiro break;
1409da7d7b9cSGregory Neil Shapiro }
1410da7d7b9cSGregory Neil Shapiro else if (strncmp(response, "421 ", 4) == 0)
1411da7d7b9cSGregory Neil Shapiro {
1412da7d7b9cSGregory Neil Shapiro int skip;
1413da7d7b9cSGregory Neil Shapiro const char *msg = response + 4;
1414da7d7b9cSGregory Neil Shapiro
1415da7d7b9cSGregory Neil Shapiro if (MilterLogLevel > 3)
1416da7d7b9cSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
1417da7d7b9cSGregory Neil Shapiro "Milter: connect: host=%s, addr=%s, shutdown=%s",
1418da7d7b9cSGregory Neil Shapiro peerhostname,
1419da7d7b9cSGregory Neil Shapiro anynet_ntoa(&RealHostAddr),
1420da7d7b9cSGregory Neil Shapiro response);
1421da7d7b9cSGregory Neil Shapiro tempfail = true;
1422da7d7b9cSGregory Neil Shapiro smtp.sm_milterize = false;
1423da7d7b9cSGregory Neil Shapiro
1424da7d7b9cSGregory Neil Shapiro /* skip over enhanced status code */
1425da7d7b9cSGregory Neil Shapiro skip = isenhsc(msg, ' ');
1426da7d7b9cSGregory Neil Shapiro if (skip > 0)
1427da7d7b9cSGregory Neil Shapiro msg += skip + 1;
1428da7d7b9cSGregory Neil Shapiro message("421 %s %s", MyHostName, msg);
1429da7d7b9cSGregory Neil Shapiro
1430da7d7b9cSGregory Neil Shapiro /* arrange to ignore send list */
1431da7d7b9cSGregory Neil Shapiro e->e_sendqueue = NULL;
1432*d39bd2c1SGregory Neil Shapiro gotodoquit = true;
1433*d39bd2c1SGregory Neil Shapiro goto cmdloop;
1434da7d7b9cSGregory Neil Shapiro }
1435da7d7b9cSGregory Neil Shapiro else
1436da7d7b9cSGregory Neil Shapiro {
1437da7d7b9cSGregory Neil Shapiro if (MilterLogLevel > 3)
1438da7d7b9cSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
1439da7d7b9cSGregory Neil Shapiro "Milter: connect: host=%s, addr=%s, temp failing commands=%s",
1440da7d7b9cSGregory Neil Shapiro peerhostname,
1441da7d7b9cSGregory Neil Shapiro anynet_ntoa(&RealHostAddr),
1442da7d7b9cSGregory Neil Shapiro response);
1443da7d7b9cSGregory Neil Shapiro /*tempfail = true;*/
1444da7d7b9cSGregory Neil Shapiro smtp.sm_milterize = false;
1445da7d7b9cSGregory Neil Shapiro nullserver = newstr(response);
1446da7d7b9cSGregory Neil Shapiro break;
1447da7d7b9cSGregory Neil Shapiro }
1448da7d7b9cSGregory Neil Shapiro
1449da7d7b9cSGregory Neil Shapiro # else /* _FFR_MILTER_CONNECT_REPLYCODE */
145006f25ae9SGregory Neil Shapiro case SMFIR_REPLYCODE: /* REPLYCODE shouldn't happen */
1451da7d7b9cSGregory Neil Shapiro # endif /* _FFR_MILTER_CONNECT_REPLYCODE */
145206f25ae9SGregory Neil Shapiro case SMFIR_REJECT:
145340266059SGregory Neil Shapiro if (MilterLogLevel > 3)
145440266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
145540266059SGregory Neil Shapiro "Milter: connect: host=%s, addr=%s, rejecting commands",
145640266059SGregory Neil Shapiro peerhostname,
145740266059SGregory Neil Shapiro anynet_ntoa(&RealHostAddr));
145806f25ae9SGregory Neil Shapiro greetcode = "554";
145906f25ae9SGregory Neil Shapiro nullserver = "Command rejected";
146040266059SGregory Neil Shapiro smtp.sm_milterize = false;
146106f25ae9SGregory Neil Shapiro break;
146206f25ae9SGregory Neil Shapiro
146306f25ae9SGregory Neil Shapiro case SMFIR_TEMPFAIL:
146440266059SGregory Neil Shapiro if (MilterLogLevel > 3)
146540266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
146640266059SGregory Neil Shapiro "Milter: connect: host=%s, addr=%s, temp failing commands",
146740266059SGregory Neil Shapiro peerhostname,
146840266059SGregory Neil Shapiro anynet_ntoa(&RealHostAddr));
146940266059SGregory Neil Shapiro tempfail = true;
147040266059SGregory Neil Shapiro smtp.sm_milterize = false;
147106f25ae9SGregory Neil Shapiro break;
147213bd1963SGregory Neil Shapiro
147313bd1963SGregory Neil Shapiro case SMFIR_SHUTDOWN:
147413bd1963SGregory Neil Shapiro if (MilterLogLevel > 3)
147513bd1963SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
147613bd1963SGregory Neil Shapiro "Milter: connect: host=%s, addr=%s, shutdown",
147713bd1963SGregory Neil Shapiro peerhostname,
147813bd1963SGregory Neil Shapiro anynet_ntoa(&RealHostAddr));
147913bd1963SGregory Neil Shapiro tempfail = true;
148013bd1963SGregory Neil Shapiro smtp.sm_milterize = false;
148113bd1963SGregory Neil Shapiro message("421 4.7.0 %s closing connection",
148213bd1963SGregory Neil Shapiro MyHostName);
148313bd1963SGregory Neil Shapiro
148413bd1963SGregory Neil Shapiro /* arrange to ignore send list */
148513bd1963SGregory Neil Shapiro e->e_sendqueue = NULL;
1486*d39bd2c1SGregory Neil Shapiro gotodoquit = true;
1487*d39bd2c1SGregory Neil Shapiro goto cmdloop;
148806f25ae9SGregory Neil Shapiro }
148940266059SGregory Neil Shapiro if (response != NULL)
1490da7d7b9cSGregory Neil Shapiro sm_free(response);
149106f25ae9SGregory Neil Shapiro }
149240266059SGregory Neil Shapiro #endif /* MILTER */
149340266059SGregory Neil Shapiro
1494e92d3f3fSGregory Neil Shapiro /*
1495e92d3f3fSGregory Neil Shapiro ** Broken proxies and SMTP slammers
1496e92d3f3fSGregory Neil Shapiro ** push data without waiting, catch them
1497e92d3f3fSGregory Neil Shapiro */
1498e92d3f3fSGregory Neil Shapiro
1499e92d3f3fSGregory Neil Shapiro if (
150040266059SGregory Neil Shapiro #if STARTTLS
1501e92d3f3fSGregory Neil Shapiro !smtps &&
15025b0945b5SGregory Neil Shapiro #endif
1503d0cef73dSGregory Neil Shapiro *greetcode == '2' && nullserver == NULL)
1504e92d3f3fSGregory Neil Shapiro {
1505e92d3f3fSGregory Neil Shapiro time_t msecs = 0;
1506e92d3f3fSGregory Neil Shapiro char **pvp;
1507e92d3f3fSGregory Neil Shapiro char pvpbuf[PSBUFSIZE];
1508e92d3f3fSGregory Neil Shapiro
1509e92d3f3fSGregory Neil Shapiro /* Ask the rulesets how long to pause */
1510e92d3f3fSGregory Neil Shapiro pvp = NULL;
1511e92d3f3fSGregory Neil Shapiro r = rscap("greet_pause", peerhostname,
1512e92d3f3fSGregory Neil Shapiro anynet_ntoa(&RealHostAddr), e,
1513e92d3f3fSGregory Neil Shapiro &pvp, pvpbuf, sizeof(pvpbuf));
1514e92d3f3fSGregory Neil Shapiro if (r == EX_OK && pvp != NULL && pvp[0] != NULL &&
1515e92d3f3fSGregory Neil Shapiro (pvp[0][0] & 0377) == CANONNET && pvp[1] != NULL)
1516e92d3f3fSGregory Neil Shapiro {
1517e92d3f3fSGregory Neil Shapiro msecs = strtol(pvp[1], NULL, 10);
1518e92d3f3fSGregory Neil Shapiro }
1519e92d3f3fSGregory Neil Shapiro
1520e92d3f3fSGregory Neil Shapiro if (msecs > 0)
1521e92d3f3fSGregory Neil Shapiro {
1522*d39bd2c1SGregory Neil Shapiro struct timeval *tp; /* total pause */
1523e92d3f3fSGregory Neil Shapiro
1524*d39bd2c1SGregory Neil Shapiro /* Obey RFC 2821: 4.5.3.2: 220 timeout of 5 minutes (300 seconds) */
1525*d39bd2c1SGregory Neil Shapiro if (msecs >= 300000)
1526*d39bd2c1SGregory Neil Shapiro msecs = 300000;
1527e92d3f3fSGregory Neil Shapiro
1528e92d3f3fSGregory Neil Shapiro /* check if data is on the socket during the pause */
1529*d39bd2c1SGregory Neil Shapiro if ((tp = channel_readable(InChannel, msecs)) != NULL)
1530e92d3f3fSGregory Neil Shapiro {
1531e92d3f3fSGregory Neil Shapiro greetcode = "554";
1532e92d3f3fSGregory Neil Shapiro nullserver = "Command rejected";
1533e92d3f3fSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
1534d0cef73dSGregory Neil Shapiro "rejecting commands from %s [%s] due to pre-greeting traffic after %d seconds",
1535e92d3f3fSGregory Neil Shapiro peerhostname,
1536d0cef73dSGregory Neil Shapiro anynet_ntoa(&RealHostAddr),
1537*d39bd2c1SGregory Neil Shapiro (int) tp->tv_sec +
1538*d39bd2c1SGregory Neil Shapiro (tp->tv_usec >= 500000 ? 1 : 0)
15394e4196cbSGregory Neil Shapiro );
1540e92d3f3fSGregory Neil Shapiro }
1541e92d3f3fSGregory Neil Shapiro }
1542e92d3f3fSGregory Neil Shapiro }
1543e92d3f3fSGregory Neil Shapiro
1544e92d3f3fSGregory Neil Shapiro #if STARTTLS
154540266059SGregory Neil Shapiro /* If this an smtps connection, start TLS now */
154640266059SGregory Neil Shapiro if (smtps)
1547a7ec597cSGregory Neil Shapiro {
15485b0945b5SGregory Neil Shapiro if (!tls_ok_srv || srv_ctx == NULL)
15495b0945b5SGregory Neil Shapiro {
15505b0945b5SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
15515b0945b5SGregory Neil Shapiro "smtps: TLS not available, exiting");
15525b0945b5SGregory Neil Shapiro exit(EX_CONFIG);
15535b0945b5SGregory Neil Shapiro }
1554a7ec597cSGregory Neil Shapiro Errors = 0;
15555b0945b5SGregory Neil Shapiro first = true;
15565b0945b5SGregory Neil Shapiro gothello = false;
15575b0945b5SGregory Neil Shapiro smtp.sm_gotmail = false;
1558*d39bd2c1SGregory Neil Shapiro gotostarttls = true;
1559*d39bd2c1SGregory Neil Shapiro goto cmdloop;
1560a7ec597cSGregory Neil Shapiro }
156140266059SGregory Neil Shapiro
156240266059SGregory Neil Shapiro greeting:
156340266059SGregory Neil Shapiro
156440266059SGregory Neil Shapiro #endif /* STARTTLS */
1565c2aa98e2SPeter Wemm
1566c2aa98e2SPeter Wemm /* output the first line, inserting "ESMTP" as second word */
156740266059SGregory Neil Shapiro if (*greetcode == '5')
1568da7d7b9cSGregory Neil Shapiro (void) sm_snprintf(inp, sizeof(inp), "%s %s", hostname,
1569da7d7b9cSGregory Neil Shapiro greetmsg);
157040266059SGregory Neil Shapiro else
1571d0cef73dSGregory Neil Shapiro expand(SmtpGreeting, inp, sizeof(inp), e);
157240266059SGregory Neil Shapiro
1573c2aa98e2SPeter Wemm p = strchr(inp, '\n');
1574c2aa98e2SPeter Wemm if (p != NULL)
1575c2aa98e2SPeter Wemm *p++ = '\0';
1576c2aa98e2SPeter Wemm id = strchr(inp, ' ');
1577c2aa98e2SPeter Wemm if (id == NULL)
1578c2aa98e2SPeter Wemm id = &inp[strlen(inp)];
157906f25ae9SGregory Neil Shapiro if (p == NULL)
1580d0cef73dSGregory Neil Shapiro (void) sm_snprintf(cmdbuf, sizeof(cmdbuf),
158106f25ae9SGregory Neil Shapiro "%s %%.*s ESMTP%%s", greetcode);
158206f25ae9SGregory Neil Shapiro else
1583d0cef73dSGregory Neil Shapiro (void) sm_snprintf(cmdbuf, sizeof(cmdbuf),
158406f25ae9SGregory Neil Shapiro "%s-%%.*s ESMTP%%s", greetcode);
158542e5d165SGregory Neil Shapiro message(cmdbuf, (int) (id - inp), inp, id);
1586c2aa98e2SPeter Wemm
1587c2aa98e2SPeter Wemm /* output remaining lines */
1588c2aa98e2SPeter Wemm while ((id = p) != NULL && (p = strchr(id, '\n')) != NULL)
1589c2aa98e2SPeter Wemm {
1590c2aa98e2SPeter Wemm *p++ = '\0';
15915b0945b5SGregory Neil Shapiro if (SM_ISSPACE(*id))
1592c2aa98e2SPeter Wemm id++;
1593d0cef73dSGregory Neil Shapiro (void) sm_strlcpyn(cmdbuf, sizeof(cmdbuf), 2, greetcode, "-%s");
159406f25ae9SGregory Neil Shapiro message(cmdbuf, id);
1595c2aa98e2SPeter Wemm }
1596c2aa98e2SPeter Wemm if (id != NULL)
1597c2aa98e2SPeter Wemm {
15985b0945b5SGregory Neil Shapiro if (SM_ISSPACE(*id))
1599c2aa98e2SPeter Wemm id++;
1600d0cef73dSGregory Neil Shapiro (void) sm_strlcpyn(cmdbuf, sizeof(cmdbuf), 2, greetcode, " %s");
160106f25ae9SGregory Neil Shapiro message(cmdbuf, id);
1602c2aa98e2SPeter Wemm }
1603c2aa98e2SPeter Wemm
1604c2aa98e2SPeter Wemm protocol = NULL;
1605c2aa98e2SPeter Wemm sendinghost = macvalue('s', e);
160640266059SGregory Neil Shapiro
160740266059SGregory Neil Shapiro /* If quarantining by a connect/ehlo action, save between messages */
160840266059SGregory Neil Shapiro if (e->e_quarmsg == NULL)
160940266059SGregory Neil Shapiro smtp.sm_quarmsg = NULL;
161040266059SGregory Neil Shapiro else
161140266059SGregory Neil Shapiro smtp.sm_quarmsg = newstr(e->e_quarmsg);
161240266059SGregory Neil Shapiro
161340266059SGregory Neil Shapiro /* sendinghost's storage must outlive the current envelope */
161440266059SGregory Neil Shapiro if (sendinghost != NULL)
161540266059SGregory Neil Shapiro sendinghost = sm_strdup_x(sendinghost);
161640266059SGregory Neil Shapiro first = true;
161740266059SGregory Neil Shapiro gothello = false;
161840266059SGregory Neil Shapiro smtp.sm_gotmail = false;
1619c2aa98e2SPeter Wemm for (;;)
1620c2aa98e2SPeter Wemm {
1621*d39bd2c1SGregory Neil Shapiro
1622*d39bd2c1SGregory Neil Shapiro cmdloop:
162340266059SGregory Neil Shapiro SM_TRY
162440266059SGregory Neil Shapiro {
162540266059SGregory Neil Shapiro QuickAbort = false;
162640266059SGregory Neil Shapiro HoldErrs = false;
162740266059SGregory Neil Shapiro SuprErrs = false;
162840266059SGregory Neil Shapiro LogUsrErrs = false;
162940266059SGregory Neil Shapiro OnlyOneError = true;
1630c2aa98e2SPeter Wemm e->e_flags &= ~(EF_VRFYONLY|EF_GLOBALERRS);
1631d0cef73dSGregory Neil Shapiro #if MILTER
1632d0cef73dSGregory Neil Shapiro milter_cmd_fail = false;
16335b0945b5SGregory Neil Shapiro #endif
1634c2aa98e2SPeter Wemm
1635c2aa98e2SPeter Wemm /* setup for the read */
1636c2aa98e2SPeter Wemm e->e_to = NULL;
1637c2aa98e2SPeter Wemm Errors = 0;
163806f25ae9SGregory Neil Shapiro FileName = NULL;
163940266059SGregory Neil Shapiro (void) sm_io_flush(smioout, SM_TIME_DEFAULT);
1640c2aa98e2SPeter Wemm
1641*d39bd2c1SGregory Neil Shapiro if (gotodoquit)
1642*d39bd2c1SGregory Neil Shapiro {
1643*d39bd2c1SGregory Neil Shapiro gotodoquit = false;
1644*d39bd2c1SGregory Neil Shapiro goto doquit;
1645*d39bd2c1SGregory Neil Shapiro }
1646*d39bd2c1SGregory Neil Shapiro #if STARTTLS
1647*d39bd2c1SGregory Neil Shapiro if (gotostarttls)
1648*d39bd2c1SGregory Neil Shapiro {
1649*d39bd2c1SGregory Neil Shapiro gotostarttls = false;
1650*d39bd2c1SGregory Neil Shapiro goto starttls;
1651*d39bd2c1SGregory Neil Shapiro }
1652*d39bd2c1SGregory Neil Shapiro #endif
1653*d39bd2c1SGregory Neil Shapiro
1654c2aa98e2SPeter Wemm /* read the input line */
1655c2aa98e2SPeter Wemm SmtpPhase = "server cmd read";
165640266059SGregory Neil Shapiro sm_setproctitle(true, e, "server %s cmd read", CurSmtpClient);
1657c2aa98e2SPeter Wemm
1658c2aa98e2SPeter Wemm /* handle errors */
165940266059SGregory Neil Shapiro if (sm_io_error(OutChannel) ||
1660d0cef73dSGregory Neil Shapiro (p = sfgets(inp, sizeof(inp), InChannel,
166106f25ae9SGregory Neil Shapiro TimeOuts.to_nextcommand, SmtpPhase)) == NULL)
1662c2aa98e2SPeter Wemm {
166306f25ae9SGregory Neil Shapiro char *d;
166406f25ae9SGregory Neil Shapiro
166540266059SGregory Neil Shapiro d = macvalue(macid("{daemon_name}"), e);
166606f25ae9SGregory Neil Shapiro if (d == NULL)
166706f25ae9SGregory Neil Shapiro d = "stdin";
1668c2aa98e2SPeter Wemm /* end of file, just die */
1669c2aa98e2SPeter Wemm disconnect(1, e);
167006f25ae9SGregory Neil Shapiro
167140266059SGregory Neil Shapiro #if MILTER
167206f25ae9SGregory Neil Shapiro /* close out milter filters */
167306f25ae9SGregory Neil Shapiro milter_quit(e);
16745b0945b5SGregory Neil Shapiro #endif
167506f25ae9SGregory Neil Shapiro
167606f25ae9SGregory Neil Shapiro message("421 4.4.1 %s Lost input channel from %s",
1677c2aa98e2SPeter Wemm MyHostName, CurSmtpClient);
167840266059SGregory Neil Shapiro if (LogLevel > (smtp.sm_gotmail ? 1 : 19))
1679c2aa98e2SPeter Wemm sm_syslog(LOG_NOTICE, e->e_id,
168013bd1963SGregory Neil Shapiro "lost input channel from %s to %s after %s",
168106f25ae9SGregory Neil Shapiro CurSmtpClient, d,
168206f25ae9SGregory Neil Shapiro (c == NULL || c->cmd_name == NULL) ? "startup" : c->cmd_name);
1683c2aa98e2SPeter Wemm /*
1684c2aa98e2SPeter Wemm ** If have not accepted mail (DATA), do not bounce
1685c2aa98e2SPeter Wemm ** bad addresses back to sender.
1686c2aa98e2SPeter Wemm */
168706f25ae9SGregory Neil Shapiro
1688c2aa98e2SPeter Wemm if (bitset(EF_CLRQUEUE, e->e_flags))
1689c2aa98e2SPeter Wemm e->e_sendqueue = NULL;
169006f25ae9SGregory Neil Shapiro goto doquit;
1691c2aa98e2SPeter Wemm }
1692c2aa98e2SPeter Wemm
1693d0cef73dSGregory Neil Shapiro /* also used by "proxy" check below */
1694d0cef73dSGregory Neil Shapiro inplen = strlen(inp);
1695d0cef73dSGregory Neil Shapiro #if SASL
1696d0cef73dSGregory Neil Shapiro /*
1697d0cef73dSGregory Neil Shapiro ** SMTP AUTH requires accepting any length,
1698d0cef73dSGregory Neil Shapiro ** at least for challenge/response. However, not imposing
1699d0cef73dSGregory Neil Shapiro ** a limit is a bad idea (denial of service).
1700d0cef73dSGregory Neil Shapiro */
1701d0cef73dSGregory Neil Shapiro
1702d0cef73dSGregory Neil Shapiro if (authenticating != SASL_PROC_AUTH
1703d0cef73dSGregory Neil Shapiro && sm_strncasecmp(inp, "AUTH ", 5) != 0
1704d0cef73dSGregory Neil Shapiro && inplen > MAXLINE)
1705d0cef73dSGregory Neil Shapiro {
1706d0cef73dSGregory Neil Shapiro message("421 4.7.0 %s Command too long, possible attack %s",
1707d0cef73dSGregory Neil Shapiro MyHostName, CurSmtpClient);
1708d0cef73dSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
1709d0cef73dSGregory Neil Shapiro "%s: SMTP violation, input too long: %lu",
1710d0cef73dSGregory Neil Shapiro CurSmtpClient, (unsigned long) inplen);
1711d0cef73dSGregory Neil Shapiro goto doquit;
1712d0cef73dSGregory Neil Shapiro }
1713d0cef73dSGregory Neil Shapiro #endif /* SASL */
1714d0cef73dSGregory Neil Shapiro
17152fb4f839SGregory Neil Shapiro if (first || bitset(SRV_NO_HTTP_CMD, features))
171640266059SGregory Neil Shapiro {
1717d0cef73dSGregory Neil Shapiro size_t cmdlen;
171813bd1963SGregory Neil Shapiro int idx;
171913bd1963SGregory Neil Shapiro char *http_cmd;
172013bd1963SGregory Neil Shapiro static char *http_cmds[] = { "GET", "POST",
172113bd1963SGregory Neil Shapiro "CONNECT", "USER", NULL };
172213bd1963SGregory Neil Shapiro
172313bd1963SGregory Neil Shapiro for (idx = 0; (http_cmd = http_cmds[idx]) != NULL;
172413bd1963SGregory Neil Shapiro idx++)
172513bd1963SGregory Neil Shapiro {
172613bd1963SGregory Neil Shapiro cmdlen = strlen(http_cmd);
172713bd1963SGregory Neil Shapiro if (cmdlen < inplen &&
172813bd1963SGregory Neil Shapiro sm_strncasecmp(inp, http_cmd, cmdlen) == 0 &&
17295b0945b5SGregory Neil Shapiro SM_ISSPACE(inp[cmdlen]))
173013bd1963SGregory Neil Shapiro {
173113bd1963SGregory Neil Shapiro /* Open proxy, drop it */
17322fb4f839SGregory Neil Shapiro message("421 4.7.0 %s %s %s",
17332fb4f839SGregory Neil Shapiro MyHostName,
17342fb4f839SGregory Neil Shapiro first ? "Rejecting open proxy"
17352fb4f839SGregory Neil Shapiro : "HTTP command",
17362fb4f839SGregory Neil Shapiro CurSmtpClient);
173713bd1963SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
173813bd1963SGregory Neil Shapiro "%s: probable open proxy: command=%.40s",
173913bd1963SGregory Neil Shapiro CurSmtpClient, inp);
174013bd1963SGregory Neil Shapiro goto doquit;
174113bd1963SGregory Neil Shapiro }
174213bd1963SGregory Neil Shapiro }
174340266059SGregory Neil Shapiro first = false;
174440266059SGregory Neil Shapiro }
174540266059SGregory Neil Shapiro
1746c2aa98e2SPeter Wemm /* clean up end of line */
174740266059SGregory Neil Shapiro fixcrlf(inp, true);
174840266059SGregory Neil Shapiro
1749*d39bd2c1SGregory Neil Shapiro #if PIPELINING && _FFR_NO_PIPE
175040266059SGregory Neil Shapiro /*
175140266059SGregory Neil Shapiro ** if there is more input and pipelining is disabled:
175240266059SGregory Neil Shapiro ** delay ... (and maybe discard the input?)
175340266059SGregory Neil Shapiro */
175440266059SGregory Neil Shapiro
175540266059SGregory Neil Shapiro if (bitset(SRV_NO_PIPE, features) &&
175613bd1963SGregory Neil Shapiro sm_io_getinfo(InChannel, SM_IO_IS_READABLE, NULL) > 0)
175740266059SGregory Neil Shapiro {
175840266059SGregory Neil Shapiro if (++np_log < 3)
175940266059SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID,
17609bd497b8SGregory Neil Shapiro "unauthorized PIPELINING, sleeping, relay=%.100s",
17619bd497b8SGregory Neil Shapiro CurSmtpClient);
176240266059SGregory Neil Shapiro sleep(1);
176340266059SGregory Neil Shapiro }
1764*d39bd2c1SGregory Neil Shapiro #endif /* PIPELINING && _FFR_NO_PIPE */
1765c2aa98e2SPeter Wemm
176606f25ae9SGregory Neil Shapiro #if SASL
176706f25ae9SGregory Neil Shapiro if (authenticating == SASL_PROC_AUTH)
176806f25ae9SGregory Neil Shapiro {
176906f25ae9SGregory Neil Shapiro # if 0
177006f25ae9SGregory Neil Shapiro if (*inp == '\0')
177106f25ae9SGregory Neil Shapiro {
177206f25ae9SGregory Neil Shapiro authenticating = SASL_NOT_AUTH;
177306f25ae9SGregory Neil Shapiro message("501 5.5.2 missing input");
1774a7ec597cSGregory Neil Shapiro RESET_SASLCONN;
177506f25ae9SGregory Neil Shapiro continue;
177606f25ae9SGregory Neil Shapiro }
177706f25ae9SGregory Neil Shapiro # endif /* 0 */
177806f25ae9SGregory Neil Shapiro if (*inp == '*' && *(inp + 1) == '\0')
177906f25ae9SGregory Neil Shapiro {
178006f25ae9SGregory Neil Shapiro authenticating = SASL_NOT_AUTH;
178106f25ae9SGregory Neil Shapiro
1782ffb83623SGregory Neil Shapiro /* RFC 2554 4. */
178306f25ae9SGregory Neil Shapiro message("501 5.0.0 AUTH aborted");
1784a7ec597cSGregory Neil Shapiro RESET_SASLCONN;
178506f25ae9SGregory Neil Shapiro continue;
178606f25ae9SGregory Neil Shapiro }
178706f25ae9SGregory Neil Shapiro
178806f25ae9SGregory Neil Shapiro /* could this be shorter? XXX */
178994c01205SGregory Neil Shapiro # if SASL >= 20000
179094c01205SGregory Neil Shapiro in = xalloc(strlen(inp) + 1);
179194c01205SGregory Neil Shapiro result = sasl_decode64(inp, strlen(inp), in,
179294c01205SGregory Neil Shapiro strlen(inp), &inlen);
179394c01205SGregory Neil Shapiro # else /* SASL >= 20000 */
179406f25ae9SGregory Neil Shapiro out = xalloc(strlen(inp));
179506f25ae9SGregory Neil Shapiro result = sasl_decode64(inp, strlen(inp), out, &outlen);
179694c01205SGregory Neil Shapiro # endif /* SASL >= 20000 */
179706f25ae9SGregory Neil Shapiro if (result != SASL_OK)
179806f25ae9SGregory Neil Shapiro {
179906f25ae9SGregory Neil Shapiro authenticating = SASL_NOT_AUTH;
180006f25ae9SGregory Neil Shapiro
1801ffb83623SGregory Neil Shapiro /* RFC 2554 4. */
180206f25ae9SGregory Neil Shapiro message("501 5.5.4 cannot decode AUTH parameter %s",
180306f25ae9SGregory Neil Shapiro inp);
180494c01205SGregory Neil Shapiro # if SASL >= 20000
180594c01205SGregory Neil Shapiro sm_free(in);
18065b0945b5SGregory Neil Shapiro # endif
1807a7ec597cSGregory Neil Shapiro RESET_SASLCONN;
180806f25ae9SGregory Neil Shapiro continue;
180906f25ae9SGregory Neil Shapiro }
181006f25ae9SGregory Neil Shapiro
181194c01205SGregory Neil Shapiro # if SASL >= 20000
18125b0945b5SGregory Neil Shapiro SET_AUTH_USER_TMP(in, inlen);
181394c01205SGregory Neil Shapiro result = sasl_server_step(conn, in, inlen,
181494c01205SGregory Neil Shapiro &out, &outlen);
181594c01205SGregory Neil Shapiro sm_free(in);
181694c01205SGregory Neil Shapiro # else /* SASL >= 20000 */
18175b0945b5SGregory Neil Shapiro SET_AUTH_USER_TMP(out, outlen);
181806f25ae9SGregory Neil Shapiro result = sasl_server_step(conn, out, outlen,
181906f25ae9SGregory Neil Shapiro &out, &outlen, &errstr);
182094c01205SGregory Neil Shapiro # endif /* SASL >= 20000 */
182106f25ae9SGregory Neil Shapiro
182206f25ae9SGregory Neil Shapiro /* get an OK if we're done */
182306f25ae9SGregory Neil Shapiro if (result == SASL_OK)
182406f25ae9SGregory Neil Shapiro {
182506f25ae9SGregory Neil Shapiro authenticated:
182606f25ae9SGregory Neil Shapiro message("235 2.0.0 OK Authenticated");
182706f25ae9SGregory Neil Shapiro authenticating = SASL_IS_AUTH;
182840266059SGregory Neil Shapiro macdefine(&BlankEnvelope.e_macro, A_TEMP,
182940266059SGregory Neil Shapiro macid("{auth_type}"), auth_type);
183006f25ae9SGregory Neil Shapiro
183194c01205SGregory Neil Shapiro # if SASL >= 20000
183294c01205SGregory Neil Shapiro user = macvalue(macid("{auth_authen}"), e);
183394c01205SGregory Neil Shapiro
183494c01205SGregory Neil Shapiro /* get security strength (features) */
183594c01205SGregory Neil Shapiro result = sasl_getprop(conn, SASL_SSF,
183694c01205SGregory Neil Shapiro (const void **) &ssf);
183794c01205SGregory Neil Shapiro # else /* SASL >= 20000 */
183806f25ae9SGregory Neil Shapiro result = sasl_getprop(conn, SASL_USERNAME,
183906f25ae9SGregory Neil Shapiro (void **)&user);
184006f25ae9SGregory Neil Shapiro if (result != SASL_OK)
184106f25ae9SGregory Neil Shapiro {
184206f25ae9SGregory Neil Shapiro user = "";
184340266059SGregory Neil Shapiro macdefine(&BlankEnvelope.e_macro,
184440266059SGregory Neil Shapiro A_PERM,
184540266059SGregory Neil Shapiro macid("{auth_authen}"), NULL);
184606f25ae9SGregory Neil Shapiro }
184706f25ae9SGregory Neil Shapiro else
184806f25ae9SGregory Neil Shapiro {
184940266059SGregory Neil Shapiro macdefine(&BlankEnvelope.e_macro,
185040266059SGregory Neil Shapiro A_TEMP,
1851e92d3f3fSGregory Neil Shapiro macid("{auth_authen}"),
1852e92d3f3fSGregory Neil Shapiro xtextify(user, "<>\")"));
185306f25ae9SGregory Neil Shapiro }
185406f25ae9SGregory Neil Shapiro
185506f25ae9SGregory Neil Shapiro # if 0
185606f25ae9SGregory Neil Shapiro /* get realm? */
185706f25ae9SGregory Neil Shapiro sasl_getprop(conn, SASL_REALM, (void **) &data);
18585b0945b5SGregory Neil Shapiro # endif
185906f25ae9SGregory Neil Shapiro
186006f25ae9SGregory Neil Shapiro /* get security strength (features) */
186106f25ae9SGregory Neil Shapiro result = sasl_getprop(conn, SASL_SSF,
186206f25ae9SGregory Neil Shapiro (void **) &ssf);
186394c01205SGregory Neil Shapiro # endif /* SASL >= 20000 */
186406f25ae9SGregory Neil Shapiro if (result != SASL_OK)
186506f25ae9SGregory Neil Shapiro {
186640266059SGregory Neil Shapiro macdefine(&BlankEnvelope.e_macro,
186740266059SGregory Neil Shapiro A_PERM,
186840266059SGregory Neil Shapiro macid("{auth_ssf}"), "0");
186906f25ae9SGregory Neil Shapiro ssf = NULL;
187006f25ae9SGregory Neil Shapiro }
187106f25ae9SGregory Neil Shapiro else
187206f25ae9SGregory Neil Shapiro {
187306f25ae9SGregory Neil Shapiro char pbuf[8];
187406f25ae9SGregory Neil Shapiro
1875d0cef73dSGregory Neil Shapiro (void) sm_snprintf(pbuf, sizeof(pbuf),
187640266059SGregory Neil Shapiro "%u", *ssf);
187740266059SGregory Neil Shapiro macdefine(&BlankEnvelope.e_macro,
187840266059SGregory Neil Shapiro A_TEMP,
187940266059SGregory Neil Shapiro macid("{auth_ssf}"), pbuf);
188006f25ae9SGregory Neil Shapiro if (tTd(95, 8))
188140266059SGregory Neil Shapiro sm_dprintf("AUTH auth_ssf: %u\n",
188206f25ae9SGregory Neil Shapiro *ssf);
188306f25ae9SGregory Neil Shapiro }
188440266059SGregory Neil Shapiro
1885da7d7b9cSGregory Neil Shapiro protocol = GET_PROTOCOL();
1886da7d7b9cSGregory Neil Shapiro
188706f25ae9SGregory Neil Shapiro /*
188840266059SGregory Neil Shapiro ** Only switch to encrypted connection
188906f25ae9SGregory Neil Shapiro ** if a security layer has been negotiated
189006f25ae9SGregory Neil Shapiro */
189140266059SGregory Neil Shapiro
189206f25ae9SGregory Neil Shapiro if (ssf != NULL && *ssf > 0)
189306f25ae9SGregory Neil Shapiro {
1894af9557fdSGregory Neil Shapiro int tmo;
1895af9557fdSGregory Neil Shapiro
189606f25ae9SGregory Neil Shapiro /*
189740266059SGregory Neil Shapiro ** Convert I/O layer to use SASL.
189840266059SGregory Neil Shapiro ** If the call fails, the connection
189940266059SGregory Neil Shapiro ** is aborted.
190006f25ae9SGregory Neil Shapiro */
190140266059SGregory Neil Shapiro
1902af9557fdSGregory Neil Shapiro tmo = TimeOuts.to_datablock * 1000;
190340266059SGregory Neil Shapiro if (sfdcsasl(&InChannel, &OutChannel,
1904af9557fdSGregory Neil Shapiro conn, tmo) == 0)
190506f25ae9SGregory Neil Shapiro {
190606f25ae9SGregory Neil Shapiro /* restart dialogue */
190706f25ae9SGregory Neil Shapiro n_helo = 0;
190840266059SGregory Neil Shapiro # if PIPELINING
190940266059SGregory Neil Shapiro (void) sm_io_autoflush(InChannel,
191040266059SGregory Neil Shapiro OutChannel);
191140266059SGregory Neil Shapiro # endif /* PIPELINING */
191206f25ae9SGregory Neil Shapiro }
191306f25ae9SGregory Neil Shapiro else
191406f25ae9SGregory Neil Shapiro syserr("503 5.3.3 SASL TLS failed");
191506f25ae9SGregory Neil Shapiro }
191640266059SGregory Neil Shapiro
191740266059SGregory Neil Shapiro /* NULL pointer ok since it's our function */
191840266059SGregory Neil Shapiro if (LogLevel > 8)
191906f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID,
192013bd1963SGregory Neil Shapiro "AUTH=server, relay=%s, authid=%.128s, mech=%.16s, bits=%d",
192140266059SGregory Neil Shapiro CurSmtpClient,
192240266059SGregory Neil Shapiro shortenstring(user, 128),
192340266059SGregory Neil Shapiro auth_type, *ssf);
192406f25ae9SGregory Neil Shapiro }
192506f25ae9SGregory Neil Shapiro else if (result == SASL_CONTINUE)
192606f25ae9SGregory Neil Shapiro {
19275b0945b5SGregory Neil Shapiro SET_AUTH_USER;
19285b0945b5SGregory Neil Shapiro
192906f25ae9SGregory Neil Shapiro len = ENC64LEN(outlen);
193006f25ae9SGregory Neil Shapiro out2 = xalloc(len);
193106f25ae9SGregory Neil Shapiro result = sasl_encode64(out, outlen, out2, len,
193240266059SGregory Neil Shapiro &out2len);
193306f25ae9SGregory Neil Shapiro if (result != SASL_OK)
193406f25ae9SGregory Neil Shapiro {
193506f25ae9SGregory Neil Shapiro /* correct code? XXX */
193606f25ae9SGregory Neil Shapiro /* 454 Temp. authentication failure */
193706f25ae9SGregory Neil Shapiro message("454 4.5.4 Internal error: unable to encode64");
193806f25ae9SGregory Neil Shapiro if (LogLevel > 5)
193906f25ae9SGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id,
19409bd497b8SGregory Neil Shapiro "AUTH encode64 error [%d for \"%s\"], relay=%.100s",
19419bd497b8SGregory Neil Shapiro result, out,
19429bd497b8SGregory Neil Shapiro CurSmtpClient);
194306f25ae9SGregory Neil Shapiro /* start over? */
194406f25ae9SGregory Neil Shapiro authenticating = SASL_NOT_AUTH;
194506f25ae9SGregory Neil Shapiro }
194606f25ae9SGregory Neil Shapiro else
194706f25ae9SGregory Neil Shapiro {
194806f25ae9SGregory Neil Shapiro message("334 %s", out2);
194906f25ae9SGregory Neil Shapiro if (tTd(95, 2))
195040266059SGregory Neil Shapiro sm_dprintf("AUTH continue: msg='%s' len=%u\n",
195106f25ae9SGregory Neil Shapiro out2, out2len);
195206f25ae9SGregory Neil Shapiro }
195394c01205SGregory Neil Shapiro # if SASL >= 20000
195494c01205SGregory Neil Shapiro sm_free(out2);
19555b0945b5SGregory Neil Shapiro # endif
195606f25ae9SGregory Neil Shapiro }
195706f25ae9SGregory Neil Shapiro else
195806f25ae9SGregory Neil Shapiro {
19595b0945b5SGregory Neil Shapiro
196094c01205SGregory Neil Shapiro # if SASL >= 20000
19615b0945b5SGregory Neil Shapiro # define SASLERR sasl_errdetail(conn)
19625b0945b5SGregory Neil Shapiro # else
19635b0945b5SGregory Neil Shapiro # define SASLERR errstr == NULL ? "" : errstr
19645b0945b5SGregory Neil Shapiro # endif
19655b0945b5SGregory Neil Shapiro #define LOGAUTHFAIL \
19665b0945b5SGregory Neil Shapiro do \
19675b0945b5SGregory Neil Shapiro { \
19685b0945b5SGregory Neil Shapiro SET_AUTH_USER_CONDITIONALLY \
19695b0945b5SGregory Neil Shapiro message("535 5.7.0 authentication failed"); \
19705b0945b5SGregory Neil Shapiro if (LogLevel >= 9) \
19715b0945b5SGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id, \
19725b0945b5SGregory Neil Shapiro "AUTH failure (%s): %s (%d) %s%s%.*s, relay=%.100s", \
19735b0945b5SGregory Neil Shapiro (auth_type != NULL) ? auth_type : "unknown", \
19745b0945b5SGregory Neil Shapiro sasl_errstring(result, NULL, NULL), \
19755b0945b5SGregory Neil Shapiro result, \
19765b0945b5SGregory Neil Shapiro SASLERR, \
19775b0945b5SGregory Neil Shapiro LOG_AUTH_FAIL_USER, \
19785b0945b5SGregory Neil Shapiro CurSmtpClient); \
19795b0945b5SGregory Neil Shapiro RESET_SASLCONN; \
19805b0945b5SGregory Neil Shapiro } while (0)
19815b0945b5SGregory Neil Shapiro
19825b0945b5SGregory Neil Shapiro
19835b0945b5SGregory Neil Shapiro LOGAUTHFAIL;
198406f25ae9SGregory Neil Shapiro authenticating = SASL_NOT_AUTH;
198506f25ae9SGregory Neil Shapiro }
198606f25ae9SGregory Neil Shapiro }
198706f25ae9SGregory Neil Shapiro else
198806f25ae9SGregory Neil Shapiro {
198906f25ae9SGregory Neil Shapiro /* don't want to do any of this if authenticating */
199006f25ae9SGregory Neil Shapiro #endif /* SASL */
199106f25ae9SGregory Neil Shapiro
1992c2aa98e2SPeter Wemm /* echo command to transcript */
1993c2aa98e2SPeter Wemm if (e->e_xfp != NULL)
199440266059SGregory Neil Shapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT,
199540266059SGregory Neil Shapiro "<<< %s\n", inp);
1996c2aa98e2SPeter Wemm
199740266059SGregory Neil Shapiro if (LogLevel > 14)
199840266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "<-- %s", inp);
1999c2aa98e2SPeter Wemm
2000c2aa98e2SPeter Wemm /* break off command */
20015b0945b5SGregory Neil Shapiro for (p = inp; SM_ISSPACE(*p); p++)
2002c2aa98e2SPeter Wemm continue;
2003c2aa98e2SPeter Wemm cmd = cmdbuf;
2004c2aa98e2SPeter Wemm while (*p != '\0' &&
20055b0945b5SGregory Neil Shapiro !(SM_ISSPACE(*p)) &&
2006d0cef73dSGregory Neil Shapiro cmd < &cmdbuf[sizeof(cmdbuf) - 2])
2007c2aa98e2SPeter Wemm *cmd++ = *p++;
2008c2aa98e2SPeter Wemm *cmd = '\0';
2009c2aa98e2SPeter Wemm
2010c2aa98e2SPeter Wemm /* throw away leading whitespace */
201140266059SGregory Neil Shapiro SKIP_SPACE(p);
2012c2aa98e2SPeter Wemm
2013c2aa98e2SPeter Wemm /* decode command */
201406f25ae9SGregory Neil Shapiro for (c = CmdTab; c->cmd_name != NULL; c++)
2015c2aa98e2SPeter Wemm {
20162fb4f839SGregory Neil Shapiro if (SM_STRCASEEQ(c->cmd_name, cmdbuf))
2017c2aa98e2SPeter Wemm break;
2018c2aa98e2SPeter Wemm }
2019c2aa98e2SPeter Wemm
2020c2aa98e2SPeter Wemm /* reset errors */
2021c2aa98e2SPeter Wemm errno = 0;
2022c2aa98e2SPeter Wemm
202340266059SGregory Neil Shapiro /* check whether a "non-null" command has been used */
202440266059SGregory Neil Shapiro switch (c->cmd_code)
202540266059SGregory Neil Shapiro {
202640266059SGregory Neil Shapiro #if SASL
202740266059SGregory Neil Shapiro case CMDAUTH:
202840266059SGregory Neil Shapiro /* avoid information leak; take first two words? */
202940266059SGregory Neil Shapiro q = "AUTH";
203040266059SGregory Neil Shapiro break;
203140266059SGregory Neil Shapiro #endif /* SASL */
203240266059SGregory Neil Shapiro
203340266059SGregory Neil Shapiro case CMDMAIL:
203440266059SGregory Neil Shapiro case CMDEXPN:
203540266059SGregory Neil Shapiro case CMDVRFY:
203640266059SGregory Neil Shapiro case CMDETRN:
203740266059SGregory Neil Shapiro lognullconnection = false;
203840266059SGregory Neil Shapiro /* FALLTHROUGH */
203940266059SGregory Neil Shapiro default:
204040266059SGregory Neil Shapiro q = inp;
204140266059SGregory Neil Shapiro break;
204240266059SGregory Neil Shapiro }
204340266059SGregory Neil Shapiro
204440266059SGregory Neil Shapiro if (e->e_id == NULL)
204540266059SGregory Neil Shapiro sm_setproctitle(true, e, "%s: %.80s",
204640266059SGregory Neil Shapiro CurSmtpClient, q);
204740266059SGregory Neil Shapiro else
204840266059SGregory Neil Shapiro sm_setproctitle(true, e, "%s %s: %.80s",
204940266059SGregory Neil Shapiro qid_printname(e),
205040266059SGregory Neil Shapiro CurSmtpClient, q);
205140266059SGregory Neil Shapiro
2052c2aa98e2SPeter Wemm /*
2053c2aa98e2SPeter Wemm ** Process command.
2054c2aa98e2SPeter Wemm **
2055c2aa98e2SPeter Wemm ** If we are running as a null server, return 550
205640266059SGregory Neil Shapiro ** to almost everything.
2057c2aa98e2SPeter Wemm */
2058c2aa98e2SPeter Wemm
205906f25ae9SGregory Neil Shapiro if (nullserver != NULL || bitnset(D_ETRNONLY, d_flags))
2060c2aa98e2SPeter Wemm {
206106f25ae9SGregory Neil Shapiro switch (c->cmd_code)
2062c2aa98e2SPeter Wemm {
2063c2aa98e2SPeter Wemm case CMDQUIT:
2064c2aa98e2SPeter Wemm case CMDHELO:
2065c2aa98e2SPeter Wemm case CMDEHLO:
2066c2aa98e2SPeter Wemm case CMDNOOP:
206706f25ae9SGregory Neil Shapiro case CMDRSET:
2068323f6dcbSGregory Neil Shapiro case CMDERROR:
2069c2aa98e2SPeter Wemm /* process normally */
2070c2aa98e2SPeter Wemm break;
2071c2aa98e2SPeter Wemm
207206f25ae9SGregory Neil Shapiro case CMDETRN:
207306f25ae9SGregory Neil Shapiro if (bitnset(D_ETRNONLY, d_flags) &&
207406f25ae9SGregory Neil Shapiro nullserver == NULL)
207506f25ae9SGregory Neil Shapiro break;
207640266059SGregory Neil Shapiro DELAY_CONN("ETRN");
207713058a91SGregory Neil Shapiro /* FALLTHROUGH */
207806f25ae9SGregory Neil Shapiro
2079c2aa98e2SPeter Wemm default:
208040266059SGregory Neil Shapiro #if MAXBADCOMMANDS > 0
208140266059SGregory Neil Shapiro /* theoretically this could overflow */
208240266059SGregory Neil Shapiro if (nullserver != NULL &&
208340266059SGregory Neil Shapiro ++n_badcmds > MAXBADCOMMANDS)
208406f25ae9SGregory Neil Shapiro {
208540266059SGregory Neil Shapiro message("421 4.7.0 %s Too many bad commands; closing connection",
208640266059SGregory Neil Shapiro MyHostName);
208740266059SGregory Neil Shapiro
208840266059SGregory Neil Shapiro /* arrange to ignore send list */
208940266059SGregory Neil Shapiro e->e_sendqueue = NULL;
209040266059SGregory Neil Shapiro goto doquit;
209106f25ae9SGregory Neil Shapiro }
209240266059SGregory Neil Shapiro #endif /* MAXBADCOMMANDS > 0 */
209306f25ae9SGregory Neil Shapiro if (nullserver != NULL)
209406f25ae9SGregory Neil Shapiro {
209506f25ae9SGregory Neil Shapiro if (ISSMTPREPLY(nullserver))
20965b0945b5SGregory Neil Shapiro {
20975b0945b5SGregory Neil Shapiro /* Can't use ("%s", ...) due to usrerr() requirements */
209806f25ae9SGregory Neil Shapiro usrerr(nullserver);
20995b0945b5SGregory Neil Shapiro }
210006f25ae9SGregory Neil Shapiro else
21015b0945b5SGregory Neil Shapiro {
210240266059SGregory Neil Shapiro usrerr("550 5.0.0 %s",
210340266059SGregory Neil Shapiro nullserver);
210406f25ae9SGregory Neil Shapiro }
21055b0945b5SGregory Neil Shapiro }
210606f25ae9SGregory Neil Shapiro else
210706f25ae9SGregory Neil Shapiro usrerr("452 4.4.5 Insufficient disk space; try again later");
2108c2aa98e2SPeter Wemm continue;
2109c2aa98e2SPeter Wemm }
2110c2aa98e2SPeter Wemm }
2111c2aa98e2SPeter Wemm
211206f25ae9SGregory Neil Shapiro switch (c->cmd_code)
2113c2aa98e2SPeter Wemm {
211406f25ae9SGregory Neil Shapiro #if SASL
211506f25ae9SGregory Neil Shapiro case CMDAUTH: /* sasl */
211640266059SGregory Neil Shapiro DELAY_CONN("AUTH");
211740266059SGregory Neil Shapiro if (!sasl_ok || n_mechs <= 0)
211806f25ae9SGregory Neil Shapiro {
211906f25ae9SGregory Neil Shapiro message("503 5.3.3 AUTH not available");
212006f25ae9SGregory Neil Shapiro break;
212106f25ae9SGregory Neil Shapiro }
2122*d39bd2c1SGregory Neil Shapiro if (auth_active)
212306f25ae9SGregory Neil Shapiro {
212406f25ae9SGregory Neil Shapiro message("503 5.5.0 Already Authenticated");
212506f25ae9SGregory Neil Shapiro break;
212606f25ae9SGregory Neil Shapiro }
212740266059SGregory Neil Shapiro if (smtp.sm_gotmail)
212806f25ae9SGregory Neil Shapiro {
212906f25ae9SGregory Neil Shapiro message("503 5.5.0 AUTH not permitted during a mail transaction");
213006f25ae9SGregory Neil Shapiro break;
213106f25ae9SGregory Neil Shapiro }
213206f25ae9SGregory Neil Shapiro if (tempfail)
213306f25ae9SGregory Neil Shapiro {
213406f25ae9SGregory Neil Shapiro if (LogLevel > 9)
213506f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
213613bd1963SGregory Neil Shapiro "SMTP AUTH command (%.100s) from %s tempfailed (due to previous checks)",
213706f25ae9SGregory Neil Shapiro p, CurSmtpClient);
2138e92d3f3fSGregory Neil Shapiro usrerr("454 4.3.0 Please try again later");
213906f25ae9SGregory Neil Shapiro break;
214006f25ae9SGregory Neil Shapiro }
214106f25ae9SGregory Neil Shapiro
214240266059SGregory Neil Shapiro ismore = false;
214306f25ae9SGregory Neil Shapiro
214406f25ae9SGregory Neil Shapiro /* crude way to avoid crack attempts */
2145e92d3f3fSGregory Neil Shapiro STOP_IF_ATTACK(checksmtpattack(&n_auth, n_mechs + 1,
2146e92d3f3fSGregory Neil Shapiro true, "AUTH", e));
214706f25ae9SGregory Neil Shapiro
214840266059SGregory Neil Shapiro /* make sure mechanism (p) is a valid string */
214906f25ae9SGregory Neil Shapiro for (q = p; *q != '\0' && isascii(*q); q++)
215006f25ae9SGregory Neil Shapiro {
215106f25ae9SGregory Neil Shapiro if (isspace(*q))
215206f25ae9SGregory Neil Shapiro {
215306f25ae9SGregory Neil Shapiro *q = '\0';
21545b0945b5SGregory Neil Shapiro while (*++q != '\0' && SM_ISSPACE(*q))
215506f25ae9SGregory Neil Shapiro continue;
215606f25ae9SGregory Neil Shapiro *(q - 1) = '\0';
215706f25ae9SGregory Neil Shapiro ismore = (*q != '\0');
215806f25ae9SGregory Neil Shapiro break;
215906f25ae9SGregory Neil Shapiro }
216006f25ae9SGregory Neil Shapiro }
216106f25ae9SGregory Neil Shapiro
216294c01205SGregory Neil Shapiro if (*p == '\0')
216394c01205SGregory Neil Shapiro {
216494c01205SGregory Neil Shapiro message("501 5.5.2 AUTH mechanism must be specified");
216594c01205SGregory Neil Shapiro break;
216694c01205SGregory Neil Shapiro }
216794c01205SGregory Neil Shapiro
216806f25ae9SGregory Neil Shapiro /* check whether mechanism is available */
216906f25ae9SGregory Neil Shapiro if (iteminlist(p, mechlist, " ") == NULL)
217006f25ae9SGregory Neil Shapiro {
217194c01205SGregory Neil Shapiro message("504 5.3.3 AUTH mechanism %.32s not available",
217206f25ae9SGregory Neil Shapiro p);
217306f25ae9SGregory Neil Shapiro break;
217406f25ae9SGregory Neil Shapiro }
217506f25ae9SGregory Neil Shapiro
2176ffb83623SGregory Neil Shapiro /*
2177ffb83623SGregory Neil Shapiro ** RFC 2554 4.
2178ffb83623SGregory Neil Shapiro ** Unlike a zero-length client answer to a
2179ffb83623SGregory Neil Shapiro ** 334 reply, a zero- length initial response
2180ffb83623SGregory Neil Shapiro ** is sent as a single equals sign ("=").
2181ffb83623SGregory Neil Shapiro */
2182ffb83623SGregory Neil Shapiro
2183ffb83623SGregory Neil Shapiro if (ismore && *q == '=' && *(q + 1) == '\0')
2184ffb83623SGregory Neil Shapiro {
2185ffb83623SGregory Neil Shapiro /* will be free()d, don't use in=""; */
2186ffb83623SGregory Neil Shapiro in = xalloc(1);
2187ffb83623SGregory Neil Shapiro *in = '\0';
2188ffb83623SGregory Neil Shapiro inlen = 0;
2189ffb83623SGregory Neil Shapiro }
2190ffb83623SGregory Neil Shapiro else if (ismore)
219106f25ae9SGregory Neil Shapiro {
219206f25ae9SGregory Neil Shapiro /* could this be shorter? XXX */
219394c01205SGregory Neil Shapiro # if SASL >= 20000
219494c01205SGregory Neil Shapiro in = xalloc(strlen(q) + 1);
219594c01205SGregory Neil Shapiro result = sasl_decode64(q, strlen(q), in,
219694c01205SGregory Neil Shapiro strlen(q), &inlen);
219794c01205SGregory Neil Shapiro # else /* SASL >= 20000 */
219840266059SGregory Neil Shapiro in = sm_rpool_malloc(e->e_rpool, strlen(q));
219906f25ae9SGregory Neil Shapiro result = sasl_decode64(q, strlen(q), in,
220040266059SGregory Neil Shapiro &inlen);
220194c01205SGregory Neil Shapiro # endif /* SASL >= 20000 */
22025b0945b5SGregory Neil Shapiro
220306f25ae9SGregory Neil Shapiro if (result != SASL_OK)
220406f25ae9SGregory Neil Shapiro {
220506f25ae9SGregory Neil Shapiro message("501 5.5.4 cannot BASE64 decode '%s'",
220606f25ae9SGregory Neil Shapiro q);
220706f25ae9SGregory Neil Shapiro if (LogLevel > 5)
220806f25ae9SGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id,
22099bd497b8SGregory Neil Shapiro "AUTH decode64 error [%d for \"%s\"], relay=%.100s",
22109bd497b8SGregory Neil Shapiro result, q,
22119bd497b8SGregory Neil Shapiro CurSmtpClient);
221206f25ae9SGregory Neil Shapiro /* start over? */
221306f25ae9SGregory Neil Shapiro authenticating = SASL_NOT_AUTH;
221494c01205SGregory Neil Shapiro # if SASL >= 20000
221594c01205SGregory Neil Shapiro sm_free(in);
22165b0945b5SGregory Neil Shapiro # endif
221706f25ae9SGregory Neil Shapiro in = NULL;
221806f25ae9SGregory Neil Shapiro inlen = 0;
221906f25ae9SGregory Neil Shapiro break;
222006f25ae9SGregory Neil Shapiro }
22215b0945b5SGregory Neil Shapiro SET_AUTH_USER_TMP(in, inlen);
222206f25ae9SGregory Neil Shapiro }
222306f25ae9SGregory Neil Shapiro else
222406f25ae9SGregory Neil Shapiro {
222506f25ae9SGregory Neil Shapiro in = NULL;
222606f25ae9SGregory Neil Shapiro inlen = 0;
222706f25ae9SGregory Neil Shapiro }
222806f25ae9SGregory Neil Shapiro
222906f25ae9SGregory Neil Shapiro /* see if that auth type exists */
223094c01205SGregory Neil Shapiro # if SASL >= 20000
223194c01205SGregory Neil Shapiro result = sasl_server_start(conn, p, in, inlen,
223294c01205SGregory Neil Shapiro &out, &outlen);
22335b0945b5SGregory Neil Shapiro SM_FREE(in);
223494c01205SGregory Neil Shapiro # else /* SASL >= 20000 */
223506f25ae9SGregory Neil Shapiro result = sasl_server_start(conn, p, in, inlen,
223606f25ae9SGregory Neil Shapiro &out, &outlen, &errstr);
223794c01205SGregory Neil Shapiro # endif /* SASL >= 20000 */
223806f25ae9SGregory Neil Shapiro
22395b0945b5SGregory Neil Shapiro if (p != NULL)
22405b0945b5SGregory Neil Shapiro auth_type = newstr(p);
224106f25ae9SGregory Neil Shapiro if (result != SASL_OK && result != SASL_CONTINUE)
224206f25ae9SGregory Neil Shapiro {
22435b0945b5SGregory Neil Shapiro LOGAUTHFAIL;
224406f25ae9SGregory Neil Shapiro break;
224506f25ae9SGregory Neil Shapiro }
224606f25ae9SGregory Neil Shapiro
224706f25ae9SGregory Neil Shapiro if (result == SASL_OK)
224806f25ae9SGregory Neil Shapiro {
224906f25ae9SGregory Neil Shapiro /* ugly, but same code */
225006f25ae9SGregory Neil Shapiro goto authenticated;
225106f25ae9SGregory Neil Shapiro /* authenticated by the initial response */
225206f25ae9SGregory Neil Shapiro }
225306f25ae9SGregory Neil Shapiro
22545b0945b5SGregory Neil Shapiro SET_AUTH_USER;
22555b0945b5SGregory Neil Shapiro
225606f25ae9SGregory Neil Shapiro /* len is at least 2 */
225706f25ae9SGregory Neil Shapiro len = ENC64LEN(outlen);
225806f25ae9SGregory Neil Shapiro out2 = xalloc(len);
225906f25ae9SGregory Neil Shapiro result = sasl_encode64(out, outlen, out2, len,
226040266059SGregory Neil Shapiro &out2len);
226106f25ae9SGregory Neil Shapiro
226206f25ae9SGregory Neil Shapiro if (result != SASL_OK)
226306f25ae9SGregory Neil Shapiro {
226406f25ae9SGregory Neil Shapiro message("454 4.5.4 Temporary authentication failure");
226506f25ae9SGregory Neil Shapiro if (LogLevel > 5)
226606f25ae9SGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id,
226740266059SGregory Neil Shapiro "AUTH encode64 error [%d for \"%s\"]",
226806f25ae9SGregory Neil Shapiro result, out);
226906f25ae9SGregory Neil Shapiro
227006f25ae9SGregory Neil Shapiro /* start over? */
227106f25ae9SGregory Neil Shapiro authenticating = SASL_NOT_AUTH;
2272a7ec597cSGregory Neil Shapiro RESET_SASLCONN;
227306f25ae9SGregory Neil Shapiro }
227406f25ae9SGregory Neil Shapiro else
227506f25ae9SGregory Neil Shapiro {
227606f25ae9SGregory Neil Shapiro message("334 %s", out2);
227706f25ae9SGregory Neil Shapiro authenticating = SASL_PROC_AUTH;
227806f25ae9SGregory Neil Shapiro }
227994c01205SGregory Neil Shapiro # if SASL >= 20000
228094c01205SGregory Neil Shapiro sm_free(out2);
22815b0945b5SGregory Neil Shapiro # endif
228206f25ae9SGregory Neil Shapiro break;
228306f25ae9SGregory Neil Shapiro #endif /* SASL */
228406f25ae9SGregory Neil Shapiro
228506f25ae9SGregory Neil Shapiro #if STARTTLS
228606f25ae9SGregory Neil Shapiro case CMDSTLS: /* starttls */
228740266059SGregory Neil Shapiro DELAY_CONN("STARTTLS");
228806f25ae9SGregory Neil Shapiro if (*p != '\0')
228906f25ae9SGregory Neil Shapiro {
229006f25ae9SGregory Neil Shapiro message("501 5.5.2 Syntax error (no parameters allowed)");
229106f25ae9SGregory Neil Shapiro break;
229206f25ae9SGregory Neil Shapiro }
229340266059SGregory Neil Shapiro if (!bitset(SRV_OFFER_TLS, features))
229406f25ae9SGregory Neil Shapiro {
229506f25ae9SGregory Neil Shapiro message("503 5.5.0 TLS not available");
229606f25ae9SGregory Neil Shapiro break;
229706f25ae9SGregory Neil Shapiro }
22985b0945b5SGregory Neil Shapiro starttls:
22998774250cSGregory Neil Shapiro if (!tls_ok_srv)
230006f25ae9SGregory Neil Shapiro {
230106f25ae9SGregory Neil Shapiro message("454 4.3.3 TLS not available after start");
230206f25ae9SGregory Neil Shapiro break;
230306f25ae9SGregory Neil Shapiro }
230440266059SGregory Neil Shapiro if (smtp.sm_gotmail)
230506f25ae9SGregory Neil Shapiro {
230606f25ae9SGregory Neil Shapiro message("503 5.5.0 TLS not permitted during a mail transaction");
230706f25ae9SGregory Neil Shapiro break;
230806f25ae9SGregory Neil Shapiro }
230906f25ae9SGregory Neil Shapiro if (tempfail)
231006f25ae9SGregory Neil Shapiro {
231106f25ae9SGregory Neil Shapiro if (LogLevel > 9)
231206f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
231313bd1963SGregory Neil Shapiro "SMTP STARTTLS command (%.100s) from %s tempfailed (due to previous checks)",
231406f25ae9SGregory Neil Shapiro p, CurSmtpClient);
2315e92d3f3fSGregory Neil Shapiro usrerr("454 4.7.0 Please try again later");
231606f25ae9SGregory Neil Shapiro break;
231706f25ae9SGregory Neil Shapiro }
23185b0945b5SGregory Neil Shapiro if (!TLS_set_engine(SSLEngine, false))
23196f9c8e5bSGregory Neil Shapiro {
23206f9c8e5bSGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID,
23215b0945b5SGregory Neil Shapiro "STARTTLS=server, engine=%s, TLS_set_engine=failed",
23225b0945b5SGregory Neil Shapiro SSLEngine);
23236f9c8e5bSGregory Neil Shapiro tls_ok_srv = false;
23246f9c8e5bSGregory Neil Shapiro message("454 4.3.3 TLS not available right now");
23256f9c8e5bSGregory Neil Shapiro break;
23266f9c8e5bSGregory Neil Shapiro }
232706f25ae9SGregory Neil Shapiro # if TLS_NO_RSA
232806f25ae9SGregory Neil Shapiro /*
232906f25ae9SGregory Neil Shapiro ** XXX do we need a temp key ?
233006f25ae9SGregory Neil Shapiro */
23315b0945b5SGregory Neil Shapiro # endif
233240266059SGregory Neil Shapiro
233340266059SGregory Neil Shapiro # if TLS_VRFY_PER_CTX
233440266059SGregory Neil Shapiro /*
233540266059SGregory Neil Shapiro ** Note: this sets the verification globally
233640266059SGregory Neil Shapiro ** (per SSL_CTX)
233740266059SGregory Neil Shapiro ** it's ok since it applies only to one transaction
233840266059SGregory Neil Shapiro */
233940266059SGregory Neil Shapiro
234040266059SGregory Neil Shapiro TLS_VERIFY_CLIENT();
234140266059SGregory Neil Shapiro # endif /* TLS_VRFY_PER_CTX */
234240266059SGregory Neil Shapiro
23435b0945b5SGregory Neil Shapiro #define SMTLSFAILED \
23445b0945b5SGregory Neil Shapiro do { \
23455b0945b5SGregory Neil Shapiro SM_SSL_FREE(srv_ssl); \
23465b0945b5SGregory Neil Shapiro goto tls_done; \
23475b0945b5SGregory Neil Shapiro } while (0)
23485b0945b5SGregory Neil Shapiro
234906f25ae9SGregory Neil Shapiro if (srv_ssl != NULL)
235006f25ae9SGregory Neil Shapiro SSL_clear(srv_ssl);
235106f25ae9SGregory Neil Shapiro else if ((srv_ssl = SSL_new(srv_ctx)) == NULL)
235206f25ae9SGregory Neil Shapiro {
235306f25ae9SGregory Neil Shapiro message("454 4.3.3 TLS not available: error generating SSL handle");
23545b0945b5SGregory Neil Shapiro tlslogerr(LOG_WARNING, 8, "server");
235540266059SGregory Neil Shapiro goto tls_done;
235606f25ae9SGregory Neil Shapiro }
2357*d39bd2c1SGregory Neil Shapiro # if DANE
2358*d39bd2c1SGregory Neil Shapiro tlsi_ctx.tlsi_dvc.dane_vrfy_dane_enabled = false;
2359*d39bd2c1SGregory Neil Shapiro tlsi_ctx.tlsi_dvc.dane_vrfy_chk = DANE_NEVER;
2360*d39bd2c1SGregory Neil Shapiro # endif
23612fb4f839SGregory Neil Shapiro if (get_tls_se_features(e, srv_ssl, &tlsi_ctx, true)
23622fb4f839SGregory Neil Shapiro != EX_OK)
2363da7d7b9cSGregory Neil Shapiro {
23642fb4f839SGregory Neil Shapiro /* do not offer too much info to client */
2365*d39bd2c1SGregory Neil Shapiro message("454 4.3.3 TLS currently not available");
23665b0945b5SGregory Neil Shapiro SMTLSFAILED;
23675b0945b5SGregory Neil Shapiro }
23685b0945b5SGregory Neil Shapiro r = SSL_set_ex_data(srv_ssl, TLSsslidx, &tlsi_ctx);
23695b0945b5SGregory Neil Shapiro if (0 == r)
23705b0945b5SGregory Neil Shapiro {
23715b0945b5SGregory Neil Shapiro if (LogLevel > 5)
23725b0945b5SGregory Neil Shapiro {
23735b0945b5SGregory Neil Shapiro sm_syslog(LOG_ERR, NOQID,
2374*d39bd2c1SGregory Neil Shapiro "STARTTLS=server, error: SSL_set_ex_data failed=%d, TLSsslidx=%d",
2375*d39bd2c1SGregory Neil Shapiro r, TLSsslidx);
23765b0945b5SGregory Neil Shapiro tlslogerr(LOG_WARNING, 9, "server");
23775b0945b5SGregory Neil Shapiro }
23785b0945b5SGregory Neil Shapiro SMTLSFAILED;
2379da7d7b9cSGregory Neil Shapiro }
2380da7d7b9cSGregory Neil Shapiro
238140266059SGregory Neil Shapiro # if !TLS_VRFY_PER_CTX
238240266059SGregory Neil Shapiro /*
238340266059SGregory Neil Shapiro ** this could be used if it were possible to set
238440266059SGregory Neil Shapiro ** verification per SSL (connection)
238540266059SGregory Neil Shapiro ** not just per SSL_CTX (global)
238640266059SGregory Neil Shapiro */
238740266059SGregory Neil Shapiro
238840266059SGregory Neil Shapiro TLS_VERIFY_CLIENT();
238940266059SGregory Neil Shapiro # endif /* !TLS_VRFY_PER_CTX */
239040266059SGregory Neil Shapiro
239140266059SGregory Neil Shapiro rfd = sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL);
239240266059SGregory Neil Shapiro wfd = sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL);
239340266059SGregory Neil Shapiro
239442e5d165SGregory Neil Shapiro if (rfd < 0 || wfd < 0 ||
239542e5d165SGregory Neil Shapiro SSL_set_rfd(srv_ssl, rfd) <= 0 ||
239642e5d165SGregory Neil Shapiro SSL_set_wfd(srv_ssl, wfd) <= 0)
239706f25ae9SGregory Neil Shapiro {
239806f25ae9SGregory Neil Shapiro message("454 4.3.3 TLS not available: error set fd");
23995b0945b5SGregory Neil Shapiro SMTLSFAILED;
240006f25ae9SGregory Neil Shapiro }
240140266059SGregory Neil Shapiro if (!smtps)
240206f25ae9SGregory Neil Shapiro message("220 2.0.0 Ready to start TLS");
240340266059SGregory Neil Shapiro # if PIPELINING
240440266059SGregory Neil Shapiro (void) sm_io_flush(OutChannel, SM_TIME_DEFAULT);
24055b0945b5SGregory Neil Shapiro # endif
240640266059SGregory Neil Shapiro
240706f25ae9SGregory Neil Shapiro SSL_set_accept_state(srv_ssl);
240806f25ae9SGregory Neil Shapiro
240940266059SGregory Neil Shapiro tlsstart = curtime();
241006f25ae9SGregory Neil Shapiro
24115b0945b5SGregory Neil Shapiro ssl_err = SSL_ERROR_WANT_READ;
24125b0945b5SGregory Neil Shapiro save_errno = 0;
24135b0945b5SGregory Neil Shapiro do
24145b0945b5SGregory Neil Shapiro {
24155b0945b5SGregory Neil Shapiro tlsret = tls_retry(srv_ssl, rfd, wfd, tlsstart,
24164e4196cbSGregory Neil Shapiro TimeOuts.to_starttls, ssl_err,
24174e4196cbSGregory Neil Shapiro "server");
24185b0945b5SGregory Neil Shapiro if (tlsret <= 0)
24195b0945b5SGregory Neil Shapiro {
242006f25ae9SGregory Neil Shapiro if (LogLevel > 5)
242106f25ae9SGregory Neil Shapiro {
2422ba00ec3dSGregory Neil Shapiro unsigned long l;
2423ba00ec3dSGregory Neil Shapiro const char *sr;
2424ba00ec3dSGregory Neil Shapiro
2425ba00ec3dSGregory Neil Shapiro l = ERR_peek_error();
2426ba00ec3dSGregory Neil Shapiro sr = ERR_reason_error_string(l);
24275b0945b5SGregory Neil Shapiro
242840266059SGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID,
2429ba00ec3dSGregory Neil Shapiro "STARTTLS=server, error: accept failed=%d, reason=%s, SSL_error=%d, errno=%d, retry=%d, relay=%.100s",
2430ba00ec3dSGregory Neil Shapiro r, sr == NULL ? "unknown"
2431ba00ec3dSGregory Neil Shapiro : sr,
24325b0945b5SGregory Neil Shapiro ssl_err, save_errno,
24335b0945b5SGregory Neil Shapiro tlsret, CurSmtpClient);
24345b0945b5SGregory Neil Shapiro tlslogerr(LOG_WARNING, 9, "server");
243506f25ae9SGregory Neil Shapiro }
243640266059SGregory Neil Shapiro tls_ok_srv = false;
24375b0945b5SGregory Neil Shapiro SM_SSL_FREE(srv_ssl);
243806f25ae9SGregory Neil Shapiro
243906f25ae9SGregory Neil Shapiro /*
244006f25ae9SGregory Neil Shapiro ** according to the next draft of
24415b0945b5SGregory Neil Shapiro ** RFC 2487 the connection should
24425b0945b5SGregory Neil Shapiro ** be dropped
24435b0945b5SGregory Neil Shapiro **
24445b0945b5SGregory Neil Shapiro ** arrange to ignore any current
24455b0945b5SGregory Neil Shapiro ** send list
244606f25ae9SGregory Neil Shapiro */
244706f25ae9SGregory Neil Shapiro
244806f25ae9SGregory Neil Shapiro e->e_sendqueue = NULL;
244906f25ae9SGregory Neil Shapiro goto doquit;
245006f25ae9SGregory Neil Shapiro }
245106f25ae9SGregory Neil Shapiro
24525b0945b5SGregory Neil Shapiro r = SSL_accept(srv_ssl);
24535b0945b5SGregory Neil Shapiro save_errno = 0;
24545b0945b5SGregory Neil Shapiro if (r <= 0)
24555b0945b5SGregory Neil Shapiro ssl_err = SSL_get_error(srv_ssl, r);
24565b0945b5SGregory Neil Shapiro } while (r <= 0);
24575b0945b5SGregory Neil Shapiro
245806f25ae9SGregory Neil Shapiro /* ignore return code for now, it's in {verify} */
245940266059SGregory Neil Shapiro (void) tls_get_info(srv_ssl, true,
246040266059SGregory Neil Shapiro CurSmtpClient,
246140266059SGregory Neil Shapiro &BlankEnvelope.e_macro,
246240266059SGregory Neil Shapiro bitset(SRV_VRFY_CLT, features));
246306f25ae9SGregory Neil Shapiro
246406f25ae9SGregory Neil Shapiro /*
246506f25ae9SGregory Neil Shapiro ** call Stls_client to find out whether
246606f25ae9SGregory Neil Shapiro ** to accept the connection from the client
246706f25ae9SGregory Neil Shapiro */
246806f25ae9SGregory Neil Shapiro
246906f25ae9SGregory Neil Shapiro saveQuickAbort = QuickAbort;
247006f25ae9SGregory Neil Shapiro saveSuprErrs = SuprErrs;
247140266059SGregory Neil Shapiro SuprErrs = true;
247240266059SGregory Neil Shapiro QuickAbort = false;
247306f25ae9SGregory Neil Shapiro if (rscheck("tls_client",
247440266059SGregory Neil Shapiro macvalue(macid("{verify}"), e),
2475959366dcSGregory Neil Shapiro "STARTTLS", e,
2476959366dcSGregory Neil Shapiro RSF_RMCOMM|RSF_COUNT,
2477da7d7b9cSGregory Neil Shapiro 5, NULL, NOQID, NULL, NULL) != EX_OK ||
247840266059SGregory Neil Shapiro Errors > 0)
247906f25ae9SGregory Neil Shapiro {
248006f25ae9SGregory Neil Shapiro extern char MsgBuf[];
248106f25ae9SGregory Neil Shapiro
248206f25ae9SGregory Neil Shapiro if (MsgBuf[0] != '\0' && ISSMTPREPLY(MsgBuf))
248306f25ae9SGregory Neil Shapiro nullserver = newstr(MsgBuf);
248406f25ae9SGregory Neil Shapiro else
248506f25ae9SGregory Neil Shapiro nullserver = "503 5.7.0 Authentication required.";
248606f25ae9SGregory Neil Shapiro }
248706f25ae9SGregory Neil Shapiro QuickAbort = saveQuickAbort;
248806f25ae9SGregory Neil Shapiro SuprErrs = saveSuprErrs;
248906f25ae9SGregory Neil Shapiro
249040266059SGregory Neil Shapiro tls_ok_srv = false; /* don't offer STARTTLS again */
24912fb4f839SGregory Neil Shapiro first = true;
249206f25ae9SGregory Neil Shapiro n_helo = 0;
249306f25ae9SGregory Neil Shapiro # if SASL
249406f25ae9SGregory Neil Shapiro if (sasl_ok)
249506f25ae9SGregory Neil Shapiro {
2496e92d3f3fSGregory Neil Shapiro int cipher_bits;
2497e92d3f3fSGregory Neil Shapiro bool verified;
2498e92d3f3fSGregory Neil Shapiro char *s, *v, *c;
249906f25ae9SGregory Neil Shapiro
250040266059SGregory Neil Shapiro s = macvalue(macid("{cipher_bits}"), e);
2501e92d3f3fSGregory Neil Shapiro v = macvalue(macid("{verify}"), e);
2502e92d3f3fSGregory Neil Shapiro c = macvalue(macid("{cert_subject}"), e);
2503e92d3f3fSGregory Neil Shapiro verified = (v != NULL && strcmp(v, "OK") == 0);
2504e92d3f3fSGregory Neil Shapiro if (s != NULL && (cipher_bits = atoi(s)) > 0)
250594c01205SGregory Neil Shapiro {
2506e92d3f3fSGregory Neil Shapiro # if SASL >= 20000
2507e92d3f3fSGregory Neil Shapiro ext_ssf = cipher_bits;
2508e92d3f3fSGregory Neil Shapiro auth_id = verified ? c : NULL;
2509e92d3f3fSGregory Neil Shapiro sasl_ok = ((sasl_setprop(conn,
2510e92d3f3fSGregory Neil Shapiro SASL_SSF_EXTERNAL,
251194c01205SGregory Neil Shapiro &ext_ssf) == SASL_OK) &&
2512e92d3f3fSGregory Neil Shapiro (sasl_setprop(conn,
2513e92d3f3fSGregory Neil Shapiro SASL_AUTH_EXTERNAL,
251494c01205SGregory Neil Shapiro auth_id) == SASL_OK));
251594c01205SGregory Neil Shapiro # else /* SASL >= 20000 */
2516e92d3f3fSGregory Neil Shapiro ext_ssf.ssf = cipher_bits;
2517e92d3f3fSGregory Neil Shapiro ext_ssf.auth_id = verified ? c : NULL;
2518e92d3f3fSGregory Neil Shapiro sasl_ok = sasl_setprop(conn,
2519e92d3f3fSGregory Neil Shapiro SASL_SSF_EXTERNAL,
252006f25ae9SGregory Neil Shapiro &ext_ssf) == SASL_OK;
252194c01205SGregory Neil Shapiro # endif /* SASL >= 20000 */
252206f25ae9SGregory Neil Shapiro mechlist = NULL;
252306f25ae9SGregory Neil Shapiro if (sasl_ok)
252406f25ae9SGregory Neil Shapiro n_mechs = saslmechs(conn,
252506f25ae9SGregory Neil Shapiro &mechlist);
252606f25ae9SGregory Neil Shapiro }
252706f25ae9SGregory Neil Shapiro }
252806f25ae9SGregory Neil Shapiro # endif /* SASL */
252906f25ae9SGregory Neil Shapiro
253006f25ae9SGregory Neil Shapiro /* switch to secure connection */
253140266059SGregory Neil Shapiro if (sfdctls(&InChannel, &OutChannel, srv_ssl) == 0)
253240266059SGregory Neil Shapiro {
253340266059SGregory Neil Shapiro tls_active = true;
253440266059SGregory Neil Shapiro # if PIPELINING
253540266059SGregory Neil Shapiro (void) sm_io_autoflush(InChannel, OutChannel);
25365b0945b5SGregory Neil Shapiro # endif
253740266059SGregory Neil Shapiro }
253806f25ae9SGregory Neil Shapiro else
253906f25ae9SGregory Neil Shapiro {
254006f25ae9SGregory Neil Shapiro /*
254106f25ae9SGregory Neil Shapiro ** XXX this is an internal error
254206f25ae9SGregory Neil Shapiro ** how to deal with it?
254306f25ae9SGregory Neil Shapiro ** we can't generate an error message
254406f25ae9SGregory Neil Shapiro ** since the other side switched to an
254506f25ae9SGregory Neil Shapiro ** encrypted layer, but we could not...
254606f25ae9SGregory Neil Shapiro ** just "hang up"?
254706f25ae9SGregory Neil Shapiro */
254840266059SGregory Neil Shapiro
254906f25ae9SGregory Neil Shapiro nullserver = "454 4.3.3 TLS not available: can't switch to encrypted layer";
255040266059SGregory Neil Shapiro syserr("STARTTLS: can't switch to encrypted layer");
255106f25ae9SGregory Neil Shapiro }
255240266059SGregory Neil Shapiro tls_done:
255340266059SGregory Neil Shapiro if (smtps)
255440266059SGregory Neil Shapiro {
255540266059SGregory Neil Shapiro if (tls_active)
255640266059SGregory Neil Shapiro goto greeting;
255740266059SGregory Neil Shapiro else
255840266059SGregory Neil Shapiro goto doquit;
255940266059SGregory Neil Shapiro }
256006f25ae9SGregory Neil Shapiro break;
256106f25ae9SGregory Neil Shapiro #endif /* STARTTLS */
256206f25ae9SGregory Neil Shapiro
2563c2aa98e2SPeter Wemm case CMDHELO: /* hello -- introduce yourself */
2564c2aa98e2SPeter Wemm case CMDEHLO: /* extended hello */
256540266059SGregory Neil Shapiro DELAY_CONN("EHLO");
256606f25ae9SGregory Neil Shapiro if (c->cmd_code == CMDEHLO)
2567c2aa98e2SPeter Wemm {
2568da7d7b9cSGregory Neil Shapiro protocol = GET_PROTOCOL();
2569c2aa98e2SPeter Wemm SmtpPhase = "server EHLO";
2570c2aa98e2SPeter Wemm }
2571c2aa98e2SPeter Wemm else
2572c2aa98e2SPeter Wemm {
2573c2aa98e2SPeter Wemm protocol = "SMTP";
2574c2aa98e2SPeter Wemm SmtpPhase = "server HELO";
2575c2aa98e2SPeter Wemm }
2576c2aa98e2SPeter Wemm
2577c2aa98e2SPeter Wemm /* avoid denial-of-service */
2578e92d3f3fSGregory Neil Shapiro STOP_IF_ATTACK(checksmtpattack(&n_helo, MAXHELOCOMMANDS,
2579e92d3f3fSGregory Neil Shapiro true, "HELO/EHLO", e));
2580c2aa98e2SPeter Wemm
2581*d39bd2c1SGregory Neil Shapiro /*
2582*d39bd2c1SGregory Neil Shapiro ** Despite the fact that the name indicates this
2583*d39bd2c1SGregory Neil Shapiro ** a PIPELINE related feature, do not enclose
2584*d39bd2c1SGregory Neil Shapiro ** it in #if PIPELINING so we can protect SMTP
2585*d39bd2c1SGregory Neil Shapiro ** servers not compiled with PIPELINE support
2586*d39bd2c1SGregory Neil Shapiro ** from transaction stuffing.
2587*d39bd2c1SGregory Neil Shapiro */
2588*d39bd2c1SGregory Neil Shapiro
2589*d39bd2c1SGregory Neil Shapiro /* check if data is on the socket before the EHLO reply */
2590*d39bd2c1SGregory Neil Shapiro if (bitset(SRV_BAD_PIPELINE, features) &&
2591*d39bd2c1SGregory Neil Shapiro sm_io_getinfo(InChannel, SM_IO_IS_READABLE, NULL) > 0)
2592*d39bd2c1SGregory Neil Shapiro {
2593*d39bd2c1SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
2594*d39bd2c1SGregory Neil Shapiro "rejecting %s from %s [%s] due to traffic before response",
2595*d39bd2c1SGregory Neil Shapiro SmtpPhase, CurHostName,
2596*d39bd2c1SGregory Neil Shapiro anynet_ntoa(&RealHostAddr));
2597*d39bd2c1SGregory Neil Shapiro usrerr("554 5.5.0 SMTP protocol error");
2598*d39bd2c1SGregory Neil Shapiro nullserver = "Command rejected";
2599*d39bd2c1SGregory Neil Shapiro #if MILTER
2600*d39bd2c1SGregory Neil Shapiro smtp.sm_milterize = false;
2601*d39bd2c1SGregory Neil Shapiro #endif
2602*d39bd2c1SGregory Neil Shapiro break;
2603*d39bd2c1SGregory Neil Shapiro }
2604*d39bd2c1SGregory Neil Shapiro
260540266059SGregory Neil Shapiro #if 0
260640266059SGregory Neil Shapiro /* RFC2821 4.1.4 allows duplicate HELO/EHLO */
2607c2aa98e2SPeter Wemm /* check for duplicate HELO/EHLO per RFC 1651 4.2 */
2608c2aa98e2SPeter Wemm if (gothello)
2609c2aa98e2SPeter Wemm {
2610c2aa98e2SPeter Wemm usrerr("503 %s Duplicate HELO/EHLO",
2611c2aa98e2SPeter Wemm MyHostName);
2612c2aa98e2SPeter Wemm break;
2613c2aa98e2SPeter Wemm }
261440266059SGregory Neil Shapiro #endif /* 0 */
2615c2aa98e2SPeter Wemm
2616c2aa98e2SPeter Wemm /* check for valid domain name (re 1123 5.2.5) */
2617c2aa98e2SPeter Wemm if (*p == '\0' && !AllowBogusHELO)
2618c2aa98e2SPeter Wemm {
2619c2aa98e2SPeter Wemm usrerr("501 %s requires domain address",
2620c2aa98e2SPeter Wemm cmdbuf);
2621c2aa98e2SPeter Wemm break;
2622c2aa98e2SPeter Wemm }
2623c2aa98e2SPeter Wemm
2624c2aa98e2SPeter Wemm /* check for long domain name (hides Received: info) */
26252fb4f839SGregory Neil Shapiro if (strlen(p) > MAXNAME) /* EAI:ok:EHLO name must be ASCII */
2626c2aa98e2SPeter Wemm {
2627c2aa98e2SPeter Wemm usrerr("501 Invalid domain name");
262806f25ae9SGregory Neil Shapiro if (LogLevel > 9)
262906f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, CurEnv->e_id,
263013bd1963SGregory Neil Shapiro "invalid domain name (too long) from %s",
263106f25ae9SGregory Neil Shapiro CurSmtpClient);
2632c2aa98e2SPeter Wemm break;
2633c2aa98e2SPeter Wemm }
2634c2aa98e2SPeter Wemm
263594c01205SGregory Neil Shapiro ok = true;
2636c2aa98e2SPeter Wemm for (q = p; *q != '\0'; q++)
2637c2aa98e2SPeter Wemm {
2638c2aa98e2SPeter Wemm if (!isascii(*q))
2639c2aa98e2SPeter Wemm break;
2640c2aa98e2SPeter Wemm if (isalnum(*q))
2641c2aa98e2SPeter Wemm continue;
2642c2aa98e2SPeter Wemm if (isspace(*q))
2643c2aa98e2SPeter Wemm {
2644c2aa98e2SPeter Wemm *q = '\0';
264594c01205SGregory Neil Shapiro
264694c01205SGregory Neil Shapiro /* only complain if strict check */
264794c01205SGregory Neil Shapiro ok = AllowBogusHELO;
2648b6bacd31SGregory Neil Shapiro
2649b6bacd31SGregory Neil Shapiro /* allow trailing whitespace */
2650b6bacd31SGregory Neil Shapiro while (!ok && *++q != '\0' &&
2651b6bacd31SGregory Neil Shapiro isspace(*q))
2652b6bacd31SGregory Neil Shapiro ;
2653b6bacd31SGregory Neil Shapiro if (*q == '\0')
2654b6bacd31SGregory Neil Shapiro ok = true;
2655c2aa98e2SPeter Wemm break;
2656c2aa98e2SPeter Wemm }
2657a7ec597cSGregory Neil Shapiro if (strchr("[].-_#:", *q) == NULL)
2658c2aa98e2SPeter Wemm break;
2659c2aa98e2SPeter Wemm }
266006f25ae9SGregory Neil Shapiro
266194c01205SGregory Neil Shapiro if (*q == '\0' && ok)
2662c2aa98e2SPeter Wemm {
2663c2aa98e2SPeter Wemm q = "pleased to meet you";
266440266059SGregory Neil Shapiro sendinghost = sm_strdup_x(p);
2665c2aa98e2SPeter Wemm }
2666c2aa98e2SPeter Wemm else if (!AllowBogusHELO)
2667c2aa98e2SPeter Wemm {
2668c2aa98e2SPeter Wemm usrerr("501 Invalid domain name");
266906f25ae9SGregory Neil Shapiro if (LogLevel > 9)
267006f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, CurEnv->e_id,
267113bd1963SGregory Neil Shapiro "invalid domain name (%s) from %.100s",
267206f25ae9SGregory Neil Shapiro p, CurSmtpClient);
2673c2aa98e2SPeter Wemm break;
2674c2aa98e2SPeter Wemm }
2675c2aa98e2SPeter Wemm else
2676c2aa98e2SPeter Wemm {
2677c2aa98e2SPeter Wemm q = "accepting invalid domain name";
2678c2aa98e2SPeter Wemm }
2679c2aa98e2SPeter Wemm
26804e4196cbSGregory Neil Shapiro if (gothello || smtp.sm_gotmail)
268140266059SGregory Neil Shapiro CLEAR_STATE(cmdbuf);
268240266059SGregory Neil Shapiro
268340266059SGregory Neil Shapiro #if MILTER
268440266059SGregory Neil Shapiro if (smtp.sm_milterlist && smtp.sm_milterize &&
268540266059SGregory Neil Shapiro !bitset(EF_DISCARD, e->e_flags))
268606f25ae9SGregory Neil Shapiro {
268706f25ae9SGregory Neil Shapiro char state;
268806f25ae9SGregory Neil Shapiro char *response;
268906f25ae9SGregory Neil Shapiro
269006f25ae9SGregory Neil Shapiro response = milter_helo(p, e, &state);
269106f25ae9SGregory Neil Shapiro switch (state)
269206f25ae9SGregory Neil Shapiro {
269306f25ae9SGregory Neil Shapiro case SMFIR_REJECT:
269440266059SGregory Neil Shapiro if (MilterLogLevel > 3)
269540266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
269640266059SGregory Neil Shapiro "Milter: helo=%s, reject=Command rejected",
269740266059SGregory Neil Shapiro p);
269806f25ae9SGregory Neil Shapiro nullserver = "Command rejected";
269940266059SGregory Neil Shapiro smtp.sm_milterize = false;
270006f25ae9SGregory Neil Shapiro break;
270106f25ae9SGregory Neil Shapiro
270206f25ae9SGregory Neil Shapiro case SMFIR_TEMPFAIL:
270340266059SGregory Neil Shapiro if (MilterLogLevel > 3)
270440266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
270540266059SGregory Neil Shapiro "Milter: helo=%s, reject=%s",
270640266059SGregory Neil Shapiro p, MSG_TEMPFAIL);
270740266059SGregory Neil Shapiro tempfail = true;
270840266059SGregory Neil Shapiro smtp.sm_milterize = false;
270906f25ae9SGregory Neil Shapiro break;
27104e4196cbSGregory Neil Shapiro
2711d0cef73dSGregory Neil Shapiro case SMFIR_REPLYCODE:
27124e4196cbSGregory Neil Shapiro if (MilterLogLevel > 3)
27134e4196cbSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
2714d0cef73dSGregory Neil Shapiro "Milter: helo=%s, reject=%s",
2715d0cef73dSGregory Neil Shapiro p, response);
2716d0cef73dSGregory Neil Shapiro if (strncmp(response, "421 ", 4) != 0
2717d0cef73dSGregory Neil Shapiro && strncmp(response, "421-", 4) != 0)
2718d0cef73dSGregory Neil Shapiro {
2719d0cef73dSGregory Neil Shapiro nullserver = newstr(response);
2720d0cef73dSGregory Neil Shapiro smtp.sm_milterize = false;
2721d0cef73dSGregory Neil Shapiro break;
2722d0cef73dSGregory Neil Shapiro }
2723d0cef73dSGregory Neil Shapiro /* FALLTHROUGH */
2724d0cef73dSGregory Neil Shapiro
2725d0cef73dSGregory Neil Shapiro case SMFIR_SHUTDOWN:
2726d0cef73dSGregory Neil Shapiro if (MilterLogLevel > 3 &&
2727d0cef73dSGregory Neil Shapiro response == NULL)
2728d0cef73dSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
2729af9557fdSGregory Neil Shapiro "Milter: helo=%s, reject=421 4.7.0 %s closing connection",
27304e4196cbSGregory Neil Shapiro p, MyHostName);
27314e4196cbSGregory Neil Shapiro tempfail = true;
27324e4196cbSGregory Neil Shapiro smtp.sm_milterize = false;
2733d0cef73dSGregory Neil Shapiro if (response != NULL)
27345b0945b5SGregory Neil Shapiro {
27355b0945b5SGregory Neil Shapiro /* Can't use ("%s", ...) due to usrerr() requirements */
2736d0cef73dSGregory Neil Shapiro usrerr(response);
27375b0945b5SGregory Neil Shapiro }
2738d0cef73dSGregory Neil Shapiro else
27395b0945b5SGregory Neil Shapiro {
27404e4196cbSGregory Neil Shapiro message("421 4.7.0 %s closing connection",
27414e4196cbSGregory Neil Shapiro MyHostName);
27425b0945b5SGregory Neil Shapiro }
27434e4196cbSGregory Neil Shapiro /* arrange to ignore send list */
27444e4196cbSGregory Neil Shapiro e->e_sendqueue = NULL;
2745d0cef73dSGregory Neil Shapiro lognullconnection = false;
27464e4196cbSGregory Neil Shapiro goto doquit;
274706f25ae9SGregory Neil Shapiro }
274840266059SGregory Neil Shapiro if (response != NULL)
274940266059SGregory Neil Shapiro sm_free(response);
275040266059SGregory Neil Shapiro
275140266059SGregory Neil Shapiro /*
275240266059SGregory Neil Shapiro ** If quarantining by a connect/ehlo action,
275340266059SGregory Neil Shapiro ** save between messages
275440266059SGregory Neil Shapiro */
275540266059SGregory Neil Shapiro
275640266059SGregory Neil Shapiro if (smtp.sm_quarmsg == NULL &&
275740266059SGregory Neil Shapiro e->e_quarmsg != NULL)
275840266059SGregory Neil Shapiro smtp.sm_quarmsg = newstr(e->e_quarmsg);
275906f25ae9SGregory Neil Shapiro }
276040266059SGregory Neil Shapiro #endif /* MILTER */
276140266059SGregory Neil Shapiro gothello = true;
276206f25ae9SGregory Neil Shapiro
2763c2aa98e2SPeter Wemm /* print HELO response message */
276406f25ae9SGregory Neil Shapiro if (c->cmd_code != CMDEHLO)
2765c2aa98e2SPeter Wemm {
2766c2aa98e2SPeter Wemm message("250 %s Hello %s, %s",
2767c2aa98e2SPeter Wemm MyHostName, CurSmtpClient, q);
2768c2aa98e2SPeter Wemm break;
2769c2aa98e2SPeter Wemm }
2770c2aa98e2SPeter Wemm
2771c2aa98e2SPeter Wemm message("250-%s Hello %s, %s",
2772c2aa98e2SPeter Wemm MyHostName, CurSmtpClient, q);
2773c2aa98e2SPeter Wemm
277406f25ae9SGregory Neil Shapiro /* offer ENHSC even for nullserver */
277506f25ae9SGregory Neil Shapiro if (nullserver != NULL)
277606f25ae9SGregory Neil Shapiro {
277706f25ae9SGregory Neil Shapiro message("250 ENHANCEDSTATUSCODES");
277806f25ae9SGregory Neil Shapiro break;
277906f25ae9SGregory Neil Shapiro }
278006f25ae9SGregory Neil Shapiro
278142e5d165SGregory Neil Shapiro /*
278242e5d165SGregory Neil Shapiro ** print EHLO features list
278342e5d165SGregory Neil Shapiro **
278442e5d165SGregory Neil Shapiro ** Note: If you change this list,
278542e5d165SGregory Neil Shapiro ** remember to update 'helpfile'
278642e5d165SGregory Neil Shapiro */
278742e5d165SGregory Neil Shapiro
278806f25ae9SGregory Neil Shapiro message("250-ENHANCEDSTATUSCODES");
278940266059SGregory Neil Shapiro #if PIPELINING
279040266059SGregory Neil Shapiro if (bitset(SRV_OFFER_PIPE, features))
279140266059SGregory Neil Shapiro message("250-PIPELINING");
27925b0945b5SGregory Neil Shapiro #endif
279340266059SGregory Neil Shapiro if (bitset(SRV_OFFER_EXPN, features))
2794c2aa98e2SPeter Wemm {
2795c2aa98e2SPeter Wemm message("250-EXPN");
279640266059SGregory Neil Shapiro if (bitset(SRV_OFFER_VERB, features))
2797c2aa98e2SPeter Wemm message("250-VERB");
2798c2aa98e2SPeter Wemm }
2799c2aa98e2SPeter Wemm #if MIME8TO7
2800c2aa98e2SPeter Wemm message("250-8BITMIME");
28015b0945b5SGregory Neil Shapiro #endif
2802c2aa98e2SPeter Wemm if (MaxMessageSize > 0)
2803c2aa98e2SPeter Wemm message("250-SIZE %ld", MaxMessageSize);
2804c2aa98e2SPeter Wemm else
2805c2aa98e2SPeter Wemm message("250-SIZE");
2806c2aa98e2SPeter Wemm #if DSN
280740266059SGregory Neil Shapiro if (SendMIMEErrors && bitset(SRV_OFFER_DSN, features))
2808c2aa98e2SPeter Wemm message("250-DSN");
28095b0945b5SGregory Neil Shapiro #endif
28102fb4f839SGregory Neil Shapiro #if USE_EAI
28115b0945b5SGregory Neil Shapiro if (bitset(SRV_OFFER_EAI, features))
28125b0945b5SGregory Neil Shapiro message("250-SMTPUTF8");
28132fb4f839SGregory Neil Shapiro #endif
281440266059SGregory Neil Shapiro if (bitset(SRV_OFFER_ETRN, features))
2815c2aa98e2SPeter Wemm message("250-ETRN");
281606f25ae9SGregory Neil Shapiro #if SASL
281706f25ae9SGregory Neil Shapiro if (sasl_ok && mechlist != NULL && *mechlist != '\0')
281806f25ae9SGregory Neil Shapiro message("250-AUTH %s", mechlist);
28195b0945b5SGregory Neil Shapiro #endif
282006f25ae9SGregory Neil Shapiro #if STARTTLS
28216f9c8e5bSGregory Neil Shapiro if (tls_ok_srv && bitset(SRV_OFFER_TLS, features))
282206f25ae9SGregory Neil Shapiro message("250-STARTTLS");
28235b0945b5SGregory Neil Shapiro #endif
282440266059SGregory Neil Shapiro if (DeliverByMin > 0)
282540266059SGregory Neil Shapiro message("250-DELIVERBY %ld",
282640266059SGregory Neil Shapiro (long) DeliverByMin);
282740266059SGregory Neil Shapiro else if (DeliverByMin == 0)
282840266059SGregory Neil Shapiro message("250-DELIVERBY");
282940266059SGregory Neil Shapiro
283040266059SGregory Neil Shapiro /* < 0: no deliver-by */
283140266059SGregory Neil Shapiro
2832c2aa98e2SPeter Wemm message("250 HELP");
2833c2aa98e2SPeter Wemm break;
2834c2aa98e2SPeter Wemm
2835c2aa98e2SPeter Wemm case CMDMAIL: /* mail -- designate sender */
2836c2aa98e2SPeter Wemm SmtpPhase = "server MAIL";
283740266059SGregory Neil Shapiro DELAY_CONN("MAIL");
2838c2aa98e2SPeter Wemm
2839c2aa98e2SPeter Wemm /* check for validity of this command */
2840c2aa98e2SPeter Wemm if (!gothello && bitset(PRIV_NEEDMAILHELO, PrivacyFlags))
2841c2aa98e2SPeter Wemm {
284206f25ae9SGregory Neil Shapiro usrerr("503 5.0.0 Polite people say HELO first");
2843c2aa98e2SPeter Wemm break;
2844c2aa98e2SPeter Wemm }
284540266059SGregory Neil Shapiro if (smtp.sm_gotmail)
2846c2aa98e2SPeter Wemm {
284706f25ae9SGregory Neil Shapiro usrerr("503 5.5.0 Sender already specified");
2848c2aa98e2SPeter Wemm break;
2849c2aa98e2SPeter Wemm }
285006f25ae9SGregory Neil Shapiro #if SASL
285140266059SGregory Neil Shapiro if (bitset(SRV_REQ_AUTH, features) &&
285206f25ae9SGregory Neil Shapiro authenticating != SASL_IS_AUTH)
285306f25ae9SGregory Neil Shapiro {
285406f25ae9SGregory Neil Shapiro usrerr("530 5.7.0 Authentication required");
285506f25ae9SGregory Neil Shapiro break;
285606f25ae9SGregory Neil Shapiro }
285706f25ae9SGregory Neil Shapiro #endif /* SASL */
285806f25ae9SGregory Neil Shapiro
285906f25ae9SGregory Neil Shapiro p = skipword(p, "from");
286006f25ae9SGregory Neil Shapiro if (p == NULL)
286106f25ae9SGregory Neil Shapiro break;
2862*d39bd2c1SGregory Neil Shapiro maps_reset_chged("server:MAIL");
286306f25ae9SGregory Neil Shapiro if (tempfail)
286406f25ae9SGregory Neil Shapiro {
286506f25ae9SGregory Neil Shapiro if (LogLevel > 9)
286606f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
286713bd1963SGregory Neil Shapiro "SMTP MAIL command (%.100s) from %s tempfailed (due to previous checks)",
286806f25ae9SGregory Neil Shapiro p, CurSmtpClient);
28695b0945b5SGregory Neil Shapiro /* Can't use ("%s", ...) due to usrerr() requirements */
287040266059SGregory Neil Shapiro usrerr(MSG_TEMPFAIL);
287106f25ae9SGregory Neil Shapiro break;
287206f25ae9SGregory Neil Shapiro }
2873c2aa98e2SPeter Wemm
2874c2aa98e2SPeter Wemm /* make sure we know who the sending host is */
2875c2aa98e2SPeter Wemm if (sendinghost == NULL)
2876c2aa98e2SPeter Wemm sendinghost = peerhostname;
2877c2aa98e2SPeter Wemm
2878c2aa98e2SPeter Wemm
287940266059SGregory Neil Shapiro #if SM_HEAP_CHECK
288040266059SGregory Neil Shapiro if (sm_debug_active(&DebugLeakSmtp, 1))
288140266059SGregory Neil Shapiro {
288240266059SGregory Neil Shapiro sm_heap_newgroup();
288340266059SGregory Neil Shapiro sm_dprintf("smtp() heap group #%d\n",
288440266059SGregory Neil Shapiro sm_heap_group());
288540266059SGregory Neil Shapiro }
288640266059SGregory Neil Shapiro #endif /* SM_HEAP_CHECK */
288706f25ae9SGregory Neil Shapiro
2888c2aa98e2SPeter Wemm if (Errors > 0)
288940266059SGregory Neil Shapiro goto undo_no_pm;
2890c2aa98e2SPeter Wemm if (!gothello)
2891c2aa98e2SPeter Wemm {
289240266059SGregory Neil Shapiro auth_warning(e, "%s didn't use HELO protocol",
2893c2aa98e2SPeter Wemm CurSmtpClient);
2894c2aa98e2SPeter Wemm }
2895c2aa98e2SPeter Wemm #ifdef PICKY_HELO_CHECK
289640266059SGregory Neil Shapiro if (sm_strcasecmp(sendinghost, peerhostname) != 0 &&
289740266059SGregory Neil Shapiro (sm_strcasecmp(peerhostname, "localhost") != 0 ||
289840266059SGregory Neil Shapiro sm_strcasecmp(sendinghost, MyHostName) != 0))
2899c2aa98e2SPeter Wemm {
2900c2aa98e2SPeter Wemm auth_warning(e, "Host %s claimed to be %s",
2901c2aa98e2SPeter Wemm CurSmtpClient, sendinghost);
2902c2aa98e2SPeter Wemm }
290306f25ae9SGregory Neil Shapiro #endif /* PICKY_HELO_CHECK */
2904c2aa98e2SPeter Wemm
2905c2aa98e2SPeter Wemm if (protocol == NULL)
2906c2aa98e2SPeter Wemm protocol = "SMTP";
290740266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'r', protocol);
290840266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 's', sendinghost);
290906f25ae9SGregory Neil Shapiro
2910c2aa98e2SPeter Wemm if (Errors > 0)
291140266059SGregory Neil Shapiro goto undo_no_pm;
291240266059SGregory Neil Shapiro smtp.sm_nrcpts = 0;
291340266059SGregory Neil Shapiro n_badrcpts = 0;
291440266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{ntries}"), "0");
291540266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{nrcpts}"), "0");
2916e92d3f3fSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{nbadrcpts}"),
2917e92d3f3fSGregory Neil Shapiro "0");
291806f25ae9SGregory Neil Shapiro e->e_flags |= EF_CLRQUEUE;
291940266059SGregory Neil Shapiro sm_setproctitle(true, e, "%s %s: %.80s",
292006f25ae9SGregory Neil Shapiro qid_printname(e),
292106f25ae9SGregory Neil Shapiro CurSmtpClient, inp);
2922c2aa98e2SPeter Wemm
292340266059SGregory Neil Shapiro /* do the processing */
292440266059SGregory Neil Shapiro SM_TRY
2925c2aa98e2SPeter Wemm {
2926605302a5SGregory Neil Shapiro extern char *FullName;
29272fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR
29282fb4f839SGregory Neil Shapiro char *origp;
29292fb4f839SGregory Neil Shapiro char iaddr[MAXLINE * 2];
29302fb4f839SGregory Neil Shapiro int len;
29312fb4f839SGregory Neil Shapiro #else
29322fb4f839SGregory Neil Shapiro # define origp p
29332fb4f839SGregory Neil Shapiro #endif
2934605302a5SGregory Neil Shapiro
293540266059SGregory Neil Shapiro QuickAbort = true;
29365b0945b5SGregory Neil Shapiro SM_FREE(FullName);
29372fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR
29382fb4f839SGregory Neil Shapiro len = sizeof(iaddr);
29392fb4f839SGregory Neil Shapiro origp = p;
29402fb4f839SGregory Neil Shapiro
29412fb4f839SGregory Neil Shapiro /* HACK!!!! p is more than the address! */
29422fb4f839SGregory Neil Shapiro p = quote_internal_chars(p, iaddr, &len, NULL);
29432fb4f839SGregory Neil Shapiro #endif
2944c2aa98e2SPeter Wemm
2945c2aa98e2SPeter Wemm /* must parse sender first */
2946c2aa98e2SPeter Wemm delimptr = NULL;
294740266059SGregory Neil Shapiro setsender(p, e, &delimptr, ' ', false);
2948c2aa98e2SPeter Wemm if (delimptr != NULL && *delimptr != '\0')
29492fb4f839SGregory Neil Shapiro {
2950c2aa98e2SPeter Wemm *delimptr++ = '\0';
29512fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR
29522fb4f839SGregory Neil Shapiro len = sizeof(iaddr) - (delimptr - iaddr);
29532fb4f839SGregory Neil Shapiro (void) dequote_internal_chars(delimptr, delimptr, len);
2954*d39bd2c1SGregory Neil Shapiro sep_args(delimptr, origp, e->e_id, p);
29552fb4f839SGregory Neil Shapiro #endif
29562fb4f839SGregory Neil Shapiro }
2957c2aa98e2SPeter Wemm if (Errors > 0)
295840266059SGregory Neil Shapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1);
2959c2aa98e2SPeter Wemm
296006f25ae9SGregory Neil Shapiro /* Successfully set e_from, allow logging */
296106f25ae9SGregory Neil Shapiro e->e_flags |= EF_LOGSENDER;
296206f25ae9SGregory Neil Shapiro
296306f25ae9SGregory Neil Shapiro /* put resulting triple from parseaddr() into macros */
296406f25ae9SGregory Neil Shapiro if (e->e_from.q_mailer != NULL)
296540266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
296640266059SGregory Neil Shapiro macid("{mail_mailer}"),
296740266059SGregory Neil Shapiro e->e_from.q_mailer->m_name);
296806f25ae9SGregory Neil Shapiro else
296940266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
297040266059SGregory Neil Shapiro macid("{mail_mailer}"), NULL);
297106f25ae9SGregory Neil Shapiro if (e->e_from.q_host != NULL)
297240266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
297340266059SGregory Neil Shapiro macid("{mail_host}"),
297440266059SGregory Neil Shapiro e->e_from.q_host);
297506f25ae9SGregory Neil Shapiro else
297640266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
297740266059SGregory Neil Shapiro macid("{mail_host}"), "localhost");
297806f25ae9SGregory Neil Shapiro if (e->e_from.q_user != NULL)
297940266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
298040266059SGregory Neil Shapiro macid("{mail_addr}"),
298140266059SGregory Neil Shapiro e->e_from.q_user);
298206f25ae9SGregory Neil Shapiro else
298340266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
298440266059SGregory Neil Shapiro macid("{mail_addr}"), NULL);
298506f25ae9SGregory Neil Shapiro if (Errors > 0)
298640266059SGregory Neil Shapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1);
2987c2aa98e2SPeter Wemm
2988c2aa98e2SPeter Wemm /* check for possible spoofing */
2989c2aa98e2SPeter Wemm if (RealUid != 0 && OpMode == MD_SMTP &&
2990c2aa98e2SPeter Wemm !wordinclass(RealUserName, 't') &&
299106f25ae9SGregory Neil Shapiro (!bitnset(M_LOCALMAILER,
299206f25ae9SGregory Neil Shapiro e->e_from.q_mailer->m_flags) ||
299306f25ae9SGregory Neil Shapiro strcmp(e->e_from.q_user, RealUserName) != 0))
2994c2aa98e2SPeter Wemm {
2995c2aa98e2SPeter Wemm auth_warning(e, "%s owned process doing -bs",
2996c2aa98e2SPeter Wemm RealUserName);
2997c2aa98e2SPeter Wemm }
2998c2aa98e2SPeter Wemm
2999a7ec597cSGregory Neil Shapiro /* reset to default value */
3000*d39bd2c1SGregory Neil Shapiro e->e_flags &= ~EF_7BITBODY;
3001a7ec597cSGregory Neil Shapiro
3002c2aa98e2SPeter Wemm /* now parse ESMTP arguments */
3003c2aa98e2SPeter Wemm e->e_msgsize = 0;
300406f25ae9SGregory Neil Shapiro addr = p;
30052fb4f839SGregory Neil Shapiro parse_esmtp_args(e, NULL, origp, delimptr, "MAIL", args,
3006d0cef73dSGregory Neil Shapiro mail_esmtp_args);
3007c2aa98e2SPeter Wemm if (Errors > 0)
300840266059SGregory Neil Shapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1);
300940266059SGregory Neil Shapiro
30102fb4f839SGregory Neil Shapiro #if USE_EAI
30115b0945b5SGregory Neil Shapiro if (e->e_smtputf8)
30125b0945b5SGregory Neil Shapiro {
30135b0945b5SGregory Neil Shapiro protocol = GET_PROTOCOL();
30145b0945b5SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'r', protocol);
30155b0945b5SGregory Neil Shapiro }
30165b0945b5SGregory Neil Shapiro
30175b0945b5SGregory Neil Shapiro /* UTF8 addresses are only legal with SMTPUTF8 */
30182fb4f839SGregory Neil Shapiro /* XXX different error if SMTPUTF8 is not enabled? */
30192fb4f839SGregory Neil Shapiro CHECK_UTF8_ADDR(e->e_from.q_paddr, q);
30202fb4f839SGregory Neil Shapiro if (q != NULL)
30215b0945b5SGregory Neil Shapiro {
30222fb4f839SGregory Neil Shapiro usrerr(q);
30235b0945b5SGregory Neil Shapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1);
30245b0945b5SGregory Neil Shapiro }
30255b0945b5SGregory Neil Shapiro #endif
30265b0945b5SGregory Neil Shapiro
302740266059SGregory Neil Shapiro #if SASL
302840266059SGregory Neil Shapiro # if _FFR_AUTH_PASSING
302940266059SGregory Neil Shapiro /* set the default AUTH= if the sender didn't */
303040266059SGregory Neil Shapiro if (e->e_auth_param == NULL)
303140266059SGregory Neil Shapiro {
303240266059SGregory Neil Shapiro /* XXX only do this for an MSA? */
303340266059SGregory Neil Shapiro e->e_auth_param = macvalue(macid("{auth_authen}"),
303440266059SGregory Neil Shapiro e);
303540266059SGregory Neil Shapiro if (e->e_auth_param == NULL)
303640266059SGregory Neil Shapiro e->e_auth_param = "<>";
303740266059SGregory Neil Shapiro
303840266059SGregory Neil Shapiro /*
303940266059SGregory Neil Shapiro ** XXX should we invoke Strust_auth now?
304040266059SGregory Neil Shapiro ** authorizing as the client that just
304140266059SGregory Neil Shapiro ** authenticated, so we'll trust implicitly
304240266059SGregory Neil Shapiro */
304340266059SGregory Neil Shapiro }
304440266059SGregory Neil Shapiro # endif /* _FFR_AUTH_PASSING */
304540266059SGregory Neil Shapiro #endif /* SASL */
3046c2aa98e2SPeter Wemm
304706f25ae9SGregory Neil Shapiro /* do config file checking of the sender */
304840266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
304940266059SGregory Neil Shapiro macid("{addr_type}"), "e s");
305040266059SGregory Neil Shapiro #if _FFR_MAIL_MACRO
305140266059SGregory Neil Shapiro /* make the "real" sender address available */
305240266059SGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, macid("{mail_from}"),
305340266059SGregory Neil Shapiro e->e_from.q_paddr);
30545b0945b5SGregory Neil Shapiro #endif
305506f25ae9SGregory Neil Shapiro if (rscheck("check_mail", addr,
3056959366dcSGregory Neil Shapiro NULL, e, RSF_RMCOMM|RSF_COUNT, 3,
3057da7d7b9cSGregory Neil Shapiro NULL, e->e_id, NULL, NULL) != EX_OK ||
305806f25ae9SGregory Neil Shapiro Errors > 0)
305940266059SGregory Neil Shapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1);
306040266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
306140266059SGregory Neil Shapiro macid("{addr_type}"), NULL);
306206f25ae9SGregory Neil Shapiro
306342e5d165SGregory Neil Shapiro if (MaxMessageSize > 0 &&
30648774250cSGregory Neil Shapiro (e->e_msgsize > MaxMessageSize ||
30658774250cSGregory Neil Shapiro e->e_msgsize < 0))
3066c2aa98e2SPeter Wemm {
306706f25ae9SGregory Neil Shapiro usrerr("552 5.2.3 Message size exceeds fixed maximum message size (%ld)",
3068c2aa98e2SPeter Wemm MaxMessageSize);
306940266059SGregory Neil Shapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1);
3070c2aa98e2SPeter Wemm }
3071c2aa98e2SPeter Wemm
307240266059SGregory Neil Shapiro /*
307340266059SGregory Neil Shapiro ** XXX always check whether there is at least one fs
307440266059SGregory Neil Shapiro ** with enough space?
307540266059SGregory Neil Shapiro ** However, this may not help much: the queue group
307640266059SGregory Neil Shapiro ** selection may later on select a FS that hasn't
307740266059SGregory Neil Shapiro ** enough space.
307840266059SGregory Neil Shapiro */
307940266059SGregory Neil Shapiro
308040266059SGregory Neil Shapiro if ((NumFileSys == 1 || NumQueue == 1) &&
308140266059SGregory Neil Shapiro !enoughdiskspace(e->e_msgsize, e)
308240266059SGregory Neil Shapiro #if _FFR_ANY_FREE_FS
308340266059SGregory Neil Shapiro && !filesys_free(e->e_msgsize)
30845b0945b5SGregory Neil Shapiro #endif
308540266059SGregory Neil Shapiro )
3086c2aa98e2SPeter Wemm {
308740266059SGregory Neil Shapiro /*
308840266059SGregory Neil Shapiro ** We perform this test again when the
308940266059SGregory Neil Shapiro ** queue directory is selected, in collect.
309040266059SGregory Neil Shapiro */
309140266059SGregory Neil Shapiro
309206f25ae9SGregory Neil Shapiro usrerr("452 4.4.5 Insufficient disk space; try again later");
309340266059SGregory Neil Shapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1);
3094c2aa98e2SPeter Wemm }
3095c2aa98e2SPeter Wemm if (Errors > 0)
309640266059SGregory Neil Shapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1);
309706f25ae9SGregory Neil Shapiro
309840266059SGregory Neil Shapiro LogUsrErrs = true;
309940266059SGregory Neil Shapiro #if MILTER
310040266059SGregory Neil Shapiro if (smtp.sm_milterlist && smtp.sm_milterize &&
310140266059SGregory Neil Shapiro !bitset(EF_DISCARD, e->e_flags))
310206f25ae9SGregory Neil Shapiro {
310306f25ae9SGregory Neil Shapiro char state;
310406f25ae9SGregory Neil Shapiro char *response;
310506f25ae9SGregory Neil Shapiro
310606f25ae9SGregory Neil Shapiro response = milter_envfrom(args, e, &state);
310740266059SGregory Neil Shapiro MILTER_REPLY("from");
310806f25ae9SGregory Neil Shapiro }
310940266059SGregory Neil Shapiro #endif /* MILTER */
311006f25ae9SGregory Neil Shapiro if (Errors > 0)
311140266059SGregory Neil Shapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1);
311206f25ae9SGregory Neil Shapiro
311306f25ae9SGregory Neil Shapiro message("250 2.1.0 Sender ok");
311440266059SGregory Neil Shapiro smtp.sm_gotmail = true;
311540266059SGregory Neil Shapiro }
311640266059SGregory Neil Shapiro SM_EXCEPT(exc, "[!F]*")
311740266059SGregory Neil Shapiro {
311840266059SGregory Neil Shapiro /*
311940266059SGregory Neil Shapiro ** An error occurred while processing a MAIL command.
312040266059SGregory Neil Shapiro ** Jump to the common error handling code.
312140266059SGregory Neil Shapiro */
312240266059SGregory Neil Shapiro
312340266059SGregory Neil Shapiro sm_exc_free(exc);
312440266059SGregory Neil Shapiro goto undo_no_pm;
312540266059SGregory Neil Shapiro }
312640266059SGregory Neil Shapiro SM_END_TRY
312740266059SGregory Neil Shapiro break;
312840266059SGregory Neil Shapiro
312940266059SGregory Neil Shapiro undo_no_pm:
313040266059SGregory Neil Shapiro e->e_flags &= ~EF_PM_NOTIFY;
313140266059SGregory Neil Shapiro undo:
3132c2aa98e2SPeter Wemm break;
3133c2aa98e2SPeter Wemm
3134c2aa98e2SPeter Wemm case CMDRCPT: /* rcpt -- designate recipient */
313540266059SGregory Neil Shapiro DELAY_CONN("RCPT");
3136d0cef73dSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
3137d0cef73dSGregory Neil Shapiro macid("{rcpt_mailer}"), NULL);
3138d0cef73dSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
3139d0cef73dSGregory Neil Shapiro macid("{rcpt_host}"), NULL);
3140d0cef73dSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
3141d0cef73dSGregory Neil Shapiro macid("{rcpt_addr}"), NULL);
3142d0cef73dSGregory Neil Shapiro #if MILTER
3143d0cef73dSGregory Neil Shapiro (void) memset(&addr_st, '\0', sizeof(addr_st));
3144d0cef73dSGregory Neil Shapiro a = NULL;
3145d0cef73dSGregory Neil Shapiro milter_rcpt_added = false;
3146ffb83623SGregory Neil Shapiro smtp.sm_e_nrcpts_orig = e->e_nrcpts;
3147d0cef73dSGregory Neil Shapiro #endif
3148e3793f76SGregory Neil Shapiro #if _FFR_BADRCPT_SHUTDOWN
3149e3793f76SGregory Neil Shapiro /*
3150e3793f76SGregory Neil Shapiro ** hack to deal with hack, see below:
31519bd497b8SGregory Neil Shapiro ** n_badrcpts is increased if limit is reached.
3152e3793f76SGregory Neil Shapiro */
3153e3793f76SGregory Neil Shapiro
3154e3793f76SGregory Neil Shapiro n_badrcpts_adj = (BadRcptThrottle > 0 &&
3155e3793f76SGregory Neil Shapiro n_badrcpts > BadRcptThrottle &&
3156e3793f76SGregory Neil Shapiro LogLevel > 5)
3157e3793f76SGregory Neil Shapiro ? n_badrcpts - 1 : n_badrcpts;
3158e3793f76SGregory Neil Shapiro if (BadRcptShutdown > 0 &&
3159e3793f76SGregory Neil Shapiro n_badrcpts_adj >= BadRcptShutdown &&
3160e3793f76SGregory Neil Shapiro (BadRcptShutdownGood == 0 ||
3161e3793f76SGregory Neil Shapiro smtp.sm_nrcpts == 0 ||
3162e3793f76SGregory Neil Shapiro (n_badrcpts_adj * 100 /
3163e3793f76SGregory Neil Shapiro (smtp.sm_nrcpts + n_badrcpts) >=
3164e3793f76SGregory Neil Shapiro BadRcptShutdownGood)))
3165e3793f76SGregory Neil Shapiro {
3166e3793f76SGregory Neil Shapiro if (LogLevel > 5)
3167e3793f76SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
3168e3793f76SGregory Neil Shapiro "%s: Possible SMTP RCPT flood, shutting down connection.",
3169e3793f76SGregory Neil Shapiro CurSmtpClient);
3170e3793f76SGregory Neil Shapiro message("421 4.7.0 %s Too many bad recipients; closing connection",
3171e3793f76SGregory Neil Shapiro MyHostName);
3172e3793f76SGregory Neil Shapiro
3173e3793f76SGregory Neil Shapiro /* arrange to ignore any current send list */
3174e3793f76SGregory Neil Shapiro e->e_sendqueue = NULL;
3175e3793f76SGregory Neil Shapiro goto doquit;
3176e3793f76SGregory Neil Shapiro }
3177e3793f76SGregory Neil Shapiro #endif /* _FFR_BADRCPT_SHUTDOWN */
3178323f6dcbSGregory Neil Shapiro if (BadRcptThrottle > 0 &&
3179323f6dcbSGregory Neil Shapiro n_badrcpts >= BadRcptThrottle)
3180323f6dcbSGregory Neil Shapiro {
3181323f6dcbSGregory Neil Shapiro if (LogLevel > 5 &&
3182323f6dcbSGregory Neil Shapiro n_badrcpts == BadRcptThrottle)
3183323f6dcbSGregory Neil Shapiro {
3184323f6dcbSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
3185323f6dcbSGregory Neil Shapiro "%s: Possible SMTP RCPT flood, throttling.",
3186323f6dcbSGregory Neil Shapiro CurSmtpClient);
3187323f6dcbSGregory Neil Shapiro
3188323f6dcbSGregory Neil Shapiro /* To avoid duplicated message */
3189323f6dcbSGregory Neil Shapiro n_badrcpts++;
3190323f6dcbSGregory Neil Shapiro }
3191e92d3f3fSGregory Neil Shapiro NBADRCPTS;
3192323f6dcbSGregory Neil Shapiro
3193323f6dcbSGregory Neil Shapiro /*
3194323f6dcbSGregory Neil Shapiro ** Don't use exponential backoff for now.
31959bd497b8SGregory Neil Shapiro ** Some systems will open more connections
3196323f6dcbSGregory Neil Shapiro ** and actually overload the receiver even
3197323f6dcbSGregory Neil Shapiro ** more.
3198323f6dcbSGregory Neil Shapiro */
3199323f6dcbSGregory Neil Shapiro
32009bd497b8SGregory Neil Shapiro (void) sleep(BadRcptThrottleDelay);
3201323f6dcbSGregory Neil Shapiro }
320240266059SGregory Neil Shapiro if (!smtp.sm_gotmail)
3203c2aa98e2SPeter Wemm {
320406f25ae9SGregory Neil Shapiro usrerr("503 5.0.0 Need MAIL before RCPT");
3205c2aa98e2SPeter Wemm break;
3206c2aa98e2SPeter Wemm }
3207c2aa98e2SPeter Wemm SmtpPhase = "server RCPT";
320840266059SGregory Neil Shapiro SM_TRY
3209c2aa98e2SPeter Wemm {
32102fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR
32112fb4f839SGregory Neil Shapiro char iaddr[MAXLINE * 2];
32122fb4f839SGregory Neil Shapiro int len;
32132fb4f839SGregory Neil Shapiro char *origp;
32142fb4f839SGregory Neil Shapiro #endif
32152fb4f839SGregory Neil Shapiro
321640266059SGregory Neil Shapiro QuickAbort = true;
321740266059SGregory Neil Shapiro LogUsrErrs = true;
3218c2aa98e2SPeter Wemm
3219c2aa98e2SPeter Wemm /* limit flooding of our machine */
322040266059SGregory Neil Shapiro if (MaxRcptPerMsg > 0 &&
322140266059SGregory Neil Shapiro smtp.sm_nrcpts >= MaxRcptPerMsg)
3222c2aa98e2SPeter Wemm {
322340266059SGregory Neil Shapiro /* sleep(1); / * slow down? */
322406f25ae9SGregory Neil Shapiro usrerr("452 4.5.3 Too many recipients");
322540266059SGregory Neil Shapiro goto rcpt_done;
3226c2aa98e2SPeter Wemm }
3227c2aa98e2SPeter Wemm
32286f9c8e5bSGregory Neil Shapiro if (!SM_IS_INTERACTIVE(e->e_sendmode)
32294e4196cbSGregory Neil Shapiro #if _FFR_DM_ONE
32304e4196cbSGregory Neil Shapiro && (NotFirstDelivery || SM_DM_ONE != e->e_sendmode)
32315b0945b5SGregory Neil Shapiro #endif
32324e4196cbSGregory Neil Shapiro )
3233c2aa98e2SPeter Wemm e->e_flags |= EF_VRFYONLY;
3234c2aa98e2SPeter Wemm
323540266059SGregory Neil Shapiro #if MILTER
323606f25ae9SGregory Neil Shapiro /*
3237d0cef73dSGregory Neil Shapiro ** Do not expand recipients at RCPT time (in the call
3238ffb83623SGregory Neil Shapiro ** to recipient()) if a milter can delete or reject
3239ffb83623SGregory Neil Shapiro ** a RCPT. If they are expanded, it is impossible
3240ffb83623SGregory Neil Shapiro ** for removefromlist() to figure out the expanded
3241ffb83623SGregory Neil Shapiro ** members of the original recipient and mark them
3242ffb83623SGregory Neil Shapiro ** as QS_DONTSEND.
324306f25ae9SGregory Neil Shapiro */
324406f25ae9SGregory Neil Shapiro
32455b0945b5SGregory Neil Shapiro if (smtp.sm_milterlist && smtp.sm_milterize &&
32465b0945b5SGregory Neil Shapiro !bitset(EF_DISCARD, e->e_flags) &&
3247ffb83623SGregory Neil Shapiro (smtp.sm_milters.mis_flags &
3248ffb83623SGregory Neil Shapiro (MIS_FL_DEL_RCPT|MIS_FL_REJ_RCPT)) != 0)
324906f25ae9SGregory Neil Shapiro e->e_flags |= EF_VRFYONLY;
3250d0cef73dSGregory Neil Shapiro milter_cmd_done = false;
3251d0cef73dSGregory Neil Shapiro milter_cmd_safe = false;
325240266059SGregory Neil Shapiro #endif /* MILTER */
325306f25ae9SGregory Neil Shapiro
3254c2aa98e2SPeter Wemm p = skipword(p, "to");
3255c2aa98e2SPeter Wemm if (p == NULL)
325640266059SGregory Neil Shapiro goto rcpt_done;
325740266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
325840266059SGregory Neil Shapiro macid("{addr_type}"), "e r");
32592fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR
32602fb4f839SGregory Neil Shapiro len = sizeof(iaddr);
32612fb4f839SGregory Neil Shapiro origp = p;
32622fb4f839SGregory Neil Shapiro
32632fb4f839SGregory Neil Shapiro /* HACK!!!! p is more than the address! */
32642fb4f839SGregory Neil Shapiro p = quote_internal_chars(p, iaddr, &len, NULL);
32652fb4f839SGregory Neil Shapiro #endif
326640266059SGregory Neil Shapiro a = parseaddr(p, NULLADDR, RF_COPYALL, ' ', &delimptr,
326740266059SGregory Neil Shapiro e, true);
326840266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
326940266059SGregory Neil Shapiro macid("{addr_type}"), NULL);
3270065a643dSPeter Wemm if (Errors > 0)
327140266059SGregory Neil Shapiro goto rcpt_done;
3272065a643dSPeter Wemm if (a == NULL)
3273065a643dSPeter Wemm {
327406f25ae9SGregory Neil Shapiro usrerr("501 5.0.0 Missing recipient");
327540266059SGregory Neil Shapiro goto rcpt_done;
3276065a643dSPeter Wemm }
32772fb4f839SGregory Neil Shapiro #if USE_EAI
32782fb4f839SGregory Neil Shapiro CHECK_UTF8_ADDR(a->q_paddr, q);
32792fb4f839SGregory Neil Shapiro if (q != NULL)
32805b0945b5SGregory Neil Shapiro {
32812fb4f839SGregory Neil Shapiro usrerr(q);
32825b0945b5SGregory Neil Shapiro goto rcpt_done;
32835b0945b5SGregory Neil Shapiro }
32845b0945b5SGregory Neil Shapiro #endif
3285065a643dSPeter Wemm
3286c2aa98e2SPeter Wemm if (delimptr != NULL && *delimptr != '\0')
32872fb4f839SGregory Neil Shapiro {
3288c2aa98e2SPeter Wemm *delimptr++ = '\0';
32892fb4f839SGregory Neil Shapiro #if _FFR_8BITENVADDR
32902fb4f839SGregory Neil Shapiro len = sizeof(iaddr) - (delimptr - iaddr);
32912fb4f839SGregory Neil Shapiro (void) dequote_internal_chars(delimptr, delimptr, len);
3292*d39bd2c1SGregory Neil Shapiro sep_args(delimptr, origp, e->e_id, p);
32932fb4f839SGregory Neil Shapiro #endif
32942fb4f839SGregory Neil Shapiro }
3295c2aa98e2SPeter Wemm
329606f25ae9SGregory Neil Shapiro /* put resulting triple from parseaddr() into macros */
329706f25ae9SGregory Neil Shapiro if (a->q_mailer != NULL)
329840266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
329940266059SGregory Neil Shapiro macid("{rcpt_mailer}"),
330040266059SGregory Neil Shapiro a->q_mailer->m_name);
330106f25ae9SGregory Neil Shapiro else
330240266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
330340266059SGregory Neil Shapiro macid("{rcpt_mailer}"), NULL);
330406f25ae9SGregory Neil Shapiro if (a->q_host != NULL)
330540266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
330640266059SGregory Neil Shapiro macid("{rcpt_host}"), a->q_host);
330706f25ae9SGregory Neil Shapiro else
330840266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
330940266059SGregory Neil Shapiro macid("{rcpt_host}"), "localhost");
331006f25ae9SGregory Neil Shapiro if (a->q_user != NULL)
331140266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
331240266059SGregory Neil Shapiro macid("{rcpt_addr}"), a->q_user);
331306f25ae9SGregory Neil Shapiro else
331440266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
331540266059SGregory Neil Shapiro macid("{rcpt_addr}"), NULL);
331606f25ae9SGregory Neil Shapiro if (Errors > 0)
331740266059SGregory Neil Shapiro goto rcpt_done;
3318c2aa98e2SPeter Wemm
3319c2aa98e2SPeter Wemm /* now parse ESMTP arguments */
33202fb4f839SGregory Neil Shapiro addr = sm_rpool_strdup_x(e->e_rpool, p);
33212fb4f839SGregory Neil Shapiro parse_esmtp_args(e, a, origp, delimptr, "RCPT", args,
3322d0cef73dSGregory Neil Shapiro rcpt_esmtp_args);
332306f25ae9SGregory Neil Shapiro if (Errors > 0)
332440266059SGregory Neil Shapiro goto rcpt_done;
332506f25ae9SGregory Neil Shapiro
3326d0cef73dSGregory Neil Shapiro #if MILTER
3327d0cef73dSGregory Neil Shapiro /*
3328d0cef73dSGregory Neil Shapiro ** rscheck() can trigger an "exception"
3329d0cef73dSGregory Neil Shapiro ** in which case the execution continues at
3330d0cef73dSGregory Neil Shapiro ** SM_EXCEPT(exc, "[!F]*")
3331d0cef73dSGregory Neil Shapiro ** This means milter_cmd_safe is not set
3332d0cef73dSGregory Neil Shapiro ** and hence milter is not invoked.
3333d0cef73dSGregory Neil Shapiro ** Would it be "safe" to change that, i.e., use
3334d0cef73dSGregory Neil Shapiro ** milter_cmd_safe = true;
3335d0cef73dSGregory Neil Shapiro ** here so a milter is informed (if requested)
3336d0cef73dSGregory Neil Shapiro ** about RCPTs that are rejected by check_rcpt?
3337d0cef73dSGregory Neil Shapiro */
3338d0cef73dSGregory Neil Shapiro # if _FFR_MILTER_CHECK_REJECTIONS_TOO
3339d0cef73dSGregory Neil Shapiro milter_cmd_safe = true;
3340d0cef73dSGregory Neil Shapiro # endif
3341d0cef73dSGregory Neil Shapiro #endif
3342d0cef73dSGregory Neil Shapiro
334306f25ae9SGregory Neil Shapiro /* do config file checking of the recipient */
334440266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
334540266059SGregory Neil Shapiro macid("{addr_type}"), "e r");
334606f25ae9SGregory Neil Shapiro if (rscheck("check_rcpt", addr,
3347959366dcSGregory Neil Shapiro NULL, e, RSF_RMCOMM|RSF_COUNT, 3,
3348da7d7b9cSGregory Neil Shapiro NULL, e->e_id, p_addr_st, NULL) != EX_OK ||
334906f25ae9SGregory Neil Shapiro Errors > 0)
335040266059SGregory Neil Shapiro goto rcpt_done;
335140266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
335240266059SGregory Neil Shapiro macid("{addr_type}"), NULL);
335306f25ae9SGregory Neil Shapiro
3354959366dcSGregory Neil Shapiro /* If discarding, don't bother to verify user */
3355959366dcSGregory Neil Shapiro if (bitset(EF_DISCARD, e->e_flags))
3356959366dcSGregory Neil Shapiro a->q_state = QS_VERIFIED;
3357d0cef73dSGregory Neil Shapiro #if MILTER
3358d0cef73dSGregory Neil Shapiro milter_cmd_safe = true;
3359d0cef73dSGregory Neil Shapiro #endif
3360d0cef73dSGregory Neil Shapiro
3361da7d7b9cSGregory Neil Shapiro addbcc(a, e);
3362da7d7b9cSGregory Neil Shapiro rcptmods(a, e);
3363da7d7b9cSGregory Neil Shapiro
3364d0cef73dSGregory Neil Shapiro /* save in recipient list after ESMTP mods */
3365d0cef73dSGregory Neil Shapiro a = recipient(a, &e->e_sendqueue, 0, e);
3366d0cef73dSGregory Neil Shapiro /* may trigger exception... */
3367959366dcSGregory Neil Shapiro
336840266059SGregory Neil Shapiro #if MILTER
3369d0cef73dSGregory Neil Shapiro milter_rcpt_added = true;
3370d0cef73dSGregory Neil Shapiro #endif
3371d0cef73dSGregory Neil Shapiro
3372d0cef73dSGregory Neil Shapiro if(!(Errors > 0) && QS_IS_BADADDR(a->q_state))
3373d0cef73dSGregory Neil Shapiro {
3374d0cef73dSGregory Neil Shapiro /* punt -- should keep message in ADDRESS.... */
3375d0cef73dSGregory Neil Shapiro usrerr("550 5.1.1 Addressee unknown");
3376d0cef73dSGregory Neil Shapiro }
3377d0cef73dSGregory Neil Shapiro
3378d0cef73dSGregory Neil Shapiro #if MILTER
3379d0cef73dSGregory Neil Shapiro rcpt_done:
338040266059SGregory Neil Shapiro if (smtp.sm_milterlist && smtp.sm_milterize &&
338140266059SGregory Neil Shapiro !bitset(EF_DISCARD, e->e_flags))
338206f25ae9SGregory Neil Shapiro {
338306f25ae9SGregory Neil Shapiro char state;
338406f25ae9SGregory Neil Shapiro char *response;
338506f25ae9SGregory Neil Shapiro
3386d0cef73dSGregory Neil Shapiro /* how to get the error codes? */
3387d0cef73dSGregory Neil Shapiro if (Errors > 0)
3388d0cef73dSGregory Neil Shapiro {
3389d0cef73dSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
3390d0cef73dSGregory Neil Shapiro macid("{rcpt_mailer}"),
3391d0cef73dSGregory Neil Shapiro "error");
3392d0cef73dSGregory Neil Shapiro if (a != NULL &&
3393d0cef73dSGregory Neil Shapiro a->q_status != NULL &&
3394d0cef73dSGregory Neil Shapiro a->q_rstatus != NULL)
3395d0cef73dSGregory Neil Shapiro {
3396d0cef73dSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
3397d0cef73dSGregory Neil Shapiro macid("{rcpt_host}"),
3398d0cef73dSGregory Neil Shapiro a->q_status);
3399d0cef73dSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
3400d0cef73dSGregory Neil Shapiro macid("{rcpt_addr}"),
3401d0cef73dSGregory Neil Shapiro a->q_rstatus);
3402d0cef73dSGregory Neil Shapiro }
3403d0cef73dSGregory Neil Shapiro else
3404d0cef73dSGregory Neil Shapiro {
3405d0cef73dSGregory Neil Shapiro if (addr_st.q_host != NULL)
3406d0cef73dSGregory Neil Shapiro macdefine(&e->e_macro,
3407d0cef73dSGregory Neil Shapiro A_PERM,
3408d0cef73dSGregory Neil Shapiro macid("{rcpt_host}"),
3409d0cef73dSGregory Neil Shapiro addr_st.q_host);
3410d0cef73dSGregory Neil Shapiro if (addr_st.q_user != NULL)
3411d0cef73dSGregory Neil Shapiro macdefine(&e->e_macro,
3412d0cef73dSGregory Neil Shapiro A_PERM,
3413d0cef73dSGregory Neil Shapiro macid("{rcpt_addr}"),
3414d0cef73dSGregory Neil Shapiro addr_st.q_user);
3415d0cef73dSGregory Neil Shapiro }
3416d0cef73dSGregory Neil Shapiro }
3417d0cef73dSGregory Neil Shapiro
3418d0cef73dSGregory Neil Shapiro response = milter_envrcpt(args, e, &state,
3419d0cef73dSGregory Neil Shapiro Errors > 0);
3420d0cef73dSGregory Neil Shapiro milter_cmd_done = true;
342140266059SGregory Neil Shapiro MILTER_REPLY("to");
342206f25ae9SGregory Neil Shapiro }
342340266059SGregory Neil Shapiro #endif /* MILTER */
342406f25ae9SGregory Neil Shapiro
3425c2aa98e2SPeter Wemm /* no errors during parsing, but might be a duplicate */
3426c2aa98e2SPeter Wemm e->e_to = a->q_paddr;
3427d0cef73dSGregory Neil Shapiro if (!(Errors > 0) && !QS_IS_BADADDR(a->q_state))
3428c2aa98e2SPeter Wemm {
342940266059SGregory Neil Shapiro if (smtp.sm_nrcpts == 0)
343006f25ae9SGregory Neil Shapiro initsys(e);
343106f25ae9SGregory Neil Shapiro message("250 2.1.5 Recipient ok%s",
343206f25ae9SGregory Neil Shapiro QS_IS_QUEUEUP(a->q_state) ?
3433c2aa98e2SPeter Wemm " (will queue)" : "");
343440266059SGregory Neil Shapiro smtp.sm_nrcpts++;
3435c2aa98e2SPeter Wemm }
3436d0cef73dSGregory Neil Shapiro
3437d0cef73dSGregory Neil Shapiro /* Is this needed? */
3438d0cef73dSGregory Neil Shapiro #if !MILTER
343940266059SGregory Neil Shapiro rcpt_done:
34405b0945b5SGregory Neil Shapiro #endif
3441da7d7b9cSGregory Neil Shapiro
3442d0cef73dSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
3443d0cef73dSGregory Neil Shapiro macid("{rcpt_mailer}"), NULL);
3444d0cef73dSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
3445d0cef73dSGregory Neil Shapiro macid("{rcpt_host}"), NULL);
3446d0cef73dSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
3447d0cef73dSGregory Neil Shapiro macid("{rcpt_addr}"), NULL);
3448d0cef73dSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
3449d0cef73dSGregory Neil Shapiro macid("{dsn_notify}"), NULL);
3450d0cef73dSGregory Neil Shapiro
345140266059SGregory Neil Shapiro if (Errors > 0)
3452e92d3f3fSGregory Neil Shapiro {
345340266059SGregory Neil Shapiro ++n_badrcpts;
3454e92d3f3fSGregory Neil Shapiro NBADRCPTS;
3455e92d3f3fSGregory Neil Shapiro }
345640266059SGregory Neil Shapiro }
345740266059SGregory Neil Shapiro SM_EXCEPT(exc, "[!F]*")
345840266059SGregory Neil Shapiro {
345940266059SGregory Neil Shapiro /* An exception occurred while processing RCPT */
346040266059SGregory Neil Shapiro e->e_flags &= ~(EF_FATALERRS|EF_PM_NOTIFY);
346140266059SGregory Neil Shapiro ++n_badrcpts;
3462e92d3f3fSGregory Neil Shapiro NBADRCPTS;
3463d0cef73dSGregory Neil Shapiro #if MILTER
3464d0cef73dSGregory Neil Shapiro if (smtp.sm_milterlist && smtp.sm_milterize &&
3465d0cef73dSGregory Neil Shapiro !bitset(EF_DISCARD, e->e_flags) &&
3466d0cef73dSGregory Neil Shapiro !milter_cmd_done && milter_cmd_safe)
3467d0cef73dSGregory Neil Shapiro {
3468d0cef73dSGregory Neil Shapiro char state;
3469d0cef73dSGregory Neil Shapiro char *response;
3470d0cef73dSGregory Neil Shapiro
3471d0cef73dSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
3472d0cef73dSGregory Neil Shapiro macid("{rcpt_mailer}"), "error");
3473d0cef73dSGregory Neil Shapiro
3474d0cef73dSGregory Neil Shapiro /* how to get the error codes? */
3475d0cef73dSGregory Neil Shapiro if (addr_st.q_host != NULL)
3476d0cef73dSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
3477d0cef73dSGregory Neil Shapiro macid("{rcpt_host}"),
3478d0cef73dSGregory Neil Shapiro addr_st.q_host);
3479d0cef73dSGregory Neil Shapiro else if (a != NULL && a->q_status != NULL)
3480d0cef73dSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
3481d0cef73dSGregory Neil Shapiro macid("{rcpt_host}"),
3482d0cef73dSGregory Neil Shapiro a->q_status);
3483d0cef73dSGregory Neil Shapiro
3484d0cef73dSGregory Neil Shapiro if (addr_st.q_user != NULL)
3485d0cef73dSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
3486d0cef73dSGregory Neil Shapiro macid("{rcpt_addr}"),
3487d0cef73dSGregory Neil Shapiro addr_st.q_user);
3488d0cef73dSGregory Neil Shapiro else if (a != NULL && a->q_rstatus != NULL)
3489d0cef73dSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
3490d0cef73dSGregory Neil Shapiro macid("{rcpt_addr}"),
3491d0cef73dSGregory Neil Shapiro a->q_rstatus);
3492d0cef73dSGregory Neil Shapiro
3493d0cef73dSGregory Neil Shapiro response = milter_envrcpt(args, e, &state,
3494d0cef73dSGregory Neil Shapiro true);
3495d0cef73dSGregory Neil Shapiro milter_cmd_done = true;
3496d0cef73dSGregory Neil Shapiro MILTER_REPLY("to");
3497d0cef73dSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
3498d0cef73dSGregory Neil Shapiro macid("{rcpt_mailer}"), NULL);
3499d0cef73dSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
3500d0cef73dSGregory Neil Shapiro macid("{rcpt_host}"), NULL);
3501d0cef73dSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
3502d0cef73dSGregory Neil Shapiro macid("{rcpt_addr}"), NULL);
3503d0cef73dSGregory Neil Shapiro }
3504d0cef73dSGregory Neil Shapiro if (smtp.sm_milterlist && smtp.sm_milterize &&
3505d0cef73dSGregory Neil Shapiro milter_rcpt_added && milter_cmd_done &&
3506d0cef73dSGregory Neil Shapiro milter_cmd_fail)
3507d0cef73dSGregory Neil Shapiro {
3508d0cef73dSGregory Neil Shapiro (void) removefromlist(addr, &e->e_sendqueue, e);
3509d0cef73dSGregory Neil Shapiro milter_cmd_fail = false;
3510ffb83623SGregory Neil Shapiro if (smtp.sm_e_nrcpts_orig < e->e_nrcpts)
3511ffb83623SGregory Neil Shapiro e->e_nrcpts = smtp.sm_e_nrcpts_orig;
3512d0cef73dSGregory Neil Shapiro }
3513d0cef73dSGregory Neil Shapiro #endif /* MILTER */
351440266059SGregory Neil Shapiro }
351540266059SGregory Neil Shapiro SM_END_TRY
3516c2aa98e2SPeter Wemm break;
3517c2aa98e2SPeter Wemm
3518c2aa98e2SPeter Wemm case CMDDATA: /* data -- text of mail */
351940266059SGregory Neil Shapiro DELAY_CONN("DATA");
3520*d39bd2c1SGregory Neil Shapiro if (!smtp_data(&smtp, e,
3521*d39bd2c1SGregory Neil Shapiro bitset(SRV_BAD_PIPELINE, features)))
3522e92d3f3fSGregory Neil Shapiro goto doquit;
3523c2aa98e2SPeter Wemm break;
3524c2aa98e2SPeter Wemm
3525c2aa98e2SPeter Wemm case CMDRSET: /* rset -- reset state */
3526c2aa98e2SPeter Wemm if (tTd(94, 100))
352706f25ae9SGregory Neil Shapiro message("451 4.0.0 Test failure");
3528c2aa98e2SPeter Wemm else
352906f25ae9SGregory Neil Shapiro message("250 2.0.0 Reset state");
353040266059SGregory Neil Shapiro CLEAR_STATE(cmdbuf);
3531c2aa98e2SPeter Wemm break;
3532c2aa98e2SPeter Wemm
3533c2aa98e2SPeter Wemm case CMDVRFY: /* vrfy -- verify address */
3534c2aa98e2SPeter Wemm case CMDEXPN: /* expn -- expand address */
353540266059SGregory Neil Shapiro vrfy = c->cmd_code == CMDVRFY;
353640266059SGregory Neil Shapiro DELAY_CONN(vrfy ? "VRFY" : "EXPN");
353706f25ae9SGregory Neil Shapiro if (tempfail)
353806f25ae9SGregory Neil Shapiro {
353906f25ae9SGregory Neil Shapiro if (LogLevel > 9)
354006f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
354113bd1963SGregory Neil Shapiro "SMTP %s command (%.100s) from %s tempfailed (due to previous checks)",
354240266059SGregory Neil Shapiro vrfy ? "VRFY" : "EXPN",
354306f25ae9SGregory Neil Shapiro p, CurSmtpClient);
354440266059SGregory Neil Shapiro
354540266059SGregory Neil Shapiro /* RFC 821 doesn't allow 4xy reply code */
354606f25ae9SGregory Neil Shapiro usrerr("550 5.7.1 Please try again later");
354706f25ae9SGregory Neil Shapiro break;
354806f25ae9SGregory Neil Shapiro }
354940266059SGregory Neil Shapiro wt = checksmtpattack(&n_verifies, MAXVRFYCOMMANDS,
355040266059SGregory Neil Shapiro false, vrfy ? "VRFY" : "EXPN", e);
3551e92d3f3fSGregory Neil Shapiro STOP_IF_ATTACK(wt);
355206f25ae9SGregory Neil Shapiro previous = curtime();
355313bd1963SGregory Neil Shapiro if ((vrfy && bitset(PRIV_NOVRFY, PrivacyFlags)) ||
355413bd1963SGregory Neil Shapiro (!vrfy && !bitset(SRV_OFFER_EXPN, features)))
3555c2aa98e2SPeter Wemm {
3556c2aa98e2SPeter Wemm if (vrfy)
355706f25ae9SGregory Neil Shapiro message("252 2.5.2 Cannot VRFY user; try RCPT to attempt delivery (or try finger)");
3558c2aa98e2SPeter Wemm else
355906f25ae9SGregory Neil Shapiro message("502 5.7.0 Sorry, we do not allow this operation");
3560c2aa98e2SPeter Wemm if (LogLevel > 5)
3561c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id,
356213bd1963SGregory Neil Shapiro "%s: %s [rejected]",
3563c2aa98e2SPeter Wemm CurSmtpClient,
3564c2aa98e2SPeter Wemm shortenstring(inp, MAXSHORTSTR));
3565c2aa98e2SPeter Wemm break;
3566c2aa98e2SPeter Wemm }
3567c2aa98e2SPeter Wemm else if (!gothello &&
3568c2aa98e2SPeter Wemm bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO,
3569c2aa98e2SPeter Wemm PrivacyFlags))
3570c2aa98e2SPeter Wemm {
357106f25ae9SGregory Neil Shapiro usrerr("503 5.0.0 I demand that you introduce yourself first");
3572c2aa98e2SPeter Wemm break;
3573c2aa98e2SPeter Wemm }
3574c2aa98e2SPeter Wemm if (Errors > 0)
357540266059SGregory Neil Shapiro break;
3576c2aa98e2SPeter Wemm if (LogLevel > 5)
357713bd1963SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "%s: %s",
3578c2aa98e2SPeter Wemm CurSmtpClient,
3579c2aa98e2SPeter Wemm shortenstring(inp, MAXSHORTSTR));
358040266059SGregory Neil Shapiro SM_TRY
358140266059SGregory Neil Shapiro {
358240266059SGregory Neil Shapiro QuickAbort = true;
3583c2aa98e2SPeter Wemm vrfyqueue = NULL;
3584c2aa98e2SPeter Wemm if (vrfy)
3585c2aa98e2SPeter Wemm e->e_flags |= EF_VRFYONLY;
35865b0945b5SGregory Neil Shapiro while (*p != '\0' && SM_ISSPACE(*p))
3587c2aa98e2SPeter Wemm p++;
3588c2aa98e2SPeter Wemm if (*p == '\0')
3589c2aa98e2SPeter Wemm {
359006f25ae9SGregory Neil Shapiro usrerr("501 5.5.2 Argument required");
3591c2aa98e2SPeter Wemm }
3592c2aa98e2SPeter Wemm else
3593c2aa98e2SPeter Wemm {
359406f25ae9SGregory Neil Shapiro /* do config file checking of the address */
359506f25ae9SGregory Neil Shapiro if (rscheck(vrfy ? "check_vrfy" : "check_expn",
3596da7d7b9cSGregory Neil Shapiro p, NULL, e, RSF_RMCOMM, 3, NULL,
3597da7d7b9cSGregory Neil Shapiro NOQID, NULL, NULL) != EX_OK ||
359840266059SGregory Neil Shapiro Errors > 0)
359940266059SGregory Neil Shapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1);
3600c2aa98e2SPeter Wemm (void) sendtolist(p, NULLADDR, &vrfyqueue, 0, e);
3601c2aa98e2SPeter Wemm }
360206f25ae9SGregory Neil Shapiro if (wt > 0)
3603193538b7SGregory Neil Shapiro {
3604193538b7SGregory Neil Shapiro time_t t;
3605193538b7SGregory Neil Shapiro
3606193538b7SGregory Neil Shapiro t = wt - (curtime() - previous);
3607193538b7SGregory Neil Shapiro if (t > 0)
3608193538b7SGregory Neil Shapiro (void) sleep(t);
3609193538b7SGregory Neil Shapiro }
3610c2aa98e2SPeter Wemm if (Errors > 0)
361140266059SGregory Neil Shapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1);
3612c2aa98e2SPeter Wemm if (vrfyqueue == NULL)
3613c2aa98e2SPeter Wemm {
361406f25ae9SGregory Neil Shapiro usrerr("554 5.5.2 Nothing to %s", vrfy ? "VRFY" : "EXPN");
3615c2aa98e2SPeter Wemm }
3616c2aa98e2SPeter Wemm while (vrfyqueue != NULL)
3617c2aa98e2SPeter Wemm {
361806f25ae9SGregory Neil Shapiro if (!QS_IS_UNDELIVERED(vrfyqueue->q_state))
361906f25ae9SGregory Neil Shapiro {
362006f25ae9SGregory Neil Shapiro vrfyqueue = vrfyqueue->q_next;
362106f25ae9SGregory Neil Shapiro continue;
362206f25ae9SGregory Neil Shapiro }
3623c2aa98e2SPeter Wemm
362406f25ae9SGregory Neil Shapiro /* see if there is more in the vrfy list */
3625c2aa98e2SPeter Wemm a = vrfyqueue;
3626c2aa98e2SPeter Wemm while ((a = a->q_next) != NULL &&
362742e5d165SGregory Neil Shapiro (!QS_IS_UNDELIVERED(a->q_state)))
3628c2aa98e2SPeter Wemm continue;
3629c2aa98e2SPeter Wemm printvrfyaddr(vrfyqueue, a == NULL, vrfy);
363006f25ae9SGregory Neil Shapiro vrfyqueue = a;
3631c2aa98e2SPeter Wemm }
363240266059SGregory Neil Shapiro }
363340266059SGregory Neil Shapiro SM_EXCEPT(exc, "[!F]*")
363440266059SGregory Neil Shapiro {
363540266059SGregory Neil Shapiro /*
363640266059SGregory Neil Shapiro ** An exception occurred while processing VRFY/EXPN
363740266059SGregory Neil Shapiro */
363840266059SGregory Neil Shapiro
363940266059SGregory Neil Shapiro sm_exc_free(exc);
364040266059SGregory Neil Shapiro goto undo;
364140266059SGregory Neil Shapiro }
364240266059SGregory Neil Shapiro SM_END_TRY
3643c2aa98e2SPeter Wemm break;
3644c2aa98e2SPeter Wemm
3645c2aa98e2SPeter Wemm case CMDETRN: /* etrn -- force queue flush */
364640266059SGregory Neil Shapiro DELAY_CONN("ETRN");
364740266059SGregory Neil Shapiro
364840266059SGregory Neil Shapiro /* Don't leak queue information via debug flags */
364940266059SGregory Neil Shapiro if (!bitset(SRV_OFFER_ETRN, features) || UseMSP ||
365040266059SGregory Neil Shapiro (RealUid != 0 && RealUid != TrustedUid &&
365140266059SGregory Neil Shapiro OpMode == MD_SMTP))
3652c2aa98e2SPeter Wemm {
365306f25ae9SGregory Neil Shapiro /* different message for MSA ? */
365406f25ae9SGregory Neil Shapiro message("502 5.7.0 Sorry, we do not allow this operation");
3655c2aa98e2SPeter Wemm if (LogLevel > 5)
3656c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id,
365713bd1963SGregory Neil Shapiro "%s: %s [rejected]",
3658c2aa98e2SPeter Wemm CurSmtpClient,
3659c2aa98e2SPeter Wemm shortenstring(inp, MAXSHORTSTR));
3660c2aa98e2SPeter Wemm break;
3661c2aa98e2SPeter Wemm }
366206f25ae9SGregory Neil Shapiro if (tempfail)
366306f25ae9SGregory Neil Shapiro {
366406f25ae9SGregory Neil Shapiro if (LogLevel > 9)
366506f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
366613bd1963SGregory Neil Shapiro "SMTP ETRN command (%.100s) from %s tempfailed (due to previous checks)",
366706f25ae9SGregory Neil Shapiro p, CurSmtpClient);
36685b0945b5SGregory Neil Shapiro /* Can't use ("%s", ...) due to usrerr() requirements */
366940266059SGregory Neil Shapiro usrerr(MSG_TEMPFAIL);
367006f25ae9SGregory Neil Shapiro break;
367106f25ae9SGregory Neil Shapiro }
3672c2aa98e2SPeter Wemm
3673c2aa98e2SPeter Wemm if (strlen(p) <= 0)
3674c2aa98e2SPeter Wemm {
367506f25ae9SGregory Neil Shapiro usrerr("500 5.5.2 Parameter required");
3676c2aa98e2SPeter Wemm break;
3677c2aa98e2SPeter Wemm }
3678c2aa98e2SPeter Wemm
3679c2aa98e2SPeter Wemm /* crude way to avoid denial-of-service attacks */
3680e92d3f3fSGregory Neil Shapiro STOP_IF_ATTACK(checksmtpattack(&n_etrn, MAXETRNCOMMANDS,
3681e92d3f3fSGregory Neil Shapiro true, "ETRN", e));
368206f25ae9SGregory Neil Shapiro
368340266059SGregory Neil Shapiro /*
368440266059SGregory Neil Shapiro ** Do config file checking of the parameter.
368540266059SGregory Neil Shapiro ** Even though we have srv_features now, we still
368640266059SGregory Neil Shapiro ** need this ruleset because the former is called
368740266059SGregory Neil Shapiro ** when the connection has been established, while
368840266059SGregory Neil Shapiro ** this ruleset is called when the command is
368940266059SGregory Neil Shapiro ** actually issued and therefore has all information
369040266059SGregory Neil Shapiro ** available to make a decision.
369140266059SGregory Neil Shapiro */
369240266059SGregory Neil Shapiro
3693da7d7b9cSGregory Neil Shapiro if (rscheck("check_etrn", p, NULL, e, RSF_RMCOMM, 3,
3694da7d7b9cSGregory Neil Shapiro NULL, NOQID, NULL, NULL) != EX_OK ||
3695959366dcSGregory Neil Shapiro Errors > 0)
369606f25ae9SGregory Neil Shapiro break;
3697c2aa98e2SPeter Wemm
3698c2aa98e2SPeter Wemm if (LogLevel > 5)
3699c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id,
370013bd1963SGregory Neil Shapiro "%s: ETRN %s", CurSmtpClient,
3701c2aa98e2SPeter Wemm shortenstring(p, MAXSHORTSTR));
3702c2aa98e2SPeter Wemm
3703c2aa98e2SPeter Wemm id = p;
370440266059SGregory Neil Shapiro if (*id == '#')
370540266059SGregory Neil Shapiro {
3706d9986b26SGregory Neil Shapiro int i, qgrp;
370740266059SGregory Neil Shapiro
370840266059SGregory Neil Shapiro id++;
3709d9986b26SGregory Neil Shapiro qgrp = name2qid(id);
3710d9986b26SGregory Neil Shapiro if (!ISVALIDQGRP(qgrp))
371140266059SGregory Neil Shapiro {
371240266059SGregory Neil Shapiro usrerr("459 4.5.4 Queue %s unknown",
371340266059SGregory Neil Shapiro id);
371440266059SGregory Neil Shapiro break;
371540266059SGregory Neil Shapiro }
3716d9986b26SGregory Neil Shapiro for (i = 0; i < NumQueue && Queue[i] != NULL;
3717d9986b26SGregory Neil Shapiro i++)
3718d9986b26SGregory Neil Shapiro Queue[i]->qg_nextrun = (time_t) -1;
3719d9986b26SGregory Neil Shapiro Queue[qgrp]->qg_nextrun = 0;
3720d9986b26SGregory Neil Shapiro ok = run_work_group(Queue[qgrp]->qg_wgrp,
3721d9986b26SGregory Neil Shapiro RWG_FORK|RWG_FORCE);
372240266059SGregory Neil Shapiro if (ok && Errors == 0)
372340266059SGregory Neil Shapiro message("250 2.0.0 Queuing for queue group %s started", id);
372440266059SGregory Neil Shapiro break;
372540266059SGregory Neil Shapiro }
372640266059SGregory Neil Shapiro
3727c2aa98e2SPeter Wemm if (*id == '@')
3728c2aa98e2SPeter Wemm id++;
3729c2aa98e2SPeter Wemm else
3730c2aa98e2SPeter Wemm *--id = '@';
3731c2aa98e2SPeter Wemm
373240266059SGregory Neil Shapiro new = (QUEUE_CHAR *) sm_malloc(sizeof(QUEUE_CHAR));
373340266059SGregory Neil Shapiro if (new == NULL)
373440266059SGregory Neil Shapiro {
373540266059SGregory Neil Shapiro syserr("500 5.5.0 ETRN out of memory");
373640266059SGregory Neil Shapiro break;
373740266059SGregory Neil Shapiro }
3738c2aa98e2SPeter Wemm new->queue_match = id;
373940266059SGregory Neil Shapiro new->queue_negate = false;
3740c2aa98e2SPeter Wemm new->queue_next = NULL;
3741c2aa98e2SPeter Wemm QueueLimitRecipient = new;
374240266059SGregory Neil Shapiro ok = runqueue(true, false, false, true);
374340266059SGregory Neil Shapiro sm_free(QueueLimitRecipient); /* XXX */
3744c2aa98e2SPeter Wemm QueueLimitRecipient = NULL;
3745c2aa98e2SPeter Wemm if (ok && Errors == 0)
374606f25ae9SGregory Neil Shapiro message("250 2.0.0 Queuing for node %s started", p);
3747c2aa98e2SPeter Wemm break;
3748c2aa98e2SPeter Wemm
3749c2aa98e2SPeter Wemm case CMDHELP: /* help -- give user info */
375040266059SGregory Neil Shapiro DELAY_CONN("HELP");
375106f25ae9SGregory Neil Shapiro help(p, e);
3752c2aa98e2SPeter Wemm break;
3753c2aa98e2SPeter Wemm
37542fb4f839SGregory Neil Shapiro #define CHECK_OTHER(type) do \
37552fb4f839SGregory Neil Shapiro { \
37562fb4f839SGregory Neil Shapiro bool saveQuickAbort = QuickAbort; \
37572fb4f839SGregory Neil Shapiro extern char MsgBuf[]; \
37582fb4f839SGregory Neil Shapiro int rsc; \
37592fb4f839SGregory Neil Shapiro QuickAbort = false; \
37602fb4f839SGregory Neil Shapiro if ((rsc = rscheck("check_other", inp, type, e, \
37612fb4f839SGregory Neil Shapiro RSF_UNSTRUCTURED, 3, NULL, NOQID, NULL, NULL)) \
37622fb4f839SGregory Neil Shapiro != EX_OK || \
37632fb4f839SGregory Neil Shapiro Errors > 0) \
37642fb4f839SGregory Neil Shapiro { \
37652fb4f839SGregory Neil Shapiro if (strncmp(MsgBuf, "421 ", 4) == 0) \
37662fb4f839SGregory Neil Shapiro { \
37672fb4f839SGregory Neil Shapiro e->e_sendqueue = NULL; \
37682fb4f839SGregory Neil Shapiro goto doquit; \
37692fb4f839SGregory Neil Shapiro } \
37702fb4f839SGregory Neil Shapiro } \
37712fb4f839SGregory Neil Shapiro QuickAbort = saveQuickAbort; \
37722fb4f839SGregory Neil Shapiro } while (0)
37732fb4f839SGregory Neil Shapiro
3774c2aa98e2SPeter Wemm case CMDNOOP: /* noop -- do nothing */
377540266059SGregory Neil Shapiro DELAY_CONN("NOOP");
37764e4196cbSGregory Neil Shapiro STOP_IF_ATTACK(checksmtpattack(&n_noop, MaxNOOPCommands,
3777e92d3f3fSGregory Neil Shapiro true, "NOOP", e));
37782fb4f839SGregory Neil Shapiro CHECK_OTHER("2");
377906f25ae9SGregory Neil Shapiro message("250 2.0.0 OK");
3780c2aa98e2SPeter Wemm break;
3781c2aa98e2SPeter Wemm
3782c2aa98e2SPeter Wemm case CMDQUIT: /* quit -- leave mail */
378306f25ae9SGregory Neil Shapiro message("221 2.0.0 %s closing connection", MyHostName);
378440266059SGregory Neil Shapiro #if PIPELINING
378540266059SGregory Neil Shapiro (void) sm_io_flush(OutChannel, SM_TIME_DEFAULT);
37865b0945b5SGregory Neil Shapiro #endif
378740266059SGregory Neil Shapiro
378840266059SGregory Neil Shapiro if (smtp.sm_nrcpts > 0)
378940266059SGregory Neil Shapiro logundelrcpts(e, "aborted by sender", 9, false);
3790c2aa98e2SPeter Wemm
3791c2aa98e2SPeter Wemm /* arrange to ignore any current send list */
3792c2aa98e2SPeter Wemm e->e_sendqueue = NULL;
3793c2aa98e2SPeter Wemm
379406f25ae9SGregory Neil Shapiro #if STARTTLS
379506f25ae9SGregory Neil Shapiro /* shutdown TLS connection */
379606f25ae9SGregory Neil Shapiro if (tls_active)
379706f25ae9SGregory Neil Shapiro {
37985b0945b5SGregory Neil Shapiro (void) endtls(&srv_ssl, "server");
379940266059SGregory Neil Shapiro tls_active = false;
380006f25ae9SGregory Neil Shapiro }
380106f25ae9SGregory Neil Shapiro #endif /* STARTTLS */
380206f25ae9SGregory Neil Shapiro #if SASL
3803*d39bd2c1SGregory Neil Shapiro if (auth_active)
380406f25ae9SGregory Neil Shapiro {
380506f25ae9SGregory Neil Shapiro sasl_dispose(&conn);
380606f25ae9SGregory Neil Shapiro authenticating = SASL_NOT_AUTH;
380740266059SGregory Neil Shapiro /* XXX sasl_done(); this is a child */
380806f25ae9SGregory Neil Shapiro }
380906f25ae9SGregory Neil Shapiro #endif /* SASL */
381006f25ae9SGregory Neil Shapiro
381106f25ae9SGregory Neil Shapiro doquit:
3812c2aa98e2SPeter Wemm /* avoid future 050 messages */
3813c2aa98e2SPeter Wemm disconnect(1, e);
3814c2aa98e2SPeter Wemm
381540266059SGregory Neil Shapiro #if MILTER
381606f25ae9SGregory Neil Shapiro /* close out milter filters */
381706f25ae9SGregory Neil Shapiro milter_quit(e);
38185b0945b5SGregory Neil Shapiro #endif
381906f25ae9SGregory Neil Shapiro
38209bd497b8SGregory Neil Shapiro if (tTd(92, 2))
38219bd497b8SGregory Neil Shapiro sm_dprintf("QUIT: e_id=%s, EF_LOGSENDER=%d, LogLevel=%d\n",
38229bd497b8SGregory Neil Shapiro e->e_id,
38239bd497b8SGregory Neil Shapiro bitset(EF_LOGSENDER, e->e_flags),
38249bd497b8SGregory Neil Shapiro LogLevel);
382506f25ae9SGregory Neil Shapiro if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags))
382606f25ae9SGregory Neil Shapiro logsender(e, NULL);
382706f25ae9SGregory Neil Shapiro e->e_flags &= ~EF_LOGSENDER;
382806f25ae9SGregory Neil Shapiro
382994c01205SGregory Neil Shapiro if (lognullconnection && LogLevel > 5 &&
383094c01205SGregory Neil Shapiro nullserver == NULL)
383106f25ae9SGregory Neil Shapiro {
383206f25ae9SGregory Neil Shapiro char *d;
383306f25ae9SGregory Neil Shapiro
383440266059SGregory Neil Shapiro d = macvalue(macid("{daemon_name}"), e);
383506f25ae9SGregory Neil Shapiro if (d == NULL)
383606f25ae9SGregory Neil Shapiro d = "stdin";
383740266059SGregory Neil Shapiro
383840266059SGregory Neil Shapiro /*
383940266059SGregory Neil Shapiro ** even though this id is "bogus", it makes
384040266059SGregory Neil Shapiro ** it simpler to "grep" related events, e.g.,
384140266059SGregory Neil Shapiro ** timeouts for the same connection.
384240266059SGregory Neil Shapiro */
384340266059SGregory Neil Shapiro
384440266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
384513bd1963SGregory Neil Shapiro "%s did not issue MAIL/EXPN/VRFY/ETRN during connection to %s",
384606f25ae9SGregory Neil Shapiro CurSmtpClient, d);
384706f25ae9SGregory Neil Shapiro }
384813bd1963SGregory Neil Shapiro if (tTd(93, 100))
384913bd1963SGregory Neil Shapiro {
385013bd1963SGregory Neil Shapiro /* return to handle next connection */
38512fb4f839SGregory Neil Shapiro #if SM_HEAP_CHECK
38522fb4f839SGregory Neil Shapiro # define SM_HC_TRIGGER "heapdump"
38532fb4f839SGregory Neil Shapiro if (sm_debug_active(&SmHeapCheck, 2)
38542fb4f839SGregory Neil Shapiro && access(SM_HC_TRIGGER, F_OK) == 0
38552fb4f839SGregory Neil Shapiro )
38562fb4f839SGregory Neil Shapiro {
38572fb4f839SGregory Neil Shapiro SM_FILE_T *out;
38582fb4f839SGregory Neil Shapiro
38592fb4f839SGregory Neil Shapiro remove(SM_HC_TRIGGER);
38602fb4f839SGregory Neil Shapiro out = sm_io_open(SmFtStdio,
38612fb4f839SGregory Neil Shapiro SM_TIME_DEFAULT, SM_HC_TRIGGER ".heap",
38622fb4f839SGregory Neil Shapiro SM_IO_APPEND, NULL);
38632fb4f839SGregory Neil Shapiro if (out != NULL)
38642fb4f839SGregory Neil Shapiro {
38652fb4f839SGregory Neil Shapiro (void) sm_io_fprintf(out, SM_TIME_DEFAULT, "----------------------\n");
38662fb4f839SGregory Neil Shapiro sm_heap_report(out,
38672fb4f839SGregory Neil Shapiro sm_debug_level(&SmHeapCheck) - 1);
38682fb4f839SGregory Neil Shapiro (void) sm_io_close(out, SM_TIME_DEFAULT);
38692fb4f839SGregory Neil Shapiro }
38702fb4f839SGregory Neil Shapiro }
38712fb4f839SGregory Neil Shapiro #endif /* SM_HEAP_CHECK */
387240266059SGregory Neil Shapiro return;
387313bd1963SGregory Neil Shapiro }
387440266059SGregory Neil Shapiro finis(true, true, ExitStat);
387506f25ae9SGregory Neil Shapiro /* NOTREACHED */
3876c2aa98e2SPeter Wemm
38774e4196cbSGregory Neil Shapiro /* just to avoid bogus warning from some compilers */
38784e4196cbSGregory Neil Shapiro exit(EX_OSERR);
38794e4196cbSGregory Neil Shapiro
3880c2aa98e2SPeter Wemm case CMDVERB: /* set verbose mode */
388140266059SGregory Neil Shapiro DELAY_CONN("VERB");
388213bd1963SGregory Neil Shapiro if (!bitset(SRV_OFFER_EXPN, features) ||
388313bd1963SGregory Neil Shapiro !bitset(SRV_OFFER_VERB, features))
3884c2aa98e2SPeter Wemm {
3885c2aa98e2SPeter Wemm /* this would give out the same info */
388606f25ae9SGregory Neil Shapiro message("502 5.7.0 Verbose unavailable");
3887c2aa98e2SPeter Wemm break;
3888c2aa98e2SPeter Wemm }
38894e4196cbSGregory Neil Shapiro STOP_IF_ATTACK(checksmtpattack(&n_noop, MaxNOOPCommands,
3890e92d3f3fSGregory Neil Shapiro true, "VERB", e));
38912fb4f839SGregory Neil Shapiro CHECK_OTHER("2");
3892c2aa98e2SPeter Wemm Verbose = 1;
389306f25ae9SGregory Neil Shapiro set_delivery_mode(SM_DELIVER, e);
389406f25ae9SGregory Neil Shapiro message("250 2.0.0 Verbose mode");
3895c2aa98e2SPeter Wemm break;
3896c2aa98e2SPeter Wemm
3897c2aa98e2SPeter Wemm #if SMTPDEBUG
3898c2aa98e2SPeter Wemm case CMDDBGQSHOW: /* show queues */
38992fb4f839SGregory Neil Shapiro CHECK_OTHER("2");
390040266059SGregory Neil Shapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT,
390140266059SGregory Neil Shapiro "Send Queue=");
3902e92d3f3fSGregory Neil Shapiro printaddr(smioout, e->e_sendqueue, true);
3903c2aa98e2SPeter Wemm break;
3904c2aa98e2SPeter Wemm
3905c2aa98e2SPeter Wemm case CMDDBGDEBUG: /* set debug mode */
39062fb4f839SGregory Neil Shapiro CHECK_OTHER("2");
3907d0cef73dSGregory Neil Shapiro tTsetup(tTdvect, sizeof(tTdvect), "0-99.1");
3908c2aa98e2SPeter Wemm tTflag(p);
390906f25ae9SGregory Neil Shapiro message("200 2.0.0 Debug set");
3910c2aa98e2SPeter Wemm break;
3911c2aa98e2SPeter Wemm
391206f25ae9SGregory Neil Shapiro #else /* SMTPDEBUG */
3913c2aa98e2SPeter Wemm case CMDDBGQSHOW: /* show queues */
3914c2aa98e2SPeter Wemm case CMDDBGDEBUG: /* set debug mode */
3915c2aa98e2SPeter Wemm #endif /* SMTPDEBUG */
3916c2aa98e2SPeter Wemm case CMDLOGBOGUS: /* bogus command */
391740266059SGregory Neil Shapiro DELAY_CONN("Bogus");
3918c2aa98e2SPeter Wemm if (LogLevel > 0)
3919c2aa98e2SPeter Wemm sm_syslog(LOG_CRIT, e->e_id,
392013bd1963SGregory Neil Shapiro "\"%s\" command from %s (%.100s)",
392106f25ae9SGregory Neil Shapiro c->cmd_name, CurSmtpClient,
3922c2aa98e2SPeter Wemm anynet_ntoa(&RealHostAddr));
3923c2aa98e2SPeter Wemm /* FALLTHROUGH */
3924c2aa98e2SPeter Wemm
3925c2aa98e2SPeter Wemm case CMDERROR: /* unknown command */
392640266059SGregory Neil Shapiro #if MAXBADCOMMANDS > 0
392740266059SGregory Neil Shapiro if (++n_badcmds > MAXBADCOMMANDS)
3928c2aa98e2SPeter Wemm {
3929e92d3f3fSGregory Neil Shapiro stopattack:
393006f25ae9SGregory Neil Shapiro message("421 4.7.0 %s Too many bad commands; closing connection",
3931c2aa98e2SPeter Wemm MyHostName);
393206f25ae9SGregory Neil Shapiro
393306f25ae9SGregory Neil Shapiro /* arrange to ignore any current send list */
393406f25ae9SGregory Neil Shapiro e->e_sendqueue = NULL;
3935c2aa98e2SPeter Wemm goto doquit;
3936c2aa98e2SPeter Wemm }
393740266059SGregory Neil Shapiro #endif /* MAXBADCOMMANDS > 0 */
3938c2aa98e2SPeter Wemm
3939e92d3f3fSGregory Neil Shapiro #if MILTER && SMFI_VERSION > 2
3940e92d3f3fSGregory Neil Shapiro if (smtp.sm_milterlist && smtp.sm_milterize &&
3941e92d3f3fSGregory Neil Shapiro !bitset(EF_DISCARD, e->e_flags))
3942e92d3f3fSGregory Neil Shapiro {
3943e92d3f3fSGregory Neil Shapiro char state;
3944e92d3f3fSGregory Neil Shapiro char *response;
3945e92d3f3fSGregory Neil Shapiro
3946e92d3f3fSGregory Neil Shapiro if (MilterLogLevel > 9)
3947e92d3f3fSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
3948e92d3f3fSGregory Neil Shapiro "Sending \"%s\" to Milter", inp);
3949e92d3f3fSGregory Neil Shapiro response = milter_unknown(inp, e, &state);
3950e92d3f3fSGregory Neil Shapiro MILTER_REPLY("unknown");
3951e92d3f3fSGregory Neil Shapiro if (state == SMFIR_REPLYCODE ||
3952e92d3f3fSGregory Neil Shapiro state == SMFIR_REJECT ||
39534e4196cbSGregory Neil Shapiro state == SMFIR_TEMPFAIL ||
39544e4196cbSGregory Neil Shapiro state == SMFIR_SHUTDOWN)
3955e92d3f3fSGregory Neil Shapiro {
3956e92d3f3fSGregory Neil Shapiro /* MILTER_REPLY already gave an error */
3957e92d3f3fSGregory Neil Shapiro break;
3958e92d3f3fSGregory Neil Shapiro }
3959e92d3f3fSGregory Neil Shapiro }
3960e92d3f3fSGregory Neil Shapiro #endif /* MILTER && SMFI_VERSION > 2 */
3961e92d3f3fSGregory Neil Shapiro
39622fb4f839SGregory Neil Shapiro CHECK_OTHER("5");
396306f25ae9SGregory Neil Shapiro usrerr("500 5.5.1 Command unrecognized: \"%s\"",
39642fb4f839SGregory Neil Shapiro SHOWSHRTCMDINREPLY(inp));
396506f25ae9SGregory Neil Shapiro break;
396606f25ae9SGregory Neil Shapiro
396706f25ae9SGregory Neil Shapiro case CMDUNIMPL:
396840266059SGregory Neil Shapiro DELAY_CONN("Unimpl");
39692fb4f839SGregory Neil Shapiro CHECK_OTHER("5");
397006f25ae9SGregory Neil Shapiro usrerr("502 5.5.1 Command not implemented: \"%s\"",
39712fb4f839SGregory Neil Shapiro SHOWSHRTCMDINREPLY(inp));
3972c2aa98e2SPeter Wemm break;
3973c2aa98e2SPeter Wemm
3974c2aa98e2SPeter Wemm default:
397540266059SGregory Neil Shapiro DELAY_CONN("default");
39762fb4f839SGregory Neil Shapiro CHECK_OTHER("5");
3977c2aa98e2SPeter Wemm errno = 0;
397806f25ae9SGregory Neil Shapiro syserr("500 5.5.0 smtp: unknown code %d", c->cmd_code);
3979c2aa98e2SPeter Wemm break;
3980c2aa98e2SPeter Wemm }
398106f25ae9SGregory Neil Shapiro #if SASL
3982c2aa98e2SPeter Wemm }
39835b0945b5SGregory Neil Shapiro #endif
398406f25ae9SGregory Neil Shapiro }
398540266059SGregory Neil Shapiro SM_EXCEPT(exc, "[!F]*")
398640266059SGregory Neil Shapiro {
398740266059SGregory Neil Shapiro /*
398840266059SGregory Neil Shapiro ** The only possible exception is "E:mta.quickabort".
398940266059SGregory Neil Shapiro ** There is nothing to do except fall through and loop.
399040266059SGregory Neil Shapiro */
3991c2aa98e2SPeter Wemm }
399240266059SGregory Neil Shapiro SM_END_TRY
399340266059SGregory Neil Shapiro }
399440266059SGregory Neil Shapiro }
399540266059SGregory Neil Shapiro /*
399640266059SGregory Neil Shapiro ** SMTP_DATA -- implement the SMTP DATA command.
399740266059SGregory Neil Shapiro **
399840266059SGregory Neil Shapiro ** Parameters:
399940266059SGregory Neil Shapiro ** smtp -- status of SMTP connection.
400040266059SGregory Neil Shapiro ** e -- envelope.
4001*d39bd2c1SGregory Neil Shapiro ** check_stuffing -- check for transaction stuffing.
400240266059SGregory Neil Shapiro **
400340266059SGregory Neil Shapiro ** Returns:
4004e92d3f3fSGregory Neil Shapiro ** true iff SMTP session can continue.
400540266059SGregory Neil Shapiro **
400640266059SGregory Neil Shapiro ** Side Effects:
400740266059SGregory Neil Shapiro ** possibly sends message.
400840266059SGregory Neil Shapiro */
400940266059SGregory Neil Shapiro
4010e92d3f3fSGregory Neil Shapiro static bool
smtp_data(smtp,e,check_stuffing)4011*d39bd2c1SGregory Neil Shapiro smtp_data(smtp, e, check_stuffing)
401240266059SGregory Neil Shapiro SMTP_T *smtp;
401340266059SGregory Neil Shapiro ENVELOPE *e;
4014*d39bd2c1SGregory Neil Shapiro bool check_stuffing;
401540266059SGregory Neil Shapiro {
401640266059SGregory Neil Shapiro #if MILTER
401740266059SGregory Neil Shapiro bool milteraccept;
40185b0945b5SGregory Neil Shapiro #endif
401940266059SGregory Neil Shapiro bool aborting;
402040266059SGregory Neil Shapiro bool doublequeue;
4021d0cef73dSGregory Neil Shapiro bool rv = true;
402240266059SGregory Neil Shapiro ADDRESS *a;
402340266059SGregory Neil Shapiro ENVELOPE *ee;
402440266059SGregory Neil Shapiro char *id;
402594c01205SGregory Neil Shapiro char *oldid;
4026*d39bd2c1SGregory Neil Shapiro unsigned long features;
402740266059SGregory Neil Shapiro char buf[32];
402840266059SGregory Neil Shapiro
402940266059SGregory Neil Shapiro SmtpPhase = "server DATA";
403040266059SGregory Neil Shapiro if (!smtp->sm_gotmail)
403140266059SGregory Neil Shapiro {
403240266059SGregory Neil Shapiro usrerr("503 5.0.0 Need MAIL command");
4033e92d3f3fSGregory Neil Shapiro return true;
403440266059SGregory Neil Shapiro }
403540266059SGregory Neil Shapiro else if (smtp->sm_nrcpts <= 0)
403640266059SGregory Neil Shapiro {
403740266059SGregory Neil Shapiro usrerr("503 5.0.0 Need RCPT (recipient)");
4038e92d3f3fSGregory Neil Shapiro return true;
403940266059SGregory Neil Shapiro }
4040*d39bd2c1SGregory Neil Shapiro
4041*d39bd2c1SGregory Neil Shapiro /* check if data is on the socket before the DATA reply */
4042*d39bd2c1SGregory Neil Shapiro if (check_stuffing &&
4043*d39bd2c1SGregory Neil Shapiro sm_io_getinfo(InChannel, SM_IO_IS_READABLE, NULL) > 0)
4044*d39bd2c1SGregory Neil Shapiro {
4045*d39bd2c1SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
4046*d39bd2c1SGregory Neil Shapiro "rejecting %s from %s [%s] due to traffic before response",
4047*d39bd2c1SGregory Neil Shapiro SmtpPhase, CurHostName, anynet_ntoa(&RealHostAddr));
4048*d39bd2c1SGregory Neil Shapiro usrerr("554 5.5.0 SMTP protocol error");
4049*d39bd2c1SGregory Neil Shapiro return false;
4050*d39bd2c1SGregory Neil Shapiro }
4051*d39bd2c1SGregory Neil Shapiro
4052d0cef73dSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "%u", smtp->sm_nrcpts);
405340266059SGregory Neil Shapiro if (rscheck("check_data", buf, NULL, e,
4054959366dcSGregory Neil Shapiro RSF_RMCOMM|RSF_UNSTRUCTURED|RSF_COUNT, 3, NULL,
4055da7d7b9cSGregory Neil Shapiro e->e_id, NULL, NULL) != EX_OK)
4056e92d3f3fSGregory Neil Shapiro return true;
4057e92d3f3fSGregory Neil Shapiro
4058e92d3f3fSGregory Neil Shapiro #if MILTER && SMFI_VERSION > 3
4059e92d3f3fSGregory Neil Shapiro if (smtp->sm_milterlist && smtp->sm_milterize &&
4060e92d3f3fSGregory Neil Shapiro !bitset(EF_DISCARD, e->e_flags))
4061e92d3f3fSGregory Neil Shapiro {
4062e92d3f3fSGregory Neil Shapiro char state;
4063e92d3f3fSGregory Neil Shapiro char *response;
4064e92d3f3fSGregory Neil Shapiro int savelogusrerrs = LogUsrErrs;
4065e92d3f3fSGregory Neil Shapiro
4066e92d3f3fSGregory Neil Shapiro response = milter_data_cmd(e, &state);
4067e92d3f3fSGregory Neil Shapiro switch (state)
4068e92d3f3fSGregory Neil Shapiro {
4069e92d3f3fSGregory Neil Shapiro case SMFIR_REPLYCODE:
4070e92d3f3fSGregory Neil Shapiro if (MilterLogLevel > 3)
4071e92d3f3fSGregory Neil Shapiro {
4072e92d3f3fSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
4073e92d3f3fSGregory Neil Shapiro "Milter: cmd=data, reject=%s",
4074e92d3f3fSGregory Neil Shapiro response);
4075e92d3f3fSGregory Neil Shapiro LogUsrErrs = false;
4076e92d3f3fSGregory Neil Shapiro }
40779bd497b8SGregory Neil Shapiro # if _FFR_MILTER_ENHSC
40789bd497b8SGregory Neil Shapiro if (ISSMTPCODE(response))
40799bd497b8SGregory Neil Shapiro (void) extenhsc(response + 4, ' ', e->e_enhsc);
40805b0945b5SGregory Neil Shapiro # endif
40819bd497b8SGregory Neil Shapiro
40825b0945b5SGregory Neil Shapiro /* Can't use ("%s", ...) due to usrerr() requirements */
4083e92d3f3fSGregory Neil Shapiro usrerr(response);
40844e4196cbSGregory Neil Shapiro if (strncmp(response, "421 ", 4) == 0
40854e4196cbSGregory Neil Shapiro || strncmp(response, "421-", 4) == 0)
4086e92d3f3fSGregory Neil Shapiro {
4087e92d3f3fSGregory Neil Shapiro e->e_sendqueue = NULL;
4088e92d3f3fSGregory Neil Shapiro return false;
4089e92d3f3fSGregory Neil Shapiro }
4090e92d3f3fSGregory Neil Shapiro return true;
4091e92d3f3fSGregory Neil Shapiro
4092e92d3f3fSGregory Neil Shapiro case SMFIR_REJECT:
4093e92d3f3fSGregory Neil Shapiro if (MilterLogLevel > 3)
4094e92d3f3fSGregory Neil Shapiro {
4095e92d3f3fSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
4096e92d3f3fSGregory Neil Shapiro "Milter: cmd=data, reject=550 5.7.1 Command rejected");
4097e92d3f3fSGregory Neil Shapiro LogUsrErrs = false;
4098e92d3f3fSGregory Neil Shapiro }
40999bd497b8SGregory Neil Shapiro # if _FFR_MILTER_ENHSC
41009bd497b8SGregory Neil Shapiro (void) sm_strlcpy(e->e_enhsc, "5.7.1",
41019bd497b8SGregory Neil Shapiro sizeof(e->e_enhsc));
41025b0945b5SGregory Neil Shapiro # endif
4103e92d3f3fSGregory Neil Shapiro usrerr("550 5.7.1 Command rejected");
4104e92d3f3fSGregory Neil Shapiro return true;
4105e92d3f3fSGregory Neil Shapiro
4106e92d3f3fSGregory Neil Shapiro case SMFIR_DISCARD:
4107e92d3f3fSGregory Neil Shapiro if (MilterLogLevel > 3)
4108e92d3f3fSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
4109e92d3f3fSGregory Neil Shapiro "Milter: cmd=data, discard");
4110e92d3f3fSGregory Neil Shapiro e->e_flags |= EF_DISCARD;
4111e92d3f3fSGregory Neil Shapiro break;
4112e92d3f3fSGregory Neil Shapiro
4113e92d3f3fSGregory Neil Shapiro case SMFIR_TEMPFAIL:
4114e92d3f3fSGregory Neil Shapiro if (MilterLogLevel > 3)
4115e92d3f3fSGregory Neil Shapiro {
4116e92d3f3fSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
4117e92d3f3fSGregory Neil Shapiro "Milter: cmd=data, reject=%s",
4118e92d3f3fSGregory Neil Shapiro MSG_TEMPFAIL);
4119e92d3f3fSGregory Neil Shapiro LogUsrErrs = false;
4120e92d3f3fSGregory Neil Shapiro }
41219bd497b8SGregory Neil Shapiro # if _FFR_MILTER_ENHSC
41229bd497b8SGregory Neil Shapiro (void) extenhsc(MSG_TEMPFAIL + 4, ' ', e->e_enhsc);
41235b0945b5SGregory Neil Shapiro # endif
41245b0945b5SGregory Neil Shapiro /* Can't use ("%s", ...) due to usrerr() requirements */
4125e92d3f3fSGregory Neil Shapiro usrerr(MSG_TEMPFAIL);
4126e92d3f3fSGregory Neil Shapiro return true;
41274e4196cbSGregory Neil Shapiro
41284e4196cbSGregory Neil Shapiro case SMFIR_SHUTDOWN:
41294e4196cbSGregory Neil Shapiro if (MilterLogLevel > 3)
41304e4196cbSGregory Neil Shapiro {
41314e4196cbSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
41324e4196cbSGregory Neil Shapiro "Milter: cmd=data, reject=421 4.7.0 %s closing connection",
41334e4196cbSGregory Neil Shapiro MyHostName);
41344e4196cbSGregory Neil Shapiro LogUsrErrs = false;
41354e4196cbSGregory Neil Shapiro }
41364e4196cbSGregory Neil Shapiro usrerr("421 4.7.0 %s closing connection", MyHostName);
41374e4196cbSGregory Neil Shapiro e->e_sendqueue = NULL;
41384e4196cbSGregory Neil Shapiro return false;
4139e92d3f3fSGregory Neil Shapiro }
4140e92d3f3fSGregory Neil Shapiro LogUsrErrs = savelogusrerrs;
4141e92d3f3fSGregory Neil Shapiro if (response != NULL)
4142e92d3f3fSGregory Neil Shapiro sm_free(response); /* XXX */
4143e92d3f3fSGregory Neil Shapiro }
4144e92d3f3fSGregory Neil Shapiro #endif /* MILTER && SMFI_VERSION > 3 */
414540266059SGregory Neil Shapiro
414640266059SGregory Neil Shapiro /* put back discard bit */
414740266059SGregory Neil Shapiro if (smtp->sm_discard)
414840266059SGregory Neil Shapiro e->e_flags |= EF_DISCARD;
414940266059SGregory Neil Shapiro
415040266059SGregory Neil Shapiro /* check to see if we need to re-expand aliases */
415140266059SGregory Neil Shapiro /* also reset QS_BADADDR on already-diagnosted addrs */
415240266059SGregory Neil Shapiro doublequeue = false;
415340266059SGregory Neil Shapiro for (a = e->e_sendqueue; a != NULL; a = a->q_next)
415440266059SGregory Neil Shapiro {
415540266059SGregory Neil Shapiro if (QS_IS_VERIFIED(a->q_state) &&
415640266059SGregory Neil Shapiro !bitset(EF_DISCARD, e->e_flags))
415740266059SGregory Neil Shapiro {
415840266059SGregory Neil Shapiro /* need to re-expand aliases */
415940266059SGregory Neil Shapiro doublequeue = true;
416040266059SGregory Neil Shapiro }
416140266059SGregory Neil Shapiro if (QS_IS_BADADDR(a->q_state))
416240266059SGregory Neil Shapiro {
416340266059SGregory Neil Shapiro /* make this "go away" */
416440266059SGregory Neil Shapiro a->q_state = QS_DONTSEND;
416540266059SGregory Neil Shapiro }
416640266059SGregory Neil Shapiro }
416740266059SGregory Neil Shapiro
416840266059SGregory Neil Shapiro /* collect the text of the message */
416940266059SGregory Neil Shapiro SmtpPhase = "collect";
417040266059SGregory Neil Shapiro buffer_errors();
417140266059SGregory Neil Shapiro
4172*d39bd2c1SGregory Neil Shapiro collect(InChannel, SMTPMODE_LAX
4173*d39bd2c1SGregory Neil Shapiro | (bitset(SRV_BARE_LF_421, e->e_features) ? SMTPMODE_LF_421 : 0)
4174*d39bd2c1SGregory Neil Shapiro | (bitset(SRV_BARE_CR_421, e->e_features) ? SMTPMODE_CR_421 : 0)
4175*d39bd2c1SGregory Neil Shapiro | (bitset(SRV_BARE_LF_SP, e->e_features) ? SMTPMODE_LF_SP : 0)
4176*d39bd2c1SGregory Neil Shapiro | (bitset(SRV_BARE_CR_SP, e->e_features) ? SMTPMODE_CR_SP : 0)
4177*d39bd2c1SGregory Neil Shapiro | (bitset(SRV_REQ_CRLF, e->e_features) ? SMTPMODE_CRLF : 0),
4178*d39bd2c1SGregory Neil Shapiro NULL, e, true);
417940266059SGregory Neil Shapiro
418040266059SGregory Neil Shapiro /* redefine message size */
4181ba00ec3dSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "%ld", PRT_NONNEGL(e->e_msgsize));
418240266059SGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, macid("{msg_size}"), buf);
418340266059SGregory Neil Shapiro
418440266059SGregory Neil Shapiro /* rscheck() will set Errors or EF_DISCARD if it trips */
4185959366dcSGregory Neil Shapiro (void) rscheck("check_eom", buf, NULL, e, RSF_UNSTRUCTURED|RSF_COUNT,
4186da7d7b9cSGregory Neil Shapiro 3, NULL, e->e_id, NULL, NULL);
418740266059SGregory Neil Shapiro
418840266059SGregory Neil Shapiro #if MILTER
418940266059SGregory Neil Shapiro milteraccept = true;
419040266059SGregory Neil Shapiro if (smtp->sm_milterlist && smtp->sm_milterize &&
419140266059SGregory Neil Shapiro Errors <= 0 &&
419240266059SGregory Neil Shapiro !bitset(EF_DISCARD, e->e_flags))
419340266059SGregory Neil Shapiro {
419440266059SGregory Neil Shapiro char state;
419540266059SGregory Neil Shapiro char *response;
419640266059SGregory Neil Shapiro
419740266059SGregory Neil Shapiro response = milter_data(e, &state);
419840266059SGregory Neil Shapiro switch (state)
419940266059SGregory Neil Shapiro {
420040266059SGregory Neil Shapiro case SMFIR_REPLYCODE:
420140266059SGregory Neil Shapiro if (MilterLogLevel > 3)
420240266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
420340266059SGregory Neil Shapiro "Milter: data, reject=%s",
420440266059SGregory Neil Shapiro response);
420540266059SGregory Neil Shapiro milteraccept = false;
42069bd497b8SGregory Neil Shapiro # if _FFR_MILTER_ENHSC
42079bd497b8SGregory Neil Shapiro if (ISSMTPCODE(response))
42089bd497b8SGregory Neil Shapiro (void) extenhsc(response + 4, ' ', e->e_enhsc);
42095b0945b5SGregory Neil Shapiro # endif
42105b0945b5SGregory Neil Shapiro /* Can't use ("%s", ...) due to usrerr() requirements */
421140266059SGregory Neil Shapiro usrerr(response);
42129bd497b8SGregory Neil Shapiro if (strncmp(response, "421 ", 4) == 0
42139bd497b8SGregory Neil Shapiro || strncmp(response, "421-", 4) == 0)
42149bd497b8SGregory Neil Shapiro rv = false;
421540266059SGregory Neil Shapiro break;
421640266059SGregory Neil Shapiro
421740266059SGregory Neil Shapiro case SMFIR_REJECT:
421840266059SGregory Neil Shapiro milteraccept = false;
421940266059SGregory Neil Shapiro if (MilterLogLevel > 3)
422040266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
422140266059SGregory Neil Shapiro "Milter: data, reject=554 5.7.1 Command rejected");
422240266059SGregory Neil Shapiro usrerr("554 5.7.1 Command rejected");
422340266059SGregory Neil Shapiro break;
422440266059SGregory Neil Shapiro
422540266059SGregory Neil Shapiro case SMFIR_DISCARD:
422640266059SGregory Neil Shapiro if (MilterLogLevel > 3)
422740266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
422840266059SGregory Neil Shapiro "Milter: data, discard");
422940266059SGregory Neil Shapiro milteraccept = false;
423040266059SGregory Neil Shapiro e->e_flags |= EF_DISCARD;
423140266059SGregory Neil Shapiro break;
423240266059SGregory Neil Shapiro
423340266059SGregory Neil Shapiro case SMFIR_TEMPFAIL:
423440266059SGregory Neil Shapiro if (MilterLogLevel > 3)
423540266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
423640266059SGregory Neil Shapiro "Milter: data, reject=%s",
423740266059SGregory Neil Shapiro MSG_TEMPFAIL);
423840266059SGregory Neil Shapiro milteraccept = false;
42399bd497b8SGregory Neil Shapiro # if _FFR_MILTER_ENHSC
42409bd497b8SGregory Neil Shapiro (void) extenhsc(MSG_TEMPFAIL + 4, ' ', e->e_enhsc);
42415b0945b5SGregory Neil Shapiro # endif
42425b0945b5SGregory Neil Shapiro /* Can't use ("%s", ...) due to usrerr() requirements */
424340266059SGregory Neil Shapiro usrerr(MSG_TEMPFAIL);
424440266059SGregory Neil Shapiro break;
42454e4196cbSGregory Neil Shapiro
42464e4196cbSGregory Neil Shapiro case SMFIR_SHUTDOWN:
42474e4196cbSGregory Neil Shapiro if (MilterLogLevel > 3)
42484e4196cbSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
42494e4196cbSGregory Neil Shapiro "Milter: data, reject=421 4.7.0 %s closing connection",
42504e4196cbSGregory Neil Shapiro MyHostName);
42514e4196cbSGregory Neil Shapiro milteraccept = false;
42524e4196cbSGregory Neil Shapiro usrerr("421 4.7.0 %s closing connection", MyHostName);
42534e4196cbSGregory Neil Shapiro rv = false;
42544e4196cbSGregory Neil Shapiro break;
425540266059SGregory Neil Shapiro }
425640266059SGregory Neil Shapiro if (response != NULL)
425740266059SGregory Neil Shapiro sm_free(response);
425840266059SGregory Neil Shapiro }
425940266059SGregory Neil Shapiro
426040266059SGregory Neil Shapiro /* Milter may have changed message size */
4261ba00ec3dSGregory Neil Shapiro (void) sm_snprintf(buf, sizeof(buf), "%ld", PRT_NONNEGL(e->e_msgsize));
426240266059SGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, macid("{msg_size}"), buf);
426340266059SGregory Neil Shapiro
426440266059SGregory Neil Shapiro /* abort message filters that didn't get the body & log msg is OK */
426540266059SGregory Neil Shapiro if (smtp->sm_milterlist && smtp->sm_milterize)
426640266059SGregory Neil Shapiro {
426740266059SGregory Neil Shapiro milter_abort(e);
426840266059SGregory Neil Shapiro if (milteraccept && MilterLogLevel > 9)
426940266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter accept: message");
427040266059SGregory Neil Shapiro }
4271e92d3f3fSGregory Neil Shapiro
4272e92d3f3fSGregory Neil Shapiro /*
4273e92d3f3fSGregory Neil Shapiro ** If SuperSafe is SAFE_REALLY_POSTMILTER, and we don't have milter or
4274e92d3f3fSGregory Neil Shapiro ** milter accepted message, sync it now
4275e92d3f3fSGregory Neil Shapiro **
4276e92d3f3fSGregory Neil Shapiro ** XXX This is almost a copy of the code in collect(): put it into
4277e92d3f3fSGregory Neil Shapiro ** a function that is called from both places?
4278e92d3f3fSGregory Neil Shapiro */
4279e92d3f3fSGregory Neil Shapiro
4280e92d3f3fSGregory Neil Shapiro if (milteraccept && SuperSafe == SAFE_REALLY_POSTMILTER)
4281e92d3f3fSGregory Neil Shapiro {
4282e92d3f3fSGregory Neil Shapiro int afd;
4283e92d3f3fSGregory Neil Shapiro SM_FILE_T *volatile df;
4284e92d3f3fSGregory Neil Shapiro char *dfname;
4285e92d3f3fSGregory Neil Shapiro
4286e92d3f3fSGregory Neil Shapiro df = e->e_dfp;
4287e92d3f3fSGregory Neil Shapiro dfname = queuename(e, DATAFL_LETTER);
4288e92d3f3fSGregory Neil Shapiro if (sm_io_setinfo(df, SM_BF_COMMIT, NULL) < 0
4289e92d3f3fSGregory Neil Shapiro && errno != EINVAL)
4290e92d3f3fSGregory Neil Shapiro {
4291e92d3f3fSGregory Neil Shapiro int save_errno;
4292e92d3f3fSGregory Neil Shapiro
4293e92d3f3fSGregory Neil Shapiro save_errno = errno;
4294e92d3f3fSGregory Neil Shapiro if (save_errno == EEXIST)
4295e92d3f3fSGregory Neil Shapiro {
4296e92d3f3fSGregory Neil Shapiro struct stat st;
4297e92d3f3fSGregory Neil Shapiro int dfd;
4298e92d3f3fSGregory Neil Shapiro
4299e92d3f3fSGregory Neil Shapiro if (stat(dfname, &st) < 0)
4300e92d3f3fSGregory Neil Shapiro st.st_size = -1;
4301e92d3f3fSGregory Neil Shapiro errno = EEXIST;
4302e92d3f3fSGregory Neil Shapiro syserr("@collect: bfcommit(%s): already on disk, size=%ld",
4303e92d3f3fSGregory Neil Shapiro dfname, (long) st.st_size);
4304e92d3f3fSGregory Neil Shapiro dfd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL);
4305e92d3f3fSGregory Neil Shapiro if (dfd >= 0)
4306e92d3f3fSGregory Neil Shapiro dumpfd(dfd, true, true);
4307e92d3f3fSGregory Neil Shapiro }
4308e92d3f3fSGregory Neil Shapiro errno = save_errno;
4309e92d3f3fSGregory Neil Shapiro dferror(df, "bfcommit", e);
4310e92d3f3fSGregory Neil Shapiro flush_errors(true);
4311e92d3f3fSGregory Neil Shapiro finis(save_errno != EEXIST, true, ExitStat);
4312e92d3f3fSGregory Neil Shapiro }
4313e92d3f3fSGregory Neil Shapiro else if ((afd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL)) < 0)
4314e92d3f3fSGregory Neil Shapiro {
4315e92d3f3fSGregory Neil Shapiro dferror(df, "sm_io_getinfo", e);
4316e92d3f3fSGregory Neil Shapiro flush_errors(true);
4317e92d3f3fSGregory Neil Shapiro finis(true, true, ExitStat);
4318e92d3f3fSGregory Neil Shapiro /* NOTREACHED */
4319e92d3f3fSGregory Neil Shapiro }
4320e92d3f3fSGregory Neil Shapiro else if (fsync(afd) < 0)
4321e92d3f3fSGregory Neil Shapiro {
4322e92d3f3fSGregory Neil Shapiro dferror(df, "fsync", e);
4323e92d3f3fSGregory Neil Shapiro flush_errors(true);
4324e92d3f3fSGregory Neil Shapiro finis(true, true, ExitStat);
4325e92d3f3fSGregory Neil Shapiro /* NOTREACHED */
4326e92d3f3fSGregory Neil Shapiro }
4327e92d3f3fSGregory Neil Shapiro else if (sm_io_close(df, SM_TIME_DEFAULT) < 0)
4328e92d3f3fSGregory Neil Shapiro {
4329e92d3f3fSGregory Neil Shapiro dferror(df, "sm_io_close", e);
4330e92d3f3fSGregory Neil Shapiro flush_errors(true);
4331e92d3f3fSGregory Neil Shapiro finis(true, true, ExitStat);
4332e92d3f3fSGregory Neil Shapiro /* NOTREACHED */
4333e92d3f3fSGregory Neil Shapiro }
4334e92d3f3fSGregory Neil Shapiro
4335e92d3f3fSGregory Neil Shapiro /* Now reopen the df file */
4336e92d3f3fSGregory Neil Shapiro e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname,
4337e92d3f3fSGregory Neil Shapiro SM_IO_RDONLY, NULL);
4338e92d3f3fSGregory Neil Shapiro if (e->e_dfp == NULL)
4339e92d3f3fSGregory Neil Shapiro {
4340e92d3f3fSGregory Neil Shapiro /* we haven't acked receipt yet, so just chuck this */
4341e92d3f3fSGregory Neil Shapiro syserr("@Cannot reopen %s", dfname);
4342e92d3f3fSGregory Neil Shapiro finis(true, true, ExitStat);
4343e92d3f3fSGregory Neil Shapiro /* NOTREACHED */
4344e92d3f3fSGregory Neil Shapiro }
4345e92d3f3fSGregory Neil Shapiro }
434640266059SGregory Neil Shapiro #endif /* MILTER */
434740266059SGregory Neil Shapiro
434840266059SGregory Neil Shapiro /* Check if quarantining stats should be updated */
434940266059SGregory Neil Shapiro if (e->e_quarmsg != NULL)
435040266059SGregory Neil Shapiro markstats(e, NULL, STATS_QUARANTINE);
435140266059SGregory Neil Shapiro
435240266059SGregory Neil Shapiro /*
435340266059SGregory Neil Shapiro ** If a header/body check (header checks or milter)
435440266059SGregory Neil Shapiro ** set EF_DISCARD, don't queueup the message --
435540266059SGregory Neil Shapiro ** that would lose the EF_DISCARD bit and deliver
435640266059SGregory Neil Shapiro ** the message.
435740266059SGregory Neil Shapiro */
435840266059SGregory Neil Shapiro
435940266059SGregory Neil Shapiro if (bitset(EF_DISCARD, e->e_flags))
436040266059SGregory Neil Shapiro doublequeue = false;
436140266059SGregory Neil Shapiro
436240266059SGregory Neil Shapiro aborting = Errors > 0;
4363323f6dcbSGregory Neil Shapiro if (!(aborting || bitset(EF_DISCARD, e->e_flags)) &&
436440266059SGregory Neil Shapiro (QueueMode == QM_QUARANTINE || e->e_quarmsg == NULL) &&
436540266059SGregory Neil Shapiro !split_by_recipient(e))
436640266059SGregory Neil Shapiro aborting = bitset(EF_FATALERRS, e->e_flags);
436740266059SGregory Neil Shapiro
436840266059SGregory Neil Shapiro if (aborting)
436940266059SGregory Neil Shapiro {
4370ffb83623SGregory Neil Shapiro ADDRESS *q;
4371ffb83623SGregory Neil Shapiro
437240266059SGregory Neil Shapiro /* Log who the mail would have gone to */
437340266059SGregory Neil Shapiro logundelrcpts(e, e->e_message, 8, false);
4374ffb83623SGregory Neil Shapiro
4375ffb83623SGregory Neil Shapiro /*
4376ffb83623SGregory Neil Shapiro ** If something above refused the message, we still haven't
4377ffb83623SGregory Neil Shapiro ** accepted responsibility for it. Don't send DSNs.
4378ffb83623SGregory Neil Shapiro */
4379ffb83623SGregory Neil Shapiro
4380ffb83623SGregory Neil Shapiro for (q = e->e_sendqueue; q != NULL; q = q->q_next)
4381ffb83623SGregory Neil Shapiro q->q_flags &= ~Q_PINGFLAGS;
4382ffb83623SGregory Neil Shapiro
438340266059SGregory Neil Shapiro flush_errors(true);
438440266059SGregory Neil Shapiro buffer_errors();
438540266059SGregory Neil Shapiro goto abortmessage;
438640266059SGregory Neil Shapiro }
438740266059SGregory Neil Shapiro
438840266059SGregory Neil Shapiro /* from now on, we have to operate silently */
438940266059SGregory Neil Shapiro buffer_errors();
439040266059SGregory Neil Shapiro
439140266059SGregory Neil Shapiro #if 0
439240266059SGregory Neil Shapiro /*
439340266059SGregory Neil Shapiro ** Clear message, it may contain an error from the SMTP dialogue.
439440266059SGregory Neil Shapiro ** This error must not show up in the queue.
439540266059SGregory Neil Shapiro ** Some error message should show up, e.g., alias database
439640266059SGregory Neil Shapiro ** not available, but others shouldn't, e.g., from check_rcpt.
439740266059SGregory Neil Shapiro */
439840266059SGregory Neil Shapiro
439940266059SGregory Neil Shapiro e->e_message = NULL;
440040266059SGregory Neil Shapiro #endif /* 0 */
440140266059SGregory Neil Shapiro
440240266059SGregory Neil Shapiro /*
440340266059SGregory Neil Shapiro ** Arrange to send to everyone.
440440266059SGregory Neil Shapiro ** If sending to multiple people, mail back
440540266059SGregory Neil Shapiro ** errors rather than reporting directly.
440640266059SGregory Neil Shapiro ** In any case, don't mail back errors for
440740266059SGregory Neil Shapiro ** anything that has happened up to
440840266059SGregory Neil Shapiro ** now (the other end will do this).
440940266059SGregory Neil Shapiro ** Truncate our transcript -- the mail has gotten
441040266059SGregory Neil Shapiro ** to us successfully, and if we have
441140266059SGregory Neil Shapiro ** to mail this back, it will be easier
441240266059SGregory Neil Shapiro ** on the reader.
441340266059SGregory Neil Shapiro ** Then send to everyone.
441440266059SGregory Neil Shapiro ** Finally give a reply code. If an error has
441540266059SGregory Neil Shapiro ** already been given, don't mail a
441640266059SGregory Neil Shapiro ** message back.
441740266059SGregory Neil Shapiro ** We goose error returns by clearing error bit.
441840266059SGregory Neil Shapiro */
441940266059SGregory Neil Shapiro
442040266059SGregory Neil Shapiro SmtpPhase = "delivery";
442140266059SGregory Neil Shapiro (void) sm_io_setinfo(e->e_xfp, SM_BF_TRUNCATE, NULL);
442240266059SGregory Neil Shapiro id = e->e_id;
442340266059SGregory Neil Shapiro
442440266059SGregory Neil Shapiro #if NAMED_BIND
442540266059SGregory Neil Shapiro _res.retry = TimeOuts.res_retry[RES_TO_FIRST];
442640266059SGregory Neil Shapiro _res.retrans = TimeOuts.res_retrans[RES_TO_FIRST];
44275b0945b5SGregory Neil Shapiro #endif
442840266059SGregory Neil Shapiro
4429da7d7b9cSGregory Neil Shapiro #if _FFR_PROXY
4430da7d7b9cSGregory Neil Shapiro if (SM_PROXY_REQ == e->e_sendmode)
4431da7d7b9cSGregory Neil Shapiro {
4432da7d7b9cSGregory Neil Shapiro /* is proxy mode possible? */
4433da7d7b9cSGregory Neil Shapiro if (e->e_sibling == NULL && e->e_nrcpts == 1
4434da7d7b9cSGregory Neil Shapiro && smtp->sm_nrcpts == 1
4435da7d7b9cSGregory Neil Shapiro && (a = e->e_sendqueue) != NULL && a->q_next == NULL)
4436da7d7b9cSGregory Neil Shapiro {
4437da7d7b9cSGregory Neil Shapiro a->q_flags &= ~(QPINGONFAILURE|QPINGONSUCCESS|
4438da7d7b9cSGregory Neil Shapiro QPINGONDELAY);
4439da7d7b9cSGregory Neil Shapiro e->e_errormode = EM_QUIET;
4440da7d7b9cSGregory Neil Shapiro e->e_sendmode = SM_PROXY;
4441da7d7b9cSGregory Neil Shapiro }
4442da7d7b9cSGregory Neil Shapiro else
4443da7d7b9cSGregory Neil Shapiro {
4444da7d7b9cSGregory Neil Shapiro if (tTd(87, 2))
4445da7d7b9cSGregory Neil Shapiro {
4446da7d7b9cSGregory Neil Shapiro a = e->e_sendqueue;
4447da7d7b9cSGregory Neil Shapiro sm_dprintf("srv: mode=%c, e=%p, sibling=%p, nrcpts=%d, sm_nrcpts=%d, sendqueue=%p, next=%p\n",
4448da7d7b9cSGregory Neil Shapiro e->e_sendmode, e, e->e_sibling, e->e_nrcpts,
4449da7d7b9cSGregory Neil Shapiro smtp->sm_nrcpts, a,
4450da7d7b9cSGregory Neil Shapiro (a == NULL) ? (void *)0 : a->q_next);
4451da7d7b9cSGregory Neil Shapiro }
4452da7d7b9cSGregory Neil Shapiro
4453da7d7b9cSGregory Neil Shapiro /* switch to interactive mode */
4454da7d7b9cSGregory Neil Shapiro e->e_sendmode = SM_DELIVER;
4455da7d7b9cSGregory Neil Shapiro if (LogLevel > 9)
4456da7d7b9cSGregory Neil Shapiro sm_syslog(LOG_DEBUG, e->e_id,
4457da7d7b9cSGregory Neil Shapiro "proxy mode requested but not possible");
4458da7d7b9cSGregory Neil Shapiro }
4459da7d7b9cSGregory Neil Shapiro }
4460da7d7b9cSGregory Neil Shapiro #endif /* _FFR_PROXY */
44616f9c8e5bSGregory Neil Shapiro
44622fb4f839SGregory Neil Shapiro #if _FFR_DMTRIGGER
44632fb4f839SGregory Neil Shapiro if (SM_TRIGGER == e->e_sendmode)
44642fb4f839SGregory Neil Shapiro doublequeue = true;
44652fb4f839SGregory Neil Shapiro #endif
446640266059SGregory Neil Shapiro for (ee = e; ee != NULL; ee = ee->e_sibling)
446740266059SGregory Neil Shapiro {
446840266059SGregory Neil Shapiro /* make sure we actually do delivery */
446940266059SGregory Neil Shapiro ee->e_flags &= ~EF_CLRQUEUE;
447040266059SGregory Neil Shapiro
447140266059SGregory Neil Shapiro /* from now on, operate silently */
447240266059SGregory Neil Shapiro ee->e_errormode = EM_MAIL;
447340266059SGregory Neil Shapiro
447440266059SGregory Neil Shapiro if (doublequeue)
447540266059SGregory Neil Shapiro {
44762fb4f839SGregory Neil Shapiro unsigned int qup_flags;
44772fb4f839SGregory Neil Shapiro
44782fb4f839SGregory Neil Shapiro qup_flags = QUP_FL_MSYNC;
44792fb4f839SGregory Neil Shapiro #if _FFR_DMTRIGGER
44802fb4f839SGregory Neil Shapiro if (IS_SM_TRIGGER(ee->e_sendmode))
44812fb4f839SGregory Neil Shapiro qup_flags |= QUP_FL_UNLOCK;
44822fb4f839SGregory Neil Shapiro #endif
448340266059SGregory Neil Shapiro /* make sure it is in the queue */
44842fb4f839SGregory Neil Shapiro queueup(ee, qup_flags);
448540266059SGregory Neil Shapiro }
448640266059SGregory Neil Shapiro else
448740266059SGregory Neil Shapiro {
44884e4196cbSGregory Neil Shapiro int mode;
44894e4196cbSGregory Neil Shapiro
449040266059SGregory Neil Shapiro /* send to all recipients */
44914e4196cbSGregory Neil Shapiro mode = SM_DEFAULT;
44924e4196cbSGregory Neil Shapiro #if _FFR_DM_ONE
44934e4196cbSGregory Neil Shapiro if (SM_DM_ONE == e->e_sendmode)
44944e4196cbSGregory Neil Shapiro {
44954e4196cbSGregory Neil Shapiro if (NotFirstDelivery)
44964e4196cbSGregory Neil Shapiro {
44974e4196cbSGregory Neil Shapiro mode = SM_QUEUE;
44984e4196cbSGregory Neil Shapiro e->e_sendmode = SM_QUEUE;
44994e4196cbSGregory Neil Shapiro }
45004e4196cbSGregory Neil Shapiro else
45014e4196cbSGregory Neil Shapiro {
45024e4196cbSGregory Neil Shapiro mode = SM_FORK;
45034e4196cbSGregory Neil Shapiro NotFirstDelivery = true;
45044e4196cbSGregory Neil Shapiro }
45054e4196cbSGregory Neil Shapiro }
45064e4196cbSGregory Neil Shapiro #endif /* _FFR_DM_ONE */
45074e4196cbSGregory Neil Shapiro sendall(ee, mode);
450840266059SGregory Neil Shapiro }
450940266059SGregory Neil Shapiro ee->e_to = NULL;
451040266059SGregory Neil Shapiro }
451140266059SGregory Neil Shapiro
451294c01205SGregory Neil Shapiro /* put back id for SMTP logging in putoutmsg() */
451394c01205SGregory Neil Shapiro oldid = CurEnv->e_id;
451494c01205SGregory Neil Shapiro CurEnv->e_id = id;
451594c01205SGregory Neil Shapiro
4516da7d7b9cSGregory Neil Shapiro #if _FFR_PROXY
4517da7d7b9cSGregory Neil Shapiro a = e->e_sendqueue;
4518da7d7b9cSGregory Neil Shapiro if (tTd(87, 1))
4519da7d7b9cSGregory Neil Shapiro {
4520da7d7b9cSGregory Neil Shapiro sm_dprintf("srv: mode=%c, e=%p, sibling=%p, nrcpts=%d, msg=%s, sendqueue=%p, next=%p, state=%d, SmtpError=%s, rcode=%d, renhsc=%s, text=%s\n",
4521da7d7b9cSGregory Neil Shapiro e->e_sendmode, e, e->e_sibling, e->e_nrcpts, e->e_message, a,
4522da7d7b9cSGregory Neil Shapiro (a == NULL) ? (void *)0 : a->q_next,
4523da7d7b9cSGregory Neil Shapiro (a == NULL) ? -1 : a->q_state, SmtpError, e->e_rcode,
4524da7d7b9cSGregory Neil Shapiro e->e_renhsc, e->e_text);
4525da7d7b9cSGregory Neil Shapiro }
4526da7d7b9cSGregory Neil Shapiro
4527da7d7b9cSGregory Neil Shapiro if (SM_PROXY == e->e_sendmode && a->q_state != QS_SENT &&
4528da7d7b9cSGregory Neil Shapiro a->q_state != QS_VERIFIED) /* discarded! */
4529da7d7b9cSGregory Neil Shapiro {
4530da7d7b9cSGregory Neil Shapiro char *m, *errtext;
4531da7d7b9cSGregory Neil Shapiro char replycode[4];
4532da7d7b9cSGregory Neil Shapiro char enhsc[10];
4533da7d7b9cSGregory Neil Shapiro int offset;
4534da7d7b9cSGregory Neil Shapiro
4535da7d7b9cSGregory Neil Shapiro #define NN_MSG(e) (((e)->e_message != NULL) ? (e)->e_message : "")
4536da7d7b9cSGregory Neil Shapiro m = e->e_message;
4537da7d7b9cSGregory Neil Shapiro #define SM_MSG_DEFERRED "Deferred: "
4538da7d7b9cSGregory Neil Shapiro if (m != NULL && strncmp(SM_MSG_DEFERRED, m,
4539da7d7b9cSGregory Neil Shapiro sizeof(SM_MSG_DEFERRED) - 1) == 0)
4540da7d7b9cSGregory Neil Shapiro m += sizeof(SM_MSG_DEFERRED) - 1;
4541da7d7b9cSGregory Neil Shapiro offset = extsc(m, ' ', replycode, enhsc);
4542da7d7b9cSGregory Neil Shapiro
4543da7d7b9cSGregory Neil Shapiro if (tTd(87, 2))
4544da7d7b9cSGregory Neil Shapiro {
4545da7d7b9cSGregory Neil Shapiro sm_dprintf("srv: SmtpError=%s, rcode=%d, renhsc=%s, replycode=%s, enhsc=%s, offset=%d\n",
4546da7d7b9cSGregory Neil Shapiro SmtpError, e->e_rcode, e->e_renhsc,
4547da7d7b9cSGregory Neil Shapiro replycode, enhsc, offset);
4548da7d7b9cSGregory Neil Shapiro }
4549da7d7b9cSGregory Neil Shapiro
4550da7d7b9cSGregory Neil Shapiro #define DIG2CHAR(d) ((d) + '0')
4551da7d7b9cSGregory Neil Shapiro if (e->e_rcode != 0 && (replycode[0] == '\0' ||
4552da7d7b9cSGregory Neil Shapiro replycode[0] == DIG2CHAR(REPLYTYPE(e->e_rcode))))
4553da7d7b9cSGregory Neil Shapiro {
4554da7d7b9cSGregory Neil Shapiro replycode[0] = DIG2CHAR(REPLYTYPE(e->e_rcode));
4555da7d7b9cSGregory Neil Shapiro replycode[1] = DIG2CHAR(REPLYCLASS(e->e_rcode));
4556da7d7b9cSGregory Neil Shapiro replycode[2] = DIG2CHAR(REPLYMINOR(e->e_rcode));
4557da7d7b9cSGregory Neil Shapiro replycode[3] = '\0';
4558da7d7b9cSGregory Neil Shapiro if (e->e_renhsc[0] == replycode[0])
4559da7d7b9cSGregory Neil Shapiro sm_strlcpy(enhsc, e->e_renhsc, sizeof(enhsc));
4560da7d7b9cSGregory Neil Shapiro if (offset < 0)
4561da7d7b9cSGregory Neil Shapiro offset = 0;
4562da7d7b9cSGregory Neil Shapiro }
4563da7d7b9cSGregory Neil Shapiro if (e->e_text != NULL)
4564da7d7b9cSGregory Neil Shapiro {
4565da7d7b9cSGregory Neil Shapiro (void) strreplnonprt(e->e_text, '_');
4566da7d7b9cSGregory Neil Shapiro errtext = e->e_text;
4567da7d7b9cSGregory Neil Shapiro }
4568da7d7b9cSGregory Neil Shapiro else
4569da7d7b9cSGregory Neil Shapiro errtext = m + offset;
4570da7d7b9cSGregory Neil Shapiro
4571da7d7b9cSGregory Neil Shapiro if (replycode[0] != '\0' && enhsc[0] != '\0')
4572da7d7b9cSGregory Neil Shapiro emessage(replycode, enhsc, "%s", errtext);
4573da7d7b9cSGregory Neil Shapiro else if (replycode[0] != '\0')
4574da7d7b9cSGregory Neil Shapiro emessage(replycode, smtptodsn(atoi(replycode)),
4575da7d7b9cSGregory Neil Shapiro "%s", errtext);
4576da7d7b9cSGregory Neil Shapiro else if (QS_IS_TEMPFAIL(a->q_state))
4577da7d7b9cSGregory Neil Shapiro {
4578da7d7b9cSGregory Neil Shapiro if (m != NULL)
4579da7d7b9cSGregory Neil Shapiro message("450 4.5.1 %s", m);
4580da7d7b9cSGregory Neil Shapiro else
4581da7d7b9cSGregory Neil Shapiro message("450 4.5.1 Temporary error");
4582da7d7b9cSGregory Neil Shapiro }
4583da7d7b9cSGregory Neil Shapiro else
4584da7d7b9cSGregory Neil Shapiro {
4585da7d7b9cSGregory Neil Shapiro if (m != NULL)
4586da7d7b9cSGregory Neil Shapiro message("550 5.5.1 %s", m);
4587da7d7b9cSGregory Neil Shapiro else
4588da7d7b9cSGregory Neil Shapiro message("550 5.0.0 Permanent error");
4589da7d7b9cSGregory Neil Shapiro }
4590da7d7b9cSGregory Neil Shapiro }
4591da7d7b9cSGregory Neil Shapiro else
4592da7d7b9cSGregory Neil Shapiro {
4593da7d7b9cSGregory Neil Shapiro #endif /* _FFR_PROXY */
459440266059SGregory Neil Shapiro /* issue success message */
45954e4196cbSGregory Neil Shapiro #if _FFR_MSG_ACCEPT
45964e4196cbSGregory Neil Shapiro if (MessageAccept != NULL && *MessageAccept != '\0')
45974e4196cbSGregory Neil Shapiro {
45984e4196cbSGregory Neil Shapiro char msg[MAXLINE];
45994e4196cbSGregory Neil Shapiro
4600d0cef73dSGregory Neil Shapiro expand(MessageAccept, msg, sizeof(msg), e);
46014e4196cbSGregory Neil Shapiro message("250 2.0.0 %s", msg);
46024e4196cbSGregory Neil Shapiro }
46034e4196cbSGregory Neil Shapiro else
46044e4196cbSGregory Neil Shapiro #endif /* _FFR_MSG_ACCEPT */
46052fb4f839SGregory Neil Shapiro /* "else" in #if code above */
460640266059SGregory Neil Shapiro message("250 2.0.0 %s Message accepted for delivery", id);
4607da7d7b9cSGregory Neil Shapiro #if _FFR_PROXY
4608da7d7b9cSGregory Neil Shapiro }
46095b0945b5SGregory Neil Shapiro #endif
461094c01205SGregory Neil Shapiro CurEnv->e_id = oldid;
461140266059SGregory Neil Shapiro
461240266059SGregory Neil Shapiro /* if we just queued, poke it */
461340266059SGregory Neil Shapiro if (doublequeue)
461440266059SGregory Neil Shapiro {
461540266059SGregory Neil Shapiro bool anything_to_send = false;
461640266059SGregory Neil Shapiro
461740266059SGregory Neil Shapiro sm_getla();
461840266059SGregory Neil Shapiro for (ee = e; ee != NULL; ee = ee->e_sibling)
461940266059SGregory Neil Shapiro {
46202fb4f839SGregory Neil Shapiro #if _FFR_DMTRIGGER
46212fb4f839SGregory Neil Shapiro if (SM_TRIGGER == ee->e_sendmode)
46222fb4f839SGregory Neil Shapiro {
46232fb4f839SGregory Neil Shapiro sm_syslog(LOG_DEBUG, ee->e_id,
46242fb4f839SGregory Neil Shapiro "smtp: doublequeue, mode=%c", ee->e_sendmode);
46252fb4f839SGregory Neil Shapiro ee->e_sendmode = SM_DELIVER;
46262fb4f839SGregory Neil Shapiro
46272fb4f839SGregory Neil Shapiro /* close all the queue files */
46282fb4f839SGregory Neil Shapiro /* almost the same as below */
46292fb4f839SGregory Neil Shapiro closexscript(ee);
46302fb4f839SGregory Neil Shapiro SM_CLOSE_FP(ee->e_dfp);
46312fb4f839SGregory Neil Shapiro continue;
46322fb4f839SGregory Neil Shapiro }
46332fb4f839SGregory Neil Shapiro #endif /* _FFR_DMTRIGGER */
463440266059SGregory Neil Shapiro if (WILL_BE_QUEUED(ee->e_sendmode))
463540266059SGregory Neil Shapiro continue;
463640266059SGregory Neil Shapiro if (shouldqueue(ee->e_msgpriority, ee->e_ctime))
463740266059SGregory Neil Shapiro {
463840266059SGregory Neil Shapiro ee->e_sendmode = SM_QUEUE;
463940266059SGregory Neil Shapiro continue;
464040266059SGregory Neil Shapiro }
464140266059SGregory Neil Shapiro else if (QueueMode != QM_QUARANTINE &&
464240266059SGregory Neil Shapiro ee->e_quarmsg != NULL)
464340266059SGregory Neil Shapiro {
464440266059SGregory Neil Shapiro ee->e_sendmode = SM_QUEUE;
464540266059SGregory Neil Shapiro continue;
464640266059SGregory Neil Shapiro }
464740266059SGregory Neil Shapiro anything_to_send = true;
464840266059SGregory Neil Shapiro
464940266059SGregory Neil Shapiro /* close all the queue files */
465040266059SGregory Neil Shapiro closexscript(ee);
46512fb4f839SGregory Neil Shapiro SM_CLOSE_FP(ee->e_dfp);
465240266059SGregory Neil Shapiro unlockqueue(ee);
465340266059SGregory Neil Shapiro }
465440266059SGregory Neil Shapiro if (anything_to_send)
465540266059SGregory Neil Shapiro {
465640266059SGregory Neil Shapiro #if PIPELINING
465740266059SGregory Neil Shapiro /*
465840266059SGregory Neil Shapiro ** XXX if we don't do this, we get 250 twice
465940266059SGregory Neil Shapiro ** because it is also flushed in the child.
466040266059SGregory Neil Shapiro */
466140266059SGregory Neil Shapiro
466240266059SGregory Neil Shapiro (void) sm_io_flush(OutChannel, SM_TIME_DEFAULT);
466340266059SGregory Neil Shapiro #endif /* PIPELINING */
46642fb4f839SGregory Neil Shapiro #if _FFR_DMTRIGGER
46652fb4f839SGregory Neil Shapiro sm_syslog(LOG_DEBUG, e->e_id, "smtp: doublequeue=send");
46662fb4f839SGregory Neil Shapiro #endif
466740266059SGregory Neil Shapiro (void) doworklist(e, true, true);
466840266059SGregory Neil Shapiro }
466940266059SGregory Neil Shapiro }
467040266059SGregory Neil Shapiro
467140266059SGregory Neil Shapiro abortmessage:
46729bd497b8SGregory Neil Shapiro if (tTd(92, 2))
46739bd497b8SGregory Neil Shapiro sm_dprintf("abortmessage: e_id=%s, EF_LOGSENDER=%d, LogLevel=%d\n",
46749bd497b8SGregory Neil Shapiro e->e_id, bitset(EF_LOGSENDER, e->e_flags), LogLevel);
467540266059SGregory Neil Shapiro if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags))
467640266059SGregory Neil Shapiro logsender(e, NULL);
467740266059SGregory Neil Shapiro e->e_flags &= ~EF_LOGSENDER;
467840266059SGregory Neil Shapiro
467940266059SGregory Neil Shapiro /* clean up a bit */
468040266059SGregory Neil Shapiro smtp->sm_gotmail = false;
468140266059SGregory Neil Shapiro
468240266059SGregory Neil Shapiro /*
468340266059SGregory Neil Shapiro ** Call dropenvelope if and only if the envelope is *not*
468440266059SGregory Neil Shapiro ** being processed by the child process forked by doworklist().
468540266059SGregory Neil Shapiro */
468640266059SGregory Neil Shapiro
468740266059SGregory Neil Shapiro if (aborting || bitset(EF_DISCARD, e->e_flags))
46889bd497b8SGregory Neil Shapiro (void) dropenvelope(e, true, false);
468940266059SGregory Neil Shapiro else
469040266059SGregory Neil Shapiro {
469140266059SGregory Neil Shapiro for (ee = e; ee != NULL; ee = ee->e_sibling)
469240266059SGregory Neil Shapiro {
469340266059SGregory Neil Shapiro if (!doublequeue &&
469440266059SGregory Neil Shapiro QueueMode != QM_QUARANTINE &&
469540266059SGregory Neil Shapiro ee->e_quarmsg != NULL)
469640266059SGregory Neil Shapiro {
46979bd497b8SGregory Neil Shapiro (void) dropenvelope(ee, true, false);
469840266059SGregory Neil Shapiro continue;
469940266059SGregory Neil Shapiro }
470040266059SGregory Neil Shapiro if (WILL_BE_QUEUED(ee->e_sendmode))
47019bd497b8SGregory Neil Shapiro (void) dropenvelope(ee, true, false);
470240266059SGregory Neil Shapiro }
470340266059SGregory Neil Shapiro }
470440266059SGregory Neil Shapiro
470540266059SGregory Neil Shapiro CurEnv = e;
4706d0cef73dSGregory Neil Shapiro features = e->e_features;
4707e3793f76SGregory Neil Shapiro sm_rpool_free(e->e_rpool);
470840266059SGregory Neil Shapiro newenvelope(e, e, sm_rpool_new_x(NULL));
470940266059SGregory Neil Shapiro e->e_flags = BlankEnvelope.e_flags;
4710d0cef73dSGregory Neil Shapiro e->e_features = features;
471140266059SGregory Neil Shapiro
471240266059SGregory Neil Shapiro /* restore connection quarantining */
471340266059SGregory Neil Shapiro if (smtp->sm_quarmsg == NULL)
471440266059SGregory Neil Shapiro {
471540266059SGregory Neil Shapiro e->e_quarmsg = NULL;
471640266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), "");
471740266059SGregory Neil Shapiro }
471840266059SGregory Neil Shapiro else
471940266059SGregory Neil Shapiro {
472040266059SGregory Neil Shapiro e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, smtp->sm_quarmsg);
472140266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
472240266059SGregory Neil Shapiro macid("{quarantine}"), e->e_quarmsg);
472340266059SGregory Neil Shapiro }
47244e4196cbSGregory Neil Shapiro return rv;
472540266059SGregory Neil Shapiro }
472640266059SGregory Neil Shapiro /*
472740266059SGregory Neil Shapiro ** LOGUNDELRCPTS -- log undelivered (or all) recipients.
472840266059SGregory Neil Shapiro **
472940266059SGregory Neil Shapiro ** Parameters:
473040266059SGregory Neil Shapiro ** e -- envelope.
473140266059SGregory Neil Shapiro ** msg -- message for Stat=
473240266059SGregory Neil Shapiro ** level -- log level.
473340266059SGregory Neil Shapiro ** all -- log all recipients.
473440266059SGregory Neil Shapiro **
473540266059SGregory Neil Shapiro ** Returns:
473640266059SGregory Neil Shapiro ** none.
473740266059SGregory Neil Shapiro **
473840266059SGregory Neil Shapiro ** Side Effects:
473940266059SGregory Neil Shapiro ** logs undelivered (or all) recipients
474040266059SGregory Neil Shapiro */
474140266059SGregory Neil Shapiro
474240266059SGregory Neil Shapiro void
logundelrcpts(e,msg,level,all)474340266059SGregory Neil Shapiro logundelrcpts(e, msg, level, all)
474440266059SGregory Neil Shapiro ENVELOPE *e;
474540266059SGregory Neil Shapiro char *msg;
474640266059SGregory Neil Shapiro int level;
474740266059SGregory Neil Shapiro bool all;
474840266059SGregory Neil Shapiro {
474940266059SGregory Neil Shapiro ADDRESS *a;
475040266059SGregory Neil Shapiro
475140266059SGregory Neil Shapiro if (LogLevel <= level || msg == NULL || *msg == '\0')
475240266059SGregory Neil Shapiro return;
475340266059SGregory Neil Shapiro
475440266059SGregory Neil Shapiro /* Clear $h so relay= doesn't get mislogged by logdelivery() */
475540266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 'h', NULL);
475640266059SGregory Neil Shapiro
475740266059SGregory Neil Shapiro /* Log who the mail would have gone to */
475840266059SGregory Neil Shapiro for (a = e->e_sendqueue; a != NULL; a = a->q_next)
475940266059SGregory Neil Shapiro {
476040266059SGregory Neil Shapiro if (!QS_IS_UNDELIVERED(a->q_state) && !all)
476140266059SGregory Neil Shapiro continue;
476240266059SGregory Neil Shapiro e->e_to = a->q_paddr;
47639bd497b8SGregory Neil Shapiro logdelivery(NULL, NULL,
47649bd497b8SGregory Neil Shapiro #if _FFR_MILTER_ENHSC
47659bd497b8SGregory Neil Shapiro (a->q_status == NULL && e->e_enhsc[0] != '\0')
47669bd497b8SGregory Neil Shapiro ? e->e_enhsc :
47675b0945b5SGregory Neil Shapiro #endif
47682fb4f839SGregory Neil Shapiro /* not yet documented or tested */
47692fb4f839SGregory Neil Shapiro #if _FFR_USE_E_STATUS
47702fb4f839SGregory Neil Shapiro (NULL == a->q_status) ? e->e_status :
47712fb4f839SGregory Neil Shapiro #endif
47729bd497b8SGregory Neil Shapiro a->q_status,
4773da7d7b9cSGregory Neil Shapiro msg, NULL, (time_t) 0, e, a, EX_OK /* ??? */);
477440266059SGregory Neil Shapiro }
477540266059SGregory Neil Shapiro e->e_to = NULL;
477640266059SGregory Neil Shapiro }
477740266059SGregory Neil Shapiro /*
4778c2aa98e2SPeter Wemm ** CHECKSMTPATTACK -- check for denial-of-service attack by repetition
4779c2aa98e2SPeter Wemm **
4780c2aa98e2SPeter Wemm ** Parameters:
4781c2aa98e2SPeter Wemm ** pcounter -- pointer to a counter for this command.
4782c2aa98e2SPeter Wemm ** maxcount -- maximum value for this counter before we
4783c2aa98e2SPeter Wemm ** slow down.
478406f25ae9SGregory Neil Shapiro ** waitnow -- sleep now (in this routine)?
4785c2aa98e2SPeter Wemm ** cname -- command name for logging.
4786c2aa98e2SPeter Wemm ** e -- the current envelope.
4787c2aa98e2SPeter Wemm **
4788c2aa98e2SPeter Wemm ** Returns:
4789e92d3f3fSGregory Neil Shapiro ** time to wait,
4790e92d3f3fSGregory Neil Shapiro ** STOP_ATTACK if twice as many commands as allowed and
4791e92d3f3fSGregory Neil Shapiro ** MaxChildren > 0.
4792c2aa98e2SPeter Wemm **
4793c2aa98e2SPeter Wemm ** Side Effects:
4794c2aa98e2SPeter Wemm ** Slows down if we seem to be under attack.
4795c2aa98e2SPeter Wemm */
4796c2aa98e2SPeter Wemm
479706f25ae9SGregory Neil Shapiro static time_t
checksmtpattack(pcounter,maxcount,waitnow,cname,e)479806f25ae9SGregory Neil Shapiro checksmtpattack(pcounter, maxcount, waitnow, cname, e)
479940266059SGregory Neil Shapiro volatile unsigned int *pcounter;
4800e92d3f3fSGregory Neil Shapiro unsigned int maxcount;
480106f25ae9SGregory Neil Shapiro bool waitnow;
4802c2aa98e2SPeter Wemm char *cname;
4803c2aa98e2SPeter Wemm ENVELOPE *e;
4804c2aa98e2SPeter Wemm {
480540266059SGregory Neil Shapiro if (maxcount <= 0) /* no limit */
480640266059SGregory Neil Shapiro return (time_t) 0;
480740266059SGregory Neil Shapiro
4808c2aa98e2SPeter Wemm if (++(*pcounter) >= maxcount)
4809c2aa98e2SPeter Wemm {
4810e92d3f3fSGregory Neil Shapiro unsigned int shift;
481106f25ae9SGregory Neil Shapiro time_t s;
481206f25ae9SGregory Neil Shapiro
4813c2aa98e2SPeter Wemm if (*pcounter == maxcount && LogLevel > 5)
4814c2aa98e2SPeter Wemm {
4815c2aa98e2SPeter Wemm sm_syslog(LOG_INFO, e->e_id,
481613bd1963SGregory Neil Shapiro "%s: possible SMTP attack: command=%.40s, count=%u",
48178774250cSGregory Neil Shapiro CurSmtpClient, cname, *pcounter);
4818c2aa98e2SPeter Wemm }
4819e92d3f3fSGregory Neil Shapiro shift = *pcounter - maxcount;
4820e92d3f3fSGregory Neil Shapiro s = 1 << shift;
4821e92d3f3fSGregory Neil Shapiro if (shift > MAXSHIFT || s >= MAXTIMEOUT || s <= 0)
482206f25ae9SGregory Neil Shapiro s = MAXTIMEOUT;
482340266059SGregory Neil Shapiro
4824e92d3f3fSGregory Neil Shapiro #define IS_ATTACK(s) ((MaxChildren > 0 && *pcounter >= maxcount * 2) \
4825e92d3f3fSGregory Neil Shapiro ? STOP_ATTACK : (time_t) s)
4826e92d3f3fSGregory Neil Shapiro
482706f25ae9SGregory Neil Shapiro /* sleep at least 1 second before returning */
482806f25ae9SGregory Neil Shapiro (void) sleep(*pcounter / maxcount);
482906f25ae9SGregory Neil Shapiro s -= *pcounter / maxcount;
4830e92d3f3fSGregory Neil Shapiro if (s >= MAXTIMEOUT || s < 0)
4831e92d3f3fSGregory Neil Shapiro s = MAXTIMEOUT;
4832e92d3f3fSGregory Neil Shapiro if (waitnow && s > 0)
483306f25ae9SGregory Neil Shapiro {
483406f25ae9SGregory Neil Shapiro (void) sleep(s);
4835e92d3f3fSGregory Neil Shapiro return IS_ATTACK(0);
4836c2aa98e2SPeter Wemm }
4837e92d3f3fSGregory Neil Shapiro return IS_ATTACK(s);
483806f25ae9SGregory Neil Shapiro }
483940266059SGregory Neil Shapiro return (time_t) 0;
4840c2aa98e2SPeter Wemm }
484140266059SGregory Neil Shapiro /*
484240266059SGregory Neil Shapiro ** SETUP_SMTPD_IO -- setup I/O fd correctly for the SMTP server
484340266059SGregory Neil Shapiro **
484440266059SGregory Neil Shapiro ** Parameters:
484540266059SGregory Neil Shapiro ** none.
484640266059SGregory Neil Shapiro **
484740266059SGregory Neil Shapiro ** Returns:
484840266059SGregory Neil Shapiro ** nothing.
484940266059SGregory Neil Shapiro **
485040266059SGregory Neil Shapiro ** Side Effects:
485140266059SGregory Neil Shapiro ** may change I/O fd.
485240266059SGregory Neil Shapiro */
485340266059SGregory Neil Shapiro
485440266059SGregory Neil Shapiro static void
setup_smtpd_io()485540266059SGregory Neil Shapiro setup_smtpd_io()
485640266059SGregory Neil Shapiro {
485740266059SGregory Neil Shapiro int inchfd, outchfd, outfd;
485840266059SGregory Neil Shapiro
485940266059SGregory Neil Shapiro inchfd = sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL);
486040266059SGregory Neil Shapiro outchfd = sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL);
486140266059SGregory Neil Shapiro outfd = sm_io_getinfo(smioout, SM_IO_WHAT_FD, NULL);
486240266059SGregory Neil Shapiro if (outchfd != outfd)
486340266059SGregory Neil Shapiro {
486440266059SGregory Neil Shapiro /* arrange for debugging output to go to remote host */
486540266059SGregory Neil Shapiro (void) dup2(outchfd, outfd);
486640266059SGregory Neil Shapiro }
486740266059SGregory Neil Shapiro
486840266059SGregory Neil Shapiro /*
486940266059SGregory Neil Shapiro ** if InChannel and OutChannel are stdin/stdout
487040266059SGregory Neil Shapiro ** and connected to ttys
487140266059SGregory Neil Shapiro ** and fcntl(STDIN, F_SETFL, O_NONBLOCKING) also changes STDOUT,
487240266059SGregory Neil Shapiro ** then "chain" them together.
487340266059SGregory Neil Shapiro */
487440266059SGregory Neil Shapiro
487540266059SGregory Neil Shapiro if (inchfd == STDIN_FILENO && outchfd == STDOUT_FILENO &&
487640266059SGregory Neil Shapiro isatty(inchfd) && isatty(outchfd))
487740266059SGregory Neil Shapiro {
487840266059SGregory Neil Shapiro int inmode, outmode;
487940266059SGregory Neil Shapiro
488040266059SGregory Neil Shapiro inmode = fcntl(inchfd, F_GETFL, 0);
488140266059SGregory Neil Shapiro if (inmode == -1)
488240266059SGregory Neil Shapiro {
488340266059SGregory Neil Shapiro if (LogLevel > 11)
488440266059SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID,
488540266059SGregory Neil Shapiro "fcntl(inchfd, F_GETFL) failed: %s",
488640266059SGregory Neil Shapiro sm_errstring(errno));
488740266059SGregory Neil Shapiro return;
488840266059SGregory Neil Shapiro }
488940266059SGregory Neil Shapiro outmode = fcntl(outchfd, F_GETFL, 0);
489040266059SGregory Neil Shapiro if (outmode == -1)
489140266059SGregory Neil Shapiro {
489240266059SGregory Neil Shapiro if (LogLevel > 11)
489340266059SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID,
489440266059SGregory Neil Shapiro "fcntl(outchfd, F_GETFL) failed: %s",
489540266059SGregory Neil Shapiro sm_errstring(errno));
489640266059SGregory Neil Shapiro return;
489740266059SGregory Neil Shapiro }
489840266059SGregory Neil Shapiro if (bitset(O_NONBLOCK, inmode) ||
489940266059SGregory Neil Shapiro bitset(O_NONBLOCK, outmode) ||
490040266059SGregory Neil Shapiro fcntl(inchfd, F_SETFL, inmode | O_NONBLOCK) == -1)
490140266059SGregory Neil Shapiro return;
490240266059SGregory Neil Shapiro outmode = fcntl(outchfd, F_GETFL, 0);
490340266059SGregory Neil Shapiro if (outmode != -1 && bitset(O_NONBLOCK, outmode))
490440266059SGregory Neil Shapiro {
490540266059SGregory Neil Shapiro /* changing InChannel also changes OutChannel */
490640266059SGregory Neil Shapiro sm_io_automode(OutChannel, InChannel);
490740266059SGregory Neil Shapiro if (tTd(97, 4) && LogLevel > 9)
490840266059SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID,
490940266059SGregory Neil Shapiro "set automode for I (%d)/O (%d) in SMTP server",
491040266059SGregory Neil Shapiro inchfd, outchfd);
491140266059SGregory Neil Shapiro }
491240266059SGregory Neil Shapiro
491340266059SGregory Neil Shapiro /* undo change of inchfd */
491440266059SGregory Neil Shapiro (void) fcntl(inchfd, F_SETFL, inmode);
491540266059SGregory Neil Shapiro }
491640266059SGregory Neil Shapiro }
491740266059SGregory Neil Shapiro /*
4918c2aa98e2SPeter Wemm ** SKIPWORD -- skip a fixed word.
4919c2aa98e2SPeter Wemm **
4920c2aa98e2SPeter Wemm ** Parameters:
4921c2aa98e2SPeter Wemm ** p -- place to start looking.
4922c2aa98e2SPeter Wemm ** w -- word to skip.
4923c2aa98e2SPeter Wemm **
4924c2aa98e2SPeter Wemm ** Returns:
4925c2aa98e2SPeter Wemm ** p following w.
4926c2aa98e2SPeter Wemm ** NULL on error.
4927c2aa98e2SPeter Wemm **
4928c2aa98e2SPeter Wemm ** Side Effects:
4929c2aa98e2SPeter Wemm ** clobbers the p data area.
4930c2aa98e2SPeter Wemm */
4931c2aa98e2SPeter Wemm
4932c2aa98e2SPeter Wemm static char *
skipword(p,w)4933c2aa98e2SPeter Wemm skipword(p, w)
4934c2aa98e2SPeter Wemm register char *volatile p;
4935c2aa98e2SPeter Wemm char *w;
4936c2aa98e2SPeter Wemm {
4937c2aa98e2SPeter Wemm register char *q;
4938c2aa98e2SPeter Wemm char *firstp = p;
4939c2aa98e2SPeter Wemm
4940c2aa98e2SPeter Wemm /* find beginning of word */
494140266059SGregory Neil Shapiro SKIP_SPACE(p);
4942c2aa98e2SPeter Wemm q = p;
4943c2aa98e2SPeter Wemm
4944c2aa98e2SPeter Wemm /* find end of word */
49455b0945b5SGregory Neil Shapiro while (*p != '\0' && *p != ':' && !(SM_ISSPACE(*p)))
4946c2aa98e2SPeter Wemm p++;
49475b0945b5SGregory Neil Shapiro while (SM_ISSPACE(*p))
4948c2aa98e2SPeter Wemm *p++ = '\0';
4949c2aa98e2SPeter Wemm if (*p != ':')
4950c2aa98e2SPeter Wemm {
4951c2aa98e2SPeter Wemm syntax:
495206f25ae9SGregory Neil Shapiro usrerr("501 5.5.2 Syntax error in parameters scanning \"%s\"",
49532fb4f839SGregory Neil Shapiro SHOWSHRTCMDINREPLY(firstp));
495406f25ae9SGregory Neil Shapiro return NULL;
4955c2aa98e2SPeter Wemm }
4956c2aa98e2SPeter Wemm *p++ = '\0';
495740266059SGregory Neil Shapiro SKIP_SPACE(p);
4958c2aa98e2SPeter Wemm
4959c2aa98e2SPeter Wemm if (*p == '\0')
4960c2aa98e2SPeter Wemm goto syntax;
4961c2aa98e2SPeter Wemm
4962c2aa98e2SPeter Wemm /* see if the input word matches desired word */
496340266059SGregory Neil Shapiro if (sm_strcasecmp(q, w))
4964c2aa98e2SPeter Wemm goto syntax;
4965c2aa98e2SPeter Wemm
496606f25ae9SGregory Neil Shapiro return p;
4967c2aa98e2SPeter Wemm }
4968af9557fdSGregory Neil Shapiro
496940266059SGregory Neil Shapiro /*
4970*d39bd2c1SGregory Neil Shapiro ** RESET_MAIL_ESMTP_ARGS -- reset ESMTP arguments for MAIL
4971c2aa98e2SPeter Wemm **
4972c2aa98e2SPeter Wemm ** Parameters:
4973c2aa98e2SPeter Wemm ** e -- the envelope.
4974c2aa98e2SPeter Wemm **
4975c2aa98e2SPeter Wemm ** Returns:
4976c2aa98e2SPeter Wemm ** none.
4977c2aa98e2SPeter Wemm */
4978c2aa98e2SPeter Wemm
4979d0cef73dSGregory Neil Shapiro void
reset_mail_esmtp_args(e)4980d0cef73dSGregory Neil Shapiro reset_mail_esmtp_args(e)
4981d0cef73dSGregory Neil Shapiro ENVELOPE *e;
4982d0cef73dSGregory Neil Shapiro {
4983d0cef73dSGregory Neil Shapiro /* "size": no reset */
4984d0cef73dSGregory Neil Shapiro
4985d0cef73dSGregory Neil Shapiro /* "body" */
4986*d39bd2c1SGregory Neil Shapiro e->e_flags &= ~EF_7BITBODY;
4987d0cef73dSGregory Neil Shapiro e->e_bodytype = NULL;
4988d0cef73dSGregory Neil Shapiro
4989d0cef73dSGregory Neil Shapiro /* "envid" */
4990d0cef73dSGregory Neil Shapiro e->e_envid = NULL;
4991d0cef73dSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{dsn_envid}"), NULL);
4992d0cef73dSGregory Neil Shapiro
4993d0cef73dSGregory Neil Shapiro /* "ret" */
4994ffb83623SGregory Neil Shapiro e->e_flags &= ~(EF_RET_PARAM|EF_NO_BODY_RETN);
4995d0cef73dSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, macid("{dsn_ret}"), NULL);
4996d0cef73dSGregory Neil Shapiro
4997d0cef73dSGregory Neil Shapiro #if SASL
4998d0cef73dSGregory Neil Shapiro /* "auth" */
4999d0cef73dSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, macid("{auth_author}"), NULL);
5000d0cef73dSGregory Neil Shapiro e->e_auth_param = "";
5001d0cef73dSGregory Neil Shapiro # if _FFR_AUTH_PASSING
5002d0cef73dSGregory Neil Shapiro macdefine(&BlankEnvelope.e_macro, A_PERM,
5003d0cef73dSGregory Neil Shapiro macid("{auth_author}"), NULL);
50045b0945b5SGregory Neil Shapiro # endif
5005d0cef73dSGregory Neil Shapiro #endif /* SASL */
5006d0cef73dSGregory Neil Shapiro
5007d0cef73dSGregory Neil Shapiro /* "by" */
5008d0cef73dSGregory Neil Shapiro e->e_deliver_by = 0;
5009d0cef73dSGregory Neil Shapiro e->e_dlvr_flag = 0;
5010d0cef73dSGregory Neil Shapiro }
5011d0cef73dSGregory Neil Shapiro
5012d0cef73dSGregory Neil Shapiro /*
5013d0cef73dSGregory Neil Shapiro ** MAIL_ESMTP_ARGS -- process ESMTP arguments from MAIL line
5014d0cef73dSGregory Neil Shapiro **
5015d0cef73dSGregory Neil Shapiro ** Parameters:
5016d0cef73dSGregory Neil Shapiro ** a -- address (unused, for compatibility with rcpt_esmtp_args)
5017d0cef73dSGregory Neil Shapiro ** kp -- the parameter key.
5018d0cef73dSGregory Neil Shapiro ** vp -- the value of that parameter.
5019d0cef73dSGregory Neil Shapiro ** e -- the envelope.
5020d0cef73dSGregory Neil Shapiro **
5021d0cef73dSGregory Neil Shapiro ** Returns:
5022d0cef73dSGregory Neil Shapiro ** none.
5023d0cef73dSGregory Neil Shapiro */
5024d0cef73dSGregory Neil Shapiro
5025d0cef73dSGregory Neil Shapiro void
mail_esmtp_args(a,kp,vp,e)5026d0cef73dSGregory Neil Shapiro mail_esmtp_args(a, kp, vp, e)
5027d0cef73dSGregory Neil Shapiro ADDRESS *a;
5028c2aa98e2SPeter Wemm char *kp;
5029c2aa98e2SPeter Wemm char *vp;
5030c2aa98e2SPeter Wemm ENVELOPE *e;
5031c2aa98e2SPeter Wemm {
50322fb4f839SGregory Neil Shapiro if (SM_STRCASEEQ(kp, "size"))
5033c2aa98e2SPeter Wemm {
5034c2aa98e2SPeter Wemm if (vp == NULL)
5035c2aa98e2SPeter Wemm {
503606f25ae9SGregory Neil Shapiro usrerr("501 5.5.2 SIZE requires a value");
5037c2aa98e2SPeter Wemm /* NOTREACHED */
5038c2aa98e2SPeter Wemm }
503940266059SGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, macid("{msg_size}"), vp);
504040266059SGregory Neil Shapiro errno = 0;
5041c2aa98e2SPeter Wemm e->e_msgsize = strtol(vp, (char **) NULL, 10);
504242e5d165SGregory Neil Shapiro if (e->e_msgsize == LONG_MAX && errno == ERANGE)
504342e5d165SGregory Neil Shapiro {
504442e5d165SGregory Neil Shapiro usrerr("552 5.2.3 Message size exceeds maximum value");
504542e5d165SGregory Neil Shapiro /* NOTREACHED */
504642e5d165SGregory Neil Shapiro }
504740266059SGregory Neil Shapiro if (e->e_msgsize < 0)
504840266059SGregory Neil Shapiro {
504940266059SGregory Neil Shapiro usrerr("552 5.2.3 Message size invalid");
505040266059SGregory Neil Shapiro /* NOTREACHED */
5051c2aa98e2SPeter Wemm }
505240266059SGregory Neil Shapiro }
50532fb4f839SGregory Neil Shapiro else if (SM_STRCASEEQ(kp, "body"))
5054c2aa98e2SPeter Wemm {
5055c2aa98e2SPeter Wemm if (vp == NULL)
5056c2aa98e2SPeter Wemm {
505706f25ae9SGregory Neil Shapiro usrerr("501 5.5.2 BODY requires a value");
5058c2aa98e2SPeter Wemm /* NOTREACHED */
5059c2aa98e2SPeter Wemm }
50602fb4f839SGregory Neil Shapiro else if (SM_STRCASEEQ(vp, "8bitmime"))
5061*d39bd2c1SGregory Neil Shapiro ;
50622fb4f839SGregory Neil Shapiro else if (SM_STRCASEEQ(vp, "7bit"))
5063*d39bd2c1SGregory Neil Shapiro e->e_flags |= EF_7BITBODY;
5064c2aa98e2SPeter Wemm else
5065c2aa98e2SPeter Wemm {
50662fb4f839SGregory Neil Shapiro usrerr("501 5.5.4 Unknown BODY type %s",
50672fb4f839SGregory Neil Shapiro SHOWCMDINREPLY(vp));
5068c2aa98e2SPeter Wemm /* NOTREACHED */
5069c2aa98e2SPeter Wemm }
507040266059SGregory Neil Shapiro e->e_bodytype = sm_rpool_strdup_x(e->e_rpool, vp);
5071c2aa98e2SPeter Wemm }
50722fb4f839SGregory Neil Shapiro else if (SM_STRCASEEQ(kp, "envid"))
5073c2aa98e2SPeter Wemm {
5074d0cef73dSGregory Neil Shapiro if (!bitset(SRV_OFFER_DSN, e->e_features))
507506f25ae9SGregory Neil Shapiro {
507606f25ae9SGregory Neil Shapiro usrerr("504 5.7.0 Sorry, ENVID not supported, we do not allow DSN");
507706f25ae9SGregory Neil Shapiro /* NOTREACHED */
507806f25ae9SGregory Neil Shapiro }
5079c2aa98e2SPeter Wemm if (vp == NULL)
5080c2aa98e2SPeter Wemm {
508106f25ae9SGregory Neil Shapiro usrerr("501 5.5.2 ENVID requires a value");
5082c2aa98e2SPeter Wemm /* NOTREACHED */
5083c2aa98e2SPeter Wemm }
5084c2aa98e2SPeter Wemm if (!xtextok(vp))
5085c2aa98e2SPeter Wemm {
508606f25ae9SGregory Neil Shapiro usrerr("501 5.5.4 Syntax error in ENVID parameter value");
5087c2aa98e2SPeter Wemm /* NOTREACHED */
5088c2aa98e2SPeter Wemm }
5089c2aa98e2SPeter Wemm if (e->e_envid != NULL)
5090c2aa98e2SPeter Wemm {
509106f25ae9SGregory Neil Shapiro usrerr("501 5.5.0 Duplicate ENVID parameter");
5092c2aa98e2SPeter Wemm /* NOTREACHED */
5093c2aa98e2SPeter Wemm }
509440266059SGregory Neil Shapiro e->e_envid = sm_rpool_strdup_x(e->e_rpool, vp);
509540266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
509640266059SGregory Neil Shapiro macid("{dsn_envid}"), e->e_envid);
5097c2aa98e2SPeter Wemm }
50982fb4f839SGregory Neil Shapiro else if (SM_STRCASEEQ(kp, "ret"))
5099c2aa98e2SPeter Wemm {
5100d0cef73dSGregory Neil Shapiro if (!bitset(SRV_OFFER_DSN, e->e_features))
510106f25ae9SGregory Neil Shapiro {
510206f25ae9SGregory Neil Shapiro usrerr("504 5.7.0 Sorry, RET not supported, we do not allow DSN");
510306f25ae9SGregory Neil Shapiro /* NOTREACHED */
510406f25ae9SGregory Neil Shapiro }
5105c2aa98e2SPeter Wemm if (vp == NULL)
5106c2aa98e2SPeter Wemm {
510706f25ae9SGregory Neil Shapiro usrerr("501 5.5.2 RET requires a value");
5108c2aa98e2SPeter Wemm /* NOTREACHED */
5109c2aa98e2SPeter Wemm }
5110c2aa98e2SPeter Wemm if (bitset(EF_RET_PARAM, e->e_flags))
5111c2aa98e2SPeter Wemm {
511206f25ae9SGregory Neil Shapiro usrerr("501 5.5.0 Duplicate RET parameter");
5113c2aa98e2SPeter Wemm /* NOTREACHED */
5114c2aa98e2SPeter Wemm }
5115c2aa98e2SPeter Wemm e->e_flags |= EF_RET_PARAM;
51162fb4f839SGregory Neil Shapiro if (SM_STRCASEEQ(vp, "hdrs"))
5117c2aa98e2SPeter Wemm e->e_flags |= EF_NO_BODY_RETN;
511840266059SGregory Neil Shapiro else if (sm_strcasecmp(vp, "full") != 0)
5119c2aa98e2SPeter Wemm {
51202fb4f839SGregory Neil Shapiro usrerr("501 5.5.2 Bad argument \"%s\" to RET",
51212fb4f839SGregory Neil Shapiro SHOWCMDINREPLY(vp));
5122c2aa98e2SPeter Wemm /* NOTREACHED */
5123c2aa98e2SPeter Wemm }
512440266059SGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, macid("{dsn_ret}"), vp);
512506f25ae9SGregory Neil Shapiro }
512606f25ae9SGregory Neil Shapiro #if SASL
51272fb4f839SGregory Neil Shapiro else if (SM_STRCASEEQ(kp, "auth"))
512806f25ae9SGregory Neil Shapiro {
512906f25ae9SGregory Neil Shapiro int len;
513006f25ae9SGregory Neil Shapiro char *q;
513106f25ae9SGregory Neil Shapiro char *auth_param; /* the value of the AUTH=x */
513206f25ae9SGregory Neil Shapiro bool saveQuickAbort = QuickAbort;
513306f25ae9SGregory Neil Shapiro bool saveSuprErrs = SuprErrs;
513440266059SGregory Neil Shapiro bool saveExitStat = ExitStat;
513506f25ae9SGregory Neil Shapiro
513606f25ae9SGregory Neil Shapiro if (vp == NULL)
513706f25ae9SGregory Neil Shapiro {
513806f25ae9SGregory Neil Shapiro usrerr("501 5.5.2 AUTH= requires a value");
513906f25ae9SGregory Neil Shapiro /* NOTREACHED */
514006f25ae9SGregory Neil Shapiro }
514106f25ae9SGregory Neil Shapiro if (e->e_auth_param != NULL)
514206f25ae9SGregory Neil Shapiro {
514306f25ae9SGregory Neil Shapiro usrerr("501 5.5.0 Duplicate AUTH parameter");
514406f25ae9SGregory Neil Shapiro /* NOTREACHED */
514506f25ae9SGregory Neil Shapiro }
514606f25ae9SGregory Neil Shapiro if ((q = strchr(vp, ' ')) != NULL)
514706f25ae9SGregory Neil Shapiro len = q - vp + 1;
514806f25ae9SGregory Neil Shapiro else
514906f25ae9SGregory Neil Shapiro len = strlen(vp) + 1;
515006f25ae9SGregory Neil Shapiro auth_param = xalloc(len);
515140266059SGregory Neil Shapiro (void) sm_strlcpy(auth_param, vp, len);
515206f25ae9SGregory Neil Shapiro if (!xtextok(auth_param))
515306f25ae9SGregory Neil Shapiro {
515406f25ae9SGregory Neil Shapiro usrerr("501 5.5.4 Syntax error in AUTH parameter value");
515506f25ae9SGregory Neil Shapiro /* just a warning? */
515606f25ae9SGregory Neil Shapiro /* NOTREACHED */
515706f25ae9SGregory Neil Shapiro }
515806f25ae9SGregory Neil Shapiro
515906f25ae9SGregory Neil Shapiro /* XXX define this always or only if trusted? */
5160e92d3f3fSGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, macid("{auth_author}"),
5161e92d3f3fSGregory Neil Shapiro auth_param);
516206f25ae9SGregory Neil Shapiro
516306f25ae9SGregory Neil Shapiro /*
516406f25ae9SGregory Neil Shapiro ** call Strust_auth to find out whether
516506f25ae9SGregory Neil Shapiro ** auth_param is acceptable (trusted)
516606f25ae9SGregory Neil Shapiro ** we shouldn't trust it if not authenticated
516706f25ae9SGregory Neil Shapiro ** (required by RFC, leave it to ruleset?)
516806f25ae9SGregory Neil Shapiro */
516906f25ae9SGregory Neil Shapiro
517040266059SGregory Neil Shapiro SuprErrs = true;
517140266059SGregory Neil Shapiro QuickAbort = false;
517206f25ae9SGregory Neil Shapiro if (strcmp(auth_param, "<>") != 0 &&
5173da7d7b9cSGregory Neil Shapiro (rscheck("trust_auth", auth_param, NULL, e, RSF_RMCOMM, 9,
5174da7d7b9cSGregory Neil Shapiro NULL, NOQID, NULL, NULL) != EX_OK || Errors > 0))
517506f25ae9SGregory Neil Shapiro {
517606f25ae9SGregory Neil Shapiro if (tTd(95, 8))
517706f25ae9SGregory Neil Shapiro {
517806f25ae9SGregory Neil Shapiro q = e->e_auth_param;
517940266059SGregory Neil Shapiro sm_dprintf("auth=\"%.100s\" not trusted user=\"%.100s\"\n",
5180e92d3f3fSGregory Neil Shapiro auth_param, (q == NULL) ? "" : q);
518106f25ae9SGregory Neil Shapiro }
518240266059SGregory Neil Shapiro
518306f25ae9SGregory Neil Shapiro /* not trusted */
518440266059SGregory Neil Shapiro e->e_auth_param = "<>";
518540266059SGregory Neil Shapiro # if _FFR_AUTH_PASSING
518640266059SGregory Neil Shapiro macdefine(&BlankEnvelope.e_macro, A_PERM,
518740266059SGregory Neil Shapiro macid("{auth_author}"), NULL);
51885b0945b5SGregory Neil Shapiro # endif
5189c2aa98e2SPeter Wemm }
5190c2aa98e2SPeter Wemm else
5191c2aa98e2SPeter Wemm {
519206f25ae9SGregory Neil Shapiro if (tTd(95, 8))
5193e92d3f3fSGregory Neil Shapiro sm_dprintf("auth=\"%.100s\" trusted\n", auth_param);
519440266059SGregory Neil Shapiro e->e_auth_param = sm_rpool_strdup_x(e->e_rpool,
519540266059SGregory Neil Shapiro auth_param);
519606f25ae9SGregory Neil Shapiro }
519740266059SGregory Neil Shapiro sm_free(auth_param); /* XXX */
51988774250cSGregory Neil Shapiro
519906f25ae9SGregory Neil Shapiro /* reset values */
520006f25ae9SGregory Neil Shapiro Errors = 0;
520106f25ae9SGregory Neil Shapiro QuickAbort = saveQuickAbort;
520206f25ae9SGregory Neil Shapiro SuprErrs = saveSuprErrs;
520340266059SGregory Neil Shapiro ExitStat = saveExitStat;
520406f25ae9SGregory Neil Shapiro }
520506f25ae9SGregory Neil Shapiro #endif /* SASL */
520640266059SGregory Neil Shapiro #define PRTCHAR(c) ((isascii(c) && isprint(c)) ? (c) : '?')
520740266059SGregory Neil Shapiro
520840266059SGregory Neil Shapiro /*
520940266059SGregory Neil Shapiro ** "by" is only accepted if DeliverByMin >= 0.
521040266059SGregory Neil Shapiro ** We maybe could add this to the list of server_features.
521140266059SGregory Neil Shapiro */
521240266059SGregory Neil Shapiro
52132fb4f839SGregory Neil Shapiro else if (SM_STRCASEEQ(kp, "by") && DeliverByMin >= 0)
521440266059SGregory Neil Shapiro {
521540266059SGregory Neil Shapiro char *s;
521640266059SGregory Neil Shapiro
521740266059SGregory Neil Shapiro if (vp == NULL)
521840266059SGregory Neil Shapiro {
521940266059SGregory Neil Shapiro usrerr("501 5.5.2 BY= requires a value");
522040266059SGregory Neil Shapiro /* NOTREACHED */
522140266059SGregory Neil Shapiro }
522240266059SGregory Neil Shapiro errno = 0;
522340266059SGregory Neil Shapiro e->e_deliver_by = strtol(vp, &s, 10);
522440266059SGregory Neil Shapiro if (e->e_deliver_by == LONG_MIN ||
522540266059SGregory Neil Shapiro e->e_deliver_by == LONG_MAX ||
522640266059SGregory Neil Shapiro e->e_deliver_by > 999999999l ||
522740266059SGregory Neil Shapiro e->e_deliver_by < -999999999l)
522840266059SGregory Neil Shapiro {
52292fb4f839SGregory Neil Shapiro usrerr("501 5.5.2 BY=%s out of range",
52302fb4f839SGregory Neil Shapiro SHOWCMDINREPLY(vp));
523140266059SGregory Neil Shapiro /* NOTREACHED */
523240266059SGregory Neil Shapiro }
523340266059SGregory Neil Shapiro if (s == NULL || *s != ';')
523440266059SGregory Neil Shapiro {
523540266059SGregory Neil Shapiro usrerr("501 5.5.2 BY= missing ';'");
523640266059SGregory Neil Shapiro /* NOTREACHED */
523740266059SGregory Neil Shapiro }
523840266059SGregory Neil Shapiro e->e_dlvr_flag = 0;
523940266059SGregory Neil Shapiro ++s; /* XXX: spaces allowed? */
524040266059SGregory Neil Shapiro SKIP_SPACE(s);
524140266059SGregory Neil Shapiro switch (tolower(*s))
524240266059SGregory Neil Shapiro {
524340266059SGregory Neil Shapiro case 'n':
524440266059SGregory Neil Shapiro e->e_dlvr_flag = DLVR_NOTIFY;
524540266059SGregory Neil Shapiro break;
524640266059SGregory Neil Shapiro case 'r':
524740266059SGregory Neil Shapiro e->e_dlvr_flag = DLVR_RETURN;
524840266059SGregory Neil Shapiro if (e->e_deliver_by <= 0)
524940266059SGregory Neil Shapiro {
525040266059SGregory Neil Shapiro usrerr("501 5.5.4 mode R requires BY time > 0");
525140266059SGregory Neil Shapiro /* NOTREACHED */
525240266059SGregory Neil Shapiro }
525340266059SGregory Neil Shapiro if (DeliverByMin > 0 && e->e_deliver_by > 0 &&
525440266059SGregory Neil Shapiro e->e_deliver_by < DeliverByMin)
525540266059SGregory Neil Shapiro {
525640266059SGregory Neil Shapiro usrerr("555 5.5.2 time %ld less than %ld",
525740266059SGregory Neil Shapiro e->e_deliver_by, (long) DeliverByMin);
525840266059SGregory Neil Shapiro /* NOTREACHED */
525940266059SGregory Neil Shapiro }
526040266059SGregory Neil Shapiro break;
526140266059SGregory Neil Shapiro default:
526240266059SGregory Neil Shapiro usrerr("501 5.5.2 illegal by-mode '%c'", PRTCHAR(*s));
526340266059SGregory Neil Shapiro /* NOTREACHED */
526440266059SGregory Neil Shapiro }
526540266059SGregory Neil Shapiro ++s; /* XXX: spaces allowed? */
526640266059SGregory Neil Shapiro SKIP_SPACE(s);
526740266059SGregory Neil Shapiro switch (tolower(*s))
526840266059SGregory Neil Shapiro {
526940266059SGregory Neil Shapiro case 't':
527040266059SGregory Neil Shapiro e->e_dlvr_flag |= DLVR_TRACE;
527140266059SGregory Neil Shapiro break;
527240266059SGregory Neil Shapiro case '\0':
527340266059SGregory Neil Shapiro break;
527440266059SGregory Neil Shapiro default:
527540266059SGregory Neil Shapiro usrerr("501 5.5.2 illegal by-trace '%c'", PRTCHAR(*s));
527640266059SGregory Neil Shapiro /* NOTREACHED */
527740266059SGregory Neil Shapiro }
527840266059SGregory Neil Shapiro
527940266059SGregory Neil Shapiro /* XXX: check whether more characters follow? */
528040266059SGregory Neil Shapiro }
52812fb4f839SGregory Neil Shapiro #if USE_EAI
52822fb4f839SGregory Neil Shapiro else if (SM_STRCASEEQ(kp, "smtputf8"))
52835b0945b5SGregory Neil Shapiro {
52845b0945b5SGregory Neil Shapiro if (!bitset(SRV_OFFER_EAI, e->e_features))
52855b0945b5SGregory Neil Shapiro {
52862fb4f839SGregory Neil Shapiro usrerr("504 5.7.0 Sorry, SMTPUTF8 not supported");
52875b0945b5SGregory Neil Shapiro /* NOTREACHED */
52885b0945b5SGregory Neil Shapiro }
52895b0945b5SGregory Neil Shapiro e->e_smtputf8 = true;
52905b0945b5SGregory Neil Shapiro }
52915b0945b5SGregory Neil Shapiro #endif
529206f25ae9SGregory Neil Shapiro else
529306f25ae9SGregory Neil Shapiro {
52942fb4f839SGregory Neil Shapiro usrerr("555 5.5.4 %s parameter unrecognized",
52952fb4f839SGregory Neil Shapiro SHOWCMDINREPLY(kp));
5296c2aa98e2SPeter Wemm /* NOTREACHED */
5297c2aa98e2SPeter Wemm }
5298c2aa98e2SPeter Wemm }
5299d0cef73dSGregory Neil Shapiro
530040266059SGregory Neil Shapiro /*
5301c2aa98e2SPeter Wemm ** RCPT_ESMTP_ARGS -- process ESMTP arguments from RCPT line
5302c2aa98e2SPeter Wemm **
5303c2aa98e2SPeter Wemm ** Parameters:
5304c2aa98e2SPeter Wemm ** a -- the address corresponding to the To: parameter.
5305c2aa98e2SPeter Wemm ** kp -- the parameter key.
5306c2aa98e2SPeter Wemm ** vp -- the value of that parameter.
5307c2aa98e2SPeter Wemm ** e -- the envelope.
5308c2aa98e2SPeter Wemm **
5309c2aa98e2SPeter Wemm ** Returns:
5310c2aa98e2SPeter Wemm ** none.
5311c2aa98e2SPeter Wemm */
5312c2aa98e2SPeter Wemm
5313d0cef73dSGregory Neil Shapiro void
rcpt_esmtp_args(a,kp,vp,e)5314d0cef73dSGregory Neil Shapiro rcpt_esmtp_args(a, kp, vp, e)
5315c2aa98e2SPeter Wemm ADDRESS *a;
5316c2aa98e2SPeter Wemm char *kp;
5317c2aa98e2SPeter Wemm char *vp;
5318c2aa98e2SPeter Wemm ENVELOPE *e;
5319c2aa98e2SPeter Wemm {
53202fb4f839SGregory Neil Shapiro if (SM_STRCASEEQ(kp, "notify"))
5321c2aa98e2SPeter Wemm {
5322c2aa98e2SPeter Wemm char *p;
5323c2aa98e2SPeter Wemm
5324d0cef73dSGregory Neil Shapiro if (!bitset(SRV_OFFER_DSN, e->e_features))
532506f25ae9SGregory Neil Shapiro {
532606f25ae9SGregory Neil Shapiro usrerr("504 5.7.0 Sorry, NOTIFY not supported, we do not allow DSN");
532706f25ae9SGregory Neil Shapiro /* NOTREACHED */
532806f25ae9SGregory Neil Shapiro }
5329c2aa98e2SPeter Wemm if (vp == NULL)
5330c2aa98e2SPeter Wemm {
533106f25ae9SGregory Neil Shapiro usrerr("501 5.5.2 NOTIFY requires a value");
5332c2aa98e2SPeter Wemm /* NOTREACHED */
5333c2aa98e2SPeter Wemm }
5334c2aa98e2SPeter Wemm a->q_flags &= ~(QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY);
5335c2aa98e2SPeter Wemm a->q_flags |= QHASNOTIFY;
533640266059SGregory Neil Shapiro macdefine(&e->e_macro, A_TEMP, macid("{dsn_notify}"), vp);
533706f25ae9SGregory Neil Shapiro
53382fb4f839SGregory Neil Shapiro if (SM_STRCASEEQ(vp, "never"))
5339c2aa98e2SPeter Wemm return;
5340c2aa98e2SPeter Wemm for (p = vp; p != NULL; vp = p)
5341c2aa98e2SPeter Wemm {
5342b6bacd31SGregory Neil Shapiro char *s;
5343b6bacd31SGregory Neil Shapiro
5344b6bacd31SGregory Neil Shapiro s = p = strchr(p, ',');
5345c2aa98e2SPeter Wemm if (p != NULL)
5346c2aa98e2SPeter Wemm *p++ = '\0';
53472fb4f839SGregory Neil Shapiro if (SM_STRCASEEQ(vp, "success"))
5348c2aa98e2SPeter Wemm a->q_flags |= QPINGONSUCCESS;
53492fb4f839SGregory Neil Shapiro else if (SM_STRCASEEQ(vp, "failure"))
5350c2aa98e2SPeter Wemm a->q_flags |= QPINGONFAILURE;
53512fb4f839SGregory Neil Shapiro else if (SM_STRCASEEQ(vp, "delay"))
5352c2aa98e2SPeter Wemm a->q_flags |= QPINGONDELAY;
5353c2aa98e2SPeter Wemm else
5354c2aa98e2SPeter Wemm {
535506f25ae9SGregory Neil Shapiro usrerr("501 5.5.4 Bad argument \"%s\" to NOTIFY",
53562fb4f839SGregory Neil Shapiro SHOWCMDINREPLY(vp));
5357c2aa98e2SPeter Wemm /* NOTREACHED */
5358c2aa98e2SPeter Wemm }
5359b6bacd31SGregory Neil Shapiro if (s != NULL)
5360b6bacd31SGregory Neil Shapiro *s = ',';
5361c2aa98e2SPeter Wemm }
5362c2aa98e2SPeter Wemm }
53632fb4f839SGregory Neil Shapiro else if (SM_STRCASEEQ(kp, "orcpt"))
5364c2aa98e2SPeter Wemm {
5365552d4955SGregory Neil Shapiro char *p;
5366552d4955SGregory Neil Shapiro
5367d0cef73dSGregory Neil Shapiro if (!bitset(SRV_OFFER_DSN, e->e_features))
536806f25ae9SGregory Neil Shapiro {
536906f25ae9SGregory Neil Shapiro usrerr("504 5.7.0 Sorry, ORCPT not supported, we do not allow DSN");
537006f25ae9SGregory Neil Shapiro /* NOTREACHED */
537106f25ae9SGregory Neil Shapiro }
5372c2aa98e2SPeter Wemm if (vp == NULL)
5373c2aa98e2SPeter Wemm {
537406f25ae9SGregory Neil Shapiro usrerr("501 5.5.2 ORCPT requires a value");
5375c2aa98e2SPeter Wemm /* NOTREACHED */
5376c2aa98e2SPeter Wemm }
5377c2aa98e2SPeter Wemm if (a->q_orcpt != NULL)
5378c2aa98e2SPeter Wemm {
537906f25ae9SGregory Neil Shapiro usrerr("501 5.5.0 Duplicate ORCPT parameter");
5380c2aa98e2SPeter Wemm /* NOTREACHED */
5381c2aa98e2SPeter Wemm }
5382552d4955SGregory Neil Shapiro p = strchr(vp, ';');
5383552d4955SGregory Neil Shapiro if (p == NULL)
5384552d4955SGregory Neil Shapiro {
5385552d4955SGregory Neil Shapiro usrerr("501 5.5.4 Syntax error in ORCPT parameter value");
5386552d4955SGregory Neil Shapiro /* NOTREACHED */
5387552d4955SGregory Neil Shapiro }
5388552d4955SGregory Neil Shapiro *p = '\0';
53892fb4f839SGregory Neil Shapiro #if USE_EAI
53902fb4f839SGregory Neil Shapiro if (SM_STRCASEEQ(vp, "utf-8"))
53912fb4f839SGregory Neil Shapiro {
53922fb4f839SGregory Neil Shapiro /* XXX check syntax of p+1 ! */
53932fb4f839SGregory Neil Shapiro if (!xtextok(p + 1) &&
53942fb4f839SGregory Neil Shapiro uxtext_unquote(p + 1, NULL, MAXNAME_I) <= 0)
53952fb4f839SGregory Neil Shapiro {
53962fb4f839SGregory Neil Shapiro *p = ';';
53972fb4f839SGregory Neil Shapiro usrerr("501 5.5.4 Syntax error in UTF-8 ORCPT parameter value");
53982fb4f839SGregory Neil Shapiro /* NOTREACHED */
53992fb4f839SGregory Neil Shapiro }
54002fb4f839SGregory Neil Shapiro # if 0
54012fb4f839SGregory Neil Shapiro complicated... see grammar!
54022fb4f839SGregory Neil Shapiro RFC 6533 Internationalized Delivery Status and Disposition Notifications
54032fb4f839SGregory Neil Shapiro utf-8-enc-addr = utf-8-addr-xtext / utf-8-addr-unitext / utf-8-address
54042fb4f839SGregory Neil Shapiro # endif
54052fb4f839SGregory Neil Shapiro }
54062fb4f839SGregory Neil Shapiro else
54072fb4f839SGregory Neil Shapiro #endif /* USE_EAI */
54082fb4f839SGregory Neil Shapiro /* "else" in #if code above */
5409552d4955SGregory Neil Shapiro if (!isatom(vp) || !xtextok(p + 1))
5410552d4955SGregory Neil Shapiro {
5411552d4955SGregory Neil Shapiro *p = ';';
5412552d4955SGregory Neil Shapiro usrerr("501 5.5.4 Syntax error in ORCPT parameter value");
5413552d4955SGregory Neil Shapiro /* NOTREACHED */
5414552d4955SGregory Neil Shapiro }
5415552d4955SGregory Neil Shapiro *p = ';';
541640266059SGregory Neil Shapiro a->q_orcpt = sm_rpool_strdup_x(e->e_rpool, vp);
5417c2aa98e2SPeter Wemm }
5418c2aa98e2SPeter Wemm else
5419c2aa98e2SPeter Wemm {
54202fb4f839SGregory Neil Shapiro usrerr("555 5.5.4 %s parameter unrecognized",
54212fb4f839SGregory Neil Shapiro SHOWCMDINREPLY(kp));
5422c2aa98e2SPeter Wemm /* NOTREACHED */
5423c2aa98e2SPeter Wemm }
5424c2aa98e2SPeter Wemm }
542540266059SGregory Neil Shapiro /*
5426c2aa98e2SPeter Wemm ** PRINTVRFYADDR -- print an entry in the verify queue
5427c2aa98e2SPeter Wemm **
5428c2aa98e2SPeter Wemm ** Parameters:
542940266059SGregory Neil Shapiro ** a -- the address to print.
5430c2aa98e2SPeter Wemm ** last -- set if this is the last one.
5431c2aa98e2SPeter Wemm ** vrfy -- set if this is a VRFY command.
5432c2aa98e2SPeter Wemm **
5433c2aa98e2SPeter Wemm ** Returns:
5434c2aa98e2SPeter Wemm ** none.
5435c2aa98e2SPeter Wemm **
5436c2aa98e2SPeter Wemm ** Side Effects:
5437c2aa98e2SPeter Wemm ** Prints the appropriate 250 codes.
5438c2aa98e2SPeter Wemm */
543906f25ae9SGregory Neil Shapiro #define OFFF (3 + 1 + 5 + 1) /* offset in fmt: SMTP reply + enh. code */
5440c2aa98e2SPeter Wemm
544106f25ae9SGregory Neil Shapiro static void
printvrfyaddr(a,last,vrfy)5442c2aa98e2SPeter Wemm printvrfyaddr(a, last, vrfy)
5443c2aa98e2SPeter Wemm register ADDRESS *a;
5444c2aa98e2SPeter Wemm bool last;
5445c2aa98e2SPeter Wemm bool vrfy;
5446c2aa98e2SPeter Wemm {
544706f25ae9SGregory Neil Shapiro char fmtbuf[30];
5448c2aa98e2SPeter Wemm
5449c2aa98e2SPeter Wemm if (vrfy && a->q_mailer != NULL &&
5450c2aa98e2SPeter Wemm !bitnset(M_VRFY250, a->q_mailer->m_flags))
5451d0cef73dSGregory Neil Shapiro (void) sm_strlcpy(fmtbuf, "252", sizeof(fmtbuf));
5452c2aa98e2SPeter Wemm else
5453d0cef73dSGregory Neil Shapiro (void) sm_strlcpy(fmtbuf, "250", sizeof(fmtbuf));
5454c2aa98e2SPeter Wemm fmtbuf[3] = last ? ' ' : '-';
5455d0cef73dSGregory Neil Shapiro (void) sm_strlcpy(&fmtbuf[4], "2.1.5 ", sizeof(fmtbuf) - 4);
5456c2aa98e2SPeter Wemm if (a->q_fullname == NULL)
5457c2aa98e2SPeter Wemm {
545806f25ae9SGregory Neil Shapiro if ((a->q_mailer == NULL ||
545906f25ae9SGregory Neil Shapiro a->q_mailer->m_addrtype == NULL ||
54602fb4f839SGregory Neil Shapiro SM_STRCASEEQ(a->q_mailer->m_addrtype, "rfc822")) &&
546106f25ae9SGregory Neil Shapiro strchr(a->q_user, '@') == NULL)
546240266059SGregory Neil Shapiro (void) sm_strlcpy(&fmtbuf[OFFF], "<%s@%s>",
5463d0cef73dSGregory Neil Shapiro sizeof(fmtbuf) - OFFF);
5464c2aa98e2SPeter Wemm else
546540266059SGregory Neil Shapiro (void) sm_strlcpy(&fmtbuf[OFFF], "<%s>",
5466d0cef73dSGregory Neil Shapiro sizeof(fmtbuf) - OFFF);
5467c2aa98e2SPeter Wemm message(fmtbuf, a->q_user, MyHostName);
5468c2aa98e2SPeter Wemm }
5469c2aa98e2SPeter Wemm else
5470c2aa98e2SPeter Wemm {
547106f25ae9SGregory Neil Shapiro if ((a->q_mailer == NULL ||
547206f25ae9SGregory Neil Shapiro a->q_mailer->m_addrtype == NULL ||
54732fb4f839SGregory Neil Shapiro SM_STRCASEEQ(a->q_mailer->m_addrtype, "rfc822")) &&
547406f25ae9SGregory Neil Shapiro strchr(a->q_user, '@') == NULL)
547540266059SGregory Neil Shapiro (void) sm_strlcpy(&fmtbuf[OFFF], "%s <%s@%s>",
5476d0cef73dSGregory Neil Shapiro sizeof(fmtbuf) - OFFF);
5477c2aa98e2SPeter Wemm else
547840266059SGregory Neil Shapiro (void) sm_strlcpy(&fmtbuf[OFFF], "%s <%s>",
5479d0cef73dSGregory Neil Shapiro sizeof(fmtbuf) - OFFF);
5480c2aa98e2SPeter Wemm message(fmtbuf, a->q_fullname, a->q_user, MyHostName);
5481c2aa98e2SPeter Wemm }
5482c2aa98e2SPeter Wemm }
5483c2aa98e2SPeter Wemm
548406f25ae9SGregory Neil Shapiro #if SASL
548540266059SGregory Neil Shapiro /*
548606f25ae9SGregory Neil Shapiro ** SASLMECHS -- get list of possible AUTH mechanisms
548706f25ae9SGregory Neil Shapiro **
548806f25ae9SGregory Neil Shapiro ** Parameters:
548940266059SGregory Neil Shapiro ** conn -- SASL connection info.
549040266059SGregory Neil Shapiro ** mechlist -- output parameter for list of mechanisms.
549106f25ae9SGregory Neil Shapiro **
549206f25ae9SGregory Neil Shapiro ** Returns:
549340266059SGregory Neil Shapiro ** number of mechs.
549406f25ae9SGregory Neil Shapiro */
549506f25ae9SGregory Neil Shapiro
549606f25ae9SGregory Neil Shapiro static int
saslmechs(conn,mechlist)549706f25ae9SGregory Neil Shapiro saslmechs(conn, mechlist)
549806f25ae9SGregory Neil Shapiro sasl_conn_t *conn;
549906f25ae9SGregory Neil Shapiro char **mechlist;
550006f25ae9SGregory Neil Shapiro {
550106f25ae9SGregory Neil Shapiro int len, num, result;
550206f25ae9SGregory Neil Shapiro
550306f25ae9SGregory Neil Shapiro /* "user" is currently unused */
550494c01205SGregory Neil Shapiro # if SASL >= 20000
550594c01205SGregory Neil Shapiro result = sasl_listmech(conn, NULL,
550694c01205SGregory Neil Shapiro "", " ", "", (const char **) mechlist,
5507a7ec597cSGregory Neil Shapiro (unsigned int *)&len, &num);
550894c01205SGregory Neil Shapiro # else /* SASL >= 20000 */
550906f25ae9SGregory Neil Shapiro result = sasl_listmech(conn, "user", /* XXX */
551006f25ae9SGregory Neil Shapiro "", " ", "", mechlist,
551140266059SGregory Neil Shapiro (unsigned int *)&len, (unsigned int *)&num);
551294c01205SGregory Neil Shapiro # endif /* SASL >= 20000 */
551340266059SGregory Neil Shapiro if (result != SASL_OK)
551406f25ae9SGregory Neil Shapiro {
551506f25ae9SGregory Neil Shapiro if (LogLevel > 9)
551606f25ae9SGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID,
551740266059SGregory Neil Shapiro "AUTH error: listmech=%d, num=%d",
551806f25ae9SGregory Neil Shapiro result, num);
5519193538b7SGregory Neil Shapiro num = 0;
552006f25ae9SGregory Neil Shapiro }
552140266059SGregory Neil Shapiro if (num > 0)
552240266059SGregory Neil Shapiro {
552340266059SGregory Neil Shapiro if (LogLevel > 11)
552440266059SGregory Neil Shapiro sm_syslog(LOG_INFO, NOQID,
552540266059SGregory Neil Shapiro "AUTH: available mech=%s, allowed mech=%s",
552640266059SGregory Neil Shapiro *mechlist, AuthMechanisms);
552740266059SGregory Neil Shapiro *mechlist = intersect(AuthMechanisms, *mechlist, NULL);
552840266059SGregory Neil Shapiro }
552940266059SGregory Neil Shapiro else
553040266059SGregory Neil Shapiro {
553140266059SGregory Neil Shapiro *mechlist = NULL; /* be paranoid... */
553240266059SGregory Neil Shapiro if (result == SASL_OK && LogLevel > 9)
553340266059SGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID,
553440266059SGregory Neil Shapiro "AUTH warning: no mechanisms");
553540266059SGregory Neil Shapiro }
553606f25ae9SGregory Neil Shapiro return num;
553706f25ae9SGregory Neil Shapiro }
553894c01205SGregory Neil Shapiro
553994c01205SGregory Neil Shapiro # if SASL >= 20000
554094c01205SGregory Neil Shapiro /*
554194c01205SGregory Neil Shapiro ** PROXY_POLICY -- define proxy policy for AUTH
554294c01205SGregory Neil Shapiro **
554394c01205SGregory Neil Shapiro ** Parameters:
554494c01205SGregory Neil Shapiro ** conn -- unused.
554594c01205SGregory Neil Shapiro ** context -- unused.
554694c01205SGregory Neil Shapiro ** requested_user -- authorization identity.
554794c01205SGregory Neil Shapiro ** rlen -- authorization identity length.
554894c01205SGregory Neil Shapiro ** auth_identity -- authentication identity.
554994c01205SGregory Neil Shapiro ** alen -- authentication identity length.
555094c01205SGregory Neil Shapiro ** def_realm -- default user realm.
555194c01205SGregory Neil Shapiro ** urlen -- user realm length.
555294c01205SGregory Neil Shapiro ** propctx -- unused.
555394c01205SGregory Neil Shapiro **
555494c01205SGregory Neil Shapiro ** Returns:
555594c01205SGregory Neil Shapiro ** ok?
555694c01205SGregory Neil Shapiro **
555794c01205SGregory Neil Shapiro ** Side Effects:
555894c01205SGregory Neil Shapiro ** sets {auth_authen} macro.
555994c01205SGregory Neil Shapiro */
556094c01205SGregory Neil Shapiro
556194c01205SGregory Neil Shapiro int
proxy_policy(conn,context,requested_user,rlen,auth_identity,alen,def_realm,urlen,propctx)556294c01205SGregory Neil Shapiro proxy_policy(conn, context, requested_user, rlen, auth_identity, alen,
556394c01205SGregory Neil Shapiro def_realm, urlen, propctx)
556494c01205SGregory Neil Shapiro sasl_conn_t *conn;
556594c01205SGregory Neil Shapiro void *context;
556694c01205SGregory Neil Shapiro const char *requested_user;
556794c01205SGregory Neil Shapiro unsigned rlen;
556894c01205SGregory Neil Shapiro const char *auth_identity;
556994c01205SGregory Neil Shapiro unsigned alen;
557094c01205SGregory Neil Shapiro const char *def_realm;
557194c01205SGregory Neil Shapiro unsigned urlen;
557294c01205SGregory Neil Shapiro struct propctx *propctx;
557394c01205SGregory Neil Shapiro {
557494c01205SGregory Neil Shapiro if (auth_identity == NULL)
557594c01205SGregory Neil Shapiro return SASL_FAIL;
557694c01205SGregory Neil Shapiro
557794c01205SGregory Neil Shapiro macdefine(&BlankEnvelope.e_macro, A_TEMP,
55786f9c8e5bSGregory Neil Shapiro macid("{auth_authen}"),
55796f9c8e5bSGregory Neil Shapiro xtextify((char *) auth_identity, "=<>\")"));
558094c01205SGregory Neil Shapiro
558194c01205SGregory Neil Shapiro return SASL_OK;
558294c01205SGregory Neil Shapiro }
558394c01205SGregory Neil Shapiro # else /* SASL >= 20000 */
558494c01205SGregory Neil Shapiro
558540266059SGregory Neil Shapiro /*
558606f25ae9SGregory Neil Shapiro ** PROXY_POLICY -- define proxy policy for AUTH
558706f25ae9SGregory Neil Shapiro **
558806f25ae9SGregory Neil Shapiro ** Parameters:
558940266059SGregory Neil Shapiro ** context -- unused.
559040266059SGregory Neil Shapiro ** auth_identity -- authentication identity.
559140266059SGregory Neil Shapiro ** requested_user -- authorization identity.
559240266059SGregory Neil Shapiro ** user -- allowed user (output).
559340266059SGregory Neil Shapiro ** errstr -- possible error string (output).
559406f25ae9SGregory Neil Shapiro **
559506f25ae9SGregory Neil Shapiro ** Returns:
559606f25ae9SGregory Neil Shapiro ** ok?
559706f25ae9SGregory Neil Shapiro */
559806f25ae9SGregory Neil Shapiro
559906f25ae9SGregory Neil Shapiro int
proxy_policy(context,auth_identity,requested_user,user,errstr)560006f25ae9SGregory Neil Shapiro proxy_policy(context, auth_identity, requested_user, user, errstr)
560106f25ae9SGregory Neil Shapiro void *context;
560206f25ae9SGregory Neil Shapiro const char *auth_identity;
560306f25ae9SGregory Neil Shapiro const char *requested_user;
560406f25ae9SGregory Neil Shapiro const char **user;
560506f25ae9SGregory Neil Shapiro const char **errstr;
560606f25ae9SGregory Neil Shapiro {
560706f25ae9SGregory Neil Shapiro if (user == NULL || auth_identity == NULL)
560806f25ae9SGregory Neil Shapiro return SASL_FAIL;
560906f25ae9SGregory Neil Shapiro *user = newstr(auth_identity);
561006f25ae9SGregory Neil Shapiro return SASL_OK;
561106f25ae9SGregory Neil Shapiro }
561294c01205SGregory Neil Shapiro # endif /* SASL >= 20000 */
561306f25ae9SGregory Neil Shapiro #endif /* SASL */
561406f25ae9SGregory Neil Shapiro
561506f25ae9SGregory Neil Shapiro #if STARTTLS
561606f25ae9SGregory Neil Shapiro /*
561706f25ae9SGregory Neil Shapiro ** INITSRVTLS -- initialize server side TLS
561806f25ae9SGregory Neil Shapiro **
561906f25ae9SGregory Neil Shapiro ** Parameters:
562040266059SGregory Neil Shapiro ** tls_ok -- should tls initialization be done?
562106f25ae9SGregory Neil Shapiro **
562206f25ae9SGregory Neil Shapiro ** Returns:
562306f25ae9SGregory Neil Shapiro ** succeeded?
56248774250cSGregory Neil Shapiro **
56258774250cSGregory Neil Shapiro ** Side Effects:
562640266059SGregory Neil Shapiro ** sets tls_ok_srv which is a static variable in this module.
562740266059SGregory Neil Shapiro ** Do NOT remove assignments to it!
562806f25ae9SGregory Neil Shapiro */
562906f25ae9SGregory Neil Shapiro
563006f25ae9SGregory Neil Shapiro bool
initsrvtls(tls_ok)563140266059SGregory Neil Shapiro initsrvtls(tls_ok)
563240266059SGregory Neil Shapiro bool tls_ok;
563306f25ae9SGregory Neil Shapiro {
563440266059SGregory Neil Shapiro if (!tls_ok)
563540266059SGregory Neil Shapiro return false;
563606f25ae9SGregory Neil Shapiro
563740266059SGregory Neil Shapiro /* do NOT remove assignment */
56389bd497b8SGregory Neil Shapiro tls_ok_srv = inittls(&srv_ctx, TLS_Srv_Opts, Srv_SSL_Options, true,
56399bd497b8SGregory Neil Shapiro SrvCertFile, SrvKeyFile,
56409bd497b8SGregory Neil Shapiro CACertPath, CACertFile, DHParams);
56418774250cSGregory Neil Shapiro return tls_ok_srv;
564206f25ae9SGregory Neil Shapiro }
564306f25ae9SGregory Neil Shapiro #endif /* STARTTLS */
564440266059SGregory Neil Shapiro /*
564540266059SGregory Neil Shapiro ** SRVFEATURES -- get features for SMTP server
564640266059SGregory Neil Shapiro **
564740266059SGregory Neil Shapiro ** Parameters:
564840266059SGregory Neil Shapiro ** e -- envelope (should be session context).
564940266059SGregory Neil Shapiro ** clientname -- name of client.
565040266059SGregory Neil Shapiro ** features -- default features for this invocation.
565140266059SGregory Neil Shapiro **
565240266059SGregory Neil Shapiro ** Returns:
565340266059SGregory Neil Shapiro ** server features.
565440266059SGregory Neil Shapiro */
565540266059SGregory Neil Shapiro
565640266059SGregory Neil Shapiro /* table with options: it uses just one character, how about strings? */
565740266059SGregory Neil Shapiro static struct
565840266059SGregory Neil Shapiro {
565940266059SGregory Neil Shapiro char srvf_opt;
5660*d39bd2c1SGregory Neil Shapiro unsigned long srvf_flag;
5661*d39bd2c1SGregory Neil Shapiro unsigned long srvf_flag2;
566240266059SGregory Neil Shapiro } srv_feat_table[] =
566340266059SGregory Neil Shapiro {
5664*d39bd2c1SGregory Neil Shapiro { 'A', SRV_OFFER_AUTH , 0 },
5665*d39bd2c1SGregory Neil Shapiro { 'B', SRV_OFFER_VERB , 0 },
5666*d39bd2c1SGregory Neil Shapiro { 'C', SRV_REQ_SEC , 0 },
5667*d39bd2c1SGregory Neil Shapiro { 'D', SRV_OFFER_DSN , 0 },
5668*d39bd2c1SGregory Neil Shapiro { 'E', SRV_OFFER_ETRN , 0 },
5669*d39bd2c1SGregory Neil Shapiro { 'F', SRV_BAD_PIPELINE , 0 },
5670*d39bd2c1SGregory Neil Shapiro { 'G', SRV_BARE_LF_421 , SRV_BARE_LF_SP },
5671*d39bd2c1SGregory Neil Shapiro { 'H', SRV_NO_HTTP_CMD , 0 },
56722fb4f839SGregory Neil Shapiro #if USE_EAI
5673*d39bd2c1SGregory Neil Shapiro { 'I', SRV_OFFER_EAI , 0 },
56745b0945b5SGregory Neil Shapiro #endif
5675*d39bd2c1SGregory Neil Shapiro /* { 'J', 0 , 0 }, */
5676*d39bd2c1SGregory Neil Shapiro /* { 'K', 0 , 0 }, */
5677*d39bd2c1SGregory Neil Shapiro { 'L', SRV_REQ_AUTH , 0 },
5678*d39bd2c1SGregory Neil Shapiro /* { 'M', 0 , 0 }, */
5679*d39bd2c1SGregory Neil Shapiro #if PIPELINING && _FFR_NO_PIPE
5680*d39bd2c1SGregory Neil Shapiro { 'N', SRV_NO_PIPE , 0 },
5681*d39bd2c1SGregory Neil Shapiro #endif
5682*d39bd2c1SGregory Neil Shapiro { 'O', SRV_REQ_CRLF , 0 }, /* eOl */
568340266059SGregory Neil Shapiro #if PIPELINING
5684*d39bd2c1SGregory Neil Shapiro { 'P', SRV_OFFER_PIPE , 0 },
56855b0945b5SGregory Neil Shapiro #endif
5686*d39bd2c1SGregory Neil Shapiro /* { 'Q', 0 , 0 }, */
5687*d39bd2c1SGregory Neil Shapiro { 'R', SRV_VRFY_CLT , 0 }, /* same as V; not documented */
5688*d39bd2c1SGregory Neil Shapiro { 'S', SRV_OFFER_TLS , 0 },
5689*d39bd2c1SGregory Neil Shapiro /* { 'T', SRV_TMP_FAIL , 0 }, */
5690*d39bd2c1SGregory Neil Shapiro { 'U', SRV_BARE_CR_421 , SRV_BARE_CR_SP },
5691*d39bd2c1SGregory Neil Shapiro { 'V', SRV_VRFY_CLT , 0 },
5692*d39bd2c1SGregory Neil Shapiro /* { 'W', 0 , 0 }, */
5693*d39bd2c1SGregory Neil Shapiro { 'X', SRV_OFFER_EXPN , 0 },
5694*d39bd2c1SGregory Neil Shapiro /* { 'Y', SRV_OFFER_VRFY , 0 }, */
5695*d39bd2c1SGregory Neil Shapiro /* { 'Z', 0 , 0 }, */
5696*d39bd2c1SGregory Neil Shapiro { '\0', SRV_NONE , 0 }
569740266059SGregory Neil Shapiro };
569840266059SGregory Neil Shapiro
5699*d39bd2c1SGregory Neil Shapiro static unsigned long
srvfeatures(e,clientname,features)570040266059SGregory Neil Shapiro srvfeatures(e, clientname, features)
570140266059SGregory Neil Shapiro ENVELOPE *e;
570240266059SGregory Neil Shapiro char *clientname;
5703*d39bd2c1SGregory Neil Shapiro unsigned long features;
570440266059SGregory Neil Shapiro {
570540266059SGregory Neil Shapiro int r, i, j;
570640266059SGregory Neil Shapiro char **pvp, c, opt;
570740266059SGregory Neil Shapiro char pvpbuf[PSBUFSIZE];
570840266059SGregory Neil Shapiro
570940266059SGregory Neil Shapiro pvp = NULL;
571040266059SGregory Neil Shapiro r = rscap("srv_features", clientname, "", e, &pvp, pvpbuf,
571140266059SGregory Neil Shapiro sizeof(pvpbuf));
571240266059SGregory Neil Shapiro if (r != EX_OK)
571340266059SGregory Neil Shapiro return features;
571440266059SGregory Neil Shapiro if (pvp == NULL || pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET)
571540266059SGregory Neil Shapiro return features;
571640266059SGregory Neil Shapiro if (pvp[1] != NULL && sm_strncasecmp(pvp[1], "temp", 4) == 0)
571740266059SGregory Neil Shapiro return SRV_TMP_FAIL;
571840266059SGregory Neil Shapiro
571940266059SGregory Neil Shapiro /*
572040266059SGregory Neil Shapiro ** General rule (see sendmail.h, d_flags):
572140266059SGregory Neil Shapiro ** lower case: required/offered, upper case: Not required/available
572240266059SGregory Neil Shapiro **
572340266059SGregory Neil Shapiro ** Since we can change some features per daemon, we have both
572440266059SGregory Neil Shapiro ** cases here: turn on/off a feature.
572540266059SGregory Neil Shapiro */
572640266059SGregory Neil Shapiro
572740266059SGregory Neil Shapiro for (i = 1; pvp[i] != NULL; i++)
572840266059SGregory Neil Shapiro {
572940266059SGregory Neil Shapiro c = pvp[i][0];
573040266059SGregory Neil Shapiro j = 0;
573140266059SGregory Neil Shapiro for (;;)
573240266059SGregory Neil Shapiro {
573340266059SGregory Neil Shapiro if ((opt = srv_feat_table[j].srvf_opt) == '\0')
573440266059SGregory Neil Shapiro {
573540266059SGregory Neil Shapiro if (LogLevel > 9)
573640266059SGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id,
5737*d39bd2c1SGregory Neil Shapiro "srv_features: unknown feature %s",
573840266059SGregory Neil Shapiro pvp[i]);
573940266059SGregory Neil Shapiro break;
574040266059SGregory Neil Shapiro }
574140266059SGregory Neil Shapiro if (c == opt)
574240266059SGregory Neil Shapiro {
574340266059SGregory Neil Shapiro features &= ~(srv_feat_table[j].srvf_flag);
574440266059SGregory Neil Shapiro break;
574540266059SGregory Neil Shapiro }
5746*d39bd2c1SGregory Neil Shapiro
5747*d39bd2c1SGregory Neil Shapiro /*
5748*d39bd2c1SGregory Neil Shapiro ** Note: the "noflag" code below works ONLY for
5749*d39bd2c1SGregory Neil Shapiro ** the current situation:
5750*d39bd2c1SGregory Neil Shapiro ** - _flag itself is set by default
5751*d39bd2c1SGregory Neil Shapiro ** (drop session if bare CR or LF is found)
5752*d39bd2c1SGregory Neil Shapiro ** - _flag2 is only "effective" if _flag is not set,
5753*d39bd2c1SGregory Neil Shapiro ** hence using it turns off _flag.
5754*d39bd2c1SGregory Neil Shapiro ** If that situation changes, the code must be changed!
5755*d39bd2c1SGregory Neil Shapiro */
5756*d39bd2c1SGregory Neil Shapiro
575740266059SGregory Neil Shapiro if (c == tolower(opt))
575840266059SGregory Neil Shapiro {
5759*d39bd2c1SGregory Neil Shapiro unsigned long flag, noflag;
5760*d39bd2c1SGregory Neil Shapiro
5761*d39bd2c1SGregory Neil Shapiro c = pvp[i][1];
5762*d39bd2c1SGregory Neil Shapiro flag = noflag = 0;
5763*d39bd2c1SGregory Neil Shapiro if ('2' == c)
5764*d39bd2c1SGregory Neil Shapiro {
5765*d39bd2c1SGregory Neil Shapiro flag = srv_feat_table[j].srvf_flag2;
5766*d39bd2c1SGregory Neil Shapiro noflag = srv_feat_table[j].srvf_flag;
5767*d39bd2c1SGregory Neil Shapiro }
5768*d39bd2c1SGregory Neil Shapiro else if ('\0' == c)
5769*d39bd2c1SGregory Neil Shapiro flag = srv_feat_table[j].srvf_flag;
5770*d39bd2c1SGregory Neil Shapiro if (0 != flag)
5771*d39bd2c1SGregory Neil Shapiro {
5772*d39bd2c1SGregory Neil Shapiro features |= flag;
5773*d39bd2c1SGregory Neil Shapiro if (0 != noflag)
5774*d39bd2c1SGregory Neil Shapiro features &= ~noflag;
5775*d39bd2c1SGregory Neil Shapiro }
5776*d39bd2c1SGregory Neil Shapiro else if (LogLevel > 9)
5777*d39bd2c1SGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id,
5778*d39bd2c1SGregory Neil Shapiro "srv_features: unknown variant %s",
5779*d39bd2c1SGregory Neil Shapiro pvp[i]);
578040266059SGregory Neil Shapiro break;
578140266059SGregory Neil Shapiro }
578240266059SGregory Neil Shapiro ++j;
578340266059SGregory Neil Shapiro }
578440266059SGregory Neil Shapiro }
578540266059SGregory Neil Shapiro return features;
578640266059SGregory Neil Shapiro }
578740266059SGregory Neil Shapiro
578840266059SGregory Neil Shapiro /*
5789c2aa98e2SPeter Wemm ** HELP -- implement the HELP command.
5790c2aa98e2SPeter Wemm **
5791c2aa98e2SPeter Wemm ** Parameters:
5792c2aa98e2SPeter Wemm ** topic -- the topic we want help for.
579340266059SGregory Neil Shapiro ** e -- envelope.
5794c2aa98e2SPeter Wemm **
5795c2aa98e2SPeter Wemm ** Returns:
5796c2aa98e2SPeter Wemm ** none.
5797c2aa98e2SPeter Wemm **
5798c2aa98e2SPeter Wemm ** Side Effects:
5799c2aa98e2SPeter Wemm ** outputs the help file to message output.
5800c2aa98e2SPeter Wemm */
580106f25ae9SGregory Neil Shapiro #define HELPVSTR "#vers "
580206f25ae9SGregory Neil Shapiro #define HELPVERSION 2
5803c2aa98e2SPeter Wemm
5804c2aa98e2SPeter Wemm void
help(topic,e)580506f25ae9SGregory Neil Shapiro help(topic, e)
5806c2aa98e2SPeter Wemm char *topic;
580706f25ae9SGregory Neil Shapiro ENVELOPE *e;
5808c2aa98e2SPeter Wemm {
580940266059SGregory Neil Shapiro register SM_FILE_T *hf;
581006f25ae9SGregory Neil Shapiro register char *p;
58112fb4f839SGregory Neil Shapiro char *lstr;
5812c2aa98e2SPeter Wemm int len;
5813c2aa98e2SPeter Wemm bool noinfo;
581440266059SGregory Neil Shapiro bool first = true;
581506f25ae9SGregory Neil Shapiro long sff = SFF_OPENASROOT|SFF_REGONLY;
5816c2aa98e2SPeter Wemm char buf[MAXLINE];
581706f25ae9SGregory Neil Shapiro char inp[MAXLINE];
581806f25ae9SGregory Neil Shapiro static int foundvers = -1;
5819c2aa98e2SPeter Wemm extern char Version[];
5820c2aa98e2SPeter Wemm
5821c2aa98e2SPeter Wemm if (DontLockReadFiles)
5822c2aa98e2SPeter Wemm sff |= SFF_NOLOCK;
582306f25ae9SGregory Neil Shapiro if (!bitnset(DBS_HELPFILEINUNSAFEDIRPATH, DontBlameSendmail))
5824c2aa98e2SPeter Wemm sff |= SFF_SAFEDIRPATH;
5825c2aa98e2SPeter Wemm
5826c2aa98e2SPeter Wemm if (HelpFile == NULL ||
5827c2aa98e2SPeter Wemm (hf = safefopen(HelpFile, O_RDONLY, 0444, sff)) == NULL)
5828c2aa98e2SPeter Wemm {
5829c2aa98e2SPeter Wemm /* no help */
5830c2aa98e2SPeter Wemm errno = 0;
583106f25ae9SGregory Neil Shapiro message("502 5.3.0 Sendmail %s -- HELP not implemented",
583206f25ae9SGregory Neil Shapiro Version);
5833c2aa98e2SPeter Wemm return;
5834c2aa98e2SPeter Wemm }
5835c2aa98e2SPeter Wemm
58362fb4f839SGregory Neil Shapiro lstr = NULL;
58372fb4f839SGregory Neil Shapiro if (SM_IS_EMPTY(topic))
5838c2aa98e2SPeter Wemm {
5839c2aa98e2SPeter Wemm topic = "smtp";
584040266059SGregory Neil Shapiro noinfo = false;
5841c2aa98e2SPeter Wemm }
5842c2aa98e2SPeter Wemm else
5843c2aa98e2SPeter Wemm {
58442fb4f839SGregory Neil Shapiro
58452fb4f839SGregory Neil Shapiro lstr = makelower_a(&topic, NULL);
58462fb4f839SGregory Neil Shapiro if (lstr != topic)
58472fb4f839SGregory Neil Shapiro topic = lstr;
58482fb4f839SGregory Neil Shapiro else
58492fb4f839SGregory Neil Shapiro lstr = NULL;
585040266059SGregory Neil Shapiro noinfo = true;
5851c2aa98e2SPeter Wemm }
5852c2aa98e2SPeter Wemm
5853c2aa98e2SPeter Wemm len = strlen(topic);
5854c2aa98e2SPeter Wemm
5855552d4955SGregory Neil Shapiro while (sm_io_fgets(hf, SM_TIME_DEFAULT, buf, sizeof(buf)) >= 0)
5856c2aa98e2SPeter Wemm {
585706f25ae9SGregory Neil Shapiro if (buf[0] == '#')
585806f25ae9SGregory Neil Shapiro {
585906f25ae9SGregory Neil Shapiro if (foundvers < 0 &&
586006f25ae9SGregory Neil Shapiro strncmp(buf, HELPVSTR, strlen(HELPVSTR)) == 0)
586106f25ae9SGregory Neil Shapiro {
586206f25ae9SGregory Neil Shapiro int h;
586306f25ae9SGregory Neil Shapiro
586440266059SGregory Neil Shapiro if (sm_io_sscanf(buf + strlen(HELPVSTR), "%d",
586506f25ae9SGregory Neil Shapiro &h) == 1)
586606f25ae9SGregory Neil Shapiro foundvers = h;
586706f25ae9SGregory Neil Shapiro }
586806f25ae9SGregory Neil Shapiro continue;
586906f25ae9SGregory Neil Shapiro }
5870c2aa98e2SPeter Wemm if (strncmp(buf, topic, len) == 0)
5871c2aa98e2SPeter Wemm {
587206f25ae9SGregory Neil Shapiro if (first)
587306f25ae9SGregory Neil Shapiro {
587440266059SGregory Neil Shapiro first = false;
5875c2aa98e2SPeter Wemm
587606f25ae9SGregory Neil Shapiro /* print version if no/old vers# in file */
587706f25ae9SGregory Neil Shapiro if (foundvers < 2 && !noinfo)
587806f25ae9SGregory Neil Shapiro message("214-2.0.0 This is Sendmail version %s", Version);
587906f25ae9SGregory Neil Shapiro }
588006f25ae9SGregory Neil Shapiro p = strpbrk(buf, " \t");
5881c2aa98e2SPeter Wemm if (p == NULL)
588206f25ae9SGregory Neil Shapiro p = buf + strlen(buf) - 1;
5883c2aa98e2SPeter Wemm else
5884c2aa98e2SPeter Wemm p++;
588540266059SGregory Neil Shapiro fixcrlf(p, true);
588606f25ae9SGregory Neil Shapiro if (foundvers >= 2)
588706f25ae9SGregory Neil Shapiro {
5888d0cef73dSGregory Neil Shapiro char *lbp;
5889d0cef73dSGregory Neil Shapiro int lbs = sizeof(buf) - (p - buf);
5890d0cef73dSGregory Neil Shapiro
5891d0cef73dSGregory Neil Shapiro lbp = translate_dollars(p, p, &lbs);
5892d0cef73dSGregory Neil Shapiro expand(lbp, inp, sizeof(inp), e);
5893d0cef73dSGregory Neil Shapiro if (p != lbp)
5894d0cef73dSGregory Neil Shapiro sm_free(lbp);
589506f25ae9SGregory Neil Shapiro p = inp;
589606f25ae9SGregory Neil Shapiro }
589706f25ae9SGregory Neil Shapiro message("214-2.0.0 %s", p);
589840266059SGregory Neil Shapiro noinfo = false;
5899c2aa98e2SPeter Wemm }
5900c2aa98e2SPeter Wemm }
5901c2aa98e2SPeter Wemm
5902c2aa98e2SPeter Wemm if (noinfo)
590306f25ae9SGregory Neil Shapiro message("504 5.3.0 HELP topic \"%.10s\" unknown", topic);
5904c2aa98e2SPeter Wemm else
590506f25ae9SGregory Neil Shapiro message("214 2.0.0 End of HELP info");
590606f25ae9SGregory Neil Shapiro
590706f25ae9SGregory Neil Shapiro if (foundvers != 0 && foundvers < HELPVERSION)
590806f25ae9SGregory Neil Shapiro {
590906f25ae9SGregory Neil Shapiro if (LogLevel > 1)
591006f25ae9SGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id,
591106f25ae9SGregory Neil Shapiro "%s too old (require version %d)",
591206f25ae9SGregory Neil Shapiro HelpFile, HELPVERSION);
591306f25ae9SGregory Neil Shapiro
591406f25ae9SGregory Neil Shapiro /* avoid log next time */
591506f25ae9SGregory Neil Shapiro foundvers = 0;
591606f25ae9SGregory Neil Shapiro }
591706f25ae9SGregory Neil Shapiro
591840266059SGregory Neil Shapiro (void) sm_io_close(hf, SM_TIME_DEFAULT);
59192fb4f839SGregory Neil Shapiro SM_FREE(lstr);
5920c2aa98e2SPeter Wemm }
5921a7ec597cSGregory Neil Shapiro
5922a7ec597cSGregory Neil Shapiro #if SASL
5923a7ec597cSGregory Neil Shapiro /*
5924a7ec597cSGregory Neil Shapiro ** RESET_SASLCONN -- reset SASL connection data
5925a7ec597cSGregory Neil Shapiro **
5926a7ec597cSGregory Neil Shapiro ** Parameters:
5927a7ec597cSGregory Neil Shapiro ** conn -- SASL connection context
5928a7ec597cSGregory Neil Shapiro ** hostname -- host name
5929a7ec597cSGregory Neil Shapiro ** various connection data
5930a7ec597cSGregory Neil Shapiro **
5931a7ec597cSGregory Neil Shapiro ** Returns:
5932a7ec597cSGregory Neil Shapiro ** SASL result
5933a7ec597cSGregory Neil Shapiro */
5934a7ec597cSGregory Neil Shapiro
59352fb4f839SGregory Neil Shapiro #ifdef __STDC__
5936a7ec597cSGregory Neil Shapiro static int
reset_saslconn(sasl_conn_t ** conn,char * hostname,char * remoteip,char * localip,char * auth_id,sasl_ssf_t * ext_ssf)5937a7ec597cSGregory Neil Shapiro reset_saslconn(sasl_conn_t **conn, char *hostname,
5938a7ec597cSGregory Neil Shapiro # if SASL >= 20000
5939a7ec597cSGregory Neil Shapiro char *remoteip, char *localip,
5940a7ec597cSGregory Neil Shapiro char *auth_id, sasl_ssf_t * ext_ssf)
5941a7ec597cSGregory Neil Shapiro # else /* SASL >= 20000 */
5942a7ec597cSGregory Neil Shapiro struct sockaddr_in *saddr_r, struct sockaddr_in *saddr_l,
5943a7ec597cSGregory Neil Shapiro sasl_external_properties_t * ext_ssf)
5944a7ec597cSGregory Neil Shapiro # endif /* SASL >= 20000 */
59452fb4f839SGregory Neil Shapiro #else /* __STDC__ */
5946*d39bd2c1SGregory Neil Shapiro # error "SASL requires __STDC__"
59472fb4f839SGregory Neil Shapiro #endif /* __STDC__ */
5948a7ec597cSGregory Neil Shapiro {
5949a7ec597cSGregory Neil Shapiro int result;
5950a7ec597cSGregory Neil Shapiro
5951a7ec597cSGregory Neil Shapiro sasl_dispose(conn);
5952a7ec597cSGregory Neil Shapiro # if SASL >= 20000
5953a7ec597cSGregory Neil Shapiro result = sasl_server_new("smtp", hostname, NULL, NULL, NULL,
5954a7ec597cSGregory Neil Shapiro NULL, 0, conn);
5955a7ec597cSGregory Neil Shapiro # elif SASL > 10505
5956a7ec597cSGregory Neil Shapiro /* use empty realm: only works in SASL > 1.5.5 */
5957a7ec597cSGregory Neil Shapiro result = sasl_server_new("smtp", hostname, "", NULL, 0, conn);
5958a7ec597cSGregory Neil Shapiro # else /* SASL >= 20000 */
5959a7ec597cSGregory Neil Shapiro /* use no realm -> realm is set to hostname by SASL lib */
5960a7ec597cSGregory Neil Shapiro result = sasl_server_new("smtp", hostname, NULL, NULL, 0,
5961a7ec597cSGregory Neil Shapiro conn);
5962a7ec597cSGregory Neil Shapiro # endif /* SASL >= 20000 */
5963a7ec597cSGregory Neil Shapiro if (result != SASL_OK)
5964a7ec597cSGregory Neil Shapiro return result;
5965a7ec597cSGregory Neil Shapiro
5966a7ec597cSGregory Neil Shapiro # if SASL >= 20000
5967a7ec597cSGregory Neil Shapiro # if NETINET || NETINET6
596813d88268SGregory Neil Shapiro if (remoteip != NULL && *remoteip != '\0')
5969a7ec597cSGregory Neil Shapiro result = sasl_setprop(*conn, SASL_IPREMOTEPORT, remoteip);
5970a7ec597cSGregory Neil Shapiro if (result != SASL_OK)
5971a7ec597cSGregory Neil Shapiro return result;
5972a7ec597cSGregory Neil Shapiro
597313d88268SGregory Neil Shapiro if (localip != NULL && *localip != '\0')
5974a7ec597cSGregory Neil Shapiro result = sasl_setprop(*conn, SASL_IPLOCALPORT, localip);
5975a7ec597cSGregory Neil Shapiro if (result != SASL_OK)
5976a7ec597cSGregory Neil Shapiro return result;
5977a7ec597cSGregory Neil Shapiro # endif /* NETINET || NETINET6 */
5978a7ec597cSGregory Neil Shapiro
5979a7ec597cSGregory Neil Shapiro result = sasl_setprop(*conn, SASL_SSF_EXTERNAL, ext_ssf);
5980a7ec597cSGregory Neil Shapiro if (result != SASL_OK)
5981a7ec597cSGregory Neil Shapiro return result;
5982a7ec597cSGregory Neil Shapiro
5983a7ec597cSGregory Neil Shapiro result = sasl_setprop(*conn, SASL_AUTH_EXTERNAL, auth_id);
5984a7ec597cSGregory Neil Shapiro if (result != SASL_OK)
5985a7ec597cSGregory Neil Shapiro return result;
5986a7ec597cSGregory Neil Shapiro # else /* SASL >= 20000 */
5987a7ec597cSGregory Neil Shapiro # if NETINET
5988a7ec597cSGregory Neil Shapiro if (saddr_r != NULL)
5989a7ec597cSGregory Neil Shapiro result = sasl_setprop(*conn, SASL_IP_REMOTE, saddr_r);
5990a7ec597cSGregory Neil Shapiro if (result != SASL_OK)
5991a7ec597cSGregory Neil Shapiro return result;
5992a7ec597cSGregory Neil Shapiro
5993a7ec597cSGregory Neil Shapiro if (saddr_l != NULL)
5994a7ec597cSGregory Neil Shapiro result = sasl_setprop(*conn, SASL_IP_LOCAL, saddr_l);
5995a7ec597cSGregory Neil Shapiro if (result != SASL_OK)
5996a7ec597cSGregory Neil Shapiro return result;
5997a7ec597cSGregory Neil Shapiro # endif /* NETINET */
5998a7ec597cSGregory Neil Shapiro
5999a7ec597cSGregory Neil Shapiro result = sasl_setprop(*conn, SASL_SSF_EXTERNAL, ext_ssf);
6000a7ec597cSGregory Neil Shapiro if (result != SASL_OK)
6001a7ec597cSGregory Neil Shapiro return result;
6002a7ec597cSGregory Neil Shapiro # endif /* SASL >= 20000 */
6003a7ec597cSGregory Neil Shapiro return SASL_OK;
6004a7ec597cSGregory Neil Shapiro }
60055b0945b5SGregory Neil Shapiro
60065b0945b5SGregory Neil Shapiro /*
60075b0945b5SGregory Neil Shapiro ** GET_SASL_USER -- extract user part from SASL reply
60085b0945b5SGregory Neil Shapiro **
60095b0945b5SGregory Neil Shapiro ** Parameters:
60105b0945b5SGregory Neil Shapiro ** val -- sasl reply (may contain NUL)
60115b0945b5SGregory Neil Shapiro ** len -- length of val
60125b0945b5SGregory Neil Shapiro ** auth_type -- auth_type (can be NULL)
60135b0945b5SGregory Neil Shapiro ** user -- output buffer for extract user
60145b0945b5SGregory Neil Shapiro ** user_len -- length of output buffer (user)
60155b0945b5SGregory Neil Shapiro **
60165b0945b5SGregory Neil Shapiro ** Returns:
60175b0945b5SGregory Neil Shapiro ** none.
60185b0945b5SGregory Neil Shapiro **
60195b0945b5SGregory Neil Shapiro ** Note: val is supplied by the client and hence may contain "bad"
60205b0945b5SGregory Neil Shapiro ** (non-printable) characters, but the returned value (user)
60215b0945b5SGregory Neil Shapiro ** is only used for logging which converts those characters.
60225b0945b5SGregory Neil Shapiro */
60235b0945b5SGregory Neil Shapiro
60245b0945b5SGregory Neil Shapiro static void
get_sasl_user(val,len,auth_type,user,user_len)60255b0945b5SGregory Neil Shapiro get_sasl_user(val, len, auth_type, user, user_len)
60265b0945b5SGregory Neil Shapiro char *val;
60275b0945b5SGregory Neil Shapiro unsigned int len;
60285b0945b5SGregory Neil Shapiro const char *auth_type;
60295b0945b5SGregory Neil Shapiro char *user;
60305b0945b5SGregory Neil Shapiro size_t user_len;
60315b0945b5SGregory Neil Shapiro {
60325b0945b5SGregory Neil Shapiro unsigned int u;
60335b0945b5SGregory Neil Shapiro
60345b0945b5SGregory Neil Shapiro SM_ASSERT(val != NULL);
60355b0945b5SGregory Neil Shapiro SM_ASSERT(user != NULL);
60365b0945b5SGregory Neil Shapiro SM_ASSERT(user_len > 0);
60375b0945b5SGregory Neil Shapiro
60385b0945b5SGregory Neil Shapiro *user = '\0';
60392fb4f839SGregory Neil Shapiro if (SM_IS_EMPTY(auth_type))
60405b0945b5SGregory Neil Shapiro return;
60415b0945b5SGregory Neil Shapiro if (0 == len)
60425b0945b5SGregory Neil Shapiro return;
60435b0945b5SGregory Neil Shapiro
60445b0945b5SGregory Neil Shapiro # define DIGMD5U "username=\""
60455b0945b5SGregory Neil Shapiro # define DIGMD5U_L (sizeof(DIGMD5U) - 1)
60462fb4f839SGregory Neil Shapiro if (SM_STRCASEEQ(auth_type, "digest-md5") &&
60475b0945b5SGregory Neil Shapiro strncmp(val, DIGMD5U, DIGMD5U_L) == 0)
60485b0945b5SGregory Neil Shapiro {
60495b0945b5SGregory Neil Shapiro char *s;
60505b0945b5SGregory Neil Shapiro
60515b0945b5SGregory Neil Shapiro val += DIGMD5U_L;
60525b0945b5SGregory Neil Shapiro if (len <= DIGMD5U_L)
60535b0945b5SGregory Neil Shapiro return;
60545b0945b5SGregory Neil Shapiro len -= DIGMD5U_L;
60555b0945b5SGregory Neil Shapiro
60565b0945b5SGregory Neil Shapiro /* format? could there be a quoted '"'? */
60575b0945b5SGregory Neil Shapiro for (s = val, u = 0; *s != '\0' && u < len; s++)
60585b0945b5SGregory Neil Shapiro {
60595b0945b5SGregory Neil Shapiro if ('"' == *s)
60605b0945b5SGregory Neil Shapiro {
60615b0945b5SGregory Neil Shapiro *s = '\0';
60625b0945b5SGregory Neil Shapiro break;
60635b0945b5SGregory Neil Shapiro }
60645b0945b5SGregory Neil Shapiro if ('\\' == *s)
60655b0945b5SGregory Neil Shapiro {
60665b0945b5SGregory Neil Shapiro ++s;
60675b0945b5SGregory Neil Shapiro if ('\0' == *s)
60685b0945b5SGregory Neil Shapiro break;
60695b0945b5SGregory Neil Shapiro }
60705b0945b5SGregory Neil Shapiro }
60715b0945b5SGregory Neil Shapiro }
60722fb4f839SGregory Neil Shapiro else if (SM_STRCASEEQ(auth_type, "cram-md5"))
60735b0945b5SGregory Neil Shapiro {
60745b0945b5SGregory Neil Shapiro char *s;
60755b0945b5SGregory Neil Shapiro
60765b0945b5SGregory Neil Shapiro for (s = val, u = 0; *s != '\0' && u < len; s++)
60775b0945b5SGregory Neil Shapiro {
60785b0945b5SGregory Neil Shapiro if (' ' == *s)
60795b0945b5SGregory Neil Shapiro {
60805b0945b5SGregory Neil Shapiro *s = '\0';
60815b0945b5SGregory Neil Shapiro break;
60825b0945b5SGregory Neil Shapiro }
60835b0945b5SGregory Neil Shapiro }
60845b0945b5SGregory Neil Shapiro }
60855b0945b5SGregory Neil Shapiro
60862fb4f839SGregory Neil Shapiro else if (SM_STRCASEEQ(auth_type, "plain") ||
60872fb4f839SGregory Neil Shapiro SM_STRCASEEQ(auth_type, "login"))
60885b0945b5SGregory Neil Shapiro {
60895b0945b5SGregory Neil Shapiro /*
60905b0945b5SGregory Neil Shapiro ** RFC 4616: The PLAIN Simple Authentication and
60915b0945b5SGregory Neil Shapiro ** Security Layer (SASL) Mechanism
60925b0945b5SGregory Neil Shapiro ** message = [authzid] UTF8NUL authcid UTF8NUL passwd
60935b0945b5SGregory Neil Shapiro ** each part: 1*SAFE ; MUST accept up to 255 octets
60945b0945b5SGregory Neil Shapiro ** UTF8NUL = %x00 ; UTF-8 encoded NUL character
60955b0945b5SGregory Neil Shapiro **
60965b0945b5SGregory Neil Shapiro ** draft-murchison-sasl-login: it's just username by its own
60975b0945b5SGregory Neil Shapiro */
60985b0945b5SGregory Neil Shapiro
60995b0945b5SGregory Neil Shapiro for (u = 0; u < len; u++)
61005b0945b5SGregory Neil Shapiro {
61015b0945b5SGregory Neil Shapiro if (val[u] == '\0')
61025b0945b5SGregory Neil Shapiro {
61035b0945b5SGregory Neil Shapiro val[u] = '/';
61045b0945b5SGregory Neil Shapiro (void) sm_strlcpy(user,
61055b0945b5SGregory Neil Shapiro val + ((0 == u) ? 1 : 0),
61065b0945b5SGregory Neil Shapiro user_len);
61075b0945b5SGregory Neil Shapiro return;
61085b0945b5SGregory Neil Shapiro }
61095b0945b5SGregory Neil Shapiro }
61105b0945b5SGregory Neil Shapiro }
61115b0945b5SGregory Neil Shapiro else
61125b0945b5SGregory Neil Shapiro {
61135b0945b5SGregory Neil Shapiro /*
61145b0945b5SGregory Neil Shapiro ** Extracting the "user" from other mechanisms
61155b0945b5SGregory Neil Shapiro ** is currently not supported.
61165b0945b5SGregory Neil Shapiro */
61175b0945b5SGregory Neil Shapiro
61185b0945b5SGregory Neil Shapiro return;
61195b0945b5SGregory Neil Shapiro }
61205b0945b5SGregory Neil Shapiro
61215b0945b5SGregory Neil Shapiro /*
61225b0945b5SGregory Neil Shapiro ** Does the input buffer has an NUL in it so it can be treated
61235b0945b5SGregory Neil Shapiro ** as a C string?
61245b0945b5SGregory Neil Shapiro */
61255b0945b5SGregory Neil Shapiro
61265b0945b5SGregory Neil Shapiro /* SM_ASSERT(len > 0); see above */
61275b0945b5SGregory Neil Shapiro u = len - 1;
61285b0945b5SGregory Neil Shapiro if (val[u] != '\0')
61295b0945b5SGregory Neil Shapiro {
61305b0945b5SGregory Neil Shapiro for (u = 0; u < len; u++)
61315b0945b5SGregory Neil Shapiro {
61325b0945b5SGregory Neil Shapiro if (val[u] == '\0')
61335b0945b5SGregory Neil Shapiro break;
61345b0945b5SGregory Neil Shapiro }
61355b0945b5SGregory Neil Shapiro }
61365b0945b5SGregory Neil Shapiro if (val[u] != '\0')
61375b0945b5SGregory Neil Shapiro user_len = SM_MIN(len, user_len);
61385b0945b5SGregory Neil Shapiro
61395b0945b5SGregory Neil Shapiro (void) sm_strlcpy(user, val, user_len);
61405b0945b5SGregory Neil Shapiro }
6141a7ec597cSGregory Neil Shapiro #endif /* SASL */
6142