srvrsmtp.c revision 168515
138032Speter/* 2157001Sgshapiro * Copyright (c) 1998-2006 Sendmail, 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 20168515SgshapiroSM_RCSID("@(#)$Id: srvrsmtp.c,v 8.960 2007/02/07 20:18:47 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 3390792Sgshapiro# include <sysexits.h> 3438032Speter 3590792Sgshapirostatic SSL_CTX *srv_ctx = NULL; /* TLS server context */ 3690792Sgshapirostatic SSL *srv_ssl = NULL; /* per connection context */ 3738032Speter 3890792Sgshapirostatic bool tls_ok_srv = false; 3990792Sgshapiro 4090792Sgshapiro# define TLS_VERIFY_CLIENT() tls_set_verify(srv_ctx, srv_ssl, \ 4190792Sgshapiro bitset(SRV_VRFY_CLT, features)) 4290792Sgshapiro#endif /* STARTTLS */ 4390792Sgshapiro 44168515Sgshapiro#if _FFR_DM_ONE 45168515Sgshapirostatic bool NotFirstDelivery = false; 46168515Sgshapiro#endif /* _FFR_DM_ONE */ 47168515Sgshapiro 4890792Sgshapiro/* server features */ 4990792Sgshapiro#define SRV_NONE 0x0000 /* none... */ 5090792Sgshapiro#define SRV_OFFER_TLS 0x0001 /* offer STARTTLS */ 5190792Sgshapiro#define SRV_VRFY_CLT 0x0002 /* request a cert */ 5290792Sgshapiro#define SRV_OFFER_AUTH 0x0004 /* offer AUTH */ 5390792Sgshapiro#define SRV_OFFER_ETRN 0x0008 /* offer ETRN */ 5490792Sgshapiro#define SRV_OFFER_VRFY 0x0010 /* offer VRFY (not yet used) */ 5590792Sgshapiro#define SRV_OFFER_EXPN 0x0020 /* offer EXPN */ 5690792Sgshapiro#define SRV_OFFER_VERB 0x0040 /* offer VERB */ 5790792Sgshapiro#define SRV_OFFER_DSN 0x0080 /* offer DSN */ 5890792Sgshapiro#if PIPELINING 5990792Sgshapiro# define SRV_OFFER_PIPE 0x0100 /* offer PIPELINING */ 6090792Sgshapiro# if _FFR_NO_PIPE 6190792Sgshapiro# define SRV_NO_PIPE 0x0200 /* disable PIPELINING, sleep if used */ 6290792Sgshapiro# endif /* _FFR_NO_PIPE */ 6390792Sgshapiro#endif /* PIPELINING */ 6490792Sgshapiro#define SRV_REQ_AUTH 0x0400 /* require AUTH */ 65132943Sgshapiro#define SRV_REQ_SEC 0x0800 /* require security - equiv to AuthOptions=p */ 6690792Sgshapiro#define SRV_TMP_FAIL 0x1000 /* ruleset caused a temporary failure */ 6790792Sgshapiro 6890792Sgshapirostatic unsigned int srvfeatures __P((ENVELOPE *, char *, unsigned int)); 6990792Sgshapiro 70132943Sgshapiro#define STOP_ATTACK ((time_t) -1) 71132943Sgshapirostatic time_t checksmtpattack __P((volatile unsigned int *, unsigned int, 72132943Sgshapiro bool, char *, ENVELOPE *)); 7364562Sgshapirostatic void printvrfyaddr __P((ADDRESS *, bool, bool)); 7464562Sgshapirostatic char *skipword __P((char *volatile, char *)); 7590792Sgshapirostatic void setup_smtpd_io __P((void)); 76120256Sgshapiro 77120256Sgshapiro#if SASL 78120256Sgshapiro# if SASL >= 20000 79120256Sgshapirostatic int reset_saslconn __P((sasl_conn_t **_conn, char *_hostname, 80120256Sgshapiro char *_remoteip, char *_localip, 81120256Sgshapiro char *_auth_id, sasl_ssf_t *_ext_ssf)); 82120256Sgshapiro 83120256Sgshapiro# define RESET_SASLCONN \ 84147078Sgshapiro do \ 85147078Sgshapiro { \ 86147078Sgshapiro result = reset_saslconn(&conn, AuthRealm, remoteip, \ 87147078Sgshapiro localip, auth_id, &ext_ssf); \ 88147078Sgshapiro if (result != SASL_OK) \ 89147078Sgshapiro sasl_ok = false; \ 90147078Sgshapiro } while (0) 91120256Sgshapiro 92120256Sgshapiro# else /* SASL >= 20000 */ 93120256Sgshapirostatic int reset_saslconn __P((sasl_conn_t **_conn, char *_hostname, 94120256Sgshapiro struct sockaddr_in *_saddr_r, 95120256Sgshapiro struct sockaddr_in *_saddr_l, 96120256Sgshapiro sasl_external_properties_t *_ext_ssf)); 97120256Sgshapiro# define RESET_SASLCONN \ 98147078Sgshapiro do \ 99147078Sgshapiro { \ 100147078Sgshapiro result = reset_saslconn(&conn, AuthRealm, &saddr_r, \ 101147078Sgshapiro &saddr_l, &ext_ssf); \ 102147078Sgshapiro if (result != SASL_OK) \ 103147078Sgshapiro sasl_ok = false; \ 104147078Sgshapiro } while (0) 105120256Sgshapiro 106120256Sgshapiro# endif /* SASL >= 20000 */ 107120256Sgshapiro#endif /* SASL */ 108120256Sgshapiro 10964562Sgshapiroextern ENVELOPE BlankEnvelope; 11038032Speter 111132943Sgshapiro#define NBADRCPTS \ 112132943Sgshapiro do \ 113132943Sgshapiro { \ 114132943Sgshapiro char buf[16]; \ 115168515Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "%d", \ 116132943Sgshapiro BadRcptThrottle > 0 && n_badrcpts > BadRcptThrottle \ 117132943Sgshapiro ? n_badrcpts - 1 : n_badrcpts); \ 118132943Sgshapiro macdefine(&e->e_macro, A_TEMP, macid("{nbadrcpts}"), buf); \ 119132943Sgshapiro } while (0) 120132943Sgshapiro 12190792Sgshapiro#define SKIP_SPACE(s) while (isascii(*s) && isspace(*s)) \ 12290792Sgshapiro (s)++ 12390792Sgshapiro 12438032Speter/* 125168515Sgshapiro** PARSE_ESMTP_ARGS -- parse EMSTP arguments (for MAIL, RCPT) 126168515Sgshapiro** 127168515Sgshapiro** Parameters: 128168515Sgshapiro** e -- the envelope 129168515Sgshapiro** addr_st -- address (RCPT only) 130168515Sgshapiro** p -- read buffer 131168515Sgshapiro** delimptr -- current position in read buffer 132168515Sgshapiro** which -- MAIL/RCPT 133168515Sgshapiro** args -- arguments (output) 134168515Sgshapiro** esmtp_args -- function to process a single ESMTP argument 135168515Sgshapiro** 136168515Sgshapiro** Returns: 137168515Sgshapiro** none 138168515Sgshapiro*/ 139168515Sgshapiro 140168515Sgshapirovoid 141168515Sgshapiroparse_esmtp_args(e, addr_st, p, delimptr, which, args, esmtp_args) 142168515Sgshapiro ENVELOPE *e; 143168515Sgshapiro ADDRESS *addr_st; 144168515Sgshapiro char *p; 145168515Sgshapiro char *delimptr; 146168515Sgshapiro char *which; 147168515Sgshapiro char *args[]; 148168515Sgshapiro esmtp_args_F esmtp_args; 149168515Sgshapiro{ 150168515Sgshapiro int argno; 151168515Sgshapiro 152168515Sgshapiro argno = 0; 153168515Sgshapiro if (args != NULL) 154168515Sgshapiro args[argno++] = p; 155168515Sgshapiro p = delimptr; 156168515Sgshapiro while (p != NULL && *p != '\0') 157168515Sgshapiro { 158168515Sgshapiro char *kp; 159168515Sgshapiro char *vp = NULL; 160168515Sgshapiro char *equal = NULL; 161168515Sgshapiro 162168515Sgshapiro /* locate the beginning of the keyword */ 163168515Sgshapiro SKIP_SPACE(p); 164168515Sgshapiro if (*p == '\0') 165168515Sgshapiro break; 166168515Sgshapiro kp = p; 167168515Sgshapiro 168168515Sgshapiro /* skip to the value portion */ 169168515Sgshapiro while ((isascii(*p) && isalnum(*p)) || *p == '-') 170168515Sgshapiro p++; 171168515Sgshapiro if (*p == '=') 172168515Sgshapiro { 173168515Sgshapiro equal = p; 174168515Sgshapiro *p++ = '\0'; 175168515Sgshapiro vp = p; 176168515Sgshapiro 177168515Sgshapiro /* skip to the end of the value */ 178168515Sgshapiro while (*p != '\0' && *p != ' ' && 179168515Sgshapiro !(isascii(*p) && iscntrl(*p)) && 180168515Sgshapiro *p != '=') 181168515Sgshapiro p++; 182168515Sgshapiro } 183168515Sgshapiro 184168515Sgshapiro if (*p != '\0') 185168515Sgshapiro *p++ = '\0'; 186168515Sgshapiro 187168515Sgshapiro if (tTd(19, 1)) 188168515Sgshapiro sm_dprintf("%s: got arg %s=\"%s\"\n", which, kp, 189168515Sgshapiro vp == NULL ? "<null>" : vp); 190168515Sgshapiro 191168515Sgshapiro esmtp_args(addr_st, kp, vp, e); 192168515Sgshapiro if (equal != NULL) 193168515Sgshapiro *equal = '='; 194168515Sgshapiro if (args != NULL) 195168515Sgshapiro args[argno] = kp; 196168515Sgshapiro argno++; 197168515Sgshapiro if (argno >= MAXSMTPARGS - 1) 198168515Sgshapiro usrerr("501 5.5.4 Too many parameters"); 199168515Sgshapiro if (Errors > 0) 200168515Sgshapiro break; 201168515Sgshapiro } 202168515Sgshapiro if (args != NULL) 203168515Sgshapiro args[argno] = NULL; 204168515Sgshapiro} 205168515Sgshapiro 206168515Sgshapiro/* 20738032Speter** SMTP -- run the SMTP protocol. 20838032Speter** 20938032Speter** Parameters: 21038032Speter** nullserver -- if non-NULL, rejection message for 21190792Sgshapiro** (almost) all SMTP commands. 21290792Sgshapiro** d_flags -- daemon flags 21338032Speter** e -- the envelope. 21438032Speter** 21538032Speter** Returns: 21638032Speter** never. 21738032Speter** 21838032Speter** Side Effects: 21990792Sgshapiro** Reads commands from the input channel and processes them. 22038032Speter*/ 22138032Speter 22290792Sgshapiro/* 22390792Sgshapiro** Notice: The smtp server doesn't have a session context like the client 22490792Sgshapiro** side has (mci). Therefore some data (session oriented) is allocated 22590792Sgshapiro** or assigned to the "wrong" structure (esp. STARTTLS, AUTH). 22690792Sgshapiro** This should be fixed in a successor version. 22790792Sgshapiro*/ 22890792Sgshapiro 22938032Speterstruct cmd 23038032Speter{ 23164562Sgshapiro char *cmd_name; /* command name */ 23264562Sgshapiro int cmd_code; /* internal code, see below */ 23338032Speter}; 23438032Speter 23564562Sgshapiro/* values for cmd_code */ 23690792Sgshapiro#define CMDERROR 0 /* bad command */ 23790792Sgshapiro#define CMDMAIL 1 /* mail -- designate sender */ 23890792Sgshapiro#define CMDRCPT 2 /* rcpt -- designate recipient */ 23990792Sgshapiro#define CMDDATA 3 /* data -- send message text */ 24090792Sgshapiro#define CMDRSET 4 /* rset -- reset state */ 24190792Sgshapiro#define CMDVRFY 5 /* vrfy -- verify address */ 24290792Sgshapiro#define CMDEXPN 6 /* expn -- expand address */ 24390792Sgshapiro#define CMDNOOP 7 /* noop -- do nothing */ 24490792Sgshapiro#define CMDQUIT 8 /* quit -- close connection and die */ 24590792Sgshapiro#define CMDHELO 9 /* helo -- be polite */ 24690792Sgshapiro#define CMDHELP 10 /* help -- give usage info */ 24790792Sgshapiro#define CMDEHLO 11 /* ehlo -- extended helo (RFC 1425) */ 24890792Sgshapiro#define CMDETRN 12 /* etrn -- flush queue */ 24990792Sgshapiro#if SASL 25090792Sgshapiro# define CMDAUTH 13 /* auth -- SASL authenticate */ 25190792Sgshapiro#endif /* SASL */ 25290792Sgshapiro#if STARTTLS 25390792Sgshapiro# define CMDSTLS 14 /* STARTTLS -- start TLS session */ 25490792Sgshapiro#endif /* STARTTLS */ 25538032Speter/* non-standard commands */ 25690792Sgshapiro#define CMDVERB 17 /* verb -- go into verbose mode */ 25764562Sgshapiro/* unimplemented commands from RFC 821 */ 25890792Sgshapiro#define CMDUNIMPL 19 /* unimplemented rfc821 commands */ 25938032Speter/* use this to catch and log "door handle" attempts on your system */ 26090792Sgshapiro#define CMDLOGBOGUS 23 /* bogus command that should be logged */ 26138032Speter/* debugging-only commands, only enabled if SMTPDEBUG is defined */ 26290792Sgshapiro#define CMDDBGQSHOW 24 /* showq -- show send queue */ 26390792Sgshapiro#define CMDDBGDEBUG 25 /* debug -- set debug mode */ 26438032Speter 26566494Sgshapiro/* 26690792Sgshapiro** Note: If you change this list, remember to update 'helpfile' 26766494Sgshapiro*/ 26866494Sgshapiro 26938032Speterstatic struct cmd CmdTab[] = 27038032Speter{ 27138032Speter { "mail", CMDMAIL }, 27238032Speter { "rcpt", CMDRCPT }, 27338032Speter { "data", CMDDATA }, 27438032Speter { "rset", CMDRSET }, 27538032Speter { "vrfy", CMDVRFY }, 27638032Speter { "expn", CMDEXPN }, 27738032Speter { "help", CMDHELP }, 27838032Speter { "noop", CMDNOOP }, 27938032Speter { "quit", CMDQUIT }, 28038032Speter { "helo", CMDHELO }, 28138032Speter { "ehlo", CMDEHLO }, 28238032Speter { "etrn", CMDETRN }, 28338032Speter { "verb", CMDVERB }, 28464562Sgshapiro { "send", CMDUNIMPL }, 28564562Sgshapiro { "saml", CMDUNIMPL }, 28664562Sgshapiro { "soml", CMDUNIMPL }, 28764562Sgshapiro { "turn", CMDUNIMPL }, 28890792Sgshapiro#if SASL 28964562Sgshapiro { "auth", CMDAUTH, }, 29090792Sgshapiro#endif /* SASL */ 29190792Sgshapiro#if STARTTLS 29264562Sgshapiro { "starttls", CMDSTLS, }, 29390792Sgshapiro#endif /* STARTTLS */ 29438032Speter /* remaining commands are here only to trap and log attempts to use them */ 29538032Speter { "showq", CMDDBGQSHOW }, 29638032Speter { "debug", CMDDBGDEBUG }, 29738032Speter { "wiz", CMDLOGBOGUS }, 29838032Speter 29938032Speter { NULL, CMDERROR } 30038032Speter}; 30138032Speter 30264562Sgshapirostatic char *CurSmtpClient; /* who's at the other end of channel */ 30338032Speter 30490792Sgshapiro#ifndef MAXBADCOMMANDS 30590792Sgshapiro# define MAXBADCOMMANDS 25 /* maximum number of bad commands */ 30694334Sgshapiro#endif /* ! MAXBADCOMMANDS */ 30790792Sgshapiro#ifndef MAXHELOCOMMANDS 30890792Sgshapiro# define MAXHELOCOMMANDS 3 /* max HELO/EHLO commands before slowdown */ 30994334Sgshapiro#endif /* ! MAXHELOCOMMANDS */ 31090792Sgshapiro#ifndef MAXVRFYCOMMANDS 31190792Sgshapiro# define MAXVRFYCOMMANDS 6 /* max VRFY/EXPN commands before slowdown */ 31294334Sgshapiro#endif /* ! MAXVRFYCOMMANDS */ 31390792Sgshapiro#ifndef MAXETRNCOMMANDS 31490792Sgshapiro# define MAXETRNCOMMANDS 8 /* max ETRN commands before slowdown */ 31594334Sgshapiro#endif /* ! MAXETRNCOMMANDS */ 31690792Sgshapiro#ifndef MAXTIMEOUT 31790792Sgshapiro# define MAXTIMEOUT (4 * 60) /* max timeout for bad commands */ 31894334Sgshapiro#endif /* ! MAXTIMEOUT */ 31938032Speter 320132943Sgshapiro/* 321132943Sgshapiro** Maximum shift value to compute timeout for bad commands. 322132943Sgshapiro** This introduces an upper limit of 2^MAXSHIFT for the timeout. 323132943Sgshapiro*/ 324132943Sgshapiro 325132943Sgshapiro#ifndef MAXSHIFT 326132943Sgshapiro# define MAXSHIFT 8 327132943Sgshapiro#endif /* ! MAXSHIFT */ 328132943Sgshapiro#if MAXSHIFT > 31 329132943Sgshapiro ERROR _MAXSHIFT > 31 is invalid 330132943Sgshapiro#endif /* MAXSHIFT */ 331132943Sgshapiro 332132943Sgshapiro 333132943Sgshapiro#if MAXBADCOMMANDS > 0 334132943Sgshapiro# define STOP_IF_ATTACK(r) do \ 335132943Sgshapiro { \ 336132943Sgshapiro if ((r) == STOP_ATTACK) \ 337132943Sgshapiro goto stopattack; \ 338132943Sgshapiro } while (0) 339132943Sgshapiro 340132943Sgshapiro#else /* MAXBADCOMMANDS > 0 */ 341132943Sgshapiro# define STOP_IF_ATTACK(r) r 342132943Sgshapiro#endif /* MAXBADCOMMANDS > 0 */ 343132943Sgshapiro 344132943Sgshapiro 34590792Sgshapiro#if SM_HEAP_CHECK 34690792Sgshapirostatic SM_DEBUG_T DebugLeakSmtp = SM_DEBUG_INITIALIZER("leak_smtp", 34790792Sgshapiro "@(#)$Debug: leak_smtp - trace memory leaks during SMTP processing $"); 34890792Sgshapiro#endif /* SM_HEAP_CHECK */ 34938032Speter 35090792Sgshapirotypedef struct 35190792Sgshapiro{ 35290792Sgshapiro bool sm_gotmail; /* mail command received */ 35390792Sgshapiro unsigned int sm_nrcpts; /* number of successful RCPT commands */ 35490792Sgshapiro bool sm_discard; 35590792Sgshapiro#if MILTER 35690792Sgshapiro bool sm_milterize; 35790792Sgshapiro bool sm_milterlist; /* any filters in the list? */ 35890792Sgshapiro#endif /* MILTER */ 35990792Sgshapiro char *sm_quarmsg; /* carry quarantining across messages */ 36090792Sgshapiro} SMTP_T; 36190792Sgshapiro 362132943Sgshapirostatic bool smtp_data __P((SMTP_T *, ENVELOPE *)); 36390792Sgshapiro 364132943Sgshapiro#define MSG_TEMPFAIL "451 4.3.2 Please try again later" 36590792Sgshapiro 36690792Sgshapiro#if MILTER 36790792Sgshapiro# define MILTER_ABORT(e) milter_abort((e)) 368110560Sgshapiro 36990792Sgshapiro# define MILTER_REPLY(str) \ 37090792Sgshapiro { \ 37190792Sgshapiro int savelogusrerrs = LogUsrErrs; \ 37290792Sgshapiro \ 373168515Sgshapiro milter_cmd_fail = true; \ 37490792Sgshapiro switch (state) \ 37590792Sgshapiro { \ 376157001Sgshapiro case SMFIR_SHUTDOWN: \ 377157001Sgshapiro if (MilterLogLevel > 3) \ 378157001Sgshapiro { \ 379157001Sgshapiro sm_syslog(LOG_INFO, e->e_id, \ 380157001Sgshapiro "Milter: %s=%s, reject=421, errormode=4", \ 381157001Sgshapiro str, addr); \ 382157001Sgshapiro LogUsrErrs = false; \ 383157001Sgshapiro } \ 384157001Sgshapiro { \ 385157001Sgshapiro bool tsave = QuickAbort; \ 386157001Sgshapiro \ 387157001Sgshapiro QuickAbort = false; \ 388157001Sgshapiro usrerr("421 4.3.0 closing connection"); \ 389157001Sgshapiro QuickAbort = tsave; \ 390157001Sgshapiro e->e_sendqueue = NULL; \ 391157001Sgshapiro goto doquit; \ 392157001Sgshapiro } \ 393157001Sgshapiro break; \ 39490792Sgshapiro case SMFIR_REPLYCODE: \ 39590792Sgshapiro if (MilterLogLevel > 3) \ 39690792Sgshapiro { \ 39790792Sgshapiro sm_syslog(LOG_INFO, e->e_id, \ 39890792Sgshapiro "Milter: %s=%s, reject=%s", \ 39990792Sgshapiro str, addr, response); \ 40090792Sgshapiro LogUsrErrs = false; \ 40190792Sgshapiro } \ 402157001Sgshapiro if (strncmp(response, "421 ", 4) == 0 \ 403157001Sgshapiro || strncmp(response, "421-", 4) == 0) \ 404132943Sgshapiro { \ 405132943Sgshapiro bool tsave = QuickAbort; \ 406132943Sgshapiro \ 407132943Sgshapiro QuickAbort = false; \ 408132943Sgshapiro usrerr(response); \ 409132943Sgshapiro QuickAbort = tsave; \ 410132943Sgshapiro e->e_sendqueue = NULL; \ 411132943Sgshapiro goto doquit; \ 412132943Sgshapiro } \ 413132943Sgshapiro else \ 414132943Sgshapiro usrerr(response); \ 41590792Sgshapiro break; \ 41690792Sgshapiro \ 41790792Sgshapiro case SMFIR_REJECT: \ 41890792Sgshapiro if (MilterLogLevel > 3) \ 41990792Sgshapiro { \ 42090792Sgshapiro sm_syslog(LOG_INFO, e->e_id, \ 42190792Sgshapiro "Milter: %s=%s, reject=550 5.7.1 Command rejected", \ 42290792Sgshapiro str, addr); \ 42390792Sgshapiro LogUsrErrs = false; \ 42490792Sgshapiro } \ 42590792Sgshapiro usrerr("550 5.7.1 Command rejected"); \ 42690792Sgshapiro break; \ 42790792Sgshapiro \ 42890792Sgshapiro case SMFIR_DISCARD: \ 42990792Sgshapiro if (MilterLogLevel > 3) \ 43090792Sgshapiro sm_syslog(LOG_INFO, e->e_id, \ 43190792Sgshapiro "Milter: %s=%s, discard", \ 43290792Sgshapiro str, addr); \ 43390792Sgshapiro e->e_flags |= EF_DISCARD; \ 434168515Sgshapiro milter_cmd_fail = false; \ 43590792Sgshapiro break; \ 43690792Sgshapiro \ 43790792Sgshapiro case SMFIR_TEMPFAIL: \ 43890792Sgshapiro if (MilterLogLevel > 3) \ 43990792Sgshapiro { \ 44090792Sgshapiro sm_syslog(LOG_INFO, e->e_id, \ 44190792Sgshapiro "Milter: %s=%s, reject=%s", \ 44290792Sgshapiro str, addr, MSG_TEMPFAIL); \ 44390792Sgshapiro LogUsrErrs = false; \ 44490792Sgshapiro } \ 44590792Sgshapiro usrerr(MSG_TEMPFAIL); \ 44690792Sgshapiro break; \ 447168515Sgshapiro default: \ 448168515Sgshapiro milter_cmd_fail = false; \ 449168515Sgshapiro break; \ 45090792Sgshapiro } \ 45190792Sgshapiro LogUsrErrs = savelogusrerrs; \ 45290792Sgshapiro if (response != NULL) \ 45390792Sgshapiro sm_free(response); /* XXX */ \ 45490792Sgshapiro } 45590792Sgshapiro 45690792Sgshapiro#else /* MILTER */ 45790792Sgshapiro# define MILTER_ABORT(e) 45890792Sgshapiro#endif /* MILTER */ 45990792Sgshapiro 46090792Sgshapiro/* clear all SMTP state (for HELO/EHLO/RSET) */ 46190792Sgshapiro#define CLEAR_STATE(cmd) \ 462132943Sgshapirodo \ 46390792Sgshapiro{ \ 46490792Sgshapiro /* abort milter filters */ \ 46590792Sgshapiro MILTER_ABORT(e); \ 46690792Sgshapiro \ 46790792Sgshapiro if (smtp.sm_nrcpts > 0) \ 46890792Sgshapiro { \ 46990792Sgshapiro logundelrcpts(e, cmd, 10, false); \ 47090792Sgshapiro smtp.sm_nrcpts = 0; \ 47190792Sgshapiro macdefine(&e->e_macro, A_PERM, \ 47290792Sgshapiro macid("{nrcpts}"), "0"); \ 47390792Sgshapiro } \ 47490792Sgshapiro \ 47590792Sgshapiro e->e_sendqueue = NULL; \ 47690792Sgshapiro e->e_flags |= EF_CLRQUEUE; \ 47790792Sgshapiro \ 47890792Sgshapiro if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags)) \ 47990792Sgshapiro logsender(e, NULL); \ 48090792Sgshapiro e->e_flags &= ~EF_LOGSENDER; \ 48190792Sgshapiro \ 48290792Sgshapiro /* clean up a bit */ \ 48390792Sgshapiro smtp.sm_gotmail = false; \ 48490792Sgshapiro SuprErrs = true; \ 48590792Sgshapiro dropenvelope(e, true, false); \ 48690792Sgshapiro sm_rpool_free(e->e_rpool); \ 48790792Sgshapiro e = newenvelope(e, CurEnv, sm_rpool_new_x(NULL)); \ 48890792Sgshapiro CurEnv = e; \ 489168515Sgshapiro e->e_features = features; \ 490132943Sgshapiro \ 491132943Sgshapiro /* put back discard bit */ \ 492132943Sgshapiro if (smtp.sm_discard) \ 493132943Sgshapiro e->e_flags |= EF_DISCARD; \ 494132943Sgshapiro \ 495132943Sgshapiro /* restore connection quarantining */ \ 496132943Sgshapiro if (smtp.sm_quarmsg == NULL) \ 497132943Sgshapiro { \ 498132943Sgshapiro e->e_quarmsg = NULL; \ 499132943Sgshapiro macdefine(&e->e_macro, A_PERM, \ 500132943Sgshapiro macid("{quarantine}"), ""); \ 501132943Sgshapiro } \ 502132943Sgshapiro else \ 503132943Sgshapiro { \ 504132943Sgshapiro e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, \ 505132943Sgshapiro smtp.sm_quarmsg); \ 506132943Sgshapiro macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), \ 507132943Sgshapiro e->e_quarmsg); \ 508132943Sgshapiro } \ 509132943Sgshapiro} while (0) 51090792Sgshapiro 51190792Sgshapiro/* sleep to flatten out connection load */ 51290792Sgshapiro#define MIN_DELAY_LOG 15 /* wait before logging this again */ 51390792Sgshapiro 51490792Sgshapiro/* is it worth setting the process title for 1s? */ 51590792Sgshapiro#define DELAY_CONN(cmd) \ 51690792Sgshapiro if (DelayLA > 0 && (CurrentLA = getla()) >= DelayLA) \ 51790792Sgshapiro { \ 51890792Sgshapiro time_t dnow; \ 51990792Sgshapiro \ 52090792Sgshapiro sm_setproctitle(true, e, \ 52190792Sgshapiro "%s: %s: delaying %s: load average: %d", \ 52290792Sgshapiro qid_printname(e), CurSmtpClient, \ 52390792Sgshapiro cmd, DelayLA); \ 52490792Sgshapiro if (LogLevel > 8 && (dnow = curtime()) > log_delay) \ 52590792Sgshapiro { \ 52690792Sgshapiro sm_syslog(LOG_INFO, e->e_id, \ 52790792Sgshapiro "delaying=%s, load average=%d >= %d", \ 52890792Sgshapiro cmd, CurrentLA, DelayLA); \ 52990792Sgshapiro log_delay = dnow + MIN_DELAY_LOG; \ 53090792Sgshapiro } \ 53190792Sgshapiro (void) sleep(1); \ 53290792Sgshapiro sm_setproctitle(true, e, "%s %s: %.80s", \ 53390792Sgshapiro qid_printname(e), CurSmtpClient, inp); \ 53490792Sgshapiro } 53590792Sgshapiro 536168515Sgshapirostatic bool SevenBitInput_Saved; /* saved version of SevenBitInput */ 53790792Sgshapiro 53838032Spetervoid 53964562Sgshapirosmtp(nullserver, d_flags, e) 54064562Sgshapiro char *volatile nullserver; 54164562Sgshapiro BITMAP256 d_flags; 54238032Speter register ENVELOPE *volatile e; 54338032Speter{ 54438032Speter register char *volatile p; 54564562Sgshapiro register struct cmd *volatile c = NULL; 54638032Speter char *cmd; 54738032Speter auto ADDRESS *vrfyqueue; 54838032Speter ADDRESS *a; 54938032Speter volatile bool gothello; /* helo command received */ 55038032Speter bool vrfy; /* set if this is a vrfy command */ 55138032Speter char *volatile protocol; /* sending protocol */ 55238032Speter char *volatile sendinghost; /* sending hostname */ 55338032Speter char *volatile peerhostname; /* name of SMTP peer or "localhost" */ 55438032Speter auto char *delimptr; 55538032Speter char *id; 55690792Sgshapiro volatile unsigned int n_badcmds = 0; /* count of bad commands */ 55790792Sgshapiro volatile unsigned int n_badrcpts = 0; /* number of rejected RCPT */ 55890792Sgshapiro volatile unsigned int n_verifies = 0; /* count of VRFY/EXPN */ 55990792Sgshapiro volatile unsigned int n_etrn = 0; /* count of ETRN */ 56090792Sgshapiro volatile unsigned int n_noop = 0; /* count of NOOP/VERB/etc */ 56190792Sgshapiro volatile unsigned int n_helo = 0; /* count of HELO/EHLO */ 56238032Speter bool ok; 56390792Sgshapiro volatile bool first; 56490792Sgshapiro volatile bool tempfail = false; 56564562Sgshapiro volatile time_t wt; /* timeout after too many commands */ 56664562Sgshapiro volatile time_t previous; /* time after checksmtpattack() */ 56790792Sgshapiro volatile bool lognullconnection = true; 56838032Speter register char *q; 56990792Sgshapiro SMTP_T smtp; 57064562Sgshapiro char *addr; 57164562Sgshapiro char *greetcode = "220"; 57290792Sgshapiro char *hostname; /* my hostname ($j) */ 57338032Speter QUEUE_CHAR *new; 57464562Sgshapiro char *args[MAXSMTPARGS]; 575168515Sgshapiro char inp[MAXINPLINE]; 576168515Sgshapiro#if MAXINPLINE < MAXLINE 577168515Sgshapiro ERROR _MAXINPLINE must NOT be less than _MAXLINE: MAXINPLINE < MAXLINE 578168515Sgshapiro#endif /* MAXINPLINE < MAXLINE */ 57938032Speter char cmdbuf[MAXLINE]; 58090792Sgshapiro#if SASL 58164562Sgshapiro sasl_conn_t *conn; 58264562Sgshapiro volatile bool sasl_ok; 58390792Sgshapiro volatile unsigned int n_auth = 0; /* count of AUTH commands */ 58464562Sgshapiro bool ismore; 58564562Sgshapiro int result; 58664562Sgshapiro volatile int authenticating; 58764562Sgshapiro char *user; 58898121Sgshapiro char *in, *out2; 58998121Sgshapiro# if SASL >= 20000 590168515Sgshapiro char *auth_id = NULL; 59198121Sgshapiro const char *out; 592102528Sgshapiro sasl_ssf_t ext_ssf; 593120256Sgshapiro char localip[60], remoteip[60]; 59498121Sgshapiro# else /* SASL >= 20000 */ 59598121Sgshapiro char *out; 59664562Sgshapiro const char *errstr; 59798121Sgshapiro sasl_external_properties_t ext_ssf; 598120256Sgshapiro struct sockaddr_in saddr_l; 599120256Sgshapiro struct sockaddr_in saddr_r; 60098121Sgshapiro# endif /* SASL >= 20000 */ 60198121Sgshapiro sasl_security_properties_t ssp; 60298121Sgshapiro sasl_ssf_t *ssf; 60390792Sgshapiro unsigned int inlen, out2len; 60464562Sgshapiro unsigned int outlen; 60564562Sgshapiro char *volatile auth_type; 60664562Sgshapiro char *mechlist; 60790792Sgshapiro volatile unsigned int n_mechs; 60890792Sgshapiro unsigned int len; 609168515Sgshapiro#else /* SASL */ 61090792Sgshapiro#endif /* SASL */ 611132943Sgshapiro int r; 61290792Sgshapiro#if STARTTLS 61366494Sgshapiro int rfd, wfd; 61490792Sgshapiro volatile bool tls_active = false; 615132943Sgshapiro volatile bool smtps = bitnset(D_SMTPS, d_flags); 61664562Sgshapiro bool saveQuickAbort; 61764562Sgshapiro bool saveSuprErrs; 61890792Sgshapiro time_t tlsstart; 61990792Sgshapiro#endif /* STARTTLS */ 62090792Sgshapiro volatile unsigned int features; 62190792Sgshapiro#if PIPELINING 62290792Sgshapiro# if _FFR_NO_PIPE 62390792Sgshapiro int np_log = 0; 62490792Sgshapiro# endif /* _FFR_NO_PIPE */ 62590792Sgshapiro#endif /* PIPELINING */ 62690792Sgshapiro volatile time_t log_delay = (time_t) 0; 627168515Sgshapiro#if MILTER 628168515Sgshapiro volatile bool milter_cmd_done, milter_cmd_safe; 629168515Sgshapiro volatile bool milter_rcpt_added, milter_cmd_fail; 630168515Sgshapiro ADDRESS addr_st; 631168515Sgshapiro# define p_addr_st &addr_st 632168515Sgshapiro#else /* MILTER */ 633168515Sgshapiro# define p_addr_st NULL 634168515Sgshapiro#endif /* MILTER */ 635168515Sgshapiro size_t inplen; 63638032Speter 637168515Sgshapiro SevenBitInput_Saved = SevenBitInput; 63890792Sgshapiro smtp.sm_nrcpts = 0; 63990792Sgshapiro#if MILTER 64090792Sgshapiro smtp.sm_milterize = (nullserver == NULL); 64190792Sgshapiro smtp.sm_milterlist = false; 642168515Sgshapiro addr = NULL; 64390792Sgshapiro#endif /* MILTER */ 64490792Sgshapiro 64590792Sgshapiro /* setup I/O fd correctly for the SMTP server */ 64690792Sgshapiro setup_smtpd_io(); 64790792Sgshapiro 64890792Sgshapiro#if SM_HEAP_CHECK 64990792Sgshapiro if (sm_debug_active(&DebugLeakSmtp, 1)) 65038032Speter { 65190792Sgshapiro sm_heap_newgroup(); 65290792Sgshapiro sm_dprintf("smtp() heap group #%d\n", sm_heap_group()); 65338032Speter } 65490792Sgshapiro#endif /* SM_HEAP_CHECK */ 65564562Sgshapiro 65690792Sgshapiro /* XXX the rpool should be set when e is initialized in main() */ 65790792Sgshapiro e->e_rpool = sm_rpool_new_x(NULL); 65890792Sgshapiro e->e_macro.mac_rpool = e->e_rpool; 65990792Sgshapiro 66038032Speter settime(e); 66190792Sgshapiro sm_getla(); 66238032Speter peerhostname = RealHostName; 66338032Speter if (peerhostname == NULL) 66438032Speter peerhostname = "localhost"; 66538032Speter CurHostName = peerhostname; 66638032Speter CurSmtpClient = macvalue('_', e); 66738032Speter if (CurSmtpClient == NULL) 66838032Speter CurSmtpClient = CurHostName; 66938032Speter 67038032Speter /* check_relay may have set discard bit, save for later */ 67190792Sgshapiro smtp.sm_discard = bitset(EF_DISCARD, e->e_flags); 67238032Speter 67390792Sgshapiro#if PIPELINING 67490792Sgshapiro /* auto-flush output when reading input */ 67590792Sgshapiro (void) sm_io_autoflush(InChannel, OutChannel); 67690792Sgshapiro#endif /* PIPELINING */ 67764562Sgshapiro 67890792Sgshapiro sm_setproctitle(true, e, "server %s startup", CurSmtpClient); 67990792Sgshapiro 68090792Sgshapiro /* Set default features for server. */ 68190792Sgshapiro features = ((bitset(PRIV_NOETRN, PrivacyFlags) || 68290792Sgshapiro bitnset(D_NOETRN, d_flags)) ? SRV_NONE : SRV_OFFER_ETRN) 68390792Sgshapiro | (bitnset(D_AUTHREQ, d_flags) ? SRV_REQ_AUTH : SRV_NONE) 68490792Sgshapiro | (bitset(PRIV_NOEXPN, PrivacyFlags) ? SRV_NONE 68590792Sgshapiro : (SRV_OFFER_EXPN 68690792Sgshapiro | (bitset(PRIV_NOVERB, PrivacyFlags) 68790792Sgshapiro ? SRV_NONE : SRV_OFFER_VERB))) 688159609Sgshapiro | ((bitset(PRIV_NORECEIPTS, PrivacyFlags) || !SendMIMEErrors) 689159609Sgshapiro ? SRV_NONE : SRV_OFFER_DSN) 69090792Sgshapiro#if SASL 69190792Sgshapiro | (bitnset(D_NOAUTH, d_flags) ? SRV_NONE : SRV_OFFER_AUTH) 692132943Sgshapiro | (bitset(SASL_SEC_NOPLAINTEXT, SASLOpts) ? SRV_REQ_SEC 693132943Sgshapiro : SRV_NONE) 69490792Sgshapiro#endif /* SASL */ 69590792Sgshapiro#if PIPELINING 69690792Sgshapiro | SRV_OFFER_PIPE 69790792Sgshapiro#endif /* PIPELINING */ 69890792Sgshapiro#if STARTTLS 69990792Sgshapiro | (bitnset(D_NOTLS, d_flags) ? SRV_NONE : SRV_OFFER_TLS) 70090792Sgshapiro | (bitset(TLS_I_NO_VRFY, TLS_Srv_Opts) ? SRV_NONE 70190792Sgshapiro : SRV_VRFY_CLT) 70290792Sgshapiro#endif /* STARTTLS */ 70390792Sgshapiro ; 70490792Sgshapiro if (nullserver == NULL) 70590792Sgshapiro { 70690792Sgshapiro features = srvfeatures(e, CurSmtpClient, features); 70790792Sgshapiro if (bitset(SRV_TMP_FAIL, features)) 70890792Sgshapiro { 70990792Sgshapiro if (LogLevel > 4) 71090792Sgshapiro sm_syslog(LOG_ERR, NOQID, 71190792Sgshapiro "ERROR: srv_features=tempfail, relay=%.100s, access temporarily disabled", 71290792Sgshapiro CurSmtpClient); 71390792Sgshapiro nullserver = "450 4.3.0 Please try again later."; 71490792Sgshapiro } 715132943Sgshapiro else 716132943Sgshapiro { 71790792Sgshapiro#if PIPELINING 71890792Sgshapiro# if _FFR_NO_PIPE 719132943Sgshapiro if (bitset(SRV_NO_PIPE, features)) 720132943Sgshapiro { 721132943Sgshapiro /* for consistency */ 722132943Sgshapiro features &= ~SRV_OFFER_PIPE; 723132943Sgshapiro } 72490792Sgshapiro# endif /* _FFR_NO_PIPE */ 72590792Sgshapiro#endif /* PIPELINING */ 726132943Sgshapiro#if SASL 727132943Sgshapiro if (bitset(SRV_REQ_SEC, features)) 728132943Sgshapiro SASLOpts |= SASL_SEC_NOPLAINTEXT; 729132943Sgshapiro else 730132943Sgshapiro SASLOpts &= ~SASL_SEC_NOPLAINTEXT; 731132943Sgshapiro#endif /* SASL */ 732132943Sgshapiro } 73390792Sgshapiro } 734132943Sgshapiro else if (strncmp(nullserver, "421 ", 4) == 0) 735132943Sgshapiro { 736132943Sgshapiro message(nullserver); 737132943Sgshapiro goto doquit; 738132943Sgshapiro } 73990792Sgshapiro 740168515Sgshapiro e->e_features = features; 74190792Sgshapiro hostname = macvalue('j', e); 74290792Sgshapiro#if SASL 743132943Sgshapiro if (AuthRealm == NULL) 744132943Sgshapiro AuthRealm = hostname; 74590792Sgshapiro sasl_ok = bitset(SRV_OFFER_AUTH, features); 74664562Sgshapiro n_mechs = 0; 74790792Sgshapiro authenticating = SASL_NOT_AUTH; 74864562Sgshapiro 74964562Sgshapiro /* SASL server new connection */ 75090792Sgshapiro if (sasl_ok) 75138032Speter { 75298121Sgshapiro# if SASL >= 20000 753132943Sgshapiro result = sasl_server_new("smtp", AuthRealm, NULL, NULL, NULL, 75498121Sgshapiro NULL, 0, &conn); 75598121Sgshapiro# elif SASL > 10505 75690792Sgshapiro /* use empty realm: only works in SASL > 1.5.5 */ 757132943Sgshapiro result = sasl_server_new("smtp", AuthRealm, "", NULL, 0, &conn); 75898121Sgshapiro# else /* SASL >= 20000 */ 75990792Sgshapiro /* use no realm -> realm is set to hostname by SASL lib */ 760132943Sgshapiro result = sasl_server_new("smtp", AuthRealm, NULL, NULL, 0, 76190792Sgshapiro &conn); 76298121Sgshapiro# endif /* SASL >= 20000 */ 76390792Sgshapiro sasl_ok = result == SASL_OK; 76490792Sgshapiro if (!sasl_ok) 76590792Sgshapiro { 76690792Sgshapiro if (LogLevel > 9) 76790792Sgshapiro sm_syslog(LOG_WARNING, NOQID, 76890792Sgshapiro "AUTH error: sasl_server_new failed=%d", 76990792Sgshapiro result); 77090792Sgshapiro } 77190792Sgshapiro } 77290792Sgshapiro if (sasl_ok) 77390792Sgshapiro { 77464562Sgshapiro /* 77564562Sgshapiro ** SASL set properties for sasl 77664562Sgshapiro ** set local/remote IP 77798121Sgshapiro ** XXX Cyrus SASL v1 only supports IPv4 77864562Sgshapiro ** 77964562Sgshapiro ** XXX where exactly are these used/required? 78064562Sgshapiro ** Kerberos_v4 78164562Sgshapiro */ 78264562Sgshapiro 78398121Sgshapiro# if SASL >= 20000 784147078Sgshapiro localip[0] = remoteip[0] = '\0'; 78598121Sgshapiro# if NETINET || NETINET6 78690792Sgshapiro in = macvalue(macid("{daemon_family}"), e); 78798121Sgshapiro if (in != NULL && ( 78898121Sgshapiro# if NETINET6 78998121Sgshapiro strcmp(in, "inet6") == 0 || 79098121Sgshapiro# endif /* NETINET6 */ 79198121Sgshapiro strcmp(in, "inet") == 0)) 79298121Sgshapiro { 79398121Sgshapiro SOCKADDR_LEN_T addrsize; 79498121Sgshapiro SOCKADDR saddr_l; 79598121Sgshapiro SOCKADDR saddr_r; 79698121Sgshapiro 79798121Sgshapiro addrsize = sizeof(saddr_r); 79898121Sgshapiro if (getpeername(sm_io_getinfo(InChannel, SM_IO_WHAT_FD, 79998121Sgshapiro NULL), 80098121Sgshapiro (struct sockaddr *) &saddr_r, 80198121Sgshapiro &addrsize) == 0) 80298121Sgshapiro { 80398121Sgshapiro if (iptostring(&saddr_r, addrsize, 804168515Sgshapiro remoteip, sizeof(remoteip))) 80598121Sgshapiro { 80698121Sgshapiro sasl_setprop(conn, SASL_IPREMOTEPORT, 80798121Sgshapiro remoteip); 80898121Sgshapiro } 80998121Sgshapiro addrsize = sizeof(saddr_l); 81098121Sgshapiro if (getsockname(sm_io_getinfo(InChannel, 81198121Sgshapiro SM_IO_WHAT_FD, 81298121Sgshapiro NULL), 81398121Sgshapiro (struct sockaddr *) &saddr_l, 81498121Sgshapiro &addrsize) == 0) 81598121Sgshapiro { 81698121Sgshapiro if (iptostring(&saddr_l, addrsize, 81798121Sgshapiro localip, 818168515Sgshapiro sizeof(localip))) 81998121Sgshapiro { 82098121Sgshapiro sasl_setprop(conn, 82198121Sgshapiro SASL_IPLOCALPORT, 82298121Sgshapiro localip); 82398121Sgshapiro } 82498121Sgshapiro } 82598121Sgshapiro } 82698121Sgshapiro } 82798121Sgshapiro# endif /* NETINET || NETINET6 */ 82898121Sgshapiro# else /* SASL >= 20000 */ 82998121Sgshapiro# if NETINET 83098121Sgshapiro in = macvalue(macid("{daemon_family}"), e); 83164562Sgshapiro if (in != NULL && strcmp(in, "inet") == 0) 83264562Sgshapiro { 83364562Sgshapiro SOCKADDR_LEN_T addrsize; 83464562Sgshapiro 83564562Sgshapiro addrsize = sizeof(struct sockaddr_in); 83690792Sgshapiro if (getpeername(sm_io_getinfo(InChannel, SM_IO_WHAT_FD, 83790792Sgshapiro NULL), 83864562Sgshapiro (struct sockaddr *)&saddr_r, 83964562Sgshapiro &addrsize) == 0) 84064562Sgshapiro { 84164562Sgshapiro sasl_setprop(conn, SASL_IP_REMOTE, &saddr_r); 84264562Sgshapiro addrsize = sizeof(struct sockaddr_in); 84390792Sgshapiro if (getsockname(sm_io_getinfo(InChannel, 84490792Sgshapiro SM_IO_WHAT_FD, 84590792Sgshapiro NULL), 84664562Sgshapiro (struct sockaddr *)&saddr_l, 84764562Sgshapiro &addrsize) == 0) 84864562Sgshapiro sasl_setprop(conn, SASL_IP_LOCAL, 84964562Sgshapiro &saddr_l); 85064562Sgshapiro } 85164562Sgshapiro } 85298121Sgshapiro# endif /* NETINET */ 85398121Sgshapiro# endif /* SASL >= 20000 */ 85464562Sgshapiro 85564562Sgshapiro auth_type = NULL; 85664562Sgshapiro mechlist = NULL; 85764562Sgshapiro user = NULL; 85890792Sgshapiro# if 0 85990792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 86090792Sgshapiro macid("{auth_author}"), NULL); 86190792Sgshapiro# endif /* 0 */ 86264562Sgshapiro 86364562Sgshapiro /* set properties */ 864168515Sgshapiro (void) memset(&ssp, '\0', sizeof(ssp)); 86590792Sgshapiro 86664562Sgshapiro /* XXX should these be options settable via .cf ? */ 86764562Sgshapiro /* ssp.min_ssf = 0; is default due to memset() */ 86864562Sgshapiro { 86990792Sgshapiro ssp.max_ssf = MaxSLBits; 87064562Sgshapiro ssp.maxbufsize = MAXOUTLEN; 87164562Sgshapiro } 87264562Sgshapiro ssp.security_flags = SASLOpts & SASL_SEC_MASK; 87364562Sgshapiro sasl_ok = sasl_setprop(conn, SASL_SEC_PROPS, &ssp) == SASL_OK; 87464562Sgshapiro 87564562Sgshapiro if (sasl_ok) 87664562Sgshapiro { 87764562Sgshapiro /* 87864562Sgshapiro ** external security strength factor; 87990792Sgshapiro ** currently we have none so zero 88064562Sgshapiro */ 88190792Sgshapiro 88298121Sgshapiro# if SASL >= 20000 88398121Sgshapiro ext_ssf = 0; 88498121Sgshapiro auth_id = NULL; 88598121Sgshapiro sasl_ok = ((sasl_setprop(conn, SASL_SSF_EXTERNAL, 88698121Sgshapiro &ext_ssf) == SASL_OK) && 88798121Sgshapiro (sasl_setprop(conn, SASL_AUTH_EXTERNAL, 888102528Sgshapiro auth_id) == SASL_OK)); 88998121Sgshapiro# else /* SASL >= 20000 */ 89064562Sgshapiro ext_ssf.ssf = 0; 89164562Sgshapiro ext_ssf.auth_id = NULL; 89264562Sgshapiro sasl_ok = sasl_setprop(conn, SASL_SSF_EXTERNAL, 89364562Sgshapiro &ext_ssf) == SASL_OK; 89498121Sgshapiro# endif /* SASL >= 20000 */ 89564562Sgshapiro } 89664562Sgshapiro if (sasl_ok) 89764562Sgshapiro n_mechs = saslmechs(conn, &mechlist); 89838032Speter } 89990792Sgshapiro#endif /* SASL */ 90038032Speter 901120256Sgshapiro#if STARTTLS 902120256Sgshapiro#endif /* STARTTLS */ 903120256Sgshapiro 90490792Sgshapiro#if MILTER 90590792Sgshapiro if (smtp.sm_milterize) 90664562Sgshapiro { 90764562Sgshapiro char state; 90864562Sgshapiro 90964562Sgshapiro /* initialize mail filter connection */ 91090792Sgshapiro smtp.sm_milterlist = milter_init(e, &state); 91164562Sgshapiro switch (state) 91264562Sgshapiro { 91364562Sgshapiro case SMFIR_REJECT: 91490792Sgshapiro if (MilterLogLevel > 3) 91590792Sgshapiro sm_syslog(LOG_INFO, e->e_id, 91694334Sgshapiro "Milter: initialization failed, rejecting commands"); 91764562Sgshapiro greetcode = "554"; 91864562Sgshapiro nullserver = "Command rejected"; 91990792Sgshapiro smtp.sm_milterize = false; 92064562Sgshapiro break; 92164562Sgshapiro 92264562Sgshapiro case SMFIR_TEMPFAIL: 92390792Sgshapiro if (MilterLogLevel > 3) 92490792Sgshapiro sm_syslog(LOG_INFO, e->e_id, 92594334Sgshapiro "Milter: initialization failed, temp failing commands"); 92690792Sgshapiro tempfail = true; 92790792Sgshapiro smtp.sm_milterize = false; 92864562Sgshapiro break; 929157001Sgshapiro 930157001Sgshapiro case SMFIR_SHUTDOWN: 931157001Sgshapiro if (MilterLogLevel > 3) 932157001Sgshapiro sm_syslog(LOG_INFO, e->e_id, 933157001Sgshapiro "Milter: initialization failed, closing connection"); 934157001Sgshapiro tempfail = true; 935157001Sgshapiro smtp.sm_milterize = false; 936157001Sgshapiro message("421 4.7.0 %s closing connection", 937157001Sgshapiro MyHostName); 938157001Sgshapiro 939157001Sgshapiro /* arrange to ignore send list */ 940157001Sgshapiro e->e_sendqueue = NULL; 941157001Sgshapiro goto doquit; 94264562Sgshapiro } 94364562Sgshapiro } 94464562Sgshapiro 94590792Sgshapiro if (smtp.sm_milterlist && smtp.sm_milterize && 94690792Sgshapiro !bitset(EF_DISCARD, e->e_flags)) 94764562Sgshapiro { 94864562Sgshapiro char state; 94990792Sgshapiro char *response; 95064562Sgshapiro 951161389Sgshapiro q = macvalue(macid("{client_name}"), e); 952168515Sgshapiro SM_ASSERT(q != NULL || OpMode == MD_SMTP); 953168515Sgshapiro if (q == NULL) 954168515Sgshapiro q = "localhost"; 955161389Sgshapiro response = milter_connect(q, RealHostAddr, e, &state); 95664562Sgshapiro switch (state) 95764562Sgshapiro { 95864562Sgshapiro case SMFIR_REPLYCODE: /* REPLYCODE shouldn't happen */ 95964562Sgshapiro case SMFIR_REJECT: 96090792Sgshapiro if (MilterLogLevel > 3) 96190792Sgshapiro sm_syslog(LOG_INFO, e->e_id, 96290792Sgshapiro "Milter: connect: host=%s, addr=%s, rejecting commands", 96390792Sgshapiro peerhostname, 96490792Sgshapiro anynet_ntoa(&RealHostAddr)); 96564562Sgshapiro greetcode = "554"; 96664562Sgshapiro nullserver = "Command rejected"; 96790792Sgshapiro smtp.sm_milterize = false; 96864562Sgshapiro break; 96964562Sgshapiro 97064562Sgshapiro case SMFIR_TEMPFAIL: 97190792Sgshapiro if (MilterLogLevel > 3) 97290792Sgshapiro sm_syslog(LOG_INFO, e->e_id, 97390792Sgshapiro "Milter: connect: host=%s, addr=%s, temp failing commands", 97490792Sgshapiro peerhostname, 97590792Sgshapiro anynet_ntoa(&RealHostAddr)); 97690792Sgshapiro tempfail = true; 97790792Sgshapiro smtp.sm_milterize = false; 97864562Sgshapiro break; 979110560Sgshapiro 980110560Sgshapiro case SMFIR_SHUTDOWN: 981110560Sgshapiro if (MilterLogLevel > 3) 982110560Sgshapiro sm_syslog(LOG_INFO, e->e_id, 983110560Sgshapiro "Milter: connect: host=%s, addr=%s, shutdown", 984110560Sgshapiro peerhostname, 985110560Sgshapiro anynet_ntoa(&RealHostAddr)); 986110560Sgshapiro tempfail = true; 987110560Sgshapiro smtp.sm_milterize = false; 988110560Sgshapiro message("421 4.7.0 %s closing connection", 989110560Sgshapiro MyHostName); 990110560Sgshapiro 991110560Sgshapiro /* arrange to ignore send list */ 992110560Sgshapiro e->e_sendqueue = NULL; 993110560Sgshapiro goto doquit; 99464562Sgshapiro } 99590792Sgshapiro if (response != NULL) 99690792Sgshapiro sm_free(response); /* XXX */ 99764562Sgshapiro } 99890792Sgshapiro#endif /* MILTER */ 99964562Sgshapiro 1000132943Sgshapiro /* 1001132943Sgshapiro ** Broken proxies and SMTP slammers 1002132943Sgshapiro ** push data without waiting, catch them 1003132943Sgshapiro */ 1004132943Sgshapiro 1005132943Sgshapiro if ( 100690792Sgshapiro#if STARTTLS 1007132943Sgshapiro !smtps && 1008132943Sgshapiro#endif /* STARTTLS */ 1009168515Sgshapiro *greetcode == '2' && nullserver == NULL) 1010132943Sgshapiro { 1011132943Sgshapiro time_t msecs = 0; 1012132943Sgshapiro char **pvp; 1013132943Sgshapiro char pvpbuf[PSBUFSIZE]; 1014132943Sgshapiro 1015132943Sgshapiro /* Ask the rulesets how long to pause */ 1016132943Sgshapiro pvp = NULL; 1017132943Sgshapiro r = rscap("greet_pause", peerhostname, 1018132943Sgshapiro anynet_ntoa(&RealHostAddr), e, 1019132943Sgshapiro &pvp, pvpbuf, sizeof(pvpbuf)); 1020132943Sgshapiro if (r == EX_OK && pvp != NULL && pvp[0] != NULL && 1021132943Sgshapiro (pvp[0][0] & 0377) == CANONNET && pvp[1] != NULL) 1022132943Sgshapiro { 1023132943Sgshapiro msecs = strtol(pvp[1], NULL, 10); 1024132943Sgshapiro } 1025132943Sgshapiro 1026132943Sgshapiro if (msecs > 0) 1027132943Sgshapiro { 1028132943Sgshapiro int fd; 1029132943Sgshapiro fd_set readfds; 1030132943Sgshapiro struct timeval timeout; 1031157001Sgshapiro struct timeval bp, ep, tp; /* {begin,end,total}pause */ 1032168515Sgshapiro int eoftest; 1033132943Sgshapiro 1034132943Sgshapiro /* pause for a moment */ 1035132943Sgshapiro timeout.tv_sec = msecs / 1000; 1036132943Sgshapiro timeout.tv_usec = (msecs % 1000) * 1000; 1037132943Sgshapiro 1038132943Sgshapiro /* Obey RFC 2821: 4.3.5.2: 220 timeout of 5 minutes */ 1039132943Sgshapiro if (timeout.tv_sec >= 300) 1040132943Sgshapiro { 1041132943Sgshapiro timeout.tv_sec = 300; 1042132943Sgshapiro timeout.tv_usec = 0; 1043132943Sgshapiro } 1044132943Sgshapiro 1045132943Sgshapiro /* check if data is on the socket during the pause */ 1046132943Sgshapiro fd = sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL); 1047132943Sgshapiro FD_ZERO(&readfds); 1048132943Sgshapiro SM_FD_SET(fd, &readfds); 1049157001Sgshapiro gettimeofday(&bp, NULL); 1050132943Sgshapiro if (select(fd + 1, FDSET_CAST &readfds, 1051132943Sgshapiro NULL, NULL, &timeout) > 0 && 1052168515Sgshapiro FD_ISSET(fd, &readfds) && 1053168515Sgshapiro (eoftest = sm_io_getc(InChannel, SM_TIME_DEFAULT)) 1054168515Sgshapiro != SM_IO_EOF) 1055132943Sgshapiro { 1056168515Sgshapiro sm_io_ungetc(InChannel, SM_TIME_DEFAULT, 1057168515Sgshapiro eoftest); 1058157001Sgshapiro gettimeofday(&ep, NULL); 1059157001Sgshapiro timersub(&ep, &bp, &tp); 1060132943Sgshapiro greetcode = "554"; 1061132943Sgshapiro nullserver = "Command rejected"; 1062132943Sgshapiro sm_syslog(LOG_INFO, e->e_id, 1063168515Sgshapiro "rejecting commands from %s [%s] due to pre-greeting traffic after %d seconds", 1064132943Sgshapiro peerhostname, 1065168515Sgshapiro anynet_ntoa(&RealHostAddr), 1066168515Sgshapiro (int) tp.tv_sec + 1067157001Sgshapiro (tp.tv_usec >= 500000 ? 1 : 0) 1068157001Sgshapiro ); 1069132943Sgshapiro } 1070132943Sgshapiro } 1071132943Sgshapiro } 1072132943Sgshapiro 1073132943Sgshapiro#if STARTTLS 107490792Sgshapiro /* If this an smtps connection, start TLS now */ 107590792Sgshapiro if (smtps) 1076120256Sgshapiro { 1077120256Sgshapiro Errors = 0; 107890792Sgshapiro goto starttls; 1079120256Sgshapiro } 108090792Sgshapiro 108190792Sgshapiro greeting: 108290792Sgshapiro 108390792Sgshapiro#endif /* STARTTLS */ 108490792Sgshapiro 108538032Speter /* output the first line, inserting "ESMTP" as second word */ 108690792Sgshapiro if (*greetcode == '5') 1087168515Sgshapiro (void) sm_snprintf(inp, sizeof(inp), 1088168515Sgshapiro "%s not accepting messages", hostname); 108990792Sgshapiro else 1090168515Sgshapiro expand(SmtpGreeting, inp, sizeof(inp), e); 109190792Sgshapiro 109238032Speter p = strchr(inp, '\n'); 109338032Speter if (p != NULL) 109438032Speter *p++ = '\0'; 109538032Speter id = strchr(inp, ' '); 109638032Speter if (id == NULL) 109738032Speter id = &inp[strlen(inp)]; 109864562Sgshapiro if (p == NULL) 1099168515Sgshapiro (void) sm_snprintf(cmdbuf, sizeof(cmdbuf), 110064562Sgshapiro "%s %%.*s ESMTP%%s", greetcode); 110164562Sgshapiro else 1102168515Sgshapiro (void) sm_snprintf(cmdbuf, sizeof(cmdbuf), 110364562Sgshapiro "%s-%%.*s ESMTP%%s", greetcode); 110466494Sgshapiro message(cmdbuf, (int) (id - inp), inp, id); 110538032Speter 110638032Speter /* output remaining lines */ 110738032Speter while ((id = p) != NULL && (p = strchr(id, '\n')) != NULL) 110838032Speter { 110938032Speter *p++ = '\0'; 111038032Speter if (isascii(*id) && isspace(*id)) 111138032Speter id++; 1112168515Sgshapiro (void) sm_strlcpyn(cmdbuf, sizeof(cmdbuf), 2, greetcode, "-%s"); 111364562Sgshapiro message(cmdbuf, id); 111438032Speter } 111538032Speter if (id != NULL) 111638032Speter { 111738032Speter if (isascii(*id) && isspace(*id)) 111838032Speter id++; 1119168515Sgshapiro (void) sm_strlcpyn(cmdbuf, sizeof(cmdbuf), 2, greetcode, " %s"); 112064562Sgshapiro message(cmdbuf, id); 112138032Speter } 112238032Speter 112338032Speter protocol = NULL; 112438032Speter sendinghost = macvalue('s', e); 112590792Sgshapiro 112690792Sgshapiro /* If quarantining by a connect/ehlo action, save between messages */ 112790792Sgshapiro if (e->e_quarmsg == NULL) 112890792Sgshapiro smtp.sm_quarmsg = NULL; 112990792Sgshapiro else 113090792Sgshapiro smtp.sm_quarmsg = newstr(e->e_quarmsg); 113190792Sgshapiro 113290792Sgshapiro /* sendinghost's storage must outlive the current envelope */ 113390792Sgshapiro if (sendinghost != NULL) 113490792Sgshapiro sendinghost = sm_strdup_x(sendinghost); 113590792Sgshapiro first = true; 113690792Sgshapiro gothello = false; 113790792Sgshapiro smtp.sm_gotmail = false; 113838032Speter for (;;) 113938032Speter { 114090792Sgshapiro SM_TRY 114190792Sgshapiro { 114290792Sgshapiro QuickAbort = false; 114390792Sgshapiro HoldErrs = false; 114490792Sgshapiro SuprErrs = false; 114590792Sgshapiro LogUsrErrs = false; 114690792Sgshapiro OnlyOneError = true; 114738032Speter e->e_flags &= ~(EF_VRFYONLY|EF_GLOBALERRS); 1148168515Sgshapiro#if MILTER 1149168515Sgshapiro milter_cmd_fail = false; 1150168515Sgshapiro#endif /* MILTER */ 115138032Speter 115238032Speter /* setup for the read */ 115338032Speter e->e_to = NULL; 115438032Speter Errors = 0; 115564562Sgshapiro FileName = NULL; 115690792Sgshapiro (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 115738032Speter 115838032Speter /* read the input line */ 115938032Speter SmtpPhase = "server cmd read"; 116090792Sgshapiro sm_setproctitle(true, e, "server %s cmd read", CurSmtpClient); 116138032Speter 116238032Speter /* handle errors */ 116390792Sgshapiro if (sm_io_error(OutChannel) || 1164168515Sgshapiro (p = sfgets(inp, sizeof(inp), InChannel, 116564562Sgshapiro TimeOuts.to_nextcommand, SmtpPhase)) == NULL) 116638032Speter { 116764562Sgshapiro char *d; 116864562Sgshapiro 116990792Sgshapiro d = macvalue(macid("{daemon_name}"), e); 117064562Sgshapiro if (d == NULL) 117164562Sgshapiro d = "stdin"; 117238032Speter /* end of file, just die */ 117338032Speter disconnect(1, e); 117464562Sgshapiro 117590792Sgshapiro#if MILTER 117664562Sgshapiro /* close out milter filters */ 117764562Sgshapiro milter_quit(e); 117890792Sgshapiro#endif /* MILTER */ 117964562Sgshapiro 118064562Sgshapiro message("421 4.4.1 %s Lost input channel from %s", 118138032Speter MyHostName, CurSmtpClient); 118290792Sgshapiro if (LogLevel > (smtp.sm_gotmail ? 1 : 19)) 118338032Speter sm_syslog(LOG_NOTICE, e->e_id, 1184110560Sgshapiro "lost input channel from %s to %s after %s", 118564562Sgshapiro CurSmtpClient, d, 118664562Sgshapiro (c == NULL || c->cmd_name == NULL) ? "startup" : c->cmd_name); 118738032Speter /* 118842575Speter ** If have not accepted mail (DATA), do not bounce 118942575Speter ** bad addresses back to sender. 119038032Speter */ 119164562Sgshapiro 119238032Speter if (bitset(EF_CLRQUEUE, e->e_flags)) 119338032Speter e->e_sendqueue = NULL; 119464562Sgshapiro goto doquit; 119538032Speter } 119638032Speter 1197168515Sgshapiro /* also used by "proxy" check below */ 1198168515Sgshapiro inplen = strlen(inp); 1199168515Sgshapiro#if SASL 1200168515Sgshapiro /* 1201168515Sgshapiro ** SMTP AUTH requires accepting any length, 1202168515Sgshapiro ** at least for challenge/response. However, not imposing 1203168515Sgshapiro ** a limit is a bad idea (denial of service). 1204168515Sgshapiro */ 1205168515Sgshapiro 1206168515Sgshapiro if (authenticating != SASL_PROC_AUTH 1207168515Sgshapiro && sm_strncasecmp(inp, "AUTH ", 5) != 0 1208168515Sgshapiro && inplen > MAXLINE) 1209168515Sgshapiro { 1210168515Sgshapiro message("421 4.7.0 %s Command too long, possible attack %s", 1211168515Sgshapiro MyHostName, CurSmtpClient); 1212168515Sgshapiro sm_syslog(LOG_INFO, e->e_id, 1213168515Sgshapiro "%s: SMTP violation, input too long: %lu", 1214168515Sgshapiro CurSmtpClient, (unsigned long) inplen); 1215168515Sgshapiro goto doquit; 1216168515Sgshapiro } 1217168515Sgshapiro#endif /* SASL */ 1218168515Sgshapiro 121990792Sgshapiro if (first) 122090792Sgshapiro { 1221168515Sgshapiro size_t cmdlen; 1222110560Sgshapiro int idx; 1223110560Sgshapiro char *http_cmd; 1224110560Sgshapiro static char *http_cmds[] = { "GET", "POST", 1225110560Sgshapiro "CONNECT", "USER", NULL }; 1226110560Sgshapiro 1227110560Sgshapiro for (idx = 0; (http_cmd = http_cmds[idx]) != NULL; 1228110560Sgshapiro idx++) 1229110560Sgshapiro { 1230110560Sgshapiro cmdlen = strlen(http_cmd); 1231110560Sgshapiro if (cmdlen < inplen && 1232110560Sgshapiro sm_strncasecmp(inp, http_cmd, cmdlen) == 0 && 1233110560Sgshapiro isascii(inp[cmdlen]) && isspace(inp[cmdlen])) 1234110560Sgshapiro { 1235110560Sgshapiro /* Open proxy, drop it */ 1236110560Sgshapiro message("421 4.7.0 %s Rejecting open proxy %s", 1237110560Sgshapiro MyHostName, CurSmtpClient); 1238110560Sgshapiro sm_syslog(LOG_INFO, e->e_id, 1239110560Sgshapiro "%s: probable open proxy: command=%.40s", 1240110560Sgshapiro CurSmtpClient, inp); 1241110560Sgshapiro goto doquit; 1242110560Sgshapiro } 1243110560Sgshapiro } 124490792Sgshapiro first = false; 124590792Sgshapiro } 124690792Sgshapiro 124738032Speter /* clean up end of line */ 124890792Sgshapiro fixcrlf(inp, true); 124938032Speter 125090792Sgshapiro#if PIPELINING 125190792Sgshapiro# if _FFR_NO_PIPE 125290792Sgshapiro /* 125390792Sgshapiro ** if there is more input and pipelining is disabled: 125490792Sgshapiro ** delay ... (and maybe discard the input?) 125590792Sgshapiro ** XXX this doesn't really work, at least in tests using 125690792Sgshapiro ** telnet SM_IO_IS_READABLE only returns 1 if there were 125790792Sgshapiro ** more than 2 input lines available. 125890792Sgshapiro */ 125990792Sgshapiro 126090792Sgshapiro if (bitset(SRV_NO_PIPE, features) && 1261110560Sgshapiro sm_io_getinfo(InChannel, SM_IO_IS_READABLE, NULL) > 0) 126290792Sgshapiro { 126390792Sgshapiro if (++np_log < 3) 126490792Sgshapiro sm_syslog(LOG_INFO, NOQID, 126590792Sgshapiro "unauthorized PIPELINING, sleeping"); 126690792Sgshapiro sleep(1); 126790792Sgshapiro } 126890792Sgshapiro 126990792Sgshapiro# endif /* _FFR_NO_PIPE */ 127090792Sgshapiro#endif /* PIPELINING */ 127190792Sgshapiro 127290792Sgshapiro#if SASL 127364562Sgshapiro if (authenticating == SASL_PROC_AUTH) 127464562Sgshapiro { 127590792Sgshapiro# if 0 127664562Sgshapiro if (*inp == '\0') 127764562Sgshapiro { 127864562Sgshapiro authenticating = SASL_NOT_AUTH; 127964562Sgshapiro message("501 5.5.2 missing input"); 1280120256Sgshapiro RESET_SASLCONN; 128164562Sgshapiro continue; 128264562Sgshapiro } 128390792Sgshapiro# endif /* 0 */ 128464562Sgshapiro if (*inp == '*' && *(inp + 1) == '\0') 128564562Sgshapiro { 128664562Sgshapiro authenticating = SASL_NOT_AUTH; 128764562Sgshapiro 128864562Sgshapiro /* rfc 2254 4. */ 128964562Sgshapiro message("501 5.0.0 AUTH aborted"); 1290120256Sgshapiro RESET_SASLCONN; 129164562Sgshapiro continue; 129264562Sgshapiro } 129364562Sgshapiro 129464562Sgshapiro /* could this be shorter? XXX */ 129598121Sgshapiro# if SASL >= 20000 129698121Sgshapiro in = xalloc(strlen(inp) + 1); 129798121Sgshapiro result = sasl_decode64(inp, strlen(inp), in, 129898121Sgshapiro strlen(inp), &inlen); 129998121Sgshapiro# else /* SASL >= 20000 */ 130064562Sgshapiro out = xalloc(strlen(inp)); 130164562Sgshapiro result = sasl_decode64(inp, strlen(inp), out, &outlen); 130298121Sgshapiro# endif /* SASL >= 20000 */ 130364562Sgshapiro if (result != SASL_OK) 130464562Sgshapiro { 130564562Sgshapiro authenticating = SASL_NOT_AUTH; 130664562Sgshapiro 130764562Sgshapiro /* rfc 2254 4. */ 130864562Sgshapiro message("501 5.5.4 cannot decode AUTH parameter %s", 130964562Sgshapiro inp); 131098121Sgshapiro# if SASL >= 20000 131198121Sgshapiro sm_free(in); 131298121Sgshapiro# endif /* SASL >= 20000 */ 1313120256Sgshapiro RESET_SASLCONN; 131464562Sgshapiro continue; 131564562Sgshapiro } 131664562Sgshapiro 131798121Sgshapiro# if SASL >= 20000 131898121Sgshapiro result = sasl_server_step(conn, in, inlen, 131998121Sgshapiro &out, &outlen); 132098121Sgshapiro sm_free(in); 132198121Sgshapiro# else /* SASL >= 20000 */ 132264562Sgshapiro result = sasl_server_step(conn, out, outlen, 132364562Sgshapiro &out, &outlen, &errstr); 132498121Sgshapiro# endif /* SASL >= 20000 */ 132564562Sgshapiro 132664562Sgshapiro /* get an OK if we're done */ 132764562Sgshapiro if (result == SASL_OK) 132864562Sgshapiro { 132964562Sgshapiro authenticated: 133064562Sgshapiro message("235 2.0.0 OK Authenticated"); 133164562Sgshapiro authenticating = SASL_IS_AUTH; 133290792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 133390792Sgshapiro macid("{auth_type}"), auth_type); 133464562Sgshapiro 133598121Sgshapiro# if SASL >= 20000 133698121Sgshapiro user = macvalue(macid("{auth_authen}"), e); 133798121Sgshapiro 133898121Sgshapiro /* get security strength (features) */ 133998121Sgshapiro result = sasl_getprop(conn, SASL_SSF, 134098121Sgshapiro (const void **) &ssf); 134198121Sgshapiro# else /* SASL >= 20000 */ 134264562Sgshapiro result = sasl_getprop(conn, SASL_USERNAME, 134364562Sgshapiro (void **)&user); 134464562Sgshapiro if (result != SASL_OK) 134564562Sgshapiro { 134664562Sgshapiro user = ""; 134790792Sgshapiro macdefine(&BlankEnvelope.e_macro, 134890792Sgshapiro A_PERM, 134990792Sgshapiro macid("{auth_authen}"), NULL); 135064562Sgshapiro } 135164562Sgshapiro else 135264562Sgshapiro { 135390792Sgshapiro macdefine(&BlankEnvelope.e_macro, 135490792Sgshapiro A_TEMP, 1355132943Sgshapiro macid("{auth_authen}"), 1356132943Sgshapiro xtextify(user, "<>\")")); 135764562Sgshapiro } 135864562Sgshapiro 135990792Sgshapiro# if 0 136064562Sgshapiro /* get realm? */ 136164562Sgshapiro sasl_getprop(conn, SASL_REALM, (void **) &data); 136290792Sgshapiro# endif /* 0 */ 136364562Sgshapiro 136464562Sgshapiro /* get security strength (features) */ 136564562Sgshapiro result = sasl_getprop(conn, SASL_SSF, 136664562Sgshapiro (void **) &ssf); 136798121Sgshapiro# endif /* SASL >= 20000 */ 136864562Sgshapiro if (result != SASL_OK) 136964562Sgshapiro { 137090792Sgshapiro macdefine(&BlankEnvelope.e_macro, 137190792Sgshapiro A_PERM, 137290792Sgshapiro macid("{auth_ssf}"), "0"); 137364562Sgshapiro ssf = NULL; 137464562Sgshapiro } 137564562Sgshapiro else 137664562Sgshapiro { 137764562Sgshapiro char pbuf[8]; 137864562Sgshapiro 1379168515Sgshapiro (void) sm_snprintf(pbuf, sizeof(pbuf), 138090792Sgshapiro "%u", *ssf); 138190792Sgshapiro macdefine(&BlankEnvelope.e_macro, 138290792Sgshapiro A_TEMP, 138390792Sgshapiro macid("{auth_ssf}"), pbuf); 138464562Sgshapiro if (tTd(95, 8)) 138590792Sgshapiro sm_dprintf("AUTH auth_ssf: %u\n", 138690792Sgshapiro *ssf); 138764562Sgshapiro } 138890792Sgshapiro 138964562Sgshapiro /* 139090792Sgshapiro ** Only switch to encrypted connection 139164562Sgshapiro ** if a security layer has been negotiated 139264562Sgshapiro */ 139390792Sgshapiro 139464562Sgshapiro if (ssf != NULL && *ssf > 0) 139564562Sgshapiro { 1396159609Sgshapiro int tmo; 1397159609Sgshapiro 139864562Sgshapiro /* 139990792Sgshapiro ** Convert I/O layer to use SASL. 140090792Sgshapiro ** If the call fails, the connection 140190792Sgshapiro ** is aborted. 140264562Sgshapiro */ 140390792Sgshapiro 1404159609Sgshapiro tmo = TimeOuts.to_datablock * 1000; 140590792Sgshapiro if (sfdcsasl(&InChannel, &OutChannel, 1406159609Sgshapiro conn, tmo) == 0) 140764562Sgshapiro { 140864562Sgshapiro /* restart dialogue */ 140964562Sgshapiro n_helo = 0; 141094334Sgshapiro# if PIPELINING 141190792Sgshapiro (void) sm_io_autoflush(InChannel, 141290792Sgshapiro OutChannel); 141394334Sgshapiro# endif /* PIPELINING */ 141464562Sgshapiro } 141564562Sgshapiro else 141664562Sgshapiro syserr("503 5.3.3 SASL TLS failed"); 141764562Sgshapiro } 141890792Sgshapiro 141990792Sgshapiro /* NULL pointer ok since it's our function */ 142090792Sgshapiro if (LogLevel > 8) 142164562Sgshapiro sm_syslog(LOG_INFO, NOQID, 1422110560Sgshapiro "AUTH=server, relay=%s, authid=%.128s, mech=%.16s, bits=%d", 142390792Sgshapiro CurSmtpClient, 142490792Sgshapiro shortenstring(user, 128), 142590792Sgshapiro auth_type, *ssf); 142664562Sgshapiro } 142764562Sgshapiro else if (result == SASL_CONTINUE) 142864562Sgshapiro { 142964562Sgshapiro len = ENC64LEN(outlen); 143064562Sgshapiro out2 = xalloc(len); 143164562Sgshapiro result = sasl_encode64(out, outlen, out2, len, 143290792Sgshapiro &out2len); 143364562Sgshapiro if (result != SASL_OK) 143464562Sgshapiro { 143564562Sgshapiro /* correct code? XXX */ 143664562Sgshapiro /* 454 Temp. authentication failure */ 143764562Sgshapiro message("454 4.5.4 Internal error: unable to encode64"); 143864562Sgshapiro if (LogLevel > 5) 143964562Sgshapiro sm_syslog(LOG_WARNING, e->e_id, 144090792Sgshapiro "AUTH encode64 error [%d for \"%s\"]", 144164562Sgshapiro result, out); 144264562Sgshapiro /* start over? */ 144364562Sgshapiro authenticating = SASL_NOT_AUTH; 144464562Sgshapiro } 144564562Sgshapiro else 144664562Sgshapiro { 144764562Sgshapiro message("334 %s", out2); 144864562Sgshapiro if (tTd(95, 2)) 144990792Sgshapiro sm_dprintf("AUTH continue: msg='%s' len=%u\n", 145090792Sgshapiro out2, out2len); 145164562Sgshapiro } 145298121Sgshapiro# if SASL >= 20000 145398121Sgshapiro sm_free(out2); 145498121Sgshapiro# endif /* SASL >= 20000 */ 145564562Sgshapiro } 145664562Sgshapiro else 145764562Sgshapiro { 145864562Sgshapiro /* not SASL_OK or SASL_CONT */ 145998121Sgshapiro message("535 5.7.0 authentication failed"); 146064562Sgshapiro if (LogLevel > 9) 146164562Sgshapiro sm_syslog(LOG_WARNING, e->e_id, 146290792Sgshapiro "AUTH failure (%s): %s (%d) %s", 146364562Sgshapiro auth_type, 146464562Sgshapiro sasl_errstring(result, NULL, 146564562Sgshapiro NULL), 146690792Sgshapiro result, 146798121Sgshapiro# if SASL >= 20000 146898121Sgshapiro sasl_errdetail(conn)); 146998121Sgshapiro# else /* SASL >= 20000 */ 147090792Sgshapiro errstr == NULL ? "" : errstr); 147198121Sgshapiro# endif /* SASL >= 20000 */ 1472120256Sgshapiro RESET_SASLCONN; 147364562Sgshapiro authenticating = SASL_NOT_AUTH; 147464562Sgshapiro } 147564562Sgshapiro } 147664562Sgshapiro else 147764562Sgshapiro { 147864562Sgshapiro /* don't want to do any of this if authenticating */ 147990792Sgshapiro#endif /* SASL */ 148064562Sgshapiro 148138032Speter /* echo command to transcript */ 148238032Speter if (e->e_xfp != NULL) 148390792Sgshapiro (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 148490792Sgshapiro "<<< %s\n", inp); 148538032Speter 148690792Sgshapiro if (LogLevel > 14) 148790792Sgshapiro sm_syslog(LOG_INFO, e->e_id, "<-- %s", inp); 148838032Speter 148938032Speter /* break off command */ 149038032Speter for (p = inp; isascii(*p) && isspace(*p); p++) 149138032Speter continue; 149238032Speter cmd = cmdbuf; 149338032Speter while (*p != '\0' && 149438032Speter !(isascii(*p) && isspace(*p)) && 1495168515Sgshapiro cmd < &cmdbuf[sizeof(cmdbuf) - 2]) 149638032Speter *cmd++ = *p++; 149738032Speter *cmd = '\0'; 149838032Speter 149938032Speter /* throw away leading whitespace */ 150090792Sgshapiro SKIP_SPACE(p); 150138032Speter 150238032Speter /* decode command */ 150364562Sgshapiro for (c = CmdTab; c->cmd_name != NULL; c++) 150438032Speter { 150590792Sgshapiro if (sm_strcasecmp(c->cmd_name, cmdbuf) == 0) 150638032Speter break; 150738032Speter } 150838032Speter 150938032Speter /* reset errors */ 151038032Speter errno = 0; 151138032Speter 151290792Sgshapiro /* check whether a "non-null" command has been used */ 151390792Sgshapiro switch (c->cmd_code) 151490792Sgshapiro { 151590792Sgshapiro#if SASL 151690792Sgshapiro case CMDAUTH: 151790792Sgshapiro /* avoid information leak; take first two words? */ 151890792Sgshapiro q = "AUTH"; 151990792Sgshapiro break; 152090792Sgshapiro#endif /* SASL */ 152190792Sgshapiro 152290792Sgshapiro case CMDMAIL: 152390792Sgshapiro case CMDEXPN: 152490792Sgshapiro case CMDVRFY: 152590792Sgshapiro case CMDETRN: 152690792Sgshapiro lognullconnection = false; 152790792Sgshapiro /* FALLTHROUGH */ 152890792Sgshapiro default: 152990792Sgshapiro q = inp; 153090792Sgshapiro break; 153190792Sgshapiro } 153290792Sgshapiro 153390792Sgshapiro if (e->e_id == NULL) 153490792Sgshapiro sm_setproctitle(true, e, "%s: %.80s", 153590792Sgshapiro CurSmtpClient, q); 153690792Sgshapiro else 153790792Sgshapiro sm_setproctitle(true, e, "%s %s: %.80s", 153890792Sgshapiro qid_printname(e), 153990792Sgshapiro CurSmtpClient, q); 154090792Sgshapiro 154138032Speter /* 154238032Speter ** Process command. 154338032Speter ** 154438032Speter ** If we are running as a null server, return 550 154590792Sgshapiro ** to almost everything. 154638032Speter */ 154738032Speter 154864562Sgshapiro if (nullserver != NULL || bitnset(D_ETRNONLY, d_flags)) 154938032Speter { 155064562Sgshapiro switch (c->cmd_code) 155138032Speter { 155238032Speter case CMDQUIT: 155338032Speter case CMDHELO: 155438032Speter case CMDEHLO: 155538032Speter case CMDNOOP: 155664562Sgshapiro case CMDRSET: 1557125820Sgshapiro case CMDERROR: 155838032Speter /* process normally */ 155938032Speter break; 156038032Speter 156164562Sgshapiro case CMDETRN: 156264562Sgshapiro if (bitnset(D_ETRNONLY, d_flags) && 156364562Sgshapiro nullserver == NULL) 156464562Sgshapiro break; 156590792Sgshapiro DELAY_CONN("ETRN"); 156680785Sgshapiro /* FALLTHROUGH */ 156764562Sgshapiro 156838032Speter default: 156990792Sgshapiro#if MAXBADCOMMANDS > 0 157090792Sgshapiro /* theoretically this could overflow */ 157190792Sgshapiro if (nullserver != NULL && 157290792Sgshapiro ++n_badcmds > MAXBADCOMMANDS) 157364562Sgshapiro { 157490792Sgshapiro message("421 4.7.0 %s Too many bad commands; closing connection", 157590792Sgshapiro MyHostName); 157690792Sgshapiro 157790792Sgshapiro /* arrange to ignore send list */ 157890792Sgshapiro e->e_sendqueue = NULL; 157990792Sgshapiro goto doquit; 158064562Sgshapiro } 158190792Sgshapiro#endif /* MAXBADCOMMANDS > 0 */ 158264562Sgshapiro if (nullserver != NULL) 158364562Sgshapiro { 158464562Sgshapiro if (ISSMTPREPLY(nullserver)) 158564562Sgshapiro usrerr(nullserver); 158664562Sgshapiro else 158790792Sgshapiro usrerr("550 5.0.0 %s", 158890792Sgshapiro nullserver); 158964562Sgshapiro } 159064562Sgshapiro else 159164562Sgshapiro usrerr("452 4.4.5 Insufficient disk space; try again later"); 159238032Speter continue; 159338032Speter } 159438032Speter } 159538032Speter 159664562Sgshapiro switch (c->cmd_code) 159738032Speter { 159890792Sgshapiro#if SASL 159964562Sgshapiro case CMDAUTH: /* sasl */ 160090792Sgshapiro DELAY_CONN("AUTH"); 160190792Sgshapiro if (!sasl_ok || n_mechs <= 0) 160264562Sgshapiro { 160364562Sgshapiro message("503 5.3.3 AUTH not available"); 160464562Sgshapiro break; 160564562Sgshapiro } 160664562Sgshapiro if (authenticating == SASL_IS_AUTH) 160764562Sgshapiro { 160864562Sgshapiro message("503 5.5.0 Already Authenticated"); 160964562Sgshapiro break; 161064562Sgshapiro } 161190792Sgshapiro if (smtp.sm_gotmail) 161264562Sgshapiro { 161364562Sgshapiro message("503 5.5.0 AUTH not permitted during a mail transaction"); 161464562Sgshapiro break; 161564562Sgshapiro } 161664562Sgshapiro if (tempfail) 161764562Sgshapiro { 161864562Sgshapiro if (LogLevel > 9) 161964562Sgshapiro sm_syslog(LOG_INFO, e->e_id, 1620110560Sgshapiro "SMTP AUTH command (%.100s) from %s tempfailed (due to previous checks)", 162164562Sgshapiro p, CurSmtpClient); 1622132943Sgshapiro usrerr("454 4.3.0 Please try again later"); 162364562Sgshapiro break; 162464562Sgshapiro } 162564562Sgshapiro 162690792Sgshapiro ismore = false; 162764562Sgshapiro 162864562Sgshapiro /* crude way to avoid crack attempts */ 1629132943Sgshapiro STOP_IF_ATTACK(checksmtpattack(&n_auth, n_mechs + 1, 1630132943Sgshapiro true, "AUTH", e)); 163164562Sgshapiro 163290792Sgshapiro /* make sure mechanism (p) is a valid string */ 163364562Sgshapiro for (q = p; *q != '\0' && isascii(*q); q++) 163464562Sgshapiro { 163564562Sgshapiro if (isspace(*q)) 163664562Sgshapiro { 163764562Sgshapiro *q = '\0'; 163864562Sgshapiro while (*++q != '\0' && 163964562Sgshapiro isascii(*q) && isspace(*q)) 164064562Sgshapiro continue; 164164562Sgshapiro *(q - 1) = '\0'; 164264562Sgshapiro ismore = (*q != '\0'); 164364562Sgshapiro break; 164464562Sgshapiro } 164564562Sgshapiro } 164664562Sgshapiro 164798121Sgshapiro if (*p == '\0') 164898121Sgshapiro { 164998121Sgshapiro message("501 5.5.2 AUTH mechanism must be specified"); 165098121Sgshapiro break; 165198121Sgshapiro } 165298121Sgshapiro 165364562Sgshapiro /* check whether mechanism is available */ 165464562Sgshapiro if (iteminlist(p, mechlist, " ") == NULL) 165564562Sgshapiro { 165698121Sgshapiro message("504 5.3.3 AUTH mechanism %.32s not available", 165764562Sgshapiro p); 165864562Sgshapiro break; 165964562Sgshapiro } 166064562Sgshapiro 166164562Sgshapiro if (ismore) 166264562Sgshapiro { 166364562Sgshapiro /* could this be shorter? XXX */ 166498121Sgshapiro# if SASL >= 20000 166598121Sgshapiro in = xalloc(strlen(q) + 1); 1666102528Sgshapiro result = sasl_decode64(q, strlen(q), in, 166798121Sgshapiro strlen(q), &inlen); 166898121Sgshapiro# else /* SASL >= 20000 */ 166990792Sgshapiro in = sm_rpool_malloc(e->e_rpool, strlen(q)); 167064562Sgshapiro result = sasl_decode64(q, strlen(q), in, 167190792Sgshapiro &inlen); 167298121Sgshapiro# endif /* SASL >= 20000 */ 167364562Sgshapiro if (result != SASL_OK) 167464562Sgshapiro { 167564562Sgshapiro message("501 5.5.4 cannot BASE64 decode '%s'", 167664562Sgshapiro q); 167764562Sgshapiro if (LogLevel > 5) 167864562Sgshapiro sm_syslog(LOG_WARNING, e->e_id, 167990792Sgshapiro "AUTH decode64 error [%d for \"%s\"]", 168064562Sgshapiro result, q); 168164562Sgshapiro /* start over? */ 168264562Sgshapiro authenticating = SASL_NOT_AUTH; 168398121Sgshapiro# if SASL >= 20000 168498121Sgshapiro sm_free(in); 168598121Sgshapiro# endif /* SASL >= 20000 */ 168664562Sgshapiro in = NULL; 168764562Sgshapiro inlen = 0; 168864562Sgshapiro break; 168964562Sgshapiro } 169064562Sgshapiro } 169164562Sgshapiro else 169264562Sgshapiro { 169364562Sgshapiro in = NULL; 169464562Sgshapiro inlen = 0; 169564562Sgshapiro } 169664562Sgshapiro 169764562Sgshapiro /* see if that auth type exists */ 169898121Sgshapiro# if SASL >= 20000 1699102528Sgshapiro result = sasl_server_start(conn, p, in, inlen, 170098121Sgshapiro &out, &outlen); 170198121Sgshapiro if (in != NULL) 170298121Sgshapiro sm_free(in); 170398121Sgshapiro# else /* SASL >= 20000 */ 170464562Sgshapiro result = sasl_server_start(conn, p, in, inlen, 170564562Sgshapiro &out, &outlen, &errstr); 170698121Sgshapiro# endif /* SASL >= 20000 */ 170764562Sgshapiro 170864562Sgshapiro if (result != SASL_OK && result != SASL_CONTINUE) 170964562Sgshapiro { 171098121Sgshapiro message("535 5.7.0 authentication failed"); 171164562Sgshapiro if (LogLevel > 9) 171264562Sgshapiro sm_syslog(LOG_ERR, e->e_id, 171390792Sgshapiro "AUTH failure (%s): %s (%d) %s", 171464562Sgshapiro p, 171564562Sgshapiro sasl_errstring(result, NULL, 171664562Sgshapiro NULL), 171790792Sgshapiro result, 171898121Sgshapiro# if SASL >= 20000 171998121Sgshapiro sasl_errdetail(conn)); 172098121Sgshapiro# else /* SASL >= 20000 */ 172190792Sgshapiro errstr); 172298121Sgshapiro# endif /* SASL >= 20000 */ 1723120256Sgshapiro RESET_SASLCONN; 172464562Sgshapiro break; 172564562Sgshapiro } 172664562Sgshapiro auth_type = newstr(p); 172764562Sgshapiro 172864562Sgshapiro if (result == SASL_OK) 172964562Sgshapiro { 173064562Sgshapiro /* ugly, but same code */ 173164562Sgshapiro goto authenticated; 173264562Sgshapiro /* authenticated by the initial response */ 173364562Sgshapiro } 173464562Sgshapiro 173564562Sgshapiro /* len is at least 2 */ 173664562Sgshapiro len = ENC64LEN(outlen); 173764562Sgshapiro out2 = xalloc(len); 173864562Sgshapiro result = sasl_encode64(out, outlen, out2, len, 173990792Sgshapiro &out2len); 174064562Sgshapiro 174164562Sgshapiro if (result != SASL_OK) 174264562Sgshapiro { 174364562Sgshapiro message("454 4.5.4 Temporary authentication failure"); 174464562Sgshapiro if (LogLevel > 5) 174564562Sgshapiro sm_syslog(LOG_WARNING, e->e_id, 174690792Sgshapiro "AUTH encode64 error [%d for \"%s\"]", 174764562Sgshapiro result, out); 174864562Sgshapiro 174964562Sgshapiro /* start over? */ 175064562Sgshapiro authenticating = SASL_NOT_AUTH; 1751120256Sgshapiro RESET_SASLCONN; 175264562Sgshapiro } 175364562Sgshapiro else 175464562Sgshapiro { 175564562Sgshapiro message("334 %s", out2); 175664562Sgshapiro authenticating = SASL_PROC_AUTH; 175764562Sgshapiro } 175898121Sgshapiro# if SASL >= 20000 175998121Sgshapiro sm_free(out2); 176098121Sgshapiro# endif /* SASL >= 20000 */ 176164562Sgshapiro break; 176290792Sgshapiro#endif /* SASL */ 176364562Sgshapiro 176490792Sgshapiro#if STARTTLS 176564562Sgshapiro case CMDSTLS: /* starttls */ 176690792Sgshapiro DELAY_CONN("STARTTLS"); 176764562Sgshapiro if (*p != '\0') 176864562Sgshapiro { 176964562Sgshapiro message("501 5.5.2 Syntax error (no parameters allowed)"); 177064562Sgshapiro break; 177164562Sgshapiro } 177290792Sgshapiro if (!bitset(SRV_OFFER_TLS, features)) 177364562Sgshapiro { 177464562Sgshapiro message("503 5.5.0 TLS not available"); 177564562Sgshapiro break; 177664562Sgshapiro } 177777349Sgshapiro if (!tls_ok_srv) 177864562Sgshapiro { 177964562Sgshapiro message("454 4.3.3 TLS not available after start"); 178064562Sgshapiro break; 178164562Sgshapiro } 178290792Sgshapiro if (smtp.sm_gotmail) 178364562Sgshapiro { 178464562Sgshapiro message("503 5.5.0 TLS not permitted during a mail transaction"); 178564562Sgshapiro break; 178664562Sgshapiro } 178764562Sgshapiro if (tempfail) 178864562Sgshapiro { 178964562Sgshapiro if (LogLevel > 9) 179064562Sgshapiro sm_syslog(LOG_INFO, e->e_id, 1791110560Sgshapiro "SMTP STARTTLS command (%.100s) from %s tempfailed (due to previous checks)", 179264562Sgshapiro p, CurSmtpClient); 1793132943Sgshapiro usrerr("454 4.7.0 Please try again later"); 179464562Sgshapiro break; 179564562Sgshapiro } 179690792Sgshapiro starttls: 179764562Sgshapiro# if TLS_NO_RSA 179864562Sgshapiro /* 179964562Sgshapiro ** XXX do we need a temp key ? 180064562Sgshapiro */ 180164562Sgshapiro# else /* TLS_NO_RSA */ 180264562Sgshapiro# endif /* TLS_NO_RSA */ 180390792Sgshapiro 180490792Sgshapiro# if TLS_VRFY_PER_CTX 180590792Sgshapiro /* 180690792Sgshapiro ** Note: this sets the verification globally 180790792Sgshapiro ** (per SSL_CTX) 180890792Sgshapiro ** it's ok since it applies only to one transaction 180990792Sgshapiro */ 181090792Sgshapiro 181190792Sgshapiro TLS_VERIFY_CLIENT(); 181290792Sgshapiro# endif /* TLS_VRFY_PER_CTX */ 181390792Sgshapiro 181464562Sgshapiro if (srv_ssl != NULL) 181564562Sgshapiro SSL_clear(srv_ssl); 181664562Sgshapiro else if ((srv_ssl = SSL_new(srv_ctx)) == NULL) 181764562Sgshapiro { 181864562Sgshapiro message("454 4.3.3 TLS not available: error generating SSL handle"); 1819120256Sgshapiro if (LogLevel > 8) 1820120256Sgshapiro tlslogerr("server"); 182190792Sgshapiro goto tls_done; 182264562Sgshapiro } 182390792Sgshapiro 182490792Sgshapiro# if !TLS_VRFY_PER_CTX 182590792Sgshapiro /* 182690792Sgshapiro ** this could be used if it were possible to set 182790792Sgshapiro ** verification per SSL (connection) 182890792Sgshapiro ** not just per SSL_CTX (global) 182990792Sgshapiro */ 183090792Sgshapiro 183190792Sgshapiro TLS_VERIFY_CLIENT(); 183290792Sgshapiro# endif /* !TLS_VRFY_PER_CTX */ 183390792Sgshapiro 183490792Sgshapiro rfd = sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL); 183590792Sgshapiro wfd = sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL); 183690792Sgshapiro 183766494Sgshapiro if (rfd < 0 || wfd < 0 || 183866494Sgshapiro SSL_set_rfd(srv_ssl, rfd) <= 0 || 183966494Sgshapiro SSL_set_wfd(srv_ssl, wfd) <= 0) 184064562Sgshapiro { 184164562Sgshapiro message("454 4.3.3 TLS not available: error set fd"); 184264562Sgshapiro SSL_free(srv_ssl); 184364562Sgshapiro srv_ssl = NULL; 184490792Sgshapiro goto tls_done; 184564562Sgshapiro } 184690792Sgshapiro if (!smtps) 184790792Sgshapiro message("220 2.0.0 Ready to start TLS"); 184890792Sgshapiro# if PIPELINING 184990792Sgshapiro (void) sm_io_flush(OutChannel, SM_TIME_DEFAULT); 185090792Sgshapiro# endif /* PIPELINING */ 185190792Sgshapiro 185264562Sgshapiro SSL_set_accept_state(srv_ssl); 185364562Sgshapiro 185464562Sgshapiro# define SSL_ACC(s) SSL_accept(s) 185590792Sgshapiro 185690792Sgshapiro tlsstart = curtime(); 185790792Sgshapiro ssl_retry: 185864562Sgshapiro if ((r = SSL_ACC(srv_ssl)) <= 0) 185964562Sgshapiro { 1860157001Sgshapiro int i, ssl_err; 186164562Sgshapiro 1862157001Sgshapiro ssl_err = SSL_get_error(srv_ssl, r); 1863157001Sgshapiro i = tls_retry(srv_ssl, rfd, wfd, tlsstart, 1864157001Sgshapiro TimeOuts.to_starttls, ssl_err, 1865157001Sgshapiro "server"); 1866157001Sgshapiro if (i > 0) 1867157001Sgshapiro goto ssl_retry; 186890792Sgshapiro 186964562Sgshapiro if (LogLevel > 5) 187064562Sgshapiro { 187190792Sgshapiro sm_syslog(LOG_WARNING, NOQID, 1872157001Sgshapiro "STARTTLS=server, error: accept failed=%d, SSL_error=%d, errno=%d, retry=%d", 1873157001Sgshapiro r, ssl_err, errno, i); 187490792Sgshapiro if (LogLevel > 8) 187590792Sgshapiro tlslogerr("server"); 187664562Sgshapiro } 187790792Sgshapiro tls_ok_srv = false; 187864562Sgshapiro SSL_free(srv_ssl); 187964562Sgshapiro srv_ssl = NULL; 188064562Sgshapiro 188164562Sgshapiro /* 188264562Sgshapiro ** according to the next draft of 188364562Sgshapiro ** RFC 2487 the connection should be dropped 188464562Sgshapiro */ 188564562Sgshapiro 188664562Sgshapiro /* arrange to ignore any current send list */ 188764562Sgshapiro e->e_sendqueue = NULL; 188864562Sgshapiro goto doquit; 188964562Sgshapiro } 189064562Sgshapiro 189164562Sgshapiro /* ignore return code for now, it's in {verify} */ 189290792Sgshapiro (void) tls_get_info(srv_ssl, true, 189390792Sgshapiro CurSmtpClient, 189490792Sgshapiro &BlankEnvelope.e_macro, 189590792Sgshapiro bitset(SRV_VRFY_CLT, features)); 189664562Sgshapiro 189764562Sgshapiro /* 189864562Sgshapiro ** call Stls_client to find out whether 189964562Sgshapiro ** to accept the connection from the client 190064562Sgshapiro */ 190164562Sgshapiro 190264562Sgshapiro saveQuickAbort = QuickAbort; 190364562Sgshapiro saveSuprErrs = SuprErrs; 190490792Sgshapiro SuprErrs = true; 190590792Sgshapiro QuickAbort = false; 190664562Sgshapiro if (rscheck("tls_client", 190790792Sgshapiro macvalue(macid("{verify}"), e), 1908102528Sgshapiro "STARTTLS", e, 1909102528Sgshapiro RSF_RMCOMM|RSF_COUNT, 1910168515Sgshapiro 5, NULL, NOQID, NULL) != EX_OK || 191190792Sgshapiro Errors > 0) 191264562Sgshapiro { 191364562Sgshapiro extern char MsgBuf[]; 191464562Sgshapiro 191564562Sgshapiro if (MsgBuf[0] != '\0' && ISSMTPREPLY(MsgBuf)) 191664562Sgshapiro nullserver = newstr(MsgBuf); 191764562Sgshapiro else 191864562Sgshapiro nullserver = "503 5.7.0 Authentication required."; 191964562Sgshapiro } 192064562Sgshapiro QuickAbort = saveQuickAbort; 192164562Sgshapiro SuprErrs = saveSuprErrs; 192264562Sgshapiro 192390792Sgshapiro tls_ok_srv = false; /* don't offer STARTTLS again */ 192464562Sgshapiro n_helo = 0; 192590792Sgshapiro# if SASL 192664562Sgshapiro if (sasl_ok) 192764562Sgshapiro { 1928132943Sgshapiro int cipher_bits; 1929132943Sgshapiro bool verified; 1930132943Sgshapiro char *s, *v, *c; 193164562Sgshapiro 193290792Sgshapiro s = macvalue(macid("{cipher_bits}"), e); 1933132943Sgshapiro v = macvalue(macid("{verify}"), e); 1934132943Sgshapiro c = macvalue(macid("{cert_subject}"), e); 1935132943Sgshapiro verified = (v != NULL && strcmp(v, "OK") == 0); 1936132943Sgshapiro if (s != NULL && (cipher_bits = atoi(s)) > 0) 1937132943Sgshapiro { 193898121Sgshapiro# if SASL >= 20000 1939132943Sgshapiro ext_ssf = cipher_bits; 1940132943Sgshapiro auth_id = verified ? c : NULL; 1941132943Sgshapiro sasl_ok = ((sasl_setprop(conn, 1942132943Sgshapiro SASL_SSF_EXTERNAL, 1943132943Sgshapiro &ext_ssf) == SASL_OK) && 1944132943Sgshapiro (sasl_setprop(conn, 1945132943Sgshapiro SASL_AUTH_EXTERNAL, 1946132943Sgshapiro auth_id) == SASL_OK)); 194798121Sgshapiro# else /* SASL >= 20000 */ 1948132943Sgshapiro ext_ssf.ssf = cipher_bits; 1949132943Sgshapiro ext_ssf.auth_id = verified ? c : NULL; 1950132943Sgshapiro sasl_ok = sasl_setprop(conn, 1951132943Sgshapiro SASL_SSF_EXTERNAL, 1952132943Sgshapiro &ext_ssf) == SASL_OK; 195398121Sgshapiro# endif /* SASL >= 20000 */ 195464562Sgshapiro mechlist = NULL; 195564562Sgshapiro if (sasl_ok) 195664562Sgshapiro n_mechs = saslmechs(conn, 195764562Sgshapiro &mechlist); 195864562Sgshapiro } 195964562Sgshapiro } 196090792Sgshapiro# endif /* SASL */ 196164562Sgshapiro 196264562Sgshapiro /* switch to secure connection */ 196390792Sgshapiro if (sfdctls(&InChannel, &OutChannel, srv_ssl) == 0) 196490792Sgshapiro { 196590792Sgshapiro tls_active = true; 196690792Sgshapiro# if PIPELINING 196790792Sgshapiro (void) sm_io_autoflush(InChannel, OutChannel); 196890792Sgshapiro# endif /* PIPELINING */ 196990792Sgshapiro } 197064562Sgshapiro else 197164562Sgshapiro { 197264562Sgshapiro /* 197364562Sgshapiro ** XXX this is an internal error 197464562Sgshapiro ** how to deal with it? 197564562Sgshapiro ** we can't generate an error message 197664562Sgshapiro ** since the other side switched to an 197764562Sgshapiro ** encrypted layer, but we could not... 197864562Sgshapiro ** just "hang up"? 197964562Sgshapiro */ 198090792Sgshapiro 198164562Sgshapiro nullserver = "454 4.3.3 TLS not available: can't switch to encrypted layer"; 198290792Sgshapiro syserr("STARTTLS: can't switch to encrypted layer"); 198364562Sgshapiro } 198490792Sgshapiro tls_done: 198590792Sgshapiro if (smtps) 198690792Sgshapiro { 198790792Sgshapiro if (tls_active) 198890792Sgshapiro goto greeting; 198990792Sgshapiro else 199090792Sgshapiro goto doquit; 199190792Sgshapiro } 199264562Sgshapiro break; 199390792Sgshapiro#endif /* STARTTLS */ 199464562Sgshapiro 199538032Speter case CMDHELO: /* hello -- introduce yourself */ 199638032Speter case CMDEHLO: /* extended hello */ 199790792Sgshapiro DELAY_CONN("EHLO"); 199864562Sgshapiro if (c->cmd_code == CMDEHLO) 199938032Speter { 200038032Speter protocol = "ESMTP"; 200138032Speter SmtpPhase = "server EHLO"; 200238032Speter } 200338032Speter else 200438032Speter { 200538032Speter protocol = "SMTP"; 200638032Speter SmtpPhase = "server HELO"; 200738032Speter } 200838032Speter 200938032Speter /* avoid denial-of-service */ 2010132943Sgshapiro STOP_IF_ATTACK(checksmtpattack(&n_helo, MAXHELOCOMMANDS, 2011132943Sgshapiro true, "HELO/EHLO", e)); 201238032Speter 201390792Sgshapiro#if 0 201490792Sgshapiro /* RFC2821 4.1.4 allows duplicate HELO/EHLO */ 201538032Speter /* check for duplicate HELO/EHLO per RFC 1651 4.2 */ 201638032Speter if (gothello) 201738032Speter { 201838032Speter usrerr("503 %s Duplicate HELO/EHLO", 201973188Sgshapiro MyHostName); 202038032Speter break; 202138032Speter } 202290792Sgshapiro#endif /* 0 */ 202338032Speter 202438032Speter /* check for valid domain name (re 1123 5.2.5) */ 202538032Speter if (*p == '\0' && !AllowBogusHELO) 202638032Speter { 202738032Speter usrerr("501 %s requires domain address", 202838032Speter cmdbuf); 202938032Speter break; 203038032Speter } 203138032Speter 203238032Speter /* check for long domain name (hides Received: info) */ 203338032Speter if (strlen(p) > MAXNAME) 203438032Speter { 203538032Speter usrerr("501 Invalid domain name"); 203664562Sgshapiro if (LogLevel > 9) 203764562Sgshapiro sm_syslog(LOG_INFO, CurEnv->e_id, 2038110560Sgshapiro "invalid domain name (too long) from %s", 203964562Sgshapiro CurSmtpClient); 204038032Speter break; 204138032Speter } 204238032Speter 204398121Sgshapiro ok = true; 204438032Speter for (q = p; *q != '\0'; q++) 204538032Speter { 204638032Speter if (!isascii(*q)) 204738032Speter break; 204838032Speter if (isalnum(*q)) 204938032Speter continue; 205038032Speter if (isspace(*q)) 205138032Speter { 205238032Speter *q = '\0'; 205398121Sgshapiro 205498121Sgshapiro /* only complain if strict check */ 205598121Sgshapiro ok = AllowBogusHELO; 2056141858Sgshapiro 2057141858Sgshapiro /* allow trailing whitespace */ 2058141858Sgshapiro while (!ok && *++q != '\0' && 2059141858Sgshapiro isspace(*q)) 2060141858Sgshapiro ; 2061141858Sgshapiro if (*q == '\0') 2062141858Sgshapiro ok = true; 206338032Speter break; 206438032Speter } 2065120256Sgshapiro if (strchr("[].-_#:", *q) == NULL) 206638032Speter break; 206738032Speter } 206864562Sgshapiro 206998121Sgshapiro if (*q == '\0' && ok) 207038032Speter { 207138032Speter q = "pleased to meet you"; 207290792Sgshapiro sendinghost = sm_strdup_x(p); 207338032Speter } 207438032Speter else if (!AllowBogusHELO) 207538032Speter { 207638032Speter usrerr("501 Invalid domain name"); 207764562Sgshapiro if (LogLevel > 9) 207864562Sgshapiro sm_syslog(LOG_INFO, CurEnv->e_id, 2079110560Sgshapiro "invalid domain name (%s) from %.100s", 208064562Sgshapiro p, CurSmtpClient); 208138032Speter break; 208238032Speter } 208338032Speter else 208438032Speter { 208538032Speter q = "accepting invalid domain name"; 208638032Speter } 208738032Speter 2088157001Sgshapiro if (gothello || smtp.sm_gotmail) 208990792Sgshapiro CLEAR_STATE(cmdbuf); 209090792Sgshapiro 209190792Sgshapiro#if MILTER 209290792Sgshapiro if (smtp.sm_milterlist && smtp.sm_milterize && 209390792Sgshapiro !bitset(EF_DISCARD, e->e_flags)) 209464562Sgshapiro { 209564562Sgshapiro char state; 209664562Sgshapiro char *response; 209764562Sgshapiro 209864562Sgshapiro response = milter_helo(p, e, &state); 209964562Sgshapiro switch (state) 210064562Sgshapiro { 210164562Sgshapiro case SMFIR_REJECT: 210290792Sgshapiro if (MilterLogLevel > 3) 210390792Sgshapiro sm_syslog(LOG_INFO, e->e_id, 210490792Sgshapiro "Milter: helo=%s, reject=Command rejected", 210590792Sgshapiro p); 210664562Sgshapiro nullserver = "Command rejected"; 210790792Sgshapiro smtp.sm_milterize = false; 210864562Sgshapiro break; 210964562Sgshapiro 211064562Sgshapiro case SMFIR_TEMPFAIL: 211190792Sgshapiro if (MilterLogLevel > 3) 211290792Sgshapiro sm_syslog(LOG_INFO, e->e_id, 211390792Sgshapiro "Milter: helo=%s, reject=%s", 211490792Sgshapiro p, MSG_TEMPFAIL); 211590792Sgshapiro tempfail = true; 211690792Sgshapiro smtp.sm_milterize = false; 211764562Sgshapiro break; 2118157001Sgshapiro 2119168515Sgshapiro case SMFIR_REPLYCODE: 2120157001Sgshapiro if (MilterLogLevel > 3) 2121157001Sgshapiro sm_syslog(LOG_INFO, e->e_id, 2122168515Sgshapiro "Milter: helo=%s, reject=%s", 2123168515Sgshapiro p, response); 2124168515Sgshapiro if (strncmp(response, "421 ", 4) != 0 2125168515Sgshapiro && strncmp(response, "421-", 4) != 0) 2126168515Sgshapiro { 2127168515Sgshapiro nullserver = newstr(response); 2128168515Sgshapiro smtp.sm_milterize = false; 2129168515Sgshapiro break; 2130168515Sgshapiro } 2131168515Sgshapiro /* FALLTHROUGH */ 2132168515Sgshapiro 2133168515Sgshapiro case SMFIR_SHUTDOWN: 2134168515Sgshapiro if (MilterLogLevel > 3 && 2135168515Sgshapiro response == NULL) 2136168515Sgshapiro sm_syslog(LOG_INFO, e->e_id, 2137159609Sgshapiro "Milter: helo=%s, reject=421 4.7.0 %s closing connection", 2138157001Sgshapiro p, MyHostName); 2139157001Sgshapiro tempfail = true; 2140157001Sgshapiro smtp.sm_milterize = false; 2141168515Sgshapiro if (response != NULL) 2142168515Sgshapiro usrerr(response); 2143168515Sgshapiro else 2144168515Sgshapiro message("421 4.7.0 %s closing connection", 2145168515Sgshapiro MyHostName); 2146157001Sgshapiro /* arrange to ignore send list */ 2147157001Sgshapiro e->e_sendqueue = NULL; 2148168515Sgshapiro lognullconnection = false; 2149157001Sgshapiro goto doquit; 215064562Sgshapiro } 215190792Sgshapiro if (response != NULL) 215290792Sgshapiro sm_free(response); 215390792Sgshapiro 215490792Sgshapiro /* 215590792Sgshapiro ** If quarantining by a connect/ehlo action, 215690792Sgshapiro ** save between messages 215790792Sgshapiro */ 215890792Sgshapiro 215990792Sgshapiro if (smtp.sm_quarmsg == NULL && 216090792Sgshapiro e->e_quarmsg != NULL) 216190792Sgshapiro smtp.sm_quarmsg = newstr(e->e_quarmsg); 216264562Sgshapiro } 216390792Sgshapiro#endif /* MILTER */ 216490792Sgshapiro gothello = true; 216564562Sgshapiro 216638032Speter /* print HELO response message */ 216764562Sgshapiro if (c->cmd_code != CMDEHLO) 216838032Speter { 216938032Speter message("250 %s Hello %s, %s", 217038032Speter MyHostName, CurSmtpClient, q); 217138032Speter break; 217238032Speter } 217338032Speter 217438032Speter message("250-%s Hello %s, %s", 217538032Speter MyHostName, CurSmtpClient, q); 217638032Speter 217764562Sgshapiro /* offer ENHSC even for nullserver */ 217864562Sgshapiro if (nullserver != NULL) 217964562Sgshapiro { 218064562Sgshapiro message("250 ENHANCEDSTATUSCODES"); 218164562Sgshapiro break; 218264562Sgshapiro } 218364562Sgshapiro 218466494Sgshapiro /* 218566494Sgshapiro ** print EHLO features list 218666494Sgshapiro ** 218766494Sgshapiro ** Note: If you change this list, 218890792Sgshapiro ** remember to update 'helpfile' 218966494Sgshapiro */ 219066494Sgshapiro 219164562Sgshapiro message("250-ENHANCEDSTATUSCODES"); 219290792Sgshapiro#if PIPELINING 219390792Sgshapiro if (bitset(SRV_OFFER_PIPE, features)) 219490792Sgshapiro message("250-PIPELINING"); 219590792Sgshapiro#endif /* PIPELINING */ 219690792Sgshapiro if (bitset(SRV_OFFER_EXPN, features)) 219738032Speter { 219838032Speter message("250-EXPN"); 219990792Sgshapiro if (bitset(SRV_OFFER_VERB, features)) 220038032Speter message("250-VERB"); 220138032Speter } 220290792Sgshapiro#if MIME8TO7 220338032Speter message("250-8BITMIME"); 220490792Sgshapiro#endif /* MIME8TO7 */ 220538032Speter if (MaxMessageSize > 0) 220638032Speter message("250-SIZE %ld", MaxMessageSize); 220738032Speter else 220838032Speter message("250-SIZE"); 220990792Sgshapiro#if DSN 221090792Sgshapiro if (SendMIMEErrors && bitset(SRV_OFFER_DSN, features)) 221138032Speter message("250-DSN"); 221290792Sgshapiro#endif /* DSN */ 221390792Sgshapiro if (bitset(SRV_OFFER_ETRN, features)) 221438032Speter message("250-ETRN"); 221590792Sgshapiro#if SASL 221664562Sgshapiro if (sasl_ok && mechlist != NULL && *mechlist != '\0') 221764562Sgshapiro message("250-AUTH %s", mechlist); 221890792Sgshapiro#endif /* SASL */ 221990792Sgshapiro#if STARTTLS 222098841Sgshapiro if (tls_ok_srv && 222198841Sgshapiro bitset(SRV_OFFER_TLS, features)) 222264562Sgshapiro message("250-STARTTLS"); 222390792Sgshapiro#endif /* STARTTLS */ 222490792Sgshapiro if (DeliverByMin > 0) 222590792Sgshapiro message("250-DELIVERBY %ld", 222690792Sgshapiro (long) DeliverByMin); 222790792Sgshapiro else if (DeliverByMin == 0) 222890792Sgshapiro message("250-DELIVERBY"); 222990792Sgshapiro 223090792Sgshapiro /* < 0: no deliver-by */ 223190792Sgshapiro 223238032Speter message("250 HELP"); 223338032Speter break; 223438032Speter 223538032Speter case CMDMAIL: /* mail -- designate sender */ 223638032Speter SmtpPhase = "server MAIL"; 223790792Sgshapiro DELAY_CONN("MAIL"); 223838032Speter 223938032Speter /* check for validity of this command */ 224038032Speter if (!gothello && bitset(PRIV_NEEDMAILHELO, PrivacyFlags)) 224138032Speter { 224264562Sgshapiro usrerr("503 5.0.0 Polite people say HELO first"); 224338032Speter break; 224438032Speter } 224590792Sgshapiro if (smtp.sm_gotmail) 224638032Speter { 224764562Sgshapiro usrerr("503 5.5.0 Sender already specified"); 224838032Speter break; 224938032Speter } 225090792Sgshapiro#if SASL 225190792Sgshapiro if (bitset(SRV_REQ_AUTH, features) && 225264562Sgshapiro authenticating != SASL_IS_AUTH) 225364562Sgshapiro { 225464562Sgshapiro usrerr("530 5.7.0 Authentication required"); 225564562Sgshapiro break; 225664562Sgshapiro } 225790792Sgshapiro#endif /* SASL */ 225838032Speter 225964562Sgshapiro p = skipword(p, "from"); 226064562Sgshapiro if (p == NULL) 226164562Sgshapiro break; 226264562Sgshapiro if (tempfail) 226364562Sgshapiro { 226464562Sgshapiro if (LogLevel > 9) 226564562Sgshapiro sm_syslog(LOG_INFO, e->e_id, 2266110560Sgshapiro "SMTP MAIL command (%.100s) from %s tempfailed (due to previous checks)", 226764562Sgshapiro p, CurSmtpClient); 226890792Sgshapiro usrerr(MSG_TEMPFAIL); 226964562Sgshapiro break; 227064562Sgshapiro } 227164562Sgshapiro 227238032Speter /* make sure we know who the sending host is */ 227338032Speter if (sendinghost == NULL) 227438032Speter sendinghost = peerhostname; 227538032Speter 227638032Speter 227790792Sgshapiro#if SM_HEAP_CHECK 227890792Sgshapiro if (sm_debug_active(&DebugLeakSmtp, 1)) 227990792Sgshapiro { 228090792Sgshapiro sm_heap_newgroup(); 228190792Sgshapiro sm_dprintf("smtp() heap group #%d\n", 228290792Sgshapiro sm_heap_group()); 228390792Sgshapiro } 228490792Sgshapiro#endif /* SM_HEAP_CHECK */ 228564562Sgshapiro 228638032Speter if (Errors > 0) 228790792Sgshapiro goto undo_no_pm; 228838032Speter if (!gothello) 228938032Speter { 229090792Sgshapiro auth_warning(e, "%s didn't use HELO protocol", 229190792Sgshapiro CurSmtpClient); 229238032Speter } 229390792Sgshapiro#ifdef PICKY_HELO_CHECK 229490792Sgshapiro if (sm_strcasecmp(sendinghost, peerhostname) != 0 && 229590792Sgshapiro (sm_strcasecmp(peerhostname, "localhost") != 0 || 229690792Sgshapiro sm_strcasecmp(sendinghost, MyHostName) != 0)) 229738032Speter { 229838032Speter auth_warning(e, "Host %s claimed to be %s", 229990792Sgshapiro CurSmtpClient, sendinghost); 230038032Speter } 230190792Sgshapiro#endif /* PICKY_HELO_CHECK */ 230238032Speter 230338032Speter if (protocol == NULL) 230438032Speter protocol = "SMTP"; 230590792Sgshapiro macdefine(&e->e_macro, A_PERM, 'r', protocol); 230690792Sgshapiro macdefine(&e->e_macro, A_PERM, 's', sendinghost); 230764562Sgshapiro 230838032Speter if (Errors > 0) 230990792Sgshapiro goto undo_no_pm; 231090792Sgshapiro smtp.sm_nrcpts = 0; 231190792Sgshapiro n_badrcpts = 0; 231290792Sgshapiro macdefine(&e->e_macro, A_PERM, macid("{ntries}"), "0"); 231390792Sgshapiro macdefine(&e->e_macro, A_PERM, macid("{nrcpts}"), "0"); 2314132943Sgshapiro macdefine(&e->e_macro, A_PERM, macid("{nbadrcpts}"), 2315132943Sgshapiro "0"); 231664562Sgshapiro e->e_flags |= EF_CLRQUEUE; 231790792Sgshapiro sm_setproctitle(true, e, "%s %s: %.80s", 231864562Sgshapiro qid_printname(e), 231964562Sgshapiro CurSmtpClient, inp); 232038032Speter 232190792Sgshapiro /* do the processing */ 232290792Sgshapiro SM_TRY 232390792Sgshapiro { 232494334Sgshapiro extern char *FullName; 232594334Sgshapiro 232690792Sgshapiro QuickAbort = true; 232794334Sgshapiro SM_FREE_CLR(FullName); 232864562Sgshapiro 232938032Speter /* must parse sender first */ 233038032Speter delimptr = NULL; 233190792Sgshapiro setsender(p, e, &delimptr, ' ', false); 233238032Speter if (delimptr != NULL && *delimptr != '\0') 233338032Speter *delimptr++ = '\0'; 233438032Speter if (Errors > 0) 233590792Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1); 233638032Speter 233764562Sgshapiro /* Successfully set e_from, allow logging */ 233864562Sgshapiro e->e_flags |= EF_LOGSENDER; 233938032Speter 234064562Sgshapiro /* put resulting triple from parseaddr() into macros */ 234164562Sgshapiro if (e->e_from.q_mailer != NULL) 234290792Sgshapiro macdefine(&e->e_macro, A_PERM, 234390792Sgshapiro macid("{mail_mailer}"), 234490792Sgshapiro e->e_from.q_mailer->m_name); 234564562Sgshapiro else 234690792Sgshapiro macdefine(&e->e_macro, A_PERM, 234790792Sgshapiro macid("{mail_mailer}"), NULL); 234864562Sgshapiro if (e->e_from.q_host != NULL) 234990792Sgshapiro macdefine(&e->e_macro, A_PERM, 235090792Sgshapiro macid("{mail_host}"), 235190792Sgshapiro e->e_from.q_host); 235264562Sgshapiro else 235390792Sgshapiro macdefine(&e->e_macro, A_PERM, 235490792Sgshapiro macid("{mail_host}"), "localhost"); 235564562Sgshapiro if (e->e_from.q_user != NULL) 235690792Sgshapiro macdefine(&e->e_macro, A_PERM, 235790792Sgshapiro macid("{mail_addr}"), 235890792Sgshapiro e->e_from.q_user); 235964562Sgshapiro else 236090792Sgshapiro macdefine(&e->e_macro, A_PERM, 236190792Sgshapiro macid("{mail_addr}"), NULL); 236264562Sgshapiro if (Errors > 0) 236390792Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1); 236464562Sgshapiro 236538032Speter /* check for possible spoofing */ 236638032Speter if (RealUid != 0 && OpMode == MD_SMTP && 236738032Speter !wordinclass(RealUserName, 't') && 236864562Sgshapiro (!bitnset(M_LOCALMAILER, 236964562Sgshapiro e->e_from.q_mailer->m_flags) || 237064562Sgshapiro strcmp(e->e_from.q_user, RealUserName) != 0)) 237138032Speter { 237238032Speter auth_warning(e, "%s owned process doing -bs", 237338032Speter RealUserName); 237438032Speter } 237538032Speter 2376120256Sgshapiro /* reset to default value */ 2377168515Sgshapiro SevenBitInput = SevenBitInput_Saved; 2378120256Sgshapiro 237938032Speter /* now parse ESMTP arguments */ 238038032Speter e->e_msgsize = 0; 238164562Sgshapiro addr = p; 2382168515Sgshapiro parse_esmtp_args(e, NULL, p, delimptr, "MAIL", args, 2383168515Sgshapiro mail_esmtp_args); 238438032Speter if (Errors > 0) 238590792Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1); 238638032Speter 238790792Sgshapiro#if SASL 238890792Sgshapiro# if _FFR_AUTH_PASSING 238990792Sgshapiro /* set the default AUTH= if the sender didn't */ 239090792Sgshapiro if (e->e_auth_param == NULL) 239190792Sgshapiro { 239290792Sgshapiro /* XXX only do this for an MSA? */ 239390792Sgshapiro e->e_auth_param = macvalue(macid("{auth_authen}"), 239490792Sgshapiro e); 239590792Sgshapiro if (e->e_auth_param == NULL) 239690792Sgshapiro e->e_auth_param = "<>"; 239790792Sgshapiro 239890792Sgshapiro /* 239990792Sgshapiro ** XXX should we invoke Strust_auth now? 240090792Sgshapiro ** authorizing as the client that just 240190792Sgshapiro ** authenticated, so we'll trust implicitly 240290792Sgshapiro */ 240390792Sgshapiro } 240490792Sgshapiro# endif /* _FFR_AUTH_PASSING */ 240590792Sgshapiro#endif /* SASL */ 240690792Sgshapiro 240764562Sgshapiro /* do config file checking of the sender */ 240890792Sgshapiro macdefine(&e->e_macro, A_PERM, 240990792Sgshapiro macid("{addr_type}"), "e s"); 241090792Sgshapiro#if _FFR_MAIL_MACRO 241190792Sgshapiro /* make the "real" sender address available */ 241290792Sgshapiro macdefine(&e->e_macro, A_TEMP, macid("{mail_from}"), 241390792Sgshapiro e->e_from.q_paddr); 241490792Sgshapiro#endif /* _FFR_MAIL_MACRO */ 241564562Sgshapiro if (rscheck("check_mail", addr, 2416102528Sgshapiro NULL, e, RSF_RMCOMM|RSF_COUNT, 3, 2417168515Sgshapiro NULL, e->e_id, NULL) != EX_OK || 241864562Sgshapiro Errors > 0) 241990792Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1); 242090792Sgshapiro macdefine(&e->e_macro, A_PERM, 242190792Sgshapiro macid("{addr_type}"), NULL); 242264562Sgshapiro 242366494Sgshapiro if (MaxMessageSize > 0 && 242477349Sgshapiro (e->e_msgsize > MaxMessageSize || 242577349Sgshapiro e->e_msgsize < 0)) 242638032Speter { 242764562Sgshapiro usrerr("552 5.2.3 Message size exceeds fixed maximum message size (%ld)", 242838032Speter MaxMessageSize); 242990792Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1); 243038032Speter } 243164562Sgshapiro 243290792Sgshapiro /* 243390792Sgshapiro ** XXX always check whether there is at least one fs 243490792Sgshapiro ** with enough space? 243590792Sgshapiro ** However, this may not help much: the queue group 243690792Sgshapiro ** selection may later on select a FS that hasn't 243790792Sgshapiro ** enough space. 243890792Sgshapiro */ 243990792Sgshapiro 244090792Sgshapiro if ((NumFileSys == 1 || NumQueue == 1) && 244190792Sgshapiro !enoughdiskspace(e->e_msgsize, e) 244290792Sgshapiro#if _FFR_ANY_FREE_FS 244390792Sgshapiro && !filesys_free(e->e_msgsize) 244490792Sgshapiro#endif /* _FFR_ANY_FREE_FS */ 244590792Sgshapiro ) 244638032Speter { 244790792Sgshapiro /* 244890792Sgshapiro ** We perform this test again when the 244990792Sgshapiro ** queue directory is selected, in collect. 245090792Sgshapiro */ 245190792Sgshapiro 245264562Sgshapiro usrerr("452 4.4.5 Insufficient disk space; try again later"); 245390792Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1); 245438032Speter } 245538032Speter if (Errors > 0) 245690792Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1); 245764562Sgshapiro 245890792Sgshapiro LogUsrErrs = true; 245990792Sgshapiro#if MILTER 246090792Sgshapiro if (smtp.sm_milterlist && smtp.sm_milterize && 246190792Sgshapiro !bitset(EF_DISCARD, e->e_flags)) 246264562Sgshapiro { 246364562Sgshapiro char state; 246464562Sgshapiro char *response; 246564562Sgshapiro 246664562Sgshapiro response = milter_envfrom(args, e, &state); 246790792Sgshapiro MILTER_REPLY("from"); 246864562Sgshapiro } 246990792Sgshapiro#endif /* MILTER */ 247064562Sgshapiro if (Errors > 0) 247190792Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1); 247264562Sgshapiro 247364562Sgshapiro message("250 2.1.0 Sender ok"); 247490792Sgshapiro smtp.sm_gotmail = true; 247590792Sgshapiro } 247690792Sgshapiro SM_EXCEPT(exc, "[!F]*") 247790792Sgshapiro { 247890792Sgshapiro /* 247990792Sgshapiro ** An error occurred while processing a MAIL command. 248090792Sgshapiro ** Jump to the common error handling code. 248190792Sgshapiro */ 248290792Sgshapiro 248390792Sgshapiro sm_exc_free(exc); 248490792Sgshapiro goto undo_no_pm; 248590792Sgshapiro } 248690792Sgshapiro SM_END_TRY 248738032Speter break; 248838032Speter 248990792Sgshapiro undo_no_pm: 249090792Sgshapiro e->e_flags &= ~EF_PM_NOTIFY; 249190792Sgshapiro undo: 249290792Sgshapiro break; 249390792Sgshapiro 249438032Speter case CMDRCPT: /* rcpt -- designate recipient */ 249590792Sgshapiro DELAY_CONN("RCPT"); 2496168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2497168515Sgshapiro macid("{rcpt_mailer}"), NULL); 2498168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2499168515Sgshapiro macid("{rcpt_host}"), NULL); 2500168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2501168515Sgshapiro macid("{rcpt_addr}"), NULL); 2502168515Sgshapiro#if MILTER 2503168515Sgshapiro (void) memset(&addr_st, '\0', sizeof(addr_st)); 2504168515Sgshapiro a = NULL; 2505168515Sgshapiro milter_rcpt_added = false; 2506168515Sgshapiro#endif 2507125820Sgshapiro if (BadRcptThrottle > 0 && 2508125820Sgshapiro n_badrcpts >= BadRcptThrottle) 2509125820Sgshapiro { 2510125820Sgshapiro if (LogLevel > 5 && 2511125820Sgshapiro n_badrcpts == BadRcptThrottle) 2512125820Sgshapiro { 2513125820Sgshapiro sm_syslog(LOG_INFO, e->e_id, 2514125820Sgshapiro "%s: Possible SMTP RCPT flood, throttling.", 2515125820Sgshapiro CurSmtpClient); 2516125820Sgshapiro 2517125820Sgshapiro /* To avoid duplicated message */ 2518125820Sgshapiro n_badrcpts++; 2519125820Sgshapiro } 2520132943Sgshapiro NBADRCPTS; 2521125820Sgshapiro 2522125820Sgshapiro /* 2523125820Sgshapiro ** Don't use exponential backoff for now. 2524125820Sgshapiro ** Some servers will open more connections 2525125820Sgshapiro ** and actually overload the receiver even 2526125820Sgshapiro ** more. 2527125820Sgshapiro */ 2528125820Sgshapiro 2529125820Sgshapiro (void) sleep(1); 2530125820Sgshapiro } 253190792Sgshapiro if (!smtp.sm_gotmail) 253238032Speter { 253364562Sgshapiro usrerr("503 5.0.0 Need MAIL before RCPT"); 253438032Speter break; 253538032Speter } 253638032Speter SmtpPhase = "server RCPT"; 253790792Sgshapiro SM_TRY 253890792Sgshapiro { 253990792Sgshapiro QuickAbort = true; 254090792Sgshapiro LogUsrErrs = true; 254138032Speter 254238032Speter /* limit flooding of our machine */ 254390792Sgshapiro if (MaxRcptPerMsg > 0 && 254490792Sgshapiro smtp.sm_nrcpts >= MaxRcptPerMsg) 254538032Speter { 254690792Sgshapiro /* sleep(1); / * slow down? */ 254764562Sgshapiro usrerr("452 4.5.3 Too many recipients"); 254890792Sgshapiro goto rcpt_done; 254938032Speter } 255038032Speter 2551157001Sgshapiro if (e->e_sendmode != SM_DELIVER 2552157001Sgshapiro#if _FFR_DM_ONE 2553157001Sgshapiro && (NotFirstDelivery || SM_DM_ONE != e->e_sendmode) 2554157001Sgshapiro#endif /* _FFR_DM_ONE */ 2555157001Sgshapiro ) 255638032Speter e->e_flags |= EF_VRFYONLY; 255738032Speter 255890792Sgshapiro#if MILTER 255964562Sgshapiro /* 2560168515Sgshapiro ** Do not expand recipients at RCPT time (in the call 256164562Sgshapiro ** to recipient()). If they are expanded, it 256264562Sgshapiro ** is impossible for removefromlist() to figure 256364562Sgshapiro ** out the expanded members of the original 256464562Sgshapiro ** recipient and mark them as QS_DONTSEND. 256564562Sgshapiro */ 256664562Sgshapiro 2567168515Sgshapiro e->e_flags |= EF_VRFYONLY; 2568168515Sgshapiro milter_cmd_done = false; 2569168515Sgshapiro milter_cmd_safe = false; 257090792Sgshapiro#endif /* MILTER */ 257164562Sgshapiro 257238032Speter p = skipword(p, "to"); 257338032Speter if (p == NULL) 257490792Sgshapiro goto rcpt_done; 257590792Sgshapiro macdefine(&e->e_macro, A_PERM, 257690792Sgshapiro macid("{addr_type}"), "e r"); 257790792Sgshapiro a = parseaddr(p, NULLADDR, RF_COPYALL, ' ', &delimptr, 257890792Sgshapiro e, true); 257990792Sgshapiro macdefine(&e->e_macro, A_PERM, 258090792Sgshapiro macid("{addr_type}"), NULL); 258142575Speter if (Errors > 0) 258290792Sgshapiro goto rcpt_done; 258342575Speter if (a == NULL) 258442575Speter { 258564562Sgshapiro usrerr("501 5.0.0 Missing recipient"); 258690792Sgshapiro goto rcpt_done; 258742575Speter } 258842575Speter 258938032Speter if (delimptr != NULL && *delimptr != '\0') 259038032Speter *delimptr++ = '\0'; 259138032Speter 259264562Sgshapiro /* put resulting triple from parseaddr() into macros */ 259364562Sgshapiro if (a->q_mailer != NULL) 259490792Sgshapiro macdefine(&e->e_macro, A_PERM, 259590792Sgshapiro macid("{rcpt_mailer}"), 259690792Sgshapiro a->q_mailer->m_name); 259764562Sgshapiro else 259890792Sgshapiro macdefine(&e->e_macro, A_PERM, 259990792Sgshapiro macid("{rcpt_mailer}"), NULL); 260064562Sgshapiro if (a->q_host != NULL) 260190792Sgshapiro macdefine(&e->e_macro, A_PERM, 260290792Sgshapiro macid("{rcpt_host}"), a->q_host); 260364562Sgshapiro else 260490792Sgshapiro macdefine(&e->e_macro, A_PERM, 260590792Sgshapiro macid("{rcpt_host}"), "localhost"); 260664562Sgshapiro if (a->q_user != NULL) 260790792Sgshapiro macdefine(&e->e_macro, A_PERM, 260890792Sgshapiro macid("{rcpt_addr}"), a->q_user); 260964562Sgshapiro else 261090792Sgshapiro macdefine(&e->e_macro, A_PERM, 261190792Sgshapiro macid("{rcpt_addr}"), NULL); 261264562Sgshapiro if (Errors > 0) 261390792Sgshapiro goto rcpt_done; 261438032Speter 261538032Speter /* now parse ESMTP arguments */ 261664562Sgshapiro addr = p; 2617168515Sgshapiro parse_esmtp_args(e, a, p, delimptr, "RCPT", args, 2618168515Sgshapiro rcpt_esmtp_args); 261938032Speter if (Errors > 0) 262090792Sgshapiro goto rcpt_done; 262138032Speter 2622168515Sgshapiro#if MILTER 2623168515Sgshapiro /* 2624168515Sgshapiro ** rscheck() can trigger an "exception" 2625168515Sgshapiro ** in which case the execution continues at 2626168515Sgshapiro ** SM_EXCEPT(exc, "[!F]*") 2627168515Sgshapiro ** This means milter_cmd_safe is not set 2628168515Sgshapiro ** and hence milter is not invoked. 2629168515Sgshapiro ** Would it be "safe" to change that, i.e., use 2630168515Sgshapiro ** milter_cmd_safe = true; 2631168515Sgshapiro ** here so a milter is informed (if requested) 2632168515Sgshapiro ** about RCPTs that are rejected by check_rcpt? 2633168515Sgshapiro */ 2634168515Sgshapiro# if _FFR_MILTER_CHECK_REJECTIONS_TOO 2635168515Sgshapiro milter_cmd_safe = true; 2636168515Sgshapiro# endif 2637168515Sgshapiro#endif 2638168515Sgshapiro 263964562Sgshapiro /* do config file checking of the recipient */ 264090792Sgshapiro macdefine(&e->e_macro, A_PERM, 264190792Sgshapiro macid("{addr_type}"), "e r"); 264264562Sgshapiro if (rscheck("check_rcpt", addr, 2643102528Sgshapiro NULL, e, RSF_RMCOMM|RSF_COUNT, 3, 2644168515Sgshapiro NULL, e->e_id, p_addr_st) != EX_OK || 264564562Sgshapiro Errors > 0) 264690792Sgshapiro goto rcpt_done; 264790792Sgshapiro macdefine(&e->e_macro, A_PERM, 264890792Sgshapiro macid("{addr_type}"), NULL); 264964562Sgshapiro 2650102528Sgshapiro /* If discarding, don't bother to verify user */ 2651102528Sgshapiro if (bitset(EF_DISCARD, e->e_flags)) 2652102528Sgshapiro a->q_state = QS_VERIFIED; 2653168515Sgshapiro#if MILTER 2654168515Sgshapiro milter_cmd_safe = true; 2655168515Sgshapiro#endif 2656102528Sgshapiro 2657168515Sgshapiro /* save in recipient list after ESMTP mods */ 2658168515Sgshapiro a = recipient(a, &e->e_sendqueue, 0, e); 2659168515Sgshapiro /* may trigger exception... */ 2660168515Sgshapiro 266190792Sgshapiro#if MILTER 2662168515Sgshapiro milter_rcpt_added = true; 2663168515Sgshapiro#endif 2664168515Sgshapiro 2665168515Sgshapiro if(!(Errors > 0) && QS_IS_BADADDR(a->q_state)) 2666168515Sgshapiro { 2667168515Sgshapiro /* punt -- should keep message in ADDRESS.... */ 2668168515Sgshapiro usrerr("550 5.1.1 Addressee unknown"); 2669168515Sgshapiro } 2670168515Sgshapiro 2671168515Sgshapiro#if MILTER 2672168515Sgshapiro rcpt_done: 267390792Sgshapiro if (smtp.sm_milterlist && smtp.sm_milterize && 267490792Sgshapiro !bitset(EF_DISCARD, e->e_flags)) 267564562Sgshapiro { 267664562Sgshapiro char state; 267764562Sgshapiro char *response; 267864562Sgshapiro 2679168515Sgshapiro /* how to get the error codes? */ 2680168515Sgshapiro if (Errors > 0) 2681168515Sgshapiro { 2682168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2683168515Sgshapiro macid("{rcpt_mailer}"), 2684168515Sgshapiro "error"); 2685168515Sgshapiro if (a != NULL && 2686168515Sgshapiro a->q_status != NULL && 2687168515Sgshapiro a->q_rstatus != NULL) 2688168515Sgshapiro { 2689168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2690168515Sgshapiro macid("{rcpt_host}"), 2691168515Sgshapiro a->q_status); 2692168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2693168515Sgshapiro macid("{rcpt_addr}"), 2694168515Sgshapiro a->q_rstatus); 2695168515Sgshapiro } 2696168515Sgshapiro else 2697168515Sgshapiro { 2698168515Sgshapiro if (addr_st.q_host != NULL) 2699168515Sgshapiro macdefine(&e->e_macro, 2700168515Sgshapiro A_PERM, 2701168515Sgshapiro macid("{rcpt_host}"), 2702168515Sgshapiro addr_st.q_host); 2703168515Sgshapiro if (addr_st.q_user != NULL) 2704168515Sgshapiro macdefine(&e->e_macro, 2705168515Sgshapiro A_PERM, 2706168515Sgshapiro macid("{rcpt_addr}"), 2707168515Sgshapiro addr_st.q_user); 2708168515Sgshapiro } 2709168515Sgshapiro } 2710168515Sgshapiro 2711168515Sgshapiro response = milter_envrcpt(args, e, &state, 2712168515Sgshapiro Errors > 0); 2713168515Sgshapiro milter_cmd_done = true; 271490792Sgshapiro MILTER_REPLY("to"); 271564562Sgshapiro } 271690792Sgshapiro#endif /* MILTER */ 271764562Sgshapiro 271838032Speter /* no errors during parsing, but might be a duplicate */ 271938032Speter e->e_to = a->q_paddr; 2720168515Sgshapiro if (!(Errors > 0) && !QS_IS_BADADDR(a->q_state)) 272138032Speter { 272290792Sgshapiro if (smtp.sm_nrcpts == 0) 272364562Sgshapiro initsys(e); 272464562Sgshapiro message("250 2.1.5 Recipient ok%s", 272564562Sgshapiro QS_IS_QUEUEUP(a->q_state) ? 272638032Speter " (will queue)" : ""); 272790792Sgshapiro smtp.sm_nrcpts++; 272838032Speter } 2729168515Sgshapiro 2730168515Sgshapiro /* Is this needed? */ 2731168515Sgshapiro#if !MILTER 2732168515Sgshapiro rcpt_done: 2733168515Sgshapiro#endif /* !MILTER */ 2734168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2735168515Sgshapiro macid("{rcpt_mailer}"), NULL); 2736168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2737168515Sgshapiro macid("{rcpt_host}"), NULL); 2738168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2739168515Sgshapiro macid("{rcpt_addr}"), NULL); 2740168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2741168515Sgshapiro macid("{dsn_notify}"), NULL); 2742168515Sgshapiro 274390792Sgshapiro if (Errors > 0) 2744132943Sgshapiro { 274590792Sgshapiro ++n_badrcpts; 2746132943Sgshapiro NBADRCPTS; 2747132943Sgshapiro } 274890792Sgshapiro } 274990792Sgshapiro SM_EXCEPT(exc, "[!F]*") 275090792Sgshapiro { 275190792Sgshapiro /* An exception occurred while processing RCPT */ 275290792Sgshapiro e->e_flags &= ~(EF_FATALERRS|EF_PM_NOTIFY); 275390792Sgshapiro ++n_badrcpts; 2754132943Sgshapiro NBADRCPTS; 2755168515Sgshapiro#if MILTER 2756168515Sgshapiro if (smtp.sm_milterlist && smtp.sm_milterize && 2757168515Sgshapiro !bitset(EF_DISCARD, e->e_flags) && 2758168515Sgshapiro !milter_cmd_done && milter_cmd_safe) 2759168515Sgshapiro { 2760168515Sgshapiro char state; 2761168515Sgshapiro char *response; 2762168515Sgshapiro 2763168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2764168515Sgshapiro macid("{rcpt_mailer}"), "error"); 2765168515Sgshapiro 2766168515Sgshapiro /* how to get the error codes? */ 2767168515Sgshapiro if (addr_st.q_host != NULL) 2768168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2769168515Sgshapiro macid("{rcpt_host}"), 2770168515Sgshapiro addr_st.q_host); 2771168515Sgshapiro else if (a != NULL && a->q_status != NULL) 2772168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2773168515Sgshapiro macid("{rcpt_host}"), 2774168515Sgshapiro a->q_status); 2775168515Sgshapiro 2776168515Sgshapiro if (addr_st.q_user != NULL) 2777168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2778168515Sgshapiro macid("{rcpt_addr}"), 2779168515Sgshapiro addr_st.q_user); 2780168515Sgshapiro else if (a != NULL && a->q_rstatus != NULL) 2781168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2782168515Sgshapiro macid("{rcpt_addr}"), 2783168515Sgshapiro a->q_rstatus); 2784168515Sgshapiro 2785168515Sgshapiro response = milter_envrcpt(args, e, &state, 2786168515Sgshapiro true); 2787168515Sgshapiro milter_cmd_done = true; 2788168515Sgshapiro MILTER_REPLY("to"); 2789168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2790168515Sgshapiro macid("{rcpt_mailer}"), NULL); 2791168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2792168515Sgshapiro macid("{rcpt_host}"), NULL); 2793168515Sgshapiro macdefine(&e->e_macro, A_PERM, 2794168515Sgshapiro macid("{rcpt_addr}"), NULL); 2795168515Sgshapiro } 2796168515Sgshapiro if (smtp.sm_milterlist && smtp.sm_milterize && 2797168515Sgshapiro milter_rcpt_added && milter_cmd_done && 2798168515Sgshapiro milter_cmd_fail) 2799168515Sgshapiro { 2800168515Sgshapiro (void) removefromlist(addr, &e->e_sendqueue, e); 2801168515Sgshapiro milter_cmd_fail = false; 2802168515Sgshapiro } 2803168515Sgshapiro#endif /* MILTER */ 280490792Sgshapiro } 280590792Sgshapiro SM_END_TRY 280638032Speter break; 280738032Speter 280838032Speter case CMDDATA: /* data -- text of mail */ 280990792Sgshapiro DELAY_CONN("DATA"); 2810132943Sgshapiro if (!smtp_data(&smtp, e)) 2811132943Sgshapiro goto doquit; 281238032Speter break; 281338032Speter 281438032Speter case CMDRSET: /* rset -- reset state */ 281538032Speter if (tTd(94, 100)) 281664562Sgshapiro message("451 4.0.0 Test failure"); 281738032Speter else 281864562Sgshapiro message("250 2.0.0 Reset state"); 281990792Sgshapiro CLEAR_STATE(cmdbuf); 282038032Speter break; 282138032Speter 282238032Speter case CMDVRFY: /* vrfy -- verify address */ 282338032Speter case CMDEXPN: /* expn -- expand address */ 282490792Sgshapiro vrfy = c->cmd_code == CMDVRFY; 282590792Sgshapiro DELAY_CONN(vrfy ? "VRFY" : "EXPN"); 282664562Sgshapiro if (tempfail) 282764562Sgshapiro { 282864562Sgshapiro if (LogLevel > 9) 282964562Sgshapiro sm_syslog(LOG_INFO, e->e_id, 2830110560Sgshapiro "SMTP %s command (%.100s) from %s tempfailed (due to previous checks)", 283190792Sgshapiro vrfy ? "VRFY" : "EXPN", 283264562Sgshapiro p, CurSmtpClient); 283390792Sgshapiro 283490792Sgshapiro /* RFC 821 doesn't allow 4xy reply code */ 283564562Sgshapiro usrerr("550 5.7.1 Please try again later"); 283664562Sgshapiro break; 283764562Sgshapiro } 283890792Sgshapiro wt = checksmtpattack(&n_verifies, MAXVRFYCOMMANDS, 283990792Sgshapiro false, vrfy ? "VRFY" : "EXPN", e); 2840132943Sgshapiro STOP_IF_ATTACK(wt); 284164562Sgshapiro previous = curtime(); 2842110560Sgshapiro if ((vrfy && bitset(PRIV_NOVRFY, PrivacyFlags)) || 2843110560Sgshapiro (!vrfy && !bitset(SRV_OFFER_EXPN, features))) 284438032Speter { 284538032Speter if (vrfy) 284664562Sgshapiro message("252 2.5.2 Cannot VRFY user; try RCPT to attempt delivery (or try finger)"); 284738032Speter else 284864562Sgshapiro message("502 5.7.0 Sorry, we do not allow this operation"); 284938032Speter if (LogLevel > 5) 285038032Speter sm_syslog(LOG_INFO, e->e_id, 2851110560Sgshapiro "%s: %s [rejected]", 285264562Sgshapiro CurSmtpClient, 285364562Sgshapiro shortenstring(inp, MAXSHORTSTR)); 285438032Speter break; 285538032Speter } 285638032Speter else if (!gothello && 285738032Speter bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO, 285838032Speter PrivacyFlags)) 285938032Speter { 286064562Sgshapiro usrerr("503 5.0.0 I demand that you introduce yourself first"); 286138032Speter break; 286238032Speter } 286390792Sgshapiro if (Errors > 0) 286438032Speter break; 286538032Speter if (LogLevel > 5) 2866110560Sgshapiro sm_syslog(LOG_INFO, e->e_id, "%s: %s", 286764562Sgshapiro CurSmtpClient, 286864562Sgshapiro shortenstring(inp, MAXSHORTSTR)); 286990792Sgshapiro SM_TRY 287090792Sgshapiro { 287190792Sgshapiro QuickAbort = true; 287238032Speter vrfyqueue = NULL; 287338032Speter if (vrfy) 287438032Speter e->e_flags |= EF_VRFYONLY; 287538032Speter while (*p != '\0' && isascii(*p) && isspace(*p)) 287638032Speter p++; 287738032Speter if (*p == '\0') 287838032Speter { 287964562Sgshapiro usrerr("501 5.5.2 Argument required"); 288038032Speter } 288138032Speter else 288238032Speter { 288364562Sgshapiro /* do config file checking of the address */ 288464562Sgshapiro if (rscheck(vrfy ? "check_vrfy" : "check_expn", 2885102528Sgshapiro p, NULL, e, RSF_RMCOMM, 2886168515Sgshapiro 3, NULL, NOQID, NULL) != EX_OK || 288790792Sgshapiro Errors > 0) 288890792Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1); 288938032Speter (void) sendtolist(p, NULLADDR, &vrfyqueue, 0, e); 289038032Speter } 289164562Sgshapiro if (wt > 0) 289271345Sgshapiro { 289371345Sgshapiro time_t t; 289471345Sgshapiro 289571345Sgshapiro t = wt - (curtime() - previous); 289671345Sgshapiro if (t > 0) 289771345Sgshapiro (void) sleep(t); 289871345Sgshapiro } 289938032Speter if (Errors > 0) 290090792Sgshapiro sm_exc_raisenew_x(&EtypeQuickAbort, 1); 290138032Speter if (vrfyqueue == NULL) 290238032Speter { 290364562Sgshapiro usrerr("554 5.5.2 Nothing to %s", vrfy ? "VRFY" : "EXPN"); 290438032Speter } 290538032Speter while (vrfyqueue != NULL) 290638032Speter { 290764562Sgshapiro if (!QS_IS_UNDELIVERED(vrfyqueue->q_state)) 290864562Sgshapiro { 290964562Sgshapiro vrfyqueue = vrfyqueue->q_next; 291064562Sgshapiro continue; 291164562Sgshapiro } 291238032Speter 291364562Sgshapiro /* see if there is more in the vrfy list */ 291438032Speter a = vrfyqueue; 291538032Speter while ((a = a->q_next) != NULL && 291666494Sgshapiro (!QS_IS_UNDELIVERED(a->q_state))) 291738032Speter continue; 291864562Sgshapiro printvrfyaddr(vrfyqueue, a == NULL, vrfy); 291964562Sgshapiro vrfyqueue = a; 292038032Speter } 292190792Sgshapiro } 292290792Sgshapiro SM_EXCEPT(exc, "[!F]*") 292390792Sgshapiro { 292490792Sgshapiro /* 292590792Sgshapiro ** An exception occurred while processing VRFY/EXPN 292690792Sgshapiro */ 292790792Sgshapiro 292890792Sgshapiro sm_exc_free(exc); 292990792Sgshapiro goto undo; 293090792Sgshapiro } 293190792Sgshapiro SM_END_TRY 293238032Speter break; 293338032Speter 293438032Speter case CMDETRN: /* etrn -- force queue flush */ 293590792Sgshapiro DELAY_CONN("ETRN"); 293690792Sgshapiro 293790792Sgshapiro /* Don't leak queue information via debug flags */ 293890792Sgshapiro if (!bitset(SRV_OFFER_ETRN, features) || UseMSP || 293990792Sgshapiro (RealUid != 0 && RealUid != TrustedUid && 294090792Sgshapiro OpMode == MD_SMTP)) 294138032Speter { 294264562Sgshapiro /* different message for MSA ? */ 294364562Sgshapiro message("502 5.7.0 Sorry, we do not allow this operation"); 294438032Speter if (LogLevel > 5) 294538032Speter sm_syslog(LOG_INFO, e->e_id, 2946110560Sgshapiro "%s: %s [rejected]", 294764562Sgshapiro CurSmtpClient, 294864562Sgshapiro shortenstring(inp, MAXSHORTSTR)); 294938032Speter break; 295038032Speter } 295164562Sgshapiro if (tempfail) 295264562Sgshapiro { 295364562Sgshapiro if (LogLevel > 9) 295464562Sgshapiro sm_syslog(LOG_INFO, e->e_id, 2955110560Sgshapiro "SMTP ETRN command (%.100s) from %s tempfailed (due to previous checks)", 295664562Sgshapiro p, CurSmtpClient); 295790792Sgshapiro usrerr(MSG_TEMPFAIL); 295864562Sgshapiro break; 295964562Sgshapiro } 296038032Speter 296138032Speter if (strlen(p) <= 0) 296238032Speter { 296364562Sgshapiro usrerr("500 5.5.2 Parameter required"); 296438032Speter break; 296538032Speter } 296638032Speter 296738032Speter /* crude way to avoid denial-of-service attacks */ 2968132943Sgshapiro STOP_IF_ATTACK(checksmtpattack(&n_etrn, MAXETRNCOMMANDS, 2969132943Sgshapiro true, "ETRN", e)); 297038032Speter 297190792Sgshapiro /* 297290792Sgshapiro ** Do config file checking of the parameter. 297390792Sgshapiro ** Even though we have srv_features now, we still 297490792Sgshapiro ** need this ruleset because the former is called 297590792Sgshapiro ** when the connection has been established, while 297690792Sgshapiro ** this ruleset is called when the command is 297790792Sgshapiro ** actually issued and therefore has all information 297890792Sgshapiro ** available to make a decision. 297990792Sgshapiro */ 298090792Sgshapiro 2981102528Sgshapiro if (rscheck("check_etrn", p, NULL, e, 2982168515Sgshapiro RSF_RMCOMM, 3, NULL, NOQID, NULL) 2983168515Sgshapiro != EX_OK || 2984102528Sgshapiro Errors > 0) 298564562Sgshapiro break; 298664562Sgshapiro 298738032Speter if (LogLevel > 5) 298838032Speter sm_syslog(LOG_INFO, e->e_id, 2989110560Sgshapiro "%s: ETRN %s", CurSmtpClient, 299064562Sgshapiro shortenstring(p, MAXSHORTSTR)); 299138032Speter 299238032Speter id = p; 299390792Sgshapiro if (*id == '#') 299490792Sgshapiro { 2995111823Sgshapiro int i, qgrp; 299690792Sgshapiro 299790792Sgshapiro id++; 2998111823Sgshapiro qgrp = name2qid(id); 2999111823Sgshapiro if (!ISVALIDQGRP(qgrp)) 300090792Sgshapiro { 300190792Sgshapiro usrerr("459 4.5.4 Queue %s unknown", 300290792Sgshapiro id); 300390792Sgshapiro break; 300490792Sgshapiro } 3005111823Sgshapiro for (i = 0; i < NumQueue && Queue[i] != NULL; 3006111823Sgshapiro i++) 3007111823Sgshapiro Queue[i]->qg_nextrun = (time_t) -1; 3008111823Sgshapiro Queue[qgrp]->qg_nextrun = 0; 3009111823Sgshapiro ok = run_work_group(Queue[qgrp]->qg_wgrp, 3010111823Sgshapiro RWG_FORK|RWG_FORCE); 301190792Sgshapiro if (ok && Errors == 0) 301290792Sgshapiro message("250 2.0.0 Queuing for queue group %s started", id); 301390792Sgshapiro break; 301490792Sgshapiro } 301590792Sgshapiro 301638032Speter if (*id == '@') 301738032Speter id++; 301838032Speter else 301938032Speter *--id = '@'; 302064562Sgshapiro 302190792Sgshapiro new = (QUEUE_CHAR *) sm_malloc(sizeof(QUEUE_CHAR)); 302290792Sgshapiro if (new == NULL) 302390792Sgshapiro { 302490792Sgshapiro syserr("500 5.5.0 ETRN out of memory"); 302590792Sgshapiro break; 302690792Sgshapiro } 302738032Speter new->queue_match = id; 302890792Sgshapiro new->queue_negate = false; 302938032Speter new->queue_next = NULL; 303038032Speter QueueLimitRecipient = new; 303190792Sgshapiro ok = runqueue(true, false, false, true); 303290792Sgshapiro sm_free(QueueLimitRecipient); /* XXX */ 303338032Speter QueueLimitRecipient = NULL; 303438032Speter if (ok && Errors == 0) 303564562Sgshapiro message("250 2.0.0 Queuing for node %s started", p); 303638032Speter break; 303738032Speter 303838032Speter case CMDHELP: /* help -- give user info */ 303990792Sgshapiro DELAY_CONN("HELP"); 304064562Sgshapiro help(p, e); 304138032Speter break; 304238032Speter 304338032Speter case CMDNOOP: /* noop -- do nothing */ 304490792Sgshapiro DELAY_CONN("NOOP"); 3045157001Sgshapiro STOP_IF_ATTACK(checksmtpattack(&n_noop, MaxNOOPCommands, 3046132943Sgshapiro true, "NOOP", e)); 304764562Sgshapiro message("250 2.0.0 OK"); 304838032Speter break; 304938032Speter 305038032Speter case CMDQUIT: /* quit -- leave mail */ 305164562Sgshapiro message("221 2.0.0 %s closing connection", MyHostName); 305290792Sgshapiro#if PIPELINING 305390792Sgshapiro (void) sm_io_flush(OutChannel, SM_TIME_DEFAULT); 305490792Sgshapiro#endif /* PIPELINING */ 305538032Speter 305690792Sgshapiro if (smtp.sm_nrcpts > 0) 305790792Sgshapiro logundelrcpts(e, "aborted by sender", 9, false); 305890792Sgshapiro 305938032Speter /* arrange to ignore any current send list */ 306038032Speter e->e_sendqueue = NULL; 306138032Speter 306290792Sgshapiro#if STARTTLS 306364562Sgshapiro /* shutdown TLS connection */ 306464562Sgshapiro if (tls_active) 306564562Sgshapiro { 306664562Sgshapiro (void) endtls(srv_ssl, "server"); 306790792Sgshapiro tls_active = false; 306864562Sgshapiro } 306990792Sgshapiro#endif /* STARTTLS */ 307090792Sgshapiro#if SASL 307164562Sgshapiro if (authenticating == SASL_IS_AUTH) 307264562Sgshapiro { 307364562Sgshapiro sasl_dispose(&conn); 307464562Sgshapiro authenticating = SASL_NOT_AUTH; 307590792Sgshapiro /* XXX sasl_done(); this is a child */ 307664562Sgshapiro } 307790792Sgshapiro#endif /* SASL */ 307864562Sgshapiro 307964562Sgshapirodoquit: 308038032Speter /* avoid future 050 messages */ 308138032Speter disconnect(1, e); 308238032Speter 308390792Sgshapiro#if MILTER 308464562Sgshapiro /* close out milter filters */ 308564562Sgshapiro milter_quit(e); 308690792Sgshapiro#endif /* MILTER */ 308764562Sgshapiro 308864562Sgshapiro if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags)) 308964562Sgshapiro logsender(e, NULL); 309064562Sgshapiro e->e_flags &= ~EF_LOGSENDER; 309164562Sgshapiro 309298121Sgshapiro if (lognullconnection && LogLevel > 5 && 309398121Sgshapiro nullserver == NULL) 309464562Sgshapiro { 309564562Sgshapiro char *d; 309664562Sgshapiro 309790792Sgshapiro d = macvalue(macid("{daemon_name}"), e); 309864562Sgshapiro if (d == NULL) 309964562Sgshapiro d = "stdin"; 310090792Sgshapiro 310190792Sgshapiro /* 310290792Sgshapiro ** even though this id is "bogus", it makes 310390792Sgshapiro ** it simpler to "grep" related events, e.g., 310490792Sgshapiro ** timeouts for the same connection. 310590792Sgshapiro */ 310690792Sgshapiro 310790792Sgshapiro sm_syslog(LOG_INFO, e->e_id, 3108110560Sgshapiro "%s did not issue MAIL/EXPN/VRFY/ETRN during connection to %s", 310964562Sgshapiro CurSmtpClient, d); 311064562Sgshapiro } 3111110560Sgshapiro if (tTd(93, 100)) 3112110560Sgshapiro { 3113110560Sgshapiro /* return to handle next connection */ 3114110560Sgshapiro return; 3115110560Sgshapiro } 311690792Sgshapiro finis(true, true, ExitStat); 311764562Sgshapiro /* NOTREACHED */ 311838032Speter 3119157001Sgshapiro /* just to avoid bogus warning from some compilers */ 3120157001Sgshapiro exit(EX_OSERR); 3121157001Sgshapiro 312238032Speter case CMDVERB: /* set verbose mode */ 312390792Sgshapiro DELAY_CONN("VERB"); 3124110560Sgshapiro if (!bitset(SRV_OFFER_EXPN, features) || 3125110560Sgshapiro !bitset(SRV_OFFER_VERB, features)) 312638032Speter { 312738032Speter /* this would give out the same info */ 312864562Sgshapiro message("502 5.7.0 Verbose unavailable"); 312938032Speter break; 313038032Speter } 3131157001Sgshapiro STOP_IF_ATTACK(checksmtpattack(&n_noop, MaxNOOPCommands, 3132132943Sgshapiro true, "VERB", e)); 313338032Speter Verbose = 1; 313464562Sgshapiro set_delivery_mode(SM_DELIVER, e); 313564562Sgshapiro message("250 2.0.0 Verbose mode"); 313638032Speter break; 313738032Speter 313890792Sgshapiro#if SMTPDEBUG 313938032Speter case CMDDBGQSHOW: /* show queues */ 314090792Sgshapiro (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 314190792Sgshapiro "Send Queue="); 3142132943Sgshapiro printaddr(smioout, e->e_sendqueue, true); 314338032Speter break; 314438032Speter 314538032Speter case CMDDBGDEBUG: /* set debug mode */ 3146168515Sgshapiro tTsetup(tTdvect, sizeof(tTdvect), "0-99.1"); 314738032Speter tTflag(p); 314864562Sgshapiro message("200 2.0.0 Debug set"); 314938032Speter break; 315038032Speter 315190792Sgshapiro#else /* SMTPDEBUG */ 315238032Speter case CMDDBGQSHOW: /* show queues */ 315338032Speter case CMDDBGDEBUG: /* set debug mode */ 315490792Sgshapiro#endif /* SMTPDEBUG */ 315538032Speter case CMDLOGBOGUS: /* bogus command */ 315690792Sgshapiro DELAY_CONN("Bogus"); 315738032Speter if (LogLevel > 0) 315838032Speter sm_syslog(LOG_CRIT, e->e_id, 3159110560Sgshapiro "\"%s\" command from %s (%.100s)", 316064562Sgshapiro c->cmd_name, CurSmtpClient, 316164562Sgshapiro anynet_ntoa(&RealHostAddr)); 316264562Sgshapiro /* FALLTHROUGH */ 316338032Speter 316438032Speter case CMDERROR: /* unknown command */ 316590792Sgshapiro#if MAXBADCOMMANDS > 0 316690792Sgshapiro if (++n_badcmds > MAXBADCOMMANDS) 316738032Speter { 3168132943Sgshapiro stopattack: 316964562Sgshapiro message("421 4.7.0 %s Too many bad commands; closing connection", 317038032Speter MyHostName); 317164562Sgshapiro 317264562Sgshapiro /* arrange to ignore any current send list */ 317364562Sgshapiro e->e_sendqueue = NULL; 317438032Speter goto doquit; 317538032Speter } 317690792Sgshapiro#endif /* MAXBADCOMMANDS > 0 */ 317738032Speter 3178132943Sgshapiro#if MILTER && SMFI_VERSION > 2 3179132943Sgshapiro if (smtp.sm_milterlist && smtp.sm_milterize && 3180132943Sgshapiro !bitset(EF_DISCARD, e->e_flags)) 3181132943Sgshapiro { 3182132943Sgshapiro char state; 3183132943Sgshapiro char *response; 3184132943Sgshapiro 3185132943Sgshapiro if (MilterLogLevel > 9) 3186132943Sgshapiro sm_syslog(LOG_INFO, e->e_id, 3187132943Sgshapiro "Sending \"%s\" to Milter", inp); 3188132943Sgshapiro response = milter_unknown(inp, e, &state); 3189132943Sgshapiro MILTER_REPLY("unknown"); 3190132943Sgshapiro if (state == SMFIR_REPLYCODE || 3191132943Sgshapiro state == SMFIR_REJECT || 3192157001Sgshapiro state == SMFIR_TEMPFAIL || 3193157001Sgshapiro state == SMFIR_SHUTDOWN) 3194132943Sgshapiro { 3195132943Sgshapiro /* MILTER_REPLY already gave an error */ 3196132943Sgshapiro break; 3197132943Sgshapiro } 3198132943Sgshapiro } 3199132943Sgshapiro#endif /* MILTER && SMFI_VERSION > 2 */ 3200132943Sgshapiro 320164562Sgshapiro usrerr("500 5.5.1 Command unrecognized: \"%s\"", 320264562Sgshapiro shortenstring(inp, MAXSHORTSTR)); 320338032Speter break; 320438032Speter 320564562Sgshapiro case CMDUNIMPL: 320690792Sgshapiro DELAY_CONN("Unimpl"); 320764562Sgshapiro usrerr("502 5.5.1 Command not implemented: \"%s\"", 320864562Sgshapiro shortenstring(inp, MAXSHORTSTR)); 320964562Sgshapiro break; 321064562Sgshapiro 321138032Speter default: 321290792Sgshapiro DELAY_CONN("default"); 321338032Speter errno = 0; 321464562Sgshapiro syserr("500 5.5.0 smtp: unknown code %d", c->cmd_code); 321538032Speter break; 321638032Speter } 321790792Sgshapiro#if SASL 321864562Sgshapiro } 321990792Sgshapiro#endif /* SASL */ 322090792Sgshapiro } 322190792Sgshapiro SM_EXCEPT(exc, "[!F]*") 322290792Sgshapiro { 322390792Sgshapiro /* 322490792Sgshapiro ** The only possible exception is "E:mta.quickabort". 322590792Sgshapiro ** There is nothing to do except fall through and loop. 322690792Sgshapiro */ 322790792Sgshapiro } 322890792Sgshapiro SM_END_TRY 322938032Speter } 323090792Sgshapiro} 323190792Sgshapiro/* 323290792Sgshapiro** SMTP_DATA -- implement the SMTP DATA command. 323390792Sgshapiro** 323490792Sgshapiro** Parameters: 323590792Sgshapiro** smtp -- status of SMTP connection. 323690792Sgshapiro** e -- envelope. 323790792Sgshapiro** 323890792Sgshapiro** Returns: 3239132943Sgshapiro** true iff SMTP session can continue. 324090792Sgshapiro** 324190792Sgshapiro** Side Effects: 324290792Sgshapiro** possibly sends message. 324390792Sgshapiro*/ 324464562Sgshapiro 3245132943Sgshapirostatic bool 324690792Sgshapirosmtp_data(smtp, e) 324790792Sgshapiro SMTP_T *smtp; 324890792Sgshapiro ENVELOPE *e; 324990792Sgshapiro{ 325090792Sgshapiro#if MILTER 325190792Sgshapiro bool milteraccept; 325290792Sgshapiro#endif /* MILTER */ 325390792Sgshapiro bool aborting; 325490792Sgshapiro bool doublequeue; 3255168515Sgshapiro bool rv = true; 325690792Sgshapiro ADDRESS *a; 325790792Sgshapiro ENVELOPE *ee; 325890792Sgshapiro char *id; 325998121Sgshapiro char *oldid; 3260168515Sgshapiro unsigned int features; 326190792Sgshapiro char buf[32]; 326290792Sgshapiro 326390792Sgshapiro SmtpPhase = "server DATA"; 326490792Sgshapiro if (!smtp->sm_gotmail) 326590792Sgshapiro { 326690792Sgshapiro usrerr("503 5.0.0 Need MAIL command"); 3267132943Sgshapiro return true; 326890792Sgshapiro } 326990792Sgshapiro else if (smtp->sm_nrcpts <= 0) 327090792Sgshapiro { 327190792Sgshapiro usrerr("503 5.0.0 Need RCPT (recipient)"); 3272132943Sgshapiro return true; 327390792Sgshapiro } 3274168515Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "%u", smtp->sm_nrcpts); 327590792Sgshapiro if (rscheck("check_data", buf, NULL, e, 3276102528Sgshapiro RSF_RMCOMM|RSF_UNSTRUCTURED|RSF_COUNT, 3, NULL, 3277168515Sgshapiro e->e_id, NULL) != EX_OK) 3278132943Sgshapiro return true; 327990792Sgshapiro 3280132943Sgshapiro#if MILTER && SMFI_VERSION > 3 3281132943Sgshapiro if (smtp->sm_milterlist && smtp->sm_milterize && 3282132943Sgshapiro !bitset(EF_DISCARD, e->e_flags)) 3283132943Sgshapiro { 3284132943Sgshapiro char state; 3285132943Sgshapiro char *response; 3286132943Sgshapiro int savelogusrerrs = LogUsrErrs; 3287132943Sgshapiro 3288132943Sgshapiro response = milter_data_cmd(e, &state); 3289132943Sgshapiro switch (state) 3290132943Sgshapiro { 3291132943Sgshapiro case SMFIR_REPLYCODE: 3292132943Sgshapiro if (MilterLogLevel > 3) 3293132943Sgshapiro { 3294132943Sgshapiro sm_syslog(LOG_INFO, e->e_id, 3295132943Sgshapiro "Milter: cmd=data, reject=%s", 3296132943Sgshapiro response); 3297132943Sgshapiro LogUsrErrs = false; 3298132943Sgshapiro } 3299132943Sgshapiro usrerr(response); 3300157001Sgshapiro if (strncmp(response, "421 ", 4) == 0 3301157001Sgshapiro || strncmp(response, "421-", 4) == 0) 3302132943Sgshapiro { 3303132943Sgshapiro e->e_sendqueue = NULL; 3304132943Sgshapiro return false; 3305132943Sgshapiro } 3306132943Sgshapiro return true; 3307132943Sgshapiro 3308132943Sgshapiro case SMFIR_REJECT: 3309132943Sgshapiro if (MilterLogLevel > 3) 3310132943Sgshapiro { 3311132943Sgshapiro sm_syslog(LOG_INFO, e->e_id, 3312132943Sgshapiro "Milter: cmd=data, reject=550 5.7.1 Command rejected"); 3313132943Sgshapiro LogUsrErrs = false; 3314132943Sgshapiro } 3315132943Sgshapiro usrerr("550 5.7.1 Command rejected"); 3316132943Sgshapiro return true; 3317132943Sgshapiro 3318132943Sgshapiro case SMFIR_DISCARD: 3319132943Sgshapiro if (MilterLogLevel > 3) 3320132943Sgshapiro sm_syslog(LOG_INFO, e->e_id, 3321132943Sgshapiro "Milter: cmd=data, discard"); 3322132943Sgshapiro e->e_flags |= EF_DISCARD; 3323132943Sgshapiro break; 3324132943Sgshapiro 3325132943Sgshapiro case SMFIR_TEMPFAIL: 3326132943Sgshapiro if (MilterLogLevel > 3) 3327132943Sgshapiro { 3328132943Sgshapiro sm_syslog(LOG_INFO, e->e_id, 3329132943Sgshapiro "Milter: cmd=data, reject=%s", 3330132943Sgshapiro MSG_TEMPFAIL); 3331132943Sgshapiro LogUsrErrs = false; 3332132943Sgshapiro } 3333132943Sgshapiro usrerr(MSG_TEMPFAIL); 3334132943Sgshapiro return true; 3335157001Sgshapiro 3336157001Sgshapiro case SMFIR_SHUTDOWN: 3337157001Sgshapiro if (MilterLogLevel > 3) 3338157001Sgshapiro { 3339157001Sgshapiro sm_syslog(LOG_INFO, e->e_id, 3340157001Sgshapiro "Milter: cmd=data, reject=421 4.7.0 %s closing connection", 3341157001Sgshapiro MyHostName); 3342157001Sgshapiro LogUsrErrs = false; 3343157001Sgshapiro } 3344157001Sgshapiro usrerr("421 4.7.0 %s closing connection", MyHostName); 3345157001Sgshapiro e->e_sendqueue = NULL; 3346157001Sgshapiro return false; 3347132943Sgshapiro } 3348132943Sgshapiro LogUsrErrs = savelogusrerrs; 3349132943Sgshapiro if (response != NULL) 3350132943Sgshapiro sm_free(response); /* XXX */ 3351132943Sgshapiro } 3352132943Sgshapiro#endif /* MILTER && SMFI_VERSION > 3 */ 3353132943Sgshapiro 335490792Sgshapiro /* put back discard bit */ 335590792Sgshapiro if (smtp->sm_discard) 335690792Sgshapiro e->e_flags |= EF_DISCARD; 335790792Sgshapiro 335890792Sgshapiro /* check to see if we need to re-expand aliases */ 335990792Sgshapiro /* also reset QS_BADADDR on already-diagnosted addrs */ 336090792Sgshapiro doublequeue = false; 336190792Sgshapiro for (a = e->e_sendqueue; a != NULL; a = a->q_next) 336290792Sgshapiro { 336390792Sgshapiro if (QS_IS_VERIFIED(a->q_state) && 336490792Sgshapiro !bitset(EF_DISCARD, e->e_flags)) 336590792Sgshapiro { 336690792Sgshapiro /* need to re-expand aliases */ 336790792Sgshapiro doublequeue = true; 336890792Sgshapiro } 336990792Sgshapiro if (QS_IS_BADADDR(a->q_state)) 337090792Sgshapiro { 337190792Sgshapiro /* make this "go away" */ 337290792Sgshapiro a->q_state = QS_DONTSEND; 337390792Sgshapiro } 337490792Sgshapiro } 337590792Sgshapiro 337690792Sgshapiro /* collect the text of the message */ 337790792Sgshapiro SmtpPhase = "collect"; 337890792Sgshapiro buffer_errors(); 337990792Sgshapiro 3380120256Sgshapiro collect(InChannel, true, NULL, e, true); 338190792Sgshapiro 338290792Sgshapiro /* redefine message size */ 3383168515Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "%ld", e->e_msgsize); 338490792Sgshapiro macdefine(&e->e_macro, A_TEMP, macid("{msg_size}"), buf); 338590792Sgshapiro 338690792Sgshapiro /* rscheck() will set Errors or EF_DISCARD if it trips */ 3387102528Sgshapiro (void) rscheck("check_eom", buf, NULL, e, RSF_UNSTRUCTURED|RSF_COUNT, 3388168515Sgshapiro 3, NULL, e->e_id, NULL); 338990792Sgshapiro 339090792Sgshapiro#if MILTER 339190792Sgshapiro milteraccept = true; 339290792Sgshapiro if (smtp->sm_milterlist && smtp->sm_milterize && 339390792Sgshapiro Errors <= 0 && 339490792Sgshapiro !bitset(EF_DISCARD, e->e_flags)) 339590792Sgshapiro { 339690792Sgshapiro char state; 339790792Sgshapiro char *response; 339890792Sgshapiro 339990792Sgshapiro response = milter_data(e, &state); 340090792Sgshapiro switch (state) 340190792Sgshapiro { 340290792Sgshapiro case SMFIR_REPLYCODE: 340390792Sgshapiro if (MilterLogLevel > 3) 340490792Sgshapiro sm_syslog(LOG_INFO, e->e_id, 340590792Sgshapiro "Milter: data, reject=%s", 340690792Sgshapiro response); 340790792Sgshapiro milteraccept = false; 340890792Sgshapiro usrerr(response); 340990792Sgshapiro break; 341090792Sgshapiro 341190792Sgshapiro case SMFIR_REJECT: 341290792Sgshapiro milteraccept = false; 341390792Sgshapiro if (MilterLogLevel > 3) 341490792Sgshapiro sm_syslog(LOG_INFO, e->e_id, 341590792Sgshapiro "Milter: data, reject=554 5.7.1 Command rejected"); 341690792Sgshapiro usrerr("554 5.7.1 Command rejected"); 341790792Sgshapiro break; 341890792Sgshapiro 341990792Sgshapiro case SMFIR_DISCARD: 342090792Sgshapiro if (MilterLogLevel > 3) 342190792Sgshapiro sm_syslog(LOG_INFO, e->e_id, 342290792Sgshapiro "Milter: data, discard"); 342390792Sgshapiro milteraccept = false; 342490792Sgshapiro e->e_flags |= EF_DISCARD; 342590792Sgshapiro break; 342690792Sgshapiro 342790792Sgshapiro case SMFIR_TEMPFAIL: 342890792Sgshapiro if (MilterLogLevel > 3) 342990792Sgshapiro sm_syslog(LOG_INFO, e->e_id, 343090792Sgshapiro "Milter: data, reject=%s", 343190792Sgshapiro MSG_TEMPFAIL); 343290792Sgshapiro milteraccept = false; 343390792Sgshapiro usrerr(MSG_TEMPFAIL); 343490792Sgshapiro break; 3435157001Sgshapiro 3436157001Sgshapiro case SMFIR_SHUTDOWN: 3437157001Sgshapiro if (MilterLogLevel > 3) 3438157001Sgshapiro sm_syslog(LOG_INFO, e->e_id, 3439157001Sgshapiro "Milter: data, reject=421 4.7.0 %s closing connection", 3440157001Sgshapiro MyHostName); 3441157001Sgshapiro milteraccept = false; 3442157001Sgshapiro usrerr("421 4.7.0 %s closing connection", MyHostName); 3443157001Sgshapiro rv = false; 3444157001Sgshapiro break; 344590792Sgshapiro } 344690792Sgshapiro if (response != NULL) 344790792Sgshapiro sm_free(response); 344890792Sgshapiro } 344990792Sgshapiro 345090792Sgshapiro /* Milter may have changed message size */ 3451168515Sgshapiro (void) sm_snprintf(buf, sizeof(buf), "%ld", e->e_msgsize); 345290792Sgshapiro macdefine(&e->e_macro, A_TEMP, macid("{msg_size}"), buf); 345390792Sgshapiro 345490792Sgshapiro /* abort message filters that didn't get the body & log msg is OK */ 345590792Sgshapiro if (smtp->sm_milterlist && smtp->sm_milterize) 345690792Sgshapiro { 345790792Sgshapiro milter_abort(e); 345890792Sgshapiro if (milteraccept && MilterLogLevel > 9) 345990792Sgshapiro sm_syslog(LOG_INFO, e->e_id, "Milter accept: message"); 346090792Sgshapiro } 3461132943Sgshapiro 3462132943Sgshapiro /* 3463132943Sgshapiro ** If SuperSafe is SAFE_REALLY_POSTMILTER, and we don't have milter or 3464132943Sgshapiro ** milter accepted message, sync it now 3465132943Sgshapiro ** 3466132943Sgshapiro ** XXX This is almost a copy of the code in collect(): put it into 3467132943Sgshapiro ** a function that is called from both places? 3468132943Sgshapiro */ 3469132943Sgshapiro 3470132943Sgshapiro if (milteraccept && SuperSafe == SAFE_REALLY_POSTMILTER) 3471132943Sgshapiro { 3472132943Sgshapiro int afd; 3473132943Sgshapiro SM_FILE_T *volatile df; 3474132943Sgshapiro char *dfname; 3475132943Sgshapiro 3476132943Sgshapiro df = e->e_dfp; 3477132943Sgshapiro dfname = queuename(e, DATAFL_LETTER); 3478132943Sgshapiro if (sm_io_setinfo(df, SM_BF_COMMIT, NULL) < 0 3479132943Sgshapiro && errno != EINVAL) 3480132943Sgshapiro { 3481132943Sgshapiro int save_errno; 3482132943Sgshapiro 3483132943Sgshapiro save_errno = errno; 3484132943Sgshapiro if (save_errno == EEXIST) 3485132943Sgshapiro { 3486132943Sgshapiro struct stat st; 3487132943Sgshapiro int dfd; 3488132943Sgshapiro 3489132943Sgshapiro if (stat(dfname, &st) < 0) 3490132943Sgshapiro st.st_size = -1; 3491132943Sgshapiro errno = EEXIST; 3492132943Sgshapiro syserr("@collect: bfcommit(%s): already on disk, size=%ld", 3493132943Sgshapiro dfname, (long) st.st_size); 3494132943Sgshapiro dfd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL); 3495132943Sgshapiro if (dfd >= 0) 3496132943Sgshapiro dumpfd(dfd, true, true); 3497132943Sgshapiro } 3498132943Sgshapiro errno = save_errno; 3499132943Sgshapiro dferror(df, "bfcommit", e); 3500132943Sgshapiro flush_errors(true); 3501132943Sgshapiro finis(save_errno != EEXIST, true, ExitStat); 3502132943Sgshapiro } 3503132943Sgshapiro else if ((afd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL)) < 0) 3504132943Sgshapiro { 3505132943Sgshapiro dferror(df, "sm_io_getinfo", e); 3506132943Sgshapiro flush_errors(true); 3507132943Sgshapiro finis(true, true, ExitStat); 3508132943Sgshapiro /* NOTREACHED */ 3509132943Sgshapiro } 3510132943Sgshapiro else if (fsync(afd) < 0) 3511132943Sgshapiro { 3512132943Sgshapiro dferror(df, "fsync", e); 3513132943Sgshapiro flush_errors(true); 3514132943Sgshapiro finis(true, true, ExitStat); 3515132943Sgshapiro /* NOTREACHED */ 3516132943Sgshapiro } 3517132943Sgshapiro else if (sm_io_close(df, SM_TIME_DEFAULT) < 0) 3518132943Sgshapiro { 3519132943Sgshapiro dferror(df, "sm_io_close", e); 3520132943Sgshapiro flush_errors(true); 3521132943Sgshapiro finis(true, true, ExitStat); 3522132943Sgshapiro /* NOTREACHED */ 3523132943Sgshapiro } 3524132943Sgshapiro 3525132943Sgshapiro /* Now reopen the df file */ 3526132943Sgshapiro e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname, 3527132943Sgshapiro SM_IO_RDONLY, NULL); 3528132943Sgshapiro if (e->e_dfp == NULL) 3529132943Sgshapiro { 3530132943Sgshapiro /* we haven't acked receipt yet, so just chuck this */ 3531132943Sgshapiro syserr("@Cannot reopen %s", dfname); 3532132943Sgshapiro finis(true, true, ExitStat); 3533132943Sgshapiro /* NOTREACHED */ 3534132943Sgshapiro } 3535132943Sgshapiro } 353690792Sgshapiro#endif /* MILTER */ 353790792Sgshapiro 353890792Sgshapiro /* Check if quarantining stats should be updated */ 353990792Sgshapiro if (e->e_quarmsg != NULL) 354090792Sgshapiro markstats(e, NULL, STATS_QUARANTINE); 354190792Sgshapiro 354290792Sgshapiro /* 354390792Sgshapiro ** If a header/body check (header checks or milter) 354490792Sgshapiro ** set EF_DISCARD, don't queueup the message -- 354590792Sgshapiro ** that would lose the EF_DISCARD bit and deliver 354690792Sgshapiro ** the message. 354790792Sgshapiro */ 354890792Sgshapiro 354990792Sgshapiro if (bitset(EF_DISCARD, e->e_flags)) 355090792Sgshapiro doublequeue = false; 355190792Sgshapiro 355290792Sgshapiro aborting = Errors > 0; 3553125820Sgshapiro if (!(aborting || bitset(EF_DISCARD, e->e_flags)) && 355490792Sgshapiro (QueueMode == QM_QUARANTINE || e->e_quarmsg == NULL) && 355590792Sgshapiro !split_by_recipient(e)) 355690792Sgshapiro aborting = bitset(EF_FATALERRS, e->e_flags); 355790792Sgshapiro 355890792Sgshapiro if (aborting) 355990792Sgshapiro { 356090792Sgshapiro /* Log who the mail would have gone to */ 356190792Sgshapiro logundelrcpts(e, e->e_message, 8, false); 356290792Sgshapiro flush_errors(true); 356390792Sgshapiro buffer_errors(); 356490792Sgshapiro goto abortmessage; 356590792Sgshapiro } 356690792Sgshapiro 356790792Sgshapiro /* from now on, we have to operate silently */ 356890792Sgshapiro buffer_errors(); 356990792Sgshapiro 357090792Sgshapiro#if 0 357190792Sgshapiro /* 357290792Sgshapiro ** Clear message, it may contain an error from the SMTP dialogue. 357390792Sgshapiro ** This error must not show up in the queue. 357490792Sgshapiro ** Some error message should show up, e.g., alias database 357590792Sgshapiro ** not available, but others shouldn't, e.g., from check_rcpt. 357690792Sgshapiro */ 357790792Sgshapiro 357890792Sgshapiro e->e_message = NULL; 357990792Sgshapiro#endif /* 0 */ 358090792Sgshapiro 358190792Sgshapiro /* 358290792Sgshapiro ** Arrange to send to everyone. 358390792Sgshapiro ** If sending to multiple people, mail back 358490792Sgshapiro ** errors rather than reporting directly. 358590792Sgshapiro ** In any case, don't mail back errors for 358690792Sgshapiro ** anything that has happened up to 358790792Sgshapiro ** now (the other end will do this). 358890792Sgshapiro ** Truncate our transcript -- the mail has gotten 358990792Sgshapiro ** to us successfully, and if we have 359090792Sgshapiro ** to mail this back, it will be easier 359190792Sgshapiro ** on the reader. 359290792Sgshapiro ** Then send to everyone. 359390792Sgshapiro ** Finally give a reply code. If an error has 359490792Sgshapiro ** already been given, don't mail a 359590792Sgshapiro ** message back. 359690792Sgshapiro ** We goose error returns by clearing error bit. 359790792Sgshapiro */ 359890792Sgshapiro 359990792Sgshapiro SmtpPhase = "delivery"; 360090792Sgshapiro (void) sm_io_setinfo(e->e_xfp, SM_BF_TRUNCATE, NULL); 360190792Sgshapiro id = e->e_id; 360290792Sgshapiro 360390792Sgshapiro#if NAMED_BIND 360490792Sgshapiro _res.retry = TimeOuts.res_retry[RES_TO_FIRST]; 360590792Sgshapiro _res.retrans = TimeOuts.res_retrans[RES_TO_FIRST]; 360690792Sgshapiro#endif /* NAMED_BIND */ 360790792Sgshapiro 360890792Sgshapiro for (ee = e; ee != NULL; ee = ee->e_sibling) 360990792Sgshapiro { 361090792Sgshapiro /* make sure we actually do delivery */ 361190792Sgshapiro ee->e_flags &= ~EF_CLRQUEUE; 361290792Sgshapiro 361390792Sgshapiro /* from now on, operate silently */ 361490792Sgshapiro ee->e_errormode = EM_MAIL; 361590792Sgshapiro 361690792Sgshapiro if (doublequeue) 361790792Sgshapiro { 361890792Sgshapiro /* make sure it is in the queue */ 361990792Sgshapiro queueup(ee, false, true); 362090792Sgshapiro } 362190792Sgshapiro else 362290792Sgshapiro { 3623157001Sgshapiro int mode; 3624157001Sgshapiro 362590792Sgshapiro /* send to all recipients */ 3626157001Sgshapiro mode = SM_DEFAULT; 3627157001Sgshapiro#if _FFR_DM_ONE 3628157001Sgshapiro if (SM_DM_ONE == e->e_sendmode) 3629157001Sgshapiro { 3630157001Sgshapiro if (NotFirstDelivery) 3631157001Sgshapiro { 3632157001Sgshapiro mode = SM_QUEUE; 3633157001Sgshapiro e->e_sendmode = SM_QUEUE; 3634157001Sgshapiro } 3635157001Sgshapiro else 3636157001Sgshapiro { 3637157001Sgshapiro mode = SM_FORK; 3638157001Sgshapiro NotFirstDelivery = true; 3639157001Sgshapiro } 3640157001Sgshapiro } 3641157001Sgshapiro#endif /* _FFR_DM_ONE */ 3642157001Sgshapiro sendall(ee, mode); 364390792Sgshapiro } 364490792Sgshapiro ee->e_to = NULL; 364590792Sgshapiro } 364690792Sgshapiro 364798121Sgshapiro /* put back id for SMTP logging in putoutmsg() */ 364898121Sgshapiro oldid = CurEnv->e_id; 364998121Sgshapiro CurEnv->e_id = id; 365098121Sgshapiro 365190792Sgshapiro /* issue success message */ 3652157001Sgshapiro#if _FFR_MSG_ACCEPT 3653157001Sgshapiro if (MessageAccept != NULL && *MessageAccept != '\0') 3654157001Sgshapiro { 3655157001Sgshapiro char msg[MAXLINE]; 3656157001Sgshapiro 3657168515Sgshapiro expand(MessageAccept, msg, sizeof(msg), e); 3658157001Sgshapiro message("250 2.0.0 %s", msg); 3659157001Sgshapiro } 3660157001Sgshapiro else 3661157001Sgshapiro#endif /* _FFR_MSG_ACCEPT */ 366290792Sgshapiro message("250 2.0.0 %s Message accepted for delivery", id); 366398121Sgshapiro CurEnv->e_id = oldid; 366490792Sgshapiro 366590792Sgshapiro /* if we just queued, poke it */ 366690792Sgshapiro if (doublequeue) 366790792Sgshapiro { 366890792Sgshapiro bool anything_to_send = false; 366990792Sgshapiro 367090792Sgshapiro sm_getla(); 367190792Sgshapiro for (ee = e; ee != NULL; ee = ee->e_sibling) 367290792Sgshapiro { 367390792Sgshapiro if (WILL_BE_QUEUED(ee->e_sendmode)) 367490792Sgshapiro continue; 367590792Sgshapiro if (shouldqueue(ee->e_msgpriority, ee->e_ctime)) 367690792Sgshapiro { 367790792Sgshapiro ee->e_sendmode = SM_QUEUE; 367890792Sgshapiro continue; 367990792Sgshapiro } 368090792Sgshapiro else if (QueueMode != QM_QUARANTINE && 368190792Sgshapiro ee->e_quarmsg != NULL) 368290792Sgshapiro { 368390792Sgshapiro ee->e_sendmode = SM_QUEUE; 368490792Sgshapiro continue; 368590792Sgshapiro } 368690792Sgshapiro anything_to_send = true; 368790792Sgshapiro 368890792Sgshapiro /* close all the queue files */ 368990792Sgshapiro closexscript(ee); 369090792Sgshapiro if (ee->e_dfp != NULL) 369190792Sgshapiro { 369290792Sgshapiro (void) sm_io_close(ee->e_dfp, SM_TIME_DEFAULT); 369390792Sgshapiro ee->e_dfp = NULL; 369490792Sgshapiro } 369590792Sgshapiro unlockqueue(ee); 369690792Sgshapiro } 369790792Sgshapiro if (anything_to_send) 369890792Sgshapiro { 369990792Sgshapiro#if PIPELINING 370090792Sgshapiro /* 370190792Sgshapiro ** XXX if we don't do this, we get 250 twice 370290792Sgshapiro ** because it is also flushed in the child. 370390792Sgshapiro */ 370490792Sgshapiro 370590792Sgshapiro (void) sm_io_flush(OutChannel, SM_TIME_DEFAULT); 370690792Sgshapiro#endif /* PIPELINING */ 370790792Sgshapiro (void) doworklist(e, true, true); 370890792Sgshapiro } 370990792Sgshapiro } 371090792Sgshapiro 371190792Sgshapiro abortmessage: 371290792Sgshapiro if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags)) 371390792Sgshapiro logsender(e, NULL); 371490792Sgshapiro e->e_flags &= ~EF_LOGSENDER; 371590792Sgshapiro 371690792Sgshapiro /* clean up a bit */ 371790792Sgshapiro smtp->sm_gotmail = false; 371890792Sgshapiro 371990792Sgshapiro /* 372090792Sgshapiro ** Call dropenvelope if and only if the envelope is *not* 372190792Sgshapiro ** being processed by the child process forked by doworklist(). 372290792Sgshapiro */ 372390792Sgshapiro 372490792Sgshapiro if (aborting || bitset(EF_DISCARD, e->e_flags)) 372590792Sgshapiro dropenvelope(e, true, false); 372690792Sgshapiro else 372790792Sgshapiro { 372890792Sgshapiro for (ee = e; ee != NULL; ee = ee->e_sibling) 372990792Sgshapiro { 373090792Sgshapiro if (!doublequeue && 373190792Sgshapiro QueueMode != QM_QUARANTINE && 373290792Sgshapiro ee->e_quarmsg != NULL) 373390792Sgshapiro { 373490792Sgshapiro dropenvelope(ee, true, false); 373590792Sgshapiro continue; 373690792Sgshapiro } 373790792Sgshapiro if (WILL_BE_QUEUED(ee->e_sendmode)) 373890792Sgshapiro dropenvelope(ee, true, false); 373990792Sgshapiro } 374090792Sgshapiro } 374190792Sgshapiro sm_rpool_free(e->e_rpool); 374290792Sgshapiro 374390792Sgshapiro /* 374490792Sgshapiro ** At this point, e == &MainEnvelope, but if we did splitting, 374590792Sgshapiro ** then CurEnv may point to an envelope structure that was just 374690792Sgshapiro ** freed with the rpool. So reset CurEnv *before* calling 374790792Sgshapiro ** newenvelope. 374890792Sgshapiro */ 374990792Sgshapiro 375090792Sgshapiro CurEnv = e; 3751168515Sgshapiro features = e->e_features; 375290792Sgshapiro newenvelope(e, e, sm_rpool_new_x(NULL)); 375390792Sgshapiro e->e_flags = BlankEnvelope.e_flags; 3754168515Sgshapiro e->e_features = features; 375590792Sgshapiro 375690792Sgshapiro /* restore connection quarantining */ 375790792Sgshapiro if (smtp->sm_quarmsg == NULL) 375890792Sgshapiro { 375990792Sgshapiro e->e_quarmsg = NULL; 376090792Sgshapiro macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), ""); 376190792Sgshapiro } 376290792Sgshapiro else 376390792Sgshapiro { 376490792Sgshapiro e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, smtp->sm_quarmsg); 376590792Sgshapiro macdefine(&e->e_macro, A_PERM, 376690792Sgshapiro macid("{quarantine}"), e->e_quarmsg); 376790792Sgshapiro } 3768157001Sgshapiro return rv; 376938032Speter} 377090792Sgshapiro/* 377190792Sgshapiro** LOGUNDELRCPTS -- log undelivered (or all) recipients. 377290792Sgshapiro** 377390792Sgshapiro** Parameters: 377490792Sgshapiro** e -- envelope. 377590792Sgshapiro** msg -- message for Stat= 377690792Sgshapiro** level -- log level. 377790792Sgshapiro** all -- log all recipients. 377890792Sgshapiro** 377990792Sgshapiro** Returns: 378090792Sgshapiro** none. 378190792Sgshapiro** 378290792Sgshapiro** Side Effects: 378390792Sgshapiro** logs undelivered (or all) recipients 378490792Sgshapiro*/ 378590792Sgshapiro 378690792Sgshapirovoid 378790792Sgshapirologundelrcpts(e, msg, level, all) 378890792Sgshapiro ENVELOPE *e; 378990792Sgshapiro char *msg; 379090792Sgshapiro int level; 379190792Sgshapiro bool all; 379290792Sgshapiro{ 379390792Sgshapiro ADDRESS *a; 379490792Sgshapiro 379590792Sgshapiro if (LogLevel <= level || msg == NULL || *msg == '\0') 379690792Sgshapiro return; 379790792Sgshapiro 379890792Sgshapiro /* Clear $h so relay= doesn't get mislogged by logdelivery() */ 379990792Sgshapiro macdefine(&e->e_macro, A_PERM, 'h', NULL); 380090792Sgshapiro 380190792Sgshapiro /* Log who the mail would have gone to */ 380290792Sgshapiro for (a = e->e_sendqueue; a != NULL; a = a->q_next) 380390792Sgshapiro { 380490792Sgshapiro if (!QS_IS_UNDELIVERED(a->q_state) && !all) 380590792Sgshapiro continue; 380690792Sgshapiro e->e_to = a->q_paddr; 380790792Sgshapiro logdelivery(NULL, NULL, a->q_status, msg, NULL, 380890792Sgshapiro (time_t) 0, e); 380990792Sgshapiro } 381090792Sgshapiro e->e_to = NULL; 381190792Sgshapiro} 381290792Sgshapiro/* 381338032Speter** CHECKSMTPATTACK -- check for denial-of-service attack by repetition 381438032Speter** 381538032Speter** Parameters: 381638032Speter** pcounter -- pointer to a counter for this command. 381738032Speter** maxcount -- maximum value for this counter before we 381838032Speter** slow down. 381964562Sgshapiro** waitnow -- sleep now (in this routine)? 382038032Speter** cname -- command name for logging. 382138032Speter** e -- the current envelope. 382238032Speter** 382338032Speter** Returns: 3824132943Sgshapiro** time to wait, 3825132943Sgshapiro** STOP_ATTACK if twice as many commands as allowed and 3826132943Sgshapiro** MaxChildren > 0. 382738032Speter** 382838032Speter** Side Effects: 382938032Speter** Slows down if we seem to be under attack. 383038032Speter*/ 383138032Speter 383264562Sgshapirostatic time_t 383364562Sgshapirochecksmtpattack(pcounter, maxcount, waitnow, cname, e) 383490792Sgshapiro volatile unsigned int *pcounter; 3835132943Sgshapiro unsigned int maxcount; 383664562Sgshapiro bool waitnow; 383738032Speter char *cname; 383838032Speter ENVELOPE *e; 383938032Speter{ 384090792Sgshapiro if (maxcount <= 0) /* no limit */ 384190792Sgshapiro return (time_t) 0; 384290792Sgshapiro 384338032Speter if (++(*pcounter) >= maxcount) 384438032Speter { 3845132943Sgshapiro unsigned int shift; 384664562Sgshapiro time_t s; 384764562Sgshapiro 384838032Speter if (*pcounter == maxcount && LogLevel > 5) 384938032Speter { 385038032Speter sm_syslog(LOG_INFO, e->e_id, 3851110560Sgshapiro "%s: possible SMTP attack: command=%.40s, count=%u", 385277349Sgshapiro CurSmtpClient, cname, *pcounter); 385338032Speter } 3854132943Sgshapiro shift = *pcounter - maxcount; 3855132943Sgshapiro s = 1 << shift; 3856132943Sgshapiro if (shift > MAXSHIFT || s >= MAXTIMEOUT || s <= 0) 385764562Sgshapiro s = MAXTIMEOUT; 385890792Sgshapiro 3859132943Sgshapiro#define IS_ATTACK(s) ((MaxChildren > 0 && *pcounter >= maxcount * 2) \ 3860132943Sgshapiro ? STOP_ATTACK : (time_t) s) 3861132943Sgshapiro 386264562Sgshapiro /* sleep at least 1 second before returning */ 386364562Sgshapiro (void) sleep(*pcounter / maxcount); 386464562Sgshapiro s -= *pcounter / maxcount; 3865132943Sgshapiro if (s >= MAXTIMEOUT || s < 0) 3866132943Sgshapiro s = MAXTIMEOUT; 3867132943Sgshapiro if (waitnow && s > 0) 386864562Sgshapiro { 386964562Sgshapiro (void) sleep(s); 3870132943Sgshapiro return IS_ATTACK(0); 387164562Sgshapiro } 3872132943Sgshapiro return IS_ATTACK(s); 387338032Speter } 387490792Sgshapiro return (time_t) 0; 387538032Speter} 387690792Sgshapiro/* 387790792Sgshapiro** SETUP_SMTPD_IO -- setup I/O fd correctly for the SMTP server 387890792Sgshapiro** 387990792Sgshapiro** Parameters: 388090792Sgshapiro** none. 388190792Sgshapiro** 388290792Sgshapiro** Returns: 388390792Sgshapiro** nothing. 388490792Sgshapiro** 388590792Sgshapiro** Side Effects: 388690792Sgshapiro** may change I/O fd. 388790792Sgshapiro*/ 388890792Sgshapiro 388990792Sgshapirostatic void 389090792Sgshapirosetup_smtpd_io() 389190792Sgshapiro{ 389290792Sgshapiro int inchfd, outchfd, outfd; 389390792Sgshapiro 389490792Sgshapiro inchfd = sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL); 389590792Sgshapiro outchfd = sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL); 389690792Sgshapiro outfd = sm_io_getinfo(smioout, SM_IO_WHAT_FD, NULL); 389790792Sgshapiro if (outchfd != outfd) 389890792Sgshapiro { 389990792Sgshapiro /* arrange for debugging output to go to remote host */ 390090792Sgshapiro (void) dup2(outchfd, outfd); 390190792Sgshapiro } 390290792Sgshapiro 390390792Sgshapiro /* 390490792Sgshapiro ** if InChannel and OutChannel are stdin/stdout 390590792Sgshapiro ** and connected to ttys 390690792Sgshapiro ** and fcntl(STDIN, F_SETFL, O_NONBLOCKING) also changes STDOUT, 390790792Sgshapiro ** then "chain" them together. 390890792Sgshapiro */ 390990792Sgshapiro 391090792Sgshapiro if (inchfd == STDIN_FILENO && outchfd == STDOUT_FILENO && 391190792Sgshapiro isatty(inchfd) && isatty(outchfd)) 391290792Sgshapiro { 391390792Sgshapiro int inmode, outmode; 391490792Sgshapiro 391590792Sgshapiro inmode = fcntl(inchfd, F_GETFL, 0); 391690792Sgshapiro if (inmode == -1) 391790792Sgshapiro { 391890792Sgshapiro if (LogLevel > 11) 391990792Sgshapiro sm_syslog(LOG_INFO, NOQID, 392090792Sgshapiro "fcntl(inchfd, F_GETFL) failed: %s", 392190792Sgshapiro sm_errstring(errno)); 392290792Sgshapiro return; 392390792Sgshapiro } 392490792Sgshapiro outmode = fcntl(outchfd, F_GETFL, 0); 392590792Sgshapiro if (outmode == -1) 392690792Sgshapiro { 392790792Sgshapiro if (LogLevel > 11) 392890792Sgshapiro sm_syslog(LOG_INFO, NOQID, 392990792Sgshapiro "fcntl(outchfd, F_GETFL) failed: %s", 393090792Sgshapiro sm_errstring(errno)); 393190792Sgshapiro return; 393290792Sgshapiro } 393390792Sgshapiro if (bitset(O_NONBLOCK, inmode) || 393490792Sgshapiro bitset(O_NONBLOCK, outmode) || 393590792Sgshapiro fcntl(inchfd, F_SETFL, inmode | O_NONBLOCK) == -1) 393690792Sgshapiro return; 393790792Sgshapiro outmode = fcntl(outchfd, F_GETFL, 0); 393890792Sgshapiro if (outmode != -1 && bitset(O_NONBLOCK, outmode)) 393990792Sgshapiro { 394090792Sgshapiro /* changing InChannel also changes OutChannel */ 394190792Sgshapiro sm_io_automode(OutChannel, InChannel); 394290792Sgshapiro if (tTd(97, 4) && LogLevel > 9) 394390792Sgshapiro sm_syslog(LOG_INFO, NOQID, 394490792Sgshapiro "set automode for I (%d)/O (%d) in SMTP server", 394590792Sgshapiro inchfd, outchfd); 394690792Sgshapiro } 394790792Sgshapiro 394890792Sgshapiro /* undo change of inchfd */ 394990792Sgshapiro (void) fcntl(inchfd, F_SETFL, inmode); 395090792Sgshapiro } 395190792Sgshapiro} 395290792Sgshapiro/* 395338032Speter** SKIPWORD -- skip a fixed word. 395438032Speter** 395538032Speter** Parameters: 395638032Speter** p -- place to start looking. 395738032Speter** w -- word to skip. 395838032Speter** 395938032Speter** Returns: 396038032Speter** p following w. 396138032Speter** NULL on error. 396238032Speter** 396338032Speter** Side Effects: 396438032Speter** clobbers the p data area. 396538032Speter*/ 396638032Speter 396738032Speterstatic char * 396838032Speterskipword(p, w) 396938032Speter register char *volatile p; 397038032Speter char *w; 397138032Speter{ 397238032Speter register char *q; 397338032Speter char *firstp = p; 397438032Speter 397538032Speter /* find beginning of word */ 397690792Sgshapiro SKIP_SPACE(p); 397738032Speter q = p; 397838032Speter 397938032Speter /* find end of word */ 398038032Speter while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p))) 398138032Speter p++; 398238032Speter while (isascii(*p) && isspace(*p)) 398338032Speter *p++ = '\0'; 398438032Speter if (*p != ':') 398538032Speter { 398638032Speter syntax: 398764562Sgshapiro usrerr("501 5.5.2 Syntax error in parameters scanning \"%s\"", 398838032Speter shortenstring(firstp, MAXSHORTSTR)); 398964562Sgshapiro return NULL; 399038032Speter } 399138032Speter *p++ = '\0'; 399290792Sgshapiro SKIP_SPACE(p); 399338032Speter 399438032Speter if (*p == '\0') 399538032Speter goto syntax; 399638032Speter 399738032Speter /* see if the input word matches desired word */ 399890792Sgshapiro if (sm_strcasecmp(q, w)) 399938032Speter goto syntax; 400038032Speter 400164562Sgshapiro return p; 400238032Speter} 4003159609Sgshapiro 400490792Sgshapiro/* 4005168515Sgshapiro** RESET_MAIL_ESMTP_ARGS -- process ESMTP arguments from MAIL line 4006168515Sgshapiro** 4007168515Sgshapiro** Parameters: 4008168515Sgshapiro** e -- the envelope. 4009168515Sgshapiro** 4010168515Sgshapiro** Returns: 4011168515Sgshapiro** none. 4012168515Sgshapiro*/ 4013168515Sgshapiro 4014168515Sgshapirovoid 4015168515Sgshapiroreset_mail_esmtp_args(e) 4016168515Sgshapiro ENVELOPE *e; 4017168515Sgshapiro{ 4018168515Sgshapiro /* "size": no reset */ 4019168515Sgshapiro 4020168515Sgshapiro /* "body" */ 4021168515Sgshapiro SevenBitInput = SevenBitInput_Saved; 4022168515Sgshapiro e->e_bodytype = NULL; 4023168515Sgshapiro 4024168515Sgshapiro /* "envid" */ 4025168515Sgshapiro e->e_envid = NULL; 4026168515Sgshapiro macdefine(&e->e_macro, A_PERM, macid("{dsn_envid}"), NULL); 4027168515Sgshapiro 4028168515Sgshapiro /* "ret" */ 4029168515Sgshapiro e->e_flags &= EF_RET_PARAM; 4030168515Sgshapiro e->e_flags &= EF_NO_BODY_RETN; 4031168515Sgshapiro macdefine(&e->e_macro, A_TEMP, macid("{dsn_ret}"), NULL); 4032168515Sgshapiro 4033168515Sgshapiro#if SASL 4034168515Sgshapiro /* "auth" */ 4035168515Sgshapiro macdefine(&e->e_macro, A_TEMP, macid("{auth_author}"), NULL); 4036168515Sgshapiro e->e_auth_param = ""; 4037168515Sgshapiro# if _FFR_AUTH_PASSING 4038168515Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 4039168515Sgshapiro macid("{auth_author}"), NULL); 4040168515Sgshapiro# endif /* _FFR_AUTH_PASSING */ 4041168515Sgshapiro#endif /* SASL */ 4042168515Sgshapiro 4043168515Sgshapiro /* "by" */ 4044168515Sgshapiro e->e_deliver_by = 0; 4045168515Sgshapiro e->e_dlvr_flag = 0; 4046168515Sgshapiro} 4047168515Sgshapiro 4048168515Sgshapiro/* 404938032Speter** MAIL_ESMTP_ARGS -- process ESMTP arguments from MAIL line 405038032Speter** 405138032Speter** Parameters: 4052168515Sgshapiro** a -- address (unused, for compatibility with rcpt_esmtp_args) 405338032Speter** kp -- the parameter key. 405438032Speter** vp -- the value of that parameter. 405538032Speter** e -- the envelope. 405638032Speter** 405738032Speter** Returns: 405838032Speter** none. 405938032Speter*/ 406038032Speter 4061168515Sgshapirovoid 4062168515Sgshapiromail_esmtp_args(a, kp, vp, e) 4063168515Sgshapiro ADDRESS *a; 406438032Speter char *kp; 406538032Speter char *vp; 406638032Speter ENVELOPE *e; 406738032Speter{ 406890792Sgshapiro if (sm_strcasecmp(kp, "size") == 0) 406938032Speter { 407038032Speter if (vp == NULL) 407138032Speter { 407264562Sgshapiro usrerr("501 5.5.2 SIZE requires a value"); 407338032Speter /* NOTREACHED */ 407438032Speter } 407590792Sgshapiro macdefine(&e->e_macro, A_TEMP, macid("{msg_size}"), vp); 407690792Sgshapiro errno = 0; 407771345Sgshapiro e->e_msgsize = strtol(vp, (char **) NULL, 10); 407866494Sgshapiro if (e->e_msgsize == LONG_MAX && errno == ERANGE) 407966494Sgshapiro { 408066494Sgshapiro usrerr("552 5.2.3 Message size exceeds maximum value"); 408166494Sgshapiro /* NOTREACHED */ 408266494Sgshapiro } 408390792Sgshapiro if (e->e_msgsize < 0) 408490792Sgshapiro { 408590792Sgshapiro usrerr("552 5.2.3 Message size invalid"); 408690792Sgshapiro /* NOTREACHED */ 408790792Sgshapiro } 408838032Speter } 408990792Sgshapiro else if (sm_strcasecmp(kp, "body") == 0) 409038032Speter { 409138032Speter if (vp == NULL) 409238032Speter { 409364562Sgshapiro usrerr("501 5.5.2 BODY requires a value"); 409438032Speter /* NOTREACHED */ 409538032Speter } 409690792Sgshapiro else if (sm_strcasecmp(vp, "8bitmime") == 0) 409738032Speter { 409890792Sgshapiro SevenBitInput = false; 409938032Speter } 410090792Sgshapiro else if (sm_strcasecmp(vp, "7bit") == 0) 410138032Speter { 410290792Sgshapiro SevenBitInput = true; 410338032Speter } 410438032Speter else 410538032Speter { 410690792Sgshapiro usrerr("501 5.5.4 Unknown BODY type %s", vp); 410738032Speter /* NOTREACHED */ 410838032Speter } 410990792Sgshapiro e->e_bodytype = sm_rpool_strdup_x(e->e_rpool, vp); 411038032Speter } 411190792Sgshapiro else if (sm_strcasecmp(kp, "envid") == 0) 411238032Speter { 4113168515Sgshapiro if (!bitset(SRV_OFFER_DSN, e->e_features)) 411464562Sgshapiro { 411564562Sgshapiro usrerr("504 5.7.0 Sorry, ENVID not supported, we do not allow DSN"); 411664562Sgshapiro /* NOTREACHED */ 411764562Sgshapiro } 411838032Speter if (vp == NULL) 411938032Speter { 412064562Sgshapiro usrerr("501 5.5.2 ENVID requires a value"); 412138032Speter /* NOTREACHED */ 412238032Speter } 412338032Speter if (!xtextok(vp)) 412438032Speter { 412564562Sgshapiro usrerr("501 5.5.4 Syntax error in ENVID parameter value"); 412638032Speter /* NOTREACHED */ 412738032Speter } 412838032Speter if (e->e_envid != NULL) 412938032Speter { 413064562Sgshapiro usrerr("501 5.5.0 Duplicate ENVID parameter"); 413138032Speter /* NOTREACHED */ 413238032Speter } 413390792Sgshapiro e->e_envid = sm_rpool_strdup_x(e->e_rpool, vp); 413490792Sgshapiro macdefine(&e->e_macro, A_PERM, 413590792Sgshapiro macid("{dsn_envid}"), e->e_envid); 413638032Speter } 413790792Sgshapiro else if (sm_strcasecmp(kp, "ret") == 0) 413838032Speter { 4139168515Sgshapiro if (!bitset(SRV_OFFER_DSN, e->e_features)) 414064562Sgshapiro { 414164562Sgshapiro usrerr("504 5.7.0 Sorry, RET not supported, we do not allow DSN"); 414264562Sgshapiro /* NOTREACHED */ 414364562Sgshapiro } 414438032Speter if (vp == NULL) 414538032Speter { 414664562Sgshapiro usrerr("501 5.5.2 RET requires a value"); 414738032Speter /* NOTREACHED */ 414838032Speter } 414938032Speter if (bitset(EF_RET_PARAM, e->e_flags)) 415038032Speter { 415164562Sgshapiro usrerr("501 5.5.0 Duplicate RET parameter"); 415238032Speter /* NOTREACHED */ 415338032Speter } 415438032Speter e->e_flags |= EF_RET_PARAM; 415590792Sgshapiro if (sm_strcasecmp(vp, "hdrs") == 0) 415638032Speter e->e_flags |= EF_NO_BODY_RETN; 415790792Sgshapiro else if (sm_strcasecmp(vp, "full") != 0) 415838032Speter { 415964562Sgshapiro usrerr("501 5.5.2 Bad argument \"%s\" to RET", vp); 416038032Speter /* NOTREACHED */ 416138032Speter } 416290792Sgshapiro macdefine(&e->e_macro, A_TEMP, macid("{dsn_ret}"), vp); 416338032Speter } 416490792Sgshapiro#if SASL 416590792Sgshapiro else if (sm_strcasecmp(kp, "auth") == 0) 416664562Sgshapiro { 416764562Sgshapiro int len; 416864562Sgshapiro char *q; 416964562Sgshapiro char *auth_param; /* the value of the AUTH=x */ 417064562Sgshapiro bool saveQuickAbort = QuickAbort; 417164562Sgshapiro bool saveSuprErrs = SuprErrs; 417290792Sgshapiro bool saveExitStat = ExitStat; 417364562Sgshapiro 417464562Sgshapiro if (vp == NULL) 417564562Sgshapiro { 417664562Sgshapiro usrerr("501 5.5.2 AUTH= requires a value"); 417764562Sgshapiro /* NOTREACHED */ 417864562Sgshapiro } 417964562Sgshapiro if (e->e_auth_param != NULL) 418064562Sgshapiro { 418164562Sgshapiro usrerr("501 5.5.0 Duplicate AUTH parameter"); 418264562Sgshapiro /* NOTREACHED */ 418364562Sgshapiro } 418464562Sgshapiro if ((q = strchr(vp, ' ')) != NULL) 418564562Sgshapiro len = q - vp + 1; 418664562Sgshapiro else 418764562Sgshapiro len = strlen(vp) + 1; 418864562Sgshapiro auth_param = xalloc(len); 418990792Sgshapiro (void) sm_strlcpy(auth_param, vp, len); 419064562Sgshapiro if (!xtextok(auth_param)) 419164562Sgshapiro { 419264562Sgshapiro usrerr("501 5.5.4 Syntax error in AUTH parameter value"); 419364562Sgshapiro /* just a warning? */ 419464562Sgshapiro /* NOTREACHED */ 419564562Sgshapiro } 419664562Sgshapiro 419764562Sgshapiro /* XXX define this always or only if trusted? */ 4198132943Sgshapiro macdefine(&e->e_macro, A_TEMP, macid("{auth_author}"), 4199132943Sgshapiro auth_param); 420064562Sgshapiro 420164562Sgshapiro /* 420264562Sgshapiro ** call Strust_auth to find out whether 420364562Sgshapiro ** auth_param is acceptable (trusted) 420464562Sgshapiro ** we shouldn't trust it if not authenticated 420564562Sgshapiro ** (required by RFC, leave it to ruleset?) 420664562Sgshapiro */ 420764562Sgshapiro 420890792Sgshapiro SuprErrs = true; 420990792Sgshapiro QuickAbort = false; 421064562Sgshapiro if (strcmp(auth_param, "<>") != 0 && 4211132943Sgshapiro (rscheck("trust_auth", auth_param, NULL, e, RSF_RMCOMM, 4212168515Sgshapiro 9, NULL, NOQID, NULL) != EX_OK || Errors > 0)) 421364562Sgshapiro { 421464562Sgshapiro if (tTd(95, 8)) 421564562Sgshapiro { 421664562Sgshapiro q = e->e_auth_param; 421790792Sgshapiro sm_dprintf("auth=\"%.100s\" not trusted user=\"%.100s\"\n", 4218132943Sgshapiro auth_param, (q == NULL) ? "" : q); 421964562Sgshapiro } 422090792Sgshapiro 422164562Sgshapiro /* not trusted */ 422290792Sgshapiro e->e_auth_param = "<>"; 422390792Sgshapiro# if _FFR_AUTH_PASSING 422490792Sgshapiro macdefine(&BlankEnvelope.e_macro, A_PERM, 422590792Sgshapiro macid("{auth_author}"), NULL); 422690792Sgshapiro# endif /* _FFR_AUTH_PASSING */ 422764562Sgshapiro } 422864562Sgshapiro else 422964562Sgshapiro { 423064562Sgshapiro if (tTd(95, 8)) 4231132943Sgshapiro sm_dprintf("auth=\"%.100s\" trusted\n", auth_param); 423290792Sgshapiro e->e_auth_param = sm_rpool_strdup_x(e->e_rpool, 423390792Sgshapiro auth_param); 423464562Sgshapiro } 423590792Sgshapiro sm_free(auth_param); /* XXX */ 423677349Sgshapiro 423764562Sgshapiro /* reset values */ 423864562Sgshapiro Errors = 0; 423964562Sgshapiro QuickAbort = saveQuickAbort; 424064562Sgshapiro SuprErrs = saveSuprErrs; 424190792Sgshapiro ExitStat = saveExitStat; 424264562Sgshapiro } 424390792Sgshapiro#endif /* SASL */ 424490792Sgshapiro#define PRTCHAR(c) ((isascii(c) && isprint(c)) ? (c) : '?') 424590792Sgshapiro 424690792Sgshapiro /* 424790792Sgshapiro ** "by" is only accepted if DeliverByMin >= 0. 424890792Sgshapiro ** We maybe could add this to the list of server_features. 424990792Sgshapiro */ 425090792Sgshapiro 425190792Sgshapiro else if (sm_strcasecmp(kp, "by") == 0 && DeliverByMin >= 0) 425290792Sgshapiro { 425390792Sgshapiro char *s; 425490792Sgshapiro 425590792Sgshapiro if (vp == NULL) 425690792Sgshapiro { 425790792Sgshapiro usrerr("501 5.5.2 BY= requires a value"); 425890792Sgshapiro /* NOTREACHED */ 425990792Sgshapiro } 426090792Sgshapiro errno = 0; 426190792Sgshapiro e->e_deliver_by = strtol(vp, &s, 10); 426290792Sgshapiro if (e->e_deliver_by == LONG_MIN || 426390792Sgshapiro e->e_deliver_by == LONG_MAX || 426490792Sgshapiro e->e_deliver_by > 999999999l || 426590792Sgshapiro e->e_deliver_by < -999999999l) 426690792Sgshapiro { 426790792Sgshapiro usrerr("501 5.5.2 BY=%s out of range", vp); 426890792Sgshapiro /* NOTREACHED */ 426990792Sgshapiro } 427090792Sgshapiro if (s == NULL || *s != ';') 427190792Sgshapiro { 427290792Sgshapiro usrerr("501 5.5.2 BY= missing ';'"); 427390792Sgshapiro /* NOTREACHED */ 427490792Sgshapiro } 427590792Sgshapiro e->e_dlvr_flag = 0; 427690792Sgshapiro ++s; /* XXX: spaces allowed? */ 427790792Sgshapiro SKIP_SPACE(s); 427890792Sgshapiro switch (tolower(*s)) 427990792Sgshapiro { 428090792Sgshapiro case 'n': 428190792Sgshapiro e->e_dlvr_flag = DLVR_NOTIFY; 428290792Sgshapiro break; 428390792Sgshapiro case 'r': 428490792Sgshapiro e->e_dlvr_flag = DLVR_RETURN; 428590792Sgshapiro if (e->e_deliver_by <= 0) 428690792Sgshapiro { 428790792Sgshapiro usrerr("501 5.5.4 mode R requires BY time > 0"); 428890792Sgshapiro /* NOTREACHED */ 428990792Sgshapiro } 429090792Sgshapiro if (DeliverByMin > 0 && e->e_deliver_by > 0 && 429190792Sgshapiro e->e_deliver_by < DeliverByMin) 429290792Sgshapiro { 429390792Sgshapiro usrerr("555 5.5.2 time %ld less than %ld", 429490792Sgshapiro e->e_deliver_by, (long) DeliverByMin); 429590792Sgshapiro /* NOTREACHED */ 429690792Sgshapiro } 429790792Sgshapiro break; 429890792Sgshapiro default: 429990792Sgshapiro usrerr("501 5.5.2 illegal by-mode '%c'", PRTCHAR(*s)); 430090792Sgshapiro /* NOTREACHED */ 430190792Sgshapiro } 430290792Sgshapiro ++s; /* XXX: spaces allowed? */ 430390792Sgshapiro SKIP_SPACE(s); 430490792Sgshapiro switch (tolower(*s)) 430590792Sgshapiro { 430690792Sgshapiro case 't': 430790792Sgshapiro e->e_dlvr_flag |= DLVR_TRACE; 430890792Sgshapiro break; 430990792Sgshapiro case '\0': 431090792Sgshapiro break; 431190792Sgshapiro default: 431290792Sgshapiro usrerr("501 5.5.2 illegal by-trace '%c'", PRTCHAR(*s)); 431390792Sgshapiro /* NOTREACHED */ 431490792Sgshapiro } 431590792Sgshapiro 431690792Sgshapiro /* XXX: check whether more characters follow? */ 431790792Sgshapiro } 431838032Speter else 431938032Speter { 432066494Sgshapiro usrerr("555 5.5.4 %s parameter unrecognized", kp); 432138032Speter /* NOTREACHED */ 432238032Speter } 432338032Speter} 4324168515Sgshapiro 432590792Sgshapiro/* 432638032Speter** RCPT_ESMTP_ARGS -- process ESMTP arguments from RCPT line 432738032Speter** 432838032Speter** Parameters: 432938032Speter** a -- the address corresponding to the To: parameter. 433038032Speter** kp -- the parameter key. 433138032Speter** vp -- the value of that parameter. 433238032Speter** e -- the envelope. 433338032Speter** 433438032Speter** Returns: 433538032Speter** none. 433638032Speter*/ 433738032Speter 4338168515Sgshapirovoid 4339168515Sgshapirorcpt_esmtp_args(a, kp, vp, e) 434038032Speter ADDRESS *a; 434138032Speter char *kp; 434238032Speter char *vp; 434338032Speter ENVELOPE *e; 434438032Speter{ 434590792Sgshapiro if (sm_strcasecmp(kp, "notify") == 0) 434638032Speter { 434738032Speter char *p; 434838032Speter 4349168515Sgshapiro if (!bitset(SRV_OFFER_DSN, e->e_features)) 435064562Sgshapiro { 435164562Sgshapiro usrerr("504 5.7.0 Sorry, NOTIFY not supported, we do not allow DSN"); 435264562Sgshapiro /* NOTREACHED */ 435364562Sgshapiro } 435438032Speter if (vp == NULL) 435538032Speter { 435664562Sgshapiro usrerr("501 5.5.2 NOTIFY requires a value"); 435738032Speter /* NOTREACHED */ 435838032Speter } 435938032Speter a->q_flags &= ~(QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY); 436038032Speter a->q_flags |= QHASNOTIFY; 436190792Sgshapiro macdefine(&e->e_macro, A_TEMP, macid("{dsn_notify}"), vp); 436264562Sgshapiro 436390792Sgshapiro if (sm_strcasecmp(vp, "never") == 0) 436438032Speter return; 436538032Speter for (p = vp; p != NULL; vp = p) 436638032Speter { 4367141858Sgshapiro char *s; 4368141858Sgshapiro 4369141858Sgshapiro s = p = strchr(p, ','); 437038032Speter if (p != NULL) 437138032Speter *p++ = '\0'; 437290792Sgshapiro if (sm_strcasecmp(vp, "success") == 0) 437338032Speter a->q_flags |= QPINGONSUCCESS; 437490792Sgshapiro else if (sm_strcasecmp(vp, "failure") == 0) 437538032Speter a->q_flags |= QPINGONFAILURE; 437690792Sgshapiro else if (sm_strcasecmp(vp, "delay") == 0) 437738032Speter a->q_flags |= QPINGONDELAY; 437838032Speter else 437938032Speter { 438064562Sgshapiro usrerr("501 5.5.4 Bad argument \"%s\" to NOTIFY", 438138032Speter vp); 438238032Speter /* NOTREACHED */ 438338032Speter } 4384141858Sgshapiro if (s != NULL) 4385141858Sgshapiro *s = ','; 438638032Speter } 438738032Speter } 438890792Sgshapiro else if (sm_strcasecmp(kp, "orcpt") == 0) 438938032Speter { 4390168515Sgshapiro if (!bitset(SRV_OFFER_DSN, e->e_features)) 439164562Sgshapiro { 439264562Sgshapiro usrerr("504 5.7.0 Sorry, ORCPT not supported, we do not allow DSN"); 439364562Sgshapiro /* NOTREACHED */ 439464562Sgshapiro } 439538032Speter if (vp == NULL) 439638032Speter { 439764562Sgshapiro usrerr("501 5.5.2 ORCPT requires a value"); 439838032Speter /* NOTREACHED */ 439938032Speter } 440038032Speter if (strchr(vp, ';') == NULL || !xtextok(vp)) 440138032Speter { 440264562Sgshapiro usrerr("501 5.5.4 Syntax error in ORCPT parameter value"); 440338032Speter /* NOTREACHED */ 440438032Speter } 440538032Speter if (a->q_orcpt != NULL) 440638032Speter { 440764562Sgshapiro usrerr("501 5.5.0 Duplicate ORCPT parameter"); 440838032Speter /* NOTREACHED */ 440938032Speter } 441090792Sgshapiro a->q_orcpt = sm_rpool_strdup_x(e->e_rpool, vp); 441138032Speter } 441238032Speter else 441338032Speter { 441466494Sgshapiro usrerr("555 5.5.4 %s parameter unrecognized", kp); 441538032Speter /* NOTREACHED */ 441638032Speter } 441738032Speter} 441890792Sgshapiro/* 441938032Speter** PRINTVRFYADDR -- print an entry in the verify queue 442038032Speter** 442138032Speter** Parameters: 442290792Sgshapiro** a -- the address to print. 442338032Speter** last -- set if this is the last one. 442438032Speter** vrfy -- set if this is a VRFY command. 442538032Speter** 442638032Speter** Returns: 442738032Speter** none. 442838032Speter** 442938032Speter** Side Effects: 443038032Speter** Prints the appropriate 250 codes. 443138032Speter*/ 443264562Sgshapiro#define OFFF (3 + 1 + 5 + 1) /* offset in fmt: SMTP reply + enh. code */ 443338032Speter 443464562Sgshapirostatic void 443538032Speterprintvrfyaddr(a, last, vrfy) 443638032Speter register ADDRESS *a; 443738032Speter bool last; 443838032Speter bool vrfy; 443938032Speter{ 444064562Sgshapiro char fmtbuf[30]; 444138032Speter 444238032Speter if (vrfy && a->q_mailer != NULL && 444338032Speter !bitnset(M_VRFY250, a->q_mailer->m_flags)) 4444168515Sgshapiro (void) sm_strlcpy(fmtbuf, "252", sizeof(fmtbuf)); 444538032Speter else 4446168515Sgshapiro (void) sm_strlcpy(fmtbuf, "250", sizeof(fmtbuf)); 444738032Speter fmtbuf[3] = last ? ' ' : '-'; 4448168515Sgshapiro (void) sm_strlcpy(&fmtbuf[4], "2.1.5 ", sizeof(fmtbuf) - 4); 444938032Speter if (a->q_fullname == NULL) 445038032Speter { 445164562Sgshapiro if ((a->q_mailer == NULL || 445264562Sgshapiro a->q_mailer->m_addrtype == NULL || 445390792Sgshapiro sm_strcasecmp(a->q_mailer->m_addrtype, "rfc822") == 0) && 445464562Sgshapiro strchr(a->q_user, '@') == NULL) 445590792Sgshapiro (void) sm_strlcpy(&fmtbuf[OFFF], "<%s@%s>", 4456168515Sgshapiro sizeof(fmtbuf) - OFFF); 445738032Speter else 445890792Sgshapiro (void) sm_strlcpy(&fmtbuf[OFFF], "<%s>", 4459168515Sgshapiro sizeof(fmtbuf) - OFFF); 446038032Speter message(fmtbuf, a->q_user, MyHostName); 446138032Speter } 446238032Speter else 446338032Speter { 446464562Sgshapiro if ((a->q_mailer == NULL || 446564562Sgshapiro a->q_mailer->m_addrtype == NULL || 446690792Sgshapiro sm_strcasecmp(a->q_mailer->m_addrtype, "rfc822") == 0) && 446764562Sgshapiro strchr(a->q_user, '@') == NULL) 446890792Sgshapiro (void) sm_strlcpy(&fmtbuf[OFFF], "%s <%s@%s>", 4469168515Sgshapiro sizeof(fmtbuf) - OFFF); 447038032Speter else 447190792Sgshapiro (void) sm_strlcpy(&fmtbuf[OFFF], "%s <%s>", 4472168515Sgshapiro sizeof(fmtbuf) - OFFF); 447338032Speter message(fmtbuf, a->q_fullname, a->q_user, MyHostName); 447438032Speter } 447538032Speter} 447638032Speter 447790792Sgshapiro#if SASL 447890792Sgshapiro/* 447964562Sgshapiro** SASLMECHS -- get list of possible AUTH mechanisms 448064562Sgshapiro** 448164562Sgshapiro** Parameters: 448290792Sgshapiro** conn -- SASL connection info. 448390792Sgshapiro** mechlist -- output parameter for list of mechanisms. 448464562Sgshapiro** 448564562Sgshapiro** Returns: 448690792Sgshapiro** number of mechs. 448764562Sgshapiro*/ 448864562Sgshapiro 448964562Sgshapirostatic int 449064562Sgshapirosaslmechs(conn, mechlist) 449164562Sgshapiro sasl_conn_t *conn; 449264562Sgshapiro char **mechlist; 449364562Sgshapiro{ 449464562Sgshapiro int len, num, result; 449564562Sgshapiro 449664562Sgshapiro /* "user" is currently unused */ 449798121Sgshapiro# if SASL >= 20000 449898121Sgshapiro result = sasl_listmech(conn, NULL, 449998121Sgshapiro "", " ", "", (const char **) mechlist, 4500120256Sgshapiro (unsigned int *)&len, &num); 450198121Sgshapiro# else /* SASL >= 20000 */ 450264562Sgshapiro result = sasl_listmech(conn, "user", /* XXX */ 450364562Sgshapiro "", " ", "", mechlist, 450490792Sgshapiro (unsigned int *)&len, (unsigned int *)&num); 450598121Sgshapiro# endif /* SASL >= 20000 */ 450690792Sgshapiro if (result != SASL_OK) 450764562Sgshapiro { 450890792Sgshapiro if (LogLevel > 9) 450990792Sgshapiro sm_syslog(LOG_WARNING, NOQID, 451090792Sgshapiro "AUTH error: listmech=%d, num=%d", 451190792Sgshapiro result, num); 451290792Sgshapiro num = 0; 451390792Sgshapiro } 451490792Sgshapiro if (num > 0) 451590792Sgshapiro { 451664562Sgshapiro if (LogLevel > 11) 451764562Sgshapiro sm_syslog(LOG_INFO, NOQID, 451890792Sgshapiro "AUTH: available mech=%s, allowed mech=%s", 451964562Sgshapiro *mechlist, AuthMechanisms); 452090792Sgshapiro *mechlist = intersect(AuthMechanisms, *mechlist, NULL); 452164562Sgshapiro } 452264562Sgshapiro else 452364562Sgshapiro { 452490792Sgshapiro *mechlist = NULL; /* be paranoid... */ 452590792Sgshapiro if (result == SASL_OK && LogLevel > 9) 452664562Sgshapiro sm_syslog(LOG_WARNING, NOQID, 452790792Sgshapiro "AUTH warning: no mechanisms"); 452864562Sgshapiro } 452964562Sgshapiro return num; 453064562Sgshapiro} 453198121Sgshapiro 453298121Sgshapiro# if SASL >= 20000 453390792Sgshapiro/* 453464562Sgshapiro** PROXY_POLICY -- define proxy policy for AUTH 453564562Sgshapiro** 453664562Sgshapiro** Parameters: 453798121Sgshapiro** conn -- unused. 453890792Sgshapiro** context -- unused. 453998121Sgshapiro** requested_user -- authorization identity. 454098121Sgshapiro** rlen -- authorization identity length. 454190792Sgshapiro** auth_identity -- authentication identity. 454298121Sgshapiro** alen -- authentication identity length. 454398121Sgshapiro** def_realm -- default user realm. 454498121Sgshapiro** urlen -- user realm length. 454598121Sgshapiro** propctx -- unused. 454698121Sgshapiro** 454798121Sgshapiro** Returns: 454898121Sgshapiro** ok? 454998121Sgshapiro** 455098121Sgshapiro** Side Effects: 455198121Sgshapiro** sets {auth_authen} macro. 455298121Sgshapiro*/ 455398121Sgshapiro 455498121Sgshapiroint 455598121Sgshapiroproxy_policy(conn, context, requested_user, rlen, auth_identity, alen, 455698121Sgshapiro def_realm, urlen, propctx) 455798121Sgshapiro sasl_conn_t *conn; 455898121Sgshapiro void *context; 455998121Sgshapiro const char *requested_user; 456098121Sgshapiro unsigned rlen; 456198121Sgshapiro const char *auth_identity; 456298121Sgshapiro unsigned alen; 456398121Sgshapiro const char *def_realm; 456498121Sgshapiro unsigned urlen; 456598121Sgshapiro struct propctx *propctx; 456698121Sgshapiro{ 456798121Sgshapiro if (auth_identity == NULL) 456898121Sgshapiro return SASL_FAIL; 456998121Sgshapiro 457098121Sgshapiro macdefine(&BlankEnvelope.e_macro, A_TEMP, 457198121Sgshapiro macid("{auth_authen}"), (char *) auth_identity); 457298121Sgshapiro 457398121Sgshapiro return SASL_OK; 457498121Sgshapiro} 457598121Sgshapiro# else /* SASL >= 20000 */ 457698121Sgshapiro 457798121Sgshapiro/* 457898121Sgshapiro** PROXY_POLICY -- define proxy policy for AUTH 457998121Sgshapiro** 458098121Sgshapiro** Parameters: 458198121Sgshapiro** context -- unused. 458298121Sgshapiro** auth_identity -- authentication identity. 458390792Sgshapiro** requested_user -- authorization identity. 458490792Sgshapiro** user -- allowed user (output). 458590792Sgshapiro** errstr -- possible error string (output). 458664562Sgshapiro** 458764562Sgshapiro** Returns: 458864562Sgshapiro** ok? 458964562Sgshapiro*/ 459064562Sgshapiro 459164562Sgshapiroint 459264562Sgshapiroproxy_policy(context, auth_identity, requested_user, user, errstr) 459364562Sgshapiro void *context; 459464562Sgshapiro const char *auth_identity; 459564562Sgshapiro const char *requested_user; 459664562Sgshapiro const char **user; 459764562Sgshapiro const char **errstr; 459864562Sgshapiro{ 459964562Sgshapiro if (user == NULL || auth_identity == NULL) 460064562Sgshapiro return SASL_FAIL; 460164562Sgshapiro *user = newstr(auth_identity); 460264562Sgshapiro return SASL_OK; 460364562Sgshapiro} 460498121Sgshapiro# endif /* SASL >= 20000 */ 460590792Sgshapiro#endif /* SASL */ 460664562Sgshapiro 460790792Sgshapiro#if STARTTLS 460890792Sgshapiro/* 460990792Sgshapiro** INITSRVTLS -- initialize server side TLS 461064562Sgshapiro** 461164562Sgshapiro** Parameters: 461290792Sgshapiro** tls_ok -- should tls initialization be done? 461364562Sgshapiro** 461464562Sgshapiro** Returns: 461590792Sgshapiro** succeeded? 461664562Sgshapiro** 461764562Sgshapiro** Side Effects: 461890792Sgshapiro** sets tls_ok_srv which is a static variable in this module. 461990792Sgshapiro** Do NOT remove assignments to it! 462064562Sgshapiro*/ 462164562Sgshapiro 462266494Sgshapirobool 462390792Sgshapiroinitsrvtls(tls_ok) 462490792Sgshapiro bool tls_ok; 462564562Sgshapiro{ 462690792Sgshapiro if (!tls_ok) 462790792Sgshapiro return false; 462864562Sgshapiro 462990792Sgshapiro /* do NOT remove assignment */ 4630110560Sgshapiro tls_ok_srv = inittls(&srv_ctx, TLS_Srv_Opts, true, SrvCertFile, 4631110560Sgshapiro SrvKeyFile, CACertPath, CACertFile, DHParams); 463290792Sgshapiro return tls_ok_srv; 463364562Sgshapiro} 463490792Sgshapiro#endif /* STARTTLS */ 463564562Sgshapiro/* 463690792Sgshapiro** SRVFEATURES -- get features for SMTP server 463764562Sgshapiro** 463864562Sgshapiro** Parameters: 463990792Sgshapiro** e -- envelope (should be session context). 464090792Sgshapiro** clientname -- name of client. 464190792Sgshapiro** features -- default features for this invocation. 464264562Sgshapiro** 464364562Sgshapiro** Returns: 464490792Sgshapiro** server features. 464564562Sgshapiro*/ 464664562Sgshapiro 464790792Sgshapiro/* table with options: it uses just one character, how about strings? */ 464890792Sgshapirostatic struct 464964562Sgshapiro{ 465090792Sgshapiro char srvf_opt; 465190792Sgshapiro unsigned int srvf_flag; 465290792Sgshapiro} srv_feat_table[] = 465364562Sgshapiro{ 465490792Sgshapiro { 'A', SRV_OFFER_AUTH }, 4655132943Sgshapiro { 'B', SRV_OFFER_VERB }, 4656132943Sgshapiro { 'C', SRV_REQ_SEC }, 4657132943Sgshapiro { 'D', SRV_OFFER_DSN }, 4658132943Sgshapiro { 'E', SRV_OFFER_ETRN }, 4659132943Sgshapiro { 'L', SRV_REQ_AUTH }, 466090792Sgshapiro#if PIPELINING 466190792Sgshapiro# if _FFR_NO_PIPE 466290792Sgshapiro { 'N', SRV_NO_PIPE }, 466390792Sgshapiro# endif /* _FFR_NO_PIPE */ 466490792Sgshapiro { 'P', SRV_OFFER_PIPE }, 466590792Sgshapiro#endif /* PIPELINING */ 4666132943Sgshapiro { 'R', SRV_VRFY_CLT }, /* same as V; not documented */ 466790792Sgshapiro { 'S', SRV_OFFER_TLS }, 466890792Sgshapiro/* { 'T', SRV_TMP_FAIL }, */ 466990792Sgshapiro { 'V', SRV_VRFY_CLT }, 4670132943Sgshapiro { 'X', SRV_OFFER_EXPN }, 467190792Sgshapiro/* { 'Y', SRV_OFFER_VRFY }, */ 467290792Sgshapiro { '\0', SRV_NONE } 467390792Sgshapiro}; 467464562Sgshapiro 467590792Sgshapirostatic unsigned int 467690792Sgshapirosrvfeatures(e, clientname, features) 467790792Sgshapiro ENVELOPE *e; 467890792Sgshapiro char *clientname; 467990792Sgshapiro unsigned int features; 468077349Sgshapiro{ 468190792Sgshapiro int r, i, j; 468290792Sgshapiro char **pvp, c, opt; 468390792Sgshapiro char pvpbuf[PSBUFSIZE]; 468477349Sgshapiro 468590792Sgshapiro pvp = NULL; 468690792Sgshapiro r = rscap("srv_features", clientname, "", e, &pvp, pvpbuf, 468790792Sgshapiro sizeof(pvpbuf)); 468890792Sgshapiro if (r != EX_OK) 468990792Sgshapiro return features; 469090792Sgshapiro if (pvp == NULL || pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 469190792Sgshapiro return features; 469290792Sgshapiro if (pvp[1] != NULL && sm_strncasecmp(pvp[1], "temp", 4) == 0) 469390792Sgshapiro return SRV_TMP_FAIL; 469477349Sgshapiro 469564562Sgshapiro /* 469690792Sgshapiro ** General rule (see sendmail.h, d_flags): 469790792Sgshapiro ** lower case: required/offered, upper case: Not required/available 469890792Sgshapiro ** 469990792Sgshapiro ** Since we can change some features per daemon, we have both 470090792Sgshapiro ** cases here: turn on/off a feature. 470164562Sgshapiro */ 470264562Sgshapiro 470390792Sgshapiro for (i = 1; pvp[i] != NULL; i++) 470464562Sgshapiro { 470590792Sgshapiro c = pvp[i][0]; 470690792Sgshapiro j = 0; 470790792Sgshapiro for (;;) 470864562Sgshapiro { 470990792Sgshapiro if ((opt = srv_feat_table[j].srvf_opt) == '\0') 471064562Sgshapiro { 471190792Sgshapiro if (LogLevel > 9) 471290792Sgshapiro sm_syslog(LOG_WARNING, e->e_id, 471390792Sgshapiro "srvfeatures: unknown feature %s", 471490792Sgshapiro pvp[i]); 471590792Sgshapiro break; 471664562Sgshapiro } 471790792Sgshapiro if (c == opt) 471864562Sgshapiro { 471990792Sgshapiro features &= ~(srv_feat_table[j].srvf_flag); 472090792Sgshapiro break; 472164562Sgshapiro } 472290792Sgshapiro if (c == tolower(opt)) 472364562Sgshapiro { 472490792Sgshapiro features |= srv_feat_table[j].srvf_flag; 472590792Sgshapiro break; 472664562Sgshapiro } 472790792Sgshapiro ++j; 472864562Sgshapiro } 472964562Sgshapiro } 473090792Sgshapiro return features; 473164562Sgshapiro} 473264562Sgshapiro 473390792Sgshapiro/* 473438032Speter** HELP -- implement the HELP command. 473538032Speter** 473638032Speter** Parameters: 473738032Speter** topic -- the topic we want help for. 473890792Sgshapiro** e -- envelope. 473938032Speter** 474038032Speter** Returns: 474138032Speter** none. 474238032Speter** 474338032Speter** Side Effects: 474438032Speter** outputs the help file to message output. 474538032Speter*/ 474664562Sgshapiro#define HELPVSTR "#vers " 474764562Sgshapiro#define HELPVERSION 2 474838032Speter 474938032Spetervoid 475064562Sgshapirohelp(topic, e) 475138032Speter char *topic; 475264562Sgshapiro ENVELOPE *e; 475338032Speter{ 475490792Sgshapiro register SM_FILE_T *hf; 475564562Sgshapiro register char *p; 475638032Speter int len; 475738032Speter bool noinfo; 475890792Sgshapiro bool first = true; 475964562Sgshapiro long sff = SFF_OPENASROOT|SFF_REGONLY; 476038032Speter char buf[MAXLINE]; 476164562Sgshapiro char inp[MAXLINE]; 476264562Sgshapiro static int foundvers = -1; 476338032Speter extern char Version[]; 476438032Speter 476538032Speter if (DontLockReadFiles) 476638032Speter sff |= SFF_NOLOCK; 476764562Sgshapiro if (!bitnset(DBS_HELPFILEINUNSAFEDIRPATH, DontBlameSendmail)) 476838032Speter sff |= SFF_SAFEDIRPATH; 476938032Speter 477038032Speter if (HelpFile == NULL || 477138032Speter (hf = safefopen(HelpFile, O_RDONLY, 0444, sff)) == NULL) 477238032Speter { 477338032Speter /* no help */ 477438032Speter errno = 0; 477564562Sgshapiro message("502 5.3.0 Sendmail %s -- HELP not implemented", 477664562Sgshapiro Version); 477738032Speter return; 477838032Speter } 477938032Speter 478038032Speter if (topic == NULL || *topic == '\0') 478138032Speter { 478238032Speter topic = "smtp"; 478390792Sgshapiro noinfo = false; 478438032Speter } 478538032Speter else 478638032Speter { 478738032Speter makelower(topic); 478890792Sgshapiro noinfo = true; 478938032Speter } 479038032Speter 479138032Speter len = strlen(topic); 479238032Speter 4793168515Sgshapiro while (sm_io_fgets(hf, SM_TIME_DEFAULT, buf, sizeof(buf)) != NULL) 479438032Speter { 479564562Sgshapiro if (buf[0] == '#') 479664562Sgshapiro { 479764562Sgshapiro if (foundvers < 0 && 479864562Sgshapiro strncmp(buf, HELPVSTR, strlen(HELPVSTR)) == 0) 479964562Sgshapiro { 480064562Sgshapiro int h; 480164562Sgshapiro 480290792Sgshapiro if (sm_io_sscanf(buf + strlen(HELPVSTR), "%d", 480390792Sgshapiro &h) == 1) 480464562Sgshapiro foundvers = h; 480564562Sgshapiro } 480664562Sgshapiro continue; 480764562Sgshapiro } 480838032Speter if (strncmp(buf, topic, len) == 0) 480938032Speter { 481064562Sgshapiro if (first) 481164562Sgshapiro { 481290792Sgshapiro first = false; 481338032Speter 481464562Sgshapiro /* print version if no/old vers# in file */ 481564562Sgshapiro if (foundvers < 2 && !noinfo) 481664562Sgshapiro message("214-2.0.0 This is Sendmail version %s", Version); 481764562Sgshapiro } 481864562Sgshapiro p = strpbrk(buf, " \t"); 481938032Speter if (p == NULL) 482064562Sgshapiro p = buf + strlen(buf) - 1; 482138032Speter else 482238032Speter p++; 482390792Sgshapiro fixcrlf(p, true); 482464562Sgshapiro if (foundvers >= 2) 482564562Sgshapiro { 4826168515Sgshapiro char *lbp; 4827168515Sgshapiro int lbs = sizeof(buf) - (p - buf); 4828168515Sgshapiro 4829168515Sgshapiro lbp = translate_dollars(p, p, &lbs); 4830168515Sgshapiro expand(lbp, inp, sizeof(inp), e); 4831168515Sgshapiro if (p != lbp) 4832168515Sgshapiro sm_free(lbp); 483364562Sgshapiro p = inp; 483464562Sgshapiro } 483564562Sgshapiro message("214-2.0.0 %s", p); 483690792Sgshapiro noinfo = false; 483738032Speter } 483838032Speter } 483938032Speter 484038032Speter if (noinfo) 484164562Sgshapiro message("504 5.3.0 HELP topic \"%.10s\" unknown", topic); 484238032Speter else 484364562Sgshapiro message("214 2.0.0 End of HELP info"); 484464562Sgshapiro 484564562Sgshapiro if (foundvers != 0 && foundvers < HELPVERSION) 484664562Sgshapiro { 484764562Sgshapiro if (LogLevel > 1) 484864562Sgshapiro sm_syslog(LOG_WARNING, e->e_id, 484964562Sgshapiro "%s too old (require version %d)", 485064562Sgshapiro HelpFile, HELPVERSION); 485164562Sgshapiro 485264562Sgshapiro /* avoid log next time */ 485364562Sgshapiro foundvers = 0; 485464562Sgshapiro } 485564562Sgshapiro 485690792Sgshapiro (void) sm_io_close(hf, SM_TIME_DEFAULT); 485738032Speter} 4858120256Sgshapiro 4859120256Sgshapiro#if SASL 4860120256Sgshapiro/* 4861120256Sgshapiro** RESET_SASLCONN -- reset SASL connection data 4862120256Sgshapiro** 4863120256Sgshapiro** Parameters: 4864120256Sgshapiro** conn -- SASL connection context 4865120256Sgshapiro** hostname -- host name 4866120256Sgshapiro** various connection data 4867120256Sgshapiro** 4868120256Sgshapiro** Returns: 4869120256Sgshapiro** SASL result 4870120256Sgshapiro*/ 4871120256Sgshapiro 4872120256Sgshapirostatic int 4873147078Sgshapiroreset_saslconn(sasl_conn_t **conn, char *hostname, 4874120256Sgshapiro# if SASL >= 20000 4875120256Sgshapiro char *remoteip, char *localip, 4876120256Sgshapiro char *auth_id, sasl_ssf_t * ext_ssf) 4877120256Sgshapiro# else /* SASL >= 20000 */ 4878147078Sgshapiro struct sockaddr_in *saddr_r, struct sockaddr_in *saddr_l, 4879120256Sgshapiro sasl_external_properties_t * ext_ssf) 4880120256Sgshapiro# endif /* SASL >= 20000 */ 4881120256Sgshapiro{ 4882120256Sgshapiro int result; 4883120256Sgshapiro 4884120256Sgshapiro sasl_dispose(conn); 4885120256Sgshapiro# if SASL >= 20000 4886120256Sgshapiro result = sasl_server_new("smtp", hostname, NULL, NULL, NULL, 4887120256Sgshapiro NULL, 0, conn); 4888120256Sgshapiro# elif SASL > 10505 4889120256Sgshapiro /* use empty realm: only works in SASL > 1.5.5 */ 4890120256Sgshapiro result = sasl_server_new("smtp", hostname, "", NULL, 0, conn); 4891120256Sgshapiro# else /* SASL >= 20000 */ 4892120256Sgshapiro /* use no realm -> realm is set to hostname by SASL lib */ 4893120256Sgshapiro result = sasl_server_new("smtp", hostname, NULL, NULL, 0, 4894120256Sgshapiro conn); 4895120256Sgshapiro# endif /* SASL >= 20000 */ 4896120256Sgshapiro if (result != SASL_OK) 4897120256Sgshapiro return result; 4898120256Sgshapiro 4899120256Sgshapiro# if SASL >= 20000 4900120256Sgshapiro# if NETINET || NETINET6 4901147078Sgshapiro if (remoteip != NULL && *remoteip != '\0') 4902120256Sgshapiro result = sasl_setprop(*conn, SASL_IPREMOTEPORT, remoteip); 4903120256Sgshapiro if (result != SASL_OK) 4904120256Sgshapiro return result; 4905120256Sgshapiro 4906147078Sgshapiro if (localip != NULL && *localip != '\0') 4907120256Sgshapiro result = sasl_setprop(*conn, SASL_IPLOCALPORT, localip); 4908120256Sgshapiro if (result != SASL_OK) 4909120256Sgshapiro return result; 4910120256Sgshapiro# endif /* NETINET || NETINET6 */ 4911120256Sgshapiro 4912120256Sgshapiro result = sasl_setprop(*conn, SASL_SSF_EXTERNAL, ext_ssf); 4913120256Sgshapiro if (result != SASL_OK) 4914120256Sgshapiro return result; 4915120256Sgshapiro 4916120256Sgshapiro result = sasl_setprop(*conn, SASL_AUTH_EXTERNAL, auth_id); 4917120256Sgshapiro if (result != SASL_OK) 4918120256Sgshapiro return result; 4919120256Sgshapiro# else /* SASL >= 20000 */ 4920120256Sgshapiro# if NETINET 4921120256Sgshapiro if (saddr_r != NULL) 4922120256Sgshapiro result = sasl_setprop(*conn, SASL_IP_REMOTE, saddr_r); 4923120256Sgshapiro if (result != SASL_OK) 4924120256Sgshapiro return result; 4925120256Sgshapiro 4926120256Sgshapiro if (saddr_l != NULL) 4927120256Sgshapiro result = sasl_setprop(*conn, SASL_IP_LOCAL, saddr_l); 4928120256Sgshapiro if (result != SASL_OK) 4929120256Sgshapiro return result; 4930120256Sgshapiro# endif /* NETINET */ 4931120256Sgshapiro 4932120256Sgshapiro result = sasl_setprop(*conn, SASL_SSF_EXTERNAL, ext_ssf); 4933120256Sgshapiro if (result != SASL_OK) 4934120256Sgshapiro return result; 4935120256Sgshapiro# endif /* SASL >= 20000 */ 4936120256Sgshapiro return SASL_OK; 4937120256Sgshapiro} 4938120256Sgshapiro#endif /* SASL */ 4939