diff options
author | gshapiro <gshapiro@FreeBSD.org> | 2007-04-09 01:38:51 +0000 |
---|---|---|
committer | gshapiro <gshapiro@FreeBSD.org> | 2007-04-09 01:38:51 +0000 |
commit | 14e22b52d4375b164f9fa21c0ab3abd9837e823f (patch) | |
tree | 2a4f38ae8ba223f3bf2402f56d35c997e5af6db5 /contrib/sendmail/src/srvrsmtp.c | |
parent | 0a9c74f73599b0ca2981b57815b436d1f6de6191 (diff) | |
download | FreeBSD-src-14e22b52d4375b164f9fa21c0ab3abd9837e823f.zip FreeBSD-src-14e22b52d4375b164f9fa21c0ab3abd9837e823f.tar.gz |
Import sendmail 8.14.1
Diffstat (limited to 'contrib/sendmail/src/srvrsmtp.c')
-rw-r--r-- | contrib/sendmail/src/srvrsmtp.c | 663 |
1 files changed, 429 insertions, 234 deletions
diff --git a/contrib/sendmail/src/srvrsmtp.c b/contrib/sendmail/src/srvrsmtp.c index d95b5a5..1f067b1 100644 --- a/contrib/sendmail/src/srvrsmtp.c +++ b/contrib/sendmail/src/srvrsmtp.c @@ -17,7 +17,7 @@ # include <libmilter/mfdef.h> #endif /* MILTER */ -SM_RCSID("@(#)$Id: srvrsmtp.c,v 8.924.2.5 2006/07/07 16:29:39 ca Exp $") +SM_RCSID("@(#)$Id: srvrsmtp.c,v 8.960 2007/02/07 20:18:47 ca Exp $") #include <sm/time.h> #include <sm/fdset.h> @@ -36,15 +36,15 @@ static SSL_CTX *srv_ctx = NULL; /* TLS server context */ static SSL *srv_ssl = NULL; /* per connection context */ static bool tls_ok_srv = false; -#if _FFR_DM_ONE -static bool NotFirstDelivery = false; -#endif /* _FFR_DM_ONE */ -extern void tls_set_verify __P((SSL_CTX *, SSL *, bool)); # define TLS_VERIFY_CLIENT() tls_set_verify(srv_ctx, srv_ssl, \ bitset(SRV_VRFY_CLT, features)) #endif /* STARTTLS */ +#if _FFR_DM_ONE +static bool NotFirstDelivery = false; +#endif /* _FFR_DM_ONE */ + /* server features */ #define SRV_NONE 0x0000 /* none... */ #define SRV_OFFER_TLS 0x0001 /* offer STARTTLS */ @@ -70,10 +70,7 @@ static unsigned int srvfeatures __P((ENVELOPE *, char *, unsigned int)); #define STOP_ATTACK ((time_t) -1) static time_t checksmtpattack __P((volatile unsigned int *, unsigned int, bool, char *, ENVELOPE *)); -static void mail_esmtp_args __P((char *, char *, ENVELOPE *, unsigned int)); static void printvrfyaddr __P((ADDRESS *, bool, bool)); -static void rcpt_esmtp_args __P((ADDRESS *, char *, char *, ENVELOPE *, - unsigned int)); static char *skipword __P((char *volatile, char *)); static void setup_smtpd_io __P((void)); @@ -115,7 +112,7 @@ extern ENVELOPE BlankEnvelope; do \ { \ char buf[16]; \ - (void) sm_snprintf(buf, sizeof buf, "%d", \ + (void) sm_snprintf(buf, sizeof(buf), "%d", \ BadRcptThrottle > 0 && n_badrcpts > BadRcptThrottle \ ? n_badrcpts - 1 : n_badrcpts); \ macdefine(&e->e_macro, A_TEMP, macid("{nbadrcpts}"), buf); \ @@ -125,6 +122,88 @@ extern ENVELOPE BlankEnvelope; (s)++ /* +** PARSE_ESMTP_ARGS -- parse EMSTP arguments (for MAIL, RCPT) +** +** Parameters: +** e -- the envelope +** addr_st -- address (RCPT only) +** p -- read buffer +** delimptr -- current position in read buffer +** which -- MAIL/RCPT +** args -- arguments (output) +** esmtp_args -- function to process a single ESMTP argument +** +** Returns: +** none +*/ + +void +parse_esmtp_args(e, addr_st, p, delimptr, which, args, esmtp_args) + ENVELOPE *e; + ADDRESS *addr_st; + char *p; + char *delimptr; + char *which; + char *args[]; + esmtp_args_F esmtp_args; +{ + int argno; + + argno = 0; + if (args != NULL) + args[argno++] = p; + p = delimptr; + while (p != NULL && *p != '\0') + { + char *kp; + char *vp = NULL; + char *equal = NULL; + + /* locate the beginning of the keyword */ + SKIP_SPACE(p); + if (*p == '\0') + break; + kp = p; + + /* skip to the value portion */ + while ((isascii(*p) && isalnum(*p)) || *p == '-') + p++; + if (*p == '=') + { + equal = p; + *p++ = '\0'; + vp = p; + + /* skip to the end of the value */ + while (*p != '\0' && *p != ' ' && + !(isascii(*p) && iscntrl(*p)) && + *p != '=') + p++; + } + + if (*p != '\0') + *p++ = '\0'; + + if (tTd(19, 1)) + sm_dprintf("%s: got arg %s=\"%s\"\n", which, kp, + vp == NULL ? "<null>" : vp); + + esmtp_args(addr_st, kp, vp, e); + if (equal != NULL) + *equal = '='; + if (args != NULL) + args[argno] = kp; + argno++; + if (argno >= MAXSMTPARGS - 1) + usrerr("501 5.5.4 Too many parameters"); + if (Errors > 0) + break; + } + if (args != NULL) + args[argno] = NULL; +} + +/* ** SMTP -- run the SMTP protocol. ** ** Parameters: @@ -291,6 +370,7 @@ static bool smtp_data __P((SMTP_T *, ENVELOPE *)); { \ int savelogusrerrs = LogUsrErrs; \ \ + milter_cmd_fail = true; \ switch (state) \ { \ case SMFIR_SHUTDOWN: \ @@ -351,6 +431,7 @@ static bool smtp_data __P((SMTP_T *, ENVELOPE *)); "Milter: %s=%s, discard", \ str, addr); \ e->e_flags |= EF_DISCARD; \ + milter_cmd_fail = false; \ break; \ \ case SMFIR_TEMPFAIL: \ @@ -363,6 +444,9 @@ static bool smtp_data __P((SMTP_T *, ENVELOPE *)); } \ usrerr(MSG_TEMPFAIL); \ break; \ + default: \ + milter_cmd_fail = false; \ + break; \ } \ LogUsrErrs = savelogusrerrs; \ if (response != NULL) \ @@ -402,6 +486,7 @@ do \ sm_rpool_free(e->e_rpool); \ e = newenvelope(e, CurEnv, sm_rpool_new_x(NULL)); \ CurEnv = e; \ + e->e_features = features; \ \ /* put back discard bit */ \ if (smtp.sm_discard) \ @@ -448,6 +533,7 @@ do \ qid_printname(e), CurSmtpClient, inp); \ } +static bool SevenBitInput_Saved; /* saved version of SevenBitInput */ void smtp(nullserver, d_flags, e) @@ -473,11 +559,8 @@ smtp(nullserver, d_flags, e) volatile unsigned int n_etrn = 0; /* count of ETRN */ volatile unsigned int n_noop = 0; /* count of NOOP/VERB/etc */ volatile unsigned int n_helo = 0; /* count of HELO/EHLO */ - volatile int save_sevenbitinput; bool ok; -#if _FFR_BLOCK_PROXIES volatile bool first; -#endif /* _FFR_BLOCK_PROXIES */ volatile bool tempfail = false; volatile time_t wt; /* timeout after too many commands */ volatile time_t previous; /* time after checksmtpattack() */ @@ -488,9 +571,11 @@ smtp(nullserver, d_flags, e) char *greetcode = "220"; char *hostname; /* my hostname ($j) */ QUEUE_CHAR *new; - int argno; char *args[MAXSMTPARGS]; - char inp[MAXLINE]; + char inp[MAXINPLINE]; +#if MAXINPLINE < MAXLINE + ERROR _MAXINPLINE must NOT be less than _MAXLINE: MAXINPLINE < MAXLINE +#endif /* MAXINPLINE < MAXLINE */ char cmdbuf[MAXLINE]; #if SASL sasl_conn_t *conn; @@ -502,7 +587,7 @@ smtp(nullserver, d_flags, e) char *user; char *in, *out2; # if SASL >= 20000 - char *auth_id; + char *auth_id = NULL; const char *out; sasl_ssf_t ext_ssf; char localip[60], remoteip[60]; @@ -521,6 +606,7 @@ smtp(nullserver, d_flags, e) char *mechlist; volatile unsigned int n_mechs; unsigned int len; +#else /* SASL */ #endif /* SASL */ int r; #if STARTTLS @@ -538,12 +624,22 @@ smtp(nullserver, d_flags, e) # endif /* _FFR_NO_PIPE */ #endif /* PIPELINING */ volatile time_t log_delay = (time_t) 0; +#if MILTER + volatile bool milter_cmd_done, milter_cmd_safe; + volatile bool milter_rcpt_added, milter_cmd_fail; + ADDRESS addr_st; +# define p_addr_st &addr_st +#else /* MILTER */ +# define p_addr_st NULL +#endif /* MILTER */ + size_t inplen; - save_sevenbitinput = SevenBitInput; + SevenBitInput_Saved = SevenBitInput; smtp.sm_nrcpts = 0; #if MILTER smtp.sm_milterize = (nullserver == NULL); smtp.sm_milterlist = false; + addr = NULL; #endif /* MILTER */ /* setup I/O fd correctly for the SMTP server */ @@ -641,6 +737,7 @@ smtp(nullserver, d_flags, e) goto doquit; } + e->e_features = features; hostname = macvalue('j', e); #if SASL if (AuthRealm == NULL) @@ -704,7 +801,7 @@ smtp(nullserver, d_flags, e) &addrsize) == 0) { if (iptostring(&saddr_r, addrsize, - remoteip, sizeof remoteip)) + remoteip, sizeof(remoteip))) { sasl_setprop(conn, SASL_IPREMOTEPORT, remoteip); @@ -718,7 +815,7 @@ smtp(nullserver, d_flags, e) { if (iptostring(&saddr_l, addrsize, localip, - sizeof localip)) + sizeof(localip))) { sasl_setprop(conn, SASL_IPLOCALPORT, @@ -764,7 +861,7 @@ smtp(nullserver, d_flags, e) # endif /* 0 */ /* set properties */ - (void) memset(&ssp, '\0', sizeof ssp); + (void) memset(&ssp, '\0', sizeof(ssp)); /* XXX should these be options settable via .cf ? */ /* ssp.min_ssf = 0; is default due to memset() */ @@ -852,7 +949,9 @@ smtp(nullserver, d_flags, e) char *response; q = macvalue(macid("{client_name}"), e); - SM_ASSERT(q != NULL); + SM_ASSERT(q != NULL || OpMode == MD_SMTP); + if (q == NULL) + q = "localhost"; response = milter_connect(q, RealHostAddr, e, &state); switch (state) { @@ -907,7 +1006,7 @@ smtp(nullserver, d_flags, e) #if STARTTLS !smtps && #endif /* STARTTLS */ - *greetcode == '2') + *greetcode == '2' && nullserver == NULL) { time_t msecs = 0; char **pvp; @@ -929,9 +1028,8 @@ smtp(nullserver, d_flags, e) int fd; fd_set readfds; struct timeval timeout; -#if _FFR_LOG_GREET_PAUSE struct timeval bp, ep, tp; /* {begin,end,total}pause */ -#endif /* _FFR_LOG_GREET_PAUSE */ + int eoftest; /* pause for a moment */ timeout.tv_sec = msecs / 1000; @@ -948,31 +1046,25 @@ smtp(nullserver, d_flags, e) fd = sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL); FD_ZERO(&readfds); SM_FD_SET(fd, &readfds); -#if _FFR_LOG_GREET_PAUSE gettimeofday(&bp, NULL); -#endif /* _FFR_LOG_GREET_PAUSE */ if (select(fd + 1, FDSET_CAST &readfds, NULL, NULL, &timeout) > 0 && - FD_ISSET(fd, &readfds)) + FD_ISSET(fd, &readfds) && + (eoftest = sm_io_getc(InChannel, SM_TIME_DEFAULT)) + != SM_IO_EOF) { -#if _FFR_LOG_GREET_PAUSE + sm_io_ungetc(InChannel, SM_TIME_DEFAULT, + eoftest); gettimeofday(&ep, NULL); timersub(&ep, &bp, &tp); -#endif /* _FFR_LOG_GREET_PAUSE */ greetcode = "554"; nullserver = "Command rejected"; sm_syslog(LOG_INFO, e->e_id, -#if _FFR_LOG_GREET_PAUSE - "rejecting commands from %s [%s] after %d seconds due to pre-greeting traffic", -#else /* _FFR_LOG_GREET_PAUSE */ - "rejecting commands from %s [%s] due to pre-greeting traffic", -#endif /* _FFR_LOG_GREET_PAUSE */ + "rejecting commands from %s [%s] due to pre-greeting traffic after %d seconds", peerhostname, - anynet_ntoa(&RealHostAddr) -#if _FFR_LOG_GREET_PAUSE - , (int) tp.tv_sec + + anynet_ntoa(&RealHostAddr), + (int) tp.tv_sec + (tp.tv_usec >= 500000 ? 1 : 0) -#endif /* _FFR_LOG_GREET_PAUSE */ ); } } @@ -992,10 +1084,10 @@ smtp(nullserver, d_flags, e) /* output the first line, inserting "ESMTP" as second word */ if (*greetcode == '5') - (void) sm_snprintf(inp, sizeof inp, "%s not accepting messages", - hostname); + (void) sm_snprintf(inp, sizeof(inp), + "%s not accepting messages", hostname); else - expand(SmtpGreeting, inp, sizeof inp, e); + expand(SmtpGreeting, inp, sizeof(inp), e); p = strchr(inp, '\n'); if (p != NULL) @@ -1004,10 +1096,10 @@ smtp(nullserver, d_flags, e) if (id == NULL) id = &inp[strlen(inp)]; if (p == NULL) - (void) sm_snprintf(cmdbuf, sizeof cmdbuf, + (void) sm_snprintf(cmdbuf, sizeof(cmdbuf), "%s %%.*s ESMTP%%s", greetcode); else - (void) sm_snprintf(cmdbuf, sizeof cmdbuf, + (void) sm_snprintf(cmdbuf, sizeof(cmdbuf), "%s-%%.*s ESMTP%%s", greetcode); message(cmdbuf, (int) (id - inp), inp, id); @@ -1017,14 +1109,14 @@ smtp(nullserver, d_flags, e) *p++ = '\0'; if (isascii(*id) && isspace(*id)) id++; - (void) sm_strlcpyn(cmdbuf, sizeof cmdbuf, 2, greetcode, "-%s"); + (void) sm_strlcpyn(cmdbuf, sizeof(cmdbuf), 2, greetcode, "-%s"); message(cmdbuf, id); } if (id != NULL) { if (isascii(*id) && isspace(*id)) id++; - (void) sm_strlcpyn(cmdbuf, sizeof cmdbuf, 2, greetcode, " %s"); + (void) sm_strlcpyn(cmdbuf, sizeof(cmdbuf), 2, greetcode, " %s"); message(cmdbuf, id); } @@ -1040,9 +1132,7 @@ smtp(nullserver, d_flags, e) /* sendinghost's storage must outlive the current envelope */ if (sendinghost != NULL) sendinghost = sm_strdup_x(sendinghost); -#if _FFR_BLOCK_PROXIES first = true; -#endif /* _FFR_BLOCK_PROXIES */ gothello = false; smtp.sm_gotmail = false; for (;;) @@ -1055,6 +1145,9 @@ smtp(nullserver, d_flags, e) LogUsrErrs = false; OnlyOneError = true; e->e_flags &= ~(EF_VRFYONLY|EF_GLOBALERRS); +#if MILTER + milter_cmd_fail = false; +#endif /* MILTER */ /* setup for the read */ e->e_to = NULL; @@ -1065,16 +1158,10 @@ smtp(nullserver, d_flags, e) /* read the input line */ SmtpPhase = "server cmd read"; sm_setproctitle(true, e, "server %s cmd read", CurSmtpClient); -#if SASL - /* - ** XXX SMTP AUTH requires accepting any length, - ** at least for challenge/response - */ -#endif /* SASL */ /* handle errors */ if (sm_io_error(OutChannel) || - (p = sfgets(inp, sizeof inp, InChannel, + (p = sfgets(inp, sizeof(inp), InChannel, TimeOuts.to_nextcommand, SmtpPhase)) == NULL) { char *d; @@ -1107,16 +1194,36 @@ smtp(nullserver, d_flags, e) goto doquit; } -#if _FFR_BLOCK_PROXIES + /* also used by "proxy" check below */ + inplen = strlen(inp); +#if SASL + /* + ** SMTP AUTH requires accepting any length, + ** at least for challenge/response. However, not imposing + ** a limit is a bad idea (denial of service). + */ + + if (authenticating != SASL_PROC_AUTH + && sm_strncasecmp(inp, "AUTH ", 5) != 0 + && inplen > MAXLINE) + { + message("421 4.7.0 %s Command too long, possible attack %s", + MyHostName, CurSmtpClient); + sm_syslog(LOG_INFO, e->e_id, + "%s: SMTP violation, input too long: %lu", + CurSmtpClient, (unsigned long) inplen); + goto doquit; + } +#endif /* SASL */ + if (first) { - size_t inplen, cmdlen; + size_t cmdlen; int idx; char *http_cmd; static char *http_cmds[] = { "GET", "POST", "CONNECT", "USER", NULL }; - inplen = strlen(inp); for (idx = 0; (http_cmd = http_cmds[idx]) != NULL; idx++) { @@ -1136,7 +1243,6 @@ smtp(nullserver, d_flags, e) } first = false; } -#endif /* _FFR_BLOCK_PROXIES */ /* clean up end of line */ fixcrlf(inp, true); @@ -1270,7 +1376,7 @@ smtp(nullserver, d_flags, e) { char pbuf[8]; - (void) sm_snprintf(pbuf, sizeof pbuf, + (void) sm_snprintf(pbuf, sizeof(pbuf), "%u", *ssf); macdefine(&BlankEnvelope.e_macro, A_TEMP, @@ -1386,7 +1492,7 @@ smtp(nullserver, d_flags, e) cmd = cmdbuf; while (*p != '\0' && !(isascii(*p) && isspace(*p)) && - cmd < &cmdbuf[sizeof cmdbuf - 2]) + cmd < &cmdbuf[sizeof(cmdbuf) - 2]) *cmd++ = *p++; *cmd = '\0'; @@ -1801,7 +1907,7 @@ smtp(nullserver, d_flags, e) macvalue(macid("{verify}"), e), "STARTTLS", e, RSF_RMCOMM|RSF_COUNT, - 5, NULL, NOQID) != EX_OK || + 5, NULL, NOQID, NULL) != EX_OK || Errors > 0) { extern char MsgBuf[]; @@ -1992,15 +2098,6 @@ smtp(nullserver, d_flags, e) response = milter_helo(p, e, &state); switch (state) { - case SMFIR_REPLYCODE: - if (MilterLogLevel > 3) - sm_syslog(LOG_INFO, e->e_id, - "Milter: helo=%s, reject=%s", - p, response); - nullserver = newstr(response); - smtp.sm_milterize = false; - break; - case SMFIR_REJECT: if (MilterLogLevel > 3) sm_syslog(LOG_INFO, e->e_id, @@ -2019,17 +2116,36 @@ smtp(nullserver, d_flags, e) smtp.sm_milterize = false; break; - case SMFIR_SHUTDOWN: + case SMFIR_REPLYCODE: if (MilterLogLevel > 3) sm_syslog(LOG_INFO, e->e_id, + "Milter: helo=%s, reject=%s", + p, response); + if (strncmp(response, "421 ", 4) != 0 + && strncmp(response, "421-", 4) != 0) + { + nullserver = newstr(response); + smtp.sm_milterize = false; + break; + } + /* FALLTHROUGH */ + + case SMFIR_SHUTDOWN: + if (MilterLogLevel > 3 && + response == NULL) + sm_syslog(LOG_INFO, e->e_id, "Milter: helo=%s, reject=421 4.7.0 %s closing connection", p, MyHostName); tempfail = true; smtp.sm_milterize = false; - message("421 4.7.0 %s closing connection", - MyHostName); + if (response != NULL) + usrerr(response); + else + message("421 4.7.0 %s closing connection", + MyHostName); /* arrange to ignore send list */ e->e_sendqueue = NULL; + lognullconnection = false; goto doquit; } if (response != NULL) @@ -2258,59 +2374,13 @@ smtp(nullserver, d_flags, e) } /* reset to default value */ - SevenBitInput = save_sevenbitinput; + SevenBitInput = SevenBitInput_Saved; /* now parse ESMTP arguments */ e->e_msgsize = 0; addr = p; - argno = 0; - args[argno++] = p; - p = delimptr; - while (p != NULL && *p != '\0') - { - char *kp; - char *vp = NULL; - char *equal = NULL; - - /* locate the beginning of the keyword */ - SKIP_SPACE(p); - if (*p == '\0') - break; - kp = p; - - /* skip to the value portion */ - while ((isascii(*p) && isalnum(*p)) || *p == '-') - p++; - if (*p == '=') - { - equal = p; - *p++ = '\0'; - vp = p; - - /* skip to the end of the value */ - while (*p != '\0' && *p != ' ' && - !(isascii(*p) && iscntrl(*p)) && - *p != '=') - p++; - } - - if (*p != '\0') - *p++ = '\0'; - - if (tTd(19, 1)) - sm_dprintf("MAIL: got arg %s=\"%s\"\n", kp, - vp == NULL ? "<null>" : vp); - - mail_esmtp_args(kp, vp, e, features); - if (equal != NULL) - *equal = '='; - args[argno++] = kp; - if (argno >= MAXSMTPARGS - 1) - usrerr("501 5.5.4 Too many parameters"); - if (Errors > 0) - sm_exc_raisenew_x(&EtypeQuickAbort, 1); - } - args[argno] = NULL; + parse_esmtp_args(e, NULL, p, delimptr, "MAIL", args, + mail_esmtp_args); if (Errors > 0) sm_exc_raisenew_x(&EtypeQuickAbort, 1); @@ -2344,7 +2414,7 @@ smtp(nullserver, d_flags, e) #endif /* _FFR_MAIL_MACRO */ if (rscheck("check_mail", addr, NULL, e, RSF_RMCOMM|RSF_COUNT, 3, - NULL, e->e_id) != EX_OK || + NULL, e->e_id, NULL) != EX_OK || Errors > 0) sm_exc_raisenew_x(&EtypeQuickAbort, 1); macdefine(&e->e_macro, A_PERM, @@ -2423,6 +2493,17 @@ smtp(nullserver, d_flags, e) case CMDRCPT: /* rcpt -- designate recipient */ DELAY_CONN("RCPT"); + macdefine(&e->e_macro, A_PERM, + macid("{rcpt_mailer}"), NULL); + macdefine(&e->e_macro, A_PERM, + macid("{rcpt_host}"), NULL); + macdefine(&e->e_macro, A_PERM, + macid("{rcpt_addr}"), NULL); +#if MILTER + (void) memset(&addr_st, '\0', sizeof(addr_st)); + a = NULL; + milter_rcpt_added = false; +#endif if (BadRcptThrottle > 0 && n_badrcpts >= BadRcptThrottle) { @@ -2476,16 +2557,16 @@ smtp(nullserver, d_flags, e) #if MILTER /* - ** If the filter will be deleting recipients, - ** don't expand them at RCPT time (in the call + ** Do not expand recipients at RCPT time (in the call ** to recipient()). If they are expanded, it ** is impossible for removefromlist() to figure ** out the expanded members of the original ** recipient and mark them as QS_DONTSEND. */ - if (milter_can_delrcpts()) - e->e_flags |= EF_VRFYONLY; + e->e_flags |= EF_VRFYONLY; + milter_cmd_done = false; + milter_cmd_safe = false; #endif /* MILTER */ p = skipword(p, "to"); @@ -2533,63 +2614,34 @@ smtp(nullserver, d_flags, e) /* now parse ESMTP arguments */ addr = p; - argno = 0; - args[argno++] = p; - p = delimptr; - while (p != NULL && *p != '\0') - { - char *kp; - char *vp = NULL; - char *equal = NULL; - - /* locate the beginning of the keyword */ - SKIP_SPACE(p); - if (*p == '\0') - break; - kp = p; - - /* skip to the value portion */ - while ((isascii(*p) && isalnum(*p)) || *p == '-') - p++; - if (*p == '=') - { - equal = p; - *p++ = '\0'; - vp = p; - - /* skip to the end of the value */ - while (*p != '\0' && *p != ' ' && - !(isascii(*p) && iscntrl(*p)) && - *p != '=') - p++; - } - - if (*p != '\0') - *p++ = '\0'; - - if (tTd(19, 1)) - sm_dprintf("RCPT: got arg %s=\"%s\"\n", kp, - vp == NULL ? "<null>" : vp); - - rcpt_esmtp_args(a, kp, vp, e, features); - if (equal != NULL) - *equal = '='; - args[argno++] = kp; - if (argno >= MAXSMTPARGS - 1) - usrerr("501 5.5.4 Too many parameters"); - if (Errors > 0) - break; - } - args[argno] = NULL; + parse_esmtp_args(e, a, p, delimptr, "RCPT", args, + rcpt_esmtp_args); if (Errors > 0) goto rcpt_done; +#if MILTER + /* + ** rscheck() can trigger an "exception" + ** in which case the execution continues at + ** SM_EXCEPT(exc, "[!F]*") + ** This means milter_cmd_safe is not set + ** and hence milter is not invoked. + ** Would it be "safe" to change that, i.e., use + ** milter_cmd_safe = true; + ** here so a milter is informed (if requested) + ** about RCPTs that are rejected by check_rcpt? + */ +# if _FFR_MILTER_CHECK_REJECTIONS_TOO + milter_cmd_safe = true; +# endif +#endif + /* do config file checking of the recipient */ macdefine(&e->e_macro, A_PERM, macid("{addr_type}"), "e r"); if (rscheck("check_rcpt", addr, NULL, e, RSF_RMCOMM|RSF_COUNT, 3, - NULL, e->e_id) != EX_OK || + NULL, e->e_id, p_addr_st) != EX_OK || Errors > 0) goto rcpt_done; macdefine(&e->e_macro, A_PERM, @@ -2598,38 +2650,74 @@ smtp(nullserver, d_flags, e) /* If discarding, don't bother to verify user */ if (bitset(EF_DISCARD, e->e_flags)) a->q_state = QS_VERIFIED; +#if MILTER + milter_cmd_safe = true; +#endif + + /* save in recipient list after ESMTP mods */ + a = recipient(a, &e->e_sendqueue, 0, e); + /* may trigger exception... */ + +#if MILTER + milter_rcpt_added = true; +#endif + + if(!(Errors > 0) && QS_IS_BADADDR(a->q_state)) + { + /* punt -- should keep message in ADDRESS.... */ + usrerr("550 5.1.1 Addressee unknown"); + } #if MILTER + rcpt_done: if (smtp.sm_milterlist && smtp.sm_milterize && !bitset(EF_DISCARD, e->e_flags)) { char state; char *response; - response = milter_envrcpt(args, e, &state); + /* how to get the error codes? */ + if (Errors > 0) + { + macdefine(&e->e_macro, A_PERM, + macid("{rcpt_mailer}"), + "error"); + if (a != NULL && + a->q_status != NULL && + a->q_rstatus != NULL) + { + macdefine(&e->e_macro, A_PERM, + macid("{rcpt_host}"), + a->q_status); + macdefine(&e->e_macro, A_PERM, + macid("{rcpt_addr}"), + a->q_rstatus); + } + else + { + if (addr_st.q_host != NULL) + macdefine(&e->e_macro, + A_PERM, + macid("{rcpt_host}"), + addr_st.q_host); + if (addr_st.q_user != NULL) + macdefine(&e->e_macro, + A_PERM, + macid("{rcpt_addr}"), + addr_st.q_user); + } + } + + response = milter_envrcpt(args, e, &state, + Errors > 0); + milter_cmd_done = true; MILTER_REPLY("to"); } #endif /* MILTER */ - macdefine(&e->e_macro, A_PERM, - macid("{rcpt_mailer}"), NULL); - macdefine(&e->e_macro, A_PERM, - macid("{rcpt_host}"), NULL); - macdefine(&e->e_macro, A_PERM, - macid("{rcpt_addr}"), NULL); - macdefine(&e->e_macro, A_PERM, - macid("{dsn_notify}"), NULL); - if (Errors > 0) - goto rcpt_done; - - /* save in recipient list after ESMTP mods */ - a = recipient(a, &e->e_sendqueue, 0, e); - if (Errors > 0) - goto rcpt_done; - /* no errors during parsing, but might be a duplicate */ e->e_to = a->q_paddr; - if (!QS_IS_BADADDR(a->q_state)) + if (!(Errors > 0) && !QS_IS_BADADDR(a->q_state)) { if (smtp.sm_nrcpts == 0) initsys(e); @@ -2638,12 +2726,20 @@ smtp(nullserver, d_flags, e) " (will queue)" : ""); smtp.sm_nrcpts++; } - else - { - /* punt -- should keep message in ADDRESS.... */ - usrerr("550 5.1.1 Addressee unknown"); - } - rcpt_done: + + /* Is this needed? */ +#if !MILTER + rcpt_done: +#endif /* !MILTER */ + macdefine(&e->e_macro, A_PERM, + macid("{rcpt_mailer}"), NULL); + macdefine(&e->e_macro, A_PERM, + macid("{rcpt_host}"), NULL); + macdefine(&e->e_macro, A_PERM, + macid("{rcpt_addr}"), NULL); + macdefine(&e->e_macro, A_PERM, + macid("{dsn_notify}"), NULL); + if (Errors > 0) { ++n_badrcpts; @@ -2656,6 +2752,55 @@ smtp(nullserver, d_flags, e) e->e_flags &= ~(EF_FATALERRS|EF_PM_NOTIFY); ++n_badrcpts; NBADRCPTS; +#if MILTER + if (smtp.sm_milterlist && smtp.sm_milterize && + !bitset(EF_DISCARD, e->e_flags) && + !milter_cmd_done && milter_cmd_safe) + { + char state; + char *response; + + macdefine(&e->e_macro, A_PERM, + macid("{rcpt_mailer}"), "error"); + + /* how to get the error codes? */ + if (addr_st.q_host != NULL) + macdefine(&e->e_macro, A_PERM, + macid("{rcpt_host}"), + addr_st.q_host); + else if (a != NULL && a->q_status != NULL) + macdefine(&e->e_macro, A_PERM, + macid("{rcpt_host}"), + a->q_status); + + if (addr_st.q_user != NULL) + macdefine(&e->e_macro, A_PERM, + macid("{rcpt_addr}"), + addr_st.q_user); + else if (a != NULL && a->q_rstatus != NULL) + macdefine(&e->e_macro, A_PERM, + macid("{rcpt_addr}"), + a->q_rstatus); + + response = milter_envrcpt(args, e, &state, + true); + milter_cmd_done = true; + MILTER_REPLY("to"); + macdefine(&e->e_macro, A_PERM, + macid("{rcpt_mailer}"), NULL); + macdefine(&e->e_macro, A_PERM, + macid("{rcpt_host}"), NULL); + macdefine(&e->e_macro, A_PERM, + macid("{rcpt_addr}"), NULL); + } + if (smtp.sm_milterlist && smtp.sm_milterize && + milter_rcpt_added && milter_cmd_done && + milter_cmd_fail) + { + (void) removefromlist(addr, &e->e_sendqueue, e); + milter_cmd_fail = false; + } +#endif /* MILTER */ } SM_END_TRY break; @@ -2738,7 +2883,7 @@ smtp(nullserver, d_flags, e) /* do config file checking of the address */ if (rscheck(vrfy ? "check_vrfy" : "check_expn", p, NULL, e, RSF_RMCOMM, - 3, NULL, NOQID) != EX_OK || + 3, NULL, NOQID, NULL) != EX_OK || Errors > 0) sm_exc_raisenew_x(&EtypeQuickAbort, 1); (void) sendtolist(p, NULLADDR, &vrfyqueue, 0, e); @@ -2834,7 +2979,8 @@ smtp(nullserver, d_flags, e) */ if (rscheck("check_etrn", p, NULL, e, - RSF_RMCOMM, 3, NULL, NOQID) != EX_OK || + RSF_RMCOMM, 3, NULL, NOQID, NULL) + != EX_OK || Errors > 0) break; @@ -2997,7 +3143,7 @@ doquit: break; case CMDDBGDEBUG: /* set debug mode */ - tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); + tTsetup(tTdvect, sizeof(tTdvect), "0-99.1"); tTflag(p); message("200 2.0.0 Debug set"); break; @@ -3106,12 +3252,13 @@ smtp_data(smtp, e) #endif /* MILTER */ bool aborting; bool doublequeue; + bool rv = true; ADDRESS *a; ENVELOPE *ee; char *id; char *oldid; + unsigned int features; char buf[32]; - bool rv = true; SmtpPhase = "server DATA"; if (!smtp->sm_gotmail) @@ -3124,10 +3271,10 @@ smtp_data(smtp, e) usrerr("503 5.0.0 Need RCPT (recipient)"); return true; } - (void) sm_snprintf(buf, sizeof buf, "%u", smtp->sm_nrcpts); + (void) sm_snprintf(buf, sizeof(buf), "%u", smtp->sm_nrcpts); if (rscheck("check_data", buf, NULL, e, RSF_RMCOMM|RSF_UNSTRUCTURED|RSF_COUNT, 3, NULL, - e->e_id) != EX_OK) + e->e_id, NULL) != EX_OK) return true; #if MILTER && SMFI_VERSION > 3 @@ -3233,14 +3380,12 @@ smtp_data(smtp, e) collect(InChannel, true, NULL, e, true); /* redefine message size */ - (void) sm_snprintf(buf, sizeof buf, "%ld", e->e_msgsize); + (void) sm_snprintf(buf, sizeof(buf), "%ld", e->e_msgsize); macdefine(&e->e_macro, A_TEMP, macid("{msg_size}"), buf); -#if _FFR_CHECK_EOM /* rscheck() will set Errors or EF_DISCARD if it trips */ (void) rscheck("check_eom", buf, NULL, e, RSF_UNSTRUCTURED|RSF_COUNT, - 3, NULL, e->e_id); -#endif /* _FFR_CHECK_EOM */ + 3, NULL, e->e_id, NULL); #if MILTER milteraccept = true; @@ -3303,7 +3448,7 @@ smtp_data(smtp, e) } /* Milter may have changed message size */ - (void) sm_snprintf(buf, sizeof buf, "%ld", e->e_msgsize); + (void) sm_snprintf(buf, sizeof(buf), "%ld", e->e_msgsize); macdefine(&e->e_macro, A_TEMP, macid("{msg_size}"), buf); /* abort message filters that didn't get the body & log msg is OK */ @@ -3509,7 +3654,7 @@ smtp_data(smtp, e) { char msg[MAXLINE]; - expand(MessageAccept, msg, sizeof msg, e); + expand(MessageAccept, msg, sizeof(msg), e); message("250 2.0.0 %s", msg); } else @@ -3603,8 +3748,10 @@ smtp_data(smtp, e) */ CurEnv = e; + features = e->e_features; newenvelope(e, e, sm_rpool_new_x(NULL)); e->e_flags = BlankEnvelope.e_flags; + e->e_features = features; /* restore connection quarantining */ if (smtp->sm_quarmsg == NULL) @@ -3855,24 +4002,68 @@ skipword(p, w) } /* +** RESET_MAIL_ESMTP_ARGS -- process ESMTP arguments from MAIL line +** +** Parameters: +** e -- the envelope. +** +** Returns: +** none. +*/ + +void +reset_mail_esmtp_args(e) + ENVELOPE *e; +{ + /* "size": no reset */ + + /* "body" */ + SevenBitInput = SevenBitInput_Saved; + e->e_bodytype = NULL; + + /* "envid" */ + e->e_envid = NULL; + macdefine(&e->e_macro, A_PERM, macid("{dsn_envid}"), NULL); + + /* "ret" */ + e->e_flags &= EF_RET_PARAM; + e->e_flags &= EF_NO_BODY_RETN; + macdefine(&e->e_macro, A_TEMP, macid("{dsn_ret}"), NULL); + +#if SASL + /* "auth" */ + macdefine(&e->e_macro, A_TEMP, macid("{auth_author}"), NULL); + e->e_auth_param = ""; +# if _FFR_AUTH_PASSING + macdefine(&BlankEnvelope.e_macro, A_PERM, + macid("{auth_author}"), NULL); +# endif /* _FFR_AUTH_PASSING */ +#endif /* SASL */ + + /* "by" */ + e->e_deliver_by = 0; + e->e_dlvr_flag = 0; +} + +/* ** MAIL_ESMTP_ARGS -- process ESMTP arguments from MAIL line ** ** Parameters: +** a -- address (unused, for compatibility with rcpt_esmtp_args) ** kp -- the parameter key. ** vp -- the value of that parameter. ** e -- the envelope. -** features -- current server features ** ** Returns: ** none. */ -static void -mail_esmtp_args(kp, vp, e, features) +void +mail_esmtp_args(a, kp, vp, e) + ADDRESS *a; char *kp; char *vp; ENVELOPE *e; - unsigned int features; { if (sm_strcasecmp(kp, "size") == 0) { @@ -3919,7 +4110,7 @@ mail_esmtp_args(kp, vp, e, features) } else if (sm_strcasecmp(kp, "envid") == 0) { - if (!bitset(SRV_OFFER_DSN, features)) + if (!bitset(SRV_OFFER_DSN, e->e_features)) { usrerr("504 5.7.0 Sorry, ENVID not supported, we do not allow DSN"); /* NOTREACHED */ @@ -3945,7 +4136,7 @@ mail_esmtp_args(kp, vp, e, features) } else if (sm_strcasecmp(kp, "ret") == 0) { - if (!bitset(SRV_OFFER_DSN, features)) + if (!bitset(SRV_OFFER_DSN, e->e_features)) { usrerr("504 5.7.0 Sorry, RET not supported, we do not allow DSN"); /* NOTREACHED */ @@ -4018,7 +4209,7 @@ mail_esmtp_args(kp, vp, e, features) QuickAbort = false; if (strcmp(auth_param, "<>") != 0 && (rscheck("trust_auth", auth_param, NULL, e, RSF_RMCOMM, - 9, NULL, NOQID) != EX_OK || Errors > 0)) + 9, NULL, NOQID, NULL) != EX_OK || Errors > 0)) { if (tTd(95, 8)) { @@ -4130,6 +4321,7 @@ mail_esmtp_args(kp, vp, e, features) /* NOTREACHED */ } } + /* ** RCPT_ESMTP_ARGS -- process ESMTP arguments from RCPT line ** @@ -4138,25 +4330,23 @@ mail_esmtp_args(kp, vp, e, features) ** kp -- the parameter key. ** vp -- the value of that parameter. ** e -- the envelope. -** features -- current server features ** ** Returns: ** none. */ -static void -rcpt_esmtp_args(a, kp, vp, e, features) +void +rcpt_esmtp_args(a, kp, vp, e) ADDRESS *a; char *kp; char *vp; ENVELOPE *e; - unsigned int features; { if (sm_strcasecmp(kp, "notify") == 0) { char *p; - if (!bitset(SRV_OFFER_DSN, features)) + if (!bitset(SRV_OFFER_DSN, e->e_features)) { usrerr("504 5.7.0 Sorry, NOTIFY not supported, we do not allow DSN"); /* NOTREACHED */ @@ -4197,7 +4387,7 @@ rcpt_esmtp_args(a, kp, vp, e, features) } else if (sm_strcasecmp(kp, "orcpt") == 0) { - if (!bitset(SRV_OFFER_DSN, features)) + if (!bitset(SRV_OFFER_DSN, e->e_features)) { usrerr("504 5.7.0 Sorry, ORCPT not supported, we do not allow DSN"); /* NOTREACHED */ @@ -4251,11 +4441,11 @@ printvrfyaddr(a, last, vrfy) if (vrfy && a->q_mailer != NULL && !bitnset(M_VRFY250, a->q_mailer->m_flags)) - (void) sm_strlcpy(fmtbuf, "252", sizeof fmtbuf); + (void) sm_strlcpy(fmtbuf, "252", sizeof(fmtbuf)); else - (void) sm_strlcpy(fmtbuf, "250", sizeof fmtbuf); + (void) sm_strlcpy(fmtbuf, "250", sizeof(fmtbuf)); fmtbuf[3] = last ? ' ' : '-'; - (void) sm_strlcpy(&fmtbuf[4], "2.1.5 ", sizeof fmtbuf - 4); + (void) sm_strlcpy(&fmtbuf[4], "2.1.5 ", sizeof(fmtbuf) - 4); if (a->q_fullname == NULL) { if ((a->q_mailer == NULL || @@ -4263,10 +4453,10 @@ printvrfyaddr(a, last, vrfy) sm_strcasecmp(a->q_mailer->m_addrtype, "rfc822") == 0) && strchr(a->q_user, '@') == NULL) (void) sm_strlcpy(&fmtbuf[OFFF], "<%s@%s>", - sizeof fmtbuf - OFFF); + sizeof(fmtbuf) - OFFF); else (void) sm_strlcpy(&fmtbuf[OFFF], "<%s>", - sizeof fmtbuf - OFFF); + sizeof(fmtbuf) - OFFF); message(fmtbuf, a->q_user, MyHostName); } else @@ -4276,10 +4466,10 @@ printvrfyaddr(a, last, vrfy) sm_strcasecmp(a->q_mailer->m_addrtype, "rfc822") == 0) && strchr(a->q_user, '@') == NULL) (void) sm_strlcpy(&fmtbuf[OFFF], "%s <%s@%s>", - sizeof fmtbuf - OFFF); + sizeof(fmtbuf) - OFFF); else (void) sm_strlcpy(&fmtbuf[OFFF], "%s <%s>", - sizeof fmtbuf - OFFF); + sizeof(fmtbuf) - OFFF); message(fmtbuf, a->q_fullname, a->q_user, MyHostName); } } @@ -4600,7 +4790,7 @@ help(topic, e) len = strlen(topic); - while (sm_io_fgets(hf, SM_TIME_DEFAULT, buf, sizeof buf) != NULL) + while (sm_io_fgets(hf, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL) { if (buf[0] == '#') { @@ -4633,8 +4823,13 @@ help(topic, e) fixcrlf(p, true); if (foundvers >= 2) { - translate_dollars(p); - expand(p, inp, sizeof inp, e); + char *lbp; + int lbs = sizeof(buf) - (p - buf); + + lbp = translate_dollars(p, p, &lbs); + expand(lbp, inp, sizeof(inp), e); + if (p != lbp) + sm_free(lbp); p = inp; } message("214-2.0.0 %s", p); |