138032Speter/* 2261370Sgshapiro * Copyright (c) 1998-2010, 2012, 2013 Proofpoint, Inc. and its suppliers. 364562Sgshapiro * All rights reserved. 438032Speter * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 538032Speter * Copyright (c) 1988, 1993 638032Speter * The Regents of the University of California. All rights reserved. 738032Speter * 838032Speter * By using this file, you agree to the terms and conditions set 938032Speter * forth in the LICENSE file which can be found at the top level of 1038032Speter * the sendmail distribution. 1138032Speter * 1238032Speter */ 1338032Speter 1464562Sgshapiro#include <sendmail.h> 1590792Sgshapiro#if MILTER 16132943Sgshapiro# include <libmilter/mfapi.h> 1790792Sgshapiro# include <libmilter/mfdef.h> 1890792Sgshapiro#endif /* MILTER */ 1964562Sgshapiro 20266711SgshapiroSM_RCSID("@(#)$Id: srvrsmtp.c,v 8.1016 2013-11-22 20:51:56 ca Exp $") 2164562Sgshapiro 22157001Sgshapiro#include <sm/time.h> 23132943Sgshapiro#include <sm/fdset.h> 24132943Sgshapiro 2590792Sgshapiro#if SASL || STARTTLS 2690792Sgshapiro# include "sfsasl.h" 2790792Sgshapiro#endif /* SASL || STARTTLS */ 2890792Sgshapiro#if SASL 2990792Sgshapiro# define ENC64LEN(l) (((l) + 2) * 4 / 3 + 1) 3064562Sgshapirostatic int saslmechs __P((sasl_conn_t *, char **)); 3190792Sgshapiro#endif /* SASL */ 3290792Sgshapiro#if STARTTLS 33244928Sgshapiro# include <openssl/err.h> 3490792Sgshapiro# include <sysexits.h> 3538032Speter 3690792Sgshapirostatic SSL_CTX *srv_ctx = NULL; /* TLS server context */ 3790792Sgshapirostatic SSL *srv_ssl = NULL; /* per connection context */ 3838032Speter 3990792Sgshapirostatic bool tls_ok_srv = false; 4090792Sgshapiro 4190792Sgshapiro# define TLS_VERIFY_CLIENT() tls_set_verify(srv_ctx, srv_ssl, \ 4290792Sgshapiro bitset(SRV_VRFY_CLT, features)) 4390792Sgshapiro#endif /* STARTTLS */ 4490792Sgshapiro 45168515Sgshapiro#if _FFR_DM_ONE 46168515Sgshapirostatic bool NotFirstDelivery = false; 47168515Sgshapiro#endif /* _FFR_DM_ONE */ 48168515Sgshapiro 4990792Sgshapiro/* server features */ 5090792Sgshapiro#define SRV_NONE 0x0000 /* none... */ 5190792Sgshapiro#define SRV_OFFER_TLS 0x0001 /* offer STARTTLS */ 5290792Sgshapiro#define SRV_VRFY_CLT 0x0002 /* request a cert */ 5390792Sgshapiro#define SRV_OFFER_AUTH 0x0004 /* offer AUTH */ 5490792Sgshapiro#define SRV_OFFER_ETRN 0x0008 /* offer ETRN */ 5590792Sgshapiro#define SRV_OFFER_VRFY 0x0010 /* offer VRFY (not yet used) */ 5690792Sgshapiro#define SRV_OFFER_EXPN 0x0020 /* offer EXPN */ 5790792Sgshapiro#define SRV_OFFER_VERB 0x0040 /* offer VERB */ 5890792Sgshapiro#define SRV_OFFER_DSN 0x0080 /* offer DSN */ 5990792Sgshapiro#if PIPELINING 6090792Sgshapiro# define SRV_OFFER_PIPE 0x0100 /* offer PIPELINING */ 6190792Sgshapiro# if _FFR_NO_PIPE 6290792Sgshapiro# define SRV_NO_PIPE 0x0200 /* disable PIPELINING, sleep if used */ 6390792Sgshapiro# endif /* _FFR_NO_PIPE */ 6490792Sgshapiro#endif /* PIPELINING */ 6590792Sgshapiro#define SRV_REQ_AUTH 0x0400 /* require AUTH */ 66132943Sgshapiro#define SRV_REQ_SEC 0x0800 /* require security - equiv to AuthOptions=p */ 6790792Sgshapiro#define SRV_TMP_FAIL 0x1000 /* ruleset caused a temporary failure */ 6890792Sgshapiro 6990792Sgshapirostatic unsigned int srvfeatures __P((ENVELOPE *, char *, unsigned int)); 7090792Sgshapiro 71132943Sgshapiro#define STOP_ATTACK ((time_t) -1) 72132943Sgshapirostatic time_t checksmtpattack __P((volatile unsigned int *, unsigned int, 73132943Sgshapiro bool, char *, ENVELOPE *)); 7464562Sgshapirostatic void printvrfyaddr __P((ADDRESS *, bool, bool)); 7564562Sgshapirostatic char *skipword __P((char *volatile, char *)); 7690792Sgshapirostatic void setup_smtpd_io __P((void)); 77120256Sgshapiro 78120256Sgshapiro#if SASL 79120256Sgshapiro# if SASL >= 20000 80120256Sgshapirostatic int reset_saslconn __P((sasl_conn_t **_conn, char *_hostname, 81120256Sgshapiro char *_remoteip, char *_localip, 82120256Sgshapiro char *_auth_id, sasl_ssf_t *_ext_ssf)); 83120256Sgshapiro 84120256Sgshapiro# define RESET_SASLCONN \ 85147078Sgshapiro do \ 86147078Sgshapiro { \ 87147078Sgshapiro result = reset_saslconn(&conn, AuthRealm, remoteip, \ 88147078Sgshapiro localip, auth_id, &ext_ssf); \ 89147078Sgshapiro if (result != SASL_OK) \ 90147078Sgshapiro sasl_ok = false; \ 91147078Sgshapiro } while (0) 92120256Sgshapiro 93120256Sgshapiro# else /* SASL >= 20000 */ 94120256Sgshapirostatic int reset_saslconn __P((sasl_conn_t **_conn, char *_hostname, 95120256Sgshapiro struct sockaddr_in *_saddr_r, 96120256Sgshapiro struct sockaddr_in *_saddr_l, 97120256Sgshapiro sasl_external_properties_t *_ext_ssf)); 98120256Sgshapiro# define RESET_SASLCONN \ 99147078Sgshapiro do \ 100147078Sgshapiro { \ 101147078Sgshapiro result = reset_saslconn(&conn, AuthRealm, &saddr_r, \ 102147078Sgshapiro &saddr_l, &ext_ssf); \ 103147078Sgshapiro if (result != SASL_OK) \ 104147078Sgshapiro sasl_ok = false; \ 105147078Sgshapiro } while (0) 106120256Sgshapiro 107120256Sgshapiro# endif /* SASL >= 20000 */ 108120256Sgshapiro#endif /* SASL */ 109120256Sgshapiro 11064562Sgshapiroextern ENVELOPE BlankEnvelope; 11138032Speter 112132943Sgshapiro#define NBADRCPTS \ 113132943Sgshapiro do \ 114132943Sgshapiro { \ 115132943Sgshapiro char buf[16]; \ 116168515Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "%d", \ 117132943Sgshapiro BadRcptThrottle > 0 && n_badrcpts > BadRcptThrottle \ 118132943Sgshapiro ? n_badrcpts - 1 : n_badrcpts); \ 119132943Sgshapiro macdefine(&e->e_macro, A_TEMP, macid("{nbadrcpts}"), buf); \ 120132943Sgshapiro } while (0) 121132943Sgshapiro 12290792Sgshapiro#define SKIP_SPACE(s) while (isascii(*s) && isspace(*s)) \ 12390792Sgshapiro (s)++ 12490792Sgshapiro 12538032Speter/* 126168515Sgshapiro** PARSE_ESMTP_ARGS -- parse EMSTP arguments (for MAIL, RCPT) 127168515Sgshapiro** 128168515Sgshapiro** Parameters: 129168515Sgshapiro** e -- the envelope 130168515Sgshapiro** addr_st -- address (RCPT only) 131168515Sgshapiro** p -- read buffer 132168515Sgshapiro** delimptr -- current position in read buffer 133168515Sgshapiro** which -- MAIL/RCPT 134168515Sgshapiro** args -- arguments (output) 135168515Sgshapiro** esmtp_args -- function to process a single ESMTP argument 136168515Sgshapiro** 137168515Sgshapiro** Returns: 138168515Sgshapiro** none 139168515Sgshapiro*/ 140168515Sgshapiro 141168515Sgshapirovoid 142168515Sgshapiroparse_esmtp_args(e, addr_st, p, delimptr, which, args, esmtp_args) 143168515Sgshapiro ENVELOPE *e; 144168515Sgshapiro ADDRESS *addr_st; 145168515Sgshapiro char *p; 146168515Sgshapiro char *delimptr; 147168515Sgshapiro char *which; 148168515Sgshapiro char *args[]; 149168515Sgshapiro esmtp_args_F esmtp_args; 150168515Sgshapiro{ 151168515Sgshapiro int argno; 152168515Sgshapiro 153168515Sgshapiro argno = 0; 154168515Sgshapiro if (args != NULL) 155168515Sgshapiro args[argno++] = p; 156168515Sgshapiro p = delimptr; 157168515Sgshapiro while (p != NULL && *p != '\0') 158168515Sgshapiro { 159168515Sgshapiro char *kp; 160168515Sgshapiro char *vp = NULL; 161168515Sgshapiro char *equal = NULL; 162168515Sgshapiro 163168515Sgshapiro /* locate the beginning of the keyword */ 164168515Sgshapiro SKIP_SPACE(p); 165168515Sgshapiro if (*p == '\0') 166168515Sgshapiro break; 167168515Sgshapiro kp = p; 168168515Sgshapiro 169168515Sgshapiro /* skip to the value portion */ 170168515Sgshapiro while ((isascii(*p) && isalnum(*p)) || *p == '-') 171168515Sgshapiro p++; 172168515Sgshapiro if (*p == '=') 173168515Sgshapiro { 174168515Sgshapiro equal = p; 175168515Sgshapiro *p++ = '\0'; 176168515Sgshapiro vp = p; 177168515Sgshapiro 178168515Sgshapiro /* skip to the end of the value */ 179168515Sgshapiro while (*p != '\0' && *p != ' ' && 180168515Sgshapiro !(isascii(*p) && iscntrl(*p)) && 181168515Sgshapiro *p != '=') 182168515Sgshapiro p++; 183168515Sgshapiro } 184168515Sgshapiro 185168515Sgshapiro if (*p != '\0') 186168515Sgshapiro *p++ = '\0'; 187168515Sgshapiro 188168515Sgshapiro if (tTd(19, 1)) 189168515Sgshapiro sm_dprintf("%s: got arg %s=\"%s\"\n", which, kp, 190168515Sgshapiro vp == NULL ? "<null>" : vp); 191168515Sgshapiro 192168515Sgshapiro esmtp_args(addr_st, kp, vp, e); 193168515Sgshapiro if (equal != NULL) 194168515Sgshapiro *equal = '='; 195168515Sgshapiro if (args != NULL) 196168515Sgshapiro args[argno] = kp; 197168515Sgshapiro argno++; 198168515Sgshapiro if (argno >= MAXSMTPARGS - 1) 199168515Sgshapiro usrerr("501 5.5.4 Too many parameters"); 200168515Sgshapiro if (Errors > 0) 201168515Sgshapiro break; 202168515Sgshapiro } 203168515Sgshapiro if (args != NULL) 204168515Sgshapiro args[argno] = NULL; 205168515Sgshapiro} 206168515Sgshapiro 207168515Sgshapiro/* 20838032Speter** SMTP -- run the SMTP protocol. 20938032Speter** 21038032Speter** Parameters: 21138032Speter** nullserver -- if non-NULL, rejection message for 21290792Sgshapiro** (almost) all SMTP commands. 21390792Sgshapiro** d_flags -- daemon flags 21438032Speter** e -- the envelope. 21538032Speter** 21638032Speter** Returns: 21738032Speter** never. 21838032Speter** 21938032Speter** Side Effects: 22090792Sgshapiro** Reads commands from the input channel and processes them. 22138032Speter*/ 22238032Speter 22390792Sgshapiro/* 22490792Sgshapiro** Notice: The smtp server doesn't have a session context like the client 22590792Sgshapiro** side has (mci). Therefore some data (session oriented) is allocated 22690792Sgshapiro** or assigned to the "wrong" structure (esp. STARTTLS, AUTH). 22790792Sgshapiro** This should be fixed in a successor version. 22890792Sgshapiro*/ 22990792Sgshapiro 23038032Speterstruct cmd 23138032Speter{ 23264562Sgshapiro char *cmd_name; /* command name */ 23364562Sgshapiro int cmd_code; /* internal code, see below */ 23438032Speter}; 23538032Speter 23664562Sgshapiro/* values for cmd_code */ 23790792Sgshapiro#define CMDERROR 0 /* bad command */ 23890792Sgshapiro#define CMDMAIL 1 /* mail -- designate sender */ 23990792Sgshapiro#define CMDRCPT 2 /* rcpt -- designate recipient */ 24090792Sgshapiro#define CMDDATA 3 /* data -- send message text */ 24190792Sgshapiro#define CMDRSET 4 /* rset -- reset state */ 24290792Sgshapiro#define CMDVRFY 5 /* vrfy -- verify address */ 24390792Sgshapiro#define CMDEXPN 6 /* expn -- expand address */ 24490792Sgshapiro#define CMDNOOP 7 /* noop -- do nothing */ 24590792Sgshapiro#define CMDQUIT 8 /* quit -- close connection and die */ 24690792Sgshapiro#define CMDHELO 9 /* helo -- be polite */ 24790792Sgshapiro#define CMDHELP 10 /* help -- give usage info */ 24890792Sgshapiro#define CMDEHLO 11 /* ehlo -- extended helo (RFC 1425) */ 24990792Sgshapiro#define CMDETRN 12 /* etrn -- flush queue */ 25090792Sgshapiro#if SASL 25190792Sgshapiro# define CMDAUTH 13 /* auth -- SASL authenticate */ 25290792Sgshapiro#endif /* SASL */ 25390792Sgshapiro#if STARTTLS 25490792Sgshapiro# define CMDSTLS 14 /* STARTTLS -- start TLS session */ 25590792Sgshapiro#endif /* STARTTLS */ 25638032Speter/* non-standard commands */ 25790792Sgshapiro#define CMDVERB 17 /* verb -- go into verbose mode */ 25864562Sgshapiro/* unimplemented commands from RFC 821 */ 25990792Sgshapiro#define CMDUNIMPL 19 /* unimplemented rfc821 commands */ 26038032Speter/* use this to catch and log "door handle" attempts on your system */ 26190792Sgshapiro#define CMDLOGBOGUS 23 /* bogus command that should be logged */ 26238032Speter/* debugging-only commands, only enabled if SMTPDEBUG is defined */ 26390792Sgshapiro#define CMDDBGQSHOW 24 /* showq -- show send queue */ 26490792Sgshapiro#define CMDDBGDEBUG 25 /* debug -- set debug mode */ 26538032Speter 26666494Sgshapiro/* 26790792Sgshapiro** Note: If you change this list, remember to update 'helpfile' 26866494Sgshapiro*/ 26966494Sgshapiro 27038032Speterstatic struct cmd CmdTab[] = 27138032Speter{ 27238032Speter { "mail", CMDMAIL }, 27338032Speter { "rcpt", CMDRCPT }, 27438032Speter { "data", CMDDATA }, 27538032Speter { "rset", CMDRSET }, 27638032Speter { "vrfy", CMDVRFY }, 27738032Speter { "expn", CMDEXPN }, 27838032Speter { "help", CMDHELP }, 27938032Speter { "noop", CMDNOOP }, 28038032Speter { "quit", CMDQUIT }, 28138032Speter { "helo", CMDHELO }, 28238032Speter { "ehlo", CMDEHLO }, 28338032Speter { "etrn", CMDETRN }, 28438032Speter { "verb", CMDVERB }, 28564562Sgshapiro { "send", CMDUNIMPL }, 28664562Sgshapiro { "saml", CMDUNIMPL }, 28764562Sgshapiro { "soml", CMDUNIMPL }, 28864562Sgshapiro { "turn", CMDUNIMPL }, 28990792Sgshapiro#if SASL 29064562Sgshapiro { "auth", CMDAUTH, }, 29190792Sgshapiro#endif /* SASL */ 29290792Sgshapiro#if STARTTLS 29364562Sgshapiro { "starttls", CMDSTLS, }, 29490792Sgshapiro#endif /* STARTTLS */ 29538032Speter /* remaining commands are here only to trap and log attempts to use them */ 29638032Speter { "showq", CMDDBGQSHOW }, 29738032Speter { "debug", CMDDBGDEBUG }, 29838032Speter { "wiz", CMDLOGBOGUS }, 29938032Speter 30038032Speter { NULL, CMDERROR } 30138032Speter}; 30238032Speter 30364562Sgshapirostatic char *CurSmtpClient; /* who's at the other end of channel */ 30438032Speter 30590792Sgshapiro#ifndef MAXBADCOMMANDS 30690792Sgshapiro# define MAXBADCOMMANDS 25 /* maximum number of bad commands */ 30794334Sgshapiro#endif /* ! MAXBADCOMMANDS */ 30890792Sgshapiro#ifndef MAXHELOCOMMANDS 30990792Sgshapiro# define MAXHELOCOMMANDS 3 /* max HELO/EHLO commands before slowdown */ 31094334Sgshapiro#endif /* ! MAXHELOCOMMANDS */ 31190792Sgshapiro#ifndef MAXVRFYCOMMANDS 31290792Sgshapiro# define MAXVRFYCOMMANDS 6 /* max VRFY/EXPN commands before slowdown */ 31394334Sgshapiro#endif /* ! MAXVRFYCOMMANDS */ 31490792Sgshapiro#ifndef MAXETRNCOMMANDS 31590792Sgshapiro# define MAXETRNCOMMANDS 8 /* max ETRN commands before slowdown */ 31694334Sgshapiro#endif /* ! MAXETRNCOMMANDS */ 31790792Sgshapiro#ifndef MAXTIMEOUT 31890792Sgshapiro# define MAXTIMEOUT (4 * 60) /* max timeout for bad commands */ 31994334Sgshapiro#endif /* ! MAXTIMEOUT */ 32038032Speter 321132943Sgshapiro/* 322132943Sgshapiro** Maximum shift value to compute timeout for bad commands. 323132943Sgshapiro** This introduces an upper limit of 2^MAXSHIFT for the timeout. 324132943Sgshapiro*/ 325132943Sgshapiro 326132943Sgshapiro#ifndef MAXSHIFT 327132943Sgshapiro# define MAXSHIFT 8 328132943Sgshapiro#endif /* ! MAXSHIFT */ 329132943Sgshapiro#if MAXSHIFT > 31 330132943Sgshapiro ERROR _MAXSHIFT > 31 is invalid 331132943Sgshapiro#endif /* MAXSHIFT */ 332132943Sgshapiro 333132943Sgshapiro 334132943Sgshapiro#if MAXBADCOMMANDS > 0 335132943Sgshapiro# define STOP_IF_ATTACK(r) do \ 336132943Sgshapiro { \ 337132943Sgshapiro if ((r) == STOP_ATTACK) \ 338132943Sgshapiro goto stopattack; \ 339132943Sgshapiro } while (0) 340132943Sgshapiro 341132943Sgshapiro#else /* MAXBADCOMMANDS > 0 */ 342132943Sgshapiro# define STOP_IF_ATTACK(r) r 343132943Sgshapiro#endif /* MAXBADCOMMANDS > 0 */ 344132943Sgshapiro 345132943Sgshapiro 34690792Sgshapiro#if SM_HEAP_CHECK 34790792Sgshapirostatic SM_DEBUG_T DebugLeakSmtp = SM_DEBUG_INITIALIZER("leak_smtp", 34890792Sgshapiro "@(#)$Debug: leak_smtp - trace memory leaks during SMTP processing $"); 34990792Sgshapiro#endif /* SM_HEAP_CHECK */ 35038032Speter 35190792Sgshapirotypedef struct 35290792Sgshapiro{ 353173340Sgshapiro bool sm_gotmail; /* mail command received */ 354173340Sgshapiro unsigned int sm_nrcpts; /* number of successful RCPT commands */ 355173340Sgshapiro bool sm_discard; 35690792Sgshapiro#if MILTER 357173340Sgshapiro bool sm_milterize; 358173340Sgshapiro bool sm_milterlist; /* any filters in the list? */ 359173340Sgshapiro milters_T sm_milters; 360173340Sgshapiro 361173340Sgshapiro /* e_nrcpts from envelope before recipient() call */ 362173340Sgshapiro unsigned int sm_e_nrcpts_orig; 36390792Sgshapiro#endif /* MILTER */ 364173340Sgshapiro char *sm_quarmsg; /* carry quarantining across messages */ 36590792Sgshapiro} SMTP_T; 36690792Sgshapiro 367132943Sgshapirostatic bool smtp_data __P((SMTP_T *, ENVELOPE *)); 36890792Sgshapiro 369132943Sgshapiro#define MSG_TEMPFAIL "451 4.3.2 Please try again later" 37090792Sgshapiro 37190792Sgshapiro#if MILTER 37290792Sgshapiro# define MILTER_ABORT(e) milter_abort((e)) 373110560Sgshapiro 37490792Sgshapiro# define MILTER_REPLY(str) \ 37590792Sgshapiro { \ 37690792Sgshapiro int savelogusrerrs = LogUsrErrs; \ 37790792Sgshapiro \ 378168515Sgshapiro milter_cmd_fail = true; \ 37990792Sgshapiro switch (state) \ 38090792Sgshapiro { \ 381157001Sgshapiro case SMFIR_SHUTDOWN: \ 382157001Sgshapiro if (MilterLogLevel > 3) \ 383157001Sgshapiro { \ 384157001Sgshapiro sm_syslog(LOG_INFO, e->e_id, \ 385157001Sgshapiro "Milter: %s=%s, reject=421, errormode=4", \ 386157001Sgshapiro str, addr); \ 387157001Sgshapiro LogUsrErrs = false; \ 388157001Sgshapiro } \ 389157001Sgshapiro { \ 390157001Sgshapiro bool tsave = QuickAbort; \ 391157001Sgshapiro \ 392157001Sgshapiro QuickAbort = false; \ 393157001Sgshapiro usrerr("421 4.3.0 closing connection"); \ 394157001Sgshapiro QuickAbort = tsave; \ 395157001Sgshapiro e->e_sendqueue = NULL; \ 396157001Sgshapiro goto doquit; \ 397157001Sgshapiro } \ 398157001Sgshapiro break; \ 39990792Sgshapiro case SMFIR_REPLYCODE: \ 40090792Sgshapiro if (MilterLogLevel > 3) \ 40190792Sgshapiro { \ 40290792Sgshapiro sm_syslog(LOG_INFO, e->e_id, \ 40390792Sgshapiro "Milter: %s=%s, reject=%s", \ 40490792Sgshapiro str, addr, response); \ 40590792Sgshapiro LogUsrErrs = false; \ 40690792Sgshapiro } \ 407157001Sgshapiro if (strncmp(response, "421 ", 4) == 0 \ 408157001Sgshapiro || strncmp(response, "421-", 4) == 0) \ 409132943Sgshapiro { \ 410132943Sgshapiro bool tsave = QuickAbort; \ 411132943Sgshapiro \ 412132943Sgshapiro QuickAbort = false; \ 413132943Sgshapiro usrerr(response); \ 414132943Sgshapiro QuickAbort = tsave; \ 415132943Sgshapiro e->e_sendqueue = NULL; \ 416132943Sgshapiro goto doquit; \ 417132943Sgshapiro } \ 418132943Sgshapiro else \ 419132943Sgshapiro usrerr(response); \ 42090792Sgshapiro break; \ 42190792Sgshapiro \ 42290792Sgshapiro case SMFIR_REJECT: \ 42390792Sgshapiro if (MilterLogLevel > 3) \ 42490792Sgshapiro { \ 42590792Sgshapiro sm_syslog(LOG_INFO, e->e_id, \ 42690792Sgshapiro "Milter: %s=%s, reject=550 5.7.1 Command rejected", \ 42790792Sgshapiro str, addr); \ 42890792Sgshapiro LogUsrErrs = false; \ 42990792Sgshapiro } \ 43090792Sgshapiro usrerr("550 5.7.1 Command rejected"); \ 43190792Sgshapiro break; \ 43290792Sgshapiro \ 43390792Sgshapiro case SMFIR_DISCARD: \ 43490792Sgshapiro if (MilterLogLevel > 3) \ 43590792Sgshapiro sm_syslog(LOG_INFO, e->e_id, \ 43690792Sgshapiro "Milter: %s=%s, discard", \ 43790792Sgshapiro str, addr); \ 43890792Sgshapiro e->e_flags |= EF_DISCARD; \ 439168515Sgshapiro milter_cmd_fail = false; \ 44090792Sgshapiro break; \ 44190792Sgshapiro \ 44290792Sgshapiro case SMFIR_TEMPFAIL: \ 44390792Sgshapiro if (MilterLogLevel > 3) \ 44490792Sgshapiro { \ 44590792Sgshapiro sm_syslog(LOG_INFO, e->e_id, \ 44690792Sgshapiro "Milter: %s=%s, reject=%s", \ 44790792Sgshapiro str, addr, MSG_TEMPFAIL); \ 44890792Sgshapiro LogUsrErrs = false; \ 44990792Sgshapiro } \ 45090792Sgshapiro usrerr(MSG_TEMPFAIL); \ 45190792Sgshapiro break; \ 452168515Sgshapiro default: \ 453168515Sgshapiro milter_cmd_fail = false; \ 454168515Sgshapiro break; \ 45590792Sgshapiro } \ 45690792Sgshapiro LogUsrErrs = savelogusrerrs; \ 45790792Sgshapiro if (response != NULL) \ 45890792Sgshapiro sm_free(response); /* XXX */ \ 45990792Sgshapiro } 46090792Sgshapiro 46190792Sgshapiro#else /* MILTER */ 46290792Sgshapiro# define MILTER_ABORT(e) 46390792Sgshapiro#endif /* MILTER */ 46490792Sgshapiro 46590792Sgshapiro/* clear all SMTP state (for HELO/EHLO/RSET) */ 46690792Sgshapiro#define CLEAR_STATE(cmd) \ 467132943Sgshapirodo \ 46890792Sgshapiro{ \ 46990792Sgshapiro /* abort milter filters */ \ 47090792Sgshapiro MILTER_ABORT(e); \ 47190792Sgshapiro \ 47290792Sgshapiro if (smtp.sm_nrcpts > 0) \ 47390792Sgshapiro { \ 47490792Sgshapiro logundelrcpts(e, cmd, 10, false); \ 47590792Sgshapiro smtp.sm_nrcpts = 0; \ 47690792Sgshapiro macdefine(&e->e_macro, A_PERM, \ 47790792Sgshapiro macid("{nrcpts}"), "0"); \ 47890792Sgshapiro } \ 47990792Sgshapiro \ 48090792Sgshapiro e->e_sendqueue = NULL; \ 48190792Sgshapiro e->e_flags |= EF_CLRQUEUE; \ 48290792Sgshapiro \ 483203004Sgshapiro if (tTd(92, 2)) \ 484203004Sgshapiro sm_dprintf("CLEAR_STATE: e_id=%s, EF_LOGSENDER=%d, LogLevel=%d\n",\ 485203004Sgshapiro e->e_id, bitset(EF_LOGSENDER, e->e_flags), LogLevel);\ 48690792Sgshapiro if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags)) \ 48790792Sgshapiro logsender(e, NULL); \ 48890792Sgshapiro e->e_flags &= ~EF_LOGSENDER; \ 48990792Sgshapiro \ 49090792Sgshapiro /* clean up a bit */ \ 49190792Sgshapiro smtp.sm_gotmail = false; \ 49290792Sgshapiro SuprErrs = true; \ 493203004Sgshapiro (void) dropenvelope(e, true, false); \ 49490792Sgshapiro sm_rpool_free(e->e_rpool); \ 49590792Sgshapiro e = newenvelope(e, CurEnv, sm_rpool_new_x(NULL)); \ 49690792Sgshapiro CurEnv = e; \ 497168515Sgshapiro e->e_features = features; \ 498132943Sgshapiro \ 499132943Sgshapiro /* put back discard bit */ \ 500132943Sgshapiro if (smtp.sm_discard) \ 501132943Sgshapiro e->e_flags |= EF_DISCARD; \ 502132943Sgshapiro \ 503132943Sgshapiro /* restore connection quarantining */ \ 504132943Sgshapiro if (smtp.sm_quarmsg == NULL) \ 505132943Sgshapiro { \ 506132943Sgshapiro e->e_quarmsg = NULL; \ 507132943Sgshapiro macdefine(&e->e_macro, A_PERM, \ 508132943Sgshapiro macid("{quarantine}"), ""); \ 509132943Sgshapiro } \ 510132943Sgshapiro else \ 511132943Sgshapiro { \ 512132943Sgshapiro e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, \ 513132943Sgshapiro smtp.sm_quarmsg); \ 514132943Sgshapiro macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), \ 515132943Sgshapiro e->e_quarmsg); \ 516132943Sgshapiro } \ 517132943Sgshapiro} while (0) 51890792Sgshapiro 51990792Sgshapiro/* sleep to flatten out connection load */ 52090792Sgshapiro#define MIN_DELAY_LOG 15 /* wait before logging this again */ 52190792Sgshapiro 52290792Sgshapiro/* is it worth setting the process title for 1s? */ 52390792Sgshapiro#define DELAY_CONN(cmd) \ 52490792Sgshapiro if (DelayLA > 0 && (CurrentLA = getla()) >= DelayLA) \ 52590792Sgshapiro { \ 52690792Sgshapiro time_t dnow; \ 52790792Sgshapiro \ 52890792Sgshapiro sm_setproctitle(true, e, \ 52990792Sgshapiro "%s: %s: delaying %s: load average: %d", \ 53090792Sgshapiro qid_printname(e), CurSmtpClient, \ 53190792Sgshapiro cmd, DelayLA); \ 53290792Sgshapiro if (LogLevel > 8 && (dnow = curtime()) > log_delay) \ 53390792Sgshapiro { \ 53490792Sgshapiro sm_syslog(LOG_INFO, e->e_id, \ 53590792Sgshapiro "delaying=%s, load average=%d >= %d", \ 53690792Sgshapiro cmd, CurrentLA, DelayLA); \ 53790792Sgshapiro log_delay = dnow + MIN_DELAY_LOG; \ 53890792Sgshapiro } \ 53990792Sgshapiro (void) sleep(1); \ 54090792Sgshapiro sm_setproctitle(true, e, "%s %s: %.80s", \ 54190792Sgshapiro qid_printname(e), CurSmtpClient, inp); \ 54290792Sgshapiro } 54390792Sgshapiro 544168515Sgshapirostatic bool SevenBitInput_Saved; /* saved version of SevenBitInput */ 54590792Sgshapiro 54638032Spetervoid 54764562Sgshapirosmtp(nullserver, d_flags, e) 54864562Sgshapiro char *volatile nullserver; 54964562Sgshapiro BITMAP256 d_flags; 55038032Speter register ENVELOPE *volatile e; 55138032Speter{ 55238032Speter register char *volatile p; 55364562Sgshapiro register struct cmd *volatile c = NULL; 55438032Speter char *cmd; 55538032Speter auto ADDRESS *vrfyqueue; 55638032Speter ADDRESS *a; 55738032Speter volatile bool gothello; /* helo command received */ 55838032Speter bool vrfy; /* set if this is a vrfy command */ 55938032Speter char *volatile protocol; /* sending protocol */ 56038032Speter char *volatile sendinghost; /* sending hostname */ 56138032Speter char *volatile peerhostname; /* name of SMTP peer or "localhost" */ 56238032Speter auto char *delimptr; 56338032Speter char *id; 56490792Sgshapiro volatile unsigned int n_badcmds = 0; /* count of bad commands */ 56590792Sgshapiro volatile unsigned int n_badrcpts = 0; /* number of rejected RCPT */ 56690792Sgshapiro volatile unsigned int n_verifies = 0; /* count of VRFY/EXPN */ 56790792Sgshapiro volatile unsigned int n_etrn = 0; /* count of ETRN */ 56890792Sgshapiro volatile unsigned int n_noop = 0; /* count of NOOP/VERB/etc */ 56990792Sgshapiro volatile unsigned int n_helo = 0; /* count of HELO/EHLO */ 57038032Speter bool ok; 57190792Sgshapiro volatile bool first; 57290792Sgshapiro volatile bool tempfail = false; 57364562Sgshapiro volatile time_t wt; /* timeout after too many commands */ 57464562Sgshapiro volatile time_t previous; /* time after checksmtpattack() */ 57590792Sgshapiro volatile bool lognullconnection = true; 57638032Speter register char *q; 57790792Sgshapiro SMTP_T smtp; 57864562Sgshapiro char *addr; 57964562Sgshapiro char *greetcode = "220"; 58090792Sgshapiro char *hostname; /* my hostname ($j) */ 58138032Speter QUEUE_CHAR *new; 58264562Sgshapiro char *args[MAXSMTPARGS]; 583168515Sgshapiro char inp[MAXINPLINE]; 584168515Sgshapiro#if MAXINPLINE < MAXLINE 585168515Sgshapiro ERROR _MAXINPLINE must NOT be less than _MAXLINE: MAXINPLINE < MAXLINE 586168515Sgshapiro#endif /* MAXINPLINE < MAXLINE */ 58738032Speter char cmdbuf[MAXLINE]; 58890792Sgshapiro#if SASL 58964562Sgshapiro sasl_conn_t *conn; 59064562Sgshapiro volatile bool sasl_ok; 59190792Sgshapiro volatile unsigned int n_auth = 0; /* count of AUTH commands */ 59264562Sgshapiro bool ismore; 59364562Sgshapiro int result; 59464562Sgshapiro volatile int authenticating; 59564562Sgshapiro char *user; 59698121Sgshapiro char *in, *out2; 59798121Sgshapiro# if SASL >= 20000 598168515Sgshapiro char *auth_id = NULL; 59998121Sgshapiro const char *out; 600102528Sgshapiro sasl_ssf_t ext_ssf; 601120256Sgshapiro char localip[60], remoteip[60]; 60298121Sgshapiro# else /* SASL >= 20000 */ 60398121Sgshapiro char *out; 60464562Sgshapiro const char *errstr; 60598121Sgshapiro sasl_external_properties_t ext_ssf; 606120256Sgshapiro struct sockaddr_in saddr_l; 607120256Sgshapiro struct sockaddr_in saddr_r; 60898121Sgshapiro# endif /* SASL >= 20000 */ 60998121Sgshapiro sasl_security_properties_t ssp; 61098121Sgshapiro sasl_ssf_t *ssf; 61190792Sgshapiro unsigned int inlen, out2len; 61264562Sgshapiro unsigned int outlen; 61364562Sgshapiro char *volatile auth_type; 61464562Sgshapiro char *mechlist; 61590792Sgshapiro volatile unsigned int n_mechs; 61690792Sgshapiro unsigned int len; 617168515Sgshapiro#else /* SASL */ 61890792Sgshapiro#endif /* SASL */ 619132943Sgshapiro int r; 62090792Sgshapiro#if STARTTLS 62166494Sgshapiro int rfd, wfd; 62290792Sgshapiro volatile bool tls_active = false; 623132943Sgshapiro volatile bool smtps = bitnset(D_SMTPS, d_flags); 62464562Sgshapiro bool saveQuickAbort; 62564562Sgshapiro bool saveSuprErrs; 62690792Sgshapiro time_t tlsstart; 62790792Sgshapiro#endif /* STARTTLS */ 62890792Sgshapiro volatile unsigned int features; 62990792Sgshapiro#if PIPELINING 63090792Sgshapiro# if _FFR_NO_PIPE 63190792Sgshapiro int np_log = 0; 63290792Sgshapiro# endif /* _FFR_NO_PIPE */ 63390792Sgshapiro#endif /* PIPELINING */ 63490792Sgshapiro volatile time_t log_delay = (time_t) 0; 635168515Sgshapiro#if MILTER 636168515Sgshapiro volatile bool milter_cmd_done, milter_cmd_safe; 637168515Sgshapiro volatile bool milter_rcpt_added, milter_cmd_fail; 638168515Sgshapiro ADDRESS addr_st; 639168515Sgshapiro# define p_addr_st &addr_st 640168515Sgshapiro#else /* MILTER */ 641168515Sgshapiro# define p_addr_st NULL 642168515Sgshapiro#endif /* MILTER */ 643168515Sgshapiro size_t inplen; 644182352Sgshapiro#if _FFR_BADRCPT_SHUTDOWN 645182352Sgshapiro int n_badrcpts_adj; 646182352Sgshapiro#endif /* _FFR_BADRCPT_SHUTDOWN */ 64738032Speter 648168515Sgshapiro SevenBitInput_Saved = SevenBitInput; 64990792Sgshapiro smtp.sm_nrcpts = 0; 65090792Sgshapiro#if MILTER 65190792Sgshapiro smtp.sm_milterize = (nullserver == NULL); 65290792Sgshapiro smtp.sm_milterlist = false; 653168515Sgshapiro addr = NULL; 65490792Sgshapiro#endif /* MILTER */ 65590792Sgshapiro 65690792Sgshapiro /* setup I/O fd correctly for the SMTP server */ 65790792Sgshapiro setup_smtpd_io(); 65890792Sgshapiro 65990792Sgshapiro#if SM_HEAP_CHECK 66090792Sgshapiro if (sm_debug_active(&DebugLeakSmtp, 1)) 66138032Speter { 66290792Sgshapiro sm_heap_newgroup(); 66390792Sgshapiro sm_dprintf("smtp() heap group #%d\n", sm_heap_group()); 66438032Speter } 66590792Sgshapiro#endif /* SM_HEAP_CHECK */ 66664562Sgshapiro 66790792Sgshapiro /* XXX the rpool should be set when e is initialized in main() */ 66890792Sgshapiro e->e_rpool = sm_rpool_new_x(NULL); 66990792Sgshapiro e->e_macro.mac_rpool = e->e_rpool; 67090792Sgshapiro 67138032Speter settime(e); 67290792Sgshapiro sm_getla(); 67338032Speter peerhostname = RealHostName; 67438032Speter if (peerhostname == NULL) 67538032Speter peerhostname = "localhost"; 67638032Speter CurHostName = peerhostname; 67738032Speter CurSmtpClient = macvalue('_', e); 67838032Speter if (CurSmtpClient == NULL) 67938032Speter CurSmtpClient = CurHostName; 68038032Speter 68138032Speter /* check_relay may have set discard bit, save for later */ 68290792Sgshapiro smtp.sm_discard = bitset(EF_DISCARD, e->e_flags); 68338032Speter 68490792Sgshapiro#if PIPELINING 68590792Sgshapiro /* auto-flush output when reading input */ 68690792Sgshapiro (void) sm_io_autoflush(InChannel, OutChannel); 68790792Sgshapiro#endif /* PIPELINING */ 68864562Sgshapiro 68990792Sgshapiro sm_setproctitle(true, e, "server %s startup", CurSmtpClient); 69090792Sgshapiro 69190792Sgshapiro /* Set default features for server. */ 69290792Sgshapiro features = ((bitset(PRIV_NOETRN, PrivacyFlags) || 69390792Sgshapiro bitnset(D_NOETRN, d_flags)) ? SRV_NONE : SRV_OFFER_ETRN) 69490792Sgshapiro | (bitnset(D_AUTHREQ, d_flags) ? SRV_REQ_AUTH : SRV_NONE) 69590792Sgshapiro | (bitset(PRIV_NOEXPN, PrivacyFlags) ? SRV_NONE 69690792Sgshapiro : (SRV_OFFER_EXPN 69790792Sgshapiro | (bitset(PRIV_NOVERB, PrivacyFlags) 69890792Sgshapiro ? SRV_NONE : SRV_OFFER_VERB))) 699159609Sgshapiro | ((bitset(PRIV_NORECEIPTS, PrivacyFlags) || !SendMIMEErrors) 700159609Sgshapiro ? SRV_NONE : SRV_OFFER_DSN) 70190792Sgshapiro#if SASL 70290792Sgshapiro | (bitnset(D_NOAUTH, d_flags) ? SRV_NONE : SRV_OFFER_AUTH) 703132943Sgshapiro | (bitset(SASL_SEC_NOPLAINTEXT, SASLOpts) ? SRV_REQ_SEC 704132943Sgshapiro : SRV_NONE) 70590792Sgshapiro#endif /* SASL */ 70690792Sgshapiro#if PIPELINING 70790792Sgshapiro | SRV_OFFER_PIPE 70890792Sgshapiro#endif /* PIPELINING */ 70990792Sgshapiro#if STARTTLS 71090792Sgshapiro | (bitnset(D_NOTLS, d_flags) ? SRV_NONE : SRV_OFFER_TLS) 71190792Sgshapiro | (bitset(TLS_I_NO_VRFY, TLS_Srv_Opts) ? SRV_NONE 71290792Sgshapiro : SRV_VRFY_CLT) 71390792Sgshapiro#endif /* STARTTLS */ 71490792Sgshapiro ; 71590792Sgshapiro if (nullserver == NULL) 71690792Sgshapiro { 71790792Sgshapiro features = srvfeatures(e, CurSmtpClient, features); 71890792Sgshapiro if (bitset(SRV_TMP_FAIL, features)) 71990792Sgshapiro { 72090792Sgshapiro if (LogLevel > 4) 72190792Sgshapiro sm_syslog(LOG_ERR, NOQID, 72290792Sgshapiro "ERROR: srv_features=tempfail, relay=%.100s, access temporarily disabled", 72390792Sgshapiro CurSmtpClient); 72490792Sgshapiro nullserver = "450 4.3.0 Please try again later."; 72590792Sgshapiro } 726132943Sgshapiro else 727132943Sgshapiro { 72890792Sgshapiro#if PIPELINING 72990792Sgshapiro# if _FFR_NO_PIPE 730132943Sgshapiro if (bitset(SRV_NO_PIPE, features)) 731132943Sgshapiro { 732132943Sgshapiro /* for consistency */ 733132943Sgshapiro features &= ~SRV_OFFER_PIPE; 734132943Sgshapiro } 73590792Sgshapiro# endif /* _FFR_NO_PIPE */ 73690792Sgshapiro#endif /* PIPELINING */ 737132943Sgshapiro#if SASL 738132943Sgshapiro if (bitset(SRV_REQ_SEC, features)) 739132943Sgshapiro SASLOpts |= SASL_SEC_NOPLAINTEXT; 740132943Sgshapiro else 741132943Sgshapiro SASLOpts &= ~SASL_SEC_NOPLAINTEXT; 742132943Sgshapiro#endif /* SASL */ 743132943Sgshapiro } 74490792Sgshapiro } 745132943Sgshapiro else if (strncmp(nullserver, "421 ", 4) == 0) 746132943Sgshapiro { 747132943Sgshapiro message(nullserver); 748132943Sgshapiro goto doquit; 749132943Sgshapiro } 75090792Sgshapiro 751168515Sgshapiro e->e_features = features; 75290792Sgshapiro hostname = macvalue('j', e); 75390792Sgshapiro#if SASL 754132943Sgshapiro if (AuthRealm == NULL) 755132943Sgshapiro AuthRealm = hostname; 75690792Sgshapiro sasl_ok = bitset(SRV_OFFER_AUTH, features); 75764562Sgshapiro n_mechs = 0; 75890792Sgshapiro authenticating = SASL_NOT_AUTH; 75964562Sgshapiro 76064562Sgshapiro /* SASL server new connection */ 76190792Sgshapiro if (sasl_ok) 76238032Speter { 76398121Sgshapiro# if SASL >= 20000 764132943Sgshapiro result = sasl_server_new("smtp", AuthRealm, NULL, NULL, NULL, 76598121Sgshapiro NULL, 0, &conn); 76698121Sgshapiro# elif SASL > 10505 76790792Sgshapiro /* use empty realm: only works in SASL > 1.5.5 */ 768132943Sgshapiro result = sasl_server_new("smtp", AuthRealm, "", NULL, 0, &conn); 76998121Sgshapiro# else /* SASL >= 20000 */ 77090792Sgshapiro /* use no realm -> realm is set to hostname by SASL lib */ 771132943Sgshapiro result = sasl_server_new("smtp", AuthRealm, NULL, NULL, 0, 77290792Sgshapiro &conn); 77398121Sgshapiro# endif /* SASL >= 20000 */ 77490792Sgshapiro sasl_ok = result == SASL_OK; 77590792Sgshapiro if (!sasl_ok) 77690792Sgshapiro { 77790792Sgshapiro if (LogLevel > 9) 77890792Sgshapiro sm_syslog(LOG_WARNING, NOQID, 77990792Sgshapiro "AUTH error: sasl_server_new failed=%d", 78090792Sgshapiro result); 78190792Sgshapiro } 78290792Sgshapiro } 78390792Sgshapiro if (sasl_ok) 78490792Sgshapiro { 78564562Sgshapiro /* 78664562Sgshapiro ** SASL set properties for sasl 78764562Sgshapiro ** set local/remote IP 78898121Sgshapiro ** XXX Cyrus SASL v1 only supports IPv4 78964562Sgshapiro ** 79064562Sgshapiro ** XXX where exactly are these used/required? 79164562Sgshapiro ** Kerberos_v4 79264562Sgshapiro */ 79364562Sgshapiro 79498121Sgshapiro# if SASL >= 20000 795147078Sgshapiro localip[0] = remoteip[0] = '\0'; 79698121Sgshapiro# if NETINET || NETINET6 79790792Sgshapiro in = macvalue(macid("{daemon_family}"), e); 79898121Sgshapiro if (in != NULL && ( 79998121Sgshapiro# if NETINET6 80098121Sgshapiro strcmp(in, "inet6") == 0 || 80198121Sgshapiro# endif /* NETINET6 */ 80298121Sgshapiro strcmp(in, "inet") == 0)) 80398121Sgshapiro { 80498121Sgshapiro SOCKADDR_LEN_T addrsize; 80598121Sgshapiro SOCKADDR saddr_l; 80698121Sgshapiro SOCKADDR saddr_r; 80798121Sgshapiro 80898121Sgshapiro addrsize = sizeof(saddr_r); 80998121Sgshapiro if (getpeername(sm_io_getinfo(InChannel, SM_IO_WHAT_FD, 81098121Sgshapiro NULL), 81198121Sgshapiro (struct sockaddr *) &saddr_r, 81298121Sgshapiro &addrsize) == 0) 81398121Sgshapiro { 81498121Sgshapiro if (iptostring(&saddr_r, addrsize, 815168515Sgshapiro remoteip, sizeof(remoteip))) 81698121Sgshapiro { 81798121Sgshapiro sasl_setprop(conn, SASL_IPREMOTEPORT, 81898121Sgshapiro remoteip); 81998121Sgshapiro } 82098121Sgshapiro addrsize = sizeof(saddr_l); 82198121Sgshapiro if (getsockname(sm_io_getinfo(InChannel, 82298121Sgshapiro SM_IO_WHAT_FD, 82398121Sgshapiro NULL), 82498121Sgshapiro (struct sockaddr *) &saddr_l, 82598121Sgshapiro &addrsize) == 0) 82698121Sgshapiro { 82798121Sgshapiro if (iptostring(&saddr_l, addrsize, 82898121Sgshapiro localip, 829168515Sgshapiro sizeof(localip))) 83098121Sgshapiro { 83198121Sgshapiro sasl_setprop(conn, 83298121Sgshapiro SASL_IPLOCALPORT, 83398121Sgshapiro localip); 83498121Sgshapiro } 83598121Sgshapiro } 83698121Sgshapiro } 83798121Sgshapiro } 83898121Sgshapiro# endif /* NETINET || NETINET6 */ 83998121Sgshapiro# else /* SASL >= 20000 */ 84098121Sgshapiro# if NETINET 84198121Sgshapiro in = macvalue(macid("{daemon_family}"), e); 84264562Sgshapiro if (in != NULL && strcmp(in, "inet") == 0) 84364562Sgshapiro { 84464562Sgshapiro SOCKADDR_LEN_T addrsize; 84564562Sgshapiro 84664562Sgshapiro addrsize = sizeof(struct sockaddr_in); 84790792Sgshapiro if (getpeername(sm_io_getinfo(InChannel, SM_IO_WHAT_FD, 84890792Sgshapiro NULL), 84964562Sgshapiro (struct sockaddr *)&saddr_r, 85064562Sgshapiro &addrsize) == 0) 85164562Sgshapiro { 85264562Sgshapiro sasl_setprop(conn, SASL_IP_REMOTE, &saddr_r); 85364562Sgshapiro addrsize = sizeof(struct sockaddr_in); 85490792Sgshapiro if (getsockname(sm_io_getinfo(InChannel, 85590792Sgshapiro SM_IO_WHAT_FD, 85690792Sgshapiro NULL), 85764562Sgshapiro (struct sockaddr *)&saddr_l, 85864562Sgshapiro &addrsize) == 0) 85964562Sgshapiro sasl_setprop(conn, SASL_IP_LOCAL, 86064562Sgshapiro &saddr_l); 86164562Sgshapiro } 86264562Sgshapiro } 86398121Sgshapiro# endif /* NETINET */ 86498121Sgshapiro# endif /* SASL >= 20000 */ 86564562Sgshapiro 86664562Sgshapiro auth_type = NULL; 86764562Sgshapiro mechlist = NULL; 86864562Sgshapiro user = NULL; 86990792Sgshapiro# if 0 87090792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 87190792Sgshapiro macid("{auth_author}"), NULL); 87290792Sgshapiro# endif /* 0 */ 87364562Sgshapiro 87464562Sgshapiro /* set properties */ 875168515Sgshapiro (void) memset(&ssp, '\0', sizeof(ssp)); 87690792Sgshapiro 87764562Sgshapiro /* XXX should these be options settable via .cf ? */ 87864562Sgshapiro /* ssp.min_ssf = 0; is default due to memset() */ 879223067Sgshapiro ssp.max_ssf = MaxSLBits; 880223067Sgshapiro ssp.maxbufsize = MAXOUTLEN; 88164562Sgshapiro ssp.security_flags = SASLOpts & SASL_SEC_MASK; 88264562Sgshapiro sasl_ok = sasl_setprop(conn, SASL_SEC_PROPS, &ssp) == SASL_OK; 88364562Sgshapiro 88464562Sgshapiro if (sasl_ok) 88564562Sgshapiro { 88664562Sgshapiro /* 88764562Sgshapiro ** external security strength factor; 88890792Sgshapiro ** currently we have none so zero 88964562Sgshapiro */ 89090792Sgshapiro 89198121Sgshapiro# if SASL >= 20000 89298121Sgshapiro ext_ssf = 0; 89398121Sgshapiro auth_id = NULL; 89498121Sgshapiro sasl_ok = ((sasl_setprop(conn, SASL_SSF_EXTERNAL, 89598121Sgshapiro &ext_ssf) == SASL_OK) && 89698121Sgshapiro (sasl_setprop(conn, SASL_AUTH_EXTERNAL, 897102528Sgshapiro auth_id) == SASL_OK)); 89898121Sgshapiro# else /* SASL >= 20000 */ 89964562Sgshapiro ext_ssf.ssf = 0; 90064562Sgshapiro ext_ssf.auth_id = NULL; 90164562Sgshapiro sasl_ok = sasl_setprop(conn, SASL_SSF_EXTERNAL, 90264562Sgshapiro &ext_ssf) == SASL_OK; 90398121Sgshapiro# endif /* SASL >= 20000 */ 90464562Sgshapiro } 90564562Sgshapiro if (sasl_ok) 90664562Sgshapiro n_mechs = saslmechs(conn, &mechlist); 90738032Speter } 90890792Sgshapiro#endif /* SASL */ 90938032Speter 910120256Sgshapiro#if STARTTLS 911182352Sgshapiro 912203004Sgshapiro 913182352Sgshapiro set_tls_rd_tmo(TimeOuts.to_nextcommand); 914120256Sgshapiro#endif /* STARTTLS */ 915120256Sgshapiro 91690792Sgshapiro#if MILTER 91790792Sgshapiro if (smtp.sm_milterize) 91864562Sgshapiro { 91964562Sgshapiro char state; 92064562Sgshapiro 92164562Sgshapiro /* initialize mail filter connection */ 922173340Sgshapiro smtp.sm_milterlist = milter_init(e, &state, &smtp.sm_milters); 92364562Sgshapiro switch (state) 92464562Sgshapiro { 92564562Sgshapiro case SMFIR_REJECT: 92690792Sgshapiro if (MilterLogLevel > 3) 92790792Sgshapiro sm_syslog(LOG_INFO, e->e_id, 92894334Sgshapiro "Milter: initialization failed, rejecting commands"); 92964562Sgshapiro greetcode = "554"; 93064562Sgshapiro nullserver = "Command rejected"; 93190792Sgshapiro smtp.sm_milterize = false; 93264562Sgshapiro break; 93364562Sgshapiro 93464562Sgshapiro case SMFIR_TEMPFAIL: 93590792Sgshapiro if (MilterLogLevel > 3) 93690792Sgshapiro sm_syslog(LOG_INFO, e->e_id, 93794334Sgshapiro "Milter: initialization failed, temp failing commands"); 93890792Sgshapiro tempfail = true; 93990792Sgshapiro smtp.sm_milterize = false; 94064562Sgshapiro break; 941157001Sgshapiro 942157001Sgshapiro case SMFIR_SHUTDOWN: 943157001Sgshapiro if (MilterLogLevel > 3) 944157001Sgshapiro sm_syslog(LOG_INFO, e->e_id, 945157001Sgshapiro "Milter: initialization failed, closing connection"); 946157001Sgshapiro tempfail = true; 947157001Sgshapiro smtp.sm_milterize = false; 948157001Sgshapiro message("421 4.7.0 %s closing connection", 949157001Sgshapiro MyHostName); 950157001Sgshapiro 951157001Sgshapiro /* arrange to ignore send list */ 952157001Sgshapiro e->e_sendqueue = NULL; 953182352Sgshapiro lognullconnection = false; 954157001Sgshapiro goto doquit; 95564562Sgshapiro } 95664562Sgshapiro } 95764562Sgshapiro 95890792Sgshapiro if (smtp.sm_milterlist && smtp.sm_milterize && 95990792Sgshapiro !bitset(EF_DISCARD, e->e_flags)) 96064562Sgshapiro { 96164562Sgshapiro char state; 96290792Sgshapiro char *response; 96364562Sgshapiro 964161389Sgshapiro q = macvalue(macid("{client_name}"), e); 965168515Sgshapiro SM_ASSERT(q != NULL || OpMode == MD_SMTP); 966168515Sgshapiro if (q == NULL) 967168515Sgshapiro q = "localhost"; 968161389Sgshapiro response = milter_connect(q, RealHostAddr, e, &state); 96964562Sgshapiro switch (state) 97064562Sgshapiro { 97164562Sgshapiro case SMFIR_REPLYCODE: /* REPLYCODE shouldn't happen */ 97264562Sgshapiro case SMFIR_REJECT: 97390792Sgshapiro if (MilterLogLevel > 3) 97490792Sgshapiro sm_syslog(LOG_INFO, e->e_id, 97590792Sgshapiro "Milter: connect: host=%s, addr=%s, rejecting commands", 97690792Sgshapiro peerhostname, 97790792Sgshapiro anynet_ntoa(&RealHostAddr)); 97864562Sgshapiro greetcode = "554"; 97964562Sgshapiro nullserver = "Command rejected"; 98090792Sgshapiro smtp.sm_milterize = false; 98164562Sgshapiro break; 98264562Sgshapiro 98364562Sgshapiro case SMFIR_TEMPFAIL: 98490792Sgshapiro if (MilterLogLevel > 3) 98590792Sgshapiro sm_syslog(LOG_INFO, e->e_id, 98690792Sgshapiro "Milter: connect: host=%s, addr=%s, temp failing commands", 98790792Sgshapiro peerhostname, 98890792Sgshapiro anynet_ntoa(&RealHostAddr)); 98990792Sgshapiro tempfail = true; 99090792Sgshapiro smtp.sm_milterize = false; 99164562Sgshapiro break; 992110560Sgshapiro 993110560Sgshapiro case SMFIR_SHUTDOWN: 994110560Sgshapiro if (MilterLogLevel > 3) 995110560Sgshapiro sm_syslog(LOG_INFO, e->e_id, 996110560Sgshapiro "Milter: connect: host=%s, addr=%s, shutdown", 997110560Sgshapiro peerhostname, 998110560Sgshapiro anynet_ntoa(&RealHostAddr)); 999110560Sgshapiro tempfail = true; 1000110560Sgshapiro smtp.sm_milterize = false; 1001110560Sgshapiro message("421 4.7.0 %s closing connection", 1002110560Sgshapiro MyHostName); 1003110560Sgshapiro 1004110560Sgshapiro /* arrange to ignore send list */ 1005110560Sgshapiro e->e_sendqueue = NULL; 1006110560Sgshapiro goto doquit; 100764562Sgshapiro } 100890792Sgshapiro if (response != NULL) 100990792Sgshapiro sm_free(response); /* XXX */ 101064562Sgshapiro } 101190792Sgshapiro#endif /* MILTER */ 101264562Sgshapiro 1013132943Sgshapiro /* 1014132943Sgshapiro ** Broken proxies and SMTP slammers 1015132943Sgshapiro ** push data without waiting, catch them 1016132943Sgshapiro */ 1017132943Sgshapiro 1018132943Sgshapiro if ( 101990792Sgshapiro#if STARTTLS 1020132943Sgshapiro !smtps && 1021132943Sgshapiro#endif /* STARTTLS */ 1022168515Sgshapiro *greetcode == '2' && nullserver == NULL) 1023132943Sgshapiro { 1024132943Sgshapiro time_t msecs = 0; 1025132943Sgshapiro char **pvp; 1026132943Sgshapiro char pvpbuf[PSBUFSIZE]; 1027132943Sgshapiro 1028132943Sgshapiro /* Ask the rulesets how long to pause */ 1029132943Sgshapiro pvp = NULL; 1030132943Sgshapiro r = rscap("greet_pause", peerhostname, 1031132943Sgshapiro anynet_ntoa(&RealHostAddr), e, 1032132943Sgshapiro &pvp, pvpbuf, sizeof(pvpbuf)); 1033132943Sgshapiro if (r == EX_OK && pvp != NULL && pvp[0] != NULL && 1034132943Sgshapiro (pvp[0][0] & 0377) == CANONNET && pvp[1] != NULL) 1035132943Sgshapiro { 1036132943Sgshapiro msecs = strtol(pvp[1], NULL, 10); 1037132943Sgshapiro } 1038132943Sgshapiro 1039132943Sgshapiro if (msecs > 0) 1040132943Sgshapiro { 1041132943Sgshapiro int fd; 1042132943Sgshapiro fd_set readfds; 1043132943Sgshapiro struct timeval timeout; 1044157001Sgshapiro struct timeval bp, ep, tp; /* {begin,end,total}pause */ 1045168515Sgshapiro int eoftest; 1046132943Sgshapiro 1047132943Sgshapiro /* pause for a moment */ 1048132943Sgshapiro timeout.tv_sec = msecs / 1000; 1049132943Sgshapiro timeout.tv_usec = (msecs % 1000) * 1000; 1050132943Sgshapiro 1051132943Sgshapiro /* Obey RFC 2821: 4.3.5.2: 220 timeout of 5 minutes */ 1052132943Sgshapiro if (timeout.tv_sec >= 300) 1053132943Sgshapiro { 1054132943Sgshapiro timeout.tv_sec = 300; 1055132943Sgshapiro timeout.tv_usec = 0; 1056132943Sgshapiro } 1057132943Sgshapiro 1058132943Sgshapiro /* check if data is on the socket during the pause */ 1059132943Sgshapiro fd = sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL); 1060132943Sgshapiro FD_ZERO(&readfds); 1061132943Sgshapiro SM_FD_SET(fd, &readfds); 1062157001Sgshapiro gettimeofday(&bp, NULL); 1063132943Sgshapiro if (select(fd + 1, FDSET_CAST &readfds, 1064132943Sgshapiro NULL, NULL, &timeout) > 0 && 1065168515Sgshapiro FD_ISSET(fd, &readfds) && 1066182352Sgshapiro (eoftest = sm_io_getc(InChannel, SM_TIME_DEFAULT)) 1067168515Sgshapiro != SM_IO_EOF) 1068132943Sgshapiro { 1069182352Sgshapiro sm_io_ungetc(InChannel, SM_TIME_DEFAULT, 1070168515Sgshapiro eoftest); 1071157001Sgshapiro gettimeofday(&ep, NULL); 1072157001Sgshapiro timersub(&ep, &bp, &tp); 1073132943Sgshapiro greetcode = "554"; 1074132943Sgshapiro nullserver = "Command rejected"; 1075132943Sgshapiro sm_syslog(LOG_INFO, e->e_id, 1076168515Sgshapiro "rejecting commands from %s [%s] due to pre-greeting traffic after %d seconds", 1077132943Sgshapiro peerhostname, 1078168515Sgshapiro anynet_ntoa(&RealHostAddr), 1079168515Sgshapiro (int) tp.tv_sec + 1080157001Sgshapiro (tp.tv_usec >= 500000 ? 1 : 0) 1081157001Sgshapiro ); 1082132943Sgshapiro } 1083132943Sgshapiro } 1084132943Sgshapiro } 1085132943Sgshapiro 1086132943Sgshapiro#if STARTTLS 108790792Sgshapiro /* If this an smtps connection, start TLS now */ 108890792Sgshapiro if (smtps) 1089120256Sgshapiro { 1090120256Sgshapiro Errors = 0; 109190792Sgshapiro goto starttls; 1092120256Sgshapiro } 109390792Sgshapiro 109490792Sgshapiro greeting: 109590792Sgshapiro 109690792Sgshapiro#endif /* STARTTLS */ 109790792Sgshapiro 109838032Speter /* output the first line, inserting "ESMTP" as second word */ 109990792Sgshapiro if (*greetcode == '5') 1100168515Sgshapiro (void) sm_snprintf(inp, sizeof(inp), 1101168515Sgshapiro "%s not accepting messages", hostname); 110290792Sgshapiro else 1103168515Sgshapiro expand(SmtpGreeting, inp, sizeof(inp), e); 110490792Sgshapiro 110538032Speter p = strchr(inp, '\n'); 110638032Speter if (p != NULL) 110738032Speter *p++ = '\0'; 110838032Speter id = strchr(inp, ' '); 110938032Speter if (id == NULL) 111038032Speter id = &inp[strlen(inp)]; 111164562Sgshapiro if (p == NULL) 1112168515Sgshapiro (void) sm_snprintf(cmdbuf, sizeof(cmdbuf), 111364562Sgshapiro "%s %%.*s ESMTP%%s", greetcode); 111464562Sgshapiro else 1115168515Sgshapiro (void) sm_snprintf(cmdbuf, sizeof(cmdbuf), 111664562Sgshapiro "%s-%%.*s ESMTP%%s", greetcode); 111766494Sgshapiro message(cmdbuf, (int) (id - inp), inp, id); 111838032Speter 111938032Speter /* output remaining lines */ 112038032Speter while ((id = p) != NULL && (p = strchr(id, '\n')) != NULL) 112138032Speter { 112238032Speter *p++ = '\0'; 112338032Speter if (isascii(*id) && isspace(*id)) 112438032Speter id++; 1125168515Sgshapiro (void) sm_strlcpyn(cmdbuf, sizeof(cmdbuf), 2, greetcode, "-%s"); 112664562Sgshapiro message(cmdbuf, id); 112738032Speter } 112838032Speter if (id != NULL) 112938032Speter { 113038032Speter if (isascii(*id) && isspace(*id)) 113138032Speter id++; 1132168515Sgshapiro (void) sm_strlcpyn(cmdbuf, sizeof(cmdbuf), 2, greetcode, " %s"); 113364562Sgshapiro message(cmdbuf, id); 113438032Speter } 113538032Speter 113638032Speter protocol = NULL; 113738032Speter sendinghost = macvalue('s', e); 113890792Sgshapiro 113990792Sgshapiro /* If quarantining by a connect/ehlo action, save between messages */ 114090792Sgshapiro if (e->e_quarmsg == NULL) 114190792Sgshapiro smtp.sm_quarmsg = NULL; 114290792Sgshapiro else 114390792Sgshapiro smtp.sm_quarmsg = newstr(e->e_quarmsg); 114490792Sgshapiro 114590792Sgshapiro /* sendinghost's storage must outlive the current envelope */ 114690792Sgshapiro if (sendinghost != NULL) 114790792Sgshapiro sendinghost = sm_strdup_x(sendinghost); 114890792Sgshapiro first = true; 114990792Sgshapiro gothello = false; 115090792Sgshapiro smtp.sm_gotmail = false; 115138032Speter for (;;) 115238032Speter { 115390792Sgshapiro SM_TRY 115490792Sgshapiro { 115590792Sgshapiro QuickAbort = false; 115690792Sgshapiro HoldErrs = false; 115790792Sgshapiro SuprErrs = false; 115890792Sgshapiro LogUsrErrs = false; 115990792Sgshapiro OnlyOneError = true; 116038032Speter e->e_flags &= ~(EF_VRFYONLY|EF_GLOBALERRS); 1161168515Sgshapiro#if MILTER 1162168515Sgshapiro milter_cmd_fail = false; 1163168515Sgshapiro#endif /* MILTER */ 116438032Speter 116538032Speter /* setup for the read */ 116638032Speter e->e_to = NULL; 116738032Speter Errors = 0; 116864562Sgshapiro FileName = NULL; 116990792Sgshapiro (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 117038032Speter 117138032Speter /* read the input line */ 117238032Speter SmtpPhase = "server cmd read"; 117390792Sgshapiro sm_setproctitle(true, e, "server %s cmd read", CurSmtpClient); 117438032Speter 117538032Speter /* handle errors */ 117690792Sgshapiro if (sm_io_error(OutChannel) || 1177168515Sgshapiro (p = sfgets(inp, sizeof(inp), InChannel, 117864562Sgshapiro TimeOuts.to_nextcommand, SmtpPhase)) == NULL) 117938032Speter { 118064562Sgshapiro char *d; 118164562Sgshapiro 118290792Sgshapiro d = macvalue(macid("{daemon_name}"), e); 118364562Sgshapiro if (d == NULL) 118464562Sgshapiro d = "stdin"; 118538032Speter /* end of file, just die */ 118638032Speter disconnect(1, e); 118764562Sgshapiro 118890792Sgshapiro#if MILTER 118964562Sgshapiro /* close out milter filters */ 119064562Sgshapiro milter_quit(e); 119190792Sgshapiro#endif /* MILTER */ 119264562Sgshapiro 119364562Sgshapiro message("421 4.4.1 %s Lost input channel from %s", 119438032Speter MyHostName, CurSmtpClient); 119590792Sgshapiro if (LogLevel > (smtp.sm_gotmail ? 1 : 19)) 119638032Speter sm_syslog(LOG_NOTICE, e->e_id, 1197110560Sgshapiro "lost input channel from %s to %s after %s", 119864562Sgshapiro CurSmtpClient, d, 119964562Sgshapiro (c == NULL || c->cmd_name == NULL) ? "startup" : c->cmd_name); 120038032Speter /* 120142575Speter ** If have not accepted mail (DATA), do not bounce 120242575Speter ** bad addresses back to sender. 120338032Speter */ 120464562Sgshapiro 120538032Speter if (bitset(EF_CLRQUEUE, e->e_flags)) 120638032Speter e->e_sendqueue = NULL; 120764562Sgshapiro goto doquit; 120838032Speter } 120938032Speter 1210168515Sgshapiro /* also used by "proxy" check below */ 1211168515Sgshapiro inplen = strlen(inp); 1212168515Sgshapiro#if SASL 1213168515Sgshapiro /* 1214168515Sgshapiro ** SMTP AUTH requires accepting any length, 1215168515Sgshapiro ** at least for challenge/response. However, not imposing 1216168515Sgshapiro ** a limit is a bad idea (denial of service). 1217168515Sgshapiro */ 1218168515Sgshapiro 1219168515Sgshapiro if (authenticating != SASL_PROC_AUTH 1220168515Sgshapiro && sm_strncasecmp(inp, "AUTH ", 5) != 0 1221168515Sgshapiro && inplen > MAXLINE) 1222168515Sgshapiro { 1223168515Sgshapiro message("421 4.7.0 %s Command too long, possible attack %s", 1224168515Sgshapiro MyHostName, CurSmtpClient); 1225168515Sgshapiro sm_syslog(LOG_INFO, e->e_id, 1226168515Sgshapiro "%s: SMTP violation, input too long: %lu", 1227168515Sgshapiro CurSmtpClient, (unsigned long) inplen); 1228168515Sgshapiro goto doquit; 1229168515Sgshapiro } 1230168515Sgshapiro#endif /* SASL */ 1231168515Sgshapiro 123290792Sgshapiro if (first) 123390792Sgshapiro { 1234168515Sgshapiro size_t cmdlen; 1235110560Sgshapiro int idx; 1236110560Sgshapiro char *http_cmd; 1237110560Sgshapiro static char *http_cmds[] = { "GET", "POST", 1238110560Sgshapiro "CONNECT", "USER", NULL }; 1239110560Sgshapiro 1240110560Sgshapiro for (idx = 0; (http_cmd = http_cmds[idx]) != NULL; 1241110560Sgshapiro idx++) 1242110560Sgshapiro { 1243110560Sgshapiro cmdlen = strlen(http_cmd); 1244110560Sgshapiro if (cmdlen < inplen && 1245110560Sgshapiro sm_strncasecmp(inp, http_cmd, cmdlen) == 0 && 1246110560Sgshapiro isascii(inp[cmdlen]) && isspace(inp[cmdlen])) 1247110560Sgshapiro { 1248110560Sgshapiro /* Open proxy, drop it */ 1249110560Sgshapiro message("421 4.7.0 %s Rejecting open proxy %s", 1250110560Sgshapiro MyHostName, CurSmtpClient); 1251110560Sgshapiro sm_syslog(LOG_INFO, e->e_id, 1252110560Sgshapiro "%s: probable open proxy: command=%.40s", 1253110560Sgshapiro CurSmtpClient, inp); 1254110560Sgshapiro goto doquit; 1255110560Sgshapiro } 1256110560Sgshapiro } 125790792Sgshapiro first = false; 125890792Sgshapiro } 125990792Sgshapiro 126038032Speter /* clean up end of line */ 126190792Sgshapiro fixcrlf(inp, true); 126238032Speter 126390792Sgshapiro#if PIPELINING 126490792Sgshapiro# if _FFR_NO_PIPE 126590792Sgshapiro /* 126690792Sgshapiro ** if there is more input and pipelining is disabled: 126790792Sgshapiro ** delay ... (and maybe discard the input?) 126890792Sgshapiro ** XXX this doesn't really work, at least in tests using 126990792Sgshapiro ** telnet SM_IO_IS_READABLE only returns 1 if there were 127090792Sgshapiro ** more than 2 input lines available. 127190792Sgshapiro */ 127290792Sgshapiro 127390792Sgshapiro if (bitset(SRV_NO_PIPE, features) && 1274110560Sgshapiro sm_io_getinfo(InChannel, SM_IO_IS_READABLE, NULL) > 0) 127590792Sgshapiro { 127690792Sgshapiro if (++np_log < 3) 127790792Sgshapiro sm_syslog(LOG_INFO, NOQID, 1278203004Sgshapiro "unauthorized PIPELINING, sleeping, relay=%.100s", 1279203004Sgshapiro CurSmtpClient); 128090792Sgshapiro sleep(1); 128190792Sgshapiro } 128290792Sgshapiro 128390792Sgshapiro# endif /* _FFR_NO_PIPE */ 128490792Sgshapiro#endif /* PIPELINING */ 128590792Sgshapiro 128690792Sgshapiro#if SASL 128764562Sgshapiro if (authenticating == SASL_PROC_AUTH) 128864562Sgshapiro { 128990792Sgshapiro# if 0 129064562Sgshapiro if (*inp == '\0') 129164562Sgshapiro { 129264562Sgshapiro authenticating = SASL_NOT_AUTH; 129364562Sgshapiro message("501 5.5.2 missing input"); 1294120256Sgshapiro RESET_SASLCONN; 129564562Sgshapiro continue; 129664562Sgshapiro } 129790792Sgshapiro# endif /* 0 */ 129864562Sgshapiro if (*inp == '*' && *(inp + 1) == '\0') 129964562Sgshapiro { 130064562Sgshapiro authenticating = SASL_NOT_AUTH; 130164562Sgshapiro 1302173340Sgshapiro /* RFC 2554 4. */ 130364562Sgshapiro message("501 5.0.0 AUTH aborted"); 1304120256Sgshapiro RESET_SASLCONN; 130564562Sgshapiro continue; 130664562Sgshapiro } 130764562Sgshapiro 130864562Sgshapiro /* could this be shorter? XXX */ 130998121Sgshapiro# if SASL >= 20000 131098121Sgshapiro in = xalloc(strlen(inp) + 1); 131198121Sgshapiro result = sasl_decode64(inp, strlen(inp), in, 131298121Sgshapiro strlen(inp), &inlen); 131398121Sgshapiro# else /* SASL >= 20000 */ 131464562Sgshapiro out = xalloc(strlen(inp)); 131564562Sgshapiro result = sasl_decode64(inp, strlen(inp), out, &outlen); 131698121Sgshapiro# endif /* SASL >= 20000 */ 131764562Sgshapiro if (result != SASL_OK) 131864562Sgshapiro { 131964562Sgshapiro authenticating = SASL_NOT_AUTH; 132064562Sgshapiro 1321173340Sgshapiro /* RFC 2554 4. */ 132264562Sgshapiro message("501 5.5.4 cannot decode AUTH parameter %s", 132364562Sgshapiro inp); 132498121Sgshapiro# if SASL >= 20000 132598121Sgshapiro sm_free(in); 132698121Sgshapiro# endif /* SASL >= 20000 */ 1327120256Sgshapiro RESET_SASLCONN; 132864562Sgshapiro continue; 132964562Sgshapiro } 133064562Sgshapiro 133198121Sgshapiro# if SASL >= 20000 133298121Sgshapiro result = sasl_server_step(conn, in, inlen, 133398121Sgshapiro &out, &outlen); 133498121Sgshapiro sm_free(in); 133598121Sgshapiro# else /* SASL >= 20000 */ 133664562Sgshapiro result = sasl_server_step(conn, out, outlen, 133764562Sgshapiro &out, &outlen, &errstr); 133898121Sgshapiro# endif /* SASL >= 20000 */ 133964562Sgshapiro 134064562Sgshapiro /* get an OK if we're done */ 134164562Sgshapiro if (result == SASL_OK) 134264562Sgshapiro { 134364562Sgshapiro authenticated: 134464562Sgshapiro message("235 2.0.0 OK Authenticated"); 134564562Sgshapiro authenticating = SASL_IS_AUTH; 134690792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 134790792Sgshapiro macid("{auth_type}"), auth_type); 134864562Sgshapiro 134998121Sgshapiro# if SASL >= 20000 135098121Sgshapiro user = macvalue(macid("{auth_authen}"), e); 135198121Sgshapiro 135298121Sgshapiro /* get security strength (features) */ 135398121Sgshapiro result = sasl_getprop(conn, SASL_SSF, 135498121Sgshapiro (const void **) &ssf); 135598121Sgshapiro# else /* SASL >= 20000 */ 135664562Sgshapiro result = sasl_getprop(conn, SASL_USERNAME, 135764562Sgshapiro (void **)&user); 135864562Sgshapiro if (result != SASL_OK) 135964562Sgshapiro { 136064562Sgshapiro user = ""; 136190792Sgshapiro macdefine(&BlankEnvelope.e_macro, 136290792Sgshapiro A_PERM, 136390792Sgshapiro macid("{auth_authen}"), NULL); 136464562Sgshapiro } 136564562Sgshapiro else 136664562Sgshapiro { 136790792Sgshapiro macdefine(&BlankEnvelope.e_macro, 136890792Sgshapiro A_TEMP, 1369132943Sgshapiro macid("{auth_authen}"), 1370132943Sgshapiro xtextify(user, "<>\")")); 137164562Sgshapiro } 137264562Sgshapiro 137390792Sgshapiro# if 0 137464562Sgshapiro /* get realm? */ 137564562Sgshapiro sasl_getprop(conn, SASL_REALM, (void **) &data); 137690792Sgshapiro# endif /* 0 */ 137764562Sgshapiro 137864562Sgshapiro /* get security strength (features) */ 137964562Sgshapiro result = sasl_getprop(conn, SASL_SSF, 138064562Sgshapiro (void **) &ssf); 138198121Sgshapiro# endif /* SASL >= 20000 */ 138264562Sgshapiro if (result != SASL_OK) 138364562Sgshapiro { 138490792Sgshapiro macdefine(&BlankEnvelope.e_macro, 138590792Sgshapiro A_PERM, 138690792Sgshapiro macid("{auth_ssf}"), "0"); 138764562Sgshapiro ssf = NULL; 138864562Sgshapiro } 138964562Sgshapiro else 139064562Sgshapiro { 139164562Sgshapiro char pbuf[8]; 139264562Sgshapiro 1393168515Sgshapiro (void) sm_snprintf(pbuf, sizeof(pbuf), 139490792Sgshapiro "%u", *ssf); 139590792Sgshapiro macdefine(&BlankEnvelope.e_macro, 139690792Sgshapiro A_TEMP, 139790792Sgshapiro macid("{auth_ssf}"), pbuf); 139864562Sgshapiro if (tTd(95, 8)) 139990792Sgshapiro sm_dprintf("AUTH auth_ssf: %u\n", 140090792Sgshapiro *ssf); 140164562Sgshapiro } 140290792Sgshapiro 140364562Sgshapiro /* 140490792Sgshapiro ** Only switch to encrypted connection 140564562Sgshapiro ** if a security layer has been negotiated 140664562Sgshapiro */ 140790792Sgshapiro 140864562Sgshapiro if (ssf != NULL && *ssf > 0) 140964562Sgshapiro { 1410159609Sgshapiro int tmo; 1411159609Sgshapiro 141264562Sgshapiro /* 141390792Sgshapiro ** Convert I/O layer to use SASL. 141490792Sgshapiro ** If the call fails, the connection 141590792Sgshapiro ** is aborted. 141664562Sgshapiro */ 141790792Sgshapiro 1418159609Sgshapiro tmo = TimeOuts.to_datablock * 1000; 141990792Sgshapiro if (sfdcsasl(&InChannel, &OutChannel, 1420159609Sgshapiro conn, tmo) == 0) 142164562Sgshapiro { 142264562Sgshapiro /* restart dialogue */ 142364562Sgshapiro n_helo = 0; 142494334Sgshapiro# if PIPELINING 142590792Sgshapiro (void) sm_io_autoflush(InChannel, 142690792Sgshapiro OutChannel); 142794334Sgshapiro# endif /* PIPELINING */ 142864562Sgshapiro } 142964562Sgshapiro else 143064562Sgshapiro syserr("503 5.3.3 SASL TLS failed"); 143164562Sgshapiro } 143290792Sgshapiro 143390792Sgshapiro /* NULL pointer ok since it's our function */ 143490792Sgshapiro if (LogLevel > 8) 143564562Sgshapiro sm_syslog(LOG_INFO, NOQID, 1436110560Sgshapiro "AUTH=server, relay=%s, authid=%.128s, mech=%.16s, bits=%d", 143790792Sgshapiro CurSmtpClient, 143890792Sgshapiro shortenstring(user, 128), 143990792Sgshapiro auth_type, *ssf); 144064562Sgshapiro } 144164562Sgshapiro else if (result == SASL_CONTINUE) 144264562Sgshapiro { 144364562Sgshapiro len = ENC64LEN(outlen); 144464562Sgshapiro out2 = xalloc(len); 144564562Sgshapiro result = sasl_encode64(out, outlen, out2, len, 144690792Sgshapiro &out2len); 144764562Sgshapiro if (result != SASL_OK) 144864562Sgshapiro { 144964562Sgshapiro /* correct code? XXX */ 145064562Sgshapiro /* 454 Temp. authentication failure */ 145164562Sgshapiro message("454 4.5.4 Internal error: unable to encode64"); 145264562Sgshapiro if (LogLevel > 5) 145364562Sgshapiro sm_syslog(LOG_WARNING, e->e_id, 1454203004Sgshapiro "AUTH encode64 error [%d for \"%s\"], relay=%.100s", 1455203004Sgshapiro result, out, 1456203004Sgshapiro CurSmtpClient); 145764562Sgshapiro /* start over? */ 145864562Sgshapiro authenticating = SASL_NOT_AUTH; 145964562Sgshapiro } 146064562Sgshapiro else 146164562Sgshapiro { 146264562Sgshapiro message("334 %s", out2); 146364562Sgshapiro if (tTd(95, 2)) 146490792Sgshapiro sm_dprintf("AUTH continue: msg='%s' len=%u\n", 146590792Sgshapiro out2, out2len); 146664562Sgshapiro } 146798121Sgshapiro# if SASL >= 20000 146898121Sgshapiro sm_free(out2); 146998121Sgshapiro# endif /* SASL >= 20000 */ 147064562Sgshapiro } 147164562Sgshapiro else 147264562Sgshapiro { 147364562Sgshapiro /* not SASL_OK or SASL_CONT */ 147498121Sgshapiro message("535 5.7.0 authentication failed"); 147564562Sgshapiro if (LogLevel > 9) 147664562Sgshapiro sm_syslog(LOG_WARNING, e->e_id, 1477203004Sgshapiro "AUTH failure (%s): %s (%d) %s, relay=%.100s", 147864562Sgshapiro auth_type, 147964562Sgshapiro sasl_errstring(result, NULL, 148064562Sgshapiro NULL), 148190792Sgshapiro result, 148298121Sgshapiro# if SASL >= 20000 1483203004Sgshapiro sasl_errdetail(conn), 148498121Sgshapiro# else /* SASL >= 20000 */ 1485203004Sgshapiro errstr == NULL ? "" : errstr, 148698121Sgshapiro# endif /* SASL >= 20000 */ 1487203004Sgshapiro CurSmtpClient); 1488120256Sgshapiro RESET_SASLCONN; 148964562Sgshapiro authenticating = SASL_NOT_AUTH; 149064562Sgshapiro } 149164562Sgshapiro } 149264562Sgshapiro else 149364562Sgshapiro { 149464562Sgshapiro /* don't want to do any of this if authenticating */ 149590792Sgshapiro#endif /* SASL */ 149664562Sgshapiro 149738032Speter /* echo command to transcript */ 149838032Speter if (e->e_xfp != NULL) 149990792Sgshapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 150090792Sgshapiro "<<< %s\n", inp); 150138032Speter 150290792Sgshapiro if (LogLevel > 14) 150390792Sgshapiro sm_syslog(LOG_INFO, e->e_id, "<-- %s", inp); 150438032Speter 150538032Speter /* break off command */ 150638032Speter for (p = inp; isascii(*p) && isspace(*p); p++) 150738032Speter continue; 150838032Speter cmd = cmdbuf; 150938032Speter while (*p != '\0' && 151038032Speter !(isascii(*p) && isspace(*p)) && 1511168515Sgshapiro cmd < &cmdbuf[sizeof(cmdbuf) - 2]) 151238032Speter *cmd++ = *p++; 151338032Speter *cmd = '\0'; 151438032Speter 151538032Speter /* throw away leading whitespace */ 151690792Sgshapiro SKIP_SPACE(p); 151738032Speter 151838032Speter /* decode command */ 151964562Sgshapiro for (c = CmdTab; c->cmd_name != NULL; c++) 152038032Speter { 152190792Sgshapiro if (sm_strcasecmp(c->cmd_name, cmdbuf) == 0) 152238032Speter break; 152338032Speter } 152438032Speter 152538032Speter /* reset errors */ 152638032Speter errno = 0; 152738032Speter 152890792Sgshapiro /* check whether a "non-null" command has been used */ 152990792Sgshapiro switch (c->cmd_code) 153090792Sgshapiro { 153190792Sgshapiro#if SASL 153290792Sgshapiro case CMDAUTH: 153390792Sgshapiro /* avoid information leak; take first two words? */ 153490792Sgshapiro q = "AUTH"; 153590792Sgshapiro break; 153690792Sgshapiro#endif /* SASL */ 153790792Sgshapiro 153890792Sgshapiro case CMDMAIL: 153990792Sgshapiro case CMDEXPN: 154090792Sgshapiro case CMDVRFY: 154190792Sgshapiro case CMDETRN: 154290792Sgshapiro lognullconnection = false; 154390792Sgshapiro /* FALLTHROUGH */ 154490792Sgshapiro default: 154590792Sgshapiro q = inp; 154690792Sgshapiro break; 154790792Sgshapiro } 154890792Sgshapiro 154990792Sgshapiro if (e->e_id == NULL) 155090792Sgshapiro sm_setproctitle(true, e, "%s: %.80s", 155190792Sgshapiro CurSmtpClient, q); 155290792Sgshapiro else 155390792Sgshapiro sm_setproctitle(true, e, "%s %s: %.80s", 155490792Sgshapiro qid_printname(e), 155590792Sgshapiro CurSmtpClient, q); 155690792Sgshapiro 155738032Speter /* 155838032Speter ** Process command. 155938032Speter ** 156038032Speter ** If we are running as a null server, return 550 156190792Sgshapiro ** to almost everything. 156238032Speter */ 156338032Speter 156464562Sgshapiro if (nullserver != NULL || bitnset(D_ETRNONLY, d_flags)) 156538032Speter { 156664562Sgshapiro switch (c->cmd_code) 156738032Speter { 156838032Speter case CMDQUIT: 156938032Speter case CMDHELO: 157038032Speter case CMDEHLO: 157138032Speter case CMDNOOP: 157264562Sgshapiro case CMDRSET: 1573125820Sgshapiro case CMDERROR: 157438032Speter /* process normally */ 157538032Speter break; 157638032Speter 157764562Sgshapiro case CMDETRN: 157864562Sgshapiro if (bitnset(D_ETRNONLY, d_flags) && 157964562Sgshapiro nullserver == NULL) 158064562Sgshapiro break; 158190792Sgshapiro DELAY_CONN("ETRN"); 158280785Sgshapiro /* FALLTHROUGH */ 158364562Sgshapiro 158438032Speter default: 158590792Sgshapiro#if MAXBADCOMMANDS > 0 158690792Sgshapiro /* theoretically this could overflow */ 158790792Sgshapiro if (nullserver != NULL && 158890792Sgshapiro ++n_badcmds > MAXBADCOMMANDS) 158964562Sgshapiro { 159090792Sgshapiro message("421 4.7.0 %s Too many bad commands; closing connection", 159190792Sgshapiro MyHostName); 159290792Sgshapiro 159390792Sgshapiro /* arrange to ignore send list */ 159490792Sgshapiro e->e_sendqueue = NULL; 159590792Sgshapiro goto doquit; 159664562Sgshapiro } 159790792Sgshapiro#endif /* MAXBADCOMMANDS > 0 */ 159864562Sgshapiro if (nullserver != NULL) 159964562Sgshapiro { 160064562Sgshapiro if (ISSMTPREPLY(nullserver)) 160164562Sgshapiro usrerr(nullserver); 160264562Sgshapiro else 160390792Sgshapiro usrerr("550 5.0.0 %s", 160490792Sgshapiro nullserver); 160564562Sgshapiro } 160664562Sgshapiro else 160764562Sgshapiro usrerr("452 4.4.5 Insufficient disk space; try again later"); 160838032Speter continue; 160938032Speter } 161038032Speter } 161138032Speter 161264562Sgshapiro switch (c->cmd_code) 161338032Speter { 161490792Sgshapiro#if SASL 161564562Sgshapiro case CMDAUTH: /* sasl */ 161690792Sgshapiro DELAY_CONN("AUTH"); 161790792Sgshapiro if (!sasl_ok || n_mechs <= 0) 161864562Sgshapiro { 161964562Sgshapiro message("503 5.3.3 AUTH not available"); 162064562Sgshapiro break; 162164562Sgshapiro } 162264562Sgshapiro if (authenticating == SASL_IS_AUTH) 162364562Sgshapiro { 162464562Sgshapiro message("503 5.5.0 Already Authenticated"); 162564562Sgshapiro break; 162664562Sgshapiro } 162790792Sgshapiro if (smtp.sm_gotmail) 162864562Sgshapiro { 162964562Sgshapiro message("503 5.5.0 AUTH not permitted during a mail transaction"); 163064562Sgshapiro break; 163164562Sgshapiro } 163264562Sgshapiro if (tempfail) 163364562Sgshapiro { 163464562Sgshapiro if (LogLevel > 9) 163564562Sgshapiro sm_syslog(LOG_INFO, e->e_id, 1636110560Sgshapiro "SMTP AUTH command (%.100s) from %s tempfailed (due to previous checks)", 163764562Sgshapiro p, CurSmtpClient); 1638132943Sgshapiro usrerr("454 4.3.0 Please try again later"); 163964562Sgshapiro break; 164064562Sgshapiro } 164164562Sgshapiro 164290792Sgshapiro ismore = false; 164364562Sgshapiro 164464562Sgshapiro /* crude way to avoid crack attempts */ 1645132943Sgshapiro STOP_IF_ATTACK(checksmtpattack(&n_auth, n_mechs + 1, 1646132943Sgshapiro true, "AUTH", e)); 164764562Sgshapiro 164890792Sgshapiro /* make sure mechanism (p) is a valid string */ 164964562Sgshapiro for (q = p; *q != '\0' && isascii(*q); q++) 165064562Sgshapiro { 165164562Sgshapiro if (isspace(*q)) 165264562Sgshapiro { 165364562Sgshapiro *q = '\0'; 165464562Sgshapiro while (*++q != '\0' && 165564562Sgshapiro isascii(*q) && isspace(*q)) 165664562Sgshapiro continue; 165764562Sgshapiro *(q - 1) = '\0'; 165864562Sgshapiro ismore = (*q != '\0'); 165964562Sgshapiro break; 166064562Sgshapiro } 166164562Sgshapiro } 166264562Sgshapiro 166398121Sgshapiro if (*p == '\0') 166498121Sgshapiro { 166598121Sgshapiro message("501 5.5.2 AUTH mechanism must be specified"); 166698121Sgshapiro break; 166798121Sgshapiro } 166898121Sgshapiro 166964562Sgshapiro /* check whether mechanism is available */ 167064562Sgshapiro if (iteminlist(p, mechlist, " ") == NULL) 167164562Sgshapiro { 167298121Sgshapiro message("504 5.3.3 AUTH mechanism %.32s not available", 167364562Sgshapiro p); 167464562Sgshapiro break; 167564562Sgshapiro } 167664562Sgshapiro 1677173340Sgshapiro /* 1678173340Sgshapiro ** RFC 2554 4. 1679173340Sgshapiro ** Unlike a zero-length client answer to a 1680173340Sgshapiro ** 334 reply, a zero- length initial response 1681173340Sgshapiro ** is sent as a single equals sign ("="). 1682173340Sgshapiro */ 1683173340Sgshapiro 1684173340Sgshapiro if (ismore && *q == '=' && *(q + 1) == '\0') 168564562Sgshapiro { 1686173340Sgshapiro /* will be free()d, don't use in=""; */ 1687173340Sgshapiro in = xalloc(1); 1688173340Sgshapiro *in = '\0'; 1689173340Sgshapiro inlen = 0; 1690173340Sgshapiro } 1691173340Sgshapiro else if (ismore) 1692173340Sgshapiro { 169364562Sgshapiro /* could this be shorter? XXX */ 169498121Sgshapiro# if SASL >= 20000 169598121Sgshapiro in = xalloc(strlen(q) + 1); 1696102528Sgshapiro result = sasl_decode64(q, strlen(q), in, 169798121Sgshapiro strlen(q), &inlen); 169898121Sgshapiro# else /* SASL >= 20000 */ 169990792Sgshapiro in = sm_rpool_malloc(e->e_rpool, strlen(q)); 170064562Sgshapiro result = sasl_decode64(q, strlen(q), in, 170190792Sgshapiro &inlen); 170298121Sgshapiro# endif /* SASL >= 20000 */ 170364562Sgshapiro if (result != SASL_OK) 170464562Sgshapiro { 170564562Sgshapiro message("501 5.5.4 cannot BASE64 decode '%s'", 170664562Sgshapiro q); 170764562Sgshapiro if (LogLevel > 5) 170864562Sgshapiro sm_syslog(LOG_WARNING, e->e_id, 1709203004Sgshapiro "AUTH decode64 error [%d for \"%s\"], relay=%.100s", 1710203004Sgshapiro result, q, 1711203004Sgshapiro CurSmtpClient); 171264562Sgshapiro /* start over? */ 171364562Sgshapiro authenticating = SASL_NOT_AUTH; 171498121Sgshapiro# if SASL >= 20000 171598121Sgshapiro sm_free(in); 171698121Sgshapiro# endif /* SASL >= 20000 */ 171764562Sgshapiro in = NULL; 171864562Sgshapiro inlen = 0; 171964562Sgshapiro break; 172064562Sgshapiro } 172164562Sgshapiro } 172264562Sgshapiro else 172364562Sgshapiro { 172464562Sgshapiro in = NULL; 172564562Sgshapiro inlen = 0; 172664562Sgshapiro } 172764562Sgshapiro 172864562Sgshapiro /* see if that auth type exists */ 172998121Sgshapiro# if SASL >= 20000 1730102528Sgshapiro result = sasl_server_start(conn, p, in, inlen, 173198121Sgshapiro &out, &outlen); 173298121Sgshapiro if (in != NULL) 173398121Sgshapiro sm_free(in); 173498121Sgshapiro# else /* SASL >= 20000 */ 173564562Sgshapiro result = sasl_server_start(conn, p, in, inlen, 173664562Sgshapiro &out, &outlen, &errstr); 173798121Sgshapiro# endif /* SASL >= 20000 */ 173864562Sgshapiro 173964562Sgshapiro if (result != SASL_OK && result != SASL_CONTINUE) 174064562Sgshapiro { 174198121Sgshapiro message("535 5.7.0 authentication failed"); 174264562Sgshapiro if (LogLevel > 9) 174364562Sgshapiro sm_syslog(LOG_ERR, e->e_id, 1744203004Sgshapiro "AUTH failure (%s): %s (%d) %s, relay=%.100s", 174564562Sgshapiro p, 174664562Sgshapiro sasl_errstring(result, NULL, 174764562Sgshapiro NULL), 174890792Sgshapiro result, 174998121Sgshapiro# if SASL >= 20000 1750203004Sgshapiro sasl_errdetail(conn), 175198121Sgshapiro# else /* SASL >= 20000 */ 1752203004Sgshapiro errstr, 175398121Sgshapiro# endif /* SASL >= 20000 */ 1754203004Sgshapiro CurSmtpClient); 1755120256Sgshapiro RESET_SASLCONN; 175664562Sgshapiro break; 175764562Sgshapiro } 175864562Sgshapiro auth_type = newstr(p); 175964562Sgshapiro 176064562Sgshapiro if (result == SASL_OK) 176164562Sgshapiro { 176264562Sgshapiro /* ugly, but same code */ 176364562Sgshapiro goto authenticated; 176464562Sgshapiro /* authenticated by the initial response */ 176564562Sgshapiro } 176664562Sgshapiro 176764562Sgshapiro /* len is at least 2 */ 176864562Sgshapiro len = ENC64LEN(outlen); 176964562Sgshapiro out2 = xalloc(len); 177064562Sgshapiro result = sasl_encode64(out, outlen, out2, len, 177190792Sgshapiro &out2len); 177264562Sgshapiro 177364562Sgshapiro if (result != SASL_OK) 177464562Sgshapiro { 177564562Sgshapiro message("454 4.5.4 Temporary authentication failure"); 177664562Sgshapiro if (LogLevel > 5) 177764562Sgshapiro sm_syslog(LOG_WARNING, e->e_id, 177890792Sgshapiro "AUTH encode64 error [%d for \"%s\"]", 177964562Sgshapiro result, out); 178064562Sgshapiro 178164562Sgshapiro /* start over? */ 178264562Sgshapiro authenticating = SASL_NOT_AUTH; 1783120256Sgshapiro RESET_SASLCONN; 178464562Sgshapiro } 178564562Sgshapiro else 178664562Sgshapiro { 178764562Sgshapiro message("334 %s", out2); 178864562Sgshapiro authenticating = SASL_PROC_AUTH; 178964562Sgshapiro } 179098121Sgshapiro# if SASL >= 20000 179198121Sgshapiro sm_free(out2); 179298121Sgshapiro# endif /* SASL >= 20000 */ 179364562Sgshapiro break; 179490792Sgshapiro#endif /* SASL */ 179564562Sgshapiro 179690792Sgshapiro#if STARTTLS 179764562Sgshapiro case CMDSTLS: /* starttls */ 179890792Sgshapiro DELAY_CONN("STARTTLS"); 179964562Sgshapiro if (*p != '\0') 180064562Sgshapiro { 180164562Sgshapiro message("501 5.5.2 Syntax error (no parameters allowed)"); 180264562Sgshapiro break; 180364562Sgshapiro } 180490792Sgshapiro if (!bitset(SRV_OFFER_TLS, features)) 180564562Sgshapiro { 180664562Sgshapiro message("503 5.5.0 TLS not available"); 180764562Sgshapiro break; 180864562Sgshapiro } 180977349Sgshapiro if (!tls_ok_srv) 181064562Sgshapiro { 181164562Sgshapiro message("454 4.3.3 TLS not available after start"); 181264562Sgshapiro break; 181364562Sgshapiro } 181490792Sgshapiro if (smtp.sm_gotmail) 181564562Sgshapiro { 181664562Sgshapiro message("503 5.5.0 TLS not permitted during a mail transaction"); 181764562Sgshapiro break; 181864562Sgshapiro } 181964562Sgshapiro if (tempfail) 182064562Sgshapiro { 182164562Sgshapiro if (LogLevel > 9) 182264562Sgshapiro sm_syslog(LOG_INFO, e->e_id, 1823110560Sgshapiro "SMTP STARTTLS command (%.100s) from %s tempfailed (due to previous checks)", 182464562Sgshapiro p, CurSmtpClient); 1825132943Sgshapiro usrerr("454 4.7.0 Please try again later"); 182664562Sgshapiro break; 182764562Sgshapiro } 182890792Sgshapiro starttls: 1829223067Sgshapiro# if USE_OPENSSL_ENGINE 1830223067Sgshapiro if (!SSLEngineInitialized) 1831223067Sgshapiro { 1832223067Sgshapiro if (!SSL_set_engine(NULL)) 1833223067Sgshapiro { 1834223067Sgshapiro sm_syslog(LOG_ERR, NOQID, 1835223067Sgshapiro "STARTTLS=server, SSL_set_engine=failed"); 1836223067Sgshapiro tls_ok_srv = false; 1837223067Sgshapiro message("454 4.3.3 TLS not available right now"); 1838223067Sgshapiro break; 1839223067Sgshapiro } 1840223067Sgshapiro else 1841223067Sgshapiro SSLEngineInitialized = true; 1842223067Sgshapiro } 1843223067Sgshapiro# endif /* USE_OPENSSL_ENGINE */ 184464562Sgshapiro# if TLS_NO_RSA 184564562Sgshapiro /* 184664562Sgshapiro ** XXX do we need a temp key ? 184764562Sgshapiro */ 184864562Sgshapiro# else /* TLS_NO_RSA */ 184964562Sgshapiro# endif /* TLS_NO_RSA */ 185090792Sgshapiro 185190792Sgshapiro# if TLS_VRFY_PER_CTX 185290792Sgshapiro /* 185390792Sgshapiro ** Note: this sets the verification globally 185490792Sgshapiro ** (per SSL_CTX) 185590792Sgshapiro ** it's ok since it applies only to one transaction 185690792Sgshapiro */ 185790792Sgshapiro 185890792Sgshapiro TLS_VERIFY_CLIENT(); 185990792Sgshapiro# endif /* TLS_VRFY_PER_CTX */ 186090792Sgshapiro 186164562Sgshapiro if (srv_ssl != NULL) 186264562Sgshapiro SSL_clear(srv_ssl); 186364562Sgshapiro else if ((srv_ssl = SSL_new(srv_ctx)) == NULL) 186464562Sgshapiro { 186564562Sgshapiro message("454 4.3.3 TLS not available: error generating SSL handle"); 1866120256Sgshapiro if (LogLevel > 8) 1867249865Sgshapiro tlslogerr(LOG_WARNING, "server"); 186890792Sgshapiro goto tls_done; 186964562Sgshapiro } 187090792Sgshapiro 187190792Sgshapiro# if !TLS_VRFY_PER_CTX 187290792Sgshapiro /* 187390792Sgshapiro ** this could be used if it were possible to set 187490792Sgshapiro ** verification per SSL (connection) 187590792Sgshapiro ** not just per SSL_CTX (global) 187690792Sgshapiro */ 187790792Sgshapiro 187890792Sgshapiro TLS_VERIFY_CLIENT(); 187990792Sgshapiro# endif /* !TLS_VRFY_PER_CTX */ 188090792Sgshapiro 188190792Sgshapiro rfd = sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL); 188290792Sgshapiro wfd = sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL); 188390792Sgshapiro 188466494Sgshapiro if (rfd < 0 || wfd < 0 || 188566494Sgshapiro SSL_set_rfd(srv_ssl, rfd) <= 0 || 188666494Sgshapiro SSL_set_wfd(srv_ssl, wfd) <= 0) 188764562Sgshapiro { 188864562Sgshapiro message("454 4.3.3 TLS not available: error set fd"); 188964562Sgshapiro SSL_free(srv_ssl); 189064562Sgshapiro srv_ssl = NULL; 189190792Sgshapiro goto tls_done; 189264562Sgshapiro } 189390792Sgshapiro if (!smtps) 189490792Sgshapiro message("220 2.0.0 Ready to start TLS"); 189590792Sgshapiro# if PIPELINING 189690792Sgshapiro (void) sm_io_flush(OutChannel, SM_TIME_DEFAULT); 189790792Sgshapiro# endif /* PIPELINING */ 189890792Sgshapiro 189964562Sgshapiro SSL_set_accept_state(srv_ssl); 190064562Sgshapiro 190164562Sgshapiro# define SSL_ACC(s) SSL_accept(s) 190290792Sgshapiro 190390792Sgshapiro tlsstart = curtime(); 190490792Sgshapiro ssl_retry: 190564562Sgshapiro if ((r = SSL_ACC(srv_ssl)) <= 0) 190664562Sgshapiro { 1907157001Sgshapiro int i, ssl_err; 190864562Sgshapiro 1909157001Sgshapiro ssl_err = SSL_get_error(srv_ssl, r); 1910157001Sgshapiro i = tls_retry(srv_ssl, rfd, wfd, tlsstart, 1911157001Sgshapiro TimeOuts.to_starttls, ssl_err, 1912157001Sgshapiro "server"); 1913157001Sgshapiro if (i > 0) 1914157001Sgshapiro goto ssl_retry; 191590792Sgshapiro 191664562Sgshapiro if (LogLevel > 5) 191764562Sgshapiro { 1918244928Sgshapiro unsigned long l; 1919244928Sgshapiro const char *sr; 1920244928Sgshapiro 1921244928Sgshapiro l = ERR_peek_error(); 1922244928Sgshapiro sr = ERR_reason_error_string(l); 192390792Sgshapiro sm_syslog(LOG_WARNING, NOQID, 1924244928Sgshapiro "STARTTLS=server, error: accept failed=%d, reason=%s, SSL_error=%d, errno=%d, retry=%d, relay=%.100s", 1925244928Sgshapiro r, sr == NULL ? "unknown" 1926244928Sgshapiro : sr, 1927244928Sgshapiro ssl_err, errno, i, 1928203004Sgshapiro CurSmtpClient); 1929244928Sgshapiro if (LogLevel > 9) 1930249865Sgshapiro tlslogerr(LOG_WARNING, "server"); 193164562Sgshapiro } 193290792Sgshapiro tls_ok_srv = false; 193364562Sgshapiro SSL_free(srv_ssl); 193464562Sgshapiro srv_ssl = NULL; 193564562Sgshapiro 193664562Sgshapiro /* 193764562Sgshapiro ** according to the next draft of 193864562Sgshapiro ** RFC 2487 the connection should be dropped 193964562Sgshapiro */ 194064562Sgshapiro 194164562Sgshapiro /* arrange to ignore any current send list */ 194264562Sgshapiro e->e_sendqueue = NULL; 194364562Sgshapiro goto doquit; 194464562Sgshapiro } 194564562Sgshapiro 194664562Sgshapiro /* ignore return code for now, it's in {verify} */ 194790792Sgshapiro (void) tls_get_info(srv_ssl, true, 194890792Sgshapiro CurSmtpClient, 194990792Sgshapiro &BlankEnvelope.e_macro, 195090792Sgshapiro bitset(SRV_VRFY_CLT, features)); 195164562Sgshapiro 195264562Sgshapiro /* 195364562Sgshapiro ** call Stls_client to find out whether 195464562Sgshapiro ** to accept the connection from the client 195564562Sgshapiro */ 195664562Sgshapiro 195764562Sgshapiro saveQuickAbort = QuickAbort; 195864562Sgshapiro saveSuprErrs = SuprErrs; 195990792Sgshapiro SuprErrs = true; 196090792Sgshapiro QuickAbort = false; 196164562Sgshapiro if (rscheck("tls_client", 196290792Sgshapiro macvalue(macid("{verify}"), e), 1963102528Sgshapiro "STARTTLS", e, 1964102528Sgshapiro RSF_RMCOMM|RSF_COUNT, 1965168515Sgshapiro 5, NULL, NOQID, NULL) != EX_OK || 196690792Sgshapiro Errors > 0) 196764562Sgshapiro { 196864562Sgshapiro extern char MsgBuf[]; 196964562Sgshapiro 197064562Sgshapiro if (MsgBuf[0] != '\0' && ISSMTPREPLY(MsgBuf)) 197164562Sgshapiro nullserver = newstr(MsgBuf); 197264562Sgshapiro else 197364562Sgshapiro nullserver = "503 5.7.0 Authentication required."; 197464562Sgshapiro } 197564562Sgshapiro QuickAbort = saveQuickAbort; 197664562Sgshapiro SuprErrs = saveSuprErrs; 197764562Sgshapiro 197890792Sgshapiro tls_ok_srv = false; /* don't offer STARTTLS again */ 197964562Sgshapiro n_helo = 0; 198090792Sgshapiro# if SASL 198164562Sgshapiro if (sasl_ok) 198264562Sgshapiro { 1983132943Sgshapiro int cipher_bits; 1984132943Sgshapiro bool verified; 1985132943Sgshapiro char *s, *v, *c; 198664562Sgshapiro 198790792Sgshapiro s = macvalue(macid("{cipher_bits}"), e); 1988132943Sgshapiro v = macvalue(macid("{verify}"), e); 1989132943Sgshapiro c = macvalue(macid("{cert_subject}"), e); 1990132943Sgshapiro verified = (v != NULL && strcmp(v, "OK") == 0); 1991132943Sgshapiro if (s != NULL && (cipher_bits = atoi(s)) > 0) 1992132943Sgshapiro { 199398121Sgshapiro# if SASL >= 20000 1994132943Sgshapiro ext_ssf = cipher_bits; 1995132943Sgshapiro auth_id = verified ? c : NULL; 1996132943Sgshapiro sasl_ok = ((sasl_setprop(conn, 1997132943Sgshapiro SASL_SSF_EXTERNAL, 1998132943Sgshapiro &ext_ssf) == SASL_OK) && 1999132943Sgshapiro (sasl_setprop(conn, 2000132943Sgshapiro SASL_AUTH_EXTERNAL, 2001132943Sgshapiro auth_id) == SASL_OK)); 200298121Sgshapiro# else /* SASL >= 20000 */ 2003132943Sgshapiro ext_ssf.ssf = cipher_bits; 2004132943Sgshapiro ext_ssf.auth_id = verified ? c : NULL; 2005132943Sgshapiro sasl_ok = sasl_setprop(conn, 2006132943Sgshapiro SASL_SSF_EXTERNAL, 2007132943Sgshapiro &ext_ssf) == SASL_OK; 200898121Sgshapiro# endif /* SASL >= 20000 */ 200964562Sgshapiro mechlist = NULL; 201064562Sgshapiro if (sasl_ok) 201164562Sgshapiro n_mechs = saslmechs(conn, 201264562Sgshapiro &mechlist); 201364562Sgshapiro } 201464562Sgshapiro } 201590792Sgshapiro# endif /* SASL */ 201664562Sgshapiro 201764562Sgshapiro /* switch to secure connection */ 201890792Sgshapiro if (sfdctls(&InChannel, &OutChannel, srv_ssl) == 0) 201990792Sgshapiro { 202090792Sgshapiro tls_active = true; 202190792Sgshapiro# if PIPELINING 202290792Sgshapiro (void) sm_io_autoflush(InChannel, OutChannel); 202390792Sgshapiro# endif /* PIPELINING */ 202490792Sgshapiro } 202564562Sgshapiro else 202664562Sgshapiro { 202764562Sgshapiro /* 202864562Sgshapiro ** XXX this is an internal error 202964562Sgshapiro ** how to deal with it? 203064562Sgshapiro ** we can't generate an error message 203164562Sgshapiro ** since the other side switched to an 203264562Sgshapiro ** encrypted layer, but we could not... 203364562Sgshapiro ** just "hang up"? 203464562Sgshapiro */ 203590792Sgshapiro 203664562Sgshapiro nullserver = "454 4.3.3 TLS not available: can't switch to encrypted layer"; 203790792Sgshapiro syserr("STARTTLS: can't switch to encrypted layer"); 203864562Sgshapiro } 203990792Sgshapiro tls_done: 204090792Sgshapiro if (smtps) 204190792Sgshapiro { 204290792Sgshapiro if (tls_active) 204390792Sgshapiro goto greeting; 204490792Sgshapiro else 204590792Sgshapiro goto doquit; 204690792Sgshapiro } 204764562Sgshapiro break; 204890792Sgshapiro#endif /* STARTTLS */ 204964562Sgshapiro 205038032Speter case CMDHELO: /* hello -- introduce yourself */ 205138032Speter case CMDEHLO: /* extended hello */ 205290792Sgshapiro DELAY_CONN("EHLO"); 205364562Sgshapiro if (c->cmd_code == CMDEHLO) 205438032Speter { 205538032Speter protocol = "ESMTP"; 205638032Speter SmtpPhase = "server EHLO"; 205738032Speter } 205838032Speter else 205938032Speter { 206038032Speter protocol = "SMTP"; 206138032Speter SmtpPhase = "server HELO"; 206238032Speter } 206338032Speter 206438032Speter /* avoid denial-of-service */ 2065132943Sgshapiro STOP_IF_ATTACK(checksmtpattack(&n_helo, MAXHELOCOMMANDS, 2066132943Sgshapiro true, "HELO/EHLO", e)); 206738032Speter 206890792Sgshapiro#if 0 206990792Sgshapiro /* RFC2821 4.1.4 allows duplicate HELO/EHLO */ 207038032Speter /* check for duplicate HELO/EHLO per RFC 1651 4.2 */ 207138032Speter if (gothello) 207238032Speter { 207338032Speter usrerr("503 %s Duplicate HELO/EHLO", 207473188Sgshapiro MyHostName); 207538032Speter break; 207638032Speter } 207790792Sgshapiro#endif /* 0 */ 207838032Speter 207938032Speter /* check for valid domain name (re 1123 5.2.5) */ 208038032Speter if (*p == '\0' && !AllowBogusHELO) 208138032Speter { 208238032Speter usrerr("501 %s requires domain address", 208338032Speter cmdbuf); 208438032Speter break; 208538032Speter } 208638032Speter 208738032Speter /* check for long domain name (hides Received: info) */ 208838032Speter if (strlen(p) > MAXNAME) 208938032Speter { 209038032Speter usrerr("501 Invalid domain name"); 209164562Sgshapiro if (LogLevel > 9) 209264562Sgshapiro sm_syslog(LOG_INFO, CurEnv->e_id, 2093110560Sgshapiro "invalid domain name (too long) from %s", 209464562Sgshapiro CurSmtpClient); 209538032Speter break; 209638032Speter } 209738032Speter 209898121Sgshapiro ok = true; 209938032Speter for (q = p; *q != '\0'; q++) 210038032Speter { 210138032Speter if (!isascii(*q)) 210238032Speter break; 210338032Speter if (isalnum(*q)) 210438032Speter continue; 210538032Speter if (isspace(*q)) 210638032Speter { 210738032Speter *q = '\0'; 210898121Sgshapiro 210998121Sgshapiro /* only complain if strict check */ 211098121Sgshapiro ok = AllowBogusHELO; 2111141858Sgshapiro 2112141858Sgshapiro /* allow trailing whitespace */ 2113141858Sgshapiro while (!ok && *++q != '\0' && 2114141858Sgshapiro isspace(*q)) 2115141858Sgshapiro ; 2116141858Sgshapiro if (*q == '\0') 2117141858Sgshapiro ok = true; 211838032Speter break; 211938032Speter } 2120120256Sgshapiro if (strchr("[].-_#:", *q) == NULL) 212138032Speter break; 212238032Speter } 212364562Sgshapiro 212498121Sgshapiro if (*q == '\0' && ok) 212538032Speter { 212638032Speter q = "pleased to meet you"; 212790792Sgshapiro sendinghost = sm_strdup_x(p); 212838032Speter } 212938032Speter else if (!AllowBogusHELO) 213038032Speter { 213138032Speter usrerr("501 Invalid domain name"); 213264562Sgshapiro if (LogLevel > 9) 213364562Sgshapiro sm_syslog(LOG_INFO, CurEnv->e_id, 2134110560Sgshapiro "invalid domain name (%s) from %.100s", 213564562Sgshapiro p, CurSmtpClient); 213638032Speter break; 213738032Speter } 213838032Speter else 213938032Speter { 214038032Speter q = "accepting invalid domain name"; 214138032Speter } 214238032Speter 2143157001Sgshapiro if (gothello || smtp.sm_gotmail) 214490792Sgshapiro CLEAR_STATE(cmdbuf); 214590792Sgshapiro 214690792Sgshapiro#if MILTER 214790792Sgshapiro if (smtp.sm_milterlist && smtp.sm_milterize && 214890792Sgshapiro !bitset(EF_DISCARD, e->e_flags)) 214964562Sgshapiro { 215064562Sgshapiro char state; 215164562Sgshapiro char *response; 215264562Sgshapiro 215364562Sgshapiro response = milter_helo(p, e, &state); 215464562Sgshapiro switch (state) 215564562Sgshapiro { 215664562Sgshapiro case SMFIR_REJECT: 215790792Sgshapiro if (MilterLogLevel > 3) 215890792Sgshapiro sm_syslog(LOG_INFO, e->e_id, 215990792Sgshapiro "Milter: helo=%s, reject=Command rejected", 216090792Sgshapiro p); 216164562Sgshapiro nullserver = "Command rejected"; 216290792Sgshapiro smtp.sm_milterize = false; 216364562Sgshapiro break; 216464562Sgshapiro 216564562Sgshapiro case SMFIR_TEMPFAIL: 216690792Sgshapiro if (MilterLogLevel > 3) 216790792Sgshapiro sm_syslog(LOG_INFO, e->e_id, 216890792Sgshapiro "Milter: helo=%s, reject=%s", 216990792Sgshapiro p, MSG_TEMPFAIL); 217090792Sgshapiro tempfail = true; 217190792Sgshapiro smtp.sm_milterize = false; 217264562Sgshapiro break; 2173157001Sgshapiro 2174168515Sgshapiro case SMFIR_REPLYCODE: 2175157001Sgshapiro if (MilterLogLevel > 3) 2176157001Sgshapiro sm_syslog(LOG_INFO, e->e_id, 2177168515Sgshapiro "Milter: helo=%s, reject=%s", 2178168515Sgshapiro p, response); 2179168515Sgshapiro if (strncmp(response, "421 ", 4) != 0 2180168515Sgshapiro && strncmp(response, "421-", 4) != 0) 2181168515Sgshapiro { 2182168515Sgshapiro nullserver = newstr(response); 2183168515Sgshapiro smtp.sm_milterize = false; 2184168515Sgshapiro break; 2185168515Sgshapiro } 2186168515Sgshapiro /* FALLTHROUGH */ 2187168515Sgshapiro 2188168515Sgshapiro case SMFIR_SHUTDOWN: 2189168515Sgshapiro if (MilterLogLevel > 3 && 2190168515Sgshapiro response == NULL) 2191168515Sgshapiro sm_syslog(LOG_INFO, e->e_id, 2192159609Sgshapiro "Milter: helo=%s, reject=421 4.7.0 %s closing connection", 2193157001Sgshapiro p, MyHostName); 2194157001Sgshapiro tempfail = true; 2195157001Sgshapiro smtp.sm_milterize = false; 2196168515Sgshapiro if (response != NULL) 2197168515Sgshapiro usrerr(response); 2198168515Sgshapiro else 2199168515Sgshapiro message("421 4.7.0 %s closing connection", 2200168515Sgshapiro MyHostName); 2201157001Sgshapiro /* arrange to ignore send list */ 2202157001Sgshapiro e->e_sendqueue = NULL; 2203168515Sgshapiro lognullconnection = false; 2204157001Sgshapiro goto doquit; 220564562Sgshapiro } 220690792Sgshapiro if (response != NULL) 220790792Sgshapiro sm_free(response); 220890792Sgshapiro 220990792Sgshapiro /* 221090792Sgshapiro ** If quarantining by a connect/ehlo action, 221190792Sgshapiro ** save between messages 221290792Sgshapiro */ 221390792Sgshapiro 221490792Sgshapiro if (smtp.sm_quarmsg == NULL && 221590792Sgshapiro e->e_quarmsg != NULL) 221690792Sgshapiro smtp.sm_quarmsg = newstr(e->e_quarmsg); 221764562Sgshapiro } 221890792Sgshapiro#endif /* MILTER */ 221990792Sgshapiro gothello = true; 222064562Sgshapiro 222138032Speter /* print HELO response message */ 222264562Sgshapiro if (c->cmd_code != CMDEHLO) 222338032Speter { 222438032Speter message("250 %s Hello %s, %s", 222538032Speter MyHostName, CurSmtpClient, q); 222638032Speter break; 222738032Speter } 222838032Speter 222938032Speter message("250-%s Hello %s, %s", 223038032Speter MyHostName, CurSmtpClient, q); 223138032Speter 223264562Sgshapiro /* offer ENHSC even for nullserver */ 223364562Sgshapiro if (nullserver != NULL) 223464562Sgshapiro { 223564562Sgshapiro message("250 ENHANCEDSTATUSCODES"); 223664562Sgshapiro break; 223764562Sgshapiro } 223864562Sgshapiro 223966494Sgshapiro /* 224066494Sgshapiro ** print EHLO features list 224166494Sgshapiro ** 224266494Sgshapiro ** Note: If you change this list, 224390792Sgshapiro ** remember to update 'helpfile' 224466494Sgshapiro */ 224566494Sgshapiro 224664562Sgshapiro message("250-ENHANCEDSTATUSCODES"); 224790792Sgshapiro#if PIPELINING 224890792Sgshapiro if (bitset(SRV_OFFER_PIPE, features)) 224990792Sgshapiro message("250-PIPELINING"); 225090792Sgshapiro#endif /* PIPELINING */ 225190792Sgshapiro if (bitset(SRV_OFFER_EXPN, features)) 225238032Speter { 225338032Speter message("250-EXPN"); 225490792Sgshapiro if (bitset(SRV_OFFER_VERB, features)) 225538032Speter message("250-VERB"); 225638032Speter } 225790792Sgshapiro#if MIME8TO7 225838032Speter message("250-8BITMIME"); 225990792Sgshapiro#endif /* MIME8TO7 */ 226038032Speter if (MaxMessageSize > 0) 226138032Speter message("250-SIZE %ld", MaxMessageSize); 226238032Speter else 226338032Speter message("250-SIZE"); 226490792Sgshapiro#if DSN 226590792Sgshapiro if (SendMIMEErrors && bitset(SRV_OFFER_DSN, features)) 226638032Speter message("250-DSN"); 226790792Sgshapiro#endif /* DSN */ 226890792Sgshapiro if (bitset(SRV_OFFER_ETRN, features)) 226938032Speter message("250-ETRN"); 227090792Sgshapiro#if SASL 227164562Sgshapiro if (sasl_ok && mechlist != NULL && *mechlist != '\0') 227264562Sgshapiro message("250-AUTH %s", mechlist); 227390792Sgshapiro#endif /* SASL */ 227490792Sgshapiro#if STARTTLS 2275223067Sgshapiro if (tls_ok_srv && bitset(SRV_OFFER_TLS, features)) 227664562Sgshapiro message("250-STARTTLS"); 227790792Sgshapiro#endif /* STARTTLS */ 227890792Sgshapiro if (DeliverByMin > 0) 227990792Sgshapiro message("250-DELIVERBY %ld", 228090792Sgshapiro (long) DeliverByMin); 228190792Sgshapiro else if (DeliverByMin == 0) 228290792Sgshapiro message("250-DELIVERBY"); 228390792Sgshapiro 228490792Sgshapiro /* < 0: no deliver-by */ 228590792Sgshapiro 228638032Speter message("250 HELP"); 228738032Speter break; 228838032Speter 228938032Speter case CMDMAIL: /* mail -- designate sender */ 229038032Speter SmtpPhase = "server MAIL"; 229190792Sgshapiro DELAY_CONN("MAIL"); 229238032Speter 229338032Speter /* check for validity of this command */ 229438032Speter if (!gothello && bitset(PRIV_NEEDMAILHELO, PrivacyFlags)) 229538032Speter { 229664562Sgshapiro usrerr("503 5.0.0 Polite people say HELO first"); 229738032Speter break; 229838032Speter } 229990792Sgshapiro if (smtp.sm_gotmail) 230038032Speter { 230164562Sgshapiro usrerr("503 5.5.0 Sender already specified"); 230238032Speter break; 230338032Speter } 230490792Sgshapiro#if SASL 230590792Sgshapiro if (bitset(SRV_REQ_AUTH, features) && 230664562Sgshapiro authenticating != SASL_IS_AUTH) 230764562Sgshapiro { 230864562Sgshapiro usrerr("530 5.7.0 Authentication required"); 230964562Sgshapiro break; 231064562Sgshapiro } 231190792Sgshapiro#endif /* SASL */ 231238032Speter 231364562Sgshapiro p = skipword(p, "from"); 231464562Sgshapiro if (p == NULL) 231564562Sgshapiro break; 231664562Sgshapiro if (tempfail) 231764562Sgshapiro { 231864562Sgshapiro if (LogLevel > 9) 231964562Sgshapiro sm_syslog(LOG_INFO, e->e_id, 2320110560Sgshapiro "SMTP MAIL command (%.100s) from %s tempfailed (due to previous checks)", 232164562Sgshapiro p, CurSmtpClient); 232290792Sgshapiro usrerr(MSG_TEMPFAIL); 232364562Sgshapiro break; 232464562Sgshapiro } 232564562Sgshapiro 232638032Speter /* make sure we know who the sending host is */ 232738032Speter if (sendinghost == NULL) 232838032Speter sendinghost = peerhostname; 232938032Speter 233038032Speter 233190792Sgshapiro#if SM_HEAP_CHECK 233290792Sgshapiro if (sm_debug_active(&DebugLeakSmtp, 1)) 233390792Sgshapiro { 233490792Sgshapiro sm_heap_newgroup(); 233590792Sgshapiro sm_dprintf("smtp() heap group #%d\n", 233690792Sgshapiro sm_heap_group()); 233790792Sgshapiro } 233890792Sgshapiro#endif /* SM_HEAP_CHECK */ 233964562Sgshapiro 234038032Speter if (Errors > 0) 234190792Sgshapiro goto undo_no_pm; 234238032Speter if (!gothello) 234338032Speter { 234490792Sgshapiro auth_warning(e, "%s didn't use HELO protocol", 234590792Sgshapiro CurSmtpClient); 234638032Speter } 234790792Sgshapiro#ifdef PICKY_HELO_CHECK 234890792Sgshapiro if (sm_strcasecmp(sendinghost, peerhostname) != 0 && 234990792Sgshapiro (sm_strcasecmp(peerhostname, "localhost") != 0 || 235090792Sgshapiro sm_strcasecmp(sendinghost, MyHostName) != 0)) 235138032Speter { 235238032Speter auth_warning(e, "Host %s claimed to be %s", 235390792Sgshapiro CurSmtpClient, sendinghost); 235438032Speter } 235590792Sgshapiro#endif /* PICKY_HELO_CHECK */ 235638032Speter 235738032Speter if (protocol == NULL) 235838032Speter protocol = "SMTP"; 235990792Sgshapiro macdefine(&e->e_macro, A_PERM, 'r', protocol); 236090792Sgshapiro macdefine(&e->e_macro, A_PERM, 's', sendinghost); 236164562Sgshapiro 236238032Speter if (Errors > 0) 236390792Sgshapiro goto undo_no_pm; 236490792Sgshapiro smtp.sm_nrcpts = 0; 236590792Sgshapiro n_badrcpts = 0; 236690792Sgshapiro macdefine(&e->e_macro, A_PERM, macid("{ntries}"), "0"); 236790792Sgshapiro macdefine(&e->e_macro, A_PERM, macid("{nrcpts}"), "0"); 2368132943Sgshapiro macdefine(&e->e_macro, A_PERM, macid("{nbadrcpts}"), 2369132943Sgshapiro "0"); 237064562Sgshapiro e->e_flags |= EF_CLRQUEUE; 237190792Sgshapiro sm_setproctitle(true, e, "%s %s: %.80s", 237264562Sgshapiro qid_printname(e), 237364562Sgshapiro CurSmtpClient, inp); 237438032Speter 237590792Sgshapiro /* do the processing */ 237690792Sgshapiro SM_TRY 237790792Sgshapiro { 237894334Sgshapiro extern char *FullName; 237994334Sgshapiro 238090792Sgshapiro QuickAbort = true; 238194334Sgshapiro SM_FREE_CLR(FullName); 238264562Sgshapiro 238338032Speter /* must parse sender first */ 238438032Speter delimptr = NULL; 238590792Sgshapiro setsender(p, e, &delimptr, ' ', false); 238638032Speter if (delimptr != NULL && *delimptr != '\0') 238738032Speter *delimptr++ = '\0'; 238838032Speter if (Errors > 0) 238990792Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1); 239038032Speter 239164562Sgshapiro /* Successfully set e_from, allow logging */ 239264562Sgshapiro e->e_flags |= EF_LOGSENDER; 239338032Speter 239464562Sgshapiro /* put resulting triple from parseaddr() into macros */ 239564562Sgshapiro if (e->e_from.q_mailer != NULL) 239690792Sgshapiro macdefine(&e->e_macro, A_PERM, 239790792Sgshapiro macid("{mail_mailer}"), 239890792Sgshapiro e->e_from.q_mailer->m_name); 239964562Sgshapiro else 240090792Sgshapiro macdefine(&e->e_macro, A_PERM, 240190792Sgshapiro macid("{mail_mailer}"), NULL); 240264562Sgshapiro if (e->e_from.q_host != NULL) 240390792Sgshapiro macdefine(&e->e_macro, A_PERM, 240490792Sgshapiro macid("{mail_host}"), 240590792Sgshapiro e->e_from.q_host); 240664562Sgshapiro else 240790792Sgshapiro macdefine(&e->e_macro, A_PERM, 240890792Sgshapiro macid("{mail_host}"), "localhost"); 240964562Sgshapiro if (e->e_from.q_user != NULL) 241090792Sgshapiro macdefine(&e->e_macro, A_PERM, 241190792Sgshapiro macid("{mail_addr}"), 241290792Sgshapiro e->e_from.q_user); 241364562Sgshapiro else 241490792Sgshapiro macdefine(&e->e_macro, A_PERM, 241590792Sgshapiro macid("{mail_addr}"), NULL); 241664562Sgshapiro if (Errors > 0) 241790792Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1); 241864562Sgshapiro 241938032Speter /* check for possible spoofing */ 242038032Speter if (RealUid != 0 && OpMode == MD_SMTP && 242138032Speter !wordinclass(RealUserName, 't') && 242264562Sgshapiro (!bitnset(M_LOCALMAILER, 242364562Sgshapiro e->e_from.q_mailer->m_flags) || 242464562Sgshapiro strcmp(e->e_from.q_user, RealUserName) != 0)) 242538032Speter { 242638032Speter auth_warning(e, "%s owned process doing -bs", 242738032Speter RealUserName); 242838032Speter } 242938032Speter 2430120256Sgshapiro /* reset to default value */ 2431168515Sgshapiro SevenBitInput = SevenBitInput_Saved; 2432120256Sgshapiro 243338032Speter /* now parse ESMTP arguments */ 243438032Speter e->e_msgsize = 0; 243564562Sgshapiro addr = p; 2436168515Sgshapiro parse_esmtp_args(e, NULL, p, delimptr, "MAIL", args, 2437168515Sgshapiro mail_esmtp_args); 243838032Speter if (Errors > 0) 243990792Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1); 244038032Speter 244190792Sgshapiro#if SASL 244290792Sgshapiro# if _FFR_AUTH_PASSING 244390792Sgshapiro /* set the default AUTH= if the sender didn't */ 244490792Sgshapiro if (e->e_auth_param == NULL) 244590792Sgshapiro { 244690792Sgshapiro /* XXX only do this for an MSA? */ 244790792Sgshapiro e->e_auth_param = macvalue(macid("{auth_authen}"), 244890792Sgshapiro e); 244990792Sgshapiro if (e->e_auth_param == NULL) 245090792Sgshapiro e->e_auth_param = "<>"; 245190792Sgshapiro 245290792Sgshapiro /* 245390792Sgshapiro ** XXX should we invoke Strust_auth now? 245490792Sgshapiro ** authorizing as the client that just 245590792Sgshapiro ** authenticated, so we'll trust implicitly 245690792Sgshapiro */ 245790792Sgshapiro } 245890792Sgshapiro# endif /* _FFR_AUTH_PASSING */ 245990792Sgshapiro#endif /* SASL */ 246090792Sgshapiro 246164562Sgshapiro /* do config file checking of the sender */ 246290792Sgshapiro macdefine(&e->e_macro, A_PERM, 246390792Sgshapiro macid("{addr_type}"), "e s"); 246490792Sgshapiro#if _FFR_MAIL_MACRO 246590792Sgshapiro /* make the "real" sender address available */ 246690792Sgshapiro macdefine(&e->e_macro, A_TEMP, macid("{mail_from}"), 246790792Sgshapiro e->e_from.q_paddr); 246890792Sgshapiro#endif /* _FFR_MAIL_MACRO */ 246964562Sgshapiro if (rscheck("check_mail", addr, 2470102528Sgshapiro NULL, e, RSF_RMCOMM|RSF_COUNT, 3, 2471168515Sgshapiro NULL, e->e_id, NULL) != EX_OK || 247264562Sgshapiro Errors > 0) 247390792Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1); 247490792Sgshapiro macdefine(&e->e_macro, A_PERM, 247590792Sgshapiro macid("{addr_type}"), NULL); 247664562Sgshapiro 247766494Sgshapiro if (MaxMessageSize > 0 && 247877349Sgshapiro (e->e_msgsize > MaxMessageSize || 247977349Sgshapiro e->e_msgsize < 0)) 248038032Speter { 248164562Sgshapiro usrerr("552 5.2.3 Message size exceeds fixed maximum message size (%ld)", 248238032Speter MaxMessageSize); 248390792Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1); 248438032Speter } 248564562Sgshapiro 248690792Sgshapiro /* 248790792Sgshapiro ** XXX always check whether there is at least one fs 248890792Sgshapiro ** with enough space? 248990792Sgshapiro ** However, this may not help much: the queue group 249090792Sgshapiro ** selection may later on select a FS that hasn't 249190792Sgshapiro ** enough space. 249290792Sgshapiro */ 249390792Sgshapiro 249490792Sgshapiro if ((NumFileSys == 1 || NumQueue == 1) && 249590792Sgshapiro !enoughdiskspace(e->e_msgsize, e) 249690792Sgshapiro#if _FFR_ANY_FREE_FS 249790792Sgshapiro && !filesys_free(e->e_msgsize) 249890792Sgshapiro#endif /* _FFR_ANY_FREE_FS */ 249990792Sgshapiro ) 250038032Speter { 250190792Sgshapiro /* 250290792Sgshapiro ** We perform this test again when the 250390792Sgshapiro ** queue directory is selected, in collect. 250490792Sgshapiro */ 250590792Sgshapiro 250664562Sgshapiro usrerr("452 4.4.5 Insufficient disk space; try again later"); 250790792Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1); 250838032Speter } 250938032Speter if (Errors > 0) 251090792Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1); 251164562Sgshapiro 251290792Sgshapiro LogUsrErrs = true; 251390792Sgshapiro#if MILTER 251490792Sgshapiro if (smtp.sm_milterlist && smtp.sm_milterize && 251590792Sgshapiro !bitset(EF_DISCARD, e->e_flags)) 251664562Sgshapiro { 251764562Sgshapiro char state; 251864562Sgshapiro char *response; 251964562Sgshapiro 252064562Sgshapiro response = milter_envfrom(args, e, &state); 252190792Sgshapiro MILTER_REPLY("from"); 252264562Sgshapiro } 252390792Sgshapiro#endif /* MILTER */ 252464562Sgshapiro if (Errors > 0) 252590792Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1); 252664562Sgshapiro 252764562Sgshapiro message("250 2.1.0 Sender ok"); 252890792Sgshapiro smtp.sm_gotmail = true; 252990792Sgshapiro } 253090792Sgshapiro SM_EXCEPT(exc, "[!F]*") 253190792Sgshapiro { 253290792Sgshapiro /* 253390792Sgshapiro ** An error occurred while processing a MAIL command. 253490792Sgshapiro ** Jump to the common error handling code. 253590792Sgshapiro */ 253690792Sgshapiro 253790792Sgshapiro sm_exc_free(exc); 253890792Sgshapiro goto undo_no_pm; 253990792Sgshapiro } 254090792Sgshapiro SM_END_TRY 254138032Speter break; 254238032Speter 254390792Sgshapiro undo_no_pm: 254490792Sgshapiro e->e_flags &= ~EF_PM_NOTIFY; 254590792Sgshapiro undo: 254690792Sgshapiro break; 254790792Sgshapiro 254838032Speter case CMDRCPT: /* rcpt -- designate recipient */ 254990792Sgshapiro DELAY_CONN("RCPT"); 2550168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2551168515Sgshapiro macid("{rcpt_mailer}"), NULL); 2552168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2553168515Sgshapiro macid("{rcpt_host}"), NULL); 2554168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2555168515Sgshapiro macid("{rcpt_addr}"), NULL); 2556168515Sgshapiro#if MILTER 2557168515Sgshapiro (void) memset(&addr_st, '\0', sizeof(addr_st)); 2558168515Sgshapiro a = NULL; 2559168515Sgshapiro milter_rcpt_added = false; 2560173340Sgshapiro smtp.sm_e_nrcpts_orig = e->e_nrcpts; 2561168515Sgshapiro#endif 2562182352Sgshapiro#if _FFR_BADRCPT_SHUTDOWN 2563182352Sgshapiro /* 2564182352Sgshapiro ** hack to deal with hack, see below: 2565203004Sgshapiro ** n_badrcpts is increased if limit is reached. 2566182352Sgshapiro */ 2567182352Sgshapiro 2568182352Sgshapiro n_badrcpts_adj = (BadRcptThrottle > 0 && 2569182352Sgshapiro n_badrcpts > BadRcptThrottle && 2570182352Sgshapiro LogLevel > 5) 2571182352Sgshapiro ? n_badrcpts - 1 : n_badrcpts; 2572182352Sgshapiro if (BadRcptShutdown > 0 && 2573182352Sgshapiro n_badrcpts_adj >= BadRcptShutdown && 2574182352Sgshapiro (BadRcptShutdownGood == 0 || 2575182352Sgshapiro smtp.sm_nrcpts == 0 || 2576182352Sgshapiro (n_badrcpts_adj * 100 / 2577182352Sgshapiro (smtp.sm_nrcpts + n_badrcpts) >= 2578182352Sgshapiro BadRcptShutdownGood))) 2579182352Sgshapiro { 2580182352Sgshapiro if (LogLevel > 5) 2581182352Sgshapiro sm_syslog(LOG_INFO, e->e_id, 2582182352Sgshapiro "%s: Possible SMTP RCPT flood, shutting down connection.", 2583182352Sgshapiro CurSmtpClient); 2584182352Sgshapiro message("421 4.7.0 %s Too many bad recipients; closing connection", 2585182352Sgshapiro MyHostName); 2586182352Sgshapiro 2587182352Sgshapiro /* arrange to ignore any current send list */ 2588182352Sgshapiro e->e_sendqueue = NULL; 2589182352Sgshapiro goto doquit; 2590182352Sgshapiro } 2591182352Sgshapiro#endif /* _FFR_BADRCPT_SHUTDOWN */ 2592125820Sgshapiro if (BadRcptThrottle > 0 && 2593125820Sgshapiro n_badrcpts >= BadRcptThrottle) 2594125820Sgshapiro { 2595125820Sgshapiro if (LogLevel > 5 && 2596125820Sgshapiro n_badrcpts == BadRcptThrottle) 2597125820Sgshapiro { 2598125820Sgshapiro sm_syslog(LOG_INFO, e->e_id, 2599125820Sgshapiro "%s: Possible SMTP RCPT flood, throttling.", 2600125820Sgshapiro CurSmtpClient); 2601125820Sgshapiro 2602125820Sgshapiro /* To avoid duplicated message */ 2603125820Sgshapiro n_badrcpts++; 2604125820Sgshapiro } 2605132943Sgshapiro NBADRCPTS; 2606125820Sgshapiro 2607125820Sgshapiro /* 2608125820Sgshapiro ** Don't use exponential backoff for now. 2609203004Sgshapiro ** Some systems will open more connections 2610125820Sgshapiro ** and actually overload the receiver even 2611125820Sgshapiro ** more. 2612125820Sgshapiro */ 2613125820Sgshapiro 2614203004Sgshapiro (void) sleep(BadRcptThrottleDelay); 2615125820Sgshapiro } 261690792Sgshapiro if (!smtp.sm_gotmail) 261738032Speter { 261864562Sgshapiro usrerr("503 5.0.0 Need MAIL before RCPT"); 261938032Speter break; 262038032Speter } 262138032Speter SmtpPhase = "server RCPT"; 262290792Sgshapiro SM_TRY 262390792Sgshapiro { 262490792Sgshapiro QuickAbort = true; 262590792Sgshapiro LogUsrErrs = true; 262638032Speter 262738032Speter /* limit flooding of our machine */ 262890792Sgshapiro if (MaxRcptPerMsg > 0 && 262990792Sgshapiro smtp.sm_nrcpts >= MaxRcptPerMsg) 263038032Speter { 263190792Sgshapiro /* sleep(1); / * slow down? */ 263264562Sgshapiro usrerr("452 4.5.3 Too many recipients"); 263390792Sgshapiro goto rcpt_done; 263438032Speter } 263538032Speter 2636223067Sgshapiro if (!SM_IS_INTERACTIVE(e->e_sendmode) 2637157001Sgshapiro#if _FFR_DM_ONE 2638157001Sgshapiro && (NotFirstDelivery || SM_DM_ONE != e->e_sendmode) 2639157001Sgshapiro#endif /* _FFR_DM_ONE */ 2640157001Sgshapiro ) 264138032Speter e->e_flags |= EF_VRFYONLY; 264238032Speter 264390792Sgshapiro#if MILTER 264464562Sgshapiro /* 2645168515Sgshapiro ** Do not expand recipients at RCPT time (in the call 2646173340Sgshapiro ** to recipient()) if a milter can delete or reject 2647173340Sgshapiro ** a RCPT. If they are expanded, it is impossible 2648173340Sgshapiro ** for removefromlist() to figure out the expanded 2649173340Sgshapiro ** members of the original recipient and mark them 2650173340Sgshapiro ** as QS_DONTSEND. 265164562Sgshapiro */ 265264562Sgshapiro 2653173340Sgshapiro if (!(smtp.sm_milterlist && smtp.sm_milterize && 2654173340Sgshapiro !bitset(EF_DISCARD, e->e_flags)) && 2655173340Sgshapiro (smtp.sm_milters.mis_flags & 2656173340Sgshapiro (MIS_FL_DEL_RCPT|MIS_FL_REJ_RCPT)) != 0) 2657173340Sgshapiro e->e_flags |= EF_VRFYONLY; 2658168515Sgshapiro milter_cmd_done = false; 2659168515Sgshapiro milter_cmd_safe = false; 266090792Sgshapiro#endif /* MILTER */ 266164562Sgshapiro 266238032Speter p = skipword(p, "to"); 266338032Speter if (p == NULL) 266490792Sgshapiro goto rcpt_done; 266590792Sgshapiro macdefine(&e->e_macro, A_PERM, 266690792Sgshapiro macid("{addr_type}"), "e r"); 266790792Sgshapiro a = parseaddr(p, NULLADDR, RF_COPYALL, ' ', &delimptr, 266890792Sgshapiro e, true); 266990792Sgshapiro macdefine(&e->e_macro, A_PERM, 267090792Sgshapiro macid("{addr_type}"), NULL); 267142575Speter if (Errors > 0) 267290792Sgshapiro goto rcpt_done; 267342575Speter if (a == NULL) 267442575Speter { 267564562Sgshapiro usrerr("501 5.0.0 Missing recipient"); 267690792Sgshapiro goto rcpt_done; 267742575Speter } 267842575Speter 267938032Speter if (delimptr != NULL && *delimptr != '\0') 268038032Speter *delimptr++ = '\0'; 268138032Speter 268264562Sgshapiro /* put resulting triple from parseaddr() into macros */ 268364562Sgshapiro if (a->q_mailer != NULL) 268490792Sgshapiro macdefine(&e->e_macro, A_PERM, 268590792Sgshapiro macid("{rcpt_mailer}"), 268690792Sgshapiro a->q_mailer->m_name); 268764562Sgshapiro else 268890792Sgshapiro macdefine(&e->e_macro, A_PERM, 268990792Sgshapiro macid("{rcpt_mailer}"), NULL); 269064562Sgshapiro if (a->q_host != NULL) 269190792Sgshapiro macdefine(&e->e_macro, A_PERM, 269290792Sgshapiro macid("{rcpt_host}"), a->q_host); 269364562Sgshapiro else 269490792Sgshapiro macdefine(&e->e_macro, A_PERM, 269590792Sgshapiro macid("{rcpt_host}"), "localhost"); 269664562Sgshapiro if (a->q_user != NULL) 269790792Sgshapiro macdefine(&e->e_macro, A_PERM, 269890792Sgshapiro macid("{rcpt_addr}"), a->q_user); 269964562Sgshapiro else 270090792Sgshapiro macdefine(&e->e_macro, A_PERM, 270190792Sgshapiro macid("{rcpt_addr}"), NULL); 270264562Sgshapiro if (Errors > 0) 270390792Sgshapiro goto rcpt_done; 270438032Speter 270538032Speter /* now parse ESMTP arguments */ 270664562Sgshapiro addr = p; 2707168515Sgshapiro parse_esmtp_args(e, a, p, delimptr, "RCPT", args, 2708168515Sgshapiro rcpt_esmtp_args); 270938032Speter if (Errors > 0) 271090792Sgshapiro goto rcpt_done; 271138032Speter 2712168515Sgshapiro#if MILTER 2713168515Sgshapiro /* 2714168515Sgshapiro ** rscheck() can trigger an "exception" 2715168515Sgshapiro ** in which case the execution continues at 2716168515Sgshapiro ** SM_EXCEPT(exc, "[!F]*") 2717168515Sgshapiro ** This means milter_cmd_safe is not set 2718168515Sgshapiro ** and hence milter is not invoked. 2719168515Sgshapiro ** Would it be "safe" to change that, i.e., use 2720168515Sgshapiro ** milter_cmd_safe = true; 2721168515Sgshapiro ** here so a milter is informed (if requested) 2722168515Sgshapiro ** about RCPTs that are rejected by check_rcpt? 2723168515Sgshapiro */ 2724168515Sgshapiro# if _FFR_MILTER_CHECK_REJECTIONS_TOO 2725168515Sgshapiro milter_cmd_safe = true; 2726168515Sgshapiro# endif 2727168515Sgshapiro#endif 2728168515Sgshapiro 272964562Sgshapiro /* do config file checking of the recipient */ 273090792Sgshapiro macdefine(&e->e_macro, A_PERM, 273190792Sgshapiro macid("{addr_type}"), "e r"); 273264562Sgshapiro if (rscheck("check_rcpt", addr, 2733102528Sgshapiro NULL, e, RSF_RMCOMM|RSF_COUNT, 3, 2734168515Sgshapiro NULL, e->e_id, p_addr_st) != EX_OK || 273564562Sgshapiro Errors > 0) 273690792Sgshapiro goto rcpt_done; 273790792Sgshapiro macdefine(&e->e_macro, A_PERM, 273890792Sgshapiro macid("{addr_type}"), NULL); 273964562Sgshapiro 2740102528Sgshapiro /* If discarding, don't bother to verify user */ 2741102528Sgshapiro if (bitset(EF_DISCARD, e->e_flags)) 2742102528Sgshapiro a->q_state = QS_VERIFIED; 2743168515Sgshapiro#if MILTER 2744168515Sgshapiro milter_cmd_safe = true; 2745168515Sgshapiro#endif 2746102528Sgshapiro 2747168515Sgshapiro /* save in recipient list after ESMTP mods */ 2748168515Sgshapiro a = recipient(a, &e->e_sendqueue, 0, e); 2749168515Sgshapiro /* may trigger exception... */ 2750168515Sgshapiro 275190792Sgshapiro#if MILTER 2752168515Sgshapiro milter_rcpt_added = true; 2753168515Sgshapiro#endif 2754168515Sgshapiro 2755168515Sgshapiro if(!(Errors > 0) && QS_IS_BADADDR(a->q_state)) 2756168515Sgshapiro { 2757168515Sgshapiro /* punt -- should keep message in ADDRESS.... */ 2758168515Sgshapiro usrerr("550 5.1.1 Addressee unknown"); 2759168515Sgshapiro } 2760168515Sgshapiro 2761168515Sgshapiro#if MILTER 2762168515Sgshapiro rcpt_done: 276390792Sgshapiro if (smtp.sm_milterlist && smtp.sm_milterize && 276490792Sgshapiro !bitset(EF_DISCARD, e->e_flags)) 276564562Sgshapiro { 276664562Sgshapiro char state; 276764562Sgshapiro char *response; 276864562Sgshapiro 2769168515Sgshapiro /* how to get the error codes? */ 2770168515Sgshapiro if (Errors > 0) 2771168515Sgshapiro { 2772168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2773168515Sgshapiro macid("{rcpt_mailer}"), 2774168515Sgshapiro "error"); 2775168515Sgshapiro if (a != NULL && 2776168515Sgshapiro a->q_status != NULL && 2777168515Sgshapiro a->q_rstatus != NULL) 2778168515Sgshapiro { 2779168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2780168515Sgshapiro macid("{rcpt_host}"), 2781168515Sgshapiro a->q_status); 2782168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2783168515Sgshapiro macid("{rcpt_addr}"), 2784168515Sgshapiro a->q_rstatus); 2785168515Sgshapiro } 2786168515Sgshapiro else 2787168515Sgshapiro { 2788168515Sgshapiro if (addr_st.q_host != NULL) 2789168515Sgshapiro macdefine(&e->e_macro, 2790168515Sgshapiro A_PERM, 2791168515Sgshapiro macid("{rcpt_host}"), 2792168515Sgshapiro addr_st.q_host); 2793168515Sgshapiro if (addr_st.q_user != NULL) 2794168515Sgshapiro macdefine(&e->e_macro, 2795168515Sgshapiro A_PERM, 2796168515Sgshapiro macid("{rcpt_addr}"), 2797168515Sgshapiro addr_st.q_user); 2798168515Sgshapiro } 2799168515Sgshapiro } 2800168515Sgshapiro 2801168515Sgshapiro response = milter_envrcpt(args, e, &state, 2802168515Sgshapiro Errors > 0); 2803168515Sgshapiro milter_cmd_done = true; 280490792Sgshapiro MILTER_REPLY("to"); 280564562Sgshapiro } 280690792Sgshapiro#endif /* MILTER */ 280764562Sgshapiro 280838032Speter /* no errors during parsing, but might be a duplicate */ 280938032Speter e->e_to = a->q_paddr; 2810168515Sgshapiro if (!(Errors > 0) && !QS_IS_BADADDR(a->q_state)) 281138032Speter { 281290792Sgshapiro if (smtp.sm_nrcpts == 0) 281364562Sgshapiro initsys(e); 281464562Sgshapiro message("250 2.1.5 Recipient ok%s", 281564562Sgshapiro QS_IS_QUEUEUP(a->q_state) ? 281638032Speter " (will queue)" : ""); 281790792Sgshapiro smtp.sm_nrcpts++; 281838032Speter } 2819168515Sgshapiro 2820168515Sgshapiro /* Is this needed? */ 2821168515Sgshapiro#if !MILTER 2822168515Sgshapiro rcpt_done: 2823168515Sgshapiro#endif /* !MILTER */ 2824168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2825168515Sgshapiro macid("{rcpt_mailer}"), NULL); 2826168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2827168515Sgshapiro macid("{rcpt_host}"), NULL); 2828168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2829168515Sgshapiro macid("{rcpt_addr}"), NULL); 2830168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2831168515Sgshapiro macid("{dsn_notify}"), NULL); 2832168515Sgshapiro 283390792Sgshapiro if (Errors > 0) 2834132943Sgshapiro { 283590792Sgshapiro ++n_badrcpts; 2836132943Sgshapiro NBADRCPTS; 2837132943Sgshapiro } 283890792Sgshapiro } 283990792Sgshapiro SM_EXCEPT(exc, "[!F]*") 284090792Sgshapiro { 284190792Sgshapiro /* An exception occurred while processing RCPT */ 284290792Sgshapiro e->e_flags &= ~(EF_FATALERRS|EF_PM_NOTIFY); 284390792Sgshapiro ++n_badrcpts; 2844132943Sgshapiro NBADRCPTS; 2845168515Sgshapiro#if MILTER 2846168515Sgshapiro if (smtp.sm_milterlist && smtp.sm_milterize && 2847168515Sgshapiro !bitset(EF_DISCARD, e->e_flags) && 2848168515Sgshapiro !milter_cmd_done && milter_cmd_safe) 2849168515Sgshapiro { 2850168515Sgshapiro char state; 2851168515Sgshapiro char *response; 2852168515Sgshapiro 2853168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2854168515Sgshapiro macid("{rcpt_mailer}"), "error"); 2855168515Sgshapiro 2856168515Sgshapiro /* how to get the error codes? */ 2857168515Sgshapiro if (addr_st.q_host != NULL) 2858168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2859168515Sgshapiro macid("{rcpt_host}"), 2860168515Sgshapiro addr_st.q_host); 2861168515Sgshapiro else if (a != NULL && a->q_status != NULL) 2862168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2863168515Sgshapiro macid("{rcpt_host}"), 2864168515Sgshapiro a->q_status); 2865168515Sgshapiro 2866168515Sgshapiro if (addr_st.q_user != NULL) 2867168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2868168515Sgshapiro macid("{rcpt_addr}"), 2869168515Sgshapiro addr_st.q_user); 2870168515Sgshapiro else if (a != NULL && a->q_rstatus != NULL) 2871168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2872168515Sgshapiro macid("{rcpt_addr}"), 2873168515Sgshapiro a->q_rstatus); 2874168515Sgshapiro 2875168515Sgshapiro response = milter_envrcpt(args, e, &state, 2876168515Sgshapiro true); 2877168515Sgshapiro milter_cmd_done = true; 2878168515Sgshapiro MILTER_REPLY("to"); 2879168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2880168515Sgshapiro macid("{rcpt_mailer}"), NULL); 2881168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2882168515Sgshapiro macid("{rcpt_host}"), NULL); 2883168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2884168515Sgshapiro macid("{rcpt_addr}"), NULL); 2885168515Sgshapiro } 2886168515Sgshapiro if (smtp.sm_milterlist && smtp.sm_milterize && 2887168515Sgshapiro milter_rcpt_added && milter_cmd_done && 2888168515Sgshapiro milter_cmd_fail) 2889168515Sgshapiro { 2890168515Sgshapiro (void) removefromlist(addr, &e->e_sendqueue, e); 2891168515Sgshapiro milter_cmd_fail = false; 2892173340Sgshapiro if (smtp.sm_e_nrcpts_orig < e->e_nrcpts) 2893173340Sgshapiro e->e_nrcpts = smtp.sm_e_nrcpts_orig; 2894168515Sgshapiro } 2895168515Sgshapiro#endif /* MILTER */ 289690792Sgshapiro } 289790792Sgshapiro SM_END_TRY 289838032Speter break; 289938032Speter 290038032Speter case CMDDATA: /* data -- text of mail */ 290190792Sgshapiro DELAY_CONN("DATA"); 2902132943Sgshapiro if (!smtp_data(&smtp, e)) 2903132943Sgshapiro goto doquit; 290438032Speter break; 290538032Speter 290638032Speter case CMDRSET: /* rset -- reset state */ 290738032Speter if (tTd(94, 100)) 290864562Sgshapiro message("451 4.0.0 Test failure"); 290938032Speter else 291064562Sgshapiro message("250 2.0.0 Reset state"); 291190792Sgshapiro CLEAR_STATE(cmdbuf); 291238032Speter break; 291338032Speter 291438032Speter case CMDVRFY: /* vrfy -- verify address */ 291538032Speter case CMDEXPN: /* expn -- expand address */ 291690792Sgshapiro vrfy = c->cmd_code == CMDVRFY; 291790792Sgshapiro DELAY_CONN(vrfy ? "VRFY" : "EXPN"); 291864562Sgshapiro if (tempfail) 291964562Sgshapiro { 292064562Sgshapiro if (LogLevel > 9) 292164562Sgshapiro sm_syslog(LOG_INFO, e->e_id, 2922110560Sgshapiro "SMTP %s command (%.100s) from %s tempfailed (due to previous checks)", 292390792Sgshapiro vrfy ? "VRFY" : "EXPN", 292464562Sgshapiro p, CurSmtpClient); 292590792Sgshapiro 292690792Sgshapiro /* RFC 821 doesn't allow 4xy reply code */ 292764562Sgshapiro usrerr("550 5.7.1 Please try again later"); 292864562Sgshapiro break; 292964562Sgshapiro } 293090792Sgshapiro wt = checksmtpattack(&n_verifies, MAXVRFYCOMMANDS, 293190792Sgshapiro false, vrfy ? "VRFY" : "EXPN", e); 2932132943Sgshapiro STOP_IF_ATTACK(wt); 293364562Sgshapiro previous = curtime(); 2934110560Sgshapiro if ((vrfy && bitset(PRIV_NOVRFY, PrivacyFlags)) || 2935110560Sgshapiro (!vrfy && !bitset(SRV_OFFER_EXPN, features))) 293638032Speter { 293738032Speter if (vrfy) 293864562Sgshapiro message("252 2.5.2 Cannot VRFY user; try RCPT to attempt delivery (or try finger)"); 293938032Speter else 294064562Sgshapiro message("502 5.7.0 Sorry, we do not allow this operation"); 294138032Speter if (LogLevel > 5) 294238032Speter sm_syslog(LOG_INFO, e->e_id, 2943110560Sgshapiro "%s: %s [rejected]", 294464562Sgshapiro CurSmtpClient, 294564562Sgshapiro shortenstring(inp, MAXSHORTSTR)); 294638032Speter break; 294738032Speter } 294838032Speter else if (!gothello && 294938032Speter bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO, 295038032Speter PrivacyFlags)) 295138032Speter { 295264562Sgshapiro usrerr("503 5.0.0 I demand that you introduce yourself first"); 295338032Speter break; 295438032Speter } 295590792Sgshapiro if (Errors > 0) 295638032Speter break; 295738032Speter if (LogLevel > 5) 2958110560Sgshapiro sm_syslog(LOG_INFO, e->e_id, "%s: %s", 295964562Sgshapiro CurSmtpClient, 296064562Sgshapiro shortenstring(inp, MAXSHORTSTR)); 296190792Sgshapiro SM_TRY 296290792Sgshapiro { 296390792Sgshapiro QuickAbort = true; 296438032Speter vrfyqueue = NULL; 296538032Speter if (vrfy) 296638032Speter e->e_flags |= EF_VRFYONLY; 296738032Speter while (*p != '\0' && isascii(*p) && isspace(*p)) 296838032Speter p++; 296938032Speter if (*p == '\0') 297038032Speter { 297164562Sgshapiro usrerr("501 5.5.2 Argument required"); 297238032Speter } 297338032Speter else 297438032Speter { 297564562Sgshapiro /* do config file checking of the address */ 297664562Sgshapiro if (rscheck(vrfy ? "check_vrfy" : "check_expn", 2977102528Sgshapiro p, NULL, e, RSF_RMCOMM, 2978168515Sgshapiro 3, NULL, NOQID, NULL) != EX_OK || 297990792Sgshapiro Errors > 0) 298090792Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1); 298138032Speter (void) sendtolist(p, NULLADDR, &vrfyqueue, 0, e); 298238032Speter } 298364562Sgshapiro if (wt > 0) 298471345Sgshapiro { 298571345Sgshapiro time_t t; 298671345Sgshapiro 298771345Sgshapiro t = wt - (curtime() - previous); 298871345Sgshapiro if (t > 0) 298971345Sgshapiro (void) sleep(t); 299071345Sgshapiro } 299138032Speter if (Errors > 0) 299290792Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1); 299338032Speter if (vrfyqueue == NULL) 299438032Speter { 299564562Sgshapiro usrerr("554 5.5.2 Nothing to %s", vrfy ? "VRFY" : "EXPN"); 299638032Speter } 299738032Speter while (vrfyqueue != NULL) 299838032Speter { 299964562Sgshapiro if (!QS_IS_UNDELIVERED(vrfyqueue->q_state)) 300064562Sgshapiro { 300164562Sgshapiro vrfyqueue = vrfyqueue->q_next; 300264562Sgshapiro continue; 300364562Sgshapiro } 300438032Speter 300564562Sgshapiro /* see if there is more in the vrfy list */ 300638032Speter a = vrfyqueue; 300738032Speter while ((a = a->q_next) != NULL && 300866494Sgshapiro (!QS_IS_UNDELIVERED(a->q_state))) 300938032Speter continue; 301064562Sgshapiro printvrfyaddr(vrfyqueue, a == NULL, vrfy); 301164562Sgshapiro vrfyqueue = a; 301238032Speter } 301390792Sgshapiro } 301490792Sgshapiro SM_EXCEPT(exc, "[!F]*") 301590792Sgshapiro { 301690792Sgshapiro /* 301790792Sgshapiro ** An exception occurred while processing VRFY/EXPN 301890792Sgshapiro */ 301990792Sgshapiro 302090792Sgshapiro sm_exc_free(exc); 302190792Sgshapiro goto undo; 302290792Sgshapiro } 302390792Sgshapiro SM_END_TRY 302438032Speter break; 302538032Speter 302638032Speter case CMDETRN: /* etrn -- force queue flush */ 302790792Sgshapiro DELAY_CONN("ETRN"); 302890792Sgshapiro 302990792Sgshapiro /* Don't leak queue information via debug flags */ 303090792Sgshapiro if (!bitset(SRV_OFFER_ETRN, features) || UseMSP || 303190792Sgshapiro (RealUid != 0 && RealUid != TrustedUid && 303290792Sgshapiro OpMode == MD_SMTP)) 303338032Speter { 303464562Sgshapiro /* different message for MSA ? */ 303564562Sgshapiro message("502 5.7.0 Sorry, we do not allow this operation"); 303638032Speter if (LogLevel > 5) 303738032Speter sm_syslog(LOG_INFO, e->e_id, 3038110560Sgshapiro "%s: %s [rejected]", 303964562Sgshapiro CurSmtpClient, 304064562Sgshapiro shortenstring(inp, MAXSHORTSTR)); 304138032Speter break; 304238032Speter } 304364562Sgshapiro if (tempfail) 304464562Sgshapiro { 304564562Sgshapiro if (LogLevel > 9) 304664562Sgshapiro sm_syslog(LOG_INFO, e->e_id, 3047110560Sgshapiro "SMTP ETRN command (%.100s) from %s tempfailed (due to previous checks)", 304864562Sgshapiro p, CurSmtpClient); 304990792Sgshapiro usrerr(MSG_TEMPFAIL); 305064562Sgshapiro break; 305164562Sgshapiro } 305238032Speter 305338032Speter if (strlen(p) <= 0) 305438032Speter { 305564562Sgshapiro usrerr("500 5.5.2 Parameter required"); 305638032Speter break; 305738032Speter } 305838032Speter 305938032Speter /* crude way to avoid denial-of-service attacks */ 3060132943Sgshapiro STOP_IF_ATTACK(checksmtpattack(&n_etrn, MAXETRNCOMMANDS, 3061132943Sgshapiro true, "ETRN", e)); 306238032Speter 306390792Sgshapiro /* 306490792Sgshapiro ** Do config file checking of the parameter. 306590792Sgshapiro ** Even though we have srv_features now, we still 306690792Sgshapiro ** need this ruleset because the former is called 306790792Sgshapiro ** when the connection has been established, while 306890792Sgshapiro ** this ruleset is called when the command is 306990792Sgshapiro ** actually issued and therefore has all information 307090792Sgshapiro ** available to make a decision. 307190792Sgshapiro */ 307290792Sgshapiro 3073102528Sgshapiro if (rscheck("check_etrn", p, NULL, e, 3074168515Sgshapiro RSF_RMCOMM, 3, NULL, NOQID, NULL) 3075168515Sgshapiro != EX_OK || 3076102528Sgshapiro Errors > 0) 307764562Sgshapiro break; 307864562Sgshapiro 307938032Speter if (LogLevel > 5) 308038032Speter sm_syslog(LOG_INFO, e->e_id, 3081110560Sgshapiro "%s: ETRN %s", CurSmtpClient, 308264562Sgshapiro shortenstring(p, MAXSHORTSTR)); 308338032Speter 308438032Speter id = p; 308590792Sgshapiro if (*id == '#') 308690792Sgshapiro { 3087111823Sgshapiro int i, qgrp; 308890792Sgshapiro 308990792Sgshapiro id++; 3090111823Sgshapiro qgrp = name2qid(id); 3091111823Sgshapiro if (!ISVALIDQGRP(qgrp)) 309290792Sgshapiro { 309390792Sgshapiro usrerr("459 4.5.4 Queue %s unknown", 309490792Sgshapiro id); 309590792Sgshapiro break; 309690792Sgshapiro } 3097111823Sgshapiro for (i = 0; i < NumQueue && Queue[i] != NULL; 3098111823Sgshapiro i++) 3099111823Sgshapiro Queue[i]->qg_nextrun = (time_t) -1; 3100111823Sgshapiro Queue[qgrp]->qg_nextrun = 0; 3101111823Sgshapiro ok = run_work_group(Queue[qgrp]->qg_wgrp, 3102111823Sgshapiro RWG_FORK|RWG_FORCE); 310390792Sgshapiro if (ok && Errors == 0) 310490792Sgshapiro message("250 2.0.0 Queuing for queue group %s started", id); 310590792Sgshapiro break; 310690792Sgshapiro } 310790792Sgshapiro 310838032Speter if (*id == '@') 310938032Speter id++; 311038032Speter else 311138032Speter *--id = '@'; 311264562Sgshapiro 311390792Sgshapiro new = (QUEUE_CHAR *) sm_malloc(sizeof(QUEUE_CHAR)); 311490792Sgshapiro if (new == NULL) 311590792Sgshapiro { 311690792Sgshapiro syserr("500 5.5.0 ETRN out of memory"); 311790792Sgshapiro break; 311890792Sgshapiro } 311938032Speter new->queue_match = id; 312090792Sgshapiro new->queue_negate = false; 312138032Speter new->queue_next = NULL; 312238032Speter QueueLimitRecipient = new; 312390792Sgshapiro ok = runqueue(true, false, false, true); 312490792Sgshapiro sm_free(QueueLimitRecipient); /* XXX */ 312538032Speter QueueLimitRecipient = NULL; 312638032Speter if (ok && Errors == 0) 312764562Sgshapiro message("250 2.0.0 Queuing for node %s started", p); 312838032Speter break; 312938032Speter 313038032Speter case CMDHELP: /* help -- give user info */ 313190792Sgshapiro DELAY_CONN("HELP"); 313264562Sgshapiro help(p, e); 313338032Speter break; 313438032Speter 313538032Speter case CMDNOOP: /* noop -- do nothing */ 313690792Sgshapiro DELAY_CONN("NOOP"); 3137157001Sgshapiro STOP_IF_ATTACK(checksmtpattack(&n_noop, MaxNOOPCommands, 3138132943Sgshapiro true, "NOOP", e)); 313964562Sgshapiro message("250 2.0.0 OK"); 314038032Speter break; 314138032Speter 314238032Speter case CMDQUIT: /* quit -- leave mail */ 314364562Sgshapiro message("221 2.0.0 %s closing connection", MyHostName); 314490792Sgshapiro#if PIPELINING 314590792Sgshapiro (void) sm_io_flush(OutChannel, SM_TIME_DEFAULT); 314690792Sgshapiro#endif /* PIPELINING */ 314738032Speter 314890792Sgshapiro if (smtp.sm_nrcpts > 0) 314990792Sgshapiro logundelrcpts(e, "aborted by sender", 9, false); 315090792Sgshapiro 315138032Speter /* arrange to ignore any current send list */ 315238032Speter e->e_sendqueue = NULL; 315338032Speter 315490792Sgshapiro#if STARTTLS 315564562Sgshapiro /* shutdown TLS connection */ 315664562Sgshapiro if (tls_active) 315764562Sgshapiro { 315864562Sgshapiro (void) endtls(srv_ssl, "server"); 315990792Sgshapiro tls_active = false; 316064562Sgshapiro } 316190792Sgshapiro#endif /* STARTTLS */ 316290792Sgshapiro#if SASL 316364562Sgshapiro if (authenticating == SASL_IS_AUTH) 316464562Sgshapiro { 316564562Sgshapiro sasl_dispose(&conn); 316664562Sgshapiro authenticating = SASL_NOT_AUTH; 316790792Sgshapiro /* XXX sasl_done(); this is a child */ 316864562Sgshapiro } 316990792Sgshapiro#endif /* SASL */ 317064562Sgshapiro 317164562Sgshapirodoquit: 317238032Speter /* avoid future 050 messages */ 317338032Speter disconnect(1, e); 317438032Speter 317590792Sgshapiro#if MILTER 317664562Sgshapiro /* close out milter filters */ 317764562Sgshapiro milter_quit(e); 317890792Sgshapiro#endif /* MILTER */ 317964562Sgshapiro 3180203004Sgshapiro if (tTd(92, 2)) 3181203004Sgshapiro sm_dprintf("QUIT: e_id=%s, EF_LOGSENDER=%d, LogLevel=%d\n", 3182203004Sgshapiro e->e_id, 3183203004Sgshapiro bitset(EF_LOGSENDER, e->e_flags), 3184203004Sgshapiro LogLevel); 318564562Sgshapiro if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags)) 318664562Sgshapiro logsender(e, NULL); 318764562Sgshapiro e->e_flags &= ~EF_LOGSENDER; 318864562Sgshapiro 318998121Sgshapiro if (lognullconnection && LogLevel > 5 && 319098121Sgshapiro nullserver == NULL) 319164562Sgshapiro { 319264562Sgshapiro char *d; 319364562Sgshapiro 319490792Sgshapiro d = macvalue(macid("{daemon_name}"), e); 319564562Sgshapiro if (d == NULL) 319664562Sgshapiro d = "stdin"; 319790792Sgshapiro 319890792Sgshapiro /* 319990792Sgshapiro ** even though this id is "bogus", it makes 320090792Sgshapiro ** it simpler to "grep" related events, e.g., 320190792Sgshapiro ** timeouts for the same connection. 320290792Sgshapiro */ 320390792Sgshapiro 320490792Sgshapiro sm_syslog(LOG_INFO, e->e_id, 3205110560Sgshapiro "%s did not issue MAIL/EXPN/VRFY/ETRN during connection to %s", 320664562Sgshapiro CurSmtpClient, d); 320764562Sgshapiro } 3208110560Sgshapiro if (tTd(93, 100)) 3209110560Sgshapiro { 3210110560Sgshapiro /* return to handle next connection */ 3211110560Sgshapiro return; 3212110560Sgshapiro } 321390792Sgshapiro finis(true, true, ExitStat); 321464562Sgshapiro /* NOTREACHED */ 321538032Speter 3216157001Sgshapiro /* just to avoid bogus warning from some compilers */ 3217157001Sgshapiro exit(EX_OSERR); 3218157001Sgshapiro 321938032Speter case CMDVERB: /* set verbose mode */ 322090792Sgshapiro DELAY_CONN("VERB"); 3221110560Sgshapiro if (!bitset(SRV_OFFER_EXPN, features) || 3222110560Sgshapiro !bitset(SRV_OFFER_VERB, features)) 322338032Speter { 322438032Speter /* this would give out the same info */ 322564562Sgshapiro message("502 5.7.0 Verbose unavailable"); 322638032Speter break; 322738032Speter } 3228157001Sgshapiro STOP_IF_ATTACK(checksmtpattack(&n_noop, MaxNOOPCommands, 3229132943Sgshapiro true, "VERB", e)); 323038032Speter Verbose = 1; 323164562Sgshapiro set_delivery_mode(SM_DELIVER, e); 323264562Sgshapiro message("250 2.0.0 Verbose mode"); 323338032Speter break; 323438032Speter 323590792Sgshapiro#if SMTPDEBUG 323638032Speter case CMDDBGQSHOW: /* show queues */ 323790792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 323890792Sgshapiro "Send Queue="); 3239132943Sgshapiro printaddr(smioout, e->e_sendqueue, true); 324038032Speter break; 324138032Speter 324238032Speter case CMDDBGDEBUG: /* set debug mode */ 3243168515Sgshapiro tTsetup(tTdvect, sizeof(tTdvect), "0-99.1"); 324438032Speter tTflag(p); 324564562Sgshapiro message("200 2.0.0 Debug set"); 324638032Speter break; 324738032Speter 324890792Sgshapiro#else /* SMTPDEBUG */ 324938032Speter case CMDDBGQSHOW: /* show queues */ 325038032Speter case CMDDBGDEBUG: /* set debug mode */ 325190792Sgshapiro#endif /* SMTPDEBUG */ 325238032Speter case CMDLOGBOGUS: /* bogus command */ 325390792Sgshapiro DELAY_CONN("Bogus"); 325438032Speter if (LogLevel > 0) 325538032Speter sm_syslog(LOG_CRIT, e->e_id, 3256110560Sgshapiro "\"%s\" command from %s (%.100s)", 325764562Sgshapiro c->cmd_name, CurSmtpClient, 325864562Sgshapiro anynet_ntoa(&RealHostAddr)); 325964562Sgshapiro /* FALLTHROUGH */ 326038032Speter 326138032Speter case CMDERROR: /* unknown command */ 326290792Sgshapiro#if MAXBADCOMMANDS > 0 326390792Sgshapiro if (++n_badcmds > MAXBADCOMMANDS) 326438032Speter { 3265132943Sgshapiro stopattack: 326664562Sgshapiro message("421 4.7.0 %s Too many bad commands; closing connection", 326738032Speter MyHostName); 326864562Sgshapiro 326964562Sgshapiro /* arrange to ignore any current send list */ 327064562Sgshapiro e->e_sendqueue = NULL; 327138032Speter goto doquit; 327238032Speter } 327390792Sgshapiro#endif /* MAXBADCOMMANDS > 0 */ 327438032Speter 3275132943Sgshapiro#if MILTER && SMFI_VERSION > 2 3276132943Sgshapiro if (smtp.sm_milterlist && smtp.sm_milterize && 3277132943Sgshapiro !bitset(EF_DISCARD, e->e_flags)) 3278132943Sgshapiro { 3279132943Sgshapiro char state; 3280132943Sgshapiro char *response; 3281132943Sgshapiro 3282132943Sgshapiro if (MilterLogLevel > 9) 3283132943Sgshapiro sm_syslog(LOG_INFO, e->e_id, 3284132943Sgshapiro "Sending \"%s\" to Milter", inp); 3285132943Sgshapiro response = milter_unknown(inp, e, &state); 3286132943Sgshapiro MILTER_REPLY("unknown"); 3287132943Sgshapiro if (state == SMFIR_REPLYCODE || 3288132943Sgshapiro state == SMFIR_REJECT || 3289157001Sgshapiro state == SMFIR_TEMPFAIL || 3290157001Sgshapiro state == SMFIR_SHUTDOWN) 3291132943Sgshapiro { 3292132943Sgshapiro /* MILTER_REPLY already gave an error */ 3293132943Sgshapiro break; 3294132943Sgshapiro } 3295132943Sgshapiro } 3296132943Sgshapiro#endif /* MILTER && SMFI_VERSION > 2 */ 3297132943Sgshapiro 329864562Sgshapiro usrerr("500 5.5.1 Command unrecognized: \"%s\"", 329964562Sgshapiro shortenstring(inp, MAXSHORTSTR)); 330038032Speter break; 330138032Speter 330264562Sgshapiro case CMDUNIMPL: 330390792Sgshapiro DELAY_CONN("Unimpl"); 330464562Sgshapiro usrerr("502 5.5.1 Command not implemented: \"%s\"", 330564562Sgshapiro shortenstring(inp, MAXSHORTSTR)); 330664562Sgshapiro break; 330764562Sgshapiro 330838032Speter default: 330990792Sgshapiro DELAY_CONN("default"); 331038032Speter errno = 0; 331164562Sgshapiro syserr("500 5.5.0 smtp: unknown code %d", c->cmd_code); 331238032Speter break; 331338032Speter } 331490792Sgshapiro#if SASL 331564562Sgshapiro } 331690792Sgshapiro#endif /* SASL */ 331790792Sgshapiro } 331890792Sgshapiro SM_EXCEPT(exc, "[!F]*") 331990792Sgshapiro { 332090792Sgshapiro /* 332190792Sgshapiro ** The only possible exception is "E:mta.quickabort". 332290792Sgshapiro ** There is nothing to do except fall through and loop. 332390792Sgshapiro */ 332490792Sgshapiro } 332590792Sgshapiro SM_END_TRY 332638032Speter } 332790792Sgshapiro} 332890792Sgshapiro/* 332990792Sgshapiro** SMTP_DATA -- implement the SMTP DATA command. 333090792Sgshapiro** 333190792Sgshapiro** Parameters: 333290792Sgshapiro** smtp -- status of SMTP connection. 333390792Sgshapiro** e -- envelope. 333490792Sgshapiro** 333590792Sgshapiro** Returns: 3336132943Sgshapiro** true iff SMTP session can continue. 333790792Sgshapiro** 333890792Sgshapiro** Side Effects: 333990792Sgshapiro** possibly sends message. 334090792Sgshapiro*/ 334164562Sgshapiro 3342132943Sgshapirostatic bool 334390792Sgshapirosmtp_data(smtp, e) 334490792Sgshapiro SMTP_T *smtp; 334590792Sgshapiro ENVELOPE *e; 334690792Sgshapiro{ 334790792Sgshapiro#if MILTER 334890792Sgshapiro bool milteraccept; 334990792Sgshapiro#endif /* MILTER */ 335090792Sgshapiro bool aborting; 335190792Sgshapiro bool doublequeue; 3352168515Sgshapiro bool rv = true; 335390792Sgshapiro ADDRESS *a; 335490792Sgshapiro ENVELOPE *ee; 335590792Sgshapiro char *id; 335698121Sgshapiro char *oldid; 3357168515Sgshapiro unsigned int features; 335890792Sgshapiro char buf[32]; 335990792Sgshapiro 336090792Sgshapiro SmtpPhase = "server DATA"; 336190792Sgshapiro if (!smtp->sm_gotmail) 336290792Sgshapiro { 336390792Sgshapiro usrerr("503 5.0.0 Need MAIL command"); 3364132943Sgshapiro return true; 336590792Sgshapiro } 336690792Sgshapiro else if (smtp->sm_nrcpts <= 0) 336790792Sgshapiro { 336890792Sgshapiro usrerr("503 5.0.0 Need RCPT (recipient)"); 3369132943Sgshapiro return true; 337090792Sgshapiro } 3371168515Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "%u", smtp->sm_nrcpts); 337290792Sgshapiro if (rscheck("check_data", buf, NULL, e, 3373102528Sgshapiro RSF_RMCOMM|RSF_UNSTRUCTURED|RSF_COUNT, 3, NULL, 3374168515Sgshapiro e->e_id, NULL) != EX_OK) 3375132943Sgshapiro return true; 337690792Sgshapiro 3377132943Sgshapiro#if MILTER && SMFI_VERSION > 3 3378132943Sgshapiro if (smtp->sm_milterlist && smtp->sm_milterize && 3379132943Sgshapiro !bitset(EF_DISCARD, e->e_flags)) 3380132943Sgshapiro { 3381132943Sgshapiro char state; 3382132943Sgshapiro char *response; 3383132943Sgshapiro int savelogusrerrs = LogUsrErrs; 3384132943Sgshapiro 3385132943Sgshapiro response = milter_data_cmd(e, &state); 3386132943Sgshapiro switch (state) 3387132943Sgshapiro { 3388132943Sgshapiro case SMFIR_REPLYCODE: 3389132943Sgshapiro if (MilterLogLevel > 3) 3390132943Sgshapiro { 3391132943Sgshapiro sm_syslog(LOG_INFO, e->e_id, 3392132943Sgshapiro "Milter: cmd=data, reject=%s", 3393132943Sgshapiro response); 3394132943Sgshapiro LogUsrErrs = false; 3395132943Sgshapiro } 3396203004Sgshapiro#if _FFR_MILTER_ENHSC 3397203004Sgshapiro if (ISSMTPCODE(response)) 3398203004Sgshapiro (void) extenhsc(response + 4, ' ', e->e_enhsc); 3399203004Sgshapiro#endif /* _FFR_MILTER_ENHSC */ 3400203004Sgshapiro 3401132943Sgshapiro usrerr(response); 3402157001Sgshapiro if (strncmp(response, "421 ", 4) == 0 3403157001Sgshapiro || strncmp(response, "421-", 4) == 0) 3404132943Sgshapiro { 3405132943Sgshapiro e->e_sendqueue = NULL; 3406132943Sgshapiro return false; 3407132943Sgshapiro } 3408132943Sgshapiro return true; 3409132943Sgshapiro 3410132943Sgshapiro case SMFIR_REJECT: 3411132943Sgshapiro if (MilterLogLevel > 3) 3412132943Sgshapiro { 3413132943Sgshapiro sm_syslog(LOG_INFO, e->e_id, 3414132943Sgshapiro "Milter: cmd=data, reject=550 5.7.1 Command rejected"); 3415132943Sgshapiro LogUsrErrs = false; 3416132943Sgshapiro } 3417203004Sgshapiro#if _FFR_MILTER_ENHSC 3418203004Sgshapiro (void) sm_strlcpy(e->e_enhsc, "5.7.1", 3419203004Sgshapiro sizeof(e->e_enhsc)); 3420203004Sgshapiro#endif /* _FFR_MILTER_ENHSC */ 3421132943Sgshapiro usrerr("550 5.7.1 Command rejected"); 3422132943Sgshapiro return true; 3423132943Sgshapiro 3424132943Sgshapiro case SMFIR_DISCARD: 3425132943Sgshapiro if (MilterLogLevel > 3) 3426132943Sgshapiro sm_syslog(LOG_INFO, e->e_id, 3427132943Sgshapiro "Milter: cmd=data, discard"); 3428132943Sgshapiro e->e_flags |= EF_DISCARD; 3429132943Sgshapiro break; 3430132943Sgshapiro 3431132943Sgshapiro case SMFIR_TEMPFAIL: 3432132943Sgshapiro if (MilterLogLevel > 3) 3433132943Sgshapiro { 3434132943Sgshapiro sm_syslog(LOG_INFO, e->e_id, 3435132943Sgshapiro "Milter: cmd=data, reject=%s", 3436132943Sgshapiro MSG_TEMPFAIL); 3437132943Sgshapiro LogUsrErrs = false; 3438132943Sgshapiro } 3439203004Sgshapiro#if _FFR_MILTER_ENHSC 3440203004Sgshapiro (void) extenhsc(MSG_TEMPFAIL + 4, ' ', e->e_enhsc); 3441203004Sgshapiro#endif /* _FFR_MILTER_ENHSC */ 3442132943Sgshapiro usrerr(MSG_TEMPFAIL); 3443132943Sgshapiro return true; 3444157001Sgshapiro 3445157001Sgshapiro case SMFIR_SHUTDOWN: 3446157001Sgshapiro if (MilterLogLevel > 3) 3447157001Sgshapiro { 3448157001Sgshapiro sm_syslog(LOG_INFO, e->e_id, 3449157001Sgshapiro "Milter: cmd=data, reject=421 4.7.0 %s closing connection", 3450157001Sgshapiro MyHostName); 3451157001Sgshapiro LogUsrErrs = false; 3452157001Sgshapiro } 3453157001Sgshapiro usrerr("421 4.7.0 %s closing connection", MyHostName); 3454157001Sgshapiro e->e_sendqueue = NULL; 3455157001Sgshapiro return false; 3456132943Sgshapiro } 3457132943Sgshapiro LogUsrErrs = savelogusrerrs; 3458132943Sgshapiro if (response != NULL) 3459132943Sgshapiro sm_free(response); /* XXX */ 3460132943Sgshapiro } 3461132943Sgshapiro#endif /* MILTER && SMFI_VERSION > 3 */ 3462132943Sgshapiro 346390792Sgshapiro /* put back discard bit */ 346490792Sgshapiro if (smtp->sm_discard) 346590792Sgshapiro e->e_flags |= EF_DISCARD; 346690792Sgshapiro 346790792Sgshapiro /* check to see if we need to re-expand aliases */ 346890792Sgshapiro /* also reset QS_BADADDR on already-diagnosted addrs */ 346990792Sgshapiro doublequeue = false; 347090792Sgshapiro for (a = e->e_sendqueue; a != NULL; a = a->q_next) 347190792Sgshapiro { 347290792Sgshapiro if (QS_IS_VERIFIED(a->q_state) && 347390792Sgshapiro !bitset(EF_DISCARD, e->e_flags)) 347490792Sgshapiro { 347590792Sgshapiro /* need to re-expand aliases */ 347690792Sgshapiro doublequeue = true; 347790792Sgshapiro } 347890792Sgshapiro if (QS_IS_BADADDR(a->q_state)) 347990792Sgshapiro { 348090792Sgshapiro /* make this "go away" */ 348190792Sgshapiro a->q_state = QS_DONTSEND; 348290792Sgshapiro } 348390792Sgshapiro } 348490792Sgshapiro 348590792Sgshapiro /* collect the text of the message */ 348690792Sgshapiro SmtpPhase = "collect"; 348790792Sgshapiro buffer_errors(); 348890792Sgshapiro 3489120256Sgshapiro collect(InChannel, true, NULL, e, true); 349090792Sgshapiro 349190792Sgshapiro /* redefine message size */ 3492244928Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "%ld", PRT_NONNEGL(e->e_msgsize)); 349390792Sgshapiro macdefine(&e->e_macro, A_TEMP, macid("{msg_size}"), buf); 349490792Sgshapiro 349590792Sgshapiro /* rscheck() will set Errors or EF_DISCARD if it trips */ 3496102528Sgshapiro (void) rscheck("check_eom", buf, NULL, e, RSF_UNSTRUCTURED|RSF_COUNT, 3497168515Sgshapiro 3, NULL, e->e_id, NULL); 349890792Sgshapiro 349990792Sgshapiro#if MILTER 350090792Sgshapiro milteraccept = true; 350190792Sgshapiro if (smtp->sm_milterlist && smtp->sm_milterize && 350290792Sgshapiro Errors <= 0 && 350390792Sgshapiro !bitset(EF_DISCARD, e->e_flags)) 350490792Sgshapiro { 350590792Sgshapiro char state; 350690792Sgshapiro char *response; 350790792Sgshapiro 350890792Sgshapiro response = milter_data(e, &state); 350990792Sgshapiro switch (state) 351090792Sgshapiro { 351190792Sgshapiro case SMFIR_REPLYCODE: 351290792Sgshapiro if (MilterLogLevel > 3) 351390792Sgshapiro sm_syslog(LOG_INFO, e->e_id, 351490792Sgshapiro "Milter: data, reject=%s", 351590792Sgshapiro response); 351690792Sgshapiro milteraccept = false; 3517203004Sgshapiro#if _FFR_MILTER_ENHSC 3518203004Sgshapiro if (ISSMTPCODE(response)) 3519203004Sgshapiro (void) extenhsc(response + 4, ' ', e->e_enhsc); 3520203004Sgshapiro#endif /* _FFR_MILTER_ENHSC */ 352190792Sgshapiro usrerr(response); 3522203004Sgshapiro if (strncmp(response, "421 ", 4) == 0 3523203004Sgshapiro || strncmp(response, "421-", 4) == 0) 3524203004Sgshapiro rv = false; 352590792Sgshapiro break; 352690792Sgshapiro 352790792Sgshapiro case SMFIR_REJECT: 352890792Sgshapiro milteraccept = false; 352990792Sgshapiro if (MilterLogLevel > 3) 353090792Sgshapiro sm_syslog(LOG_INFO, e->e_id, 353190792Sgshapiro "Milter: data, reject=554 5.7.1 Command rejected"); 353290792Sgshapiro usrerr("554 5.7.1 Command rejected"); 353390792Sgshapiro break; 353490792Sgshapiro 353590792Sgshapiro case SMFIR_DISCARD: 353690792Sgshapiro if (MilterLogLevel > 3) 353790792Sgshapiro sm_syslog(LOG_INFO, e->e_id, 353890792Sgshapiro "Milter: data, discard"); 353990792Sgshapiro milteraccept = false; 354090792Sgshapiro e->e_flags |= EF_DISCARD; 354190792Sgshapiro break; 354290792Sgshapiro 354390792Sgshapiro case SMFIR_TEMPFAIL: 354490792Sgshapiro if (MilterLogLevel > 3) 354590792Sgshapiro sm_syslog(LOG_INFO, e->e_id, 354690792Sgshapiro "Milter: data, reject=%s", 354790792Sgshapiro MSG_TEMPFAIL); 354890792Sgshapiro milteraccept = false; 3549203004Sgshapiro#if _FFR_MILTER_ENHSC 3550203004Sgshapiro (void) extenhsc(MSG_TEMPFAIL + 4, ' ', e->e_enhsc); 3551203004Sgshapiro#endif /* _FFR_MILTER_ENHSC */ 355290792Sgshapiro usrerr(MSG_TEMPFAIL); 355390792Sgshapiro break; 3554157001Sgshapiro 3555157001Sgshapiro case SMFIR_SHUTDOWN: 3556157001Sgshapiro if (MilterLogLevel > 3) 3557157001Sgshapiro sm_syslog(LOG_INFO, e->e_id, 3558157001Sgshapiro "Milter: data, reject=421 4.7.0 %s closing connection", 3559157001Sgshapiro MyHostName); 3560157001Sgshapiro milteraccept = false; 3561157001Sgshapiro usrerr("421 4.7.0 %s closing connection", MyHostName); 3562157001Sgshapiro rv = false; 3563157001Sgshapiro break; 356490792Sgshapiro } 356590792Sgshapiro if (response != NULL) 356690792Sgshapiro sm_free(response); 356790792Sgshapiro } 356890792Sgshapiro 356990792Sgshapiro /* Milter may have changed message size */ 3570244928Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "%ld", PRT_NONNEGL(e->e_msgsize)); 357190792Sgshapiro macdefine(&e->e_macro, A_TEMP, macid("{msg_size}"), buf); 357290792Sgshapiro 357390792Sgshapiro /* abort message filters that didn't get the body & log msg is OK */ 357490792Sgshapiro if (smtp->sm_milterlist && smtp->sm_milterize) 357590792Sgshapiro { 357690792Sgshapiro milter_abort(e); 357790792Sgshapiro if (milteraccept && MilterLogLevel > 9) 357890792Sgshapiro sm_syslog(LOG_INFO, e->e_id, "Milter accept: message"); 357990792Sgshapiro } 3580132943Sgshapiro 3581132943Sgshapiro /* 3582132943Sgshapiro ** If SuperSafe is SAFE_REALLY_POSTMILTER, and we don't have milter or 3583132943Sgshapiro ** milter accepted message, sync it now 3584132943Sgshapiro ** 3585132943Sgshapiro ** XXX This is almost a copy of the code in collect(): put it into 3586132943Sgshapiro ** a function that is called from both places? 3587132943Sgshapiro */ 3588132943Sgshapiro 3589132943Sgshapiro if (milteraccept && SuperSafe == SAFE_REALLY_POSTMILTER) 3590132943Sgshapiro { 3591132943Sgshapiro int afd; 3592132943Sgshapiro SM_FILE_T *volatile df; 3593132943Sgshapiro char *dfname; 3594132943Sgshapiro 3595132943Sgshapiro df = e->e_dfp; 3596132943Sgshapiro dfname = queuename(e, DATAFL_LETTER); 3597132943Sgshapiro if (sm_io_setinfo(df, SM_BF_COMMIT, NULL) < 0 3598132943Sgshapiro && errno != EINVAL) 3599132943Sgshapiro { 3600132943Sgshapiro int save_errno; 3601132943Sgshapiro 3602132943Sgshapiro save_errno = errno; 3603132943Sgshapiro if (save_errno == EEXIST) 3604132943Sgshapiro { 3605132943Sgshapiro struct stat st; 3606132943Sgshapiro int dfd; 3607132943Sgshapiro 3608132943Sgshapiro if (stat(dfname, &st) < 0) 3609132943Sgshapiro st.st_size = -1; 3610132943Sgshapiro errno = EEXIST; 3611132943Sgshapiro syserr("@collect: bfcommit(%s): already on disk, size=%ld", 3612132943Sgshapiro dfname, (long) st.st_size); 3613132943Sgshapiro dfd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL); 3614132943Sgshapiro if (dfd >= 0) 3615132943Sgshapiro dumpfd(dfd, true, true); 3616132943Sgshapiro } 3617132943Sgshapiro errno = save_errno; 3618132943Sgshapiro dferror(df, "bfcommit", e); 3619132943Sgshapiro flush_errors(true); 3620132943Sgshapiro finis(save_errno != EEXIST, true, ExitStat); 3621132943Sgshapiro } 3622132943Sgshapiro else if ((afd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL)) < 0) 3623132943Sgshapiro { 3624132943Sgshapiro dferror(df, "sm_io_getinfo", e); 3625132943Sgshapiro flush_errors(true); 3626132943Sgshapiro finis(true, true, ExitStat); 3627132943Sgshapiro /* NOTREACHED */ 3628132943Sgshapiro } 3629132943Sgshapiro else if (fsync(afd) < 0) 3630132943Sgshapiro { 3631132943Sgshapiro dferror(df, "fsync", e); 3632132943Sgshapiro flush_errors(true); 3633132943Sgshapiro finis(true, true, ExitStat); 3634132943Sgshapiro /* NOTREACHED */ 3635132943Sgshapiro } 3636132943Sgshapiro else if (sm_io_close(df, SM_TIME_DEFAULT) < 0) 3637132943Sgshapiro { 3638132943Sgshapiro dferror(df, "sm_io_close", e); 3639132943Sgshapiro flush_errors(true); 3640132943Sgshapiro finis(true, true, ExitStat); 3641132943Sgshapiro /* NOTREACHED */ 3642132943Sgshapiro } 3643132943Sgshapiro 3644132943Sgshapiro /* Now reopen the df file */ 3645132943Sgshapiro e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname, 3646132943Sgshapiro SM_IO_RDONLY, NULL); 3647132943Sgshapiro if (e->e_dfp == NULL) 3648132943Sgshapiro { 3649132943Sgshapiro /* we haven't acked receipt yet, so just chuck this */ 3650132943Sgshapiro syserr("@Cannot reopen %s", dfname); 3651132943Sgshapiro finis(true, true, ExitStat); 3652132943Sgshapiro /* NOTREACHED */ 3653132943Sgshapiro } 3654132943Sgshapiro } 365590792Sgshapiro#endif /* MILTER */ 365690792Sgshapiro 365790792Sgshapiro /* Check if quarantining stats should be updated */ 365890792Sgshapiro if (e->e_quarmsg != NULL) 365990792Sgshapiro markstats(e, NULL, STATS_QUARANTINE); 366090792Sgshapiro 366190792Sgshapiro /* 366290792Sgshapiro ** If a header/body check (header checks or milter) 366390792Sgshapiro ** set EF_DISCARD, don't queueup the message -- 366490792Sgshapiro ** that would lose the EF_DISCARD bit and deliver 366590792Sgshapiro ** the message. 366690792Sgshapiro */ 366790792Sgshapiro 366890792Sgshapiro if (bitset(EF_DISCARD, e->e_flags)) 366990792Sgshapiro doublequeue = false; 367090792Sgshapiro 367190792Sgshapiro aborting = Errors > 0; 3672125820Sgshapiro if (!(aborting || bitset(EF_DISCARD, e->e_flags)) && 367390792Sgshapiro (QueueMode == QM_QUARANTINE || e->e_quarmsg == NULL) && 367490792Sgshapiro !split_by_recipient(e)) 367590792Sgshapiro aborting = bitset(EF_FATALERRS, e->e_flags); 367690792Sgshapiro 367790792Sgshapiro if (aborting) 367890792Sgshapiro { 3679173340Sgshapiro ADDRESS *q; 3680173340Sgshapiro 368190792Sgshapiro /* Log who the mail would have gone to */ 368290792Sgshapiro logundelrcpts(e, e->e_message, 8, false); 3683173340Sgshapiro 3684173340Sgshapiro /* 3685173340Sgshapiro ** If something above refused the message, we still haven't 3686173340Sgshapiro ** accepted responsibility for it. Don't send DSNs. 3687173340Sgshapiro */ 3688173340Sgshapiro 3689173340Sgshapiro for (q = e->e_sendqueue; q != NULL; q = q->q_next) 3690173340Sgshapiro q->q_flags &= ~Q_PINGFLAGS; 3691173340Sgshapiro 369290792Sgshapiro flush_errors(true); 369390792Sgshapiro buffer_errors(); 369490792Sgshapiro goto abortmessage; 369590792Sgshapiro } 369690792Sgshapiro 369790792Sgshapiro /* from now on, we have to operate silently */ 369890792Sgshapiro buffer_errors(); 369990792Sgshapiro 370090792Sgshapiro#if 0 370190792Sgshapiro /* 370290792Sgshapiro ** Clear message, it may contain an error from the SMTP dialogue. 370390792Sgshapiro ** This error must not show up in the queue. 370490792Sgshapiro ** Some error message should show up, e.g., alias database 370590792Sgshapiro ** not available, but others shouldn't, e.g., from check_rcpt. 370690792Sgshapiro */ 370790792Sgshapiro 370890792Sgshapiro e->e_message = NULL; 370990792Sgshapiro#endif /* 0 */ 371090792Sgshapiro 371190792Sgshapiro /* 371290792Sgshapiro ** Arrange to send to everyone. 371390792Sgshapiro ** If sending to multiple people, mail back 371490792Sgshapiro ** errors rather than reporting directly. 371590792Sgshapiro ** In any case, don't mail back errors for 371690792Sgshapiro ** anything that has happened up to 371790792Sgshapiro ** now (the other end will do this). 371890792Sgshapiro ** Truncate our transcript -- the mail has gotten 371990792Sgshapiro ** to us successfully, and if we have 372090792Sgshapiro ** to mail this back, it will be easier 372190792Sgshapiro ** on the reader. 372290792Sgshapiro ** Then send to everyone. 372390792Sgshapiro ** Finally give a reply code. If an error has 372490792Sgshapiro ** already been given, don't mail a 372590792Sgshapiro ** message back. 372690792Sgshapiro ** We goose error returns by clearing error bit. 372790792Sgshapiro */ 372890792Sgshapiro 372990792Sgshapiro SmtpPhase = "delivery"; 373090792Sgshapiro (void) sm_io_setinfo(e->e_xfp, SM_BF_TRUNCATE, NULL); 373190792Sgshapiro id = e->e_id; 373290792Sgshapiro 373390792Sgshapiro#if NAMED_BIND 373490792Sgshapiro _res.retry = TimeOuts.res_retry[RES_TO_FIRST]; 373590792Sgshapiro _res.retrans = TimeOuts.res_retrans[RES_TO_FIRST]; 373690792Sgshapiro#endif /* NAMED_BIND */ 373790792Sgshapiro 3738223067Sgshapiro 373990792Sgshapiro for (ee = e; ee != NULL; ee = ee->e_sibling) 374090792Sgshapiro { 374190792Sgshapiro /* make sure we actually do delivery */ 374290792Sgshapiro ee->e_flags &= ~EF_CLRQUEUE; 374390792Sgshapiro 374490792Sgshapiro /* from now on, operate silently */ 374590792Sgshapiro ee->e_errormode = EM_MAIL; 374690792Sgshapiro 374790792Sgshapiro if (doublequeue) 374890792Sgshapiro { 374990792Sgshapiro /* make sure it is in the queue */ 375090792Sgshapiro queueup(ee, false, true); 375190792Sgshapiro } 375290792Sgshapiro else 375390792Sgshapiro { 3754157001Sgshapiro int mode; 3755157001Sgshapiro 375690792Sgshapiro /* send to all recipients */ 3757157001Sgshapiro mode = SM_DEFAULT; 3758157001Sgshapiro#if _FFR_DM_ONE 3759157001Sgshapiro if (SM_DM_ONE == e->e_sendmode) 3760157001Sgshapiro { 3761157001Sgshapiro if (NotFirstDelivery) 3762157001Sgshapiro { 3763157001Sgshapiro mode = SM_QUEUE; 3764157001Sgshapiro e->e_sendmode = SM_QUEUE; 3765157001Sgshapiro } 3766157001Sgshapiro else 3767157001Sgshapiro { 3768157001Sgshapiro mode = SM_FORK; 3769157001Sgshapiro NotFirstDelivery = true; 3770157001Sgshapiro } 3771157001Sgshapiro } 3772157001Sgshapiro#endif /* _FFR_DM_ONE */ 3773157001Sgshapiro sendall(ee, mode); 377490792Sgshapiro } 377590792Sgshapiro ee->e_to = NULL; 377690792Sgshapiro } 377790792Sgshapiro 377898121Sgshapiro /* put back id for SMTP logging in putoutmsg() */ 377998121Sgshapiro oldid = CurEnv->e_id; 378098121Sgshapiro CurEnv->e_id = id; 378198121Sgshapiro 3782223067Sgshapiro /* issue success message */ 3783157001Sgshapiro#if _FFR_MSG_ACCEPT 3784223067Sgshapiro if (MessageAccept != NULL && *MessageAccept != '\0') 3785223067Sgshapiro { 3786223067Sgshapiro char msg[MAXLINE]; 3787157001Sgshapiro 3788223067Sgshapiro expand(MessageAccept, msg, sizeof(msg), e); 3789223067Sgshapiro message("250 2.0.0 %s", msg); 3790223067Sgshapiro } 3791223067Sgshapiro else 3792157001Sgshapiro#endif /* _FFR_MSG_ACCEPT */ 3793223067Sgshapiro message("250 2.0.0 %s Message accepted for delivery", id); 379498121Sgshapiro CurEnv->e_id = oldid; 379590792Sgshapiro 379690792Sgshapiro /* if we just queued, poke it */ 379790792Sgshapiro if (doublequeue) 379890792Sgshapiro { 379990792Sgshapiro bool anything_to_send = false; 380090792Sgshapiro 380190792Sgshapiro sm_getla(); 380290792Sgshapiro for (ee = e; ee != NULL; ee = ee->e_sibling) 380390792Sgshapiro { 380490792Sgshapiro if (WILL_BE_QUEUED(ee->e_sendmode)) 380590792Sgshapiro continue; 380690792Sgshapiro if (shouldqueue(ee->e_msgpriority, ee->e_ctime)) 380790792Sgshapiro { 380890792Sgshapiro ee->e_sendmode = SM_QUEUE; 380990792Sgshapiro continue; 381090792Sgshapiro } 381190792Sgshapiro else if (QueueMode != QM_QUARANTINE && 381290792Sgshapiro ee->e_quarmsg != NULL) 381390792Sgshapiro { 381490792Sgshapiro ee->e_sendmode = SM_QUEUE; 381590792Sgshapiro continue; 381690792Sgshapiro } 381790792Sgshapiro anything_to_send = true; 381890792Sgshapiro 381990792Sgshapiro /* close all the queue files */ 382090792Sgshapiro closexscript(ee); 382190792Sgshapiro if (ee->e_dfp != NULL) 382290792Sgshapiro { 382390792Sgshapiro (void) sm_io_close(ee->e_dfp, SM_TIME_DEFAULT); 382490792Sgshapiro ee->e_dfp = NULL; 382590792Sgshapiro } 382690792Sgshapiro unlockqueue(ee); 382790792Sgshapiro } 382890792Sgshapiro if (anything_to_send) 382990792Sgshapiro { 383090792Sgshapiro#if PIPELINING 383190792Sgshapiro /* 383290792Sgshapiro ** XXX if we don't do this, we get 250 twice 383390792Sgshapiro ** because it is also flushed in the child. 383490792Sgshapiro */ 383590792Sgshapiro 383690792Sgshapiro (void) sm_io_flush(OutChannel, SM_TIME_DEFAULT); 383790792Sgshapiro#endif /* PIPELINING */ 383890792Sgshapiro (void) doworklist(e, true, true); 383990792Sgshapiro } 384090792Sgshapiro } 384190792Sgshapiro 384290792Sgshapiro abortmessage: 3843203004Sgshapiro if (tTd(92, 2)) 3844203004Sgshapiro sm_dprintf("abortmessage: e_id=%s, EF_LOGSENDER=%d, LogLevel=%d\n", 3845203004Sgshapiro e->e_id, bitset(EF_LOGSENDER, e->e_flags), LogLevel); 384690792Sgshapiro if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags)) 384790792Sgshapiro logsender(e, NULL); 384890792Sgshapiro e->e_flags &= ~EF_LOGSENDER; 384990792Sgshapiro 385090792Sgshapiro /* clean up a bit */ 385190792Sgshapiro smtp->sm_gotmail = false; 385290792Sgshapiro 385390792Sgshapiro /* 385490792Sgshapiro ** Call dropenvelope if and only if the envelope is *not* 385590792Sgshapiro ** being processed by the child process forked by doworklist(). 385690792Sgshapiro */ 385790792Sgshapiro 385890792Sgshapiro if (aborting || bitset(EF_DISCARD, e->e_flags)) 3859203004Sgshapiro (void) dropenvelope(e, true, false); 386090792Sgshapiro else 386190792Sgshapiro { 386290792Sgshapiro for (ee = e; ee != NULL; ee = ee->e_sibling) 386390792Sgshapiro { 386490792Sgshapiro if (!doublequeue && 386590792Sgshapiro QueueMode != QM_QUARANTINE && 386690792Sgshapiro ee->e_quarmsg != NULL) 386790792Sgshapiro { 3868203004Sgshapiro (void) dropenvelope(ee, true, false); 386990792Sgshapiro continue; 387090792Sgshapiro } 387190792Sgshapiro if (WILL_BE_QUEUED(ee->e_sendmode)) 3872203004Sgshapiro (void) dropenvelope(ee, true, false); 387390792Sgshapiro } 387490792Sgshapiro } 387590792Sgshapiro 387690792Sgshapiro CurEnv = e; 3877168515Sgshapiro features = e->e_features; 3878182352Sgshapiro sm_rpool_free(e->e_rpool); 387990792Sgshapiro newenvelope(e, e, sm_rpool_new_x(NULL)); 388090792Sgshapiro e->e_flags = BlankEnvelope.e_flags; 3881168515Sgshapiro e->e_features = features; 388290792Sgshapiro 388390792Sgshapiro /* restore connection quarantining */ 388490792Sgshapiro if (smtp->sm_quarmsg == NULL) 388590792Sgshapiro { 388690792Sgshapiro e->e_quarmsg = NULL; 388790792Sgshapiro macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), ""); 388890792Sgshapiro } 388990792Sgshapiro else 389090792Sgshapiro { 389190792Sgshapiro e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, smtp->sm_quarmsg); 389290792Sgshapiro macdefine(&e->e_macro, A_PERM, 389390792Sgshapiro macid("{quarantine}"), e->e_quarmsg); 389490792Sgshapiro } 3895157001Sgshapiro return rv; 389638032Speter} 389790792Sgshapiro/* 389890792Sgshapiro** LOGUNDELRCPTS -- log undelivered (or all) recipients. 389990792Sgshapiro** 390090792Sgshapiro** Parameters: 390190792Sgshapiro** e -- envelope. 390290792Sgshapiro** msg -- message for Stat= 390390792Sgshapiro** level -- log level. 390490792Sgshapiro** all -- log all recipients. 390590792Sgshapiro** 390690792Sgshapiro** Returns: 390790792Sgshapiro** none. 390890792Sgshapiro** 390990792Sgshapiro** Side Effects: 391090792Sgshapiro** logs undelivered (or all) recipients 391190792Sgshapiro*/ 391290792Sgshapiro 391390792Sgshapirovoid 391490792Sgshapirologundelrcpts(e, msg, level, all) 391590792Sgshapiro ENVELOPE *e; 391690792Sgshapiro char *msg; 391790792Sgshapiro int level; 391890792Sgshapiro bool all; 391990792Sgshapiro{ 392090792Sgshapiro ADDRESS *a; 392190792Sgshapiro 392290792Sgshapiro if (LogLevel <= level || msg == NULL || *msg == '\0') 392390792Sgshapiro return; 392490792Sgshapiro 392590792Sgshapiro /* Clear $h so relay= doesn't get mislogged by logdelivery() */ 392690792Sgshapiro macdefine(&e->e_macro, A_PERM, 'h', NULL); 392790792Sgshapiro 392890792Sgshapiro /* Log who the mail would have gone to */ 392990792Sgshapiro for (a = e->e_sendqueue; a != NULL; a = a->q_next) 393090792Sgshapiro { 393190792Sgshapiro if (!QS_IS_UNDELIVERED(a->q_state) && !all) 393290792Sgshapiro continue; 393390792Sgshapiro e->e_to = a->q_paddr; 3934203004Sgshapiro logdelivery(NULL, NULL, 3935203004Sgshapiro#if _FFR_MILTER_ENHSC 3936203004Sgshapiro (a->q_status == NULL && e->e_enhsc[0] != '\0') 3937203004Sgshapiro ? e->e_enhsc : 3938203004Sgshapiro#endif /* _FFR_MILTER_ENHSC */ 3939203004Sgshapiro a->q_status, 3940203004Sgshapiro msg, NULL, (time_t) 0, e); 394190792Sgshapiro } 394290792Sgshapiro e->e_to = NULL; 394390792Sgshapiro} 394490792Sgshapiro/* 394538032Speter** CHECKSMTPATTACK -- check for denial-of-service attack by repetition 394638032Speter** 394738032Speter** Parameters: 394838032Speter** pcounter -- pointer to a counter for this command. 394938032Speter** maxcount -- maximum value for this counter before we 395038032Speter** slow down. 395164562Sgshapiro** waitnow -- sleep now (in this routine)? 395238032Speter** cname -- command name for logging. 395338032Speter** e -- the current envelope. 395438032Speter** 395538032Speter** Returns: 3956132943Sgshapiro** time to wait, 3957132943Sgshapiro** STOP_ATTACK if twice as many commands as allowed and 3958132943Sgshapiro** MaxChildren > 0. 395938032Speter** 396038032Speter** Side Effects: 396138032Speter** Slows down if we seem to be under attack. 396238032Speter*/ 396338032Speter 396464562Sgshapirostatic time_t 396564562Sgshapirochecksmtpattack(pcounter, maxcount, waitnow, cname, e) 396690792Sgshapiro volatile unsigned int *pcounter; 3967132943Sgshapiro unsigned int maxcount; 396864562Sgshapiro bool waitnow; 396938032Speter char *cname; 397038032Speter ENVELOPE *e; 397138032Speter{ 397290792Sgshapiro if (maxcount <= 0) /* no limit */ 397390792Sgshapiro return (time_t) 0; 397490792Sgshapiro 397538032Speter if (++(*pcounter) >= maxcount) 397638032Speter { 3977132943Sgshapiro unsigned int shift; 397864562Sgshapiro time_t s; 397964562Sgshapiro 398038032Speter if (*pcounter == maxcount && LogLevel > 5) 398138032Speter { 398238032Speter sm_syslog(LOG_INFO, e->e_id, 3983110560Sgshapiro "%s: possible SMTP attack: command=%.40s, count=%u", 398477349Sgshapiro CurSmtpClient, cname, *pcounter); 398538032Speter } 3986132943Sgshapiro shift = *pcounter - maxcount; 3987132943Sgshapiro s = 1 << shift; 3988132943Sgshapiro if (shift > MAXSHIFT || s >= MAXTIMEOUT || s <= 0) 398964562Sgshapiro s = MAXTIMEOUT; 399090792Sgshapiro 3991132943Sgshapiro#define IS_ATTACK(s) ((MaxChildren > 0 && *pcounter >= maxcount * 2) \ 3992132943Sgshapiro ? STOP_ATTACK : (time_t) s) 3993132943Sgshapiro 399464562Sgshapiro /* sleep at least 1 second before returning */ 399564562Sgshapiro (void) sleep(*pcounter / maxcount); 399664562Sgshapiro s -= *pcounter / maxcount; 3997132943Sgshapiro if (s >= MAXTIMEOUT || s < 0) 3998132943Sgshapiro s = MAXTIMEOUT; 3999132943Sgshapiro if (waitnow && s > 0) 400064562Sgshapiro { 400164562Sgshapiro (void) sleep(s); 4002132943Sgshapiro return IS_ATTACK(0); 400364562Sgshapiro } 4004132943Sgshapiro return IS_ATTACK(s); 400538032Speter } 400690792Sgshapiro return (time_t) 0; 400738032Speter} 400890792Sgshapiro/* 400990792Sgshapiro** SETUP_SMTPD_IO -- setup I/O fd correctly for the SMTP server 401090792Sgshapiro** 401190792Sgshapiro** Parameters: 401290792Sgshapiro** none. 401390792Sgshapiro** 401490792Sgshapiro** Returns: 401590792Sgshapiro** nothing. 401690792Sgshapiro** 401790792Sgshapiro** Side Effects: 401890792Sgshapiro** may change I/O fd. 401990792Sgshapiro*/ 402090792Sgshapiro 402190792Sgshapirostatic void 402290792Sgshapirosetup_smtpd_io() 402390792Sgshapiro{ 402490792Sgshapiro int inchfd, outchfd, outfd; 402590792Sgshapiro 402690792Sgshapiro inchfd = sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL); 402790792Sgshapiro outchfd = sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL); 402890792Sgshapiro outfd = sm_io_getinfo(smioout, SM_IO_WHAT_FD, NULL); 402990792Sgshapiro if (outchfd != outfd) 403090792Sgshapiro { 403190792Sgshapiro /* arrange for debugging output to go to remote host */ 403290792Sgshapiro (void) dup2(outchfd, outfd); 403390792Sgshapiro } 403490792Sgshapiro 403590792Sgshapiro /* 403690792Sgshapiro ** if InChannel and OutChannel are stdin/stdout 403790792Sgshapiro ** and connected to ttys 403890792Sgshapiro ** and fcntl(STDIN, F_SETFL, O_NONBLOCKING) also changes STDOUT, 403990792Sgshapiro ** then "chain" them together. 404090792Sgshapiro */ 404190792Sgshapiro 404290792Sgshapiro if (inchfd == STDIN_FILENO && outchfd == STDOUT_FILENO && 404390792Sgshapiro isatty(inchfd) && isatty(outchfd)) 404490792Sgshapiro { 404590792Sgshapiro int inmode, outmode; 404690792Sgshapiro 404790792Sgshapiro inmode = fcntl(inchfd, F_GETFL, 0); 404890792Sgshapiro if (inmode == -1) 404990792Sgshapiro { 405090792Sgshapiro if (LogLevel > 11) 405190792Sgshapiro sm_syslog(LOG_INFO, NOQID, 405290792Sgshapiro "fcntl(inchfd, F_GETFL) failed: %s", 405390792Sgshapiro sm_errstring(errno)); 405490792Sgshapiro return; 405590792Sgshapiro } 405690792Sgshapiro outmode = fcntl(outchfd, F_GETFL, 0); 405790792Sgshapiro if (outmode == -1) 405890792Sgshapiro { 405990792Sgshapiro if (LogLevel > 11) 406090792Sgshapiro sm_syslog(LOG_INFO, NOQID, 406190792Sgshapiro "fcntl(outchfd, F_GETFL) failed: %s", 406290792Sgshapiro sm_errstring(errno)); 406390792Sgshapiro return; 406490792Sgshapiro } 406590792Sgshapiro if (bitset(O_NONBLOCK, inmode) || 406690792Sgshapiro bitset(O_NONBLOCK, outmode) || 406790792Sgshapiro fcntl(inchfd, F_SETFL, inmode | O_NONBLOCK) == -1) 406890792Sgshapiro return; 406990792Sgshapiro outmode = fcntl(outchfd, F_GETFL, 0); 407090792Sgshapiro if (outmode != -1 && bitset(O_NONBLOCK, outmode)) 407190792Sgshapiro { 407290792Sgshapiro /* changing InChannel also changes OutChannel */ 407390792Sgshapiro sm_io_automode(OutChannel, InChannel); 407490792Sgshapiro if (tTd(97, 4) && LogLevel > 9) 407590792Sgshapiro sm_syslog(LOG_INFO, NOQID, 407690792Sgshapiro "set automode for I (%d)/O (%d) in SMTP server", 407790792Sgshapiro inchfd, outchfd); 407890792Sgshapiro } 407990792Sgshapiro 408090792Sgshapiro /* undo change of inchfd */ 408190792Sgshapiro (void) fcntl(inchfd, F_SETFL, inmode); 408290792Sgshapiro } 408390792Sgshapiro} 408490792Sgshapiro/* 408538032Speter** SKIPWORD -- skip a fixed word. 408638032Speter** 408738032Speter** Parameters: 408838032Speter** p -- place to start looking. 408938032Speter** w -- word to skip. 409038032Speter** 409138032Speter** Returns: 409238032Speter** p following w. 409338032Speter** NULL on error. 409438032Speter** 409538032Speter** Side Effects: 409638032Speter** clobbers the p data area. 409738032Speter*/ 409838032Speter 409938032Speterstatic char * 410038032Speterskipword(p, w) 410138032Speter register char *volatile p; 410238032Speter char *w; 410338032Speter{ 410438032Speter register char *q; 410538032Speter char *firstp = p; 410638032Speter 410738032Speter /* find beginning of word */ 410890792Sgshapiro SKIP_SPACE(p); 410938032Speter q = p; 411038032Speter 411138032Speter /* find end of word */ 411238032Speter while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p))) 411338032Speter p++; 411438032Speter while (isascii(*p) && isspace(*p)) 411538032Speter *p++ = '\0'; 411638032Speter if (*p != ':') 411738032Speter { 411838032Speter syntax: 411964562Sgshapiro usrerr("501 5.5.2 Syntax error in parameters scanning \"%s\"", 412038032Speter shortenstring(firstp, MAXSHORTSTR)); 412164562Sgshapiro return NULL; 412238032Speter } 412338032Speter *p++ = '\0'; 412490792Sgshapiro SKIP_SPACE(p); 412538032Speter 412638032Speter if (*p == '\0') 412738032Speter goto syntax; 412838032Speter 412938032Speter /* see if the input word matches desired word */ 413090792Sgshapiro if (sm_strcasecmp(q, w)) 413138032Speter goto syntax; 413238032Speter 413364562Sgshapiro return p; 413438032Speter} 4135159609Sgshapiro 413690792Sgshapiro/* 4137168515Sgshapiro** RESET_MAIL_ESMTP_ARGS -- process ESMTP arguments from MAIL line 4138168515Sgshapiro** 4139168515Sgshapiro** Parameters: 4140168515Sgshapiro** e -- the envelope. 4141168515Sgshapiro** 4142168515Sgshapiro** Returns: 4143168515Sgshapiro** none. 4144168515Sgshapiro*/ 4145168515Sgshapiro 4146168515Sgshapirovoid 4147168515Sgshapiroreset_mail_esmtp_args(e) 4148168515Sgshapiro ENVELOPE *e; 4149168515Sgshapiro{ 4150168515Sgshapiro /* "size": no reset */ 4151168515Sgshapiro 4152168515Sgshapiro /* "body" */ 4153168515Sgshapiro SevenBitInput = SevenBitInput_Saved; 4154168515Sgshapiro e->e_bodytype = NULL; 4155168515Sgshapiro 4156168515Sgshapiro /* "envid" */ 4157168515Sgshapiro e->e_envid = NULL; 4158168515Sgshapiro macdefine(&e->e_macro, A_PERM, macid("{dsn_envid}"), NULL); 4159168515Sgshapiro 4160168515Sgshapiro /* "ret" */ 4161173340Sgshapiro e->e_flags &= ~(EF_RET_PARAM|EF_NO_BODY_RETN); 4162168515Sgshapiro macdefine(&e->e_macro, A_TEMP, macid("{dsn_ret}"), NULL); 4163168515Sgshapiro 4164168515Sgshapiro#if SASL 4165168515Sgshapiro /* "auth" */ 4166168515Sgshapiro macdefine(&e->e_macro, A_TEMP, macid("{auth_author}"), NULL); 4167168515Sgshapiro e->e_auth_param = ""; 4168168515Sgshapiro# if _FFR_AUTH_PASSING 4169168515Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 4170168515Sgshapiro macid("{auth_author}"), NULL); 4171168515Sgshapiro# endif /* _FFR_AUTH_PASSING */ 4172168515Sgshapiro#endif /* SASL */ 4173168515Sgshapiro 4174168515Sgshapiro /* "by" */ 4175168515Sgshapiro e->e_deliver_by = 0; 4176168515Sgshapiro e->e_dlvr_flag = 0; 4177168515Sgshapiro} 4178168515Sgshapiro 4179168515Sgshapiro/* 418038032Speter** MAIL_ESMTP_ARGS -- process ESMTP arguments from MAIL line 418138032Speter** 418238032Speter** Parameters: 4183168515Sgshapiro** a -- address (unused, for compatibility with rcpt_esmtp_args) 418438032Speter** kp -- the parameter key. 418538032Speter** vp -- the value of that parameter. 418638032Speter** e -- the envelope. 418738032Speter** 418838032Speter** Returns: 418938032Speter** none. 419038032Speter*/ 419138032Speter 4192168515Sgshapirovoid 4193168515Sgshapiromail_esmtp_args(a, kp, vp, e) 4194168515Sgshapiro ADDRESS *a; 419538032Speter char *kp; 419638032Speter char *vp; 419738032Speter ENVELOPE *e; 419838032Speter{ 419990792Sgshapiro if (sm_strcasecmp(kp, "size") == 0) 420038032Speter { 420138032Speter if (vp == NULL) 420238032Speter { 420364562Sgshapiro usrerr("501 5.5.2 SIZE requires a value"); 420438032Speter /* NOTREACHED */ 420538032Speter } 420690792Sgshapiro macdefine(&e->e_macro, A_TEMP, macid("{msg_size}"), vp); 420790792Sgshapiro errno = 0; 420871345Sgshapiro e->e_msgsize = strtol(vp, (char **) NULL, 10); 420966494Sgshapiro if (e->e_msgsize == LONG_MAX && errno == ERANGE) 421066494Sgshapiro { 421166494Sgshapiro usrerr("552 5.2.3 Message size exceeds maximum value"); 421266494Sgshapiro /* NOTREACHED */ 421366494Sgshapiro } 421490792Sgshapiro if (e->e_msgsize < 0) 421590792Sgshapiro { 421690792Sgshapiro usrerr("552 5.2.3 Message size invalid"); 421790792Sgshapiro /* NOTREACHED */ 421890792Sgshapiro } 421938032Speter } 422090792Sgshapiro else if (sm_strcasecmp(kp, "body") == 0) 422138032Speter { 422238032Speter if (vp == NULL) 422338032Speter { 422464562Sgshapiro usrerr("501 5.5.2 BODY requires a value"); 422538032Speter /* NOTREACHED */ 422638032Speter } 422790792Sgshapiro else if (sm_strcasecmp(vp, "8bitmime") == 0) 422838032Speter { 422990792Sgshapiro SevenBitInput = false; 423038032Speter } 423190792Sgshapiro else if (sm_strcasecmp(vp, "7bit") == 0) 423238032Speter { 423390792Sgshapiro SevenBitInput = true; 423438032Speter } 423538032Speter else 423638032Speter { 423790792Sgshapiro usrerr("501 5.5.4 Unknown BODY type %s", vp); 423838032Speter /* NOTREACHED */ 423938032Speter } 424090792Sgshapiro e->e_bodytype = sm_rpool_strdup_x(e->e_rpool, vp); 424138032Speter } 424290792Sgshapiro else if (sm_strcasecmp(kp, "envid") == 0) 424338032Speter { 4244168515Sgshapiro if (!bitset(SRV_OFFER_DSN, e->e_features)) 424564562Sgshapiro { 424664562Sgshapiro usrerr("504 5.7.0 Sorry, ENVID not supported, we do not allow DSN"); 424764562Sgshapiro /* NOTREACHED */ 424864562Sgshapiro } 424938032Speter if (vp == NULL) 425038032Speter { 425164562Sgshapiro usrerr("501 5.5.2 ENVID requires a value"); 425238032Speter /* NOTREACHED */ 425338032Speter } 425438032Speter if (!xtextok(vp)) 425538032Speter { 425664562Sgshapiro usrerr("501 5.5.4 Syntax error in ENVID parameter value"); 425738032Speter /* NOTREACHED */ 425838032Speter } 425938032Speter if (e->e_envid != NULL) 426038032Speter { 426164562Sgshapiro usrerr("501 5.5.0 Duplicate ENVID parameter"); 426238032Speter /* NOTREACHED */ 426338032Speter } 426490792Sgshapiro e->e_envid = sm_rpool_strdup_x(e->e_rpool, vp); 426590792Sgshapiro macdefine(&e->e_macro, A_PERM, 426690792Sgshapiro macid("{dsn_envid}"), e->e_envid); 426738032Speter } 426890792Sgshapiro else if (sm_strcasecmp(kp, "ret") == 0) 426938032Speter { 4270168515Sgshapiro if (!bitset(SRV_OFFER_DSN, e->e_features)) 427164562Sgshapiro { 427264562Sgshapiro usrerr("504 5.7.0 Sorry, RET not supported, we do not allow DSN"); 427364562Sgshapiro /* NOTREACHED */ 427464562Sgshapiro } 427538032Speter if (vp == NULL) 427638032Speter { 427764562Sgshapiro usrerr("501 5.5.2 RET requires a value"); 427838032Speter /* NOTREACHED */ 427938032Speter } 428038032Speter if (bitset(EF_RET_PARAM, e->e_flags)) 428138032Speter { 428264562Sgshapiro usrerr("501 5.5.0 Duplicate RET parameter"); 428338032Speter /* NOTREACHED */ 428438032Speter } 428538032Speter e->e_flags |= EF_RET_PARAM; 428690792Sgshapiro if (sm_strcasecmp(vp, "hdrs") == 0) 428738032Speter e->e_flags |= EF_NO_BODY_RETN; 428890792Sgshapiro else if (sm_strcasecmp(vp, "full") != 0) 428938032Speter { 429064562Sgshapiro usrerr("501 5.5.2 Bad argument \"%s\" to RET", vp); 429138032Speter /* NOTREACHED */ 429238032Speter } 429390792Sgshapiro macdefine(&e->e_macro, A_TEMP, macid("{dsn_ret}"), vp); 429438032Speter } 429590792Sgshapiro#if SASL 429690792Sgshapiro else if (sm_strcasecmp(kp, "auth") == 0) 429764562Sgshapiro { 429864562Sgshapiro int len; 429964562Sgshapiro char *q; 430064562Sgshapiro char *auth_param; /* the value of the AUTH=x */ 430164562Sgshapiro bool saveQuickAbort = QuickAbort; 430264562Sgshapiro bool saveSuprErrs = SuprErrs; 430390792Sgshapiro bool saveExitStat = ExitStat; 430464562Sgshapiro 430564562Sgshapiro if (vp == NULL) 430664562Sgshapiro { 430764562Sgshapiro usrerr("501 5.5.2 AUTH= requires a value"); 430864562Sgshapiro /* NOTREACHED */ 430964562Sgshapiro } 431064562Sgshapiro if (e->e_auth_param != NULL) 431164562Sgshapiro { 431264562Sgshapiro usrerr("501 5.5.0 Duplicate AUTH parameter"); 431364562Sgshapiro /* NOTREACHED */ 431464562Sgshapiro } 431564562Sgshapiro if ((q = strchr(vp, ' ')) != NULL) 431664562Sgshapiro len = q - vp + 1; 431764562Sgshapiro else 431864562Sgshapiro len = strlen(vp) + 1; 431964562Sgshapiro auth_param = xalloc(len); 432090792Sgshapiro (void) sm_strlcpy(auth_param, vp, len); 432164562Sgshapiro if (!xtextok(auth_param)) 432264562Sgshapiro { 432364562Sgshapiro usrerr("501 5.5.4 Syntax error in AUTH parameter value"); 432464562Sgshapiro /* just a warning? */ 432564562Sgshapiro /* NOTREACHED */ 432664562Sgshapiro } 432764562Sgshapiro 432864562Sgshapiro /* XXX define this always or only if trusted? */ 4329132943Sgshapiro macdefine(&e->e_macro, A_TEMP, macid("{auth_author}"), 4330132943Sgshapiro auth_param); 433164562Sgshapiro 433264562Sgshapiro /* 433364562Sgshapiro ** call Strust_auth to find out whether 433464562Sgshapiro ** auth_param is acceptable (trusted) 433564562Sgshapiro ** we shouldn't trust it if not authenticated 433664562Sgshapiro ** (required by RFC, leave it to ruleset?) 433764562Sgshapiro */ 433864562Sgshapiro 433990792Sgshapiro SuprErrs = true; 434090792Sgshapiro QuickAbort = false; 434164562Sgshapiro if (strcmp(auth_param, "<>") != 0 && 4342132943Sgshapiro (rscheck("trust_auth", auth_param, NULL, e, RSF_RMCOMM, 4343168515Sgshapiro 9, NULL, NOQID, NULL) != EX_OK || Errors > 0)) 434464562Sgshapiro { 434564562Sgshapiro if (tTd(95, 8)) 434664562Sgshapiro { 434764562Sgshapiro q = e->e_auth_param; 434890792Sgshapiro sm_dprintf("auth=\"%.100s\" not trusted user=\"%.100s\"\n", 4349132943Sgshapiro auth_param, (q == NULL) ? "" : q); 435064562Sgshapiro } 435190792Sgshapiro 435264562Sgshapiro /* not trusted */ 435390792Sgshapiro e->e_auth_param = "<>"; 435490792Sgshapiro# if _FFR_AUTH_PASSING 435590792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 435690792Sgshapiro macid("{auth_author}"), NULL); 435790792Sgshapiro# endif /* _FFR_AUTH_PASSING */ 435864562Sgshapiro } 435964562Sgshapiro else 436064562Sgshapiro { 436164562Sgshapiro if (tTd(95, 8)) 4362132943Sgshapiro sm_dprintf("auth=\"%.100s\" trusted\n", auth_param); 436390792Sgshapiro e->e_auth_param = sm_rpool_strdup_x(e->e_rpool, 436490792Sgshapiro auth_param); 436564562Sgshapiro } 436690792Sgshapiro sm_free(auth_param); /* XXX */ 436777349Sgshapiro 436864562Sgshapiro /* reset values */ 436964562Sgshapiro Errors = 0; 437064562Sgshapiro QuickAbort = saveQuickAbort; 437164562Sgshapiro SuprErrs = saveSuprErrs; 437290792Sgshapiro ExitStat = saveExitStat; 437364562Sgshapiro } 437490792Sgshapiro#endif /* SASL */ 437590792Sgshapiro#define PRTCHAR(c) ((isascii(c) && isprint(c)) ? (c) : '?') 437690792Sgshapiro 437790792Sgshapiro /* 437890792Sgshapiro ** "by" is only accepted if DeliverByMin >= 0. 437990792Sgshapiro ** We maybe could add this to the list of server_features. 438090792Sgshapiro */ 438190792Sgshapiro 438290792Sgshapiro else if (sm_strcasecmp(kp, "by") == 0 && DeliverByMin >= 0) 438390792Sgshapiro { 438490792Sgshapiro char *s; 438590792Sgshapiro 438690792Sgshapiro if (vp == NULL) 438790792Sgshapiro { 438890792Sgshapiro usrerr("501 5.5.2 BY= requires a value"); 438990792Sgshapiro /* NOTREACHED */ 439090792Sgshapiro } 439190792Sgshapiro errno = 0; 439290792Sgshapiro e->e_deliver_by = strtol(vp, &s, 10); 439390792Sgshapiro if (e->e_deliver_by == LONG_MIN || 439490792Sgshapiro e->e_deliver_by == LONG_MAX || 439590792Sgshapiro e->e_deliver_by > 999999999l || 439690792Sgshapiro e->e_deliver_by < -999999999l) 439790792Sgshapiro { 439890792Sgshapiro usrerr("501 5.5.2 BY=%s out of range", vp); 439990792Sgshapiro /* NOTREACHED */ 440090792Sgshapiro } 440190792Sgshapiro if (s == NULL || *s != ';') 440290792Sgshapiro { 440390792Sgshapiro usrerr("501 5.5.2 BY= missing ';'"); 440490792Sgshapiro /* NOTREACHED */ 440590792Sgshapiro } 440690792Sgshapiro e->e_dlvr_flag = 0; 440790792Sgshapiro ++s; /* XXX: spaces allowed? */ 440890792Sgshapiro SKIP_SPACE(s); 440990792Sgshapiro switch (tolower(*s)) 441090792Sgshapiro { 441190792Sgshapiro case 'n': 441290792Sgshapiro e->e_dlvr_flag = DLVR_NOTIFY; 441390792Sgshapiro break; 441490792Sgshapiro case 'r': 441590792Sgshapiro e->e_dlvr_flag = DLVR_RETURN; 441690792Sgshapiro if (e->e_deliver_by <= 0) 441790792Sgshapiro { 441890792Sgshapiro usrerr("501 5.5.4 mode R requires BY time > 0"); 441990792Sgshapiro /* NOTREACHED */ 442090792Sgshapiro } 442190792Sgshapiro if (DeliverByMin > 0 && e->e_deliver_by > 0 && 442290792Sgshapiro e->e_deliver_by < DeliverByMin) 442390792Sgshapiro { 442490792Sgshapiro usrerr("555 5.5.2 time %ld less than %ld", 442590792Sgshapiro e->e_deliver_by, (long) DeliverByMin); 442690792Sgshapiro /* NOTREACHED */ 442790792Sgshapiro } 442890792Sgshapiro break; 442990792Sgshapiro default: 443090792Sgshapiro usrerr("501 5.5.2 illegal by-mode '%c'", PRTCHAR(*s)); 443190792Sgshapiro /* NOTREACHED */ 443290792Sgshapiro } 443390792Sgshapiro ++s; /* XXX: spaces allowed? */ 443490792Sgshapiro SKIP_SPACE(s); 443590792Sgshapiro switch (tolower(*s)) 443690792Sgshapiro { 443790792Sgshapiro case 't': 443890792Sgshapiro e->e_dlvr_flag |= DLVR_TRACE; 443990792Sgshapiro break; 444090792Sgshapiro case '\0': 444190792Sgshapiro break; 444290792Sgshapiro default: 444390792Sgshapiro usrerr("501 5.5.2 illegal by-trace '%c'", PRTCHAR(*s)); 444490792Sgshapiro /* NOTREACHED */ 444590792Sgshapiro } 444690792Sgshapiro 444790792Sgshapiro /* XXX: check whether more characters follow? */ 444890792Sgshapiro } 444938032Speter else 445038032Speter { 445166494Sgshapiro usrerr("555 5.5.4 %s parameter unrecognized", kp); 445238032Speter /* NOTREACHED */ 445338032Speter } 445438032Speter} 4455168515Sgshapiro 445690792Sgshapiro/* 445738032Speter** RCPT_ESMTP_ARGS -- process ESMTP arguments from RCPT line 445838032Speter** 445938032Speter** Parameters: 446038032Speter** a -- the address corresponding to the To: parameter. 446138032Speter** kp -- the parameter key. 446238032Speter** vp -- the value of that parameter. 446338032Speter** e -- the envelope. 446438032Speter** 446538032Speter** Returns: 446638032Speter** none. 446738032Speter*/ 446838032Speter 4469168515Sgshapirovoid 4470168515Sgshapirorcpt_esmtp_args(a, kp, vp, e) 447138032Speter ADDRESS *a; 447238032Speter char *kp; 447338032Speter char *vp; 447438032Speter ENVELOPE *e; 447538032Speter{ 447690792Sgshapiro if (sm_strcasecmp(kp, "notify") == 0) 447738032Speter { 447838032Speter char *p; 447938032Speter 4480168515Sgshapiro if (!bitset(SRV_OFFER_DSN, e->e_features)) 448164562Sgshapiro { 448264562Sgshapiro usrerr("504 5.7.0 Sorry, NOTIFY not supported, we do not allow DSN"); 448364562Sgshapiro /* NOTREACHED */ 448464562Sgshapiro } 448538032Speter if (vp == NULL) 448638032Speter { 448764562Sgshapiro usrerr("501 5.5.2 NOTIFY requires a value"); 448838032Speter /* NOTREACHED */ 448938032Speter } 449038032Speter a->q_flags &= ~(QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY); 449138032Speter a->q_flags |= QHASNOTIFY; 449290792Sgshapiro macdefine(&e->e_macro, A_TEMP, macid("{dsn_notify}"), vp); 449364562Sgshapiro 449490792Sgshapiro if (sm_strcasecmp(vp, "never") == 0) 449538032Speter return; 449638032Speter for (p = vp; p != NULL; vp = p) 449738032Speter { 4498141858Sgshapiro char *s; 4499141858Sgshapiro 4500141858Sgshapiro s = p = strchr(p, ','); 450138032Speter if (p != NULL) 450238032Speter *p++ = '\0'; 450390792Sgshapiro if (sm_strcasecmp(vp, "success") == 0) 450438032Speter a->q_flags |= QPINGONSUCCESS; 450590792Sgshapiro else if (sm_strcasecmp(vp, "failure") == 0) 450638032Speter a->q_flags |= QPINGONFAILURE; 450790792Sgshapiro else if (sm_strcasecmp(vp, "delay") == 0) 450838032Speter a->q_flags |= QPINGONDELAY; 450938032Speter else 451038032Speter { 451164562Sgshapiro usrerr("501 5.5.4 Bad argument \"%s\" to NOTIFY", 451238032Speter vp); 451338032Speter /* NOTREACHED */ 451438032Speter } 4515141858Sgshapiro if (s != NULL) 4516141858Sgshapiro *s = ','; 451738032Speter } 451838032Speter } 451990792Sgshapiro else if (sm_strcasecmp(kp, "orcpt") == 0) 452038032Speter { 4521249865Sgshapiro char *p; 4522249865Sgshapiro 4523168515Sgshapiro if (!bitset(SRV_OFFER_DSN, e->e_features)) 452464562Sgshapiro { 452564562Sgshapiro usrerr("504 5.7.0 Sorry, ORCPT not supported, we do not allow DSN"); 452664562Sgshapiro /* NOTREACHED */ 452764562Sgshapiro } 452838032Speter if (vp == NULL) 452938032Speter { 453064562Sgshapiro usrerr("501 5.5.2 ORCPT requires a value"); 453138032Speter /* NOTREACHED */ 453238032Speter } 4533249865Sgshapiro if (a->q_orcpt != NULL) 453438032Speter { 4535249865Sgshapiro usrerr("501 5.5.0 Duplicate ORCPT parameter"); 4536249865Sgshapiro /* NOTREACHED */ 4537249865Sgshapiro } 4538249865Sgshapiro p = strchr(vp, ';'); 4539249865Sgshapiro if (p == NULL) 4540249865Sgshapiro { 454164562Sgshapiro usrerr("501 5.5.4 Syntax error in ORCPT parameter value"); 454238032Speter /* NOTREACHED */ 454338032Speter } 4544249865Sgshapiro *p = '\0'; 4545249865Sgshapiro if (!isatom(vp) || !xtextok(p + 1)) 454638032Speter { 4547249865Sgshapiro *p = ';'; 4548249865Sgshapiro usrerr("501 5.5.4 Syntax error in ORCPT parameter value"); 454938032Speter /* NOTREACHED */ 455038032Speter } 4551249865Sgshapiro *p = ';'; 455290792Sgshapiro a->q_orcpt = sm_rpool_strdup_x(e->e_rpool, vp); 455338032Speter } 455438032Speter else 455538032Speter { 455666494Sgshapiro usrerr("555 5.5.4 %s parameter unrecognized", kp); 455738032Speter /* NOTREACHED */ 455838032Speter } 455938032Speter} 456090792Sgshapiro/* 456138032Speter** PRINTVRFYADDR -- print an entry in the verify queue 456238032Speter** 456338032Speter** Parameters: 456490792Sgshapiro** a -- the address to print. 456538032Speter** last -- set if this is the last one. 456638032Speter** vrfy -- set if this is a VRFY command. 456738032Speter** 456838032Speter** Returns: 456938032Speter** none. 457038032Speter** 457138032Speter** Side Effects: 457238032Speter** Prints the appropriate 250 codes. 457338032Speter*/ 457464562Sgshapiro#define OFFF (3 + 1 + 5 + 1) /* offset in fmt: SMTP reply + enh. code */ 457538032Speter 457664562Sgshapirostatic void 457738032Speterprintvrfyaddr(a, last, vrfy) 457838032Speter register ADDRESS *a; 457938032Speter bool last; 458038032Speter bool vrfy; 458138032Speter{ 458264562Sgshapiro char fmtbuf[30]; 458338032Speter 458438032Speter if (vrfy && a->q_mailer != NULL && 458538032Speter !bitnset(M_VRFY250, a->q_mailer->m_flags)) 4586168515Sgshapiro (void) sm_strlcpy(fmtbuf, "252", sizeof(fmtbuf)); 458738032Speter else 4588168515Sgshapiro (void) sm_strlcpy(fmtbuf, "250", sizeof(fmtbuf)); 458938032Speter fmtbuf[3] = last ? ' ' : '-'; 4590168515Sgshapiro (void) sm_strlcpy(&fmtbuf[4], "2.1.5 ", sizeof(fmtbuf) - 4); 459138032Speter if (a->q_fullname == NULL) 459238032Speter { 459364562Sgshapiro if ((a->q_mailer == NULL || 459464562Sgshapiro a->q_mailer->m_addrtype == NULL || 459590792Sgshapiro sm_strcasecmp(a->q_mailer->m_addrtype, "rfc822") == 0) && 459664562Sgshapiro strchr(a->q_user, '@') == NULL) 459790792Sgshapiro (void) sm_strlcpy(&fmtbuf[OFFF], "<%s@%s>", 4598168515Sgshapiro sizeof(fmtbuf) - OFFF); 459938032Speter else 460090792Sgshapiro (void) sm_strlcpy(&fmtbuf[OFFF], "<%s>", 4601168515Sgshapiro sizeof(fmtbuf) - OFFF); 460238032Speter message(fmtbuf, a->q_user, MyHostName); 460338032Speter } 460438032Speter else 460538032Speter { 460664562Sgshapiro if ((a->q_mailer == NULL || 460764562Sgshapiro a->q_mailer->m_addrtype == NULL || 460890792Sgshapiro sm_strcasecmp(a->q_mailer->m_addrtype, "rfc822") == 0) && 460964562Sgshapiro strchr(a->q_user, '@') == NULL) 461090792Sgshapiro (void) sm_strlcpy(&fmtbuf[OFFF], "%s <%s@%s>", 4611168515Sgshapiro sizeof(fmtbuf) - OFFF); 461238032Speter else 461390792Sgshapiro (void) sm_strlcpy(&fmtbuf[OFFF], "%s <%s>", 4614168515Sgshapiro sizeof(fmtbuf) - OFFF); 461538032Speter message(fmtbuf, a->q_fullname, a->q_user, MyHostName); 461638032Speter } 461738032Speter} 461838032Speter 461990792Sgshapiro#if SASL 462090792Sgshapiro/* 462164562Sgshapiro** SASLMECHS -- get list of possible AUTH mechanisms 462264562Sgshapiro** 462364562Sgshapiro** Parameters: 462490792Sgshapiro** conn -- SASL connection info. 462590792Sgshapiro** mechlist -- output parameter for list of mechanisms. 462664562Sgshapiro** 462764562Sgshapiro** Returns: 462890792Sgshapiro** number of mechs. 462964562Sgshapiro*/ 463064562Sgshapiro 463164562Sgshapirostatic int 463264562Sgshapirosaslmechs(conn, mechlist) 463364562Sgshapiro sasl_conn_t *conn; 463464562Sgshapiro char **mechlist; 463564562Sgshapiro{ 463664562Sgshapiro int len, num, result; 463764562Sgshapiro 463864562Sgshapiro /* "user" is currently unused */ 463998121Sgshapiro# if SASL >= 20000 464098121Sgshapiro result = sasl_listmech(conn, NULL, 464198121Sgshapiro "", " ", "", (const char **) mechlist, 4642120256Sgshapiro (unsigned int *)&len, &num); 464398121Sgshapiro# else /* SASL >= 20000 */ 464464562Sgshapiro result = sasl_listmech(conn, "user", /* XXX */ 464564562Sgshapiro "", " ", "", mechlist, 464690792Sgshapiro (unsigned int *)&len, (unsigned int *)&num); 464798121Sgshapiro# endif /* SASL >= 20000 */ 464890792Sgshapiro if (result != SASL_OK) 464964562Sgshapiro { 465090792Sgshapiro if (LogLevel > 9) 465190792Sgshapiro sm_syslog(LOG_WARNING, NOQID, 465290792Sgshapiro "AUTH error: listmech=%d, num=%d", 465390792Sgshapiro result, num); 465490792Sgshapiro num = 0; 465590792Sgshapiro } 465690792Sgshapiro if (num > 0) 465790792Sgshapiro { 465864562Sgshapiro if (LogLevel > 11) 465964562Sgshapiro sm_syslog(LOG_INFO, NOQID, 466090792Sgshapiro "AUTH: available mech=%s, allowed mech=%s", 466164562Sgshapiro *mechlist, AuthMechanisms); 466290792Sgshapiro *mechlist = intersect(AuthMechanisms, *mechlist, NULL); 466364562Sgshapiro } 466464562Sgshapiro else 466564562Sgshapiro { 466690792Sgshapiro *mechlist = NULL; /* be paranoid... */ 466790792Sgshapiro if (result == SASL_OK && LogLevel > 9) 466864562Sgshapiro sm_syslog(LOG_WARNING, NOQID, 466990792Sgshapiro "AUTH warning: no mechanisms"); 467064562Sgshapiro } 467164562Sgshapiro return num; 467264562Sgshapiro} 467398121Sgshapiro 467498121Sgshapiro# if SASL >= 20000 467590792Sgshapiro/* 467664562Sgshapiro** PROXY_POLICY -- define proxy policy for AUTH 467764562Sgshapiro** 467864562Sgshapiro** Parameters: 467998121Sgshapiro** conn -- unused. 468090792Sgshapiro** context -- unused. 468198121Sgshapiro** requested_user -- authorization identity. 468298121Sgshapiro** rlen -- authorization identity length. 468390792Sgshapiro** auth_identity -- authentication identity. 468498121Sgshapiro** alen -- authentication identity length. 468598121Sgshapiro** def_realm -- default user realm. 468698121Sgshapiro** urlen -- user realm length. 468798121Sgshapiro** propctx -- unused. 468898121Sgshapiro** 468998121Sgshapiro** Returns: 469098121Sgshapiro** ok? 469198121Sgshapiro** 469298121Sgshapiro** Side Effects: 469398121Sgshapiro** sets {auth_authen} macro. 469498121Sgshapiro*/ 469598121Sgshapiro 469698121Sgshapiroint 469798121Sgshapiroproxy_policy(conn, context, requested_user, rlen, auth_identity, alen, 469898121Sgshapiro def_realm, urlen, propctx) 469998121Sgshapiro sasl_conn_t *conn; 470098121Sgshapiro void *context; 470198121Sgshapiro const char *requested_user; 470298121Sgshapiro unsigned rlen; 470398121Sgshapiro const char *auth_identity; 470498121Sgshapiro unsigned alen; 470598121Sgshapiro const char *def_realm; 470698121Sgshapiro unsigned urlen; 470798121Sgshapiro struct propctx *propctx; 470898121Sgshapiro{ 470998121Sgshapiro if (auth_identity == NULL) 471098121Sgshapiro return SASL_FAIL; 471198121Sgshapiro 471298121Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 4713223067Sgshapiro macid("{auth_authen}"), 4714223067Sgshapiro xtextify((char *) auth_identity, "=<>\")")); 471598121Sgshapiro 471698121Sgshapiro return SASL_OK; 471798121Sgshapiro} 471898121Sgshapiro# else /* SASL >= 20000 */ 471998121Sgshapiro 472098121Sgshapiro/* 472198121Sgshapiro** PROXY_POLICY -- define proxy policy for AUTH 472298121Sgshapiro** 472398121Sgshapiro** Parameters: 472498121Sgshapiro** context -- unused. 472598121Sgshapiro** auth_identity -- authentication identity. 472690792Sgshapiro** requested_user -- authorization identity. 472790792Sgshapiro** user -- allowed user (output). 472890792Sgshapiro** errstr -- possible error string (output). 472964562Sgshapiro** 473064562Sgshapiro** Returns: 473164562Sgshapiro** ok? 473264562Sgshapiro*/ 473364562Sgshapiro 473464562Sgshapiroint 473564562Sgshapiroproxy_policy(context, auth_identity, requested_user, user, errstr) 473664562Sgshapiro void *context; 473764562Sgshapiro const char *auth_identity; 473864562Sgshapiro const char *requested_user; 473964562Sgshapiro const char **user; 474064562Sgshapiro const char **errstr; 474164562Sgshapiro{ 474264562Sgshapiro if (user == NULL || auth_identity == NULL) 474364562Sgshapiro return SASL_FAIL; 474464562Sgshapiro *user = newstr(auth_identity); 474564562Sgshapiro return SASL_OK; 474664562Sgshapiro} 474798121Sgshapiro# endif /* SASL >= 20000 */ 474890792Sgshapiro#endif /* SASL */ 474964562Sgshapiro 475090792Sgshapiro#if STARTTLS 475190792Sgshapiro/* 475290792Sgshapiro** INITSRVTLS -- initialize server side TLS 475364562Sgshapiro** 475464562Sgshapiro** Parameters: 475590792Sgshapiro** tls_ok -- should tls initialization be done? 475664562Sgshapiro** 475764562Sgshapiro** Returns: 475890792Sgshapiro** succeeded? 475964562Sgshapiro** 476064562Sgshapiro** Side Effects: 476190792Sgshapiro** sets tls_ok_srv which is a static variable in this module. 476290792Sgshapiro** Do NOT remove assignments to it! 476364562Sgshapiro*/ 476464562Sgshapiro 476566494Sgshapirobool 476690792Sgshapiroinitsrvtls(tls_ok) 476790792Sgshapiro bool tls_ok; 476864562Sgshapiro{ 476990792Sgshapiro if (!tls_ok) 477090792Sgshapiro return false; 477164562Sgshapiro 477290792Sgshapiro /* do NOT remove assignment */ 4773203004Sgshapiro tls_ok_srv = inittls(&srv_ctx, TLS_Srv_Opts, Srv_SSL_Options, true, 4774203004Sgshapiro SrvCertFile, SrvKeyFile, 4775203004Sgshapiro CACertPath, CACertFile, DHParams); 477690792Sgshapiro return tls_ok_srv; 477764562Sgshapiro} 477890792Sgshapiro#endif /* STARTTLS */ 477964562Sgshapiro/* 478090792Sgshapiro** SRVFEATURES -- get features for SMTP server 478164562Sgshapiro** 478264562Sgshapiro** Parameters: 478390792Sgshapiro** e -- envelope (should be session context). 478490792Sgshapiro** clientname -- name of client. 478590792Sgshapiro** features -- default features for this invocation. 478664562Sgshapiro** 478764562Sgshapiro** Returns: 478890792Sgshapiro** server features. 478964562Sgshapiro*/ 479064562Sgshapiro 479190792Sgshapiro/* table with options: it uses just one character, how about strings? */ 479290792Sgshapirostatic struct 479364562Sgshapiro{ 479490792Sgshapiro char srvf_opt; 479590792Sgshapiro unsigned int srvf_flag; 479690792Sgshapiro} srv_feat_table[] = 479764562Sgshapiro{ 479890792Sgshapiro { 'A', SRV_OFFER_AUTH }, 4799132943Sgshapiro { 'B', SRV_OFFER_VERB }, 4800132943Sgshapiro { 'C', SRV_REQ_SEC }, 4801132943Sgshapiro { 'D', SRV_OFFER_DSN }, 4802132943Sgshapiro { 'E', SRV_OFFER_ETRN }, 4803132943Sgshapiro { 'L', SRV_REQ_AUTH }, 480490792Sgshapiro#if PIPELINING 480590792Sgshapiro# if _FFR_NO_PIPE 480690792Sgshapiro { 'N', SRV_NO_PIPE }, 480790792Sgshapiro# endif /* _FFR_NO_PIPE */ 480890792Sgshapiro { 'P', SRV_OFFER_PIPE }, 480990792Sgshapiro#endif /* PIPELINING */ 4810132943Sgshapiro { 'R', SRV_VRFY_CLT }, /* same as V; not documented */ 481190792Sgshapiro { 'S', SRV_OFFER_TLS }, 481290792Sgshapiro/* { 'T', SRV_TMP_FAIL }, */ 481390792Sgshapiro { 'V', SRV_VRFY_CLT }, 4814132943Sgshapiro { 'X', SRV_OFFER_EXPN }, 481590792Sgshapiro/* { 'Y', SRV_OFFER_VRFY }, */ 481690792Sgshapiro { '\0', SRV_NONE } 481790792Sgshapiro}; 481864562Sgshapiro 481990792Sgshapirostatic unsigned int 482090792Sgshapirosrvfeatures(e, clientname, features) 482190792Sgshapiro ENVELOPE *e; 482290792Sgshapiro char *clientname; 482390792Sgshapiro unsigned int features; 482477349Sgshapiro{ 482590792Sgshapiro int r, i, j; 482690792Sgshapiro char **pvp, c, opt; 482790792Sgshapiro char pvpbuf[PSBUFSIZE]; 482877349Sgshapiro 482990792Sgshapiro pvp = NULL; 483090792Sgshapiro r = rscap("srv_features", clientname, "", e, &pvp, pvpbuf, 483190792Sgshapiro sizeof(pvpbuf)); 483290792Sgshapiro if (r != EX_OK) 483390792Sgshapiro return features; 483490792Sgshapiro if (pvp == NULL || pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 483590792Sgshapiro return features; 483690792Sgshapiro if (pvp[1] != NULL && sm_strncasecmp(pvp[1], "temp", 4) == 0) 483790792Sgshapiro return SRV_TMP_FAIL; 483877349Sgshapiro 483964562Sgshapiro /* 484090792Sgshapiro ** General rule (see sendmail.h, d_flags): 484190792Sgshapiro ** lower case: required/offered, upper case: Not required/available 484290792Sgshapiro ** 484390792Sgshapiro ** Since we can change some features per daemon, we have both 484490792Sgshapiro ** cases here: turn on/off a feature. 484564562Sgshapiro */ 484664562Sgshapiro 484790792Sgshapiro for (i = 1; pvp[i] != NULL; i++) 484864562Sgshapiro { 484990792Sgshapiro c = pvp[i][0]; 485090792Sgshapiro j = 0; 485190792Sgshapiro for (;;) 485264562Sgshapiro { 485390792Sgshapiro if ((opt = srv_feat_table[j].srvf_opt) == '\0') 485464562Sgshapiro { 485590792Sgshapiro if (LogLevel > 9) 485690792Sgshapiro sm_syslog(LOG_WARNING, e->e_id, 485790792Sgshapiro "srvfeatures: unknown feature %s", 485890792Sgshapiro pvp[i]); 485990792Sgshapiro break; 486064562Sgshapiro } 486190792Sgshapiro if (c == opt) 486264562Sgshapiro { 486390792Sgshapiro features &= ~(srv_feat_table[j].srvf_flag); 486490792Sgshapiro break; 486564562Sgshapiro } 486690792Sgshapiro if (c == tolower(opt)) 486764562Sgshapiro { 486890792Sgshapiro features |= srv_feat_table[j].srvf_flag; 486990792Sgshapiro break; 487064562Sgshapiro } 487190792Sgshapiro ++j; 487264562Sgshapiro } 487364562Sgshapiro } 487490792Sgshapiro return features; 487564562Sgshapiro} 487664562Sgshapiro 487790792Sgshapiro/* 487838032Speter** HELP -- implement the HELP command. 487938032Speter** 488038032Speter** Parameters: 488138032Speter** topic -- the topic we want help for. 488290792Sgshapiro** e -- envelope. 488338032Speter** 488438032Speter** Returns: 488538032Speter** none. 488638032Speter** 488738032Speter** Side Effects: 488838032Speter** outputs the help file to message output. 488938032Speter*/ 489064562Sgshapiro#define HELPVSTR "#vers " 489164562Sgshapiro#define HELPVERSION 2 489238032Speter 489338032Spetervoid 489464562Sgshapirohelp(topic, e) 489538032Speter char *topic; 489664562Sgshapiro ENVELOPE *e; 489738032Speter{ 489890792Sgshapiro register SM_FILE_T *hf; 489964562Sgshapiro register char *p; 490038032Speter int len; 490138032Speter bool noinfo; 490290792Sgshapiro bool first = true; 490364562Sgshapiro long sff = SFF_OPENASROOT|SFF_REGONLY; 490438032Speter char buf[MAXLINE]; 490564562Sgshapiro char inp[MAXLINE]; 490664562Sgshapiro static int foundvers = -1; 490738032Speter extern char Version[]; 490838032Speter 490938032Speter if (DontLockReadFiles) 491038032Speter sff |= SFF_NOLOCK; 491164562Sgshapiro if (!bitnset(DBS_HELPFILEINUNSAFEDIRPATH, DontBlameSendmail)) 491238032Speter sff |= SFF_SAFEDIRPATH; 491338032Speter 491438032Speter if (HelpFile == NULL || 491538032Speter (hf = safefopen(HelpFile, O_RDONLY, 0444, sff)) == NULL) 491638032Speter { 491738032Speter /* no help */ 491838032Speter errno = 0; 491964562Sgshapiro message("502 5.3.0 Sendmail %s -- HELP not implemented", 492064562Sgshapiro Version); 492138032Speter return; 492238032Speter } 492338032Speter 492438032Speter if (topic == NULL || *topic == '\0') 492538032Speter { 492638032Speter topic = "smtp"; 492790792Sgshapiro noinfo = false; 492838032Speter } 492938032Speter else 493038032Speter { 493138032Speter makelower(topic); 493290792Sgshapiro noinfo = true; 493338032Speter } 493438032Speter 493538032Speter len = strlen(topic); 493638032Speter 4937249865Sgshapiro while (sm_io_fgets(hf, SM_TIME_DEFAULT, buf, sizeof(buf)) >= 0) 493838032Speter { 493964562Sgshapiro if (buf[0] == '#') 494064562Sgshapiro { 494164562Sgshapiro if (foundvers < 0 && 494264562Sgshapiro strncmp(buf, HELPVSTR, strlen(HELPVSTR)) == 0) 494364562Sgshapiro { 494464562Sgshapiro int h; 494564562Sgshapiro 494690792Sgshapiro if (sm_io_sscanf(buf + strlen(HELPVSTR), "%d", 494790792Sgshapiro &h) == 1) 494864562Sgshapiro foundvers = h; 494964562Sgshapiro } 495064562Sgshapiro continue; 495164562Sgshapiro } 495238032Speter if (strncmp(buf, topic, len) == 0) 495338032Speter { 495464562Sgshapiro if (first) 495564562Sgshapiro { 495690792Sgshapiro first = false; 495738032Speter 495864562Sgshapiro /* print version if no/old vers# in file */ 495964562Sgshapiro if (foundvers < 2 && !noinfo) 496064562Sgshapiro message("214-2.0.0 This is Sendmail version %s", Version); 496164562Sgshapiro } 496264562Sgshapiro p = strpbrk(buf, " \t"); 496338032Speter if (p == NULL) 496464562Sgshapiro p = buf + strlen(buf) - 1; 496538032Speter else 496638032Speter p++; 496790792Sgshapiro fixcrlf(p, true); 496864562Sgshapiro if (foundvers >= 2) 496964562Sgshapiro { 4970168515Sgshapiro char *lbp; 4971168515Sgshapiro int lbs = sizeof(buf) - (p - buf); 4972168515Sgshapiro 4973168515Sgshapiro lbp = translate_dollars(p, p, &lbs); 4974168515Sgshapiro expand(lbp, inp, sizeof(inp), e); 4975168515Sgshapiro if (p != lbp) 4976168515Sgshapiro sm_free(lbp); 497764562Sgshapiro p = inp; 497864562Sgshapiro } 497964562Sgshapiro message("214-2.0.0 %s", p); 498090792Sgshapiro noinfo = false; 498138032Speter } 498238032Speter } 498338032Speter 498438032Speter if (noinfo) 498564562Sgshapiro message("504 5.3.0 HELP topic \"%.10s\" unknown", topic); 498638032Speter else 498764562Sgshapiro message("214 2.0.0 End of HELP info"); 498864562Sgshapiro 498964562Sgshapiro if (foundvers != 0 && foundvers < HELPVERSION) 499064562Sgshapiro { 499164562Sgshapiro if (LogLevel > 1) 499264562Sgshapiro sm_syslog(LOG_WARNING, e->e_id, 499364562Sgshapiro "%s too old (require version %d)", 499464562Sgshapiro HelpFile, HELPVERSION); 499564562Sgshapiro 499664562Sgshapiro /* avoid log next time */ 499764562Sgshapiro foundvers = 0; 499864562Sgshapiro } 499964562Sgshapiro 500090792Sgshapiro (void) sm_io_close(hf, SM_TIME_DEFAULT); 500138032Speter} 5002120256Sgshapiro 5003120256Sgshapiro#if SASL 5004120256Sgshapiro/* 5005120256Sgshapiro** RESET_SASLCONN -- reset SASL connection data 5006120256Sgshapiro** 5007120256Sgshapiro** Parameters: 5008120256Sgshapiro** conn -- SASL connection context 5009120256Sgshapiro** hostname -- host name 5010120256Sgshapiro** various connection data 5011120256Sgshapiro** 5012120256Sgshapiro** Returns: 5013120256Sgshapiro** SASL result 5014120256Sgshapiro*/ 5015120256Sgshapiro 5016120256Sgshapirostatic int 5017147078Sgshapiroreset_saslconn(sasl_conn_t **conn, char *hostname, 5018120256Sgshapiro# if SASL >= 20000 5019120256Sgshapiro char *remoteip, char *localip, 5020120256Sgshapiro char *auth_id, sasl_ssf_t * ext_ssf) 5021120256Sgshapiro# else /* SASL >= 20000 */ 5022147078Sgshapiro struct sockaddr_in *saddr_r, struct sockaddr_in *saddr_l, 5023120256Sgshapiro sasl_external_properties_t * ext_ssf) 5024120256Sgshapiro# endif /* SASL >= 20000 */ 5025120256Sgshapiro{ 5026120256Sgshapiro int result; 5027120256Sgshapiro 5028120256Sgshapiro sasl_dispose(conn); 5029120256Sgshapiro# if SASL >= 20000 5030120256Sgshapiro result = sasl_server_new("smtp", hostname, NULL, NULL, NULL, 5031120256Sgshapiro NULL, 0, conn); 5032120256Sgshapiro# elif SASL > 10505 5033120256Sgshapiro /* use empty realm: only works in SASL > 1.5.5 */ 5034120256Sgshapiro result = sasl_server_new("smtp", hostname, "", NULL, 0, conn); 5035120256Sgshapiro# else /* SASL >= 20000 */ 5036120256Sgshapiro /* use no realm -> realm is set to hostname by SASL lib */ 5037120256Sgshapiro result = sasl_server_new("smtp", hostname, NULL, NULL, 0, 5038120256Sgshapiro conn); 5039120256Sgshapiro# endif /* SASL >= 20000 */ 5040120256Sgshapiro if (result != SASL_OK) 5041120256Sgshapiro return result; 5042120256Sgshapiro 5043120256Sgshapiro# if SASL >= 20000 5044120256Sgshapiro# if NETINET || NETINET6 5045147078Sgshapiro if (remoteip != NULL && *remoteip != '\0') 5046120256Sgshapiro result = sasl_setprop(*conn, SASL_IPREMOTEPORT, remoteip); 5047120256Sgshapiro if (result != SASL_OK) 5048120256Sgshapiro return result; 5049120256Sgshapiro 5050147078Sgshapiro if (localip != NULL && *localip != '\0') 5051120256Sgshapiro result = sasl_setprop(*conn, SASL_IPLOCALPORT, localip); 5052120256Sgshapiro if (result != SASL_OK) 5053120256Sgshapiro return result; 5054120256Sgshapiro# endif /* NETINET || NETINET6 */ 5055120256Sgshapiro 5056120256Sgshapiro result = sasl_setprop(*conn, SASL_SSF_EXTERNAL, ext_ssf); 5057120256Sgshapiro if (result != SASL_OK) 5058120256Sgshapiro return result; 5059120256Sgshapiro 5060120256Sgshapiro result = sasl_setprop(*conn, SASL_AUTH_EXTERNAL, auth_id); 5061120256Sgshapiro if (result != SASL_OK) 5062120256Sgshapiro return result; 5063120256Sgshapiro# else /* SASL >= 20000 */ 5064120256Sgshapiro# if NETINET 5065120256Sgshapiro if (saddr_r != NULL) 5066120256Sgshapiro result = sasl_setprop(*conn, SASL_IP_REMOTE, saddr_r); 5067120256Sgshapiro if (result != SASL_OK) 5068120256Sgshapiro return result; 5069120256Sgshapiro 5070120256Sgshapiro if (saddr_l != NULL) 5071120256Sgshapiro result = sasl_setprop(*conn, SASL_IP_LOCAL, saddr_l); 5072120256Sgshapiro if (result != SASL_OK) 5073120256Sgshapiro return result; 5074120256Sgshapiro# endif /* NETINET */ 5075120256Sgshapiro 5076120256Sgshapiro result = sasl_setprop(*conn, SASL_SSF_EXTERNAL, ext_ssf); 5077120256Sgshapiro if (result != SASL_OK) 5078120256Sgshapiro return result; 5079120256Sgshapiro# endif /* SASL >= 20000 */ 5080120256Sgshapiro return SASL_OK; 5081120256Sgshapiro} 5082120256Sgshapiro#endif /* SASL */ 5083