1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright (c) 1998-2005 Sendmail, Inc. and its suppliers. 3*7c478bd9Sstevel@tonic-gate * All rights reserved. 4*7c478bd9Sstevel@tonic-gate * Copyright (c) 1983, 1995-1997 Eric P. Allman. All rights reserved. 5*7c478bd9Sstevel@tonic-gate * Copyright (c) 1988, 1993 6*7c478bd9Sstevel@tonic-gate * The Regents of the University of California. All rights reserved. 7*7c478bd9Sstevel@tonic-gate * 8*7c478bd9Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set 9*7c478bd9Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of 10*7c478bd9Sstevel@tonic-gate * the sendmail distribution. 11*7c478bd9Sstevel@tonic-gate * 12*7c478bd9Sstevel@tonic-gate */ 13*7c478bd9Sstevel@tonic-gate 14*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 15*7c478bd9Sstevel@tonic-gate 16*7c478bd9Sstevel@tonic-gate #include <sendmail.h> 17*7c478bd9Sstevel@tonic-gate #if MILTER 18*7c478bd9Sstevel@tonic-gate # include <libmilter/mfapi.h> 19*7c478bd9Sstevel@tonic-gate # include <libmilter/mfdef.h> 20*7c478bd9Sstevel@tonic-gate #endif /* MILTER */ 21*7c478bd9Sstevel@tonic-gate 22*7c478bd9Sstevel@tonic-gate SM_RCSID("@(#)$Id: srvrsmtp.c,v 8.906 2005/03/16 00:36:09 ca Exp $") 23*7c478bd9Sstevel@tonic-gate 24*7c478bd9Sstevel@tonic-gate #include <sys/time.h> 25*7c478bd9Sstevel@tonic-gate #include <sm/fdset.h> 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #if SASL || STARTTLS 28*7c478bd9Sstevel@tonic-gate # include "sfsasl.h" 29*7c478bd9Sstevel@tonic-gate #endif /* SASL || STARTTLS */ 30*7c478bd9Sstevel@tonic-gate #if SASL 31*7c478bd9Sstevel@tonic-gate # define ENC64LEN(l) (((l) + 2) * 4 / 3 + 1) 32*7c478bd9Sstevel@tonic-gate static int saslmechs __P((sasl_conn_t *, char **)); 33*7c478bd9Sstevel@tonic-gate #endif /* SASL */ 34*7c478bd9Sstevel@tonic-gate #if STARTTLS 35*7c478bd9Sstevel@tonic-gate # include <sysexits.h> 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate static SSL_CTX *srv_ctx = NULL; /* TLS server context */ 38*7c478bd9Sstevel@tonic-gate static SSL *srv_ssl = NULL; /* per connection context */ 39*7c478bd9Sstevel@tonic-gate 40*7c478bd9Sstevel@tonic-gate static bool tls_ok_srv = false; 41*7c478bd9Sstevel@tonic-gate 42*7c478bd9Sstevel@tonic-gate extern void tls_set_verify __P((SSL_CTX *, SSL *, bool)); 43*7c478bd9Sstevel@tonic-gate # define TLS_VERIFY_CLIENT() tls_set_verify(srv_ctx, srv_ssl, \ 44*7c478bd9Sstevel@tonic-gate bitset(SRV_VRFY_CLT, features)) 45*7c478bd9Sstevel@tonic-gate #endif /* STARTTLS */ 46*7c478bd9Sstevel@tonic-gate 47*7c478bd9Sstevel@tonic-gate /* server features */ 48*7c478bd9Sstevel@tonic-gate #define SRV_NONE 0x0000 /* none... */ 49*7c478bd9Sstevel@tonic-gate #define SRV_OFFER_TLS 0x0001 /* offer STARTTLS */ 50*7c478bd9Sstevel@tonic-gate #define SRV_VRFY_CLT 0x0002 /* request a cert */ 51*7c478bd9Sstevel@tonic-gate #define SRV_OFFER_AUTH 0x0004 /* offer AUTH */ 52*7c478bd9Sstevel@tonic-gate #define SRV_OFFER_ETRN 0x0008 /* offer ETRN */ 53*7c478bd9Sstevel@tonic-gate #define SRV_OFFER_VRFY 0x0010 /* offer VRFY (not yet used) */ 54*7c478bd9Sstevel@tonic-gate #define SRV_OFFER_EXPN 0x0020 /* offer EXPN */ 55*7c478bd9Sstevel@tonic-gate #define SRV_OFFER_VERB 0x0040 /* offer VERB */ 56*7c478bd9Sstevel@tonic-gate #define SRV_OFFER_DSN 0x0080 /* offer DSN */ 57*7c478bd9Sstevel@tonic-gate #if PIPELINING 58*7c478bd9Sstevel@tonic-gate # define SRV_OFFER_PIPE 0x0100 /* offer PIPELINING */ 59*7c478bd9Sstevel@tonic-gate # if _FFR_NO_PIPE 60*7c478bd9Sstevel@tonic-gate # define SRV_NO_PIPE 0x0200 /* disable PIPELINING, sleep if used */ 61*7c478bd9Sstevel@tonic-gate # endif /* _FFR_NO_PIPE */ 62*7c478bd9Sstevel@tonic-gate #endif /* PIPELINING */ 63*7c478bd9Sstevel@tonic-gate #define SRV_REQ_AUTH 0x0400 /* require AUTH */ 64*7c478bd9Sstevel@tonic-gate #define SRV_REQ_SEC 0x0800 /* require security - equiv to AuthOptions=p */ 65*7c478bd9Sstevel@tonic-gate #define SRV_TMP_FAIL 0x1000 /* ruleset caused a temporary failure */ 66*7c478bd9Sstevel@tonic-gate 67*7c478bd9Sstevel@tonic-gate static unsigned int srvfeatures __P((ENVELOPE *, char *, unsigned int)); 68*7c478bd9Sstevel@tonic-gate 69*7c478bd9Sstevel@tonic-gate #define STOP_ATTACK ((time_t) -1) 70*7c478bd9Sstevel@tonic-gate static time_t checksmtpattack __P((volatile unsigned int *, unsigned int, 71*7c478bd9Sstevel@tonic-gate bool, char *, ENVELOPE *)); 72*7c478bd9Sstevel@tonic-gate static void mail_esmtp_args __P((char *, char *, ENVELOPE *)); 73*7c478bd9Sstevel@tonic-gate static void printvrfyaddr __P((ADDRESS *, bool, bool)); 74*7c478bd9Sstevel@tonic-gate static void rcpt_esmtp_args __P((ADDRESS *, char *, char *, ENVELOPE *)); 75*7c478bd9Sstevel@tonic-gate static char *skipword __P((char *volatile, char *)); 76*7c478bd9Sstevel@tonic-gate static void setup_smtpd_io __P((void)); 77*7c478bd9Sstevel@tonic-gate 78*7c478bd9Sstevel@tonic-gate #if SASL 79*7c478bd9Sstevel@tonic-gate # if SASL >= 20000 80*7c478bd9Sstevel@tonic-gate static int reset_saslconn __P((sasl_conn_t **_conn, char *_hostname, 81*7c478bd9Sstevel@tonic-gate char *_remoteip, char *_localip, 82*7c478bd9Sstevel@tonic-gate char *_auth_id, sasl_ssf_t *_ext_ssf)); 83*7c478bd9Sstevel@tonic-gate 84*7c478bd9Sstevel@tonic-gate # define RESET_SASLCONN \ 85*7c478bd9Sstevel@tonic-gate do \ 86*7c478bd9Sstevel@tonic-gate { \ 87*7c478bd9Sstevel@tonic-gate result = reset_saslconn(&conn, AuthRealm, remoteip, \ 88*7c478bd9Sstevel@tonic-gate localip, auth_id, &ext_ssf); \ 89*7c478bd9Sstevel@tonic-gate if (result != SASL_OK) \ 90*7c478bd9Sstevel@tonic-gate sasl_ok = false; \ 91*7c478bd9Sstevel@tonic-gate } while (0) 92*7c478bd9Sstevel@tonic-gate 93*7c478bd9Sstevel@tonic-gate # else /* SASL >= 20000 */ 94*7c478bd9Sstevel@tonic-gate static int reset_saslconn __P((sasl_conn_t **_conn, char *_hostname, 95*7c478bd9Sstevel@tonic-gate struct sockaddr_in *_saddr_r, 96*7c478bd9Sstevel@tonic-gate struct sockaddr_in *_saddr_l, 97*7c478bd9Sstevel@tonic-gate sasl_external_properties_t *_ext_ssf)); 98*7c478bd9Sstevel@tonic-gate # define RESET_SASLCONN \ 99*7c478bd9Sstevel@tonic-gate do \ 100*7c478bd9Sstevel@tonic-gate { \ 101*7c478bd9Sstevel@tonic-gate result = reset_saslconn(&conn, AuthRealm, &saddr_r, \ 102*7c478bd9Sstevel@tonic-gate &saddr_l, &ext_ssf); \ 103*7c478bd9Sstevel@tonic-gate if (result != SASL_OK) \ 104*7c478bd9Sstevel@tonic-gate sasl_ok = false; \ 105*7c478bd9Sstevel@tonic-gate } while (0) 106*7c478bd9Sstevel@tonic-gate 107*7c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */ 108*7c478bd9Sstevel@tonic-gate #endif /* SASL */ 109*7c478bd9Sstevel@tonic-gate 110*7c478bd9Sstevel@tonic-gate extern ENVELOPE BlankEnvelope; 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate #define NBADRCPTS \ 113*7c478bd9Sstevel@tonic-gate do \ 114*7c478bd9Sstevel@tonic-gate { \ 115*7c478bd9Sstevel@tonic-gate char buf[16]; \ 116*7c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, "%d", \ 117*7c478bd9Sstevel@tonic-gate BadRcptThrottle > 0 && n_badrcpts > BadRcptThrottle \ 118*7c478bd9Sstevel@tonic-gate ? n_badrcpts - 1 : n_badrcpts); \ 119*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP, macid("{nbadrcpts}"), buf); \ 120*7c478bd9Sstevel@tonic-gate } while (0) 121*7c478bd9Sstevel@tonic-gate 122*7c478bd9Sstevel@tonic-gate #define SKIP_SPACE(s) while (isascii(*s) && isspace(*s)) \ 123*7c478bd9Sstevel@tonic-gate (s)++ 124*7c478bd9Sstevel@tonic-gate 125*7c478bd9Sstevel@tonic-gate /* 126*7c478bd9Sstevel@tonic-gate ** SMTP -- run the SMTP protocol. 127*7c478bd9Sstevel@tonic-gate ** 128*7c478bd9Sstevel@tonic-gate ** Parameters: 129*7c478bd9Sstevel@tonic-gate ** nullserver -- if non-NULL, rejection message for 130*7c478bd9Sstevel@tonic-gate ** (almost) all SMTP commands. 131*7c478bd9Sstevel@tonic-gate ** d_flags -- daemon flags 132*7c478bd9Sstevel@tonic-gate ** e -- the envelope. 133*7c478bd9Sstevel@tonic-gate ** 134*7c478bd9Sstevel@tonic-gate ** Returns: 135*7c478bd9Sstevel@tonic-gate ** never. 136*7c478bd9Sstevel@tonic-gate ** 137*7c478bd9Sstevel@tonic-gate ** Side Effects: 138*7c478bd9Sstevel@tonic-gate ** Reads commands from the input channel and processes them. 139*7c478bd9Sstevel@tonic-gate */ 140*7c478bd9Sstevel@tonic-gate 141*7c478bd9Sstevel@tonic-gate /* 142*7c478bd9Sstevel@tonic-gate ** Notice: The smtp server doesn't have a session context like the client 143*7c478bd9Sstevel@tonic-gate ** side has (mci). Therefore some data (session oriented) is allocated 144*7c478bd9Sstevel@tonic-gate ** or assigned to the "wrong" structure (esp. STARTTLS, AUTH). 145*7c478bd9Sstevel@tonic-gate ** This should be fixed in a successor version. 146*7c478bd9Sstevel@tonic-gate */ 147*7c478bd9Sstevel@tonic-gate 148*7c478bd9Sstevel@tonic-gate struct cmd 149*7c478bd9Sstevel@tonic-gate { 150*7c478bd9Sstevel@tonic-gate char *cmd_name; /* command name */ 151*7c478bd9Sstevel@tonic-gate int cmd_code; /* internal code, see below */ 152*7c478bd9Sstevel@tonic-gate }; 153*7c478bd9Sstevel@tonic-gate 154*7c478bd9Sstevel@tonic-gate /* values for cmd_code */ 155*7c478bd9Sstevel@tonic-gate #define CMDERROR 0 /* bad command */ 156*7c478bd9Sstevel@tonic-gate #define CMDMAIL 1 /* mail -- designate sender */ 157*7c478bd9Sstevel@tonic-gate #define CMDRCPT 2 /* rcpt -- designate recipient */ 158*7c478bd9Sstevel@tonic-gate #define CMDDATA 3 /* data -- send message text */ 159*7c478bd9Sstevel@tonic-gate #define CMDRSET 4 /* rset -- reset state */ 160*7c478bd9Sstevel@tonic-gate #define CMDVRFY 5 /* vrfy -- verify address */ 161*7c478bd9Sstevel@tonic-gate #define CMDEXPN 6 /* expn -- expand address */ 162*7c478bd9Sstevel@tonic-gate #define CMDNOOP 7 /* noop -- do nothing */ 163*7c478bd9Sstevel@tonic-gate #define CMDQUIT 8 /* quit -- close connection and die */ 164*7c478bd9Sstevel@tonic-gate #define CMDHELO 9 /* helo -- be polite */ 165*7c478bd9Sstevel@tonic-gate #define CMDHELP 10 /* help -- give usage info */ 166*7c478bd9Sstevel@tonic-gate #define CMDEHLO 11 /* ehlo -- extended helo (RFC 1425) */ 167*7c478bd9Sstevel@tonic-gate #define CMDETRN 12 /* etrn -- flush queue */ 168*7c478bd9Sstevel@tonic-gate #if SASL 169*7c478bd9Sstevel@tonic-gate # define CMDAUTH 13 /* auth -- SASL authenticate */ 170*7c478bd9Sstevel@tonic-gate #endif /* SASL */ 171*7c478bd9Sstevel@tonic-gate #if STARTTLS 172*7c478bd9Sstevel@tonic-gate # define CMDSTLS 14 /* STARTTLS -- start TLS session */ 173*7c478bd9Sstevel@tonic-gate #endif /* STARTTLS */ 174*7c478bd9Sstevel@tonic-gate /* non-standard commands */ 175*7c478bd9Sstevel@tonic-gate #define CMDVERB 17 /* verb -- go into verbose mode */ 176*7c478bd9Sstevel@tonic-gate /* unimplemented commands from RFC 821 */ 177*7c478bd9Sstevel@tonic-gate #define CMDUNIMPL 19 /* unimplemented rfc821 commands */ 178*7c478bd9Sstevel@tonic-gate /* use this to catch and log "door handle" attempts on your system */ 179*7c478bd9Sstevel@tonic-gate #define CMDLOGBOGUS 23 /* bogus command that should be logged */ 180*7c478bd9Sstevel@tonic-gate /* debugging-only commands, only enabled if SMTPDEBUG is defined */ 181*7c478bd9Sstevel@tonic-gate #define CMDDBGQSHOW 24 /* showq -- show send queue */ 182*7c478bd9Sstevel@tonic-gate #define CMDDBGDEBUG 25 /* debug -- set debug mode */ 183*7c478bd9Sstevel@tonic-gate 184*7c478bd9Sstevel@tonic-gate /* 185*7c478bd9Sstevel@tonic-gate ** Note: If you change this list, remember to update 'helpfile' 186*7c478bd9Sstevel@tonic-gate */ 187*7c478bd9Sstevel@tonic-gate 188*7c478bd9Sstevel@tonic-gate static struct cmd CmdTab[] = 189*7c478bd9Sstevel@tonic-gate { 190*7c478bd9Sstevel@tonic-gate { "mail", CMDMAIL }, 191*7c478bd9Sstevel@tonic-gate { "rcpt", CMDRCPT }, 192*7c478bd9Sstevel@tonic-gate { "data", CMDDATA }, 193*7c478bd9Sstevel@tonic-gate { "rset", CMDRSET }, 194*7c478bd9Sstevel@tonic-gate { "vrfy", CMDVRFY }, 195*7c478bd9Sstevel@tonic-gate { "expn", CMDEXPN }, 196*7c478bd9Sstevel@tonic-gate { "help", CMDHELP }, 197*7c478bd9Sstevel@tonic-gate { "noop", CMDNOOP }, 198*7c478bd9Sstevel@tonic-gate { "quit", CMDQUIT }, 199*7c478bd9Sstevel@tonic-gate { "helo", CMDHELO }, 200*7c478bd9Sstevel@tonic-gate { "ehlo", CMDEHLO }, 201*7c478bd9Sstevel@tonic-gate { "etrn", CMDETRN }, 202*7c478bd9Sstevel@tonic-gate { "verb", CMDVERB }, 203*7c478bd9Sstevel@tonic-gate { "send", CMDUNIMPL }, 204*7c478bd9Sstevel@tonic-gate { "saml", CMDUNIMPL }, 205*7c478bd9Sstevel@tonic-gate { "soml", CMDUNIMPL }, 206*7c478bd9Sstevel@tonic-gate { "turn", CMDUNIMPL }, 207*7c478bd9Sstevel@tonic-gate #if SASL 208*7c478bd9Sstevel@tonic-gate { "auth", CMDAUTH, }, 209*7c478bd9Sstevel@tonic-gate #endif /* SASL */ 210*7c478bd9Sstevel@tonic-gate #if STARTTLS 211*7c478bd9Sstevel@tonic-gate { "starttls", CMDSTLS, }, 212*7c478bd9Sstevel@tonic-gate #endif /* STARTTLS */ 213*7c478bd9Sstevel@tonic-gate /* remaining commands are here only to trap and log attempts to use them */ 214*7c478bd9Sstevel@tonic-gate { "showq", CMDDBGQSHOW }, 215*7c478bd9Sstevel@tonic-gate { "debug", CMDDBGDEBUG }, 216*7c478bd9Sstevel@tonic-gate { "wiz", CMDLOGBOGUS }, 217*7c478bd9Sstevel@tonic-gate 218*7c478bd9Sstevel@tonic-gate { NULL, CMDERROR } 219*7c478bd9Sstevel@tonic-gate }; 220*7c478bd9Sstevel@tonic-gate 221*7c478bd9Sstevel@tonic-gate static char *CurSmtpClient; /* who's at the other end of channel */ 222*7c478bd9Sstevel@tonic-gate 223*7c478bd9Sstevel@tonic-gate #ifndef MAXBADCOMMANDS 224*7c478bd9Sstevel@tonic-gate # define MAXBADCOMMANDS 25 /* maximum number of bad commands */ 225*7c478bd9Sstevel@tonic-gate #endif /* ! MAXBADCOMMANDS */ 226*7c478bd9Sstevel@tonic-gate #ifndef MAXNOOPCOMMANDS 227*7c478bd9Sstevel@tonic-gate # define MAXNOOPCOMMANDS 20 /* max "noise" commands before slowdown */ 228*7c478bd9Sstevel@tonic-gate #endif /* ! MAXNOOPCOMMANDS */ 229*7c478bd9Sstevel@tonic-gate #ifndef MAXHELOCOMMANDS 230*7c478bd9Sstevel@tonic-gate # define MAXHELOCOMMANDS 3 /* max HELO/EHLO commands before slowdown */ 231*7c478bd9Sstevel@tonic-gate #endif /* ! MAXHELOCOMMANDS */ 232*7c478bd9Sstevel@tonic-gate #ifndef MAXVRFYCOMMANDS 233*7c478bd9Sstevel@tonic-gate # define MAXVRFYCOMMANDS 6 /* max VRFY/EXPN commands before slowdown */ 234*7c478bd9Sstevel@tonic-gate #endif /* ! MAXVRFYCOMMANDS */ 235*7c478bd9Sstevel@tonic-gate #ifndef MAXETRNCOMMANDS 236*7c478bd9Sstevel@tonic-gate # define MAXETRNCOMMANDS 8 /* max ETRN commands before slowdown */ 237*7c478bd9Sstevel@tonic-gate #endif /* ! MAXETRNCOMMANDS */ 238*7c478bd9Sstevel@tonic-gate #ifndef MAXTIMEOUT 239*7c478bd9Sstevel@tonic-gate # define MAXTIMEOUT (4 * 60) /* max timeout for bad commands */ 240*7c478bd9Sstevel@tonic-gate #endif /* ! MAXTIMEOUT */ 241*7c478bd9Sstevel@tonic-gate 242*7c478bd9Sstevel@tonic-gate /* 243*7c478bd9Sstevel@tonic-gate ** Maximum shift value to compute timeout for bad commands. 244*7c478bd9Sstevel@tonic-gate ** This introduces an upper limit of 2^MAXSHIFT for the timeout. 245*7c478bd9Sstevel@tonic-gate */ 246*7c478bd9Sstevel@tonic-gate 247*7c478bd9Sstevel@tonic-gate #ifndef MAXSHIFT 248*7c478bd9Sstevel@tonic-gate # define MAXSHIFT 8 249*7c478bd9Sstevel@tonic-gate #endif /* ! MAXSHIFT */ 250*7c478bd9Sstevel@tonic-gate #if MAXSHIFT > 31 251*7c478bd9Sstevel@tonic-gate ERROR _MAXSHIFT > 31 is invalid 252*7c478bd9Sstevel@tonic-gate #endif /* MAXSHIFT */ 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate 255*7c478bd9Sstevel@tonic-gate #if MAXBADCOMMANDS > 0 256*7c478bd9Sstevel@tonic-gate # define STOP_IF_ATTACK(r) do \ 257*7c478bd9Sstevel@tonic-gate { \ 258*7c478bd9Sstevel@tonic-gate if ((r) == STOP_ATTACK) \ 259*7c478bd9Sstevel@tonic-gate goto stopattack; \ 260*7c478bd9Sstevel@tonic-gate } while (0) 261*7c478bd9Sstevel@tonic-gate 262*7c478bd9Sstevel@tonic-gate #else /* MAXBADCOMMANDS > 0 */ 263*7c478bd9Sstevel@tonic-gate # define STOP_IF_ATTACK(r) r 264*7c478bd9Sstevel@tonic-gate #endif /* MAXBADCOMMANDS > 0 */ 265*7c478bd9Sstevel@tonic-gate 266*7c478bd9Sstevel@tonic-gate 267*7c478bd9Sstevel@tonic-gate #if SM_HEAP_CHECK 268*7c478bd9Sstevel@tonic-gate static SM_DEBUG_T DebugLeakSmtp = SM_DEBUG_INITIALIZER("leak_smtp", 269*7c478bd9Sstevel@tonic-gate "@(#)$Debug: leak_smtp - trace memory leaks during SMTP processing $"); 270*7c478bd9Sstevel@tonic-gate #endif /* SM_HEAP_CHECK */ 271*7c478bd9Sstevel@tonic-gate 272*7c478bd9Sstevel@tonic-gate typedef struct 273*7c478bd9Sstevel@tonic-gate { 274*7c478bd9Sstevel@tonic-gate bool sm_gotmail; /* mail command received */ 275*7c478bd9Sstevel@tonic-gate unsigned int sm_nrcpts; /* number of successful RCPT commands */ 276*7c478bd9Sstevel@tonic-gate bool sm_discard; 277*7c478bd9Sstevel@tonic-gate #if MILTER 278*7c478bd9Sstevel@tonic-gate bool sm_milterize; 279*7c478bd9Sstevel@tonic-gate bool sm_milterlist; /* any filters in the list? */ 280*7c478bd9Sstevel@tonic-gate #endif /* MILTER */ 281*7c478bd9Sstevel@tonic-gate char *sm_quarmsg; /* carry quarantining across messages */ 282*7c478bd9Sstevel@tonic-gate } SMTP_T; 283*7c478bd9Sstevel@tonic-gate 284*7c478bd9Sstevel@tonic-gate static bool smtp_data __P((SMTP_T *, ENVELOPE *)); 285*7c478bd9Sstevel@tonic-gate 286*7c478bd9Sstevel@tonic-gate #define MSG_TEMPFAIL "451 4.3.2 Please try again later" 287*7c478bd9Sstevel@tonic-gate 288*7c478bd9Sstevel@tonic-gate #if MILTER 289*7c478bd9Sstevel@tonic-gate # define MILTER_ABORT(e) milter_abort((e)) 290*7c478bd9Sstevel@tonic-gate 291*7c478bd9Sstevel@tonic-gate # define MILTER_REPLY(str) \ 292*7c478bd9Sstevel@tonic-gate { \ 293*7c478bd9Sstevel@tonic-gate int savelogusrerrs = LogUsrErrs; \ 294*7c478bd9Sstevel@tonic-gate \ 295*7c478bd9Sstevel@tonic-gate switch (state) \ 296*7c478bd9Sstevel@tonic-gate { \ 297*7c478bd9Sstevel@tonic-gate case SMFIR_REPLYCODE: \ 298*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 3) \ 299*7c478bd9Sstevel@tonic-gate { \ 300*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, \ 301*7c478bd9Sstevel@tonic-gate "Milter: %s=%s, reject=%s", \ 302*7c478bd9Sstevel@tonic-gate str, addr, response); \ 303*7c478bd9Sstevel@tonic-gate LogUsrErrs = false; \ 304*7c478bd9Sstevel@tonic-gate } \ 305*7c478bd9Sstevel@tonic-gate if (strncmp(response, "421 ", 4) == 0) \ 306*7c478bd9Sstevel@tonic-gate { \ 307*7c478bd9Sstevel@tonic-gate bool tsave = QuickAbort; \ 308*7c478bd9Sstevel@tonic-gate \ 309*7c478bd9Sstevel@tonic-gate QuickAbort = false; \ 310*7c478bd9Sstevel@tonic-gate usrerr(response); \ 311*7c478bd9Sstevel@tonic-gate QuickAbort = tsave; \ 312*7c478bd9Sstevel@tonic-gate e->e_sendqueue = NULL; \ 313*7c478bd9Sstevel@tonic-gate goto doquit; \ 314*7c478bd9Sstevel@tonic-gate } \ 315*7c478bd9Sstevel@tonic-gate else \ 316*7c478bd9Sstevel@tonic-gate usrerr(response); \ 317*7c478bd9Sstevel@tonic-gate break; \ 318*7c478bd9Sstevel@tonic-gate \ 319*7c478bd9Sstevel@tonic-gate case SMFIR_REJECT: \ 320*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 3) \ 321*7c478bd9Sstevel@tonic-gate { \ 322*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, \ 323*7c478bd9Sstevel@tonic-gate "Milter: %s=%s, reject=550 5.7.1 Command rejected", \ 324*7c478bd9Sstevel@tonic-gate str, addr); \ 325*7c478bd9Sstevel@tonic-gate LogUsrErrs = false; \ 326*7c478bd9Sstevel@tonic-gate } \ 327*7c478bd9Sstevel@tonic-gate usrerr("550 5.7.1 Command rejected"); \ 328*7c478bd9Sstevel@tonic-gate break; \ 329*7c478bd9Sstevel@tonic-gate \ 330*7c478bd9Sstevel@tonic-gate case SMFIR_DISCARD: \ 331*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 3) \ 332*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, \ 333*7c478bd9Sstevel@tonic-gate "Milter: %s=%s, discard", \ 334*7c478bd9Sstevel@tonic-gate str, addr); \ 335*7c478bd9Sstevel@tonic-gate e->e_flags |= EF_DISCARD; \ 336*7c478bd9Sstevel@tonic-gate break; \ 337*7c478bd9Sstevel@tonic-gate \ 338*7c478bd9Sstevel@tonic-gate case SMFIR_TEMPFAIL: \ 339*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 3) \ 340*7c478bd9Sstevel@tonic-gate { \ 341*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, \ 342*7c478bd9Sstevel@tonic-gate "Milter: %s=%s, reject=%s", \ 343*7c478bd9Sstevel@tonic-gate str, addr, MSG_TEMPFAIL); \ 344*7c478bd9Sstevel@tonic-gate LogUsrErrs = false; \ 345*7c478bd9Sstevel@tonic-gate } \ 346*7c478bd9Sstevel@tonic-gate usrerr(MSG_TEMPFAIL); \ 347*7c478bd9Sstevel@tonic-gate break; \ 348*7c478bd9Sstevel@tonic-gate } \ 349*7c478bd9Sstevel@tonic-gate LogUsrErrs = savelogusrerrs; \ 350*7c478bd9Sstevel@tonic-gate if (response != NULL) \ 351*7c478bd9Sstevel@tonic-gate sm_free(response); /* XXX */ \ 352*7c478bd9Sstevel@tonic-gate } 353*7c478bd9Sstevel@tonic-gate 354*7c478bd9Sstevel@tonic-gate #else /* MILTER */ 355*7c478bd9Sstevel@tonic-gate # define MILTER_ABORT(e) 356*7c478bd9Sstevel@tonic-gate #endif /* MILTER */ 357*7c478bd9Sstevel@tonic-gate 358*7c478bd9Sstevel@tonic-gate /* clear all SMTP state (for HELO/EHLO/RSET) */ 359*7c478bd9Sstevel@tonic-gate #define CLEAR_STATE(cmd) \ 360*7c478bd9Sstevel@tonic-gate do \ 361*7c478bd9Sstevel@tonic-gate { \ 362*7c478bd9Sstevel@tonic-gate /* abort milter filters */ \ 363*7c478bd9Sstevel@tonic-gate MILTER_ABORT(e); \ 364*7c478bd9Sstevel@tonic-gate \ 365*7c478bd9Sstevel@tonic-gate if (smtp.sm_nrcpts > 0) \ 366*7c478bd9Sstevel@tonic-gate { \ 367*7c478bd9Sstevel@tonic-gate logundelrcpts(e, cmd, 10, false); \ 368*7c478bd9Sstevel@tonic-gate smtp.sm_nrcpts = 0; \ 369*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, \ 370*7c478bd9Sstevel@tonic-gate macid("{nrcpts}"), "0"); \ 371*7c478bd9Sstevel@tonic-gate } \ 372*7c478bd9Sstevel@tonic-gate \ 373*7c478bd9Sstevel@tonic-gate e->e_sendqueue = NULL; \ 374*7c478bd9Sstevel@tonic-gate e->e_flags |= EF_CLRQUEUE; \ 375*7c478bd9Sstevel@tonic-gate \ 376*7c478bd9Sstevel@tonic-gate if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags)) \ 377*7c478bd9Sstevel@tonic-gate logsender(e, NULL); \ 378*7c478bd9Sstevel@tonic-gate e->e_flags &= ~EF_LOGSENDER; \ 379*7c478bd9Sstevel@tonic-gate \ 380*7c478bd9Sstevel@tonic-gate /* clean up a bit */ \ 381*7c478bd9Sstevel@tonic-gate smtp.sm_gotmail = false; \ 382*7c478bd9Sstevel@tonic-gate SuprErrs = true; \ 383*7c478bd9Sstevel@tonic-gate dropenvelope(e, true, false); \ 384*7c478bd9Sstevel@tonic-gate sm_rpool_free(e->e_rpool); \ 385*7c478bd9Sstevel@tonic-gate e = newenvelope(e, CurEnv, sm_rpool_new_x(NULL)); \ 386*7c478bd9Sstevel@tonic-gate CurEnv = e; \ 387*7c478bd9Sstevel@tonic-gate \ 388*7c478bd9Sstevel@tonic-gate /* put back discard bit */ \ 389*7c478bd9Sstevel@tonic-gate if (smtp.sm_discard) \ 390*7c478bd9Sstevel@tonic-gate e->e_flags |= EF_DISCARD; \ 391*7c478bd9Sstevel@tonic-gate \ 392*7c478bd9Sstevel@tonic-gate /* restore connection quarantining */ \ 393*7c478bd9Sstevel@tonic-gate if (smtp.sm_quarmsg == NULL) \ 394*7c478bd9Sstevel@tonic-gate { \ 395*7c478bd9Sstevel@tonic-gate e->e_quarmsg = NULL; \ 396*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, \ 397*7c478bd9Sstevel@tonic-gate macid("{quarantine}"), ""); \ 398*7c478bd9Sstevel@tonic-gate } \ 399*7c478bd9Sstevel@tonic-gate else \ 400*7c478bd9Sstevel@tonic-gate { \ 401*7c478bd9Sstevel@tonic-gate e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, \ 402*7c478bd9Sstevel@tonic-gate smtp.sm_quarmsg); \ 403*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), \ 404*7c478bd9Sstevel@tonic-gate e->e_quarmsg); \ 405*7c478bd9Sstevel@tonic-gate } \ 406*7c478bd9Sstevel@tonic-gate } while (0) 407*7c478bd9Sstevel@tonic-gate 408*7c478bd9Sstevel@tonic-gate /* sleep to flatten out connection load */ 409*7c478bd9Sstevel@tonic-gate #define MIN_DELAY_LOG 15 /* wait before logging this again */ 410*7c478bd9Sstevel@tonic-gate 411*7c478bd9Sstevel@tonic-gate /* is it worth setting the process title for 1s? */ 412*7c478bd9Sstevel@tonic-gate #define DELAY_CONN(cmd) \ 413*7c478bd9Sstevel@tonic-gate if (DelayLA > 0 && (CurrentLA = getla()) >= DelayLA) \ 414*7c478bd9Sstevel@tonic-gate { \ 415*7c478bd9Sstevel@tonic-gate time_t dnow; \ 416*7c478bd9Sstevel@tonic-gate \ 417*7c478bd9Sstevel@tonic-gate sm_setproctitle(true, e, \ 418*7c478bd9Sstevel@tonic-gate "%s: %s: delaying %s: load average: %d", \ 419*7c478bd9Sstevel@tonic-gate qid_printname(e), CurSmtpClient, \ 420*7c478bd9Sstevel@tonic-gate cmd, DelayLA); \ 421*7c478bd9Sstevel@tonic-gate if (LogLevel > 8 && (dnow = curtime()) > log_delay) \ 422*7c478bd9Sstevel@tonic-gate { \ 423*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, \ 424*7c478bd9Sstevel@tonic-gate "delaying=%s, load average=%d >= %d", \ 425*7c478bd9Sstevel@tonic-gate cmd, CurrentLA, DelayLA); \ 426*7c478bd9Sstevel@tonic-gate log_delay = dnow + MIN_DELAY_LOG; \ 427*7c478bd9Sstevel@tonic-gate } \ 428*7c478bd9Sstevel@tonic-gate (void) sleep(1); \ 429*7c478bd9Sstevel@tonic-gate sm_setproctitle(true, e, "%s %s: %.80s", \ 430*7c478bd9Sstevel@tonic-gate qid_printname(e), CurSmtpClient, inp); \ 431*7c478bd9Sstevel@tonic-gate } 432*7c478bd9Sstevel@tonic-gate 433*7c478bd9Sstevel@tonic-gate 434*7c478bd9Sstevel@tonic-gate void 435*7c478bd9Sstevel@tonic-gate smtp(nullserver, d_flags, e) 436*7c478bd9Sstevel@tonic-gate char *volatile nullserver; 437*7c478bd9Sstevel@tonic-gate BITMAP256 d_flags; 438*7c478bd9Sstevel@tonic-gate register ENVELOPE *volatile e; 439*7c478bd9Sstevel@tonic-gate { 440*7c478bd9Sstevel@tonic-gate register char *volatile p; 441*7c478bd9Sstevel@tonic-gate register struct cmd *volatile c = NULL; 442*7c478bd9Sstevel@tonic-gate char *cmd; 443*7c478bd9Sstevel@tonic-gate auto ADDRESS *vrfyqueue; 444*7c478bd9Sstevel@tonic-gate ADDRESS *a; 445*7c478bd9Sstevel@tonic-gate volatile bool gothello; /* helo command received */ 446*7c478bd9Sstevel@tonic-gate bool vrfy; /* set if this is a vrfy command */ 447*7c478bd9Sstevel@tonic-gate char *volatile protocol; /* sending protocol */ 448*7c478bd9Sstevel@tonic-gate char *volatile sendinghost; /* sending hostname */ 449*7c478bd9Sstevel@tonic-gate char *volatile peerhostname; /* name of SMTP peer or "localhost" */ 450*7c478bd9Sstevel@tonic-gate auto char *delimptr; 451*7c478bd9Sstevel@tonic-gate char *id; 452*7c478bd9Sstevel@tonic-gate volatile unsigned int n_badcmds = 0; /* count of bad commands */ 453*7c478bd9Sstevel@tonic-gate volatile unsigned int n_badrcpts = 0; /* number of rejected RCPT */ 454*7c478bd9Sstevel@tonic-gate volatile unsigned int n_verifies = 0; /* count of VRFY/EXPN */ 455*7c478bd9Sstevel@tonic-gate volatile unsigned int n_etrn = 0; /* count of ETRN */ 456*7c478bd9Sstevel@tonic-gate volatile unsigned int n_noop = 0; /* count of NOOP/VERB/etc */ 457*7c478bd9Sstevel@tonic-gate volatile unsigned int n_helo = 0; /* count of HELO/EHLO */ 458*7c478bd9Sstevel@tonic-gate volatile int save_sevenbitinput; 459*7c478bd9Sstevel@tonic-gate bool ok; 460*7c478bd9Sstevel@tonic-gate #if _FFR_BLOCK_PROXIES 461*7c478bd9Sstevel@tonic-gate volatile bool first; 462*7c478bd9Sstevel@tonic-gate #endif /* _FFR_BLOCK_PROXIES */ 463*7c478bd9Sstevel@tonic-gate volatile bool tempfail = false; 464*7c478bd9Sstevel@tonic-gate volatile time_t wt; /* timeout after too many commands */ 465*7c478bd9Sstevel@tonic-gate volatile time_t previous; /* time after checksmtpattack() */ 466*7c478bd9Sstevel@tonic-gate volatile bool lognullconnection = true; 467*7c478bd9Sstevel@tonic-gate register char *q; 468*7c478bd9Sstevel@tonic-gate SMTP_T smtp; 469*7c478bd9Sstevel@tonic-gate char *addr; 470*7c478bd9Sstevel@tonic-gate char *greetcode = "220"; 471*7c478bd9Sstevel@tonic-gate char *hostname; /* my hostname ($j) */ 472*7c478bd9Sstevel@tonic-gate QUEUE_CHAR *new; 473*7c478bd9Sstevel@tonic-gate int argno; 474*7c478bd9Sstevel@tonic-gate char *args[MAXSMTPARGS]; 475*7c478bd9Sstevel@tonic-gate char inp[MAXLINE]; 476*7c478bd9Sstevel@tonic-gate char cmdbuf[MAXLINE]; 477*7c478bd9Sstevel@tonic-gate #if SASL 478*7c478bd9Sstevel@tonic-gate sasl_conn_t *conn; 479*7c478bd9Sstevel@tonic-gate volatile bool sasl_ok; 480*7c478bd9Sstevel@tonic-gate volatile unsigned int n_auth = 0; /* count of AUTH commands */ 481*7c478bd9Sstevel@tonic-gate bool ismore; 482*7c478bd9Sstevel@tonic-gate int result; 483*7c478bd9Sstevel@tonic-gate volatile int authenticating; 484*7c478bd9Sstevel@tonic-gate char *user; 485*7c478bd9Sstevel@tonic-gate char *in, *out2; 486*7c478bd9Sstevel@tonic-gate # if SASL >= 20000 487*7c478bd9Sstevel@tonic-gate char *auth_id; 488*7c478bd9Sstevel@tonic-gate const char *out; 489*7c478bd9Sstevel@tonic-gate sasl_ssf_t ext_ssf; 490*7c478bd9Sstevel@tonic-gate char localip[60], remoteip[60]; 491*7c478bd9Sstevel@tonic-gate # else /* SASL >= 20000 */ 492*7c478bd9Sstevel@tonic-gate char *out; 493*7c478bd9Sstevel@tonic-gate const char *errstr; 494*7c478bd9Sstevel@tonic-gate sasl_external_properties_t ext_ssf; 495*7c478bd9Sstevel@tonic-gate struct sockaddr_in saddr_l; 496*7c478bd9Sstevel@tonic-gate struct sockaddr_in saddr_r; 497*7c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */ 498*7c478bd9Sstevel@tonic-gate sasl_security_properties_t ssp; 499*7c478bd9Sstevel@tonic-gate sasl_ssf_t *ssf; 500*7c478bd9Sstevel@tonic-gate unsigned int inlen, out2len; 501*7c478bd9Sstevel@tonic-gate unsigned int outlen; 502*7c478bd9Sstevel@tonic-gate char *volatile auth_type; 503*7c478bd9Sstevel@tonic-gate char *mechlist; 504*7c478bd9Sstevel@tonic-gate volatile unsigned int n_mechs; 505*7c478bd9Sstevel@tonic-gate unsigned int len; 506*7c478bd9Sstevel@tonic-gate #endif /* SASL */ 507*7c478bd9Sstevel@tonic-gate int r; 508*7c478bd9Sstevel@tonic-gate #if STARTTLS 509*7c478bd9Sstevel@tonic-gate int fdfl; 510*7c478bd9Sstevel@tonic-gate int rfd, wfd; 511*7c478bd9Sstevel@tonic-gate volatile bool tls_active = false; 512*7c478bd9Sstevel@tonic-gate volatile bool smtps = bitnset(D_SMTPS, d_flags); 513*7c478bd9Sstevel@tonic-gate bool saveQuickAbort; 514*7c478bd9Sstevel@tonic-gate bool saveSuprErrs; 515*7c478bd9Sstevel@tonic-gate time_t tlsstart; 516*7c478bd9Sstevel@tonic-gate #endif /* STARTTLS */ 517*7c478bd9Sstevel@tonic-gate volatile unsigned int features; 518*7c478bd9Sstevel@tonic-gate #if PIPELINING 519*7c478bd9Sstevel@tonic-gate # if _FFR_NO_PIPE 520*7c478bd9Sstevel@tonic-gate int np_log = 0; 521*7c478bd9Sstevel@tonic-gate # endif /* _FFR_NO_PIPE */ 522*7c478bd9Sstevel@tonic-gate #endif /* PIPELINING */ 523*7c478bd9Sstevel@tonic-gate volatile time_t log_delay = (time_t) 0; 524*7c478bd9Sstevel@tonic-gate 525*7c478bd9Sstevel@tonic-gate save_sevenbitinput = SevenBitInput; 526*7c478bd9Sstevel@tonic-gate smtp.sm_nrcpts = 0; 527*7c478bd9Sstevel@tonic-gate #if MILTER 528*7c478bd9Sstevel@tonic-gate smtp.sm_milterize = (nullserver == NULL); 529*7c478bd9Sstevel@tonic-gate smtp.sm_milterlist = false; 530*7c478bd9Sstevel@tonic-gate #endif /* MILTER */ 531*7c478bd9Sstevel@tonic-gate 532*7c478bd9Sstevel@tonic-gate /* setup I/O fd correctly for the SMTP server */ 533*7c478bd9Sstevel@tonic-gate setup_smtpd_io(); 534*7c478bd9Sstevel@tonic-gate 535*7c478bd9Sstevel@tonic-gate #if SM_HEAP_CHECK 536*7c478bd9Sstevel@tonic-gate if (sm_debug_active(&DebugLeakSmtp, 1)) 537*7c478bd9Sstevel@tonic-gate { 538*7c478bd9Sstevel@tonic-gate sm_heap_newgroup(); 539*7c478bd9Sstevel@tonic-gate sm_dprintf("smtp() heap group #%d\n", sm_heap_group()); 540*7c478bd9Sstevel@tonic-gate } 541*7c478bd9Sstevel@tonic-gate #endif /* SM_HEAP_CHECK */ 542*7c478bd9Sstevel@tonic-gate 543*7c478bd9Sstevel@tonic-gate /* XXX the rpool should be set when e is initialized in main() */ 544*7c478bd9Sstevel@tonic-gate e->e_rpool = sm_rpool_new_x(NULL); 545*7c478bd9Sstevel@tonic-gate e->e_macro.mac_rpool = e->e_rpool; 546*7c478bd9Sstevel@tonic-gate 547*7c478bd9Sstevel@tonic-gate settime(e); 548*7c478bd9Sstevel@tonic-gate sm_getla(); 549*7c478bd9Sstevel@tonic-gate peerhostname = RealHostName; 550*7c478bd9Sstevel@tonic-gate if (peerhostname == NULL) 551*7c478bd9Sstevel@tonic-gate peerhostname = "localhost"; 552*7c478bd9Sstevel@tonic-gate CurHostName = peerhostname; 553*7c478bd9Sstevel@tonic-gate CurSmtpClient = macvalue('_', e); 554*7c478bd9Sstevel@tonic-gate if (CurSmtpClient == NULL) 555*7c478bd9Sstevel@tonic-gate CurSmtpClient = CurHostName; 556*7c478bd9Sstevel@tonic-gate 557*7c478bd9Sstevel@tonic-gate /* check_relay may have set discard bit, save for later */ 558*7c478bd9Sstevel@tonic-gate smtp.sm_discard = bitset(EF_DISCARD, e->e_flags); 559*7c478bd9Sstevel@tonic-gate 560*7c478bd9Sstevel@tonic-gate #if PIPELINING 561*7c478bd9Sstevel@tonic-gate /* auto-flush output when reading input */ 562*7c478bd9Sstevel@tonic-gate (void) sm_io_autoflush(InChannel, OutChannel); 563*7c478bd9Sstevel@tonic-gate #endif /* PIPELINING */ 564*7c478bd9Sstevel@tonic-gate 565*7c478bd9Sstevel@tonic-gate sm_setproctitle(true, e, "server %s startup", CurSmtpClient); 566*7c478bd9Sstevel@tonic-gate 567*7c478bd9Sstevel@tonic-gate /* Set default features for server. */ 568*7c478bd9Sstevel@tonic-gate features = ((bitset(PRIV_NOETRN, PrivacyFlags) || 569*7c478bd9Sstevel@tonic-gate bitnset(D_NOETRN, d_flags)) ? SRV_NONE : SRV_OFFER_ETRN) 570*7c478bd9Sstevel@tonic-gate | (bitnset(D_AUTHREQ, d_flags) ? SRV_REQ_AUTH : SRV_NONE) 571*7c478bd9Sstevel@tonic-gate | (bitset(PRIV_NOEXPN, PrivacyFlags) ? SRV_NONE 572*7c478bd9Sstevel@tonic-gate : (SRV_OFFER_EXPN 573*7c478bd9Sstevel@tonic-gate | (bitset(PRIV_NOVERB, PrivacyFlags) 574*7c478bd9Sstevel@tonic-gate ? SRV_NONE : SRV_OFFER_VERB))) 575*7c478bd9Sstevel@tonic-gate | (bitset(PRIV_NORECEIPTS, PrivacyFlags) ? SRV_NONE 576*7c478bd9Sstevel@tonic-gate : SRV_OFFER_DSN) 577*7c478bd9Sstevel@tonic-gate #if SASL 578*7c478bd9Sstevel@tonic-gate | (bitnset(D_NOAUTH, d_flags) ? SRV_NONE : SRV_OFFER_AUTH) 579*7c478bd9Sstevel@tonic-gate | (bitset(SASL_SEC_NOPLAINTEXT, SASLOpts) ? SRV_REQ_SEC 580*7c478bd9Sstevel@tonic-gate : SRV_NONE) 581*7c478bd9Sstevel@tonic-gate #endif /* SASL */ 582*7c478bd9Sstevel@tonic-gate #if PIPELINING 583*7c478bd9Sstevel@tonic-gate | SRV_OFFER_PIPE 584*7c478bd9Sstevel@tonic-gate #endif /* PIPELINING */ 585*7c478bd9Sstevel@tonic-gate #if STARTTLS 586*7c478bd9Sstevel@tonic-gate | (bitnset(D_NOTLS, d_flags) ? SRV_NONE : SRV_OFFER_TLS) 587*7c478bd9Sstevel@tonic-gate | (bitset(TLS_I_NO_VRFY, TLS_Srv_Opts) ? SRV_NONE 588*7c478bd9Sstevel@tonic-gate : SRV_VRFY_CLT) 589*7c478bd9Sstevel@tonic-gate #endif /* STARTTLS */ 590*7c478bd9Sstevel@tonic-gate ; 591*7c478bd9Sstevel@tonic-gate if (nullserver == NULL) 592*7c478bd9Sstevel@tonic-gate { 593*7c478bd9Sstevel@tonic-gate features = srvfeatures(e, CurSmtpClient, features); 594*7c478bd9Sstevel@tonic-gate if (bitset(SRV_TMP_FAIL, features)) 595*7c478bd9Sstevel@tonic-gate { 596*7c478bd9Sstevel@tonic-gate if (LogLevel > 4) 597*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 598*7c478bd9Sstevel@tonic-gate "ERROR: srv_features=tempfail, relay=%.100s, access temporarily disabled", 599*7c478bd9Sstevel@tonic-gate CurSmtpClient); 600*7c478bd9Sstevel@tonic-gate nullserver = "450 4.3.0 Please try again later."; 601*7c478bd9Sstevel@tonic-gate } 602*7c478bd9Sstevel@tonic-gate else 603*7c478bd9Sstevel@tonic-gate { 604*7c478bd9Sstevel@tonic-gate #if PIPELINING 605*7c478bd9Sstevel@tonic-gate # if _FFR_NO_PIPE 606*7c478bd9Sstevel@tonic-gate if (bitset(SRV_NO_PIPE, features)) 607*7c478bd9Sstevel@tonic-gate { 608*7c478bd9Sstevel@tonic-gate /* for consistency */ 609*7c478bd9Sstevel@tonic-gate features &= ~SRV_OFFER_PIPE; 610*7c478bd9Sstevel@tonic-gate } 611*7c478bd9Sstevel@tonic-gate # endif /* _FFR_NO_PIPE */ 612*7c478bd9Sstevel@tonic-gate #endif /* PIPELINING */ 613*7c478bd9Sstevel@tonic-gate #if SASL 614*7c478bd9Sstevel@tonic-gate if (bitset(SRV_REQ_SEC, features)) 615*7c478bd9Sstevel@tonic-gate SASLOpts |= SASL_SEC_NOPLAINTEXT; 616*7c478bd9Sstevel@tonic-gate else 617*7c478bd9Sstevel@tonic-gate SASLOpts &= ~SASL_SEC_NOPLAINTEXT; 618*7c478bd9Sstevel@tonic-gate #endif /* SASL */ 619*7c478bd9Sstevel@tonic-gate } 620*7c478bd9Sstevel@tonic-gate } 621*7c478bd9Sstevel@tonic-gate else if (strncmp(nullserver, "421 ", 4) == 0) 622*7c478bd9Sstevel@tonic-gate { 623*7c478bd9Sstevel@tonic-gate message(nullserver); 624*7c478bd9Sstevel@tonic-gate goto doquit; 625*7c478bd9Sstevel@tonic-gate } 626*7c478bd9Sstevel@tonic-gate 627*7c478bd9Sstevel@tonic-gate hostname = macvalue('j', e); 628*7c478bd9Sstevel@tonic-gate #if SASL 629*7c478bd9Sstevel@tonic-gate if (AuthRealm == NULL) 630*7c478bd9Sstevel@tonic-gate AuthRealm = hostname; 631*7c478bd9Sstevel@tonic-gate sasl_ok = bitset(SRV_OFFER_AUTH, features); 632*7c478bd9Sstevel@tonic-gate n_mechs = 0; 633*7c478bd9Sstevel@tonic-gate authenticating = SASL_NOT_AUTH; 634*7c478bd9Sstevel@tonic-gate 635*7c478bd9Sstevel@tonic-gate /* SASL server new connection */ 636*7c478bd9Sstevel@tonic-gate if (sasl_ok) 637*7c478bd9Sstevel@tonic-gate { 638*7c478bd9Sstevel@tonic-gate # if SASL >= 20000 639*7c478bd9Sstevel@tonic-gate result = sasl_server_new("smtp", AuthRealm, NULL, NULL, NULL, 640*7c478bd9Sstevel@tonic-gate NULL, 0, &conn); 641*7c478bd9Sstevel@tonic-gate # elif SASL > 10505 642*7c478bd9Sstevel@tonic-gate /* use empty realm: only works in SASL > 1.5.5 */ 643*7c478bd9Sstevel@tonic-gate result = sasl_server_new("smtp", AuthRealm, "", NULL, 0, &conn); 644*7c478bd9Sstevel@tonic-gate # else /* SASL >= 20000 */ 645*7c478bd9Sstevel@tonic-gate /* use no realm -> realm is set to hostname by SASL lib */ 646*7c478bd9Sstevel@tonic-gate result = sasl_server_new("smtp", AuthRealm, NULL, NULL, 0, 647*7c478bd9Sstevel@tonic-gate &conn); 648*7c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */ 649*7c478bd9Sstevel@tonic-gate sasl_ok = result == SASL_OK; 650*7c478bd9Sstevel@tonic-gate if (!sasl_ok) 651*7c478bd9Sstevel@tonic-gate { 652*7c478bd9Sstevel@tonic-gate if (LogLevel > 9) 653*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID, 654*7c478bd9Sstevel@tonic-gate "AUTH error: sasl_server_new failed=%d", 655*7c478bd9Sstevel@tonic-gate result); 656*7c478bd9Sstevel@tonic-gate } 657*7c478bd9Sstevel@tonic-gate } 658*7c478bd9Sstevel@tonic-gate if (sasl_ok) 659*7c478bd9Sstevel@tonic-gate { 660*7c478bd9Sstevel@tonic-gate /* 661*7c478bd9Sstevel@tonic-gate ** SASL set properties for sasl 662*7c478bd9Sstevel@tonic-gate ** set local/remote IP 663*7c478bd9Sstevel@tonic-gate ** XXX Cyrus SASL v1 only supports IPv4 664*7c478bd9Sstevel@tonic-gate ** 665*7c478bd9Sstevel@tonic-gate ** XXX where exactly are these used/required? 666*7c478bd9Sstevel@tonic-gate ** Kerberos_v4 667*7c478bd9Sstevel@tonic-gate */ 668*7c478bd9Sstevel@tonic-gate 669*7c478bd9Sstevel@tonic-gate # if SASL >= 20000 670*7c478bd9Sstevel@tonic-gate localip[0] = remoteip[0] = '\0'; 671*7c478bd9Sstevel@tonic-gate # if NETINET || NETINET6 672*7c478bd9Sstevel@tonic-gate in = macvalue(macid("{daemon_family}"), e); 673*7c478bd9Sstevel@tonic-gate if (in != NULL && ( 674*7c478bd9Sstevel@tonic-gate # if NETINET6 675*7c478bd9Sstevel@tonic-gate strcmp(in, "inet6") == 0 || 676*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 677*7c478bd9Sstevel@tonic-gate strcmp(in, "inet") == 0)) 678*7c478bd9Sstevel@tonic-gate { 679*7c478bd9Sstevel@tonic-gate SOCKADDR_LEN_T addrsize; 680*7c478bd9Sstevel@tonic-gate SOCKADDR saddr_l; 681*7c478bd9Sstevel@tonic-gate SOCKADDR saddr_r; 682*7c478bd9Sstevel@tonic-gate 683*7c478bd9Sstevel@tonic-gate addrsize = sizeof(saddr_r); 684*7c478bd9Sstevel@tonic-gate if (getpeername(sm_io_getinfo(InChannel, SM_IO_WHAT_FD, 685*7c478bd9Sstevel@tonic-gate NULL), 686*7c478bd9Sstevel@tonic-gate (struct sockaddr *) &saddr_r, 687*7c478bd9Sstevel@tonic-gate &addrsize) == 0) 688*7c478bd9Sstevel@tonic-gate { 689*7c478bd9Sstevel@tonic-gate if (iptostring(&saddr_r, addrsize, 690*7c478bd9Sstevel@tonic-gate remoteip, sizeof remoteip)) 691*7c478bd9Sstevel@tonic-gate { 692*7c478bd9Sstevel@tonic-gate sasl_setprop(conn, SASL_IPREMOTEPORT, 693*7c478bd9Sstevel@tonic-gate remoteip); 694*7c478bd9Sstevel@tonic-gate } 695*7c478bd9Sstevel@tonic-gate addrsize = sizeof(saddr_l); 696*7c478bd9Sstevel@tonic-gate if (getsockname(sm_io_getinfo(InChannel, 697*7c478bd9Sstevel@tonic-gate SM_IO_WHAT_FD, 698*7c478bd9Sstevel@tonic-gate NULL), 699*7c478bd9Sstevel@tonic-gate (struct sockaddr *) &saddr_l, 700*7c478bd9Sstevel@tonic-gate &addrsize) == 0) 701*7c478bd9Sstevel@tonic-gate { 702*7c478bd9Sstevel@tonic-gate if (iptostring(&saddr_l, addrsize, 703*7c478bd9Sstevel@tonic-gate localip, 704*7c478bd9Sstevel@tonic-gate sizeof localip)) 705*7c478bd9Sstevel@tonic-gate { 706*7c478bd9Sstevel@tonic-gate sasl_setprop(conn, 707*7c478bd9Sstevel@tonic-gate SASL_IPLOCALPORT, 708*7c478bd9Sstevel@tonic-gate localip); 709*7c478bd9Sstevel@tonic-gate } 710*7c478bd9Sstevel@tonic-gate } 711*7c478bd9Sstevel@tonic-gate } 712*7c478bd9Sstevel@tonic-gate } 713*7c478bd9Sstevel@tonic-gate # endif /* NETINET || NETINET6 */ 714*7c478bd9Sstevel@tonic-gate # else /* SASL >= 20000 */ 715*7c478bd9Sstevel@tonic-gate # if NETINET 716*7c478bd9Sstevel@tonic-gate in = macvalue(macid("{daemon_family}"), e); 717*7c478bd9Sstevel@tonic-gate if (in != NULL && strcmp(in, "inet") == 0) 718*7c478bd9Sstevel@tonic-gate { 719*7c478bd9Sstevel@tonic-gate SOCKADDR_LEN_T addrsize; 720*7c478bd9Sstevel@tonic-gate 721*7c478bd9Sstevel@tonic-gate addrsize = sizeof(struct sockaddr_in); 722*7c478bd9Sstevel@tonic-gate if (getpeername(sm_io_getinfo(InChannel, SM_IO_WHAT_FD, 723*7c478bd9Sstevel@tonic-gate NULL), 724*7c478bd9Sstevel@tonic-gate (struct sockaddr *)&saddr_r, 725*7c478bd9Sstevel@tonic-gate &addrsize) == 0) 726*7c478bd9Sstevel@tonic-gate { 727*7c478bd9Sstevel@tonic-gate sasl_setprop(conn, SASL_IP_REMOTE, &saddr_r); 728*7c478bd9Sstevel@tonic-gate addrsize = sizeof(struct sockaddr_in); 729*7c478bd9Sstevel@tonic-gate if (getsockname(sm_io_getinfo(InChannel, 730*7c478bd9Sstevel@tonic-gate SM_IO_WHAT_FD, 731*7c478bd9Sstevel@tonic-gate NULL), 732*7c478bd9Sstevel@tonic-gate (struct sockaddr *)&saddr_l, 733*7c478bd9Sstevel@tonic-gate &addrsize) == 0) 734*7c478bd9Sstevel@tonic-gate sasl_setprop(conn, SASL_IP_LOCAL, 735*7c478bd9Sstevel@tonic-gate &saddr_l); 736*7c478bd9Sstevel@tonic-gate } 737*7c478bd9Sstevel@tonic-gate } 738*7c478bd9Sstevel@tonic-gate # endif /* NETINET */ 739*7c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */ 740*7c478bd9Sstevel@tonic-gate 741*7c478bd9Sstevel@tonic-gate auth_type = NULL; 742*7c478bd9Sstevel@tonic-gate mechlist = NULL; 743*7c478bd9Sstevel@tonic-gate user = NULL; 744*7c478bd9Sstevel@tonic-gate # if 0 745*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_PERM, 746*7c478bd9Sstevel@tonic-gate macid("{auth_author}"), NULL); 747*7c478bd9Sstevel@tonic-gate # endif /* 0 */ 748*7c478bd9Sstevel@tonic-gate 749*7c478bd9Sstevel@tonic-gate /* set properties */ 750*7c478bd9Sstevel@tonic-gate (void) memset(&ssp, '\0', sizeof ssp); 751*7c478bd9Sstevel@tonic-gate 752*7c478bd9Sstevel@tonic-gate /* XXX should these be options settable via .cf ? */ 753*7c478bd9Sstevel@tonic-gate /* ssp.min_ssf = 0; is default due to memset() */ 754*7c478bd9Sstevel@tonic-gate { 755*7c478bd9Sstevel@tonic-gate ssp.max_ssf = MaxSLBits; 756*7c478bd9Sstevel@tonic-gate ssp.maxbufsize = MAXOUTLEN; 757*7c478bd9Sstevel@tonic-gate } 758*7c478bd9Sstevel@tonic-gate ssp.security_flags = SASLOpts & SASL_SEC_MASK; 759*7c478bd9Sstevel@tonic-gate sasl_ok = sasl_setprop(conn, SASL_SEC_PROPS, &ssp) == SASL_OK; 760*7c478bd9Sstevel@tonic-gate 761*7c478bd9Sstevel@tonic-gate if (sasl_ok) 762*7c478bd9Sstevel@tonic-gate { 763*7c478bd9Sstevel@tonic-gate /* 764*7c478bd9Sstevel@tonic-gate ** external security strength factor; 765*7c478bd9Sstevel@tonic-gate ** currently we have none so zero 766*7c478bd9Sstevel@tonic-gate */ 767*7c478bd9Sstevel@tonic-gate 768*7c478bd9Sstevel@tonic-gate # if SASL >= 20000 769*7c478bd9Sstevel@tonic-gate ext_ssf = 0; 770*7c478bd9Sstevel@tonic-gate auth_id = NULL; 771*7c478bd9Sstevel@tonic-gate sasl_ok = ((sasl_setprop(conn, SASL_SSF_EXTERNAL, 772*7c478bd9Sstevel@tonic-gate &ext_ssf) == SASL_OK) && 773*7c478bd9Sstevel@tonic-gate (sasl_setprop(conn, SASL_AUTH_EXTERNAL, 774*7c478bd9Sstevel@tonic-gate auth_id) == SASL_OK)); 775*7c478bd9Sstevel@tonic-gate # else /* SASL >= 20000 */ 776*7c478bd9Sstevel@tonic-gate ext_ssf.ssf = 0; 777*7c478bd9Sstevel@tonic-gate ext_ssf.auth_id = NULL; 778*7c478bd9Sstevel@tonic-gate sasl_ok = sasl_setprop(conn, SASL_SSF_EXTERNAL, 779*7c478bd9Sstevel@tonic-gate &ext_ssf) == SASL_OK; 780*7c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */ 781*7c478bd9Sstevel@tonic-gate } 782*7c478bd9Sstevel@tonic-gate if (sasl_ok) 783*7c478bd9Sstevel@tonic-gate n_mechs = saslmechs(conn, &mechlist); 784*7c478bd9Sstevel@tonic-gate } 785*7c478bd9Sstevel@tonic-gate #endif /* SASL */ 786*7c478bd9Sstevel@tonic-gate 787*7c478bd9Sstevel@tonic-gate #if STARTTLS 788*7c478bd9Sstevel@tonic-gate #endif /* STARTTLS */ 789*7c478bd9Sstevel@tonic-gate 790*7c478bd9Sstevel@tonic-gate #if MILTER 791*7c478bd9Sstevel@tonic-gate if (smtp.sm_milterize) 792*7c478bd9Sstevel@tonic-gate { 793*7c478bd9Sstevel@tonic-gate char state; 794*7c478bd9Sstevel@tonic-gate 795*7c478bd9Sstevel@tonic-gate /* initialize mail filter connection */ 796*7c478bd9Sstevel@tonic-gate smtp.sm_milterlist = milter_init(e, &state); 797*7c478bd9Sstevel@tonic-gate switch (state) 798*7c478bd9Sstevel@tonic-gate { 799*7c478bd9Sstevel@tonic-gate case SMFIR_REJECT: 800*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 3) 801*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 802*7c478bd9Sstevel@tonic-gate "Milter: initialization failed, rejecting commands"); 803*7c478bd9Sstevel@tonic-gate greetcode = "554"; 804*7c478bd9Sstevel@tonic-gate nullserver = "Command rejected"; 805*7c478bd9Sstevel@tonic-gate smtp.sm_milterize = false; 806*7c478bd9Sstevel@tonic-gate break; 807*7c478bd9Sstevel@tonic-gate 808*7c478bd9Sstevel@tonic-gate case SMFIR_TEMPFAIL: 809*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 3) 810*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 811*7c478bd9Sstevel@tonic-gate "Milter: initialization failed, temp failing commands"); 812*7c478bd9Sstevel@tonic-gate tempfail = true; 813*7c478bd9Sstevel@tonic-gate smtp.sm_milterize = false; 814*7c478bd9Sstevel@tonic-gate break; 815*7c478bd9Sstevel@tonic-gate } 816*7c478bd9Sstevel@tonic-gate } 817*7c478bd9Sstevel@tonic-gate 818*7c478bd9Sstevel@tonic-gate if (smtp.sm_milterlist && smtp.sm_milterize && 819*7c478bd9Sstevel@tonic-gate !bitset(EF_DISCARD, e->e_flags)) 820*7c478bd9Sstevel@tonic-gate { 821*7c478bd9Sstevel@tonic-gate char state; 822*7c478bd9Sstevel@tonic-gate char *response; 823*7c478bd9Sstevel@tonic-gate 824*7c478bd9Sstevel@tonic-gate response = milter_connect(peerhostname, RealHostAddr, 825*7c478bd9Sstevel@tonic-gate e, &state); 826*7c478bd9Sstevel@tonic-gate switch (state) 827*7c478bd9Sstevel@tonic-gate { 828*7c478bd9Sstevel@tonic-gate case SMFIR_REPLYCODE: /* REPLYCODE shouldn't happen */ 829*7c478bd9Sstevel@tonic-gate case SMFIR_REJECT: 830*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 3) 831*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 832*7c478bd9Sstevel@tonic-gate "Milter: connect: host=%s, addr=%s, rejecting commands", 833*7c478bd9Sstevel@tonic-gate peerhostname, 834*7c478bd9Sstevel@tonic-gate anynet_ntoa(&RealHostAddr)); 835*7c478bd9Sstevel@tonic-gate greetcode = "554"; 836*7c478bd9Sstevel@tonic-gate nullserver = "Command rejected"; 837*7c478bd9Sstevel@tonic-gate smtp.sm_milterize = false; 838*7c478bd9Sstevel@tonic-gate break; 839*7c478bd9Sstevel@tonic-gate 840*7c478bd9Sstevel@tonic-gate case SMFIR_TEMPFAIL: 841*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 3) 842*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 843*7c478bd9Sstevel@tonic-gate "Milter: connect: host=%s, addr=%s, temp failing commands", 844*7c478bd9Sstevel@tonic-gate peerhostname, 845*7c478bd9Sstevel@tonic-gate anynet_ntoa(&RealHostAddr)); 846*7c478bd9Sstevel@tonic-gate tempfail = true; 847*7c478bd9Sstevel@tonic-gate smtp.sm_milterize = false; 848*7c478bd9Sstevel@tonic-gate break; 849*7c478bd9Sstevel@tonic-gate 850*7c478bd9Sstevel@tonic-gate case SMFIR_SHUTDOWN: 851*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 3) 852*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 853*7c478bd9Sstevel@tonic-gate "Milter: connect: host=%s, addr=%s, shutdown", 854*7c478bd9Sstevel@tonic-gate peerhostname, 855*7c478bd9Sstevel@tonic-gate anynet_ntoa(&RealHostAddr)); 856*7c478bd9Sstevel@tonic-gate tempfail = true; 857*7c478bd9Sstevel@tonic-gate smtp.sm_milterize = false; 858*7c478bd9Sstevel@tonic-gate message("421 4.7.0 %s closing connection", 859*7c478bd9Sstevel@tonic-gate MyHostName); 860*7c478bd9Sstevel@tonic-gate 861*7c478bd9Sstevel@tonic-gate /* arrange to ignore send list */ 862*7c478bd9Sstevel@tonic-gate e->e_sendqueue = NULL; 863*7c478bd9Sstevel@tonic-gate goto doquit; 864*7c478bd9Sstevel@tonic-gate } 865*7c478bd9Sstevel@tonic-gate if (response != NULL) 866*7c478bd9Sstevel@tonic-gate sm_free(response); /* XXX */ 867*7c478bd9Sstevel@tonic-gate } 868*7c478bd9Sstevel@tonic-gate #endif /* MILTER */ 869*7c478bd9Sstevel@tonic-gate 870*7c478bd9Sstevel@tonic-gate /* 871*7c478bd9Sstevel@tonic-gate ** Broken proxies and SMTP slammers 872*7c478bd9Sstevel@tonic-gate ** push data without waiting, catch them 873*7c478bd9Sstevel@tonic-gate */ 874*7c478bd9Sstevel@tonic-gate 875*7c478bd9Sstevel@tonic-gate if ( 876*7c478bd9Sstevel@tonic-gate #if STARTTLS 877*7c478bd9Sstevel@tonic-gate !smtps && 878*7c478bd9Sstevel@tonic-gate #endif /* STARTTLS */ 879*7c478bd9Sstevel@tonic-gate *greetcode == '2') 880*7c478bd9Sstevel@tonic-gate { 881*7c478bd9Sstevel@tonic-gate time_t msecs = 0; 882*7c478bd9Sstevel@tonic-gate char **pvp; 883*7c478bd9Sstevel@tonic-gate char pvpbuf[PSBUFSIZE]; 884*7c478bd9Sstevel@tonic-gate 885*7c478bd9Sstevel@tonic-gate /* Ask the rulesets how long to pause */ 886*7c478bd9Sstevel@tonic-gate pvp = NULL; 887*7c478bd9Sstevel@tonic-gate r = rscap("greet_pause", peerhostname, 888*7c478bd9Sstevel@tonic-gate anynet_ntoa(&RealHostAddr), e, 889*7c478bd9Sstevel@tonic-gate &pvp, pvpbuf, sizeof(pvpbuf)); 890*7c478bd9Sstevel@tonic-gate if (r == EX_OK && pvp != NULL && pvp[0] != NULL && 891*7c478bd9Sstevel@tonic-gate (pvp[0][0] & 0377) == CANONNET && pvp[1] != NULL) 892*7c478bd9Sstevel@tonic-gate { 893*7c478bd9Sstevel@tonic-gate msecs = strtol(pvp[1], NULL, 10); 894*7c478bd9Sstevel@tonic-gate } 895*7c478bd9Sstevel@tonic-gate 896*7c478bd9Sstevel@tonic-gate if (msecs > 0) 897*7c478bd9Sstevel@tonic-gate { 898*7c478bd9Sstevel@tonic-gate int fd; 899*7c478bd9Sstevel@tonic-gate fd_set readfds; 900*7c478bd9Sstevel@tonic-gate struct timeval timeout; 901*7c478bd9Sstevel@tonic-gate 902*7c478bd9Sstevel@tonic-gate /* pause for a moment */ 903*7c478bd9Sstevel@tonic-gate timeout.tv_sec = msecs / 1000; 904*7c478bd9Sstevel@tonic-gate timeout.tv_usec = (msecs % 1000) * 1000; 905*7c478bd9Sstevel@tonic-gate 906*7c478bd9Sstevel@tonic-gate /* Obey RFC 2821: 4.3.5.2: 220 timeout of 5 minutes */ 907*7c478bd9Sstevel@tonic-gate if (timeout.tv_sec >= 300) 908*7c478bd9Sstevel@tonic-gate { 909*7c478bd9Sstevel@tonic-gate timeout.tv_sec = 300; 910*7c478bd9Sstevel@tonic-gate timeout.tv_usec = 0; 911*7c478bd9Sstevel@tonic-gate } 912*7c478bd9Sstevel@tonic-gate 913*7c478bd9Sstevel@tonic-gate /* check if data is on the socket during the pause */ 914*7c478bd9Sstevel@tonic-gate fd = sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL); 915*7c478bd9Sstevel@tonic-gate FD_ZERO(&readfds); 916*7c478bd9Sstevel@tonic-gate SM_FD_SET(fd, &readfds); 917*7c478bd9Sstevel@tonic-gate if (select(fd + 1, FDSET_CAST &readfds, 918*7c478bd9Sstevel@tonic-gate NULL, NULL, &timeout) > 0 && 919*7c478bd9Sstevel@tonic-gate FD_ISSET(fd, &readfds)) 920*7c478bd9Sstevel@tonic-gate { 921*7c478bd9Sstevel@tonic-gate greetcode = "554"; 922*7c478bd9Sstevel@tonic-gate nullserver = "Command rejected"; 923*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 924*7c478bd9Sstevel@tonic-gate "rejecting commands from %s [%s] due to pre-greeting traffic", 925*7c478bd9Sstevel@tonic-gate peerhostname, 926*7c478bd9Sstevel@tonic-gate anynet_ntoa(&RealHostAddr)); 927*7c478bd9Sstevel@tonic-gate } 928*7c478bd9Sstevel@tonic-gate } 929*7c478bd9Sstevel@tonic-gate } 930*7c478bd9Sstevel@tonic-gate 931*7c478bd9Sstevel@tonic-gate #if STARTTLS 932*7c478bd9Sstevel@tonic-gate /* If this an smtps connection, start TLS now */ 933*7c478bd9Sstevel@tonic-gate if (smtps) 934*7c478bd9Sstevel@tonic-gate { 935*7c478bd9Sstevel@tonic-gate Errors = 0; 936*7c478bd9Sstevel@tonic-gate goto starttls; 937*7c478bd9Sstevel@tonic-gate } 938*7c478bd9Sstevel@tonic-gate 939*7c478bd9Sstevel@tonic-gate greeting: 940*7c478bd9Sstevel@tonic-gate 941*7c478bd9Sstevel@tonic-gate #endif /* STARTTLS */ 942*7c478bd9Sstevel@tonic-gate 943*7c478bd9Sstevel@tonic-gate /* output the first line, inserting "ESMTP" as second word */ 944*7c478bd9Sstevel@tonic-gate if (*greetcode == '5') 945*7c478bd9Sstevel@tonic-gate (void) sm_snprintf(inp, sizeof inp, "%s not accepting messages", 946*7c478bd9Sstevel@tonic-gate hostname); 947*7c478bd9Sstevel@tonic-gate else 948*7c478bd9Sstevel@tonic-gate expand(SmtpGreeting, inp, sizeof inp, e); 949*7c478bd9Sstevel@tonic-gate 950*7c478bd9Sstevel@tonic-gate p = strchr(inp, '\n'); 951*7c478bd9Sstevel@tonic-gate if (p != NULL) 952*7c478bd9Sstevel@tonic-gate *p++ = '\0'; 953*7c478bd9Sstevel@tonic-gate id = strchr(inp, ' '); 954*7c478bd9Sstevel@tonic-gate if (id == NULL) 955*7c478bd9Sstevel@tonic-gate id = &inp[strlen(inp)]; 956*7c478bd9Sstevel@tonic-gate if (p == NULL) 957*7c478bd9Sstevel@tonic-gate (void) sm_snprintf(cmdbuf, sizeof cmdbuf, 958*7c478bd9Sstevel@tonic-gate "%s %%.*s ESMTP%%s", greetcode); 959*7c478bd9Sstevel@tonic-gate else 960*7c478bd9Sstevel@tonic-gate (void) sm_snprintf(cmdbuf, sizeof cmdbuf, 961*7c478bd9Sstevel@tonic-gate "%s-%%.*s ESMTP%%s", greetcode); 962*7c478bd9Sstevel@tonic-gate message(cmdbuf, (int) (id - inp), inp, id); 963*7c478bd9Sstevel@tonic-gate 964*7c478bd9Sstevel@tonic-gate /* output remaining lines */ 965*7c478bd9Sstevel@tonic-gate while ((id = p) != NULL && (p = strchr(id, '\n')) != NULL) 966*7c478bd9Sstevel@tonic-gate { 967*7c478bd9Sstevel@tonic-gate *p++ = '\0'; 968*7c478bd9Sstevel@tonic-gate if (isascii(*id) && isspace(*id)) 969*7c478bd9Sstevel@tonic-gate id++; 970*7c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(cmdbuf, sizeof cmdbuf, 2, greetcode, "-%s"); 971*7c478bd9Sstevel@tonic-gate message(cmdbuf, id); 972*7c478bd9Sstevel@tonic-gate } 973*7c478bd9Sstevel@tonic-gate if (id != NULL) 974*7c478bd9Sstevel@tonic-gate { 975*7c478bd9Sstevel@tonic-gate if (isascii(*id) && isspace(*id)) 976*7c478bd9Sstevel@tonic-gate id++; 977*7c478bd9Sstevel@tonic-gate (void) sm_strlcpyn(cmdbuf, sizeof cmdbuf, 2, greetcode, " %s"); 978*7c478bd9Sstevel@tonic-gate message(cmdbuf, id); 979*7c478bd9Sstevel@tonic-gate } 980*7c478bd9Sstevel@tonic-gate 981*7c478bd9Sstevel@tonic-gate protocol = NULL; 982*7c478bd9Sstevel@tonic-gate sendinghost = macvalue('s', e); 983*7c478bd9Sstevel@tonic-gate 984*7c478bd9Sstevel@tonic-gate /* If quarantining by a connect/ehlo action, save between messages */ 985*7c478bd9Sstevel@tonic-gate if (e->e_quarmsg == NULL) 986*7c478bd9Sstevel@tonic-gate smtp.sm_quarmsg = NULL; 987*7c478bd9Sstevel@tonic-gate else 988*7c478bd9Sstevel@tonic-gate smtp.sm_quarmsg = newstr(e->e_quarmsg); 989*7c478bd9Sstevel@tonic-gate 990*7c478bd9Sstevel@tonic-gate /* sendinghost's storage must outlive the current envelope */ 991*7c478bd9Sstevel@tonic-gate if (sendinghost != NULL) 992*7c478bd9Sstevel@tonic-gate sendinghost = sm_strdup_x(sendinghost); 993*7c478bd9Sstevel@tonic-gate #if _FFR_BLOCK_PROXIES 994*7c478bd9Sstevel@tonic-gate first = true; 995*7c478bd9Sstevel@tonic-gate #endif /* _FFR_BLOCK_PROXIES */ 996*7c478bd9Sstevel@tonic-gate gothello = false; 997*7c478bd9Sstevel@tonic-gate smtp.sm_gotmail = false; 998*7c478bd9Sstevel@tonic-gate for (;;) 999*7c478bd9Sstevel@tonic-gate { 1000*7c478bd9Sstevel@tonic-gate SM_TRY 1001*7c478bd9Sstevel@tonic-gate { 1002*7c478bd9Sstevel@tonic-gate QuickAbort = false; 1003*7c478bd9Sstevel@tonic-gate HoldErrs = false; 1004*7c478bd9Sstevel@tonic-gate SuprErrs = false; 1005*7c478bd9Sstevel@tonic-gate LogUsrErrs = false; 1006*7c478bd9Sstevel@tonic-gate OnlyOneError = true; 1007*7c478bd9Sstevel@tonic-gate e->e_flags &= ~(EF_VRFYONLY|EF_GLOBALERRS); 1008*7c478bd9Sstevel@tonic-gate 1009*7c478bd9Sstevel@tonic-gate /* setup for the read */ 1010*7c478bd9Sstevel@tonic-gate e->e_to = NULL; 1011*7c478bd9Sstevel@tonic-gate Errors = 0; 1012*7c478bd9Sstevel@tonic-gate FileName = NULL; 1013*7c478bd9Sstevel@tonic-gate (void) sm_io_flush(smioout, SM_TIME_DEFAULT); 1014*7c478bd9Sstevel@tonic-gate 1015*7c478bd9Sstevel@tonic-gate /* read the input line */ 1016*7c478bd9Sstevel@tonic-gate SmtpPhase = "server cmd read"; 1017*7c478bd9Sstevel@tonic-gate sm_setproctitle(true, e, "server %s cmd read", CurSmtpClient); 1018*7c478bd9Sstevel@tonic-gate #if SASL 1019*7c478bd9Sstevel@tonic-gate /* 1020*7c478bd9Sstevel@tonic-gate ** XXX SMTP AUTH requires accepting any length, 1021*7c478bd9Sstevel@tonic-gate ** at least for challenge/response 1022*7c478bd9Sstevel@tonic-gate */ 1023*7c478bd9Sstevel@tonic-gate #endif /* SASL */ 1024*7c478bd9Sstevel@tonic-gate 1025*7c478bd9Sstevel@tonic-gate /* handle errors */ 1026*7c478bd9Sstevel@tonic-gate if (sm_io_error(OutChannel) || 1027*7c478bd9Sstevel@tonic-gate (p = sfgets(inp, sizeof inp, InChannel, 1028*7c478bd9Sstevel@tonic-gate TimeOuts.to_nextcommand, SmtpPhase)) == NULL) 1029*7c478bd9Sstevel@tonic-gate { 1030*7c478bd9Sstevel@tonic-gate char *d; 1031*7c478bd9Sstevel@tonic-gate 1032*7c478bd9Sstevel@tonic-gate d = macvalue(macid("{daemon_name}"), e); 1033*7c478bd9Sstevel@tonic-gate if (d == NULL) 1034*7c478bd9Sstevel@tonic-gate d = "stdin"; 1035*7c478bd9Sstevel@tonic-gate /* end of file, just die */ 1036*7c478bd9Sstevel@tonic-gate disconnect(1, e); 1037*7c478bd9Sstevel@tonic-gate 1038*7c478bd9Sstevel@tonic-gate #if MILTER 1039*7c478bd9Sstevel@tonic-gate /* close out milter filters */ 1040*7c478bd9Sstevel@tonic-gate milter_quit(e); 1041*7c478bd9Sstevel@tonic-gate #endif /* MILTER */ 1042*7c478bd9Sstevel@tonic-gate 1043*7c478bd9Sstevel@tonic-gate message("421 4.4.1 %s Lost input channel from %s", 1044*7c478bd9Sstevel@tonic-gate MyHostName, CurSmtpClient); 1045*7c478bd9Sstevel@tonic-gate if (LogLevel > (smtp.sm_gotmail ? 1 : 19)) 1046*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_NOTICE, e->e_id, 1047*7c478bd9Sstevel@tonic-gate "lost input channel from %s to %s after %s", 1048*7c478bd9Sstevel@tonic-gate CurSmtpClient, d, 1049*7c478bd9Sstevel@tonic-gate (c == NULL || c->cmd_name == NULL) ? "startup" : c->cmd_name); 1050*7c478bd9Sstevel@tonic-gate /* 1051*7c478bd9Sstevel@tonic-gate ** If have not accepted mail (DATA), do not bounce 1052*7c478bd9Sstevel@tonic-gate ** bad addresses back to sender. 1053*7c478bd9Sstevel@tonic-gate */ 1054*7c478bd9Sstevel@tonic-gate 1055*7c478bd9Sstevel@tonic-gate if (bitset(EF_CLRQUEUE, e->e_flags)) 1056*7c478bd9Sstevel@tonic-gate e->e_sendqueue = NULL; 1057*7c478bd9Sstevel@tonic-gate goto doquit; 1058*7c478bd9Sstevel@tonic-gate } 1059*7c478bd9Sstevel@tonic-gate 1060*7c478bd9Sstevel@tonic-gate #if _FFR_BLOCK_PROXIES 1061*7c478bd9Sstevel@tonic-gate if (first) 1062*7c478bd9Sstevel@tonic-gate { 1063*7c478bd9Sstevel@tonic-gate size_t inplen, cmdlen; 1064*7c478bd9Sstevel@tonic-gate int idx; 1065*7c478bd9Sstevel@tonic-gate char *http_cmd; 1066*7c478bd9Sstevel@tonic-gate static char *http_cmds[] = { "GET", "POST", 1067*7c478bd9Sstevel@tonic-gate "CONNECT", "USER", NULL }; 1068*7c478bd9Sstevel@tonic-gate 1069*7c478bd9Sstevel@tonic-gate inplen = strlen(inp); 1070*7c478bd9Sstevel@tonic-gate for (idx = 0; (http_cmd = http_cmds[idx]) != NULL; 1071*7c478bd9Sstevel@tonic-gate idx++) 1072*7c478bd9Sstevel@tonic-gate { 1073*7c478bd9Sstevel@tonic-gate cmdlen = strlen(http_cmd); 1074*7c478bd9Sstevel@tonic-gate if (cmdlen < inplen && 1075*7c478bd9Sstevel@tonic-gate sm_strncasecmp(inp, http_cmd, cmdlen) == 0 && 1076*7c478bd9Sstevel@tonic-gate isascii(inp[cmdlen]) && isspace(inp[cmdlen])) 1077*7c478bd9Sstevel@tonic-gate { 1078*7c478bd9Sstevel@tonic-gate /* Open proxy, drop it */ 1079*7c478bd9Sstevel@tonic-gate message("421 4.7.0 %s Rejecting open proxy %s", 1080*7c478bd9Sstevel@tonic-gate MyHostName, CurSmtpClient); 1081*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 1082*7c478bd9Sstevel@tonic-gate "%s: probable open proxy: command=%.40s", 1083*7c478bd9Sstevel@tonic-gate CurSmtpClient, inp); 1084*7c478bd9Sstevel@tonic-gate goto doquit; 1085*7c478bd9Sstevel@tonic-gate } 1086*7c478bd9Sstevel@tonic-gate } 1087*7c478bd9Sstevel@tonic-gate first = false; 1088*7c478bd9Sstevel@tonic-gate } 1089*7c478bd9Sstevel@tonic-gate #endif /* _FFR_BLOCK_PROXIES */ 1090*7c478bd9Sstevel@tonic-gate 1091*7c478bd9Sstevel@tonic-gate /* clean up end of line */ 1092*7c478bd9Sstevel@tonic-gate fixcrlf(inp, true); 1093*7c478bd9Sstevel@tonic-gate 1094*7c478bd9Sstevel@tonic-gate #if PIPELINING 1095*7c478bd9Sstevel@tonic-gate # if _FFR_NO_PIPE 1096*7c478bd9Sstevel@tonic-gate /* 1097*7c478bd9Sstevel@tonic-gate ** if there is more input and pipelining is disabled: 1098*7c478bd9Sstevel@tonic-gate ** delay ... (and maybe discard the input?) 1099*7c478bd9Sstevel@tonic-gate ** XXX this doesn't really work, at least in tests using 1100*7c478bd9Sstevel@tonic-gate ** telnet SM_IO_IS_READABLE only returns 1 if there were 1101*7c478bd9Sstevel@tonic-gate ** more than 2 input lines available. 1102*7c478bd9Sstevel@tonic-gate */ 1103*7c478bd9Sstevel@tonic-gate 1104*7c478bd9Sstevel@tonic-gate if (bitset(SRV_NO_PIPE, features) && 1105*7c478bd9Sstevel@tonic-gate sm_io_getinfo(InChannel, SM_IO_IS_READABLE, NULL) > 0) 1106*7c478bd9Sstevel@tonic-gate { 1107*7c478bd9Sstevel@tonic-gate if (++np_log < 3) 1108*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 1109*7c478bd9Sstevel@tonic-gate "unauthorized PIPELINING, sleeping"); 1110*7c478bd9Sstevel@tonic-gate sleep(1); 1111*7c478bd9Sstevel@tonic-gate } 1112*7c478bd9Sstevel@tonic-gate 1113*7c478bd9Sstevel@tonic-gate # endif /* _FFR_NO_PIPE */ 1114*7c478bd9Sstevel@tonic-gate #endif /* PIPELINING */ 1115*7c478bd9Sstevel@tonic-gate 1116*7c478bd9Sstevel@tonic-gate #if SASL 1117*7c478bd9Sstevel@tonic-gate if (authenticating == SASL_PROC_AUTH) 1118*7c478bd9Sstevel@tonic-gate { 1119*7c478bd9Sstevel@tonic-gate # if 0 1120*7c478bd9Sstevel@tonic-gate if (*inp == '\0') 1121*7c478bd9Sstevel@tonic-gate { 1122*7c478bd9Sstevel@tonic-gate authenticating = SASL_NOT_AUTH; 1123*7c478bd9Sstevel@tonic-gate message("501 5.5.2 missing input"); 1124*7c478bd9Sstevel@tonic-gate RESET_SASLCONN; 1125*7c478bd9Sstevel@tonic-gate continue; 1126*7c478bd9Sstevel@tonic-gate } 1127*7c478bd9Sstevel@tonic-gate # endif /* 0 */ 1128*7c478bd9Sstevel@tonic-gate if (*inp == '*' && *(inp + 1) == '\0') 1129*7c478bd9Sstevel@tonic-gate { 1130*7c478bd9Sstevel@tonic-gate authenticating = SASL_NOT_AUTH; 1131*7c478bd9Sstevel@tonic-gate 1132*7c478bd9Sstevel@tonic-gate /* rfc 2254 4. */ 1133*7c478bd9Sstevel@tonic-gate message("501 5.0.0 AUTH aborted"); 1134*7c478bd9Sstevel@tonic-gate RESET_SASLCONN; 1135*7c478bd9Sstevel@tonic-gate continue; 1136*7c478bd9Sstevel@tonic-gate } 1137*7c478bd9Sstevel@tonic-gate 1138*7c478bd9Sstevel@tonic-gate /* could this be shorter? XXX */ 1139*7c478bd9Sstevel@tonic-gate # if SASL >= 20000 1140*7c478bd9Sstevel@tonic-gate in = xalloc(strlen(inp) + 1); 1141*7c478bd9Sstevel@tonic-gate result = sasl_decode64(inp, strlen(inp), in, 1142*7c478bd9Sstevel@tonic-gate strlen(inp), &inlen); 1143*7c478bd9Sstevel@tonic-gate # else /* SASL >= 20000 */ 1144*7c478bd9Sstevel@tonic-gate out = xalloc(strlen(inp)); 1145*7c478bd9Sstevel@tonic-gate result = sasl_decode64(inp, strlen(inp), out, &outlen); 1146*7c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */ 1147*7c478bd9Sstevel@tonic-gate if (result != SASL_OK) 1148*7c478bd9Sstevel@tonic-gate { 1149*7c478bd9Sstevel@tonic-gate authenticating = SASL_NOT_AUTH; 1150*7c478bd9Sstevel@tonic-gate 1151*7c478bd9Sstevel@tonic-gate /* rfc 2254 4. */ 1152*7c478bd9Sstevel@tonic-gate message("501 5.5.4 cannot decode AUTH parameter %s", 1153*7c478bd9Sstevel@tonic-gate inp); 1154*7c478bd9Sstevel@tonic-gate # if SASL >= 20000 1155*7c478bd9Sstevel@tonic-gate sm_free(in); 1156*7c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */ 1157*7c478bd9Sstevel@tonic-gate RESET_SASLCONN; 1158*7c478bd9Sstevel@tonic-gate continue; 1159*7c478bd9Sstevel@tonic-gate } 1160*7c478bd9Sstevel@tonic-gate 1161*7c478bd9Sstevel@tonic-gate # if SASL >= 20000 1162*7c478bd9Sstevel@tonic-gate result = sasl_server_step(conn, in, inlen, 1163*7c478bd9Sstevel@tonic-gate &out, &outlen); 1164*7c478bd9Sstevel@tonic-gate sm_free(in); 1165*7c478bd9Sstevel@tonic-gate # else /* SASL >= 20000 */ 1166*7c478bd9Sstevel@tonic-gate result = sasl_server_step(conn, out, outlen, 1167*7c478bd9Sstevel@tonic-gate &out, &outlen, &errstr); 1168*7c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */ 1169*7c478bd9Sstevel@tonic-gate 1170*7c478bd9Sstevel@tonic-gate /* get an OK if we're done */ 1171*7c478bd9Sstevel@tonic-gate if (result == SASL_OK) 1172*7c478bd9Sstevel@tonic-gate { 1173*7c478bd9Sstevel@tonic-gate authenticated: 1174*7c478bd9Sstevel@tonic-gate message("235 2.0.0 OK Authenticated"); 1175*7c478bd9Sstevel@tonic-gate authenticating = SASL_IS_AUTH; 1176*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, 1177*7c478bd9Sstevel@tonic-gate macid("{auth_type}"), auth_type); 1178*7c478bd9Sstevel@tonic-gate 1179*7c478bd9Sstevel@tonic-gate # if SASL >= 20000 1180*7c478bd9Sstevel@tonic-gate user = macvalue(macid("{auth_authen}"), e); 1181*7c478bd9Sstevel@tonic-gate 1182*7c478bd9Sstevel@tonic-gate /* get security strength (features) */ 1183*7c478bd9Sstevel@tonic-gate result = sasl_getprop(conn, SASL_SSF, 1184*7c478bd9Sstevel@tonic-gate (const void **) &ssf); 1185*7c478bd9Sstevel@tonic-gate # else /* SASL >= 20000 */ 1186*7c478bd9Sstevel@tonic-gate result = sasl_getprop(conn, SASL_USERNAME, 1187*7c478bd9Sstevel@tonic-gate (void **)&user); 1188*7c478bd9Sstevel@tonic-gate if (result != SASL_OK) 1189*7c478bd9Sstevel@tonic-gate { 1190*7c478bd9Sstevel@tonic-gate user = ""; 1191*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, 1192*7c478bd9Sstevel@tonic-gate A_PERM, 1193*7c478bd9Sstevel@tonic-gate macid("{auth_authen}"), NULL); 1194*7c478bd9Sstevel@tonic-gate } 1195*7c478bd9Sstevel@tonic-gate else 1196*7c478bd9Sstevel@tonic-gate { 1197*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, 1198*7c478bd9Sstevel@tonic-gate A_TEMP, 1199*7c478bd9Sstevel@tonic-gate macid("{auth_authen}"), 1200*7c478bd9Sstevel@tonic-gate xtextify(user, "<>\")")); 1201*7c478bd9Sstevel@tonic-gate } 1202*7c478bd9Sstevel@tonic-gate 1203*7c478bd9Sstevel@tonic-gate # if 0 1204*7c478bd9Sstevel@tonic-gate /* get realm? */ 1205*7c478bd9Sstevel@tonic-gate sasl_getprop(conn, SASL_REALM, (void **) &data); 1206*7c478bd9Sstevel@tonic-gate # endif /* 0 */ 1207*7c478bd9Sstevel@tonic-gate 1208*7c478bd9Sstevel@tonic-gate /* get security strength (features) */ 1209*7c478bd9Sstevel@tonic-gate result = sasl_getprop(conn, SASL_SSF, 1210*7c478bd9Sstevel@tonic-gate (void **) &ssf); 1211*7c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */ 1212*7c478bd9Sstevel@tonic-gate if (result != SASL_OK) 1213*7c478bd9Sstevel@tonic-gate { 1214*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, 1215*7c478bd9Sstevel@tonic-gate A_PERM, 1216*7c478bd9Sstevel@tonic-gate macid("{auth_ssf}"), "0"); 1217*7c478bd9Sstevel@tonic-gate ssf = NULL; 1218*7c478bd9Sstevel@tonic-gate } 1219*7c478bd9Sstevel@tonic-gate else 1220*7c478bd9Sstevel@tonic-gate { 1221*7c478bd9Sstevel@tonic-gate char pbuf[8]; 1222*7c478bd9Sstevel@tonic-gate 1223*7c478bd9Sstevel@tonic-gate (void) sm_snprintf(pbuf, sizeof pbuf, 1224*7c478bd9Sstevel@tonic-gate "%u", *ssf); 1225*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, 1226*7c478bd9Sstevel@tonic-gate A_TEMP, 1227*7c478bd9Sstevel@tonic-gate macid("{auth_ssf}"), pbuf); 1228*7c478bd9Sstevel@tonic-gate if (tTd(95, 8)) 1229*7c478bd9Sstevel@tonic-gate sm_dprintf("AUTH auth_ssf: %u\n", 1230*7c478bd9Sstevel@tonic-gate *ssf); 1231*7c478bd9Sstevel@tonic-gate } 1232*7c478bd9Sstevel@tonic-gate 1233*7c478bd9Sstevel@tonic-gate /* 1234*7c478bd9Sstevel@tonic-gate ** Only switch to encrypted connection 1235*7c478bd9Sstevel@tonic-gate ** if a security layer has been negotiated 1236*7c478bd9Sstevel@tonic-gate */ 1237*7c478bd9Sstevel@tonic-gate 1238*7c478bd9Sstevel@tonic-gate if (ssf != NULL && *ssf > 0) 1239*7c478bd9Sstevel@tonic-gate { 1240*7c478bd9Sstevel@tonic-gate /* 1241*7c478bd9Sstevel@tonic-gate ** Convert I/O layer to use SASL. 1242*7c478bd9Sstevel@tonic-gate ** If the call fails, the connection 1243*7c478bd9Sstevel@tonic-gate ** is aborted. 1244*7c478bd9Sstevel@tonic-gate */ 1245*7c478bd9Sstevel@tonic-gate 1246*7c478bd9Sstevel@tonic-gate if (sfdcsasl(&InChannel, &OutChannel, 1247*7c478bd9Sstevel@tonic-gate conn) == 0) 1248*7c478bd9Sstevel@tonic-gate { 1249*7c478bd9Sstevel@tonic-gate /* restart dialogue */ 1250*7c478bd9Sstevel@tonic-gate n_helo = 0; 1251*7c478bd9Sstevel@tonic-gate # if PIPELINING 1252*7c478bd9Sstevel@tonic-gate (void) sm_io_autoflush(InChannel, 1253*7c478bd9Sstevel@tonic-gate OutChannel); 1254*7c478bd9Sstevel@tonic-gate # endif /* PIPELINING */ 1255*7c478bd9Sstevel@tonic-gate } 1256*7c478bd9Sstevel@tonic-gate else 1257*7c478bd9Sstevel@tonic-gate syserr("503 5.3.3 SASL TLS failed"); 1258*7c478bd9Sstevel@tonic-gate } 1259*7c478bd9Sstevel@tonic-gate 1260*7c478bd9Sstevel@tonic-gate /* NULL pointer ok since it's our function */ 1261*7c478bd9Sstevel@tonic-gate if (LogLevel > 8) 1262*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 1263*7c478bd9Sstevel@tonic-gate "AUTH=server, relay=%s, authid=%.128s, mech=%.16s, bits=%d", 1264*7c478bd9Sstevel@tonic-gate CurSmtpClient, 1265*7c478bd9Sstevel@tonic-gate shortenstring(user, 128), 1266*7c478bd9Sstevel@tonic-gate auth_type, *ssf); 1267*7c478bd9Sstevel@tonic-gate } 1268*7c478bd9Sstevel@tonic-gate else if (result == SASL_CONTINUE) 1269*7c478bd9Sstevel@tonic-gate { 1270*7c478bd9Sstevel@tonic-gate len = ENC64LEN(outlen); 1271*7c478bd9Sstevel@tonic-gate out2 = xalloc(len); 1272*7c478bd9Sstevel@tonic-gate result = sasl_encode64(out, outlen, out2, len, 1273*7c478bd9Sstevel@tonic-gate &out2len); 1274*7c478bd9Sstevel@tonic-gate if (result != SASL_OK) 1275*7c478bd9Sstevel@tonic-gate { 1276*7c478bd9Sstevel@tonic-gate /* correct code? XXX */ 1277*7c478bd9Sstevel@tonic-gate /* 454 Temp. authentication failure */ 1278*7c478bd9Sstevel@tonic-gate message("454 4.5.4 Internal error: unable to encode64"); 1279*7c478bd9Sstevel@tonic-gate if (LogLevel > 5) 1280*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, e->e_id, 1281*7c478bd9Sstevel@tonic-gate "AUTH encode64 error [%d for \"%s\"]", 1282*7c478bd9Sstevel@tonic-gate result, out); 1283*7c478bd9Sstevel@tonic-gate /* start over? */ 1284*7c478bd9Sstevel@tonic-gate authenticating = SASL_NOT_AUTH; 1285*7c478bd9Sstevel@tonic-gate } 1286*7c478bd9Sstevel@tonic-gate else 1287*7c478bd9Sstevel@tonic-gate { 1288*7c478bd9Sstevel@tonic-gate message("334 %s", out2); 1289*7c478bd9Sstevel@tonic-gate if (tTd(95, 2)) 1290*7c478bd9Sstevel@tonic-gate sm_dprintf("AUTH continue: msg='%s' len=%u\n", 1291*7c478bd9Sstevel@tonic-gate out2, out2len); 1292*7c478bd9Sstevel@tonic-gate } 1293*7c478bd9Sstevel@tonic-gate # if SASL >= 20000 1294*7c478bd9Sstevel@tonic-gate sm_free(out2); 1295*7c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */ 1296*7c478bd9Sstevel@tonic-gate } 1297*7c478bd9Sstevel@tonic-gate else 1298*7c478bd9Sstevel@tonic-gate { 1299*7c478bd9Sstevel@tonic-gate /* not SASL_OK or SASL_CONT */ 1300*7c478bd9Sstevel@tonic-gate message("535 5.7.0 authentication failed"); 1301*7c478bd9Sstevel@tonic-gate if (LogLevel > 9) 1302*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, e->e_id, 1303*7c478bd9Sstevel@tonic-gate "AUTH failure (%s): %s (%d) %s", 1304*7c478bd9Sstevel@tonic-gate auth_type, 1305*7c478bd9Sstevel@tonic-gate sasl_errstring(result, NULL, 1306*7c478bd9Sstevel@tonic-gate NULL), 1307*7c478bd9Sstevel@tonic-gate result, 1308*7c478bd9Sstevel@tonic-gate # if SASL >= 20000 1309*7c478bd9Sstevel@tonic-gate sasl_errdetail(conn)); 1310*7c478bd9Sstevel@tonic-gate # else /* SASL >= 20000 */ 1311*7c478bd9Sstevel@tonic-gate errstr == NULL ? "" : errstr); 1312*7c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */ 1313*7c478bd9Sstevel@tonic-gate RESET_SASLCONN; 1314*7c478bd9Sstevel@tonic-gate authenticating = SASL_NOT_AUTH; 1315*7c478bd9Sstevel@tonic-gate } 1316*7c478bd9Sstevel@tonic-gate } 1317*7c478bd9Sstevel@tonic-gate else 1318*7c478bd9Sstevel@tonic-gate { 1319*7c478bd9Sstevel@tonic-gate /* don't want to do any of this if authenticating */ 1320*7c478bd9Sstevel@tonic-gate #endif /* SASL */ 1321*7c478bd9Sstevel@tonic-gate 1322*7c478bd9Sstevel@tonic-gate /* echo command to transcript */ 1323*7c478bd9Sstevel@tonic-gate if (e->e_xfp != NULL) 1324*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(e->e_xfp, SM_TIME_DEFAULT, 1325*7c478bd9Sstevel@tonic-gate "<<< %s\n", inp); 1326*7c478bd9Sstevel@tonic-gate 1327*7c478bd9Sstevel@tonic-gate if (LogLevel > 14) 1328*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "<-- %s", inp); 1329*7c478bd9Sstevel@tonic-gate 1330*7c478bd9Sstevel@tonic-gate /* break off command */ 1331*7c478bd9Sstevel@tonic-gate for (p = inp; isascii(*p) && isspace(*p); p++) 1332*7c478bd9Sstevel@tonic-gate continue; 1333*7c478bd9Sstevel@tonic-gate cmd = cmdbuf; 1334*7c478bd9Sstevel@tonic-gate while (*p != '\0' && 1335*7c478bd9Sstevel@tonic-gate !(isascii(*p) && isspace(*p)) && 1336*7c478bd9Sstevel@tonic-gate cmd < &cmdbuf[sizeof cmdbuf - 2]) 1337*7c478bd9Sstevel@tonic-gate *cmd++ = *p++; 1338*7c478bd9Sstevel@tonic-gate *cmd = '\0'; 1339*7c478bd9Sstevel@tonic-gate 1340*7c478bd9Sstevel@tonic-gate /* throw away leading whitespace */ 1341*7c478bd9Sstevel@tonic-gate SKIP_SPACE(p); 1342*7c478bd9Sstevel@tonic-gate 1343*7c478bd9Sstevel@tonic-gate /* decode command */ 1344*7c478bd9Sstevel@tonic-gate for (c = CmdTab; c->cmd_name != NULL; c++) 1345*7c478bd9Sstevel@tonic-gate { 1346*7c478bd9Sstevel@tonic-gate if (sm_strcasecmp(c->cmd_name, cmdbuf) == 0) 1347*7c478bd9Sstevel@tonic-gate break; 1348*7c478bd9Sstevel@tonic-gate } 1349*7c478bd9Sstevel@tonic-gate 1350*7c478bd9Sstevel@tonic-gate /* reset errors */ 1351*7c478bd9Sstevel@tonic-gate errno = 0; 1352*7c478bd9Sstevel@tonic-gate 1353*7c478bd9Sstevel@tonic-gate /* check whether a "non-null" command has been used */ 1354*7c478bd9Sstevel@tonic-gate switch (c->cmd_code) 1355*7c478bd9Sstevel@tonic-gate { 1356*7c478bd9Sstevel@tonic-gate #if SASL 1357*7c478bd9Sstevel@tonic-gate case CMDAUTH: 1358*7c478bd9Sstevel@tonic-gate /* avoid information leak; take first two words? */ 1359*7c478bd9Sstevel@tonic-gate q = "AUTH"; 1360*7c478bd9Sstevel@tonic-gate break; 1361*7c478bd9Sstevel@tonic-gate #endif /* SASL */ 1362*7c478bd9Sstevel@tonic-gate 1363*7c478bd9Sstevel@tonic-gate case CMDMAIL: 1364*7c478bd9Sstevel@tonic-gate case CMDEXPN: 1365*7c478bd9Sstevel@tonic-gate case CMDVRFY: 1366*7c478bd9Sstevel@tonic-gate case CMDETRN: 1367*7c478bd9Sstevel@tonic-gate lognullconnection = false; 1368*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 1369*7c478bd9Sstevel@tonic-gate default: 1370*7c478bd9Sstevel@tonic-gate q = inp; 1371*7c478bd9Sstevel@tonic-gate break; 1372*7c478bd9Sstevel@tonic-gate } 1373*7c478bd9Sstevel@tonic-gate 1374*7c478bd9Sstevel@tonic-gate if (e->e_id == NULL) 1375*7c478bd9Sstevel@tonic-gate sm_setproctitle(true, e, "%s: %.80s", 1376*7c478bd9Sstevel@tonic-gate CurSmtpClient, q); 1377*7c478bd9Sstevel@tonic-gate else 1378*7c478bd9Sstevel@tonic-gate sm_setproctitle(true, e, "%s %s: %.80s", 1379*7c478bd9Sstevel@tonic-gate qid_printname(e), 1380*7c478bd9Sstevel@tonic-gate CurSmtpClient, q); 1381*7c478bd9Sstevel@tonic-gate 1382*7c478bd9Sstevel@tonic-gate /* 1383*7c478bd9Sstevel@tonic-gate ** Process command. 1384*7c478bd9Sstevel@tonic-gate ** 1385*7c478bd9Sstevel@tonic-gate ** If we are running as a null server, return 550 1386*7c478bd9Sstevel@tonic-gate ** to almost everything. 1387*7c478bd9Sstevel@tonic-gate */ 1388*7c478bd9Sstevel@tonic-gate 1389*7c478bd9Sstevel@tonic-gate if (nullserver != NULL || bitnset(D_ETRNONLY, d_flags)) 1390*7c478bd9Sstevel@tonic-gate { 1391*7c478bd9Sstevel@tonic-gate switch (c->cmd_code) 1392*7c478bd9Sstevel@tonic-gate { 1393*7c478bd9Sstevel@tonic-gate case CMDQUIT: 1394*7c478bd9Sstevel@tonic-gate case CMDHELO: 1395*7c478bd9Sstevel@tonic-gate case CMDEHLO: 1396*7c478bd9Sstevel@tonic-gate case CMDNOOP: 1397*7c478bd9Sstevel@tonic-gate case CMDRSET: 1398*7c478bd9Sstevel@tonic-gate case CMDERROR: 1399*7c478bd9Sstevel@tonic-gate /* process normally */ 1400*7c478bd9Sstevel@tonic-gate break; 1401*7c478bd9Sstevel@tonic-gate 1402*7c478bd9Sstevel@tonic-gate case CMDETRN: 1403*7c478bd9Sstevel@tonic-gate if (bitnset(D_ETRNONLY, d_flags) && 1404*7c478bd9Sstevel@tonic-gate nullserver == NULL) 1405*7c478bd9Sstevel@tonic-gate break; 1406*7c478bd9Sstevel@tonic-gate DELAY_CONN("ETRN"); 1407*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 1408*7c478bd9Sstevel@tonic-gate 1409*7c478bd9Sstevel@tonic-gate default: 1410*7c478bd9Sstevel@tonic-gate #if MAXBADCOMMANDS > 0 1411*7c478bd9Sstevel@tonic-gate /* theoretically this could overflow */ 1412*7c478bd9Sstevel@tonic-gate if (nullserver != NULL && 1413*7c478bd9Sstevel@tonic-gate ++n_badcmds > MAXBADCOMMANDS) 1414*7c478bd9Sstevel@tonic-gate { 1415*7c478bd9Sstevel@tonic-gate message("421 4.7.0 %s Too many bad commands; closing connection", 1416*7c478bd9Sstevel@tonic-gate MyHostName); 1417*7c478bd9Sstevel@tonic-gate 1418*7c478bd9Sstevel@tonic-gate /* arrange to ignore send list */ 1419*7c478bd9Sstevel@tonic-gate e->e_sendqueue = NULL; 1420*7c478bd9Sstevel@tonic-gate goto doquit; 1421*7c478bd9Sstevel@tonic-gate } 1422*7c478bd9Sstevel@tonic-gate #endif /* MAXBADCOMMANDS > 0 */ 1423*7c478bd9Sstevel@tonic-gate if (nullserver != NULL) 1424*7c478bd9Sstevel@tonic-gate { 1425*7c478bd9Sstevel@tonic-gate if (ISSMTPREPLY(nullserver)) 1426*7c478bd9Sstevel@tonic-gate usrerr(nullserver); 1427*7c478bd9Sstevel@tonic-gate else 1428*7c478bd9Sstevel@tonic-gate usrerr("550 5.0.0 %s", 1429*7c478bd9Sstevel@tonic-gate nullserver); 1430*7c478bd9Sstevel@tonic-gate } 1431*7c478bd9Sstevel@tonic-gate else 1432*7c478bd9Sstevel@tonic-gate usrerr("452 4.4.5 Insufficient disk space; try again later"); 1433*7c478bd9Sstevel@tonic-gate continue; 1434*7c478bd9Sstevel@tonic-gate } 1435*7c478bd9Sstevel@tonic-gate } 1436*7c478bd9Sstevel@tonic-gate 1437*7c478bd9Sstevel@tonic-gate switch (c->cmd_code) 1438*7c478bd9Sstevel@tonic-gate { 1439*7c478bd9Sstevel@tonic-gate #if SASL 1440*7c478bd9Sstevel@tonic-gate case CMDAUTH: /* sasl */ 1441*7c478bd9Sstevel@tonic-gate DELAY_CONN("AUTH"); 1442*7c478bd9Sstevel@tonic-gate if (!sasl_ok || n_mechs <= 0) 1443*7c478bd9Sstevel@tonic-gate { 1444*7c478bd9Sstevel@tonic-gate message("503 5.3.3 AUTH not available"); 1445*7c478bd9Sstevel@tonic-gate break; 1446*7c478bd9Sstevel@tonic-gate } 1447*7c478bd9Sstevel@tonic-gate if (authenticating == SASL_IS_AUTH) 1448*7c478bd9Sstevel@tonic-gate { 1449*7c478bd9Sstevel@tonic-gate message("503 5.5.0 Already Authenticated"); 1450*7c478bd9Sstevel@tonic-gate break; 1451*7c478bd9Sstevel@tonic-gate } 1452*7c478bd9Sstevel@tonic-gate if (smtp.sm_gotmail) 1453*7c478bd9Sstevel@tonic-gate { 1454*7c478bd9Sstevel@tonic-gate message("503 5.5.0 AUTH not permitted during a mail transaction"); 1455*7c478bd9Sstevel@tonic-gate break; 1456*7c478bd9Sstevel@tonic-gate } 1457*7c478bd9Sstevel@tonic-gate if (tempfail) 1458*7c478bd9Sstevel@tonic-gate { 1459*7c478bd9Sstevel@tonic-gate if (LogLevel > 9) 1460*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 1461*7c478bd9Sstevel@tonic-gate "SMTP AUTH command (%.100s) from %s tempfailed (due to previous checks)", 1462*7c478bd9Sstevel@tonic-gate p, CurSmtpClient); 1463*7c478bd9Sstevel@tonic-gate usrerr("454 4.3.0 Please try again later"); 1464*7c478bd9Sstevel@tonic-gate break; 1465*7c478bd9Sstevel@tonic-gate } 1466*7c478bd9Sstevel@tonic-gate 1467*7c478bd9Sstevel@tonic-gate ismore = false; 1468*7c478bd9Sstevel@tonic-gate 1469*7c478bd9Sstevel@tonic-gate /* crude way to avoid crack attempts */ 1470*7c478bd9Sstevel@tonic-gate STOP_IF_ATTACK(checksmtpattack(&n_auth, n_mechs + 1, 1471*7c478bd9Sstevel@tonic-gate true, "AUTH", e)); 1472*7c478bd9Sstevel@tonic-gate 1473*7c478bd9Sstevel@tonic-gate /* make sure mechanism (p) is a valid string */ 1474*7c478bd9Sstevel@tonic-gate for (q = p; *q != '\0' && isascii(*q); q++) 1475*7c478bd9Sstevel@tonic-gate { 1476*7c478bd9Sstevel@tonic-gate if (isspace(*q)) 1477*7c478bd9Sstevel@tonic-gate { 1478*7c478bd9Sstevel@tonic-gate *q = '\0'; 1479*7c478bd9Sstevel@tonic-gate while (*++q != '\0' && 1480*7c478bd9Sstevel@tonic-gate isascii(*q) && isspace(*q)) 1481*7c478bd9Sstevel@tonic-gate continue; 1482*7c478bd9Sstevel@tonic-gate *(q - 1) = '\0'; 1483*7c478bd9Sstevel@tonic-gate ismore = (*q != '\0'); 1484*7c478bd9Sstevel@tonic-gate break; 1485*7c478bd9Sstevel@tonic-gate } 1486*7c478bd9Sstevel@tonic-gate } 1487*7c478bd9Sstevel@tonic-gate 1488*7c478bd9Sstevel@tonic-gate if (*p == '\0') 1489*7c478bd9Sstevel@tonic-gate { 1490*7c478bd9Sstevel@tonic-gate message("501 5.5.2 AUTH mechanism must be specified"); 1491*7c478bd9Sstevel@tonic-gate break; 1492*7c478bd9Sstevel@tonic-gate } 1493*7c478bd9Sstevel@tonic-gate 1494*7c478bd9Sstevel@tonic-gate /* check whether mechanism is available */ 1495*7c478bd9Sstevel@tonic-gate if (iteminlist(p, mechlist, " ") == NULL) 1496*7c478bd9Sstevel@tonic-gate { 1497*7c478bd9Sstevel@tonic-gate message("504 5.3.3 AUTH mechanism %.32s not available", 1498*7c478bd9Sstevel@tonic-gate p); 1499*7c478bd9Sstevel@tonic-gate break; 1500*7c478bd9Sstevel@tonic-gate } 1501*7c478bd9Sstevel@tonic-gate 1502*7c478bd9Sstevel@tonic-gate if (ismore) 1503*7c478bd9Sstevel@tonic-gate { 1504*7c478bd9Sstevel@tonic-gate /* could this be shorter? XXX */ 1505*7c478bd9Sstevel@tonic-gate # if SASL >= 20000 1506*7c478bd9Sstevel@tonic-gate in = xalloc(strlen(q) + 1); 1507*7c478bd9Sstevel@tonic-gate result = sasl_decode64(q, strlen(q), in, 1508*7c478bd9Sstevel@tonic-gate strlen(q), &inlen); 1509*7c478bd9Sstevel@tonic-gate # else /* SASL >= 20000 */ 1510*7c478bd9Sstevel@tonic-gate in = sm_rpool_malloc(e->e_rpool, strlen(q)); 1511*7c478bd9Sstevel@tonic-gate result = sasl_decode64(q, strlen(q), in, 1512*7c478bd9Sstevel@tonic-gate &inlen); 1513*7c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */ 1514*7c478bd9Sstevel@tonic-gate if (result != SASL_OK) 1515*7c478bd9Sstevel@tonic-gate { 1516*7c478bd9Sstevel@tonic-gate message("501 5.5.4 cannot BASE64 decode '%s'", 1517*7c478bd9Sstevel@tonic-gate q); 1518*7c478bd9Sstevel@tonic-gate if (LogLevel > 5) 1519*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, e->e_id, 1520*7c478bd9Sstevel@tonic-gate "AUTH decode64 error [%d for \"%s\"]", 1521*7c478bd9Sstevel@tonic-gate result, q); 1522*7c478bd9Sstevel@tonic-gate /* start over? */ 1523*7c478bd9Sstevel@tonic-gate authenticating = SASL_NOT_AUTH; 1524*7c478bd9Sstevel@tonic-gate # if SASL >= 20000 1525*7c478bd9Sstevel@tonic-gate sm_free(in); 1526*7c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */ 1527*7c478bd9Sstevel@tonic-gate in = NULL; 1528*7c478bd9Sstevel@tonic-gate inlen = 0; 1529*7c478bd9Sstevel@tonic-gate break; 1530*7c478bd9Sstevel@tonic-gate } 1531*7c478bd9Sstevel@tonic-gate } 1532*7c478bd9Sstevel@tonic-gate else 1533*7c478bd9Sstevel@tonic-gate { 1534*7c478bd9Sstevel@tonic-gate in = NULL; 1535*7c478bd9Sstevel@tonic-gate inlen = 0; 1536*7c478bd9Sstevel@tonic-gate } 1537*7c478bd9Sstevel@tonic-gate 1538*7c478bd9Sstevel@tonic-gate /* see if that auth type exists */ 1539*7c478bd9Sstevel@tonic-gate # if SASL >= 20000 1540*7c478bd9Sstevel@tonic-gate result = sasl_server_start(conn, p, in, inlen, 1541*7c478bd9Sstevel@tonic-gate &out, &outlen); 1542*7c478bd9Sstevel@tonic-gate if (in != NULL) 1543*7c478bd9Sstevel@tonic-gate sm_free(in); 1544*7c478bd9Sstevel@tonic-gate # else /* SASL >= 20000 */ 1545*7c478bd9Sstevel@tonic-gate result = sasl_server_start(conn, p, in, inlen, 1546*7c478bd9Sstevel@tonic-gate &out, &outlen, &errstr); 1547*7c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */ 1548*7c478bd9Sstevel@tonic-gate 1549*7c478bd9Sstevel@tonic-gate if (result != SASL_OK && result != SASL_CONTINUE) 1550*7c478bd9Sstevel@tonic-gate { 1551*7c478bd9Sstevel@tonic-gate message("535 5.7.0 authentication failed"); 1552*7c478bd9Sstevel@tonic-gate if (LogLevel > 9) 1553*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 1554*7c478bd9Sstevel@tonic-gate "AUTH failure (%s): %s (%d) %s", 1555*7c478bd9Sstevel@tonic-gate p, 1556*7c478bd9Sstevel@tonic-gate sasl_errstring(result, NULL, 1557*7c478bd9Sstevel@tonic-gate NULL), 1558*7c478bd9Sstevel@tonic-gate result, 1559*7c478bd9Sstevel@tonic-gate # if SASL >= 20000 1560*7c478bd9Sstevel@tonic-gate sasl_errdetail(conn)); 1561*7c478bd9Sstevel@tonic-gate # else /* SASL >= 20000 */ 1562*7c478bd9Sstevel@tonic-gate errstr); 1563*7c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */ 1564*7c478bd9Sstevel@tonic-gate RESET_SASLCONN; 1565*7c478bd9Sstevel@tonic-gate break; 1566*7c478bd9Sstevel@tonic-gate } 1567*7c478bd9Sstevel@tonic-gate auth_type = newstr(p); 1568*7c478bd9Sstevel@tonic-gate 1569*7c478bd9Sstevel@tonic-gate if (result == SASL_OK) 1570*7c478bd9Sstevel@tonic-gate { 1571*7c478bd9Sstevel@tonic-gate /* ugly, but same code */ 1572*7c478bd9Sstevel@tonic-gate goto authenticated; 1573*7c478bd9Sstevel@tonic-gate /* authenticated by the initial response */ 1574*7c478bd9Sstevel@tonic-gate } 1575*7c478bd9Sstevel@tonic-gate 1576*7c478bd9Sstevel@tonic-gate /* len is at least 2 */ 1577*7c478bd9Sstevel@tonic-gate len = ENC64LEN(outlen); 1578*7c478bd9Sstevel@tonic-gate out2 = xalloc(len); 1579*7c478bd9Sstevel@tonic-gate result = sasl_encode64(out, outlen, out2, len, 1580*7c478bd9Sstevel@tonic-gate &out2len); 1581*7c478bd9Sstevel@tonic-gate 1582*7c478bd9Sstevel@tonic-gate if (result != SASL_OK) 1583*7c478bd9Sstevel@tonic-gate { 1584*7c478bd9Sstevel@tonic-gate message("454 4.5.4 Temporary authentication failure"); 1585*7c478bd9Sstevel@tonic-gate if (LogLevel > 5) 1586*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, e->e_id, 1587*7c478bd9Sstevel@tonic-gate "AUTH encode64 error [%d for \"%s\"]", 1588*7c478bd9Sstevel@tonic-gate result, out); 1589*7c478bd9Sstevel@tonic-gate 1590*7c478bd9Sstevel@tonic-gate /* start over? */ 1591*7c478bd9Sstevel@tonic-gate authenticating = SASL_NOT_AUTH; 1592*7c478bd9Sstevel@tonic-gate RESET_SASLCONN; 1593*7c478bd9Sstevel@tonic-gate } 1594*7c478bd9Sstevel@tonic-gate else 1595*7c478bd9Sstevel@tonic-gate { 1596*7c478bd9Sstevel@tonic-gate message("334 %s", out2); 1597*7c478bd9Sstevel@tonic-gate authenticating = SASL_PROC_AUTH; 1598*7c478bd9Sstevel@tonic-gate } 1599*7c478bd9Sstevel@tonic-gate # if SASL >= 20000 1600*7c478bd9Sstevel@tonic-gate sm_free(out2); 1601*7c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */ 1602*7c478bd9Sstevel@tonic-gate break; 1603*7c478bd9Sstevel@tonic-gate #endif /* SASL */ 1604*7c478bd9Sstevel@tonic-gate 1605*7c478bd9Sstevel@tonic-gate #if STARTTLS 1606*7c478bd9Sstevel@tonic-gate case CMDSTLS: /* starttls */ 1607*7c478bd9Sstevel@tonic-gate DELAY_CONN("STARTTLS"); 1608*7c478bd9Sstevel@tonic-gate if (*p != '\0') 1609*7c478bd9Sstevel@tonic-gate { 1610*7c478bd9Sstevel@tonic-gate message("501 5.5.2 Syntax error (no parameters allowed)"); 1611*7c478bd9Sstevel@tonic-gate break; 1612*7c478bd9Sstevel@tonic-gate } 1613*7c478bd9Sstevel@tonic-gate if (!bitset(SRV_OFFER_TLS, features)) 1614*7c478bd9Sstevel@tonic-gate { 1615*7c478bd9Sstevel@tonic-gate message("503 5.5.0 TLS not available"); 1616*7c478bd9Sstevel@tonic-gate break; 1617*7c478bd9Sstevel@tonic-gate } 1618*7c478bd9Sstevel@tonic-gate if (!tls_ok_srv) 1619*7c478bd9Sstevel@tonic-gate { 1620*7c478bd9Sstevel@tonic-gate message("454 4.3.3 TLS not available after start"); 1621*7c478bd9Sstevel@tonic-gate break; 1622*7c478bd9Sstevel@tonic-gate } 1623*7c478bd9Sstevel@tonic-gate if (smtp.sm_gotmail) 1624*7c478bd9Sstevel@tonic-gate { 1625*7c478bd9Sstevel@tonic-gate message("503 5.5.0 TLS not permitted during a mail transaction"); 1626*7c478bd9Sstevel@tonic-gate break; 1627*7c478bd9Sstevel@tonic-gate } 1628*7c478bd9Sstevel@tonic-gate if (tempfail) 1629*7c478bd9Sstevel@tonic-gate { 1630*7c478bd9Sstevel@tonic-gate if (LogLevel > 9) 1631*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 1632*7c478bd9Sstevel@tonic-gate "SMTP STARTTLS command (%.100s) from %s tempfailed (due to previous checks)", 1633*7c478bd9Sstevel@tonic-gate p, CurSmtpClient); 1634*7c478bd9Sstevel@tonic-gate usrerr("454 4.7.0 Please try again later"); 1635*7c478bd9Sstevel@tonic-gate break; 1636*7c478bd9Sstevel@tonic-gate } 1637*7c478bd9Sstevel@tonic-gate starttls: 1638*7c478bd9Sstevel@tonic-gate # if TLS_NO_RSA 1639*7c478bd9Sstevel@tonic-gate /* 1640*7c478bd9Sstevel@tonic-gate ** XXX do we need a temp key ? 1641*7c478bd9Sstevel@tonic-gate */ 1642*7c478bd9Sstevel@tonic-gate # else /* TLS_NO_RSA */ 1643*7c478bd9Sstevel@tonic-gate # endif /* TLS_NO_RSA */ 1644*7c478bd9Sstevel@tonic-gate 1645*7c478bd9Sstevel@tonic-gate # if TLS_VRFY_PER_CTX 1646*7c478bd9Sstevel@tonic-gate /* 1647*7c478bd9Sstevel@tonic-gate ** Note: this sets the verification globally 1648*7c478bd9Sstevel@tonic-gate ** (per SSL_CTX) 1649*7c478bd9Sstevel@tonic-gate ** it's ok since it applies only to one transaction 1650*7c478bd9Sstevel@tonic-gate */ 1651*7c478bd9Sstevel@tonic-gate 1652*7c478bd9Sstevel@tonic-gate TLS_VERIFY_CLIENT(); 1653*7c478bd9Sstevel@tonic-gate # endif /* TLS_VRFY_PER_CTX */ 1654*7c478bd9Sstevel@tonic-gate 1655*7c478bd9Sstevel@tonic-gate if (srv_ssl != NULL) 1656*7c478bd9Sstevel@tonic-gate SSL_clear(srv_ssl); 1657*7c478bd9Sstevel@tonic-gate else if ((srv_ssl = SSL_new(srv_ctx)) == NULL) 1658*7c478bd9Sstevel@tonic-gate { 1659*7c478bd9Sstevel@tonic-gate message("454 4.3.3 TLS not available: error generating SSL handle"); 1660*7c478bd9Sstevel@tonic-gate if (LogLevel > 8) 1661*7c478bd9Sstevel@tonic-gate tlslogerr("server"); 1662*7c478bd9Sstevel@tonic-gate goto tls_done; 1663*7c478bd9Sstevel@tonic-gate } 1664*7c478bd9Sstevel@tonic-gate 1665*7c478bd9Sstevel@tonic-gate # if !TLS_VRFY_PER_CTX 1666*7c478bd9Sstevel@tonic-gate /* 1667*7c478bd9Sstevel@tonic-gate ** this could be used if it were possible to set 1668*7c478bd9Sstevel@tonic-gate ** verification per SSL (connection) 1669*7c478bd9Sstevel@tonic-gate ** not just per SSL_CTX (global) 1670*7c478bd9Sstevel@tonic-gate */ 1671*7c478bd9Sstevel@tonic-gate 1672*7c478bd9Sstevel@tonic-gate TLS_VERIFY_CLIENT(); 1673*7c478bd9Sstevel@tonic-gate # endif /* !TLS_VRFY_PER_CTX */ 1674*7c478bd9Sstevel@tonic-gate 1675*7c478bd9Sstevel@tonic-gate rfd = sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL); 1676*7c478bd9Sstevel@tonic-gate wfd = sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL); 1677*7c478bd9Sstevel@tonic-gate 1678*7c478bd9Sstevel@tonic-gate if (rfd < 0 || wfd < 0 || 1679*7c478bd9Sstevel@tonic-gate SSL_set_rfd(srv_ssl, rfd) <= 0 || 1680*7c478bd9Sstevel@tonic-gate SSL_set_wfd(srv_ssl, wfd) <= 0) 1681*7c478bd9Sstevel@tonic-gate { 1682*7c478bd9Sstevel@tonic-gate message("454 4.3.3 TLS not available: error set fd"); 1683*7c478bd9Sstevel@tonic-gate SSL_free(srv_ssl); 1684*7c478bd9Sstevel@tonic-gate srv_ssl = NULL; 1685*7c478bd9Sstevel@tonic-gate goto tls_done; 1686*7c478bd9Sstevel@tonic-gate } 1687*7c478bd9Sstevel@tonic-gate if (!smtps) 1688*7c478bd9Sstevel@tonic-gate message("220 2.0.0 Ready to start TLS"); 1689*7c478bd9Sstevel@tonic-gate # if PIPELINING 1690*7c478bd9Sstevel@tonic-gate (void) sm_io_flush(OutChannel, SM_TIME_DEFAULT); 1691*7c478bd9Sstevel@tonic-gate # endif /* PIPELINING */ 1692*7c478bd9Sstevel@tonic-gate 1693*7c478bd9Sstevel@tonic-gate SSL_set_accept_state(srv_ssl); 1694*7c478bd9Sstevel@tonic-gate 1695*7c478bd9Sstevel@tonic-gate # define SSL_ACC(s) SSL_accept(s) 1696*7c478bd9Sstevel@tonic-gate 1697*7c478bd9Sstevel@tonic-gate tlsstart = curtime(); 1698*7c478bd9Sstevel@tonic-gate fdfl = fcntl(rfd, F_GETFL); 1699*7c478bd9Sstevel@tonic-gate if (fdfl != -1) 1700*7c478bd9Sstevel@tonic-gate fcntl(rfd, F_SETFL, fdfl|O_NONBLOCK); 1701*7c478bd9Sstevel@tonic-gate ssl_retry: 1702*7c478bd9Sstevel@tonic-gate if ((r = SSL_ACC(srv_ssl)) <= 0) 1703*7c478bd9Sstevel@tonic-gate { 1704*7c478bd9Sstevel@tonic-gate int i; 1705*7c478bd9Sstevel@tonic-gate bool timedout; 1706*7c478bd9Sstevel@tonic-gate time_t left; 1707*7c478bd9Sstevel@tonic-gate time_t now = curtime(); 1708*7c478bd9Sstevel@tonic-gate struct timeval tv; 1709*7c478bd9Sstevel@tonic-gate 1710*7c478bd9Sstevel@tonic-gate /* what to do in this case? */ 1711*7c478bd9Sstevel@tonic-gate i = SSL_get_error(srv_ssl, r); 1712*7c478bd9Sstevel@tonic-gate 1713*7c478bd9Sstevel@tonic-gate /* 1714*7c478bd9Sstevel@tonic-gate ** For SSL_ERROR_WANT_{READ,WRITE}: 1715*7c478bd9Sstevel@tonic-gate ** There is no SSL record available yet 1716*7c478bd9Sstevel@tonic-gate ** or there is only a partial SSL record 1717*7c478bd9Sstevel@tonic-gate ** removed from the network (socket) buffer 1718*7c478bd9Sstevel@tonic-gate ** into the SSL buffer. The SSL_accept will 1719*7c478bd9Sstevel@tonic-gate ** only succeed when a full SSL record is 1720*7c478bd9Sstevel@tonic-gate ** available (assuming a "real" error 1721*7c478bd9Sstevel@tonic-gate ** doesn't happen). To handle when a "real" 1722*7c478bd9Sstevel@tonic-gate ** error does happen the select is set for 1723*7c478bd9Sstevel@tonic-gate ** exceptions too. 1724*7c478bd9Sstevel@tonic-gate ** The connection may be re-negotiated 1725*7c478bd9Sstevel@tonic-gate ** during this time so both read and write 1726*7c478bd9Sstevel@tonic-gate ** "want errors" need to be handled. 1727*7c478bd9Sstevel@tonic-gate ** A select() exception loops back so that 1728*7c478bd9Sstevel@tonic-gate ** a proper SSL error message can be gotten. 1729*7c478bd9Sstevel@tonic-gate */ 1730*7c478bd9Sstevel@tonic-gate 1731*7c478bd9Sstevel@tonic-gate left = TimeOuts.to_starttls - (now - tlsstart); 1732*7c478bd9Sstevel@tonic-gate timedout = left <= 0; 1733*7c478bd9Sstevel@tonic-gate if (!timedout) 1734*7c478bd9Sstevel@tonic-gate { 1735*7c478bd9Sstevel@tonic-gate tv.tv_sec = left; 1736*7c478bd9Sstevel@tonic-gate tv.tv_usec = 0; 1737*7c478bd9Sstevel@tonic-gate } 1738*7c478bd9Sstevel@tonic-gate 1739*7c478bd9Sstevel@tonic-gate if (!timedout && FD_SETSIZE > 0 && 1740*7c478bd9Sstevel@tonic-gate (rfd >= FD_SETSIZE || 1741*7c478bd9Sstevel@tonic-gate (i == SSL_ERROR_WANT_WRITE && 1742*7c478bd9Sstevel@tonic-gate wfd >= FD_SETSIZE))) 1743*7c478bd9Sstevel@tonic-gate { 1744*7c478bd9Sstevel@tonic-gate if (LogLevel > 5) 1745*7c478bd9Sstevel@tonic-gate { 1746*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, NOQID, 1747*7c478bd9Sstevel@tonic-gate "STARTTLS=server, error: fd %d/%d too large", 1748*7c478bd9Sstevel@tonic-gate rfd, wfd); 1749*7c478bd9Sstevel@tonic-gate if (LogLevel > 8) 1750*7c478bd9Sstevel@tonic-gate tlslogerr("server"); 1751*7c478bd9Sstevel@tonic-gate } 1752*7c478bd9Sstevel@tonic-gate goto tlsfail; 1753*7c478bd9Sstevel@tonic-gate } 1754*7c478bd9Sstevel@tonic-gate 1755*7c478bd9Sstevel@tonic-gate /* XXX what about SSL_pending() ? */ 1756*7c478bd9Sstevel@tonic-gate if (!timedout && i == SSL_ERROR_WANT_READ) 1757*7c478bd9Sstevel@tonic-gate { 1758*7c478bd9Sstevel@tonic-gate fd_set ssl_maskr, ssl_maskx; 1759*7c478bd9Sstevel@tonic-gate 1760*7c478bd9Sstevel@tonic-gate FD_ZERO(&ssl_maskr); 1761*7c478bd9Sstevel@tonic-gate FD_SET(rfd, &ssl_maskr); 1762*7c478bd9Sstevel@tonic-gate FD_ZERO(&ssl_maskx); 1763*7c478bd9Sstevel@tonic-gate FD_SET(rfd, &ssl_maskx); 1764*7c478bd9Sstevel@tonic-gate if (select(rfd + 1, &ssl_maskr, NULL, 1765*7c478bd9Sstevel@tonic-gate &ssl_maskx, &tv) > 0) 1766*7c478bd9Sstevel@tonic-gate goto ssl_retry; 1767*7c478bd9Sstevel@tonic-gate } 1768*7c478bd9Sstevel@tonic-gate if (!timedout && i == SSL_ERROR_WANT_WRITE) 1769*7c478bd9Sstevel@tonic-gate { 1770*7c478bd9Sstevel@tonic-gate fd_set ssl_maskw, ssl_maskx; 1771*7c478bd9Sstevel@tonic-gate 1772*7c478bd9Sstevel@tonic-gate FD_ZERO(&ssl_maskw); 1773*7c478bd9Sstevel@tonic-gate FD_SET(wfd, &ssl_maskw); 1774*7c478bd9Sstevel@tonic-gate FD_ZERO(&ssl_maskx); 1775*7c478bd9Sstevel@tonic-gate FD_SET(rfd, &ssl_maskx); 1776*7c478bd9Sstevel@tonic-gate if (select(wfd + 1, NULL, &ssl_maskw, 1777*7c478bd9Sstevel@tonic-gate &ssl_maskx, &tv) > 0) 1778*7c478bd9Sstevel@tonic-gate goto ssl_retry; 1779*7c478bd9Sstevel@tonic-gate } 1780*7c478bd9Sstevel@tonic-gate if (LogLevel > 5) 1781*7c478bd9Sstevel@tonic-gate { 1782*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID, 1783*7c478bd9Sstevel@tonic-gate "STARTTLS=server, error: accept failed=%d, SSL_error=%d, timedout=%d, errno=%d", 1784*7c478bd9Sstevel@tonic-gate r, i, (int) timedout, errno); 1785*7c478bd9Sstevel@tonic-gate if (LogLevel > 8) 1786*7c478bd9Sstevel@tonic-gate tlslogerr("server"); 1787*7c478bd9Sstevel@tonic-gate } 1788*7c478bd9Sstevel@tonic-gate tlsfail: 1789*7c478bd9Sstevel@tonic-gate tls_ok_srv = false; 1790*7c478bd9Sstevel@tonic-gate SSL_free(srv_ssl); 1791*7c478bd9Sstevel@tonic-gate srv_ssl = NULL; 1792*7c478bd9Sstevel@tonic-gate 1793*7c478bd9Sstevel@tonic-gate /* 1794*7c478bd9Sstevel@tonic-gate ** according to the next draft of 1795*7c478bd9Sstevel@tonic-gate ** RFC 2487 the connection should be dropped 1796*7c478bd9Sstevel@tonic-gate */ 1797*7c478bd9Sstevel@tonic-gate 1798*7c478bd9Sstevel@tonic-gate /* arrange to ignore any current send list */ 1799*7c478bd9Sstevel@tonic-gate e->e_sendqueue = NULL; 1800*7c478bd9Sstevel@tonic-gate goto doquit; 1801*7c478bd9Sstevel@tonic-gate } 1802*7c478bd9Sstevel@tonic-gate 1803*7c478bd9Sstevel@tonic-gate if (fdfl != -1) 1804*7c478bd9Sstevel@tonic-gate fcntl(rfd, F_SETFL, fdfl); 1805*7c478bd9Sstevel@tonic-gate 1806*7c478bd9Sstevel@tonic-gate /* ignore return code for now, it's in {verify} */ 1807*7c478bd9Sstevel@tonic-gate (void) tls_get_info(srv_ssl, true, 1808*7c478bd9Sstevel@tonic-gate CurSmtpClient, 1809*7c478bd9Sstevel@tonic-gate &BlankEnvelope.e_macro, 1810*7c478bd9Sstevel@tonic-gate bitset(SRV_VRFY_CLT, features)); 1811*7c478bd9Sstevel@tonic-gate 1812*7c478bd9Sstevel@tonic-gate /* 1813*7c478bd9Sstevel@tonic-gate ** call Stls_client to find out whether 1814*7c478bd9Sstevel@tonic-gate ** to accept the connection from the client 1815*7c478bd9Sstevel@tonic-gate */ 1816*7c478bd9Sstevel@tonic-gate 1817*7c478bd9Sstevel@tonic-gate saveQuickAbort = QuickAbort; 1818*7c478bd9Sstevel@tonic-gate saveSuprErrs = SuprErrs; 1819*7c478bd9Sstevel@tonic-gate SuprErrs = true; 1820*7c478bd9Sstevel@tonic-gate QuickAbort = false; 1821*7c478bd9Sstevel@tonic-gate if (rscheck("tls_client", 1822*7c478bd9Sstevel@tonic-gate macvalue(macid("{verify}"), e), 1823*7c478bd9Sstevel@tonic-gate "STARTTLS", e, 1824*7c478bd9Sstevel@tonic-gate RSF_RMCOMM|RSF_COUNT, 1825*7c478bd9Sstevel@tonic-gate 5, NULL, NOQID) != EX_OK || 1826*7c478bd9Sstevel@tonic-gate Errors > 0) 1827*7c478bd9Sstevel@tonic-gate { 1828*7c478bd9Sstevel@tonic-gate extern char MsgBuf[]; 1829*7c478bd9Sstevel@tonic-gate 1830*7c478bd9Sstevel@tonic-gate if (MsgBuf[0] != '\0' && ISSMTPREPLY(MsgBuf)) 1831*7c478bd9Sstevel@tonic-gate nullserver = newstr(MsgBuf); 1832*7c478bd9Sstevel@tonic-gate else 1833*7c478bd9Sstevel@tonic-gate nullserver = "503 5.7.0 Authentication required."; 1834*7c478bd9Sstevel@tonic-gate } 1835*7c478bd9Sstevel@tonic-gate QuickAbort = saveQuickAbort; 1836*7c478bd9Sstevel@tonic-gate SuprErrs = saveSuprErrs; 1837*7c478bd9Sstevel@tonic-gate 1838*7c478bd9Sstevel@tonic-gate tls_ok_srv = false; /* don't offer STARTTLS again */ 1839*7c478bd9Sstevel@tonic-gate n_helo = 0; 1840*7c478bd9Sstevel@tonic-gate # if SASL 1841*7c478bd9Sstevel@tonic-gate if (sasl_ok) 1842*7c478bd9Sstevel@tonic-gate { 1843*7c478bd9Sstevel@tonic-gate int cipher_bits; 1844*7c478bd9Sstevel@tonic-gate bool verified; 1845*7c478bd9Sstevel@tonic-gate char *s, *v, *c; 1846*7c478bd9Sstevel@tonic-gate 1847*7c478bd9Sstevel@tonic-gate s = macvalue(macid("{cipher_bits}"), e); 1848*7c478bd9Sstevel@tonic-gate v = macvalue(macid("{verify}"), e); 1849*7c478bd9Sstevel@tonic-gate c = macvalue(macid("{cert_subject}"), e); 1850*7c478bd9Sstevel@tonic-gate verified = (v != NULL && strcmp(v, "OK") == 0); 1851*7c478bd9Sstevel@tonic-gate if (s != NULL && (cipher_bits = atoi(s)) > 0) 1852*7c478bd9Sstevel@tonic-gate { 1853*7c478bd9Sstevel@tonic-gate # if SASL >= 20000 1854*7c478bd9Sstevel@tonic-gate ext_ssf = cipher_bits; 1855*7c478bd9Sstevel@tonic-gate auth_id = verified ? c : NULL; 1856*7c478bd9Sstevel@tonic-gate sasl_ok = ((sasl_setprop(conn, 1857*7c478bd9Sstevel@tonic-gate SASL_SSF_EXTERNAL, 1858*7c478bd9Sstevel@tonic-gate &ext_ssf) == SASL_OK) && 1859*7c478bd9Sstevel@tonic-gate (sasl_setprop(conn, 1860*7c478bd9Sstevel@tonic-gate SASL_AUTH_EXTERNAL, 1861*7c478bd9Sstevel@tonic-gate auth_id) == SASL_OK)); 1862*7c478bd9Sstevel@tonic-gate # else /* SASL >= 20000 */ 1863*7c478bd9Sstevel@tonic-gate ext_ssf.ssf = cipher_bits; 1864*7c478bd9Sstevel@tonic-gate ext_ssf.auth_id = verified ? c : NULL; 1865*7c478bd9Sstevel@tonic-gate sasl_ok = sasl_setprop(conn, 1866*7c478bd9Sstevel@tonic-gate SASL_SSF_EXTERNAL, 1867*7c478bd9Sstevel@tonic-gate &ext_ssf) == SASL_OK; 1868*7c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */ 1869*7c478bd9Sstevel@tonic-gate mechlist = NULL; 1870*7c478bd9Sstevel@tonic-gate if (sasl_ok) 1871*7c478bd9Sstevel@tonic-gate n_mechs = saslmechs(conn, 1872*7c478bd9Sstevel@tonic-gate &mechlist); 1873*7c478bd9Sstevel@tonic-gate } 1874*7c478bd9Sstevel@tonic-gate } 1875*7c478bd9Sstevel@tonic-gate # endif /* SASL */ 1876*7c478bd9Sstevel@tonic-gate 1877*7c478bd9Sstevel@tonic-gate /* switch to secure connection */ 1878*7c478bd9Sstevel@tonic-gate if (sfdctls(&InChannel, &OutChannel, srv_ssl) == 0) 1879*7c478bd9Sstevel@tonic-gate { 1880*7c478bd9Sstevel@tonic-gate tls_active = true; 1881*7c478bd9Sstevel@tonic-gate # if PIPELINING 1882*7c478bd9Sstevel@tonic-gate (void) sm_io_autoflush(InChannel, OutChannel); 1883*7c478bd9Sstevel@tonic-gate # endif /* PIPELINING */ 1884*7c478bd9Sstevel@tonic-gate } 1885*7c478bd9Sstevel@tonic-gate else 1886*7c478bd9Sstevel@tonic-gate { 1887*7c478bd9Sstevel@tonic-gate /* 1888*7c478bd9Sstevel@tonic-gate ** XXX this is an internal error 1889*7c478bd9Sstevel@tonic-gate ** how to deal with it? 1890*7c478bd9Sstevel@tonic-gate ** we can't generate an error message 1891*7c478bd9Sstevel@tonic-gate ** since the other side switched to an 1892*7c478bd9Sstevel@tonic-gate ** encrypted layer, but we could not... 1893*7c478bd9Sstevel@tonic-gate ** just "hang up"? 1894*7c478bd9Sstevel@tonic-gate */ 1895*7c478bd9Sstevel@tonic-gate 1896*7c478bd9Sstevel@tonic-gate nullserver = "454 4.3.3 TLS not available: can't switch to encrypted layer"; 1897*7c478bd9Sstevel@tonic-gate syserr("STARTTLS: can't switch to encrypted layer"); 1898*7c478bd9Sstevel@tonic-gate } 1899*7c478bd9Sstevel@tonic-gate tls_done: 1900*7c478bd9Sstevel@tonic-gate if (smtps) 1901*7c478bd9Sstevel@tonic-gate { 1902*7c478bd9Sstevel@tonic-gate if (tls_active) 1903*7c478bd9Sstevel@tonic-gate goto greeting; 1904*7c478bd9Sstevel@tonic-gate else 1905*7c478bd9Sstevel@tonic-gate goto doquit; 1906*7c478bd9Sstevel@tonic-gate } 1907*7c478bd9Sstevel@tonic-gate break; 1908*7c478bd9Sstevel@tonic-gate #endif /* STARTTLS */ 1909*7c478bd9Sstevel@tonic-gate 1910*7c478bd9Sstevel@tonic-gate case CMDHELO: /* hello -- introduce yourself */ 1911*7c478bd9Sstevel@tonic-gate case CMDEHLO: /* extended hello */ 1912*7c478bd9Sstevel@tonic-gate DELAY_CONN("EHLO"); 1913*7c478bd9Sstevel@tonic-gate if (c->cmd_code == CMDEHLO) 1914*7c478bd9Sstevel@tonic-gate { 1915*7c478bd9Sstevel@tonic-gate protocol = "ESMTP"; 1916*7c478bd9Sstevel@tonic-gate SmtpPhase = "server EHLO"; 1917*7c478bd9Sstevel@tonic-gate } 1918*7c478bd9Sstevel@tonic-gate else 1919*7c478bd9Sstevel@tonic-gate { 1920*7c478bd9Sstevel@tonic-gate protocol = "SMTP"; 1921*7c478bd9Sstevel@tonic-gate SmtpPhase = "server HELO"; 1922*7c478bd9Sstevel@tonic-gate } 1923*7c478bd9Sstevel@tonic-gate 1924*7c478bd9Sstevel@tonic-gate /* avoid denial-of-service */ 1925*7c478bd9Sstevel@tonic-gate STOP_IF_ATTACK(checksmtpattack(&n_helo, MAXHELOCOMMANDS, 1926*7c478bd9Sstevel@tonic-gate true, "HELO/EHLO", e)); 1927*7c478bd9Sstevel@tonic-gate 1928*7c478bd9Sstevel@tonic-gate #if 0 1929*7c478bd9Sstevel@tonic-gate /* RFC2821 4.1.4 allows duplicate HELO/EHLO */ 1930*7c478bd9Sstevel@tonic-gate /* check for duplicate HELO/EHLO per RFC 1651 4.2 */ 1931*7c478bd9Sstevel@tonic-gate if (gothello) 1932*7c478bd9Sstevel@tonic-gate { 1933*7c478bd9Sstevel@tonic-gate usrerr("503 %s Duplicate HELO/EHLO", 1934*7c478bd9Sstevel@tonic-gate MyHostName); 1935*7c478bd9Sstevel@tonic-gate break; 1936*7c478bd9Sstevel@tonic-gate } 1937*7c478bd9Sstevel@tonic-gate #endif /* 0 */ 1938*7c478bd9Sstevel@tonic-gate 1939*7c478bd9Sstevel@tonic-gate /* check for valid domain name (re 1123 5.2.5) */ 1940*7c478bd9Sstevel@tonic-gate if (*p == '\0' && !AllowBogusHELO) 1941*7c478bd9Sstevel@tonic-gate { 1942*7c478bd9Sstevel@tonic-gate usrerr("501 %s requires domain address", 1943*7c478bd9Sstevel@tonic-gate cmdbuf); 1944*7c478bd9Sstevel@tonic-gate break; 1945*7c478bd9Sstevel@tonic-gate } 1946*7c478bd9Sstevel@tonic-gate 1947*7c478bd9Sstevel@tonic-gate /* check for long domain name (hides Received: info) */ 1948*7c478bd9Sstevel@tonic-gate if (strlen(p) > MAXNAME) 1949*7c478bd9Sstevel@tonic-gate { 1950*7c478bd9Sstevel@tonic-gate usrerr("501 Invalid domain name"); 1951*7c478bd9Sstevel@tonic-gate if (LogLevel > 9) 1952*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, CurEnv->e_id, 1953*7c478bd9Sstevel@tonic-gate "invalid domain name (too long) from %s", 1954*7c478bd9Sstevel@tonic-gate CurSmtpClient); 1955*7c478bd9Sstevel@tonic-gate break; 1956*7c478bd9Sstevel@tonic-gate } 1957*7c478bd9Sstevel@tonic-gate 1958*7c478bd9Sstevel@tonic-gate ok = true; 1959*7c478bd9Sstevel@tonic-gate for (q = p; *q != '\0'; q++) 1960*7c478bd9Sstevel@tonic-gate { 1961*7c478bd9Sstevel@tonic-gate if (!isascii(*q)) 1962*7c478bd9Sstevel@tonic-gate break; 1963*7c478bd9Sstevel@tonic-gate if (isalnum(*q)) 1964*7c478bd9Sstevel@tonic-gate continue; 1965*7c478bd9Sstevel@tonic-gate if (isspace(*q)) 1966*7c478bd9Sstevel@tonic-gate { 1967*7c478bd9Sstevel@tonic-gate *q = '\0'; 1968*7c478bd9Sstevel@tonic-gate 1969*7c478bd9Sstevel@tonic-gate /* only complain if strict check */ 1970*7c478bd9Sstevel@tonic-gate ok = AllowBogusHELO; 1971*7c478bd9Sstevel@tonic-gate 1972*7c478bd9Sstevel@tonic-gate /* allow trailing whitespace */ 1973*7c478bd9Sstevel@tonic-gate while (!ok && *++q != '\0' && 1974*7c478bd9Sstevel@tonic-gate isspace(*q)) 1975*7c478bd9Sstevel@tonic-gate ; 1976*7c478bd9Sstevel@tonic-gate if (*q == '\0') 1977*7c478bd9Sstevel@tonic-gate ok = true; 1978*7c478bd9Sstevel@tonic-gate break; 1979*7c478bd9Sstevel@tonic-gate } 1980*7c478bd9Sstevel@tonic-gate if (strchr("[].-_#:", *q) == NULL) 1981*7c478bd9Sstevel@tonic-gate break; 1982*7c478bd9Sstevel@tonic-gate } 1983*7c478bd9Sstevel@tonic-gate 1984*7c478bd9Sstevel@tonic-gate if (*q == '\0' && ok) 1985*7c478bd9Sstevel@tonic-gate { 1986*7c478bd9Sstevel@tonic-gate q = "pleased to meet you"; 1987*7c478bd9Sstevel@tonic-gate sendinghost = sm_strdup_x(p); 1988*7c478bd9Sstevel@tonic-gate } 1989*7c478bd9Sstevel@tonic-gate else if (!AllowBogusHELO) 1990*7c478bd9Sstevel@tonic-gate { 1991*7c478bd9Sstevel@tonic-gate usrerr("501 Invalid domain name"); 1992*7c478bd9Sstevel@tonic-gate if (LogLevel > 9) 1993*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, CurEnv->e_id, 1994*7c478bd9Sstevel@tonic-gate "invalid domain name (%s) from %.100s", 1995*7c478bd9Sstevel@tonic-gate p, CurSmtpClient); 1996*7c478bd9Sstevel@tonic-gate break; 1997*7c478bd9Sstevel@tonic-gate } 1998*7c478bd9Sstevel@tonic-gate else 1999*7c478bd9Sstevel@tonic-gate { 2000*7c478bd9Sstevel@tonic-gate q = "accepting invalid domain name"; 2001*7c478bd9Sstevel@tonic-gate } 2002*7c478bd9Sstevel@tonic-gate 2003*7c478bd9Sstevel@tonic-gate if (gothello) 2004*7c478bd9Sstevel@tonic-gate { 2005*7c478bd9Sstevel@tonic-gate CLEAR_STATE(cmdbuf); 2006*7c478bd9Sstevel@tonic-gate } 2007*7c478bd9Sstevel@tonic-gate 2008*7c478bd9Sstevel@tonic-gate #if MILTER 2009*7c478bd9Sstevel@tonic-gate if (smtp.sm_milterlist && smtp.sm_milterize && 2010*7c478bd9Sstevel@tonic-gate !bitset(EF_DISCARD, e->e_flags)) 2011*7c478bd9Sstevel@tonic-gate { 2012*7c478bd9Sstevel@tonic-gate char state; 2013*7c478bd9Sstevel@tonic-gate char *response; 2014*7c478bd9Sstevel@tonic-gate 2015*7c478bd9Sstevel@tonic-gate response = milter_helo(p, e, &state); 2016*7c478bd9Sstevel@tonic-gate switch (state) 2017*7c478bd9Sstevel@tonic-gate { 2018*7c478bd9Sstevel@tonic-gate case SMFIR_REPLYCODE: 2019*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 3) 2020*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 2021*7c478bd9Sstevel@tonic-gate "Milter: helo=%s, reject=%s", 2022*7c478bd9Sstevel@tonic-gate p, response); 2023*7c478bd9Sstevel@tonic-gate nullserver = newstr(response); 2024*7c478bd9Sstevel@tonic-gate smtp.sm_milterize = false; 2025*7c478bd9Sstevel@tonic-gate break; 2026*7c478bd9Sstevel@tonic-gate 2027*7c478bd9Sstevel@tonic-gate case SMFIR_REJECT: 2028*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 3) 2029*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 2030*7c478bd9Sstevel@tonic-gate "Milter: helo=%s, reject=Command rejected", 2031*7c478bd9Sstevel@tonic-gate p); 2032*7c478bd9Sstevel@tonic-gate nullserver = "Command rejected"; 2033*7c478bd9Sstevel@tonic-gate smtp.sm_milterize = false; 2034*7c478bd9Sstevel@tonic-gate break; 2035*7c478bd9Sstevel@tonic-gate 2036*7c478bd9Sstevel@tonic-gate case SMFIR_TEMPFAIL: 2037*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 3) 2038*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 2039*7c478bd9Sstevel@tonic-gate "Milter: helo=%s, reject=%s", 2040*7c478bd9Sstevel@tonic-gate p, MSG_TEMPFAIL); 2041*7c478bd9Sstevel@tonic-gate tempfail = true; 2042*7c478bd9Sstevel@tonic-gate smtp.sm_milterize = false; 2043*7c478bd9Sstevel@tonic-gate break; 2044*7c478bd9Sstevel@tonic-gate } 2045*7c478bd9Sstevel@tonic-gate if (response != NULL) 2046*7c478bd9Sstevel@tonic-gate sm_free(response); 2047*7c478bd9Sstevel@tonic-gate 2048*7c478bd9Sstevel@tonic-gate /* 2049*7c478bd9Sstevel@tonic-gate ** If quarantining by a connect/ehlo action, 2050*7c478bd9Sstevel@tonic-gate ** save between messages 2051*7c478bd9Sstevel@tonic-gate */ 2052*7c478bd9Sstevel@tonic-gate 2053*7c478bd9Sstevel@tonic-gate if (smtp.sm_quarmsg == NULL && 2054*7c478bd9Sstevel@tonic-gate e->e_quarmsg != NULL) 2055*7c478bd9Sstevel@tonic-gate smtp.sm_quarmsg = newstr(e->e_quarmsg); 2056*7c478bd9Sstevel@tonic-gate } 2057*7c478bd9Sstevel@tonic-gate #endif /* MILTER */ 2058*7c478bd9Sstevel@tonic-gate gothello = true; 2059*7c478bd9Sstevel@tonic-gate 2060*7c478bd9Sstevel@tonic-gate /* print HELO response message */ 2061*7c478bd9Sstevel@tonic-gate if (c->cmd_code != CMDEHLO) 2062*7c478bd9Sstevel@tonic-gate { 2063*7c478bd9Sstevel@tonic-gate message("250 %s Hello %s, %s", 2064*7c478bd9Sstevel@tonic-gate MyHostName, CurSmtpClient, q); 2065*7c478bd9Sstevel@tonic-gate break; 2066*7c478bd9Sstevel@tonic-gate } 2067*7c478bd9Sstevel@tonic-gate 2068*7c478bd9Sstevel@tonic-gate message("250-%s Hello %s, %s", 2069*7c478bd9Sstevel@tonic-gate MyHostName, CurSmtpClient, q); 2070*7c478bd9Sstevel@tonic-gate 2071*7c478bd9Sstevel@tonic-gate /* offer ENHSC even for nullserver */ 2072*7c478bd9Sstevel@tonic-gate if (nullserver != NULL) 2073*7c478bd9Sstevel@tonic-gate { 2074*7c478bd9Sstevel@tonic-gate message("250 ENHANCEDSTATUSCODES"); 2075*7c478bd9Sstevel@tonic-gate break; 2076*7c478bd9Sstevel@tonic-gate } 2077*7c478bd9Sstevel@tonic-gate 2078*7c478bd9Sstevel@tonic-gate /* 2079*7c478bd9Sstevel@tonic-gate ** print EHLO features list 2080*7c478bd9Sstevel@tonic-gate ** 2081*7c478bd9Sstevel@tonic-gate ** Note: If you change this list, 2082*7c478bd9Sstevel@tonic-gate ** remember to update 'helpfile' 2083*7c478bd9Sstevel@tonic-gate */ 2084*7c478bd9Sstevel@tonic-gate 2085*7c478bd9Sstevel@tonic-gate message("250-ENHANCEDSTATUSCODES"); 2086*7c478bd9Sstevel@tonic-gate #if PIPELINING 2087*7c478bd9Sstevel@tonic-gate if (bitset(SRV_OFFER_PIPE, features)) 2088*7c478bd9Sstevel@tonic-gate message("250-PIPELINING"); 2089*7c478bd9Sstevel@tonic-gate #endif /* PIPELINING */ 2090*7c478bd9Sstevel@tonic-gate if (bitset(SRV_OFFER_EXPN, features)) 2091*7c478bd9Sstevel@tonic-gate { 2092*7c478bd9Sstevel@tonic-gate message("250-EXPN"); 2093*7c478bd9Sstevel@tonic-gate if (bitset(SRV_OFFER_VERB, features)) 2094*7c478bd9Sstevel@tonic-gate message("250-VERB"); 2095*7c478bd9Sstevel@tonic-gate } 2096*7c478bd9Sstevel@tonic-gate #if MIME8TO7 2097*7c478bd9Sstevel@tonic-gate message("250-8BITMIME"); 2098*7c478bd9Sstevel@tonic-gate #endif /* MIME8TO7 */ 2099*7c478bd9Sstevel@tonic-gate if (MaxMessageSize > 0) 2100*7c478bd9Sstevel@tonic-gate message("250-SIZE %ld", MaxMessageSize); 2101*7c478bd9Sstevel@tonic-gate else 2102*7c478bd9Sstevel@tonic-gate message("250-SIZE"); 2103*7c478bd9Sstevel@tonic-gate #if DSN 2104*7c478bd9Sstevel@tonic-gate if (SendMIMEErrors && bitset(SRV_OFFER_DSN, features)) 2105*7c478bd9Sstevel@tonic-gate message("250-DSN"); 2106*7c478bd9Sstevel@tonic-gate #endif /* DSN */ 2107*7c478bd9Sstevel@tonic-gate if (bitset(SRV_OFFER_ETRN, features)) 2108*7c478bd9Sstevel@tonic-gate message("250-ETRN"); 2109*7c478bd9Sstevel@tonic-gate #if SASL 2110*7c478bd9Sstevel@tonic-gate if (sasl_ok && mechlist != NULL && *mechlist != '\0') 2111*7c478bd9Sstevel@tonic-gate message("250-AUTH %s", mechlist); 2112*7c478bd9Sstevel@tonic-gate #endif /* SASL */ 2113*7c478bd9Sstevel@tonic-gate #if STARTTLS 2114*7c478bd9Sstevel@tonic-gate if (tls_ok_srv && 2115*7c478bd9Sstevel@tonic-gate bitset(SRV_OFFER_TLS, features)) 2116*7c478bd9Sstevel@tonic-gate message("250-STARTTLS"); 2117*7c478bd9Sstevel@tonic-gate #endif /* STARTTLS */ 2118*7c478bd9Sstevel@tonic-gate if (DeliverByMin > 0) 2119*7c478bd9Sstevel@tonic-gate message("250-DELIVERBY %ld", 2120*7c478bd9Sstevel@tonic-gate (long) DeliverByMin); 2121*7c478bd9Sstevel@tonic-gate else if (DeliverByMin == 0) 2122*7c478bd9Sstevel@tonic-gate message("250-DELIVERBY"); 2123*7c478bd9Sstevel@tonic-gate 2124*7c478bd9Sstevel@tonic-gate /* < 0: no deliver-by */ 2125*7c478bd9Sstevel@tonic-gate 2126*7c478bd9Sstevel@tonic-gate message("250 HELP"); 2127*7c478bd9Sstevel@tonic-gate break; 2128*7c478bd9Sstevel@tonic-gate 2129*7c478bd9Sstevel@tonic-gate case CMDMAIL: /* mail -- designate sender */ 2130*7c478bd9Sstevel@tonic-gate SmtpPhase = "server MAIL"; 2131*7c478bd9Sstevel@tonic-gate DELAY_CONN("MAIL"); 2132*7c478bd9Sstevel@tonic-gate 2133*7c478bd9Sstevel@tonic-gate /* check for validity of this command */ 2134*7c478bd9Sstevel@tonic-gate if (!gothello && bitset(PRIV_NEEDMAILHELO, PrivacyFlags)) 2135*7c478bd9Sstevel@tonic-gate { 2136*7c478bd9Sstevel@tonic-gate usrerr("503 5.0.0 Polite people say HELO first"); 2137*7c478bd9Sstevel@tonic-gate break; 2138*7c478bd9Sstevel@tonic-gate } 2139*7c478bd9Sstevel@tonic-gate if (smtp.sm_gotmail) 2140*7c478bd9Sstevel@tonic-gate { 2141*7c478bd9Sstevel@tonic-gate usrerr("503 5.5.0 Sender already specified"); 2142*7c478bd9Sstevel@tonic-gate break; 2143*7c478bd9Sstevel@tonic-gate } 2144*7c478bd9Sstevel@tonic-gate #if SASL 2145*7c478bd9Sstevel@tonic-gate if (bitset(SRV_REQ_AUTH, features) && 2146*7c478bd9Sstevel@tonic-gate authenticating != SASL_IS_AUTH) 2147*7c478bd9Sstevel@tonic-gate { 2148*7c478bd9Sstevel@tonic-gate usrerr("530 5.7.0 Authentication required"); 2149*7c478bd9Sstevel@tonic-gate break; 2150*7c478bd9Sstevel@tonic-gate } 2151*7c478bd9Sstevel@tonic-gate #endif /* SASL */ 2152*7c478bd9Sstevel@tonic-gate 2153*7c478bd9Sstevel@tonic-gate p = skipword(p, "from"); 2154*7c478bd9Sstevel@tonic-gate if (p == NULL) 2155*7c478bd9Sstevel@tonic-gate break; 2156*7c478bd9Sstevel@tonic-gate if (tempfail) 2157*7c478bd9Sstevel@tonic-gate { 2158*7c478bd9Sstevel@tonic-gate if (LogLevel > 9) 2159*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 2160*7c478bd9Sstevel@tonic-gate "SMTP MAIL command (%.100s) from %s tempfailed (due to previous checks)", 2161*7c478bd9Sstevel@tonic-gate p, CurSmtpClient); 2162*7c478bd9Sstevel@tonic-gate usrerr(MSG_TEMPFAIL); 2163*7c478bd9Sstevel@tonic-gate break; 2164*7c478bd9Sstevel@tonic-gate } 2165*7c478bd9Sstevel@tonic-gate 2166*7c478bd9Sstevel@tonic-gate /* make sure we know who the sending host is */ 2167*7c478bd9Sstevel@tonic-gate if (sendinghost == NULL) 2168*7c478bd9Sstevel@tonic-gate sendinghost = peerhostname; 2169*7c478bd9Sstevel@tonic-gate 2170*7c478bd9Sstevel@tonic-gate 2171*7c478bd9Sstevel@tonic-gate #if SM_HEAP_CHECK 2172*7c478bd9Sstevel@tonic-gate if (sm_debug_active(&DebugLeakSmtp, 1)) 2173*7c478bd9Sstevel@tonic-gate { 2174*7c478bd9Sstevel@tonic-gate sm_heap_newgroup(); 2175*7c478bd9Sstevel@tonic-gate sm_dprintf("smtp() heap group #%d\n", 2176*7c478bd9Sstevel@tonic-gate sm_heap_group()); 2177*7c478bd9Sstevel@tonic-gate } 2178*7c478bd9Sstevel@tonic-gate #endif /* SM_HEAP_CHECK */ 2179*7c478bd9Sstevel@tonic-gate 2180*7c478bd9Sstevel@tonic-gate if (Errors > 0) 2181*7c478bd9Sstevel@tonic-gate goto undo_no_pm; 2182*7c478bd9Sstevel@tonic-gate if (!gothello) 2183*7c478bd9Sstevel@tonic-gate { 2184*7c478bd9Sstevel@tonic-gate auth_warning(e, "%s didn't use HELO protocol", 2185*7c478bd9Sstevel@tonic-gate CurSmtpClient); 2186*7c478bd9Sstevel@tonic-gate } 2187*7c478bd9Sstevel@tonic-gate #ifdef PICKY_HELO_CHECK 2188*7c478bd9Sstevel@tonic-gate if (sm_strcasecmp(sendinghost, peerhostname) != 0 && 2189*7c478bd9Sstevel@tonic-gate (sm_strcasecmp(peerhostname, "localhost") != 0 || 2190*7c478bd9Sstevel@tonic-gate sm_strcasecmp(sendinghost, MyHostName) != 0)) 2191*7c478bd9Sstevel@tonic-gate { 2192*7c478bd9Sstevel@tonic-gate auth_warning(e, "Host %s claimed to be %s", 2193*7c478bd9Sstevel@tonic-gate CurSmtpClient, sendinghost); 2194*7c478bd9Sstevel@tonic-gate } 2195*7c478bd9Sstevel@tonic-gate #endif /* PICKY_HELO_CHECK */ 2196*7c478bd9Sstevel@tonic-gate 2197*7c478bd9Sstevel@tonic-gate if (protocol == NULL) 2198*7c478bd9Sstevel@tonic-gate protocol = "SMTP"; 2199*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'r', protocol); 2200*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 's', sendinghost); 2201*7c478bd9Sstevel@tonic-gate 2202*7c478bd9Sstevel@tonic-gate if (Errors > 0) 2203*7c478bd9Sstevel@tonic-gate goto undo_no_pm; 2204*7c478bd9Sstevel@tonic-gate smtp.sm_nrcpts = 0; 2205*7c478bd9Sstevel@tonic-gate n_badrcpts = 0; 2206*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{ntries}"), "0"); 2207*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{nrcpts}"), "0"); 2208*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{nbadrcpts}"), 2209*7c478bd9Sstevel@tonic-gate "0"); 2210*7c478bd9Sstevel@tonic-gate e->e_flags |= EF_CLRQUEUE; 2211*7c478bd9Sstevel@tonic-gate sm_setproctitle(true, e, "%s %s: %.80s", 2212*7c478bd9Sstevel@tonic-gate qid_printname(e), 2213*7c478bd9Sstevel@tonic-gate CurSmtpClient, inp); 2214*7c478bd9Sstevel@tonic-gate 2215*7c478bd9Sstevel@tonic-gate /* do the processing */ 2216*7c478bd9Sstevel@tonic-gate SM_TRY 2217*7c478bd9Sstevel@tonic-gate { 2218*7c478bd9Sstevel@tonic-gate extern char *FullName; 2219*7c478bd9Sstevel@tonic-gate 2220*7c478bd9Sstevel@tonic-gate QuickAbort = true; 2221*7c478bd9Sstevel@tonic-gate SM_FREE_CLR(FullName); 2222*7c478bd9Sstevel@tonic-gate 2223*7c478bd9Sstevel@tonic-gate /* must parse sender first */ 2224*7c478bd9Sstevel@tonic-gate delimptr = NULL; 2225*7c478bd9Sstevel@tonic-gate setsender(p, e, &delimptr, ' ', false); 2226*7c478bd9Sstevel@tonic-gate if (delimptr != NULL && *delimptr != '\0') 2227*7c478bd9Sstevel@tonic-gate *delimptr++ = '\0'; 2228*7c478bd9Sstevel@tonic-gate if (Errors > 0) 2229*7c478bd9Sstevel@tonic-gate sm_exc_raisenew_x(&EtypeQuickAbort, 1); 2230*7c478bd9Sstevel@tonic-gate 2231*7c478bd9Sstevel@tonic-gate /* Successfully set e_from, allow logging */ 2232*7c478bd9Sstevel@tonic-gate e->e_flags |= EF_LOGSENDER; 2233*7c478bd9Sstevel@tonic-gate 2234*7c478bd9Sstevel@tonic-gate /* put resulting triple from parseaddr() into macros */ 2235*7c478bd9Sstevel@tonic-gate if (e->e_from.q_mailer != NULL) 2236*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 2237*7c478bd9Sstevel@tonic-gate macid("{mail_mailer}"), 2238*7c478bd9Sstevel@tonic-gate e->e_from.q_mailer->m_name); 2239*7c478bd9Sstevel@tonic-gate else 2240*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 2241*7c478bd9Sstevel@tonic-gate macid("{mail_mailer}"), NULL); 2242*7c478bd9Sstevel@tonic-gate if (e->e_from.q_host != NULL) 2243*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 2244*7c478bd9Sstevel@tonic-gate macid("{mail_host}"), 2245*7c478bd9Sstevel@tonic-gate e->e_from.q_host); 2246*7c478bd9Sstevel@tonic-gate else 2247*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 2248*7c478bd9Sstevel@tonic-gate macid("{mail_host}"), "localhost"); 2249*7c478bd9Sstevel@tonic-gate if (e->e_from.q_user != NULL) 2250*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 2251*7c478bd9Sstevel@tonic-gate macid("{mail_addr}"), 2252*7c478bd9Sstevel@tonic-gate e->e_from.q_user); 2253*7c478bd9Sstevel@tonic-gate else 2254*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 2255*7c478bd9Sstevel@tonic-gate macid("{mail_addr}"), NULL); 2256*7c478bd9Sstevel@tonic-gate if (Errors > 0) 2257*7c478bd9Sstevel@tonic-gate sm_exc_raisenew_x(&EtypeQuickAbort, 1); 2258*7c478bd9Sstevel@tonic-gate 2259*7c478bd9Sstevel@tonic-gate /* check for possible spoofing */ 2260*7c478bd9Sstevel@tonic-gate if (RealUid != 0 && OpMode == MD_SMTP && 2261*7c478bd9Sstevel@tonic-gate !wordinclass(RealUserName, 't') && 2262*7c478bd9Sstevel@tonic-gate (!bitnset(M_LOCALMAILER, 2263*7c478bd9Sstevel@tonic-gate e->e_from.q_mailer->m_flags) || 2264*7c478bd9Sstevel@tonic-gate strcmp(e->e_from.q_user, RealUserName) != 0)) 2265*7c478bd9Sstevel@tonic-gate { 2266*7c478bd9Sstevel@tonic-gate auth_warning(e, "%s owned process doing -bs", 2267*7c478bd9Sstevel@tonic-gate RealUserName); 2268*7c478bd9Sstevel@tonic-gate } 2269*7c478bd9Sstevel@tonic-gate 2270*7c478bd9Sstevel@tonic-gate /* reset to default value */ 2271*7c478bd9Sstevel@tonic-gate SevenBitInput = save_sevenbitinput; 2272*7c478bd9Sstevel@tonic-gate 2273*7c478bd9Sstevel@tonic-gate /* now parse ESMTP arguments */ 2274*7c478bd9Sstevel@tonic-gate e->e_msgsize = 0; 2275*7c478bd9Sstevel@tonic-gate addr = p; 2276*7c478bd9Sstevel@tonic-gate argno = 0; 2277*7c478bd9Sstevel@tonic-gate args[argno++] = p; 2278*7c478bd9Sstevel@tonic-gate p = delimptr; 2279*7c478bd9Sstevel@tonic-gate while (p != NULL && *p != '\0') 2280*7c478bd9Sstevel@tonic-gate { 2281*7c478bd9Sstevel@tonic-gate char *kp; 2282*7c478bd9Sstevel@tonic-gate char *vp = NULL; 2283*7c478bd9Sstevel@tonic-gate char *equal = NULL; 2284*7c478bd9Sstevel@tonic-gate 2285*7c478bd9Sstevel@tonic-gate /* locate the beginning of the keyword */ 2286*7c478bd9Sstevel@tonic-gate SKIP_SPACE(p); 2287*7c478bd9Sstevel@tonic-gate if (*p == '\0') 2288*7c478bd9Sstevel@tonic-gate break; 2289*7c478bd9Sstevel@tonic-gate kp = p; 2290*7c478bd9Sstevel@tonic-gate 2291*7c478bd9Sstevel@tonic-gate /* skip to the value portion */ 2292*7c478bd9Sstevel@tonic-gate while ((isascii(*p) && isalnum(*p)) || *p == '-') 2293*7c478bd9Sstevel@tonic-gate p++; 2294*7c478bd9Sstevel@tonic-gate if (*p == '=') 2295*7c478bd9Sstevel@tonic-gate { 2296*7c478bd9Sstevel@tonic-gate equal = p; 2297*7c478bd9Sstevel@tonic-gate *p++ = '\0'; 2298*7c478bd9Sstevel@tonic-gate vp = p; 2299*7c478bd9Sstevel@tonic-gate 2300*7c478bd9Sstevel@tonic-gate /* skip to the end of the value */ 2301*7c478bd9Sstevel@tonic-gate while (*p != '\0' && *p != ' ' && 2302*7c478bd9Sstevel@tonic-gate !(isascii(*p) && iscntrl(*p)) && 2303*7c478bd9Sstevel@tonic-gate *p != '=') 2304*7c478bd9Sstevel@tonic-gate p++; 2305*7c478bd9Sstevel@tonic-gate } 2306*7c478bd9Sstevel@tonic-gate 2307*7c478bd9Sstevel@tonic-gate if (*p != '\0') 2308*7c478bd9Sstevel@tonic-gate *p++ = '\0'; 2309*7c478bd9Sstevel@tonic-gate 2310*7c478bd9Sstevel@tonic-gate if (tTd(19, 1)) 2311*7c478bd9Sstevel@tonic-gate sm_dprintf("MAIL: got arg %s=\"%s\"\n", kp, 2312*7c478bd9Sstevel@tonic-gate vp == NULL ? "<null>" : vp); 2313*7c478bd9Sstevel@tonic-gate 2314*7c478bd9Sstevel@tonic-gate mail_esmtp_args(kp, vp, e); 2315*7c478bd9Sstevel@tonic-gate if (equal != NULL) 2316*7c478bd9Sstevel@tonic-gate *equal = '='; 2317*7c478bd9Sstevel@tonic-gate args[argno++] = kp; 2318*7c478bd9Sstevel@tonic-gate if (argno >= MAXSMTPARGS - 1) 2319*7c478bd9Sstevel@tonic-gate usrerr("501 5.5.4 Too many parameters"); 2320*7c478bd9Sstevel@tonic-gate if (Errors > 0) 2321*7c478bd9Sstevel@tonic-gate sm_exc_raisenew_x(&EtypeQuickAbort, 1); 2322*7c478bd9Sstevel@tonic-gate } 2323*7c478bd9Sstevel@tonic-gate args[argno] = NULL; 2324*7c478bd9Sstevel@tonic-gate if (Errors > 0) 2325*7c478bd9Sstevel@tonic-gate sm_exc_raisenew_x(&EtypeQuickAbort, 1); 2326*7c478bd9Sstevel@tonic-gate 2327*7c478bd9Sstevel@tonic-gate #if SASL 2328*7c478bd9Sstevel@tonic-gate # if _FFR_AUTH_PASSING 2329*7c478bd9Sstevel@tonic-gate /* set the default AUTH= if the sender didn't */ 2330*7c478bd9Sstevel@tonic-gate if (e->e_auth_param == NULL) 2331*7c478bd9Sstevel@tonic-gate { 2332*7c478bd9Sstevel@tonic-gate /* XXX only do this for an MSA? */ 2333*7c478bd9Sstevel@tonic-gate e->e_auth_param = macvalue(macid("{auth_authen}"), 2334*7c478bd9Sstevel@tonic-gate e); 2335*7c478bd9Sstevel@tonic-gate if (e->e_auth_param == NULL) 2336*7c478bd9Sstevel@tonic-gate e->e_auth_param = "<>"; 2337*7c478bd9Sstevel@tonic-gate 2338*7c478bd9Sstevel@tonic-gate /* 2339*7c478bd9Sstevel@tonic-gate ** XXX should we invoke Strust_auth now? 2340*7c478bd9Sstevel@tonic-gate ** authorizing as the client that just 2341*7c478bd9Sstevel@tonic-gate ** authenticated, so we'll trust implicitly 2342*7c478bd9Sstevel@tonic-gate */ 2343*7c478bd9Sstevel@tonic-gate } 2344*7c478bd9Sstevel@tonic-gate # endif /* _FFR_AUTH_PASSING */ 2345*7c478bd9Sstevel@tonic-gate #endif /* SASL */ 2346*7c478bd9Sstevel@tonic-gate 2347*7c478bd9Sstevel@tonic-gate /* do config file checking of the sender */ 2348*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 2349*7c478bd9Sstevel@tonic-gate macid("{addr_type}"), "e s"); 2350*7c478bd9Sstevel@tonic-gate #if _FFR_MAIL_MACRO 2351*7c478bd9Sstevel@tonic-gate /* make the "real" sender address available */ 2352*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP, macid("{mail_from}"), 2353*7c478bd9Sstevel@tonic-gate e->e_from.q_paddr); 2354*7c478bd9Sstevel@tonic-gate #endif /* _FFR_MAIL_MACRO */ 2355*7c478bd9Sstevel@tonic-gate if (rscheck("check_mail", addr, 2356*7c478bd9Sstevel@tonic-gate NULL, e, RSF_RMCOMM|RSF_COUNT, 3, 2357*7c478bd9Sstevel@tonic-gate NULL, e->e_id) != EX_OK || 2358*7c478bd9Sstevel@tonic-gate Errors > 0) 2359*7c478bd9Sstevel@tonic-gate sm_exc_raisenew_x(&EtypeQuickAbort, 1); 2360*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 2361*7c478bd9Sstevel@tonic-gate macid("{addr_type}"), NULL); 2362*7c478bd9Sstevel@tonic-gate 2363*7c478bd9Sstevel@tonic-gate if (MaxMessageSize > 0 && 2364*7c478bd9Sstevel@tonic-gate (e->e_msgsize > MaxMessageSize || 2365*7c478bd9Sstevel@tonic-gate e->e_msgsize < 0)) 2366*7c478bd9Sstevel@tonic-gate { 2367*7c478bd9Sstevel@tonic-gate usrerr("552 5.2.3 Message size exceeds fixed maximum message size (%ld)", 2368*7c478bd9Sstevel@tonic-gate MaxMessageSize); 2369*7c478bd9Sstevel@tonic-gate sm_exc_raisenew_x(&EtypeQuickAbort, 1); 2370*7c478bd9Sstevel@tonic-gate } 2371*7c478bd9Sstevel@tonic-gate 2372*7c478bd9Sstevel@tonic-gate /* 2373*7c478bd9Sstevel@tonic-gate ** XXX always check whether there is at least one fs 2374*7c478bd9Sstevel@tonic-gate ** with enough space? 2375*7c478bd9Sstevel@tonic-gate ** However, this may not help much: the queue group 2376*7c478bd9Sstevel@tonic-gate ** selection may later on select a FS that hasn't 2377*7c478bd9Sstevel@tonic-gate ** enough space. 2378*7c478bd9Sstevel@tonic-gate */ 2379*7c478bd9Sstevel@tonic-gate 2380*7c478bd9Sstevel@tonic-gate if ((NumFileSys == 1 || NumQueue == 1) && 2381*7c478bd9Sstevel@tonic-gate !enoughdiskspace(e->e_msgsize, e) 2382*7c478bd9Sstevel@tonic-gate #if _FFR_ANY_FREE_FS 2383*7c478bd9Sstevel@tonic-gate && !filesys_free(e->e_msgsize) 2384*7c478bd9Sstevel@tonic-gate #endif /* _FFR_ANY_FREE_FS */ 2385*7c478bd9Sstevel@tonic-gate ) 2386*7c478bd9Sstevel@tonic-gate { 2387*7c478bd9Sstevel@tonic-gate /* 2388*7c478bd9Sstevel@tonic-gate ** We perform this test again when the 2389*7c478bd9Sstevel@tonic-gate ** queue directory is selected, in collect. 2390*7c478bd9Sstevel@tonic-gate */ 2391*7c478bd9Sstevel@tonic-gate 2392*7c478bd9Sstevel@tonic-gate usrerr("452 4.4.5 Insufficient disk space; try again later"); 2393*7c478bd9Sstevel@tonic-gate sm_exc_raisenew_x(&EtypeQuickAbort, 1); 2394*7c478bd9Sstevel@tonic-gate } 2395*7c478bd9Sstevel@tonic-gate if (Errors > 0) 2396*7c478bd9Sstevel@tonic-gate sm_exc_raisenew_x(&EtypeQuickAbort, 1); 2397*7c478bd9Sstevel@tonic-gate 2398*7c478bd9Sstevel@tonic-gate LogUsrErrs = true; 2399*7c478bd9Sstevel@tonic-gate #if MILTER 2400*7c478bd9Sstevel@tonic-gate if (smtp.sm_milterlist && smtp.sm_milterize && 2401*7c478bd9Sstevel@tonic-gate !bitset(EF_DISCARD, e->e_flags)) 2402*7c478bd9Sstevel@tonic-gate { 2403*7c478bd9Sstevel@tonic-gate char state; 2404*7c478bd9Sstevel@tonic-gate char *response; 2405*7c478bd9Sstevel@tonic-gate 2406*7c478bd9Sstevel@tonic-gate response = milter_envfrom(args, e, &state); 2407*7c478bd9Sstevel@tonic-gate MILTER_REPLY("from"); 2408*7c478bd9Sstevel@tonic-gate } 2409*7c478bd9Sstevel@tonic-gate #endif /* MILTER */ 2410*7c478bd9Sstevel@tonic-gate if (Errors > 0) 2411*7c478bd9Sstevel@tonic-gate sm_exc_raisenew_x(&EtypeQuickAbort, 1); 2412*7c478bd9Sstevel@tonic-gate 2413*7c478bd9Sstevel@tonic-gate message("250 2.1.0 Sender ok"); 2414*7c478bd9Sstevel@tonic-gate smtp.sm_gotmail = true; 2415*7c478bd9Sstevel@tonic-gate } 2416*7c478bd9Sstevel@tonic-gate SM_EXCEPT(exc, "[!F]*") 2417*7c478bd9Sstevel@tonic-gate { 2418*7c478bd9Sstevel@tonic-gate /* 2419*7c478bd9Sstevel@tonic-gate ** An error occurred while processing a MAIL command. 2420*7c478bd9Sstevel@tonic-gate ** Jump to the common error handling code. 2421*7c478bd9Sstevel@tonic-gate */ 2422*7c478bd9Sstevel@tonic-gate 2423*7c478bd9Sstevel@tonic-gate sm_exc_free(exc); 2424*7c478bd9Sstevel@tonic-gate goto undo_no_pm; 2425*7c478bd9Sstevel@tonic-gate } 2426*7c478bd9Sstevel@tonic-gate SM_END_TRY 2427*7c478bd9Sstevel@tonic-gate break; 2428*7c478bd9Sstevel@tonic-gate 2429*7c478bd9Sstevel@tonic-gate undo_no_pm: 2430*7c478bd9Sstevel@tonic-gate e->e_flags &= ~EF_PM_NOTIFY; 2431*7c478bd9Sstevel@tonic-gate undo: 2432*7c478bd9Sstevel@tonic-gate break; 2433*7c478bd9Sstevel@tonic-gate 2434*7c478bd9Sstevel@tonic-gate case CMDRCPT: /* rcpt -- designate recipient */ 2435*7c478bd9Sstevel@tonic-gate DELAY_CONN("RCPT"); 2436*7c478bd9Sstevel@tonic-gate if (BadRcptThrottle > 0 && 2437*7c478bd9Sstevel@tonic-gate n_badrcpts >= BadRcptThrottle) 2438*7c478bd9Sstevel@tonic-gate { 2439*7c478bd9Sstevel@tonic-gate if (LogLevel > 5 && 2440*7c478bd9Sstevel@tonic-gate n_badrcpts == BadRcptThrottle) 2441*7c478bd9Sstevel@tonic-gate { 2442*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 2443*7c478bd9Sstevel@tonic-gate "%s: Possible SMTP RCPT flood, throttling.", 2444*7c478bd9Sstevel@tonic-gate CurSmtpClient); 2445*7c478bd9Sstevel@tonic-gate 2446*7c478bd9Sstevel@tonic-gate /* To avoid duplicated message */ 2447*7c478bd9Sstevel@tonic-gate n_badrcpts++; 2448*7c478bd9Sstevel@tonic-gate } 2449*7c478bd9Sstevel@tonic-gate NBADRCPTS; 2450*7c478bd9Sstevel@tonic-gate 2451*7c478bd9Sstevel@tonic-gate /* 2452*7c478bd9Sstevel@tonic-gate ** Don't use exponential backoff for now. 2453*7c478bd9Sstevel@tonic-gate ** Some servers will open more connections 2454*7c478bd9Sstevel@tonic-gate ** and actually overload the receiver even 2455*7c478bd9Sstevel@tonic-gate ** more. 2456*7c478bd9Sstevel@tonic-gate */ 2457*7c478bd9Sstevel@tonic-gate 2458*7c478bd9Sstevel@tonic-gate (void) sleep(1); 2459*7c478bd9Sstevel@tonic-gate } 2460*7c478bd9Sstevel@tonic-gate if (!smtp.sm_gotmail) 2461*7c478bd9Sstevel@tonic-gate { 2462*7c478bd9Sstevel@tonic-gate usrerr("503 5.0.0 Need MAIL before RCPT"); 2463*7c478bd9Sstevel@tonic-gate break; 2464*7c478bd9Sstevel@tonic-gate } 2465*7c478bd9Sstevel@tonic-gate SmtpPhase = "server RCPT"; 2466*7c478bd9Sstevel@tonic-gate SM_TRY 2467*7c478bd9Sstevel@tonic-gate { 2468*7c478bd9Sstevel@tonic-gate QuickAbort = true; 2469*7c478bd9Sstevel@tonic-gate LogUsrErrs = true; 2470*7c478bd9Sstevel@tonic-gate 2471*7c478bd9Sstevel@tonic-gate /* limit flooding of our machine */ 2472*7c478bd9Sstevel@tonic-gate if (MaxRcptPerMsg > 0 && 2473*7c478bd9Sstevel@tonic-gate smtp.sm_nrcpts >= MaxRcptPerMsg) 2474*7c478bd9Sstevel@tonic-gate { 2475*7c478bd9Sstevel@tonic-gate /* sleep(1); / * slow down? */ 2476*7c478bd9Sstevel@tonic-gate usrerr("452 4.5.3 Too many recipients"); 2477*7c478bd9Sstevel@tonic-gate goto rcpt_done; 2478*7c478bd9Sstevel@tonic-gate } 2479*7c478bd9Sstevel@tonic-gate 2480*7c478bd9Sstevel@tonic-gate if (e->e_sendmode != SM_DELIVER) 2481*7c478bd9Sstevel@tonic-gate e->e_flags |= EF_VRFYONLY; 2482*7c478bd9Sstevel@tonic-gate 2483*7c478bd9Sstevel@tonic-gate #if MILTER 2484*7c478bd9Sstevel@tonic-gate /* 2485*7c478bd9Sstevel@tonic-gate ** If the filter will be deleting recipients, 2486*7c478bd9Sstevel@tonic-gate ** don't expand them at RCPT time (in the call 2487*7c478bd9Sstevel@tonic-gate ** to recipient()). If they are expanded, it 2488*7c478bd9Sstevel@tonic-gate ** is impossible for removefromlist() to figure 2489*7c478bd9Sstevel@tonic-gate ** out the expanded members of the original 2490*7c478bd9Sstevel@tonic-gate ** recipient and mark them as QS_DONTSEND. 2491*7c478bd9Sstevel@tonic-gate */ 2492*7c478bd9Sstevel@tonic-gate 2493*7c478bd9Sstevel@tonic-gate if (milter_can_delrcpts()) 2494*7c478bd9Sstevel@tonic-gate e->e_flags |= EF_VRFYONLY; 2495*7c478bd9Sstevel@tonic-gate #endif /* MILTER */ 2496*7c478bd9Sstevel@tonic-gate 2497*7c478bd9Sstevel@tonic-gate p = skipword(p, "to"); 2498*7c478bd9Sstevel@tonic-gate if (p == NULL) 2499*7c478bd9Sstevel@tonic-gate goto rcpt_done; 2500*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 2501*7c478bd9Sstevel@tonic-gate macid("{addr_type}"), "e r"); 2502*7c478bd9Sstevel@tonic-gate a = parseaddr(p, NULLADDR, RF_COPYALL, ' ', &delimptr, 2503*7c478bd9Sstevel@tonic-gate e, true); 2504*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 2505*7c478bd9Sstevel@tonic-gate macid("{addr_type}"), NULL); 2506*7c478bd9Sstevel@tonic-gate if (Errors > 0) 2507*7c478bd9Sstevel@tonic-gate goto rcpt_done; 2508*7c478bd9Sstevel@tonic-gate if (a == NULL) 2509*7c478bd9Sstevel@tonic-gate { 2510*7c478bd9Sstevel@tonic-gate usrerr("501 5.0.0 Missing recipient"); 2511*7c478bd9Sstevel@tonic-gate goto rcpt_done; 2512*7c478bd9Sstevel@tonic-gate } 2513*7c478bd9Sstevel@tonic-gate 2514*7c478bd9Sstevel@tonic-gate if (delimptr != NULL && *delimptr != '\0') 2515*7c478bd9Sstevel@tonic-gate *delimptr++ = '\0'; 2516*7c478bd9Sstevel@tonic-gate 2517*7c478bd9Sstevel@tonic-gate /* put resulting triple from parseaddr() into macros */ 2518*7c478bd9Sstevel@tonic-gate if (a->q_mailer != NULL) 2519*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 2520*7c478bd9Sstevel@tonic-gate macid("{rcpt_mailer}"), 2521*7c478bd9Sstevel@tonic-gate a->q_mailer->m_name); 2522*7c478bd9Sstevel@tonic-gate else 2523*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 2524*7c478bd9Sstevel@tonic-gate macid("{rcpt_mailer}"), NULL); 2525*7c478bd9Sstevel@tonic-gate if (a->q_host != NULL) 2526*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 2527*7c478bd9Sstevel@tonic-gate macid("{rcpt_host}"), a->q_host); 2528*7c478bd9Sstevel@tonic-gate else 2529*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 2530*7c478bd9Sstevel@tonic-gate macid("{rcpt_host}"), "localhost"); 2531*7c478bd9Sstevel@tonic-gate if (a->q_user != NULL) 2532*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 2533*7c478bd9Sstevel@tonic-gate macid("{rcpt_addr}"), a->q_user); 2534*7c478bd9Sstevel@tonic-gate else 2535*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 2536*7c478bd9Sstevel@tonic-gate macid("{rcpt_addr}"), NULL); 2537*7c478bd9Sstevel@tonic-gate if (Errors > 0) 2538*7c478bd9Sstevel@tonic-gate goto rcpt_done; 2539*7c478bd9Sstevel@tonic-gate 2540*7c478bd9Sstevel@tonic-gate /* now parse ESMTP arguments */ 2541*7c478bd9Sstevel@tonic-gate addr = p; 2542*7c478bd9Sstevel@tonic-gate argno = 0; 2543*7c478bd9Sstevel@tonic-gate args[argno++] = p; 2544*7c478bd9Sstevel@tonic-gate p = delimptr; 2545*7c478bd9Sstevel@tonic-gate while (p != NULL && *p != '\0') 2546*7c478bd9Sstevel@tonic-gate { 2547*7c478bd9Sstevel@tonic-gate char *kp; 2548*7c478bd9Sstevel@tonic-gate char *vp = NULL; 2549*7c478bd9Sstevel@tonic-gate char *equal = NULL; 2550*7c478bd9Sstevel@tonic-gate 2551*7c478bd9Sstevel@tonic-gate /* locate the beginning of the keyword */ 2552*7c478bd9Sstevel@tonic-gate SKIP_SPACE(p); 2553*7c478bd9Sstevel@tonic-gate if (*p == '\0') 2554*7c478bd9Sstevel@tonic-gate break; 2555*7c478bd9Sstevel@tonic-gate kp = p; 2556*7c478bd9Sstevel@tonic-gate 2557*7c478bd9Sstevel@tonic-gate /* skip to the value portion */ 2558*7c478bd9Sstevel@tonic-gate while ((isascii(*p) && isalnum(*p)) || *p == '-') 2559*7c478bd9Sstevel@tonic-gate p++; 2560*7c478bd9Sstevel@tonic-gate if (*p == '=') 2561*7c478bd9Sstevel@tonic-gate { 2562*7c478bd9Sstevel@tonic-gate equal = p; 2563*7c478bd9Sstevel@tonic-gate *p++ = '\0'; 2564*7c478bd9Sstevel@tonic-gate vp = p; 2565*7c478bd9Sstevel@tonic-gate 2566*7c478bd9Sstevel@tonic-gate /* skip to the end of the value */ 2567*7c478bd9Sstevel@tonic-gate while (*p != '\0' && *p != ' ' && 2568*7c478bd9Sstevel@tonic-gate !(isascii(*p) && iscntrl(*p)) && 2569*7c478bd9Sstevel@tonic-gate *p != '=') 2570*7c478bd9Sstevel@tonic-gate p++; 2571*7c478bd9Sstevel@tonic-gate } 2572*7c478bd9Sstevel@tonic-gate 2573*7c478bd9Sstevel@tonic-gate if (*p != '\0') 2574*7c478bd9Sstevel@tonic-gate *p++ = '\0'; 2575*7c478bd9Sstevel@tonic-gate 2576*7c478bd9Sstevel@tonic-gate if (tTd(19, 1)) 2577*7c478bd9Sstevel@tonic-gate sm_dprintf("RCPT: got arg %s=\"%s\"\n", kp, 2578*7c478bd9Sstevel@tonic-gate vp == NULL ? "<null>" : vp); 2579*7c478bd9Sstevel@tonic-gate 2580*7c478bd9Sstevel@tonic-gate rcpt_esmtp_args(a, kp, vp, e); 2581*7c478bd9Sstevel@tonic-gate if (equal != NULL) 2582*7c478bd9Sstevel@tonic-gate *equal = '='; 2583*7c478bd9Sstevel@tonic-gate args[argno++] = kp; 2584*7c478bd9Sstevel@tonic-gate if (argno >= MAXSMTPARGS - 1) 2585*7c478bd9Sstevel@tonic-gate usrerr("501 5.5.4 Too many parameters"); 2586*7c478bd9Sstevel@tonic-gate if (Errors > 0) 2587*7c478bd9Sstevel@tonic-gate break; 2588*7c478bd9Sstevel@tonic-gate } 2589*7c478bd9Sstevel@tonic-gate args[argno] = NULL; 2590*7c478bd9Sstevel@tonic-gate if (Errors > 0) 2591*7c478bd9Sstevel@tonic-gate goto rcpt_done; 2592*7c478bd9Sstevel@tonic-gate 2593*7c478bd9Sstevel@tonic-gate /* do config file checking of the recipient */ 2594*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 2595*7c478bd9Sstevel@tonic-gate macid("{addr_type}"), "e r"); 2596*7c478bd9Sstevel@tonic-gate if (rscheck("check_rcpt", addr, 2597*7c478bd9Sstevel@tonic-gate NULL, e, RSF_RMCOMM|RSF_COUNT, 3, 2598*7c478bd9Sstevel@tonic-gate NULL, e->e_id) != EX_OK || 2599*7c478bd9Sstevel@tonic-gate Errors > 0) 2600*7c478bd9Sstevel@tonic-gate goto rcpt_done; 2601*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 2602*7c478bd9Sstevel@tonic-gate macid("{addr_type}"), NULL); 2603*7c478bd9Sstevel@tonic-gate 2604*7c478bd9Sstevel@tonic-gate /* If discarding, don't bother to verify user */ 2605*7c478bd9Sstevel@tonic-gate if (bitset(EF_DISCARD, e->e_flags)) 2606*7c478bd9Sstevel@tonic-gate a->q_state = QS_VERIFIED; 2607*7c478bd9Sstevel@tonic-gate 2608*7c478bd9Sstevel@tonic-gate #if MILTER 2609*7c478bd9Sstevel@tonic-gate if (smtp.sm_milterlist && smtp.sm_milterize && 2610*7c478bd9Sstevel@tonic-gate !bitset(EF_DISCARD, e->e_flags)) 2611*7c478bd9Sstevel@tonic-gate { 2612*7c478bd9Sstevel@tonic-gate char state; 2613*7c478bd9Sstevel@tonic-gate char *response; 2614*7c478bd9Sstevel@tonic-gate 2615*7c478bd9Sstevel@tonic-gate response = milter_envrcpt(args, e, &state); 2616*7c478bd9Sstevel@tonic-gate MILTER_REPLY("to"); 2617*7c478bd9Sstevel@tonic-gate } 2618*7c478bd9Sstevel@tonic-gate #endif /* MILTER */ 2619*7c478bd9Sstevel@tonic-gate 2620*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 2621*7c478bd9Sstevel@tonic-gate macid("{rcpt_mailer}"), NULL); 2622*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 2623*7c478bd9Sstevel@tonic-gate macid("{rcpt_host}"), NULL); 2624*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 2625*7c478bd9Sstevel@tonic-gate macid("{rcpt_addr}"), NULL); 2626*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 2627*7c478bd9Sstevel@tonic-gate macid("{dsn_notify}"), NULL); 2628*7c478bd9Sstevel@tonic-gate if (Errors > 0) 2629*7c478bd9Sstevel@tonic-gate goto rcpt_done; 2630*7c478bd9Sstevel@tonic-gate 2631*7c478bd9Sstevel@tonic-gate /* save in recipient list after ESMTP mods */ 2632*7c478bd9Sstevel@tonic-gate a = recipient(a, &e->e_sendqueue, 0, e); 2633*7c478bd9Sstevel@tonic-gate if (Errors > 0) 2634*7c478bd9Sstevel@tonic-gate goto rcpt_done; 2635*7c478bd9Sstevel@tonic-gate 2636*7c478bd9Sstevel@tonic-gate /* no errors during parsing, but might be a duplicate */ 2637*7c478bd9Sstevel@tonic-gate e->e_to = a->q_paddr; 2638*7c478bd9Sstevel@tonic-gate if (!QS_IS_BADADDR(a->q_state)) 2639*7c478bd9Sstevel@tonic-gate { 2640*7c478bd9Sstevel@tonic-gate if (smtp.sm_nrcpts == 0) 2641*7c478bd9Sstevel@tonic-gate initsys(e); 2642*7c478bd9Sstevel@tonic-gate message("250 2.1.5 Recipient ok%s", 2643*7c478bd9Sstevel@tonic-gate QS_IS_QUEUEUP(a->q_state) ? 2644*7c478bd9Sstevel@tonic-gate " (will queue)" : ""); 2645*7c478bd9Sstevel@tonic-gate smtp.sm_nrcpts++; 2646*7c478bd9Sstevel@tonic-gate } 2647*7c478bd9Sstevel@tonic-gate else 2648*7c478bd9Sstevel@tonic-gate { 2649*7c478bd9Sstevel@tonic-gate /* punt -- should keep message in ADDRESS.... */ 2650*7c478bd9Sstevel@tonic-gate usrerr("550 5.1.1 Addressee unknown"); 2651*7c478bd9Sstevel@tonic-gate } 2652*7c478bd9Sstevel@tonic-gate rcpt_done: 2653*7c478bd9Sstevel@tonic-gate if (Errors > 0) 2654*7c478bd9Sstevel@tonic-gate { 2655*7c478bd9Sstevel@tonic-gate ++n_badrcpts; 2656*7c478bd9Sstevel@tonic-gate NBADRCPTS; 2657*7c478bd9Sstevel@tonic-gate } 2658*7c478bd9Sstevel@tonic-gate } 2659*7c478bd9Sstevel@tonic-gate SM_EXCEPT(exc, "[!F]*") 2660*7c478bd9Sstevel@tonic-gate { 2661*7c478bd9Sstevel@tonic-gate /* An exception occurred while processing RCPT */ 2662*7c478bd9Sstevel@tonic-gate e->e_flags &= ~(EF_FATALERRS|EF_PM_NOTIFY); 2663*7c478bd9Sstevel@tonic-gate ++n_badrcpts; 2664*7c478bd9Sstevel@tonic-gate NBADRCPTS; 2665*7c478bd9Sstevel@tonic-gate } 2666*7c478bd9Sstevel@tonic-gate SM_END_TRY 2667*7c478bd9Sstevel@tonic-gate break; 2668*7c478bd9Sstevel@tonic-gate 2669*7c478bd9Sstevel@tonic-gate case CMDDATA: /* data -- text of mail */ 2670*7c478bd9Sstevel@tonic-gate DELAY_CONN("DATA"); 2671*7c478bd9Sstevel@tonic-gate if (!smtp_data(&smtp, e)) 2672*7c478bd9Sstevel@tonic-gate goto doquit; 2673*7c478bd9Sstevel@tonic-gate break; 2674*7c478bd9Sstevel@tonic-gate 2675*7c478bd9Sstevel@tonic-gate case CMDRSET: /* rset -- reset state */ 2676*7c478bd9Sstevel@tonic-gate if (tTd(94, 100)) 2677*7c478bd9Sstevel@tonic-gate message("451 4.0.0 Test failure"); 2678*7c478bd9Sstevel@tonic-gate else 2679*7c478bd9Sstevel@tonic-gate message("250 2.0.0 Reset state"); 2680*7c478bd9Sstevel@tonic-gate CLEAR_STATE(cmdbuf); 2681*7c478bd9Sstevel@tonic-gate break; 2682*7c478bd9Sstevel@tonic-gate 2683*7c478bd9Sstevel@tonic-gate case CMDVRFY: /* vrfy -- verify address */ 2684*7c478bd9Sstevel@tonic-gate case CMDEXPN: /* expn -- expand address */ 2685*7c478bd9Sstevel@tonic-gate vrfy = c->cmd_code == CMDVRFY; 2686*7c478bd9Sstevel@tonic-gate DELAY_CONN(vrfy ? "VRFY" : "EXPN"); 2687*7c478bd9Sstevel@tonic-gate if (tempfail) 2688*7c478bd9Sstevel@tonic-gate { 2689*7c478bd9Sstevel@tonic-gate if (LogLevel > 9) 2690*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 2691*7c478bd9Sstevel@tonic-gate "SMTP %s command (%.100s) from %s tempfailed (due to previous checks)", 2692*7c478bd9Sstevel@tonic-gate vrfy ? "VRFY" : "EXPN", 2693*7c478bd9Sstevel@tonic-gate p, CurSmtpClient); 2694*7c478bd9Sstevel@tonic-gate 2695*7c478bd9Sstevel@tonic-gate /* RFC 821 doesn't allow 4xy reply code */ 2696*7c478bd9Sstevel@tonic-gate usrerr("550 5.7.1 Please try again later"); 2697*7c478bd9Sstevel@tonic-gate break; 2698*7c478bd9Sstevel@tonic-gate } 2699*7c478bd9Sstevel@tonic-gate wt = checksmtpattack(&n_verifies, MAXVRFYCOMMANDS, 2700*7c478bd9Sstevel@tonic-gate false, vrfy ? "VRFY" : "EXPN", e); 2701*7c478bd9Sstevel@tonic-gate STOP_IF_ATTACK(wt); 2702*7c478bd9Sstevel@tonic-gate previous = curtime(); 2703*7c478bd9Sstevel@tonic-gate if ((vrfy && bitset(PRIV_NOVRFY, PrivacyFlags)) || 2704*7c478bd9Sstevel@tonic-gate (!vrfy && !bitset(SRV_OFFER_EXPN, features))) 2705*7c478bd9Sstevel@tonic-gate { 2706*7c478bd9Sstevel@tonic-gate if (vrfy) 2707*7c478bd9Sstevel@tonic-gate message("252 2.5.2 Cannot VRFY user; try RCPT to attempt delivery (or try finger)"); 2708*7c478bd9Sstevel@tonic-gate else 2709*7c478bd9Sstevel@tonic-gate message("502 5.7.0 Sorry, we do not allow this operation"); 2710*7c478bd9Sstevel@tonic-gate if (LogLevel > 5) 2711*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 2712*7c478bd9Sstevel@tonic-gate "%s: %s [rejected]", 2713*7c478bd9Sstevel@tonic-gate CurSmtpClient, 2714*7c478bd9Sstevel@tonic-gate shortenstring(inp, MAXSHORTSTR)); 2715*7c478bd9Sstevel@tonic-gate break; 2716*7c478bd9Sstevel@tonic-gate } 2717*7c478bd9Sstevel@tonic-gate else if (!gothello && 2718*7c478bd9Sstevel@tonic-gate bitset(vrfy ? PRIV_NEEDVRFYHELO : PRIV_NEEDEXPNHELO, 2719*7c478bd9Sstevel@tonic-gate PrivacyFlags)) 2720*7c478bd9Sstevel@tonic-gate { 2721*7c478bd9Sstevel@tonic-gate usrerr("503 5.0.0 I demand that you introduce yourself first"); 2722*7c478bd9Sstevel@tonic-gate break; 2723*7c478bd9Sstevel@tonic-gate } 2724*7c478bd9Sstevel@tonic-gate if (Errors > 0) 2725*7c478bd9Sstevel@tonic-gate break; 2726*7c478bd9Sstevel@tonic-gate if (LogLevel > 5) 2727*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "%s: %s", 2728*7c478bd9Sstevel@tonic-gate CurSmtpClient, 2729*7c478bd9Sstevel@tonic-gate shortenstring(inp, MAXSHORTSTR)); 2730*7c478bd9Sstevel@tonic-gate SM_TRY 2731*7c478bd9Sstevel@tonic-gate { 2732*7c478bd9Sstevel@tonic-gate QuickAbort = true; 2733*7c478bd9Sstevel@tonic-gate vrfyqueue = NULL; 2734*7c478bd9Sstevel@tonic-gate if (vrfy) 2735*7c478bd9Sstevel@tonic-gate e->e_flags |= EF_VRFYONLY; 2736*7c478bd9Sstevel@tonic-gate while (*p != '\0' && isascii(*p) && isspace(*p)) 2737*7c478bd9Sstevel@tonic-gate p++; 2738*7c478bd9Sstevel@tonic-gate if (*p == '\0') 2739*7c478bd9Sstevel@tonic-gate { 2740*7c478bd9Sstevel@tonic-gate usrerr("501 5.5.2 Argument required"); 2741*7c478bd9Sstevel@tonic-gate } 2742*7c478bd9Sstevel@tonic-gate else 2743*7c478bd9Sstevel@tonic-gate { 2744*7c478bd9Sstevel@tonic-gate /* do config file checking of the address */ 2745*7c478bd9Sstevel@tonic-gate if (rscheck(vrfy ? "check_vrfy" : "check_expn", 2746*7c478bd9Sstevel@tonic-gate p, NULL, e, RSF_RMCOMM, 2747*7c478bd9Sstevel@tonic-gate 3, NULL, NOQID) != EX_OK || 2748*7c478bd9Sstevel@tonic-gate Errors > 0) 2749*7c478bd9Sstevel@tonic-gate sm_exc_raisenew_x(&EtypeQuickAbort, 1); 2750*7c478bd9Sstevel@tonic-gate (void) sendtolist(p, NULLADDR, &vrfyqueue, 0, e); 2751*7c478bd9Sstevel@tonic-gate } 2752*7c478bd9Sstevel@tonic-gate if (wt > 0) 2753*7c478bd9Sstevel@tonic-gate { 2754*7c478bd9Sstevel@tonic-gate time_t t; 2755*7c478bd9Sstevel@tonic-gate 2756*7c478bd9Sstevel@tonic-gate t = wt - (curtime() - previous); 2757*7c478bd9Sstevel@tonic-gate if (t > 0) 2758*7c478bd9Sstevel@tonic-gate (void) sleep(t); 2759*7c478bd9Sstevel@tonic-gate } 2760*7c478bd9Sstevel@tonic-gate if (Errors > 0) 2761*7c478bd9Sstevel@tonic-gate sm_exc_raisenew_x(&EtypeQuickAbort, 1); 2762*7c478bd9Sstevel@tonic-gate if (vrfyqueue == NULL) 2763*7c478bd9Sstevel@tonic-gate { 2764*7c478bd9Sstevel@tonic-gate usrerr("554 5.5.2 Nothing to %s", vrfy ? "VRFY" : "EXPN"); 2765*7c478bd9Sstevel@tonic-gate } 2766*7c478bd9Sstevel@tonic-gate while (vrfyqueue != NULL) 2767*7c478bd9Sstevel@tonic-gate { 2768*7c478bd9Sstevel@tonic-gate if (!QS_IS_UNDELIVERED(vrfyqueue->q_state)) 2769*7c478bd9Sstevel@tonic-gate { 2770*7c478bd9Sstevel@tonic-gate vrfyqueue = vrfyqueue->q_next; 2771*7c478bd9Sstevel@tonic-gate continue; 2772*7c478bd9Sstevel@tonic-gate } 2773*7c478bd9Sstevel@tonic-gate 2774*7c478bd9Sstevel@tonic-gate /* see if there is more in the vrfy list */ 2775*7c478bd9Sstevel@tonic-gate a = vrfyqueue; 2776*7c478bd9Sstevel@tonic-gate while ((a = a->q_next) != NULL && 2777*7c478bd9Sstevel@tonic-gate (!QS_IS_UNDELIVERED(a->q_state))) 2778*7c478bd9Sstevel@tonic-gate continue; 2779*7c478bd9Sstevel@tonic-gate printvrfyaddr(vrfyqueue, a == NULL, vrfy); 2780*7c478bd9Sstevel@tonic-gate vrfyqueue = a; 2781*7c478bd9Sstevel@tonic-gate } 2782*7c478bd9Sstevel@tonic-gate } 2783*7c478bd9Sstevel@tonic-gate SM_EXCEPT(exc, "[!F]*") 2784*7c478bd9Sstevel@tonic-gate { 2785*7c478bd9Sstevel@tonic-gate /* 2786*7c478bd9Sstevel@tonic-gate ** An exception occurred while processing VRFY/EXPN 2787*7c478bd9Sstevel@tonic-gate */ 2788*7c478bd9Sstevel@tonic-gate 2789*7c478bd9Sstevel@tonic-gate sm_exc_free(exc); 2790*7c478bd9Sstevel@tonic-gate goto undo; 2791*7c478bd9Sstevel@tonic-gate } 2792*7c478bd9Sstevel@tonic-gate SM_END_TRY 2793*7c478bd9Sstevel@tonic-gate break; 2794*7c478bd9Sstevel@tonic-gate 2795*7c478bd9Sstevel@tonic-gate case CMDETRN: /* etrn -- force queue flush */ 2796*7c478bd9Sstevel@tonic-gate DELAY_CONN("ETRN"); 2797*7c478bd9Sstevel@tonic-gate 2798*7c478bd9Sstevel@tonic-gate /* Don't leak queue information via debug flags */ 2799*7c478bd9Sstevel@tonic-gate if (!bitset(SRV_OFFER_ETRN, features) || UseMSP || 2800*7c478bd9Sstevel@tonic-gate (RealUid != 0 && RealUid != TrustedUid && 2801*7c478bd9Sstevel@tonic-gate OpMode == MD_SMTP)) 2802*7c478bd9Sstevel@tonic-gate { 2803*7c478bd9Sstevel@tonic-gate /* different message for MSA ? */ 2804*7c478bd9Sstevel@tonic-gate message("502 5.7.0 Sorry, we do not allow this operation"); 2805*7c478bd9Sstevel@tonic-gate if (LogLevel > 5) 2806*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 2807*7c478bd9Sstevel@tonic-gate "%s: %s [rejected]", 2808*7c478bd9Sstevel@tonic-gate CurSmtpClient, 2809*7c478bd9Sstevel@tonic-gate shortenstring(inp, MAXSHORTSTR)); 2810*7c478bd9Sstevel@tonic-gate break; 2811*7c478bd9Sstevel@tonic-gate } 2812*7c478bd9Sstevel@tonic-gate if (tempfail) 2813*7c478bd9Sstevel@tonic-gate { 2814*7c478bd9Sstevel@tonic-gate if (LogLevel > 9) 2815*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 2816*7c478bd9Sstevel@tonic-gate "SMTP ETRN command (%.100s) from %s tempfailed (due to previous checks)", 2817*7c478bd9Sstevel@tonic-gate p, CurSmtpClient); 2818*7c478bd9Sstevel@tonic-gate usrerr(MSG_TEMPFAIL); 2819*7c478bd9Sstevel@tonic-gate break; 2820*7c478bd9Sstevel@tonic-gate } 2821*7c478bd9Sstevel@tonic-gate 2822*7c478bd9Sstevel@tonic-gate if (strlen(p) <= 0) 2823*7c478bd9Sstevel@tonic-gate { 2824*7c478bd9Sstevel@tonic-gate usrerr("500 5.5.2 Parameter required"); 2825*7c478bd9Sstevel@tonic-gate break; 2826*7c478bd9Sstevel@tonic-gate } 2827*7c478bd9Sstevel@tonic-gate 2828*7c478bd9Sstevel@tonic-gate /* crude way to avoid denial-of-service attacks */ 2829*7c478bd9Sstevel@tonic-gate STOP_IF_ATTACK(checksmtpattack(&n_etrn, MAXETRNCOMMANDS, 2830*7c478bd9Sstevel@tonic-gate true, "ETRN", e)); 2831*7c478bd9Sstevel@tonic-gate 2832*7c478bd9Sstevel@tonic-gate /* 2833*7c478bd9Sstevel@tonic-gate ** Do config file checking of the parameter. 2834*7c478bd9Sstevel@tonic-gate ** Even though we have srv_features now, we still 2835*7c478bd9Sstevel@tonic-gate ** need this ruleset because the former is called 2836*7c478bd9Sstevel@tonic-gate ** when the connection has been established, while 2837*7c478bd9Sstevel@tonic-gate ** this ruleset is called when the command is 2838*7c478bd9Sstevel@tonic-gate ** actually issued and therefore has all information 2839*7c478bd9Sstevel@tonic-gate ** available to make a decision. 2840*7c478bd9Sstevel@tonic-gate */ 2841*7c478bd9Sstevel@tonic-gate 2842*7c478bd9Sstevel@tonic-gate if (rscheck("check_etrn", p, NULL, e, 2843*7c478bd9Sstevel@tonic-gate RSF_RMCOMM, 3, NULL, NOQID) != EX_OK || 2844*7c478bd9Sstevel@tonic-gate Errors > 0) 2845*7c478bd9Sstevel@tonic-gate break; 2846*7c478bd9Sstevel@tonic-gate 2847*7c478bd9Sstevel@tonic-gate if (LogLevel > 5) 2848*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 2849*7c478bd9Sstevel@tonic-gate "%s: ETRN %s", CurSmtpClient, 2850*7c478bd9Sstevel@tonic-gate shortenstring(p, MAXSHORTSTR)); 2851*7c478bd9Sstevel@tonic-gate 2852*7c478bd9Sstevel@tonic-gate id = p; 2853*7c478bd9Sstevel@tonic-gate if (*id == '#') 2854*7c478bd9Sstevel@tonic-gate { 2855*7c478bd9Sstevel@tonic-gate int i, qgrp; 2856*7c478bd9Sstevel@tonic-gate 2857*7c478bd9Sstevel@tonic-gate id++; 2858*7c478bd9Sstevel@tonic-gate qgrp = name2qid(id); 2859*7c478bd9Sstevel@tonic-gate if (!ISVALIDQGRP(qgrp)) 2860*7c478bd9Sstevel@tonic-gate { 2861*7c478bd9Sstevel@tonic-gate usrerr("459 4.5.4 Queue %s unknown", 2862*7c478bd9Sstevel@tonic-gate id); 2863*7c478bd9Sstevel@tonic-gate break; 2864*7c478bd9Sstevel@tonic-gate } 2865*7c478bd9Sstevel@tonic-gate for (i = 0; i < NumQueue && Queue[i] != NULL; 2866*7c478bd9Sstevel@tonic-gate i++) 2867*7c478bd9Sstevel@tonic-gate Queue[i]->qg_nextrun = (time_t) -1; 2868*7c478bd9Sstevel@tonic-gate Queue[qgrp]->qg_nextrun = 0; 2869*7c478bd9Sstevel@tonic-gate ok = run_work_group(Queue[qgrp]->qg_wgrp, 2870*7c478bd9Sstevel@tonic-gate RWG_FORK|RWG_FORCE); 2871*7c478bd9Sstevel@tonic-gate if (ok && Errors == 0) 2872*7c478bd9Sstevel@tonic-gate message("250 2.0.0 Queuing for queue group %s started", id); 2873*7c478bd9Sstevel@tonic-gate break; 2874*7c478bd9Sstevel@tonic-gate } 2875*7c478bd9Sstevel@tonic-gate 2876*7c478bd9Sstevel@tonic-gate if (*id == '@') 2877*7c478bd9Sstevel@tonic-gate id++; 2878*7c478bd9Sstevel@tonic-gate else 2879*7c478bd9Sstevel@tonic-gate *--id = '@'; 2880*7c478bd9Sstevel@tonic-gate 2881*7c478bd9Sstevel@tonic-gate new = (QUEUE_CHAR *) sm_malloc(sizeof(QUEUE_CHAR)); 2882*7c478bd9Sstevel@tonic-gate if (new == NULL) 2883*7c478bd9Sstevel@tonic-gate { 2884*7c478bd9Sstevel@tonic-gate syserr("500 5.5.0 ETRN out of memory"); 2885*7c478bd9Sstevel@tonic-gate break; 2886*7c478bd9Sstevel@tonic-gate } 2887*7c478bd9Sstevel@tonic-gate new->queue_match = id; 2888*7c478bd9Sstevel@tonic-gate new->queue_negate = false; 2889*7c478bd9Sstevel@tonic-gate new->queue_next = NULL; 2890*7c478bd9Sstevel@tonic-gate QueueLimitRecipient = new; 2891*7c478bd9Sstevel@tonic-gate ok = runqueue(true, false, false, true); 2892*7c478bd9Sstevel@tonic-gate sm_free(QueueLimitRecipient); /* XXX */ 2893*7c478bd9Sstevel@tonic-gate QueueLimitRecipient = NULL; 2894*7c478bd9Sstevel@tonic-gate if (ok && Errors == 0) 2895*7c478bd9Sstevel@tonic-gate message("250 2.0.0 Queuing for node %s started", p); 2896*7c478bd9Sstevel@tonic-gate break; 2897*7c478bd9Sstevel@tonic-gate 2898*7c478bd9Sstevel@tonic-gate case CMDHELP: /* help -- give user info */ 2899*7c478bd9Sstevel@tonic-gate DELAY_CONN("HELP"); 2900*7c478bd9Sstevel@tonic-gate help(p, e); 2901*7c478bd9Sstevel@tonic-gate break; 2902*7c478bd9Sstevel@tonic-gate 2903*7c478bd9Sstevel@tonic-gate case CMDNOOP: /* noop -- do nothing */ 2904*7c478bd9Sstevel@tonic-gate DELAY_CONN("NOOP"); 2905*7c478bd9Sstevel@tonic-gate STOP_IF_ATTACK(checksmtpattack(&n_noop, MAXNOOPCOMMANDS, 2906*7c478bd9Sstevel@tonic-gate true, "NOOP", e)); 2907*7c478bd9Sstevel@tonic-gate message("250 2.0.0 OK"); 2908*7c478bd9Sstevel@tonic-gate break; 2909*7c478bd9Sstevel@tonic-gate 2910*7c478bd9Sstevel@tonic-gate case CMDQUIT: /* quit -- leave mail */ 2911*7c478bd9Sstevel@tonic-gate message("221 2.0.0 %s closing connection", MyHostName); 2912*7c478bd9Sstevel@tonic-gate #if PIPELINING 2913*7c478bd9Sstevel@tonic-gate (void) sm_io_flush(OutChannel, SM_TIME_DEFAULT); 2914*7c478bd9Sstevel@tonic-gate #endif /* PIPELINING */ 2915*7c478bd9Sstevel@tonic-gate 2916*7c478bd9Sstevel@tonic-gate if (smtp.sm_nrcpts > 0) 2917*7c478bd9Sstevel@tonic-gate logundelrcpts(e, "aborted by sender", 9, false); 2918*7c478bd9Sstevel@tonic-gate 2919*7c478bd9Sstevel@tonic-gate /* arrange to ignore any current send list */ 2920*7c478bd9Sstevel@tonic-gate e->e_sendqueue = NULL; 2921*7c478bd9Sstevel@tonic-gate 2922*7c478bd9Sstevel@tonic-gate #if STARTTLS 2923*7c478bd9Sstevel@tonic-gate /* shutdown TLS connection */ 2924*7c478bd9Sstevel@tonic-gate if (tls_active) 2925*7c478bd9Sstevel@tonic-gate { 2926*7c478bd9Sstevel@tonic-gate (void) endtls(srv_ssl, "server"); 2927*7c478bd9Sstevel@tonic-gate tls_active = false; 2928*7c478bd9Sstevel@tonic-gate } 2929*7c478bd9Sstevel@tonic-gate #endif /* STARTTLS */ 2930*7c478bd9Sstevel@tonic-gate #if SASL 2931*7c478bd9Sstevel@tonic-gate if (authenticating == SASL_IS_AUTH) 2932*7c478bd9Sstevel@tonic-gate { 2933*7c478bd9Sstevel@tonic-gate sasl_dispose(&conn); 2934*7c478bd9Sstevel@tonic-gate authenticating = SASL_NOT_AUTH; 2935*7c478bd9Sstevel@tonic-gate /* XXX sasl_done(); this is a child */ 2936*7c478bd9Sstevel@tonic-gate } 2937*7c478bd9Sstevel@tonic-gate #endif /* SASL */ 2938*7c478bd9Sstevel@tonic-gate 2939*7c478bd9Sstevel@tonic-gate doquit: 2940*7c478bd9Sstevel@tonic-gate /* avoid future 050 messages */ 2941*7c478bd9Sstevel@tonic-gate disconnect(1, e); 2942*7c478bd9Sstevel@tonic-gate 2943*7c478bd9Sstevel@tonic-gate #if MILTER 2944*7c478bd9Sstevel@tonic-gate /* close out milter filters */ 2945*7c478bd9Sstevel@tonic-gate milter_quit(e); 2946*7c478bd9Sstevel@tonic-gate #endif /* MILTER */ 2947*7c478bd9Sstevel@tonic-gate 2948*7c478bd9Sstevel@tonic-gate if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags)) 2949*7c478bd9Sstevel@tonic-gate logsender(e, NULL); 2950*7c478bd9Sstevel@tonic-gate e->e_flags &= ~EF_LOGSENDER; 2951*7c478bd9Sstevel@tonic-gate 2952*7c478bd9Sstevel@tonic-gate if (lognullconnection && LogLevel > 5 && 2953*7c478bd9Sstevel@tonic-gate nullserver == NULL) 2954*7c478bd9Sstevel@tonic-gate { 2955*7c478bd9Sstevel@tonic-gate char *d; 2956*7c478bd9Sstevel@tonic-gate 2957*7c478bd9Sstevel@tonic-gate d = macvalue(macid("{daemon_name}"), e); 2958*7c478bd9Sstevel@tonic-gate if (d == NULL) 2959*7c478bd9Sstevel@tonic-gate d = "stdin"; 2960*7c478bd9Sstevel@tonic-gate 2961*7c478bd9Sstevel@tonic-gate /* 2962*7c478bd9Sstevel@tonic-gate ** even though this id is "bogus", it makes 2963*7c478bd9Sstevel@tonic-gate ** it simpler to "grep" related events, e.g., 2964*7c478bd9Sstevel@tonic-gate ** timeouts for the same connection. 2965*7c478bd9Sstevel@tonic-gate */ 2966*7c478bd9Sstevel@tonic-gate 2967*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 2968*7c478bd9Sstevel@tonic-gate "%s did not issue MAIL/EXPN/VRFY/ETRN during connection to %s", 2969*7c478bd9Sstevel@tonic-gate CurSmtpClient, d); 2970*7c478bd9Sstevel@tonic-gate } 2971*7c478bd9Sstevel@tonic-gate if (tTd(93, 100)) 2972*7c478bd9Sstevel@tonic-gate { 2973*7c478bd9Sstevel@tonic-gate /* return to handle next connection */ 2974*7c478bd9Sstevel@tonic-gate return; 2975*7c478bd9Sstevel@tonic-gate } 2976*7c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 2977*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 2978*7c478bd9Sstevel@tonic-gate 2979*7c478bd9Sstevel@tonic-gate case CMDVERB: /* set verbose mode */ 2980*7c478bd9Sstevel@tonic-gate DELAY_CONN("VERB"); 2981*7c478bd9Sstevel@tonic-gate if (!bitset(SRV_OFFER_EXPN, features) || 2982*7c478bd9Sstevel@tonic-gate !bitset(SRV_OFFER_VERB, features)) 2983*7c478bd9Sstevel@tonic-gate { 2984*7c478bd9Sstevel@tonic-gate /* this would give out the same info */ 2985*7c478bd9Sstevel@tonic-gate message("502 5.7.0 Verbose unavailable"); 2986*7c478bd9Sstevel@tonic-gate break; 2987*7c478bd9Sstevel@tonic-gate } 2988*7c478bd9Sstevel@tonic-gate STOP_IF_ATTACK(checksmtpattack(&n_noop, MAXNOOPCOMMANDS, 2989*7c478bd9Sstevel@tonic-gate true, "VERB", e)); 2990*7c478bd9Sstevel@tonic-gate Verbose = 1; 2991*7c478bd9Sstevel@tonic-gate set_delivery_mode(SM_DELIVER, e); 2992*7c478bd9Sstevel@tonic-gate message("250 2.0.0 Verbose mode"); 2993*7c478bd9Sstevel@tonic-gate break; 2994*7c478bd9Sstevel@tonic-gate 2995*7c478bd9Sstevel@tonic-gate #if SMTPDEBUG 2996*7c478bd9Sstevel@tonic-gate case CMDDBGQSHOW: /* show queues */ 2997*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioout, SM_TIME_DEFAULT, 2998*7c478bd9Sstevel@tonic-gate "Send Queue="); 2999*7c478bd9Sstevel@tonic-gate printaddr(smioout, e->e_sendqueue, true); 3000*7c478bd9Sstevel@tonic-gate break; 3001*7c478bd9Sstevel@tonic-gate 3002*7c478bd9Sstevel@tonic-gate case CMDDBGDEBUG: /* set debug mode */ 3003*7c478bd9Sstevel@tonic-gate tTsetup(tTdvect, sizeof tTdvect, "0-99.1"); 3004*7c478bd9Sstevel@tonic-gate tTflag(p); 3005*7c478bd9Sstevel@tonic-gate message("200 2.0.0 Debug set"); 3006*7c478bd9Sstevel@tonic-gate break; 3007*7c478bd9Sstevel@tonic-gate 3008*7c478bd9Sstevel@tonic-gate #else /* SMTPDEBUG */ 3009*7c478bd9Sstevel@tonic-gate case CMDDBGQSHOW: /* show queues */ 3010*7c478bd9Sstevel@tonic-gate case CMDDBGDEBUG: /* set debug mode */ 3011*7c478bd9Sstevel@tonic-gate #endif /* SMTPDEBUG */ 3012*7c478bd9Sstevel@tonic-gate case CMDLOGBOGUS: /* bogus command */ 3013*7c478bd9Sstevel@tonic-gate DELAY_CONN("Bogus"); 3014*7c478bd9Sstevel@tonic-gate if (LogLevel > 0) 3015*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_CRIT, e->e_id, 3016*7c478bd9Sstevel@tonic-gate "\"%s\" command from %s (%.100s)", 3017*7c478bd9Sstevel@tonic-gate c->cmd_name, CurSmtpClient, 3018*7c478bd9Sstevel@tonic-gate anynet_ntoa(&RealHostAddr)); 3019*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 3020*7c478bd9Sstevel@tonic-gate 3021*7c478bd9Sstevel@tonic-gate case CMDERROR: /* unknown command */ 3022*7c478bd9Sstevel@tonic-gate #if MAXBADCOMMANDS > 0 3023*7c478bd9Sstevel@tonic-gate if (++n_badcmds > MAXBADCOMMANDS) 3024*7c478bd9Sstevel@tonic-gate { 3025*7c478bd9Sstevel@tonic-gate stopattack: 3026*7c478bd9Sstevel@tonic-gate message("421 4.7.0 %s Too many bad commands; closing connection", 3027*7c478bd9Sstevel@tonic-gate MyHostName); 3028*7c478bd9Sstevel@tonic-gate 3029*7c478bd9Sstevel@tonic-gate /* arrange to ignore any current send list */ 3030*7c478bd9Sstevel@tonic-gate e->e_sendqueue = NULL; 3031*7c478bd9Sstevel@tonic-gate goto doquit; 3032*7c478bd9Sstevel@tonic-gate } 3033*7c478bd9Sstevel@tonic-gate #endif /* MAXBADCOMMANDS > 0 */ 3034*7c478bd9Sstevel@tonic-gate 3035*7c478bd9Sstevel@tonic-gate #if MILTER && SMFI_VERSION > 2 3036*7c478bd9Sstevel@tonic-gate if (smtp.sm_milterlist && smtp.sm_milterize && 3037*7c478bd9Sstevel@tonic-gate !bitset(EF_DISCARD, e->e_flags)) 3038*7c478bd9Sstevel@tonic-gate { 3039*7c478bd9Sstevel@tonic-gate char state; 3040*7c478bd9Sstevel@tonic-gate char *response; 3041*7c478bd9Sstevel@tonic-gate 3042*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 9) 3043*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 3044*7c478bd9Sstevel@tonic-gate "Sending \"%s\" to Milter", inp); 3045*7c478bd9Sstevel@tonic-gate response = milter_unknown(inp, e, &state); 3046*7c478bd9Sstevel@tonic-gate MILTER_REPLY("unknown"); 3047*7c478bd9Sstevel@tonic-gate if (state == SMFIR_REPLYCODE || 3048*7c478bd9Sstevel@tonic-gate state == SMFIR_REJECT || 3049*7c478bd9Sstevel@tonic-gate state == SMFIR_TEMPFAIL) 3050*7c478bd9Sstevel@tonic-gate { 3051*7c478bd9Sstevel@tonic-gate /* MILTER_REPLY already gave an error */ 3052*7c478bd9Sstevel@tonic-gate break; 3053*7c478bd9Sstevel@tonic-gate } 3054*7c478bd9Sstevel@tonic-gate } 3055*7c478bd9Sstevel@tonic-gate #endif /* MILTER && SMFI_VERSION > 2 */ 3056*7c478bd9Sstevel@tonic-gate 3057*7c478bd9Sstevel@tonic-gate usrerr("500 5.5.1 Command unrecognized: \"%s\"", 3058*7c478bd9Sstevel@tonic-gate shortenstring(inp, MAXSHORTSTR)); 3059*7c478bd9Sstevel@tonic-gate break; 3060*7c478bd9Sstevel@tonic-gate 3061*7c478bd9Sstevel@tonic-gate case CMDUNIMPL: 3062*7c478bd9Sstevel@tonic-gate DELAY_CONN("Unimpl"); 3063*7c478bd9Sstevel@tonic-gate usrerr("502 5.5.1 Command not implemented: \"%s\"", 3064*7c478bd9Sstevel@tonic-gate shortenstring(inp, MAXSHORTSTR)); 3065*7c478bd9Sstevel@tonic-gate break; 3066*7c478bd9Sstevel@tonic-gate 3067*7c478bd9Sstevel@tonic-gate default: 3068*7c478bd9Sstevel@tonic-gate DELAY_CONN("default"); 3069*7c478bd9Sstevel@tonic-gate errno = 0; 3070*7c478bd9Sstevel@tonic-gate syserr("500 5.5.0 smtp: unknown code %d", c->cmd_code); 3071*7c478bd9Sstevel@tonic-gate break; 3072*7c478bd9Sstevel@tonic-gate } 3073*7c478bd9Sstevel@tonic-gate #if SASL 3074*7c478bd9Sstevel@tonic-gate } 3075*7c478bd9Sstevel@tonic-gate #endif /* SASL */ 3076*7c478bd9Sstevel@tonic-gate } 3077*7c478bd9Sstevel@tonic-gate SM_EXCEPT(exc, "[!F]*") 3078*7c478bd9Sstevel@tonic-gate { 3079*7c478bd9Sstevel@tonic-gate /* 3080*7c478bd9Sstevel@tonic-gate ** The only possible exception is "E:mta.quickabort". 3081*7c478bd9Sstevel@tonic-gate ** There is nothing to do except fall through and loop. 3082*7c478bd9Sstevel@tonic-gate */ 3083*7c478bd9Sstevel@tonic-gate } 3084*7c478bd9Sstevel@tonic-gate SM_END_TRY 3085*7c478bd9Sstevel@tonic-gate } 3086*7c478bd9Sstevel@tonic-gate } 3087*7c478bd9Sstevel@tonic-gate /* 3088*7c478bd9Sstevel@tonic-gate ** SMTP_DATA -- implement the SMTP DATA command. 3089*7c478bd9Sstevel@tonic-gate ** 3090*7c478bd9Sstevel@tonic-gate ** Parameters: 3091*7c478bd9Sstevel@tonic-gate ** smtp -- status of SMTP connection. 3092*7c478bd9Sstevel@tonic-gate ** e -- envelope. 3093*7c478bd9Sstevel@tonic-gate ** 3094*7c478bd9Sstevel@tonic-gate ** Returns: 3095*7c478bd9Sstevel@tonic-gate ** true iff SMTP session can continue. 3096*7c478bd9Sstevel@tonic-gate ** 3097*7c478bd9Sstevel@tonic-gate ** Side Effects: 3098*7c478bd9Sstevel@tonic-gate ** possibly sends message. 3099*7c478bd9Sstevel@tonic-gate */ 3100*7c478bd9Sstevel@tonic-gate 3101*7c478bd9Sstevel@tonic-gate static bool 3102*7c478bd9Sstevel@tonic-gate smtp_data(smtp, e) 3103*7c478bd9Sstevel@tonic-gate SMTP_T *smtp; 3104*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 3105*7c478bd9Sstevel@tonic-gate { 3106*7c478bd9Sstevel@tonic-gate #if MILTER 3107*7c478bd9Sstevel@tonic-gate bool milteraccept; 3108*7c478bd9Sstevel@tonic-gate #endif /* MILTER */ 3109*7c478bd9Sstevel@tonic-gate bool aborting; 3110*7c478bd9Sstevel@tonic-gate bool doublequeue; 3111*7c478bd9Sstevel@tonic-gate ADDRESS *a; 3112*7c478bd9Sstevel@tonic-gate ENVELOPE *ee; 3113*7c478bd9Sstevel@tonic-gate char *id; 3114*7c478bd9Sstevel@tonic-gate char *oldid; 3115*7c478bd9Sstevel@tonic-gate char buf[32]; 3116*7c478bd9Sstevel@tonic-gate 3117*7c478bd9Sstevel@tonic-gate SmtpPhase = "server DATA"; 3118*7c478bd9Sstevel@tonic-gate if (!smtp->sm_gotmail) 3119*7c478bd9Sstevel@tonic-gate { 3120*7c478bd9Sstevel@tonic-gate usrerr("503 5.0.0 Need MAIL command"); 3121*7c478bd9Sstevel@tonic-gate return true; 3122*7c478bd9Sstevel@tonic-gate } 3123*7c478bd9Sstevel@tonic-gate else if (smtp->sm_nrcpts <= 0) 3124*7c478bd9Sstevel@tonic-gate { 3125*7c478bd9Sstevel@tonic-gate usrerr("503 5.0.0 Need RCPT (recipient)"); 3126*7c478bd9Sstevel@tonic-gate return true; 3127*7c478bd9Sstevel@tonic-gate } 3128*7c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, "%u", smtp->sm_nrcpts); 3129*7c478bd9Sstevel@tonic-gate if (rscheck("check_data", buf, NULL, e, 3130*7c478bd9Sstevel@tonic-gate RSF_RMCOMM|RSF_UNSTRUCTURED|RSF_COUNT, 3, NULL, 3131*7c478bd9Sstevel@tonic-gate e->e_id) != EX_OK) 3132*7c478bd9Sstevel@tonic-gate return true; 3133*7c478bd9Sstevel@tonic-gate 3134*7c478bd9Sstevel@tonic-gate #if MILTER && SMFI_VERSION > 3 3135*7c478bd9Sstevel@tonic-gate if (smtp->sm_milterlist && smtp->sm_milterize && 3136*7c478bd9Sstevel@tonic-gate !bitset(EF_DISCARD, e->e_flags)) 3137*7c478bd9Sstevel@tonic-gate { 3138*7c478bd9Sstevel@tonic-gate char state; 3139*7c478bd9Sstevel@tonic-gate char *response; 3140*7c478bd9Sstevel@tonic-gate int savelogusrerrs = LogUsrErrs; 3141*7c478bd9Sstevel@tonic-gate 3142*7c478bd9Sstevel@tonic-gate response = milter_data_cmd(e, &state); 3143*7c478bd9Sstevel@tonic-gate switch (state) 3144*7c478bd9Sstevel@tonic-gate { 3145*7c478bd9Sstevel@tonic-gate case SMFIR_REPLYCODE: 3146*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 3) 3147*7c478bd9Sstevel@tonic-gate { 3148*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 3149*7c478bd9Sstevel@tonic-gate "Milter: cmd=data, reject=%s", 3150*7c478bd9Sstevel@tonic-gate response); 3151*7c478bd9Sstevel@tonic-gate LogUsrErrs = false; 3152*7c478bd9Sstevel@tonic-gate } 3153*7c478bd9Sstevel@tonic-gate usrerr(response); 3154*7c478bd9Sstevel@tonic-gate if (strncmp(response, "421 ", 4) == 0) 3155*7c478bd9Sstevel@tonic-gate { 3156*7c478bd9Sstevel@tonic-gate e->e_sendqueue = NULL; 3157*7c478bd9Sstevel@tonic-gate return false; 3158*7c478bd9Sstevel@tonic-gate } 3159*7c478bd9Sstevel@tonic-gate return true; 3160*7c478bd9Sstevel@tonic-gate 3161*7c478bd9Sstevel@tonic-gate case SMFIR_REJECT: 3162*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 3) 3163*7c478bd9Sstevel@tonic-gate { 3164*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 3165*7c478bd9Sstevel@tonic-gate "Milter: cmd=data, reject=550 5.7.1 Command rejected"); 3166*7c478bd9Sstevel@tonic-gate LogUsrErrs = false; 3167*7c478bd9Sstevel@tonic-gate } 3168*7c478bd9Sstevel@tonic-gate usrerr("550 5.7.1 Command rejected"); 3169*7c478bd9Sstevel@tonic-gate return true; 3170*7c478bd9Sstevel@tonic-gate 3171*7c478bd9Sstevel@tonic-gate case SMFIR_DISCARD: 3172*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 3) 3173*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 3174*7c478bd9Sstevel@tonic-gate "Milter: cmd=data, discard"); 3175*7c478bd9Sstevel@tonic-gate e->e_flags |= EF_DISCARD; 3176*7c478bd9Sstevel@tonic-gate break; 3177*7c478bd9Sstevel@tonic-gate 3178*7c478bd9Sstevel@tonic-gate case SMFIR_TEMPFAIL: 3179*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 3) 3180*7c478bd9Sstevel@tonic-gate { 3181*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 3182*7c478bd9Sstevel@tonic-gate "Milter: cmd=data, reject=%s", 3183*7c478bd9Sstevel@tonic-gate MSG_TEMPFAIL); 3184*7c478bd9Sstevel@tonic-gate LogUsrErrs = false; 3185*7c478bd9Sstevel@tonic-gate } 3186*7c478bd9Sstevel@tonic-gate usrerr(MSG_TEMPFAIL); 3187*7c478bd9Sstevel@tonic-gate return true; 3188*7c478bd9Sstevel@tonic-gate } 3189*7c478bd9Sstevel@tonic-gate LogUsrErrs = savelogusrerrs; 3190*7c478bd9Sstevel@tonic-gate if (response != NULL) 3191*7c478bd9Sstevel@tonic-gate sm_free(response); /* XXX */ 3192*7c478bd9Sstevel@tonic-gate } 3193*7c478bd9Sstevel@tonic-gate #endif /* MILTER && SMFI_VERSION > 3 */ 3194*7c478bd9Sstevel@tonic-gate 3195*7c478bd9Sstevel@tonic-gate /* put back discard bit */ 3196*7c478bd9Sstevel@tonic-gate if (smtp->sm_discard) 3197*7c478bd9Sstevel@tonic-gate e->e_flags |= EF_DISCARD; 3198*7c478bd9Sstevel@tonic-gate 3199*7c478bd9Sstevel@tonic-gate /* check to see if we need to re-expand aliases */ 3200*7c478bd9Sstevel@tonic-gate /* also reset QS_BADADDR on already-diagnosted addrs */ 3201*7c478bd9Sstevel@tonic-gate doublequeue = false; 3202*7c478bd9Sstevel@tonic-gate for (a = e->e_sendqueue; a != NULL; a = a->q_next) 3203*7c478bd9Sstevel@tonic-gate { 3204*7c478bd9Sstevel@tonic-gate if (QS_IS_VERIFIED(a->q_state) && 3205*7c478bd9Sstevel@tonic-gate !bitset(EF_DISCARD, e->e_flags)) 3206*7c478bd9Sstevel@tonic-gate { 3207*7c478bd9Sstevel@tonic-gate /* need to re-expand aliases */ 3208*7c478bd9Sstevel@tonic-gate doublequeue = true; 3209*7c478bd9Sstevel@tonic-gate } 3210*7c478bd9Sstevel@tonic-gate if (QS_IS_BADADDR(a->q_state)) 3211*7c478bd9Sstevel@tonic-gate { 3212*7c478bd9Sstevel@tonic-gate /* make this "go away" */ 3213*7c478bd9Sstevel@tonic-gate a->q_state = QS_DONTSEND; 3214*7c478bd9Sstevel@tonic-gate } 3215*7c478bd9Sstevel@tonic-gate } 3216*7c478bd9Sstevel@tonic-gate 3217*7c478bd9Sstevel@tonic-gate /* collect the text of the message */ 3218*7c478bd9Sstevel@tonic-gate SmtpPhase = "collect"; 3219*7c478bd9Sstevel@tonic-gate buffer_errors(); 3220*7c478bd9Sstevel@tonic-gate 3221*7c478bd9Sstevel@tonic-gate collect(InChannel, true, NULL, e, true); 3222*7c478bd9Sstevel@tonic-gate 3223*7c478bd9Sstevel@tonic-gate /* redefine message size */ 3224*7c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, "%ld", e->e_msgsize); 3225*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP, macid("{msg_size}"), buf); 3226*7c478bd9Sstevel@tonic-gate 3227*7c478bd9Sstevel@tonic-gate #if _FFR_CHECK_EOM 3228*7c478bd9Sstevel@tonic-gate /* rscheck() will set Errors or EF_DISCARD if it trips */ 3229*7c478bd9Sstevel@tonic-gate (void) rscheck("check_eom", buf, NULL, e, RSF_UNSTRUCTURED|RSF_COUNT, 3230*7c478bd9Sstevel@tonic-gate 3, NULL, e->e_id); 3231*7c478bd9Sstevel@tonic-gate #endif /* _FFR_CHECK_EOM */ 3232*7c478bd9Sstevel@tonic-gate 3233*7c478bd9Sstevel@tonic-gate #if MILTER 3234*7c478bd9Sstevel@tonic-gate milteraccept = true; 3235*7c478bd9Sstevel@tonic-gate if (smtp->sm_milterlist && smtp->sm_milterize && 3236*7c478bd9Sstevel@tonic-gate Errors <= 0 && 3237*7c478bd9Sstevel@tonic-gate !bitset(EF_DISCARD, e->e_flags)) 3238*7c478bd9Sstevel@tonic-gate { 3239*7c478bd9Sstevel@tonic-gate char state; 3240*7c478bd9Sstevel@tonic-gate char *response; 3241*7c478bd9Sstevel@tonic-gate 3242*7c478bd9Sstevel@tonic-gate response = milter_data(e, &state); 3243*7c478bd9Sstevel@tonic-gate switch (state) 3244*7c478bd9Sstevel@tonic-gate { 3245*7c478bd9Sstevel@tonic-gate case SMFIR_REPLYCODE: 3246*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 3) 3247*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 3248*7c478bd9Sstevel@tonic-gate "Milter: data, reject=%s", 3249*7c478bd9Sstevel@tonic-gate response); 3250*7c478bd9Sstevel@tonic-gate milteraccept = false; 3251*7c478bd9Sstevel@tonic-gate usrerr(response); 3252*7c478bd9Sstevel@tonic-gate break; 3253*7c478bd9Sstevel@tonic-gate 3254*7c478bd9Sstevel@tonic-gate case SMFIR_REJECT: 3255*7c478bd9Sstevel@tonic-gate milteraccept = false; 3256*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 3) 3257*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 3258*7c478bd9Sstevel@tonic-gate "Milter: data, reject=554 5.7.1 Command rejected"); 3259*7c478bd9Sstevel@tonic-gate usrerr("554 5.7.1 Command rejected"); 3260*7c478bd9Sstevel@tonic-gate break; 3261*7c478bd9Sstevel@tonic-gate 3262*7c478bd9Sstevel@tonic-gate case SMFIR_DISCARD: 3263*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 3) 3264*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 3265*7c478bd9Sstevel@tonic-gate "Milter: data, discard"); 3266*7c478bd9Sstevel@tonic-gate milteraccept = false; 3267*7c478bd9Sstevel@tonic-gate e->e_flags |= EF_DISCARD; 3268*7c478bd9Sstevel@tonic-gate break; 3269*7c478bd9Sstevel@tonic-gate 3270*7c478bd9Sstevel@tonic-gate case SMFIR_TEMPFAIL: 3271*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 3) 3272*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 3273*7c478bd9Sstevel@tonic-gate "Milter: data, reject=%s", 3274*7c478bd9Sstevel@tonic-gate MSG_TEMPFAIL); 3275*7c478bd9Sstevel@tonic-gate milteraccept = false; 3276*7c478bd9Sstevel@tonic-gate usrerr(MSG_TEMPFAIL); 3277*7c478bd9Sstevel@tonic-gate break; 3278*7c478bd9Sstevel@tonic-gate } 3279*7c478bd9Sstevel@tonic-gate if (response != NULL) 3280*7c478bd9Sstevel@tonic-gate sm_free(response); 3281*7c478bd9Sstevel@tonic-gate } 3282*7c478bd9Sstevel@tonic-gate 3283*7c478bd9Sstevel@tonic-gate /* Milter may have changed message size */ 3284*7c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, sizeof buf, "%ld", e->e_msgsize); 3285*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP, macid("{msg_size}"), buf); 3286*7c478bd9Sstevel@tonic-gate 3287*7c478bd9Sstevel@tonic-gate /* abort message filters that didn't get the body & log msg is OK */ 3288*7c478bd9Sstevel@tonic-gate if (smtp->sm_milterlist && smtp->sm_milterize) 3289*7c478bd9Sstevel@tonic-gate { 3290*7c478bd9Sstevel@tonic-gate milter_abort(e); 3291*7c478bd9Sstevel@tonic-gate if (milteraccept && MilterLogLevel > 9) 3292*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter accept: message"); 3293*7c478bd9Sstevel@tonic-gate } 3294*7c478bd9Sstevel@tonic-gate 3295*7c478bd9Sstevel@tonic-gate /* 3296*7c478bd9Sstevel@tonic-gate ** If SuperSafe is SAFE_REALLY_POSTMILTER, and we don't have milter or 3297*7c478bd9Sstevel@tonic-gate ** milter accepted message, sync it now 3298*7c478bd9Sstevel@tonic-gate ** 3299*7c478bd9Sstevel@tonic-gate ** XXX This is almost a copy of the code in collect(): put it into 3300*7c478bd9Sstevel@tonic-gate ** a function that is called from both places? 3301*7c478bd9Sstevel@tonic-gate */ 3302*7c478bd9Sstevel@tonic-gate 3303*7c478bd9Sstevel@tonic-gate if (milteraccept && SuperSafe == SAFE_REALLY_POSTMILTER) 3304*7c478bd9Sstevel@tonic-gate { 3305*7c478bd9Sstevel@tonic-gate int afd; 3306*7c478bd9Sstevel@tonic-gate SM_FILE_T *volatile df; 3307*7c478bd9Sstevel@tonic-gate char *dfname; 3308*7c478bd9Sstevel@tonic-gate 3309*7c478bd9Sstevel@tonic-gate df = e->e_dfp; 3310*7c478bd9Sstevel@tonic-gate dfname = queuename(e, DATAFL_LETTER); 3311*7c478bd9Sstevel@tonic-gate if (sm_io_setinfo(df, SM_BF_COMMIT, NULL) < 0 3312*7c478bd9Sstevel@tonic-gate && errno != EINVAL) 3313*7c478bd9Sstevel@tonic-gate { 3314*7c478bd9Sstevel@tonic-gate int save_errno; 3315*7c478bd9Sstevel@tonic-gate 3316*7c478bd9Sstevel@tonic-gate save_errno = errno; 3317*7c478bd9Sstevel@tonic-gate if (save_errno == EEXIST) 3318*7c478bd9Sstevel@tonic-gate { 3319*7c478bd9Sstevel@tonic-gate struct stat st; 3320*7c478bd9Sstevel@tonic-gate int dfd; 3321*7c478bd9Sstevel@tonic-gate 3322*7c478bd9Sstevel@tonic-gate if (stat(dfname, &st) < 0) 3323*7c478bd9Sstevel@tonic-gate st.st_size = -1; 3324*7c478bd9Sstevel@tonic-gate errno = EEXIST; 3325*7c478bd9Sstevel@tonic-gate syserr("@collect: bfcommit(%s): already on disk, size=%ld", 3326*7c478bd9Sstevel@tonic-gate dfname, (long) st.st_size); 3327*7c478bd9Sstevel@tonic-gate dfd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL); 3328*7c478bd9Sstevel@tonic-gate if (dfd >= 0) 3329*7c478bd9Sstevel@tonic-gate dumpfd(dfd, true, true); 3330*7c478bd9Sstevel@tonic-gate } 3331*7c478bd9Sstevel@tonic-gate errno = save_errno; 3332*7c478bd9Sstevel@tonic-gate dferror(df, "bfcommit", e); 3333*7c478bd9Sstevel@tonic-gate flush_errors(true); 3334*7c478bd9Sstevel@tonic-gate finis(save_errno != EEXIST, true, ExitStat); 3335*7c478bd9Sstevel@tonic-gate } 3336*7c478bd9Sstevel@tonic-gate else if ((afd = sm_io_getinfo(df, SM_IO_WHAT_FD, NULL)) < 0) 3337*7c478bd9Sstevel@tonic-gate { 3338*7c478bd9Sstevel@tonic-gate dferror(df, "sm_io_getinfo", e); 3339*7c478bd9Sstevel@tonic-gate flush_errors(true); 3340*7c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 3341*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3342*7c478bd9Sstevel@tonic-gate } 3343*7c478bd9Sstevel@tonic-gate else if (fsync(afd) < 0) 3344*7c478bd9Sstevel@tonic-gate { 3345*7c478bd9Sstevel@tonic-gate dferror(df, "fsync", e); 3346*7c478bd9Sstevel@tonic-gate flush_errors(true); 3347*7c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 3348*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3349*7c478bd9Sstevel@tonic-gate } 3350*7c478bd9Sstevel@tonic-gate else if (sm_io_close(df, SM_TIME_DEFAULT) < 0) 3351*7c478bd9Sstevel@tonic-gate { 3352*7c478bd9Sstevel@tonic-gate dferror(df, "sm_io_close", e); 3353*7c478bd9Sstevel@tonic-gate flush_errors(true); 3354*7c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 3355*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3356*7c478bd9Sstevel@tonic-gate } 3357*7c478bd9Sstevel@tonic-gate 3358*7c478bd9Sstevel@tonic-gate /* Now reopen the df file */ 3359*7c478bd9Sstevel@tonic-gate e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname, 3360*7c478bd9Sstevel@tonic-gate SM_IO_RDONLY, NULL); 3361*7c478bd9Sstevel@tonic-gate if (e->e_dfp == NULL) 3362*7c478bd9Sstevel@tonic-gate { 3363*7c478bd9Sstevel@tonic-gate /* we haven't acked receipt yet, so just chuck this */ 3364*7c478bd9Sstevel@tonic-gate syserr("@Cannot reopen %s", dfname); 3365*7c478bd9Sstevel@tonic-gate finis(true, true, ExitStat); 3366*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3367*7c478bd9Sstevel@tonic-gate } 3368*7c478bd9Sstevel@tonic-gate } 3369*7c478bd9Sstevel@tonic-gate #endif /* MILTER */ 3370*7c478bd9Sstevel@tonic-gate 3371*7c478bd9Sstevel@tonic-gate /* Check if quarantining stats should be updated */ 3372*7c478bd9Sstevel@tonic-gate if (e->e_quarmsg != NULL) 3373*7c478bd9Sstevel@tonic-gate markstats(e, NULL, STATS_QUARANTINE); 3374*7c478bd9Sstevel@tonic-gate 3375*7c478bd9Sstevel@tonic-gate /* 3376*7c478bd9Sstevel@tonic-gate ** If a header/body check (header checks or milter) 3377*7c478bd9Sstevel@tonic-gate ** set EF_DISCARD, don't queueup the message -- 3378*7c478bd9Sstevel@tonic-gate ** that would lose the EF_DISCARD bit and deliver 3379*7c478bd9Sstevel@tonic-gate ** the message. 3380*7c478bd9Sstevel@tonic-gate */ 3381*7c478bd9Sstevel@tonic-gate 3382*7c478bd9Sstevel@tonic-gate if (bitset(EF_DISCARD, e->e_flags)) 3383*7c478bd9Sstevel@tonic-gate doublequeue = false; 3384*7c478bd9Sstevel@tonic-gate 3385*7c478bd9Sstevel@tonic-gate aborting = Errors > 0; 3386*7c478bd9Sstevel@tonic-gate if (!(aborting || bitset(EF_DISCARD, e->e_flags)) && 3387*7c478bd9Sstevel@tonic-gate (QueueMode == QM_QUARANTINE || e->e_quarmsg == NULL) && 3388*7c478bd9Sstevel@tonic-gate !split_by_recipient(e)) 3389*7c478bd9Sstevel@tonic-gate aborting = bitset(EF_FATALERRS, e->e_flags); 3390*7c478bd9Sstevel@tonic-gate 3391*7c478bd9Sstevel@tonic-gate if (aborting) 3392*7c478bd9Sstevel@tonic-gate { 3393*7c478bd9Sstevel@tonic-gate /* Log who the mail would have gone to */ 3394*7c478bd9Sstevel@tonic-gate logundelrcpts(e, e->e_message, 8, false); 3395*7c478bd9Sstevel@tonic-gate flush_errors(true); 3396*7c478bd9Sstevel@tonic-gate buffer_errors(); 3397*7c478bd9Sstevel@tonic-gate goto abortmessage; 3398*7c478bd9Sstevel@tonic-gate } 3399*7c478bd9Sstevel@tonic-gate 3400*7c478bd9Sstevel@tonic-gate /* from now on, we have to operate silently */ 3401*7c478bd9Sstevel@tonic-gate buffer_errors(); 3402*7c478bd9Sstevel@tonic-gate 3403*7c478bd9Sstevel@tonic-gate #if 0 3404*7c478bd9Sstevel@tonic-gate /* 3405*7c478bd9Sstevel@tonic-gate ** Clear message, it may contain an error from the SMTP dialogue. 3406*7c478bd9Sstevel@tonic-gate ** This error must not show up in the queue. 3407*7c478bd9Sstevel@tonic-gate ** Some error message should show up, e.g., alias database 3408*7c478bd9Sstevel@tonic-gate ** not available, but others shouldn't, e.g., from check_rcpt. 3409*7c478bd9Sstevel@tonic-gate */ 3410*7c478bd9Sstevel@tonic-gate 3411*7c478bd9Sstevel@tonic-gate e->e_message = NULL; 3412*7c478bd9Sstevel@tonic-gate #endif /* 0 */ 3413*7c478bd9Sstevel@tonic-gate 3414*7c478bd9Sstevel@tonic-gate /* 3415*7c478bd9Sstevel@tonic-gate ** Arrange to send to everyone. 3416*7c478bd9Sstevel@tonic-gate ** If sending to multiple people, mail back 3417*7c478bd9Sstevel@tonic-gate ** errors rather than reporting directly. 3418*7c478bd9Sstevel@tonic-gate ** In any case, don't mail back errors for 3419*7c478bd9Sstevel@tonic-gate ** anything that has happened up to 3420*7c478bd9Sstevel@tonic-gate ** now (the other end will do this). 3421*7c478bd9Sstevel@tonic-gate ** Truncate our transcript -- the mail has gotten 3422*7c478bd9Sstevel@tonic-gate ** to us successfully, and if we have 3423*7c478bd9Sstevel@tonic-gate ** to mail this back, it will be easier 3424*7c478bd9Sstevel@tonic-gate ** on the reader. 3425*7c478bd9Sstevel@tonic-gate ** Then send to everyone. 3426*7c478bd9Sstevel@tonic-gate ** Finally give a reply code. If an error has 3427*7c478bd9Sstevel@tonic-gate ** already been given, don't mail a 3428*7c478bd9Sstevel@tonic-gate ** message back. 3429*7c478bd9Sstevel@tonic-gate ** We goose error returns by clearing error bit. 3430*7c478bd9Sstevel@tonic-gate */ 3431*7c478bd9Sstevel@tonic-gate 3432*7c478bd9Sstevel@tonic-gate SmtpPhase = "delivery"; 3433*7c478bd9Sstevel@tonic-gate (void) sm_io_setinfo(e->e_xfp, SM_BF_TRUNCATE, NULL); 3434*7c478bd9Sstevel@tonic-gate id = e->e_id; 3435*7c478bd9Sstevel@tonic-gate 3436*7c478bd9Sstevel@tonic-gate #if NAMED_BIND 3437*7c478bd9Sstevel@tonic-gate _res.retry = TimeOuts.res_retry[RES_TO_FIRST]; 3438*7c478bd9Sstevel@tonic-gate _res.retrans = TimeOuts.res_retrans[RES_TO_FIRST]; 3439*7c478bd9Sstevel@tonic-gate #endif /* NAMED_BIND */ 3440*7c478bd9Sstevel@tonic-gate 3441*7c478bd9Sstevel@tonic-gate for (ee = e; ee != NULL; ee = ee->e_sibling) 3442*7c478bd9Sstevel@tonic-gate { 3443*7c478bd9Sstevel@tonic-gate /* make sure we actually do delivery */ 3444*7c478bd9Sstevel@tonic-gate ee->e_flags &= ~EF_CLRQUEUE; 3445*7c478bd9Sstevel@tonic-gate 3446*7c478bd9Sstevel@tonic-gate /* from now on, operate silently */ 3447*7c478bd9Sstevel@tonic-gate ee->e_errormode = EM_MAIL; 3448*7c478bd9Sstevel@tonic-gate 3449*7c478bd9Sstevel@tonic-gate if (doublequeue) 3450*7c478bd9Sstevel@tonic-gate { 3451*7c478bd9Sstevel@tonic-gate /* make sure it is in the queue */ 3452*7c478bd9Sstevel@tonic-gate queueup(ee, false, true); 3453*7c478bd9Sstevel@tonic-gate } 3454*7c478bd9Sstevel@tonic-gate else 3455*7c478bd9Sstevel@tonic-gate { 3456*7c478bd9Sstevel@tonic-gate /* send to all recipients */ 3457*7c478bd9Sstevel@tonic-gate sendall(ee, SM_DEFAULT); 3458*7c478bd9Sstevel@tonic-gate } 3459*7c478bd9Sstevel@tonic-gate ee->e_to = NULL; 3460*7c478bd9Sstevel@tonic-gate } 3461*7c478bd9Sstevel@tonic-gate 3462*7c478bd9Sstevel@tonic-gate /* put back id for SMTP logging in putoutmsg() */ 3463*7c478bd9Sstevel@tonic-gate oldid = CurEnv->e_id; 3464*7c478bd9Sstevel@tonic-gate CurEnv->e_id = id; 3465*7c478bd9Sstevel@tonic-gate 3466*7c478bd9Sstevel@tonic-gate /* issue success message */ 3467*7c478bd9Sstevel@tonic-gate message("250 2.0.0 %s Message accepted for delivery", id); 3468*7c478bd9Sstevel@tonic-gate CurEnv->e_id = oldid; 3469*7c478bd9Sstevel@tonic-gate 3470*7c478bd9Sstevel@tonic-gate /* if we just queued, poke it */ 3471*7c478bd9Sstevel@tonic-gate if (doublequeue) 3472*7c478bd9Sstevel@tonic-gate { 3473*7c478bd9Sstevel@tonic-gate bool anything_to_send = false; 3474*7c478bd9Sstevel@tonic-gate 3475*7c478bd9Sstevel@tonic-gate sm_getla(); 3476*7c478bd9Sstevel@tonic-gate for (ee = e; ee != NULL; ee = ee->e_sibling) 3477*7c478bd9Sstevel@tonic-gate { 3478*7c478bd9Sstevel@tonic-gate if (WILL_BE_QUEUED(ee->e_sendmode)) 3479*7c478bd9Sstevel@tonic-gate continue; 3480*7c478bd9Sstevel@tonic-gate if (shouldqueue(ee->e_msgpriority, ee->e_ctime)) 3481*7c478bd9Sstevel@tonic-gate { 3482*7c478bd9Sstevel@tonic-gate ee->e_sendmode = SM_QUEUE; 3483*7c478bd9Sstevel@tonic-gate continue; 3484*7c478bd9Sstevel@tonic-gate } 3485*7c478bd9Sstevel@tonic-gate else if (QueueMode != QM_QUARANTINE && 3486*7c478bd9Sstevel@tonic-gate ee->e_quarmsg != NULL) 3487*7c478bd9Sstevel@tonic-gate { 3488*7c478bd9Sstevel@tonic-gate ee->e_sendmode = SM_QUEUE; 3489*7c478bd9Sstevel@tonic-gate continue; 3490*7c478bd9Sstevel@tonic-gate } 3491*7c478bd9Sstevel@tonic-gate anything_to_send = true; 3492*7c478bd9Sstevel@tonic-gate 3493*7c478bd9Sstevel@tonic-gate /* close all the queue files */ 3494*7c478bd9Sstevel@tonic-gate closexscript(ee); 3495*7c478bd9Sstevel@tonic-gate if (ee->e_dfp != NULL) 3496*7c478bd9Sstevel@tonic-gate { 3497*7c478bd9Sstevel@tonic-gate (void) sm_io_close(ee->e_dfp, SM_TIME_DEFAULT); 3498*7c478bd9Sstevel@tonic-gate ee->e_dfp = NULL; 3499*7c478bd9Sstevel@tonic-gate } 3500*7c478bd9Sstevel@tonic-gate unlockqueue(ee); 3501*7c478bd9Sstevel@tonic-gate } 3502*7c478bd9Sstevel@tonic-gate if (anything_to_send) 3503*7c478bd9Sstevel@tonic-gate { 3504*7c478bd9Sstevel@tonic-gate #if PIPELINING 3505*7c478bd9Sstevel@tonic-gate /* 3506*7c478bd9Sstevel@tonic-gate ** XXX if we don't do this, we get 250 twice 3507*7c478bd9Sstevel@tonic-gate ** because it is also flushed in the child. 3508*7c478bd9Sstevel@tonic-gate */ 3509*7c478bd9Sstevel@tonic-gate 3510*7c478bd9Sstevel@tonic-gate (void) sm_io_flush(OutChannel, SM_TIME_DEFAULT); 3511*7c478bd9Sstevel@tonic-gate #endif /* PIPELINING */ 3512*7c478bd9Sstevel@tonic-gate (void) doworklist(e, true, true); 3513*7c478bd9Sstevel@tonic-gate } 3514*7c478bd9Sstevel@tonic-gate } 3515*7c478bd9Sstevel@tonic-gate 3516*7c478bd9Sstevel@tonic-gate abortmessage: 3517*7c478bd9Sstevel@tonic-gate if (LogLevel > 4 && bitset(EF_LOGSENDER, e->e_flags)) 3518*7c478bd9Sstevel@tonic-gate logsender(e, NULL); 3519*7c478bd9Sstevel@tonic-gate e->e_flags &= ~EF_LOGSENDER; 3520*7c478bd9Sstevel@tonic-gate 3521*7c478bd9Sstevel@tonic-gate /* clean up a bit */ 3522*7c478bd9Sstevel@tonic-gate smtp->sm_gotmail = false; 3523*7c478bd9Sstevel@tonic-gate 3524*7c478bd9Sstevel@tonic-gate /* 3525*7c478bd9Sstevel@tonic-gate ** Call dropenvelope if and only if the envelope is *not* 3526*7c478bd9Sstevel@tonic-gate ** being processed by the child process forked by doworklist(). 3527*7c478bd9Sstevel@tonic-gate */ 3528*7c478bd9Sstevel@tonic-gate 3529*7c478bd9Sstevel@tonic-gate if (aborting || bitset(EF_DISCARD, e->e_flags)) 3530*7c478bd9Sstevel@tonic-gate dropenvelope(e, true, false); 3531*7c478bd9Sstevel@tonic-gate else 3532*7c478bd9Sstevel@tonic-gate { 3533*7c478bd9Sstevel@tonic-gate for (ee = e; ee != NULL; ee = ee->e_sibling) 3534*7c478bd9Sstevel@tonic-gate { 3535*7c478bd9Sstevel@tonic-gate if (!doublequeue && 3536*7c478bd9Sstevel@tonic-gate QueueMode != QM_QUARANTINE && 3537*7c478bd9Sstevel@tonic-gate ee->e_quarmsg != NULL) 3538*7c478bd9Sstevel@tonic-gate { 3539*7c478bd9Sstevel@tonic-gate dropenvelope(ee, true, false); 3540*7c478bd9Sstevel@tonic-gate continue; 3541*7c478bd9Sstevel@tonic-gate } 3542*7c478bd9Sstevel@tonic-gate if (WILL_BE_QUEUED(ee->e_sendmode)) 3543*7c478bd9Sstevel@tonic-gate dropenvelope(ee, true, false); 3544*7c478bd9Sstevel@tonic-gate } 3545*7c478bd9Sstevel@tonic-gate } 3546*7c478bd9Sstevel@tonic-gate sm_rpool_free(e->e_rpool); 3547*7c478bd9Sstevel@tonic-gate 3548*7c478bd9Sstevel@tonic-gate /* 3549*7c478bd9Sstevel@tonic-gate ** At this point, e == &MainEnvelope, but if we did splitting, 3550*7c478bd9Sstevel@tonic-gate ** then CurEnv may point to an envelope structure that was just 3551*7c478bd9Sstevel@tonic-gate ** freed with the rpool. So reset CurEnv *before* calling 3552*7c478bd9Sstevel@tonic-gate ** newenvelope. 3553*7c478bd9Sstevel@tonic-gate */ 3554*7c478bd9Sstevel@tonic-gate 3555*7c478bd9Sstevel@tonic-gate CurEnv = e; 3556*7c478bd9Sstevel@tonic-gate newenvelope(e, e, sm_rpool_new_x(NULL)); 3557*7c478bd9Sstevel@tonic-gate e->e_flags = BlankEnvelope.e_flags; 3558*7c478bd9Sstevel@tonic-gate 3559*7c478bd9Sstevel@tonic-gate /* restore connection quarantining */ 3560*7c478bd9Sstevel@tonic-gate if (smtp->sm_quarmsg == NULL) 3561*7c478bd9Sstevel@tonic-gate { 3562*7c478bd9Sstevel@tonic-gate e->e_quarmsg = NULL; 3563*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), ""); 3564*7c478bd9Sstevel@tonic-gate } 3565*7c478bd9Sstevel@tonic-gate else 3566*7c478bd9Sstevel@tonic-gate { 3567*7c478bd9Sstevel@tonic-gate e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, smtp->sm_quarmsg); 3568*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 3569*7c478bd9Sstevel@tonic-gate macid("{quarantine}"), e->e_quarmsg); 3570*7c478bd9Sstevel@tonic-gate } 3571*7c478bd9Sstevel@tonic-gate return true; 3572*7c478bd9Sstevel@tonic-gate } 3573*7c478bd9Sstevel@tonic-gate /* 3574*7c478bd9Sstevel@tonic-gate ** LOGUNDELRCPTS -- log undelivered (or all) recipients. 3575*7c478bd9Sstevel@tonic-gate ** 3576*7c478bd9Sstevel@tonic-gate ** Parameters: 3577*7c478bd9Sstevel@tonic-gate ** e -- envelope. 3578*7c478bd9Sstevel@tonic-gate ** msg -- message for Stat= 3579*7c478bd9Sstevel@tonic-gate ** level -- log level. 3580*7c478bd9Sstevel@tonic-gate ** all -- log all recipients. 3581*7c478bd9Sstevel@tonic-gate ** 3582*7c478bd9Sstevel@tonic-gate ** Returns: 3583*7c478bd9Sstevel@tonic-gate ** none. 3584*7c478bd9Sstevel@tonic-gate ** 3585*7c478bd9Sstevel@tonic-gate ** Side Effects: 3586*7c478bd9Sstevel@tonic-gate ** logs undelivered (or all) recipients 3587*7c478bd9Sstevel@tonic-gate */ 3588*7c478bd9Sstevel@tonic-gate 3589*7c478bd9Sstevel@tonic-gate void 3590*7c478bd9Sstevel@tonic-gate logundelrcpts(e, msg, level, all) 3591*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 3592*7c478bd9Sstevel@tonic-gate char *msg; 3593*7c478bd9Sstevel@tonic-gate int level; 3594*7c478bd9Sstevel@tonic-gate bool all; 3595*7c478bd9Sstevel@tonic-gate { 3596*7c478bd9Sstevel@tonic-gate ADDRESS *a; 3597*7c478bd9Sstevel@tonic-gate 3598*7c478bd9Sstevel@tonic-gate if (LogLevel <= level || msg == NULL || *msg == '\0') 3599*7c478bd9Sstevel@tonic-gate return; 3600*7c478bd9Sstevel@tonic-gate 3601*7c478bd9Sstevel@tonic-gate /* Clear $h so relay= doesn't get mislogged by logdelivery() */ 3602*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 'h', NULL); 3603*7c478bd9Sstevel@tonic-gate 3604*7c478bd9Sstevel@tonic-gate /* Log who the mail would have gone to */ 3605*7c478bd9Sstevel@tonic-gate for (a = e->e_sendqueue; a != NULL; a = a->q_next) 3606*7c478bd9Sstevel@tonic-gate { 3607*7c478bd9Sstevel@tonic-gate if (!QS_IS_UNDELIVERED(a->q_state) && !all) 3608*7c478bd9Sstevel@tonic-gate continue; 3609*7c478bd9Sstevel@tonic-gate e->e_to = a->q_paddr; 3610*7c478bd9Sstevel@tonic-gate logdelivery(NULL, NULL, a->q_status, msg, NULL, 3611*7c478bd9Sstevel@tonic-gate (time_t) 0, e); 3612*7c478bd9Sstevel@tonic-gate } 3613*7c478bd9Sstevel@tonic-gate e->e_to = NULL; 3614*7c478bd9Sstevel@tonic-gate } 3615*7c478bd9Sstevel@tonic-gate /* 3616*7c478bd9Sstevel@tonic-gate ** CHECKSMTPATTACK -- check for denial-of-service attack by repetition 3617*7c478bd9Sstevel@tonic-gate ** 3618*7c478bd9Sstevel@tonic-gate ** Parameters: 3619*7c478bd9Sstevel@tonic-gate ** pcounter -- pointer to a counter for this command. 3620*7c478bd9Sstevel@tonic-gate ** maxcount -- maximum value for this counter before we 3621*7c478bd9Sstevel@tonic-gate ** slow down. 3622*7c478bd9Sstevel@tonic-gate ** waitnow -- sleep now (in this routine)? 3623*7c478bd9Sstevel@tonic-gate ** cname -- command name for logging. 3624*7c478bd9Sstevel@tonic-gate ** e -- the current envelope. 3625*7c478bd9Sstevel@tonic-gate ** 3626*7c478bd9Sstevel@tonic-gate ** Returns: 3627*7c478bd9Sstevel@tonic-gate ** time to wait, 3628*7c478bd9Sstevel@tonic-gate ** STOP_ATTACK if twice as many commands as allowed and 3629*7c478bd9Sstevel@tonic-gate ** MaxChildren > 0. 3630*7c478bd9Sstevel@tonic-gate ** 3631*7c478bd9Sstevel@tonic-gate ** Side Effects: 3632*7c478bd9Sstevel@tonic-gate ** Slows down if we seem to be under attack. 3633*7c478bd9Sstevel@tonic-gate */ 3634*7c478bd9Sstevel@tonic-gate 3635*7c478bd9Sstevel@tonic-gate static time_t 3636*7c478bd9Sstevel@tonic-gate checksmtpattack(pcounter, maxcount, waitnow, cname, e) 3637*7c478bd9Sstevel@tonic-gate volatile unsigned int *pcounter; 3638*7c478bd9Sstevel@tonic-gate unsigned int maxcount; 3639*7c478bd9Sstevel@tonic-gate bool waitnow; 3640*7c478bd9Sstevel@tonic-gate char *cname; 3641*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 3642*7c478bd9Sstevel@tonic-gate { 3643*7c478bd9Sstevel@tonic-gate if (maxcount <= 0) /* no limit */ 3644*7c478bd9Sstevel@tonic-gate return (time_t) 0; 3645*7c478bd9Sstevel@tonic-gate 3646*7c478bd9Sstevel@tonic-gate if (++(*pcounter) >= maxcount) 3647*7c478bd9Sstevel@tonic-gate { 3648*7c478bd9Sstevel@tonic-gate unsigned int shift; 3649*7c478bd9Sstevel@tonic-gate time_t s; 3650*7c478bd9Sstevel@tonic-gate 3651*7c478bd9Sstevel@tonic-gate if (*pcounter == maxcount && LogLevel > 5) 3652*7c478bd9Sstevel@tonic-gate { 3653*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 3654*7c478bd9Sstevel@tonic-gate "%s: possible SMTP attack: command=%.40s, count=%u", 3655*7c478bd9Sstevel@tonic-gate CurSmtpClient, cname, *pcounter); 3656*7c478bd9Sstevel@tonic-gate } 3657*7c478bd9Sstevel@tonic-gate shift = *pcounter - maxcount; 3658*7c478bd9Sstevel@tonic-gate s = 1 << shift; 3659*7c478bd9Sstevel@tonic-gate if (shift > MAXSHIFT || s >= MAXTIMEOUT || s <= 0) 3660*7c478bd9Sstevel@tonic-gate s = MAXTIMEOUT; 3661*7c478bd9Sstevel@tonic-gate 3662*7c478bd9Sstevel@tonic-gate #define IS_ATTACK(s) ((MaxChildren > 0 && *pcounter >= maxcount * 2) \ 3663*7c478bd9Sstevel@tonic-gate ? STOP_ATTACK : (time_t) s) 3664*7c478bd9Sstevel@tonic-gate 3665*7c478bd9Sstevel@tonic-gate /* sleep at least 1 second before returning */ 3666*7c478bd9Sstevel@tonic-gate (void) sleep(*pcounter / maxcount); 3667*7c478bd9Sstevel@tonic-gate s -= *pcounter / maxcount; 3668*7c478bd9Sstevel@tonic-gate if (s >= MAXTIMEOUT || s < 0) 3669*7c478bd9Sstevel@tonic-gate s = MAXTIMEOUT; 3670*7c478bd9Sstevel@tonic-gate if (waitnow && s > 0) 3671*7c478bd9Sstevel@tonic-gate { 3672*7c478bd9Sstevel@tonic-gate (void) sleep(s); 3673*7c478bd9Sstevel@tonic-gate return IS_ATTACK(0); 3674*7c478bd9Sstevel@tonic-gate } 3675*7c478bd9Sstevel@tonic-gate return IS_ATTACK(s); 3676*7c478bd9Sstevel@tonic-gate } 3677*7c478bd9Sstevel@tonic-gate return (time_t) 0; 3678*7c478bd9Sstevel@tonic-gate } 3679*7c478bd9Sstevel@tonic-gate /* 3680*7c478bd9Sstevel@tonic-gate ** SETUP_SMTPD_IO -- setup I/O fd correctly for the SMTP server 3681*7c478bd9Sstevel@tonic-gate ** 3682*7c478bd9Sstevel@tonic-gate ** Parameters: 3683*7c478bd9Sstevel@tonic-gate ** none. 3684*7c478bd9Sstevel@tonic-gate ** 3685*7c478bd9Sstevel@tonic-gate ** Returns: 3686*7c478bd9Sstevel@tonic-gate ** nothing. 3687*7c478bd9Sstevel@tonic-gate ** 3688*7c478bd9Sstevel@tonic-gate ** Side Effects: 3689*7c478bd9Sstevel@tonic-gate ** may change I/O fd. 3690*7c478bd9Sstevel@tonic-gate */ 3691*7c478bd9Sstevel@tonic-gate 3692*7c478bd9Sstevel@tonic-gate static void 3693*7c478bd9Sstevel@tonic-gate setup_smtpd_io() 3694*7c478bd9Sstevel@tonic-gate { 3695*7c478bd9Sstevel@tonic-gate int inchfd, outchfd, outfd; 3696*7c478bd9Sstevel@tonic-gate 3697*7c478bd9Sstevel@tonic-gate inchfd = sm_io_getinfo(InChannel, SM_IO_WHAT_FD, NULL); 3698*7c478bd9Sstevel@tonic-gate outchfd = sm_io_getinfo(OutChannel, SM_IO_WHAT_FD, NULL); 3699*7c478bd9Sstevel@tonic-gate outfd = sm_io_getinfo(smioout, SM_IO_WHAT_FD, NULL); 3700*7c478bd9Sstevel@tonic-gate if (outchfd != outfd) 3701*7c478bd9Sstevel@tonic-gate { 3702*7c478bd9Sstevel@tonic-gate /* arrange for debugging output to go to remote host */ 3703*7c478bd9Sstevel@tonic-gate (void) dup2(outchfd, outfd); 3704*7c478bd9Sstevel@tonic-gate } 3705*7c478bd9Sstevel@tonic-gate 3706*7c478bd9Sstevel@tonic-gate /* 3707*7c478bd9Sstevel@tonic-gate ** if InChannel and OutChannel are stdin/stdout 3708*7c478bd9Sstevel@tonic-gate ** and connected to ttys 3709*7c478bd9Sstevel@tonic-gate ** and fcntl(STDIN, F_SETFL, O_NONBLOCKING) also changes STDOUT, 3710*7c478bd9Sstevel@tonic-gate ** then "chain" them together. 3711*7c478bd9Sstevel@tonic-gate */ 3712*7c478bd9Sstevel@tonic-gate 3713*7c478bd9Sstevel@tonic-gate if (inchfd == STDIN_FILENO && outchfd == STDOUT_FILENO && 3714*7c478bd9Sstevel@tonic-gate isatty(inchfd) && isatty(outchfd)) 3715*7c478bd9Sstevel@tonic-gate { 3716*7c478bd9Sstevel@tonic-gate int inmode, outmode; 3717*7c478bd9Sstevel@tonic-gate 3718*7c478bd9Sstevel@tonic-gate inmode = fcntl(inchfd, F_GETFL, 0); 3719*7c478bd9Sstevel@tonic-gate if (inmode == -1) 3720*7c478bd9Sstevel@tonic-gate { 3721*7c478bd9Sstevel@tonic-gate if (LogLevel > 11) 3722*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 3723*7c478bd9Sstevel@tonic-gate "fcntl(inchfd, F_GETFL) failed: %s", 3724*7c478bd9Sstevel@tonic-gate sm_errstring(errno)); 3725*7c478bd9Sstevel@tonic-gate return; 3726*7c478bd9Sstevel@tonic-gate } 3727*7c478bd9Sstevel@tonic-gate outmode = fcntl(outchfd, F_GETFL, 0); 3728*7c478bd9Sstevel@tonic-gate if (outmode == -1) 3729*7c478bd9Sstevel@tonic-gate { 3730*7c478bd9Sstevel@tonic-gate if (LogLevel > 11) 3731*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 3732*7c478bd9Sstevel@tonic-gate "fcntl(outchfd, F_GETFL) failed: %s", 3733*7c478bd9Sstevel@tonic-gate sm_errstring(errno)); 3734*7c478bd9Sstevel@tonic-gate return; 3735*7c478bd9Sstevel@tonic-gate } 3736*7c478bd9Sstevel@tonic-gate if (bitset(O_NONBLOCK, inmode) || 3737*7c478bd9Sstevel@tonic-gate bitset(O_NONBLOCK, outmode) || 3738*7c478bd9Sstevel@tonic-gate fcntl(inchfd, F_SETFL, inmode | O_NONBLOCK) == -1) 3739*7c478bd9Sstevel@tonic-gate return; 3740*7c478bd9Sstevel@tonic-gate outmode = fcntl(outchfd, F_GETFL, 0); 3741*7c478bd9Sstevel@tonic-gate if (outmode != -1 && bitset(O_NONBLOCK, outmode)) 3742*7c478bd9Sstevel@tonic-gate { 3743*7c478bd9Sstevel@tonic-gate /* changing InChannel also changes OutChannel */ 3744*7c478bd9Sstevel@tonic-gate sm_io_automode(OutChannel, InChannel); 3745*7c478bd9Sstevel@tonic-gate if (tTd(97, 4) && LogLevel > 9) 3746*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 3747*7c478bd9Sstevel@tonic-gate "set automode for I (%d)/O (%d) in SMTP server", 3748*7c478bd9Sstevel@tonic-gate inchfd, outchfd); 3749*7c478bd9Sstevel@tonic-gate } 3750*7c478bd9Sstevel@tonic-gate 3751*7c478bd9Sstevel@tonic-gate /* undo change of inchfd */ 3752*7c478bd9Sstevel@tonic-gate (void) fcntl(inchfd, F_SETFL, inmode); 3753*7c478bd9Sstevel@tonic-gate } 3754*7c478bd9Sstevel@tonic-gate } 3755*7c478bd9Sstevel@tonic-gate /* 3756*7c478bd9Sstevel@tonic-gate ** SKIPWORD -- skip a fixed word. 3757*7c478bd9Sstevel@tonic-gate ** 3758*7c478bd9Sstevel@tonic-gate ** Parameters: 3759*7c478bd9Sstevel@tonic-gate ** p -- place to start looking. 3760*7c478bd9Sstevel@tonic-gate ** w -- word to skip. 3761*7c478bd9Sstevel@tonic-gate ** 3762*7c478bd9Sstevel@tonic-gate ** Returns: 3763*7c478bd9Sstevel@tonic-gate ** p following w. 3764*7c478bd9Sstevel@tonic-gate ** NULL on error. 3765*7c478bd9Sstevel@tonic-gate ** 3766*7c478bd9Sstevel@tonic-gate ** Side Effects: 3767*7c478bd9Sstevel@tonic-gate ** clobbers the p data area. 3768*7c478bd9Sstevel@tonic-gate */ 3769*7c478bd9Sstevel@tonic-gate 3770*7c478bd9Sstevel@tonic-gate static char * 3771*7c478bd9Sstevel@tonic-gate skipword(p, w) 3772*7c478bd9Sstevel@tonic-gate register char *volatile p; 3773*7c478bd9Sstevel@tonic-gate char *w; 3774*7c478bd9Sstevel@tonic-gate { 3775*7c478bd9Sstevel@tonic-gate register char *q; 3776*7c478bd9Sstevel@tonic-gate char *firstp = p; 3777*7c478bd9Sstevel@tonic-gate 3778*7c478bd9Sstevel@tonic-gate /* find beginning of word */ 3779*7c478bd9Sstevel@tonic-gate SKIP_SPACE(p); 3780*7c478bd9Sstevel@tonic-gate q = p; 3781*7c478bd9Sstevel@tonic-gate 3782*7c478bd9Sstevel@tonic-gate /* find end of word */ 3783*7c478bd9Sstevel@tonic-gate while (*p != '\0' && *p != ':' && !(isascii(*p) && isspace(*p))) 3784*7c478bd9Sstevel@tonic-gate p++; 3785*7c478bd9Sstevel@tonic-gate while (isascii(*p) && isspace(*p)) 3786*7c478bd9Sstevel@tonic-gate *p++ = '\0'; 3787*7c478bd9Sstevel@tonic-gate if (*p != ':') 3788*7c478bd9Sstevel@tonic-gate { 3789*7c478bd9Sstevel@tonic-gate syntax: 3790*7c478bd9Sstevel@tonic-gate usrerr("501 5.5.2 Syntax error in parameters scanning \"%s\"", 3791*7c478bd9Sstevel@tonic-gate shortenstring(firstp, MAXSHORTSTR)); 3792*7c478bd9Sstevel@tonic-gate return NULL; 3793*7c478bd9Sstevel@tonic-gate } 3794*7c478bd9Sstevel@tonic-gate *p++ = '\0'; 3795*7c478bd9Sstevel@tonic-gate SKIP_SPACE(p); 3796*7c478bd9Sstevel@tonic-gate 3797*7c478bd9Sstevel@tonic-gate if (*p == '\0') 3798*7c478bd9Sstevel@tonic-gate goto syntax; 3799*7c478bd9Sstevel@tonic-gate 3800*7c478bd9Sstevel@tonic-gate /* see if the input word matches desired word */ 3801*7c478bd9Sstevel@tonic-gate if (sm_strcasecmp(q, w)) 3802*7c478bd9Sstevel@tonic-gate goto syntax; 3803*7c478bd9Sstevel@tonic-gate 3804*7c478bd9Sstevel@tonic-gate return p; 3805*7c478bd9Sstevel@tonic-gate } 3806*7c478bd9Sstevel@tonic-gate /* 3807*7c478bd9Sstevel@tonic-gate ** MAIL_ESMTP_ARGS -- process ESMTP arguments from MAIL line 3808*7c478bd9Sstevel@tonic-gate ** 3809*7c478bd9Sstevel@tonic-gate ** Parameters: 3810*7c478bd9Sstevel@tonic-gate ** kp -- the parameter key. 3811*7c478bd9Sstevel@tonic-gate ** vp -- the value of that parameter. 3812*7c478bd9Sstevel@tonic-gate ** e -- the envelope. 3813*7c478bd9Sstevel@tonic-gate ** 3814*7c478bd9Sstevel@tonic-gate ** Returns: 3815*7c478bd9Sstevel@tonic-gate ** none. 3816*7c478bd9Sstevel@tonic-gate */ 3817*7c478bd9Sstevel@tonic-gate 3818*7c478bd9Sstevel@tonic-gate static void 3819*7c478bd9Sstevel@tonic-gate mail_esmtp_args(kp, vp, e) 3820*7c478bd9Sstevel@tonic-gate char *kp; 3821*7c478bd9Sstevel@tonic-gate char *vp; 3822*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 3823*7c478bd9Sstevel@tonic-gate { 3824*7c478bd9Sstevel@tonic-gate if (sm_strcasecmp(kp, "size") == 0) 3825*7c478bd9Sstevel@tonic-gate { 3826*7c478bd9Sstevel@tonic-gate if (vp == NULL) 3827*7c478bd9Sstevel@tonic-gate { 3828*7c478bd9Sstevel@tonic-gate usrerr("501 5.5.2 SIZE requires a value"); 3829*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3830*7c478bd9Sstevel@tonic-gate } 3831*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP, macid("{msg_size}"), vp); 3832*7c478bd9Sstevel@tonic-gate errno = 0; 3833*7c478bd9Sstevel@tonic-gate e->e_msgsize = strtol(vp, (char **) NULL, 10); 3834*7c478bd9Sstevel@tonic-gate if (e->e_msgsize == LONG_MAX && errno == ERANGE) 3835*7c478bd9Sstevel@tonic-gate { 3836*7c478bd9Sstevel@tonic-gate usrerr("552 5.2.3 Message size exceeds maximum value"); 3837*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3838*7c478bd9Sstevel@tonic-gate } 3839*7c478bd9Sstevel@tonic-gate if (e->e_msgsize < 0) 3840*7c478bd9Sstevel@tonic-gate { 3841*7c478bd9Sstevel@tonic-gate usrerr("552 5.2.3 Message size invalid"); 3842*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3843*7c478bd9Sstevel@tonic-gate } 3844*7c478bd9Sstevel@tonic-gate } 3845*7c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(kp, "body") == 0) 3846*7c478bd9Sstevel@tonic-gate { 3847*7c478bd9Sstevel@tonic-gate if (vp == NULL) 3848*7c478bd9Sstevel@tonic-gate { 3849*7c478bd9Sstevel@tonic-gate usrerr("501 5.5.2 BODY requires a value"); 3850*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3851*7c478bd9Sstevel@tonic-gate } 3852*7c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(vp, "8bitmime") == 0) 3853*7c478bd9Sstevel@tonic-gate { 3854*7c478bd9Sstevel@tonic-gate SevenBitInput = false; 3855*7c478bd9Sstevel@tonic-gate } 3856*7c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(vp, "7bit") == 0) 3857*7c478bd9Sstevel@tonic-gate { 3858*7c478bd9Sstevel@tonic-gate SevenBitInput = true; 3859*7c478bd9Sstevel@tonic-gate } 3860*7c478bd9Sstevel@tonic-gate else 3861*7c478bd9Sstevel@tonic-gate { 3862*7c478bd9Sstevel@tonic-gate usrerr("501 5.5.4 Unknown BODY type %s", vp); 3863*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3864*7c478bd9Sstevel@tonic-gate } 3865*7c478bd9Sstevel@tonic-gate e->e_bodytype = sm_rpool_strdup_x(e->e_rpool, vp); 3866*7c478bd9Sstevel@tonic-gate } 3867*7c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(kp, "envid") == 0) 3868*7c478bd9Sstevel@tonic-gate { 3869*7c478bd9Sstevel@tonic-gate if (bitset(PRIV_NORECEIPTS, PrivacyFlags)) 3870*7c478bd9Sstevel@tonic-gate { 3871*7c478bd9Sstevel@tonic-gate usrerr("504 5.7.0 Sorry, ENVID not supported, we do not allow DSN"); 3872*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3873*7c478bd9Sstevel@tonic-gate } 3874*7c478bd9Sstevel@tonic-gate if (vp == NULL) 3875*7c478bd9Sstevel@tonic-gate { 3876*7c478bd9Sstevel@tonic-gate usrerr("501 5.5.2 ENVID requires a value"); 3877*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3878*7c478bd9Sstevel@tonic-gate } 3879*7c478bd9Sstevel@tonic-gate if (!xtextok(vp)) 3880*7c478bd9Sstevel@tonic-gate { 3881*7c478bd9Sstevel@tonic-gate usrerr("501 5.5.4 Syntax error in ENVID parameter value"); 3882*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3883*7c478bd9Sstevel@tonic-gate } 3884*7c478bd9Sstevel@tonic-gate if (e->e_envid != NULL) 3885*7c478bd9Sstevel@tonic-gate { 3886*7c478bd9Sstevel@tonic-gate usrerr("501 5.5.0 Duplicate ENVID parameter"); 3887*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3888*7c478bd9Sstevel@tonic-gate } 3889*7c478bd9Sstevel@tonic-gate e->e_envid = sm_rpool_strdup_x(e->e_rpool, vp); 3890*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 3891*7c478bd9Sstevel@tonic-gate macid("{dsn_envid}"), e->e_envid); 3892*7c478bd9Sstevel@tonic-gate } 3893*7c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(kp, "ret") == 0) 3894*7c478bd9Sstevel@tonic-gate { 3895*7c478bd9Sstevel@tonic-gate if (bitset(PRIV_NORECEIPTS, PrivacyFlags)) 3896*7c478bd9Sstevel@tonic-gate { 3897*7c478bd9Sstevel@tonic-gate usrerr("504 5.7.0 Sorry, RET not supported, we do not allow DSN"); 3898*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3899*7c478bd9Sstevel@tonic-gate } 3900*7c478bd9Sstevel@tonic-gate if (vp == NULL) 3901*7c478bd9Sstevel@tonic-gate { 3902*7c478bd9Sstevel@tonic-gate usrerr("501 5.5.2 RET requires a value"); 3903*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3904*7c478bd9Sstevel@tonic-gate } 3905*7c478bd9Sstevel@tonic-gate if (bitset(EF_RET_PARAM, e->e_flags)) 3906*7c478bd9Sstevel@tonic-gate { 3907*7c478bd9Sstevel@tonic-gate usrerr("501 5.5.0 Duplicate RET parameter"); 3908*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3909*7c478bd9Sstevel@tonic-gate } 3910*7c478bd9Sstevel@tonic-gate e->e_flags |= EF_RET_PARAM; 3911*7c478bd9Sstevel@tonic-gate if (sm_strcasecmp(vp, "hdrs") == 0) 3912*7c478bd9Sstevel@tonic-gate e->e_flags |= EF_NO_BODY_RETN; 3913*7c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(vp, "full") != 0) 3914*7c478bd9Sstevel@tonic-gate { 3915*7c478bd9Sstevel@tonic-gate usrerr("501 5.5.2 Bad argument \"%s\" to RET", vp); 3916*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3917*7c478bd9Sstevel@tonic-gate } 3918*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP, macid("{dsn_ret}"), vp); 3919*7c478bd9Sstevel@tonic-gate } 3920*7c478bd9Sstevel@tonic-gate #if SASL 3921*7c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(kp, "auth") == 0) 3922*7c478bd9Sstevel@tonic-gate { 3923*7c478bd9Sstevel@tonic-gate int len; 3924*7c478bd9Sstevel@tonic-gate char *q; 3925*7c478bd9Sstevel@tonic-gate char *auth_param; /* the value of the AUTH=x */ 3926*7c478bd9Sstevel@tonic-gate bool saveQuickAbort = QuickAbort; 3927*7c478bd9Sstevel@tonic-gate bool saveSuprErrs = SuprErrs; 3928*7c478bd9Sstevel@tonic-gate bool saveExitStat = ExitStat; 3929*7c478bd9Sstevel@tonic-gate 3930*7c478bd9Sstevel@tonic-gate if (vp == NULL) 3931*7c478bd9Sstevel@tonic-gate { 3932*7c478bd9Sstevel@tonic-gate usrerr("501 5.5.2 AUTH= requires a value"); 3933*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3934*7c478bd9Sstevel@tonic-gate } 3935*7c478bd9Sstevel@tonic-gate if (e->e_auth_param != NULL) 3936*7c478bd9Sstevel@tonic-gate { 3937*7c478bd9Sstevel@tonic-gate usrerr("501 5.5.0 Duplicate AUTH parameter"); 3938*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3939*7c478bd9Sstevel@tonic-gate } 3940*7c478bd9Sstevel@tonic-gate if ((q = strchr(vp, ' ')) != NULL) 3941*7c478bd9Sstevel@tonic-gate len = q - vp + 1; 3942*7c478bd9Sstevel@tonic-gate else 3943*7c478bd9Sstevel@tonic-gate len = strlen(vp) + 1; 3944*7c478bd9Sstevel@tonic-gate auth_param = xalloc(len); 3945*7c478bd9Sstevel@tonic-gate (void) sm_strlcpy(auth_param, vp, len); 3946*7c478bd9Sstevel@tonic-gate if (!xtextok(auth_param)) 3947*7c478bd9Sstevel@tonic-gate { 3948*7c478bd9Sstevel@tonic-gate usrerr("501 5.5.4 Syntax error in AUTH parameter value"); 3949*7c478bd9Sstevel@tonic-gate /* just a warning? */ 3950*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 3951*7c478bd9Sstevel@tonic-gate } 3952*7c478bd9Sstevel@tonic-gate 3953*7c478bd9Sstevel@tonic-gate /* XXX define this always or only if trusted? */ 3954*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP, macid("{auth_author}"), 3955*7c478bd9Sstevel@tonic-gate auth_param); 3956*7c478bd9Sstevel@tonic-gate 3957*7c478bd9Sstevel@tonic-gate /* 3958*7c478bd9Sstevel@tonic-gate ** call Strust_auth to find out whether 3959*7c478bd9Sstevel@tonic-gate ** auth_param is acceptable (trusted) 3960*7c478bd9Sstevel@tonic-gate ** we shouldn't trust it if not authenticated 3961*7c478bd9Sstevel@tonic-gate ** (required by RFC, leave it to ruleset?) 3962*7c478bd9Sstevel@tonic-gate */ 3963*7c478bd9Sstevel@tonic-gate 3964*7c478bd9Sstevel@tonic-gate SuprErrs = true; 3965*7c478bd9Sstevel@tonic-gate QuickAbort = false; 3966*7c478bd9Sstevel@tonic-gate if (strcmp(auth_param, "<>") != 0 && 3967*7c478bd9Sstevel@tonic-gate (rscheck("trust_auth", auth_param, NULL, e, RSF_RMCOMM, 3968*7c478bd9Sstevel@tonic-gate 9, NULL, NOQID) != EX_OK || Errors > 0)) 3969*7c478bd9Sstevel@tonic-gate { 3970*7c478bd9Sstevel@tonic-gate if (tTd(95, 8)) 3971*7c478bd9Sstevel@tonic-gate { 3972*7c478bd9Sstevel@tonic-gate q = e->e_auth_param; 3973*7c478bd9Sstevel@tonic-gate sm_dprintf("auth=\"%.100s\" not trusted user=\"%.100s\"\n", 3974*7c478bd9Sstevel@tonic-gate auth_param, (q == NULL) ? "" : q); 3975*7c478bd9Sstevel@tonic-gate } 3976*7c478bd9Sstevel@tonic-gate 3977*7c478bd9Sstevel@tonic-gate /* not trusted */ 3978*7c478bd9Sstevel@tonic-gate e->e_auth_param = "<>"; 3979*7c478bd9Sstevel@tonic-gate # if _FFR_AUTH_PASSING 3980*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_PERM, 3981*7c478bd9Sstevel@tonic-gate macid("{auth_author}"), NULL); 3982*7c478bd9Sstevel@tonic-gate # endif /* _FFR_AUTH_PASSING */ 3983*7c478bd9Sstevel@tonic-gate } 3984*7c478bd9Sstevel@tonic-gate else 3985*7c478bd9Sstevel@tonic-gate { 3986*7c478bd9Sstevel@tonic-gate if (tTd(95, 8)) 3987*7c478bd9Sstevel@tonic-gate sm_dprintf("auth=\"%.100s\" trusted\n", auth_param); 3988*7c478bd9Sstevel@tonic-gate e->e_auth_param = sm_rpool_strdup_x(e->e_rpool, 3989*7c478bd9Sstevel@tonic-gate auth_param); 3990*7c478bd9Sstevel@tonic-gate } 3991*7c478bd9Sstevel@tonic-gate sm_free(auth_param); /* XXX */ 3992*7c478bd9Sstevel@tonic-gate 3993*7c478bd9Sstevel@tonic-gate /* reset values */ 3994*7c478bd9Sstevel@tonic-gate Errors = 0; 3995*7c478bd9Sstevel@tonic-gate QuickAbort = saveQuickAbort; 3996*7c478bd9Sstevel@tonic-gate SuprErrs = saveSuprErrs; 3997*7c478bd9Sstevel@tonic-gate ExitStat = saveExitStat; 3998*7c478bd9Sstevel@tonic-gate } 3999*7c478bd9Sstevel@tonic-gate #endif /* SASL */ 4000*7c478bd9Sstevel@tonic-gate #define PRTCHAR(c) ((isascii(c) && isprint(c)) ? (c) : '?') 4001*7c478bd9Sstevel@tonic-gate 4002*7c478bd9Sstevel@tonic-gate /* 4003*7c478bd9Sstevel@tonic-gate ** "by" is only accepted if DeliverByMin >= 0. 4004*7c478bd9Sstevel@tonic-gate ** We maybe could add this to the list of server_features. 4005*7c478bd9Sstevel@tonic-gate */ 4006*7c478bd9Sstevel@tonic-gate 4007*7c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(kp, "by") == 0 && DeliverByMin >= 0) 4008*7c478bd9Sstevel@tonic-gate { 4009*7c478bd9Sstevel@tonic-gate char *s; 4010*7c478bd9Sstevel@tonic-gate 4011*7c478bd9Sstevel@tonic-gate if (vp == NULL) 4012*7c478bd9Sstevel@tonic-gate { 4013*7c478bd9Sstevel@tonic-gate usrerr("501 5.5.2 BY= requires a value"); 4014*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4015*7c478bd9Sstevel@tonic-gate } 4016*7c478bd9Sstevel@tonic-gate errno = 0; 4017*7c478bd9Sstevel@tonic-gate e->e_deliver_by = strtol(vp, &s, 10); 4018*7c478bd9Sstevel@tonic-gate if (e->e_deliver_by == LONG_MIN || 4019*7c478bd9Sstevel@tonic-gate e->e_deliver_by == LONG_MAX || 4020*7c478bd9Sstevel@tonic-gate e->e_deliver_by > 999999999l || 4021*7c478bd9Sstevel@tonic-gate e->e_deliver_by < -999999999l) 4022*7c478bd9Sstevel@tonic-gate { 4023*7c478bd9Sstevel@tonic-gate usrerr("501 5.5.2 BY=%s out of range", vp); 4024*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4025*7c478bd9Sstevel@tonic-gate } 4026*7c478bd9Sstevel@tonic-gate if (s == NULL || *s != ';') 4027*7c478bd9Sstevel@tonic-gate { 4028*7c478bd9Sstevel@tonic-gate usrerr("501 5.5.2 BY= missing ';'"); 4029*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4030*7c478bd9Sstevel@tonic-gate } 4031*7c478bd9Sstevel@tonic-gate e->e_dlvr_flag = 0; 4032*7c478bd9Sstevel@tonic-gate ++s; /* XXX: spaces allowed? */ 4033*7c478bd9Sstevel@tonic-gate SKIP_SPACE(s); 4034*7c478bd9Sstevel@tonic-gate switch (tolower(*s)) 4035*7c478bd9Sstevel@tonic-gate { 4036*7c478bd9Sstevel@tonic-gate case 'n': 4037*7c478bd9Sstevel@tonic-gate e->e_dlvr_flag = DLVR_NOTIFY; 4038*7c478bd9Sstevel@tonic-gate break; 4039*7c478bd9Sstevel@tonic-gate case 'r': 4040*7c478bd9Sstevel@tonic-gate e->e_dlvr_flag = DLVR_RETURN; 4041*7c478bd9Sstevel@tonic-gate if (e->e_deliver_by <= 0) 4042*7c478bd9Sstevel@tonic-gate { 4043*7c478bd9Sstevel@tonic-gate usrerr("501 5.5.4 mode R requires BY time > 0"); 4044*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4045*7c478bd9Sstevel@tonic-gate } 4046*7c478bd9Sstevel@tonic-gate if (DeliverByMin > 0 && e->e_deliver_by > 0 && 4047*7c478bd9Sstevel@tonic-gate e->e_deliver_by < DeliverByMin) 4048*7c478bd9Sstevel@tonic-gate { 4049*7c478bd9Sstevel@tonic-gate usrerr("555 5.5.2 time %ld less than %ld", 4050*7c478bd9Sstevel@tonic-gate e->e_deliver_by, (long) DeliverByMin); 4051*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4052*7c478bd9Sstevel@tonic-gate } 4053*7c478bd9Sstevel@tonic-gate break; 4054*7c478bd9Sstevel@tonic-gate default: 4055*7c478bd9Sstevel@tonic-gate usrerr("501 5.5.2 illegal by-mode '%c'", PRTCHAR(*s)); 4056*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4057*7c478bd9Sstevel@tonic-gate } 4058*7c478bd9Sstevel@tonic-gate ++s; /* XXX: spaces allowed? */ 4059*7c478bd9Sstevel@tonic-gate SKIP_SPACE(s); 4060*7c478bd9Sstevel@tonic-gate switch (tolower(*s)) 4061*7c478bd9Sstevel@tonic-gate { 4062*7c478bd9Sstevel@tonic-gate case 't': 4063*7c478bd9Sstevel@tonic-gate e->e_dlvr_flag |= DLVR_TRACE; 4064*7c478bd9Sstevel@tonic-gate break; 4065*7c478bd9Sstevel@tonic-gate case '\0': 4066*7c478bd9Sstevel@tonic-gate break; 4067*7c478bd9Sstevel@tonic-gate default: 4068*7c478bd9Sstevel@tonic-gate usrerr("501 5.5.2 illegal by-trace '%c'", PRTCHAR(*s)); 4069*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4070*7c478bd9Sstevel@tonic-gate } 4071*7c478bd9Sstevel@tonic-gate 4072*7c478bd9Sstevel@tonic-gate /* XXX: check whether more characters follow? */ 4073*7c478bd9Sstevel@tonic-gate } 4074*7c478bd9Sstevel@tonic-gate else 4075*7c478bd9Sstevel@tonic-gate { 4076*7c478bd9Sstevel@tonic-gate usrerr("555 5.5.4 %s parameter unrecognized", kp); 4077*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4078*7c478bd9Sstevel@tonic-gate } 4079*7c478bd9Sstevel@tonic-gate } 4080*7c478bd9Sstevel@tonic-gate /* 4081*7c478bd9Sstevel@tonic-gate ** RCPT_ESMTP_ARGS -- process ESMTP arguments from RCPT line 4082*7c478bd9Sstevel@tonic-gate ** 4083*7c478bd9Sstevel@tonic-gate ** Parameters: 4084*7c478bd9Sstevel@tonic-gate ** a -- the address corresponding to the To: parameter. 4085*7c478bd9Sstevel@tonic-gate ** kp -- the parameter key. 4086*7c478bd9Sstevel@tonic-gate ** vp -- the value of that parameter. 4087*7c478bd9Sstevel@tonic-gate ** e -- the envelope. 4088*7c478bd9Sstevel@tonic-gate ** 4089*7c478bd9Sstevel@tonic-gate ** Returns: 4090*7c478bd9Sstevel@tonic-gate ** none. 4091*7c478bd9Sstevel@tonic-gate */ 4092*7c478bd9Sstevel@tonic-gate 4093*7c478bd9Sstevel@tonic-gate static void 4094*7c478bd9Sstevel@tonic-gate rcpt_esmtp_args(a, kp, vp, e) 4095*7c478bd9Sstevel@tonic-gate ADDRESS *a; 4096*7c478bd9Sstevel@tonic-gate char *kp; 4097*7c478bd9Sstevel@tonic-gate char *vp; 4098*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 4099*7c478bd9Sstevel@tonic-gate { 4100*7c478bd9Sstevel@tonic-gate if (sm_strcasecmp(kp, "notify") == 0) 4101*7c478bd9Sstevel@tonic-gate { 4102*7c478bd9Sstevel@tonic-gate char *p; 4103*7c478bd9Sstevel@tonic-gate 4104*7c478bd9Sstevel@tonic-gate if (bitset(PRIV_NORECEIPTS, PrivacyFlags)) 4105*7c478bd9Sstevel@tonic-gate { 4106*7c478bd9Sstevel@tonic-gate usrerr("504 5.7.0 Sorry, NOTIFY not supported, we do not allow DSN"); 4107*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4108*7c478bd9Sstevel@tonic-gate } 4109*7c478bd9Sstevel@tonic-gate if (vp == NULL) 4110*7c478bd9Sstevel@tonic-gate { 4111*7c478bd9Sstevel@tonic-gate usrerr("501 5.5.2 NOTIFY requires a value"); 4112*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4113*7c478bd9Sstevel@tonic-gate } 4114*7c478bd9Sstevel@tonic-gate a->q_flags &= ~(QPINGONSUCCESS|QPINGONFAILURE|QPINGONDELAY); 4115*7c478bd9Sstevel@tonic-gate a->q_flags |= QHASNOTIFY; 4116*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_TEMP, macid("{dsn_notify}"), vp); 4117*7c478bd9Sstevel@tonic-gate 4118*7c478bd9Sstevel@tonic-gate if (sm_strcasecmp(vp, "never") == 0) 4119*7c478bd9Sstevel@tonic-gate return; 4120*7c478bd9Sstevel@tonic-gate for (p = vp; p != NULL; vp = p) 4121*7c478bd9Sstevel@tonic-gate { 4122*7c478bd9Sstevel@tonic-gate char *s; 4123*7c478bd9Sstevel@tonic-gate 4124*7c478bd9Sstevel@tonic-gate s = p = strchr(p, ','); 4125*7c478bd9Sstevel@tonic-gate if (p != NULL) 4126*7c478bd9Sstevel@tonic-gate *p++ = '\0'; 4127*7c478bd9Sstevel@tonic-gate if (sm_strcasecmp(vp, "success") == 0) 4128*7c478bd9Sstevel@tonic-gate a->q_flags |= QPINGONSUCCESS; 4129*7c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(vp, "failure") == 0) 4130*7c478bd9Sstevel@tonic-gate a->q_flags |= QPINGONFAILURE; 4131*7c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(vp, "delay") == 0) 4132*7c478bd9Sstevel@tonic-gate a->q_flags |= QPINGONDELAY; 4133*7c478bd9Sstevel@tonic-gate else 4134*7c478bd9Sstevel@tonic-gate { 4135*7c478bd9Sstevel@tonic-gate usrerr("501 5.5.4 Bad argument \"%s\" to NOTIFY", 4136*7c478bd9Sstevel@tonic-gate vp); 4137*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4138*7c478bd9Sstevel@tonic-gate } 4139*7c478bd9Sstevel@tonic-gate if (s != NULL) 4140*7c478bd9Sstevel@tonic-gate *s = ','; 4141*7c478bd9Sstevel@tonic-gate } 4142*7c478bd9Sstevel@tonic-gate } 4143*7c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(kp, "orcpt") == 0) 4144*7c478bd9Sstevel@tonic-gate { 4145*7c478bd9Sstevel@tonic-gate if (bitset(PRIV_NORECEIPTS, PrivacyFlags)) 4146*7c478bd9Sstevel@tonic-gate { 4147*7c478bd9Sstevel@tonic-gate usrerr("504 5.7.0 Sorry, ORCPT not supported, we do not allow DSN"); 4148*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4149*7c478bd9Sstevel@tonic-gate } 4150*7c478bd9Sstevel@tonic-gate if (vp == NULL) 4151*7c478bd9Sstevel@tonic-gate { 4152*7c478bd9Sstevel@tonic-gate usrerr("501 5.5.2 ORCPT requires a value"); 4153*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4154*7c478bd9Sstevel@tonic-gate } 4155*7c478bd9Sstevel@tonic-gate if (strchr(vp, ';') == NULL || !xtextok(vp)) 4156*7c478bd9Sstevel@tonic-gate { 4157*7c478bd9Sstevel@tonic-gate usrerr("501 5.5.4 Syntax error in ORCPT parameter value"); 4158*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4159*7c478bd9Sstevel@tonic-gate } 4160*7c478bd9Sstevel@tonic-gate if (a->q_orcpt != NULL) 4161*7c478bd9Sstevel@tonic-gate { 4162*7c478bd9Sstevel@tonic-gate usrerr("501 5.5.0 Duplicate ORCPT parameter"); 4163*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4164*7c478bd9Sstevel@tonic-gate } 4165*7c478bd9Sstevel@tonic-gate a->q_orcpt = sm_rpool_strdup_x(e->e_rpool, vp); 4166*7c478bd9Sstevel@tonic-gate } 4167*7c478bd9Sstevel@tonic-gate else 4168*7c478bd9Sstevel@tonic-gate { 4169*7c478bd9Sstevel@tonic-gate usrerr("555 5.5.4 %s parameter unrecognized", kp); 4170*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 4171*7c478bd9Sstevel@tonic-gate } 4172*7c478bd9Sstevel@tonic-gate } 4173*7c478bd9Sstevel@tonic-gate /* 4174*7c478bd9Sstevel@tonic-gate ** PRINTVRFYADDR -- print an entry in the verify queue 4175*7c478bd9Sstevel@tonic-gate ** 4176*7c478bd9Sstevel@tonic-gate ** Parameters: 4177*7c478bd9Sstevel@tonic-gate ** a -- the address to print. 4178*7c478bd9Sstevel@tonic-gate ** last -- set if this is the last one. 4179*7c478bd9Sstevel@tonic-gate ** vrfy -- set if this is a VRFY command. 4180*7c478bd9Sstevel@tonic-gate ** 4181*7c478bd9Sstevel@tonic-gate ** Returns: 4182*7c478bd9Sstevel@tonic-gate ** none. 4183*7c478bd9Sstevel@tonic-gate ** 4184*7c478bd9Sstevel@tonic-gate ** Side Effects: 4185*7c478bd9Sstevel@tonic-gate ** Prints the appropriate 250 codes. 4186*7c478bd9Sstevel@tonic-gate */ 4187*7c478bd9Sstevel@tonic-gate #define OFFF (3 + 1 + 5 + 1) /* offset in fmt: SMTP reply + enh. code */ 4188*7c478bd9Sstevel@tonic-gate 4189*7c478bd9Sstevel@tonic-gate static void 4190*7c478bd9Sstevel@tonic-gate printvrfyaddr(a, last, vrfy) 4191*7c478bd9Sstevel@tonic-gate register ADDRESS *a; 4192*7c478bd9Sstevel@tonic-gate bool last; 4193*7c478bd9Sstevel@tonic-gate bool vrfy; 4194*7c478bd9Sstevel@tonic-gate { 4195*7c478bd9Sstevel@tonic-gate char fmtbuf[30]; 4196*7c478bd9Sstevel@tonic-gate 4197*7c478bd9Sstevel@tonic-gate if (vrfy && a->q_mailer != NULL && 4198*7c478bd9Sstevel@tonic-gate !bitnset(M_VRFY250, a->q_mailer->m_flags)) 4199*7c478bd9Sstevel@tonic-gate (void) sm_strlcpy(fmtbuf, "252", sizeof fmtbuf); 4200*7c478bd9Sstevel@tonic-gate else 4201*7c478bd9Sstevel@tonic-gate (void) sm_strlcpy(fmtbuf, "250", sizeof fmtbuf); 4202*7c478bd9Sstevel@tonic-gate fmtbuf[3] = last ? ' ' : '-'; 4203*7c478bd9Sstevel@tonic-gate (void) sm_strlcpy(&fmtbuf[4], "2.1.5 ", sizeof fmtbuf - 4); 4204*7c478bd9Sstevel@tonic-gate if (a->q_fullname == NULL) 4205*7c478bd9Sstevel@tonic-gate { 4206*7c478bd9Sstevel@tonic-gate if ((a->q_mailer == NULL || 4207*7c478bd9Sstevel@tonic-gate a->q_mailer->m_addrtype == NULL || 4208*7c478bd9Sstevel@tonic-gate sm_strcasecmp(a->q_mailer->m_addrtype, "rfc822") == 0) && 4209*7c478bd9Sstevel@tonic-gate strchr(a->q_user, '@') == NULL) 4210*7c478bd9Sstevel@tonic-gate (void) sm_strlcpy(&fmtbuf[OFFF], "<%s@%s>", 4211*7c478bd9Sstevel@tonic-gate sizeof fmtbuf - OFFF); 4212*7c478bd9Sstevel@tonic-gate else 4213*7c478bd9Sstevel@tonic-gate (void) sm_strlcpy(&fmtbuf[OFFF], "<%s>", 4214*7c478bd9Sstevel@tonic-gate sizeof fmtbuf - OFFF); 4215*7c478bd9Sstevel@tonic-gate message(fmtbuf, a->q_user, MyHostName); 4216*7c478bd9Sstevel@tonic-gate } 4217*7c478bd9Sstevel@tonic-gate else 4218*7c478bd9Sstevel@tonic-gate { 4219*7c478bd9Sstevel@tonic-gate if ((a->q_mailer == NULL || 4220*7c478bd9Sstevel@tonic-gate a->q_mailer->m_addrtype == NULL || 4221*7c478bd9Sstevel@tonic-gate sm_strcasecmp(a->q_mailer->m_addrtype, "rfc822") == 0) && 4222*7c478bd9Sstevel@tonic-gate strchr(a->q_user, '@') == NULL) 4223*7c478bd9Sstevel@tonic-gate (void) sm_strlcpy(&fmtbuf[OFFF], "%s <%s@%s>", 4224*7c478bd9Sstevel@tonic-gate sizeof fmtbuf - OFFF); 4225*7c478bd9Sstevel@tonic-gate else 4226*7c478bd9Sstevel@tonic-gate (void) sm_strlcpy(&fmtbuf[OFFF], "%s <%s>", 4227*7c478bd9Sstevel@tonic-gate sizeof fmtbuf - OFFF); 4228*7c478bd9Sstevel@tonic-gate message(fmtbuf, a->q_fullname, a->q_user, MyHostName); 4229*7c478bd9Sstevel@tonic-gate } 4230*7c478bd9Sstevel@tonic-gate } 4231*7c478bd9Sstevel@tonic-gate 4232*7c478bd9Sstevel@tonic-gate #if SASL 4233*7c478bd9Sstevel@tonic-gate /* 4234*7c478bd9Sstevel@tonic-gate ** SASLMECHS -- get list of possible AUTH mechanisms 4235*7c478bd9Sstevel@tonic-gate ** 4236*7c478bd9Sstevel@tonic-gate ** Parameters: 4237*7c478bd9Sstevel@tonic-gate ** conn -- SASL connection info. 4238*7c478bd9Sstevel@tonic-gate ** mechlist -- output parameter for list of mechanisms. 4239*7c478bd9Sstevel@tonic-gate ** 4240*7c478bd9Sstevel@tonic-gate ** Returns: 4241*7c478bd9Sstevel@tonic-gate ** number of mechs. 4242*7c478bd9Sstevel@tonic-gate */ 4243*7c478bd9Sstevel@tonic-gate 4244*7c478bd9Sstevel@tonic-gate static int 4245*7c478bd9Sstevel@tonic-gate saslmechs(conn, mechlist) 4246*7c478bd9Sstevel@tonic-gate sasl_conn_t *conn; 4247*7c478bd9Sstevel@tonic-gate char **mechlist; 4248*7c478bd9Sstevel@tonic-gate { 4249*7c478bd9Sstevel@tonic-gate int len, num, result; 4250*7c478bd9Sstevel@tonic-gate 4251*7c478bd9Sstevel@tonic-gate /* "user" is currently unused */ 4252*7c478bd9Sstevel@tonic-gate # if SASL >= 20000 4253*7c478bd9Sstevel@tonic-gate result = sasl_listmech(conn, NULL, 4254*7c478bd9Sstevel@tonic-gate "", " ", "", (const char **) mechlist, 4255*7c478bd9Sstevel@tonic-gate (unsigned int *)&len, &num); 4256*7c478bd9Sstevel@tonic-gate # else /* SASL >= 20000 */ 4257*7c478bd9Sstevel@tonic-gate result = sasl_listmech(conn, "user", /* XXX */ 4258*7c478bd9Sstevel@tonic-gate "", " ", "", mechlist, 4259*7c478bd9Sstevel@tonic-gate (unsigned int *)&len, (unsigned int *)&num); 4260*7c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */ 4261*7c478bd9Sstevel@tonic-gate if (result != SASL_OK) 4262*7c478bd9Sstevel@tonic-gate { 4263*7c478bd9Sstevel@tonic-gate if (LogLevel > 9) 4264*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID, 4265*7c478bd9Sstevel@tonic-gate "AUTH error: listmech=%d, num=%d", 4266*7c478bd9Sstevel@tonic-gate result, num); 4267*7c478bd9Sstevel@tonic-gate num = 0; 4268*7c478bd9Sstevel@tonic-gate } 4269*7c478bd9Sstevel@tonic-gate if (num > 0) 4270*7c478bd9Sstevel@tonic-gate { 4271*7c478bd9Sstevel@tonic-gate if (LogLevel > 11) 4272*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, NOQID, 4273*7c478bd9Sstevel@tonic-gate "AUTH: available mech=%s, allowed mech=%s", 4274*7c478bd9Sstevel@tonic-gate *mechlist, AuthMechanisms); 4275*7c478bd9Sstevel@tonic-gate *mechlist = intersect(AuthMechanisms, *mechlist, NULL); 4276*7c478bd9Sstevel@tonic-gate } 4277*7c478bd9Sstevel@tonic-gate else 4278*7c478bd9Sstevel@tonic-gate { 4279*7c478bd9Sstevel@tonic-gate *mechlist = NULL; /* be paranoid... */ 4280*7c478bd9Sstevel@tonic-gate if (result == SASL_OK && LogLevel > 9) 4281*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, NOQID, 4282*7c478bd9Sstevel@tonic-gate "AUTH warning: no mechanisms"); 4283*7c478bd9Sstevel@tonic-gate } 4284*7c478bd9Sstevel@tonic-gate return num; 4285*7c478bd9Sstevel@tonic-gate } 4286*7c478bd9Sstevel@tonic-gate 4287*7c478bd9Sstevel@tonic-gate # if SASL >= 20000 4288*7c478bd9Sstevel@tonic-gate /* 4289*7c478bd9Sstevel@tonic-gate ** PROXY_POLICY -- define proxy policy for AUTH 4290*7c478bd9Sstevel@tonic-gate ** 4291*7c478bd9Sstevel@tonic-gate ** Parameters: 4292*7c478bd9Sstevel@tonic-gate ** conn -- unused. 4293*7c478bd9Sstevel@tonic-gate ** context -- unused. 4294*7c478bd9Sstevel@tonic-gate ** requested_user -- authorization identity. 4295*7c478bd9Sstevel@tonic-gate ** rlen -- authorization identity length. 4296*7c478bd9Sstevel@tonic-gate ** auth_identity -- authentication identity. 4297*7c478bd9Sstevel@tonic-gate ** alen -- authentication identity length. 4298*7c478bd9Sstevel@tonic-gate ** def_realm -- default user realm. 4299*7c478bd9Sstevel@tonic-gate ** urlen -- user realm length. 4300*7c478bd9Sstevel@tonic-gate ** propctx -- unused. 4301*7c478bd9Sstevel@tonic-gate ** 4302*7c478bd9Sstevel@tonic-gate ** Returns: 4303*7c478bd9Sstevel@tonic-gate ** ok? 4304*7c478bd9Sstevel@tonic-gate ** 4305*7c478bd9Sstevel@tonic-gate ** Side Effects: 4306*7c478bd9Sstevel@tonic-gate ** sets {auth_authen} macro. 4307*7c478bd9Sstevel@tonic-gate */ 4308*7c478bd9Sstevel@tonic-gate 4309*7c478bd9Sstevel@tonic-gate int 4310*7c478bd9Sstevel@tonic-gate proxy_policy(conn, context, requested_user, rlen, auth_identity, alen, 4311*7c478bd9Sstevel@tonic-gate def_realm, urlen, propctx) 4312*7c478bd9Sstevel@tonic-gate sasl_conn_t *conn; 4313*7c478bd9Sstevel@tonic-gate void *context; 4314*7c478bd9Sstevel@tonic-gate const char *requested_user; 4315*7c478bd9Sstevel@tonic-gate unsigned rlen; 4316*7c478bd9Sstevel@tonic-gate const char *auth_identity; 4317*7c478bd9Sstevel@tonic-gate unsigned alen; 4318*7c478bd9Sstevel@tonic-gate const char *def_realm; 4319*7c478bd9Sstevel@tonic-gate unsigned urlen; 4320*7c478bd9Sstevel@tonic-gate struct propctx *propctx; 4321*7c478bd9Sstevel@tonic-gate { 4322*7c478bd9Sstevel@tonic-gate if (auth_identity == NULL) 4323*7c478bd9Sstevel@tonic-gate return SASL_FAIL; 4324*7c478bd9Sstevel@tonic-gate 4325*7c478bd9Sstevel@tonic-gate macdefine(&BlankEnvelope.e_macro, A_TEMP, 4326*7c478bd9Sstevel@tonic-gate macid("{auth_authen}"), (char *) auth_identity); 4327*7c478bd9Sstevel@tonic-gate 4328*7c478bd9Sstevel@tonic-gate return SASL_OK; 4329*7c478bd9Sstevel@tonic-gate } 4330*7c478bd9Sstevel@tonic-gate # else /* SASL >= 20000 */ 4331*7c478bd9Sstevel@tonic-gate 4332*7c478bd9Sstevel@tonic-gate /* 4333*7c478bd9Sstevel@tonic-gate ** PROXY_POLICY -- define proxy policy for AUTH 4334*7c478bd9Sstevel@tonic-gate ** 4335*7c478bd9Sstevel@tonic-gate ** Parameters: 4336*7c478bd9Sstevel@tonic-gate ** context -- unused. 4337*7c478bd9Sstevel@tonic-gate ** auth_identity -- authentication identity. 4338*7c478bd9Sstevel@tonic-gate ** requested_user -- authorization identity. 4339*7c478bd9Sstevel@tonic-gate ** user -- allowed user (output). 4340*7c478bd9Sstevel@tonic-gate ** errstr -- possible error string (output). 4341*7c478bd9Sstevel@tonic-gate ** 4342*7c478bd9Sstevel@tonic-gate ** Returns: 4343*7c478bd9Sstevel@tonic-gate ** ok? 4344*7c478bd9Sstevel@tonic-gate */ 4345*7c478bd9Sstevel@tonic-gate 4346*7c478bd9Sstevel@tonic-gate int 4347*7c478bd9Sstevel@tonic-gate proxy_policy(context, auth_identity, requested_user, user, errstr) 4348*7c478bd9Sstevel@tonic-gate void *context; 4349*7c478bd9Sstevel@tonic-gate const char *auth_identity; 4350*7c478bd9Sstevel@tonic-gate const char *requested_user; 4351*7c478bd9Sstevel@tonic-gate const char **user; 4352*7c478bd9Sstevel@tonic-gate const char **errstr; 4353*7c478bd9Sstevel@tonic-gate { 4354*7c478bd9Sstevel@tonic-gate if (user == NULL || auth_identity == NULL) 4355*7c478bd9Sstevel@tonic-gate return SASL_FAIL; 4356*7c478bd9Sstevel@tonic-gate *user = newstr(auth_identity); 4357*7c478bd9Sstevel@tonic-gate return SASL_OK; 4358*7c478bd9Sstevel@tonic-gate } 4359*7c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */ 4360*7c478bd9Sstevel@tonic-gate #endif /* SASL */ 4361*7c478bd9Sstevel@tonic-gate 4362*7c478bd9Sstevel@tonic-gate #if STARTTLS 4363*7c478bd9Sstevel@tonic-gate /* 4364*7c478bd9Sstevel@tonic-gate ** INITSRVTLS -- initialize server side TLS 4365*7c478bd9Sstevel@tonic-gate ** 4366*7c478bd9Sstevel@tonic-gate ** Parameters: 4367*7c478bd9Sstevel@tonic-gate ** tls_ok -- should tls initialization be done? 4368*7c478bd9Sstevel@tonic-gate ** 4369*7c478bd9Sstevel@tonic-gate ** Returns: 4370*7c478bd9Sstevel@tonic-gate ** succeeded? 4371*7c478bd9Sstevel@tonic-gate ** 4372*7c478bd9Sstevel@tonic-gate ** Side Effects: 4373*7c478bd9Sstevel@tonic-gate ** sets tls_ok_srv which is a static variable in this module. 4374*7c478bd9Sstevel@tonic-gate ** Do NOT remove assignments to it! 4375*7c478bd9Sstevel@tonic-gate */ 4376*7c478bd9Sstevel@tonic-gate 4377*7c478bd9Sstevel@tonic-gate bool 4378*7c478bd9Sstevel@tonic-gate initsrvtls(tls_ok) 4379*7c478bd9Sstevel@tonic-gate bool tls_ok; 4380*7c478bd9Sstevel@tonic-gate { 4381*7c478bd9Sstevel@tonic-gate if (!tls_ok) 4382*7c478bd9Sstevel@tonic-gate return false; 4383*7c478bd9Sstevel@tonic-gate 4384*7c478bd9Sstevel@tonic-gate /* do NOT remove assignment */ 4385*7c478bd9Sstevel@tonic-gate tls_ok_srv = inittls(&srv_ctx, TLS_Srv_Opts, true, SrvCertFile, 4386*7c478bd9Sstevel@tonic-gate SrvKeyFile, CACertPath, CACertFile, DHParams); 4387*7c478bd9Sstevel@tonic-gate return tls_ok_srv; 4388*7c478bd9Sstevel@tonic-gate } 4389*7c478bd9Sstevel@tonic-gate #endif /* STARTTLS */ 4390*7c478bd9Sstevel@tonic-gate /* 4391*7c478bd9Sstevel@tonic-gate ** SRVFEATURES -- get features for SMTP server 4392*7c478bd9Sstevel@tonic-gate ** 4393*7c478bd9Sstevel@tonic-gate ** Parameters: 4394*7c478bd9Sstevel@tonic-gate ** e -- envelope (should be session context). 4395*7c478bd9Sstevel@tonic-gate ** clientname -- name of client. 4396*7c478bd9Sstevel@tonic-gate ** features -- default features for this invocation. 4397*7c478bd9Sstevel@tonic-gate ** 4398*7c478bd9Sstevel@tonic-gate ** Returns: 4399*7c478bd9Sstevel@tonic-gate ** server features. 4400*7c478bd9Sstevel@tonic-gate */ 4401*7c478bd9Sstevel@tonic-gate 4402*7c478bd9Sstevel@tonic-gate /* table with options: it uses just one character, how about strings? */ 4403*7c478bd9Sstevel@tonic-gate static struct 4404*7c478bd9Sstevel@tonic-gate { 4405*7c478bd9Sstevel@tonic-gate char srvf_opt; 4406*7c478bd9Sstevel@tonic-gate unsigned int srvf_flag; 4407*7c478bd9Sstevel@tonic-gate } srv_feat_table[] = 4408*7c478bd9Sstevel@tonic-gate { 4409*7c478bd9Sstevel@tonic-gate { 'A', SRV_OFFER_AUTH }, 4410*7c478bd9Sstevel@tonic-gate { 'B', SRV_OFFER_VERB }, 4411*7c478bd9Sstevel@tonic-gate { 'C', SRV_REQ_SEC }, 4412*7c478bd9Sstevel@tonic-gate { 'D', SRV_OFFER_DSN }, 4413*7c478bd9Sstevel@tonic-gate { 'E', SRV_OFFER_ETRN }, 4414*7c478bd9Sstevel@tonic-gate { 'L', SRV_REQ_AUTH }, 4415*7c478bd9Sstevel@tonic-gate #if PIPELINING 4416*7c478bd9Sstevel@tonic-gate # if _FFR_NO_PIPE 4417*7c478bd9Sstevel@tonic-gate { 'N', SRV_NO_PIPE }, 4418*7c478bd9Sstevel@tonic-gate # endif /* _FFR_NO_PIPE */ 4419*7c478bd9Sstevel@tonic-gate { 'P', SRV_OFFER_PIPE }, 4420*7c478bd9Sstevel@tonic-gate #endif /* PIPELINING */ 4421*7c478bd9Sstevel@tonic-gate { 'R', SRV_VRFY_CLT }, /* same as V; not documented */ 4422*7c478bd9Sstevel@tonic-gate { 'S', SRV_OFFER_TLS }, 4423*7c478bd9Sstevel@tonic-gate /* { 'T', SRV_TMP_FAIL }, */ 4424*7c478bd9Sstevel@tonic-gate { 'V', SRV_VRFY_CLT }, 4425*7c478bd9Sstevel@tonic-gate { 'X', SRV_OFFER_EXPN }, 4426*7c478bd9Sstevel@tonic-gate /* { 'Y', SRV_OFFER_VRFY }, */ 4427*7c478bd9Sstevel@tonic-gate { '\0', SRV_NONE } 4428*7c478bd9Sstevel@tonic-gate }; 4429*7c478bd9Sstevel@tonic-gate 4430*7c478bd9Sstevel@tonic-gate static unsigned int 4431*7c478bd9Sstevel@tonic-gate srvfeatures(e, clientname, features) 4432*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 4433*7c478bd9Sstevel@tonic-gate char *clientname; 4434*7c478bd9Sstevel@tonic-gate unsigned int features; 4435*7c478bd9Sstevel@tonic-gate { 4436*7c478bd9Sstevel@tonic-gate int r, i, j; 4437*7c478bd9Sstevel@tonic-gate char **pvp, c, opt; 4438*7c478bd9Sstevel@tonic-gate char pvpbuf[PSBUFSIZE]; 4439*7c478bd9Sstevel@tonic-gate 4440*7c478bd9Sstevel@tonic-gate pvp = NULL; 4441*7c478bd9Sstevel@tonic-gate r = rscap("srv_features", clientname, "", e, &pvp, pvpbuf, 4442*7c478bd9Sstevel@tonic-gate sizeof(pvpbuf)); 4443*7c478bd9Sstevel@tonic-gate if (r != EX_OK) 4444*7c478bd9Sstevel@tonic-gate return features; 4445*7c478bd9Sstevel@tonic-gate if (pvp == NULL || pvp[0] == NULL || (pvp[0][0] & 0377) != CANONNET) 4446*7c478bd9Sstevel@tonic-gate return features; 4447*7c478bd9Sstevel@tonic-gate if (pvp[1] != NULL && sm_strncasecmp(pvp[1], "temp", 4) == 0) 4448*7c478bd9Sstevel@tonic-gate return SRV_TMP_FAIL; 4449*7c478bd9Sstevel@tonic-gate 4450*7c478bd9Sstevel@tonic-gate /* 4451*7c478bd9Sstevel@tonic-gate ** General rule (see sendmail.h, d_flags): 4452*7c478bd9Sstevel@tonic-gate ** lower case: required/offered, upper case: Not required/available 4453*7c478bd9Sstevel@tonic-gate ** 4454*7c478bd9Sstevel@tonic-gate ** Since we can change some features per daemon, we have both 4455*7c478bd9Sstevel@tonic-gate ** cases here: turn on/off a feature. 4456*7c478bd9Sstevel@tonic-gate */ 4457*7c478bd9Sstevel@tonic-gate 4458*7c478bd9Sstevel@tonic-gate for (i = 1; pvp[i] != NULL; i++) 4459*7c478bd9Sstevel@tonic-gate { 4460*7c478bd9Sstevel@tonic-gate c = pvp[i][0]; 4461*7c478bd9Sstevel@tonic-gate j = 0; 4462*7c478bd9Sstevel@tonic-gate for (;;) 4463*7c478bd9Sstevel@tonic-gate { 4464*7c478bd9Sstevel@tonic-gate if ((opt = srv_feat_table[j].srvf_opt) == '\0') 4465*7c478bd9Sstevel@tonic-gate { 4466*7c478bd9Sstevel@tonic-gate if (LogLevel > 9) 4467*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, e->e_id, 4468*7c478bd9Sstevel@tonic-gate "srvfeatures: unknown feature %s", 4469*7c478bd9Sstevel@tonic-gate pvp[i]); 4470*7c478bd9Sstevel@tonic-gate break; 4471*7c478bd9Sstevel@tonic-gate } 4472*7c478bd9Sstevel@tonic-gate if (c == opt) 4473*7c478bd9Sstevel@tonic-gate { 4474*7c478bd9Sstevel@tonic-gate features &= ~(srv_feat_table[j].srvf_flag); 4475*7c478bd9Sstevel@tonic-gate break; 4476*7c478bd9Sstevel@tonic-gate } 4477*7c478bd9Sstevel@tonic-gate if (c == tolower(opt)) 4478*7c478bd9Sstevel@tonic-gate { 4479*7c478bd9Sstevel@tonic-gate features |= srv_feat_table[j].srvf_flag; 4480*7c478bd9Sstevel@tonic-gate break; 4481*7c478bd9Sstevel@tonic-gate } 4482*7c478bd9Sstevel@tonic-gate ++j; 4483*7c478bd9Sstevel@tonic-gate } 4484*7c478bd9Sstevel@tonic-gate } 4485*7c478bd9Sstevel@tonic-gate return features; 4486*7c478bd9Sstevel@tonic-gate } 4487*7c478bd9Sstevel@tonic-gate 4488*7c478bd9Sstevel@tonic-gate /* 4489*7c478bd9Sstevel@tonic-gate ** HELP -- implement the HELP command. 4490*7c478bd9Sstevel@tonic-gate ** 4491*7c478bd9Sstevel@tonic-gate ** Parameters: 4492*7c478bd9Sstevel@tonic-gate ** topic -- the topic we want help for. 4493*7c478bd9Sstevel@tonic-gate ** e -- envelope. 4494*7c478bd9Sstevel@tonic-gate ** 4495*7c478bd9Sstevel@tonic-gate ** Returns: 4496*7c478bd9Sstevel@tonic-gate ** none. 4497*7c478bd9Sstevel@tonic-gate ** 4498*7c478bd9Sstevel@tonic-gate ** Side Effects: 4499*7c478bd9Sstevel@tonic-gate ** outputs the help file to message output. 4500*7c478bd9Sstevel@tonic-gate */ 4501*7c478bd9Sstevel@tonic-gate #define HELPVSTR "#vers " 4502*7c478bd9Sstevel@tonic-gate #define HELPVERSION 2 4503*7c478bd9Sstevel@tonic-gate 4504*7c478bd9Sstevel@tonic-gate void 4505*7c478bd9Sstevel@tonic-gate help(topic, e) 4506*7c478bd9Sstevel@tonic-gate char *topic; 4507*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 4508*7c478bd9Sstevel@tonic-gate { 4509*7c478bd9Sstevel@tonic-gate register SM_FILE_T *hf; 4510*7c478bd9Sstevel@tonic-gate register char *p; 4511*7c478bd9Sstevel@tonic-gate int len; 4512*7c478bd9Sstevel@tonic-gate bool noinfo; 4513*7c478bd9Sstevel@tonic-gate bool first = true; 4514*7c478bd9Sstevel@tonic-gate long sff = SFF_OPENASROOT|SFF_REGONLY; 4515*7c478bd9Sstevel@tonic-gate char buf[MAXLINE]; 4516*7c478bd9Sstevel@tonic-gate char inp[MAXLINE]; 4517*7c478bd9Sstevel@tonic-gate static int foundvers = -1; 4518*7c478bd9Sstevel@tonic-gate extern char Version[]; 4519*7c478bd9Sstevel@tonic-gate 4520*7c478bd9Sstevel@tonic-gate if (DontLockReadFiles) 4521*7c478bd9Sstevel@tonic-gate sff |= SFF_NOLOCK; 4522*7c478bd9Sstevel@tonic-gate if (!bitnset(DBS_HELPFILEINUNSAFEDIRPATH, DontBlameSendmail)) 4523*7c478bd9Sstevel@tonic-gate sff |= SFF_SAFEDIRPATH; 4524*7c478bd9Sstevel@tonic-gate 4525*7c478bd9Sstevel@tonic-gate if (HelpFile == NULL || 4526*7c478bd9Sstevel@tonic-gate (hf = safefopen(HelpFile, O_RDONLY, 0444, sff)) == NULL) 4527*7c478bd9Sstevel@tonic-gate { 4528*7c478bd9Sstevel@tonic-gate /* no help */ 4529*7c478bd9Sstevel@tonic-gate errno = 0; 4530*7c478bd9Sstevel@tonic-gate message("502 5.3.0 Sendmail %s -- HELP not implemented", 4531*7c478bd9Sstevel@tonic-gate Version); 4532*7c478bd9Sstevel@tonic-gate return; 4533*7c478bd9Sstevel@tonic-gate } 4534*7c478bd9Sstevel@tonic-gate 4535*7c478bd9Sstevel@tonic-gate if (topic == NULL || *topic == '\0') 4536*7c478bd9Sstevel@tonic-gate { 4537*7c478bd9Sstevel@tonic-gate topic = "smtp"; 4538*7c478bd9Sstevel@tonic-gate noinfo = false; 4539*7c478bd9Sstevel@tonic-gate } 4540*7c478bd9Sstevel@tonic-gate else 4541*7c478bd9Sstevel@tonic-gate { 4542*7c478bd9Sstevel@tonic-gate makelower(topic); 4543*7c478bd9Sstevel@tonic-gate noinfo = true; 4544*7c478bd9Sstevel@tonic-gate } 4545*7c478bd9Sstevel@tonic-gate 4546*7c478bd9Sstevel@tonic-gate len = strlen(topic); 4547*7c478bd9Sstevel@tonic-gate 4548*7c478bd9Sstevel@tonic-gate while (sm_io_fgets(hf, SM_TIME_DEFAULT, buf, sizeof buf) != NULL) 4549*7c478bd9Sstevel@tonic-gate { 4550*7c478bd9Sstevel@tonic-gate if (buf[0] == '#') 4551*7c478bd9Sstevel@tonic-gate { 4552*7c478bd9Sstevel@tonic-gate if (foundvers < 0 && 4553*7c478bd9Sstevel@tonic-gate strncmp(buf, HELPVSTR, strlen(HELPVSTR)) == 0) 4554*7c478bd9Sstevel@tonic-gate { 4555*7c478bd9Sstevel@tonic-gate int h; 4556*7c478bd9Sstevel@tonic-gate 4557*7c478bd9Sstevel@tonic-gate if (sm_io_sscanf(buf + strlen(HELPVSTR), "%d", 4558*7c478bd9Sstevel@tonic-gate &h) == 1) 4559*7c478bd9Sstevel@tonic-gate foundvers = h; 4560*7c478bd9Sstevel@tonic-gate } 4561*7c478bd9Sstevel@tonic-gate continue; 4562*7c478bd9Sstevel@tonic-gate } 4563*7c478bd9Sstevel@tonic-gate if (strncmp(buf, topic, len) == 0) 4564*7c478bd9Sstevel@tonic-gate { 4565*7c478bd9Sstevel@tonic-gate if (first) 4566*7c478bd9Sstevel@tonic-gate { 4567*7c478bd9Sstevel@tonic-gate first = false; 4568*7c478bd9Sstevel@tonic-gate 4569*7c478bd9Sstevel@tonic-gate /* print version if no/old vers# in file */ 4570*7c478bd9Sstevel@tonic-gate if (foundvers < 2 && !noinfo) 4571*7c478bd9Sstevel@tonic-gate message("214-2.0.0 This is Sendmail version %s", Version); 4572*7c478bd9Sstevel@tonic-gate } 4573*7c478bd9Sstevel@tonic-gate p = strpbrk(buf, " \t"); 4574*7c478bd9Sstevel@tonic-gate if (p == NULL) 4575*7c478bd9Sstevel@tonic-gate p = buf + strlen(buf) - 1; 4576*7c478bd9Sstevel@tonic-gate else 4577*7c478bd9Sstevel@tonic-gate p++; 4578*7c478bd9Sstevel@tonic-gate fixcrlf(p, true); 4579*7c478bd9Sstevel@tonic-gate if (foundvers >= 2) 4580*7c478bd9Sstevel@tonic-gate { 4581*7c478bd9Sstevel@tonic-gate translate_dollars(p); 4582*7c478bd9Sstevel@tonic-gate expand(p, inp, sizeof inp, e); 4583*7c478bd9Sstevel@tonic-gate p = inp; 4584*7c478bd9Sstevel@tonic-gate } 4585*7c478bd9Sstevel@tonic-gate message("214-2.0.0 %s", p); 4586*7c478bd9Sstevel@tonic-gate noinfo = false; 4587*7c478bd9Sstevel@tonic-gate } 4588*7c478bd9Sstevel@tonic-gate } 4589*7c478bd9Sstevel@tonic-gate 4590*7c478bd9Sstevel@tonic-gate if (noinfo) 4591*7c478bd9Sstevel@tonic-gate message("504 5.3.0 HELP topic \"%.10s\" unknown", topic); 4592*7c478bd9Sstevel@tonic-gate else 4593*7c478bd9Sstevel@tonic-gate message("214 2.0.0 End of HELP info"); 4594*7c478bd9Sstevel@tonic-gate 4595*7c478bd9Sstevel@tonic-gate if (foundvers != 0 && foundvers < HELPVERSION) 4596*7c478bd9Sstevel@tonic-gate { 4597*7c478bd9Sstevel@tonic-gate if (LogLevel > 1) 4598*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, e->e_id, 4599*7c478bd9Sstevel@tonic-gate "%s too old (require version %d)", 4600*7c478bd9Sstevel@tonic-gate HelpFile, HELPVERSION); 4601*7c478bd9Sstevel@tonic-gate 4602*7c478bd9Sstevel@tonic-gate /* avoid log next time */ 4603*7c478bd9Sstevel@tonic-gate foundvers = 0; 4604*7c478bd9Sstevel@tonic-gate } 4605*7c478bd9Sstevel@tonic-gate 4606*7c478bd9Sstevel@tonic-gate (void) sm_io_close(hf, SM_TIME_DEFAULT); 4607*7c478bd9Sstevel@tonic-gate } 4608*7c478bd9Sstevel@tonic-gate 4609*7c478bd9Sstevel@tonic-gate #if SASL 4610*7c478bd9Sstevel@tonic-gate /* 4611*7c478bd9Sstevel@tonic-gate ** RESET_SASLCONN -- reset SASL connection data 4612*7c478bd9Sstevel@tonic-gate ** 4613*7c478bd9Sstevel@tonic-gate ** Parameters: 4614*7c478bd9Sstevel@tonic-gate ** conn -- SASL connection context 4615*7c478bd9Sstevel@tonic-gate ** hostname -- host name 4616*7c478bd9Sstevel@tonic-gate ** various connection data 4617*7c478bd9Sstevel@tonic-gate ** 4618*7c478bd9Sstevel@tonic-gate ** Returns: 4619*7c478bd9Sstevel@tonic-gate ** SASL result 4620*7c478bd9Sstevel@tonic-gate */ 4621*7c478bd9Sstevel@tonic-gate 4622*7c478bd9Sstevel@tonic-gate static int 4623*7c478bd9Sstevel@tonic-gate reset_saslconn(sasl_conn_t **conn, char *hostname, 4624*7c478bd9Sstevel@tonic-gate # if SASL >= 20000 4625*7c478bd9Sstevel@tonic-gate char *remoteip, char *localip, 4626*7c478bd9Sstevel@tonic-gate char *auth_id, sasl_ssf_t * ext_ssf) 4627*7c478bd9Sstevel@tonic-gate # else /* SASL >= 20000 */ 4628*7c478bd9Sstevel@tonic-gate struct sockaddr_in *saddr_r, struct sockaddr_in *saddr_l, 4629*7c478bd9Sstevel@tonic-gate sasl_external_properties_t * ext_ssf) 4630*7c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */ 4631*7c478bd9Sstevel@tonic-gate { 4632*7c478bd9Sstevel@tonic-gate int result; 4633*7c478bd9Sstevel@tonic-gate 4634*7c478bd9Sstevel@tonic-gate sasl_dispose(conn); 4635*7c478bd9Sstevel@tonic-gate # if SASL >= 20000 4636*7c478bd9Sstevel@tonic-gate result = sasl_server_new("smtp", hostname, NULL, NULL, NULL, 4637*7c478bd9Sstevel@tonic-gate NULL, 0, conn); 4638*7c478bd9Sstevel@tonic-gate # elif SASL > 10505 4639*7c478bd9Sstevel@tonic-gate /* use empty realm: only works in SASL > 1.5.5 */ 4640*7c478bd9Sstevel@tonic-gate result = sasl_server_new("smtp", hostname, "", NULL, 0, conn); 4641*7c478bd9Sstevel@tonic-gate # else /* SASL >= 20000 */ 4642*7c478bd9Sstevel@tonic-gate /* use no realm -> realm is set to hostname by SASL lib */ 4643*7c478bd9Sstevel@tonic-gate result = sasl_server_new("smtp", hostname, NULL, NULL, 0, 4644*7c478bd9Sstevel@tonic-gate conn); 4645*7c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */ 4646*7c478bd9Sstevel@tonic-gate if (result != SASL_OK) 4647*7c478bd9Sstevel@tonic-gate return result; 4648*7c478bd9Sstevel@tonic-gate 4649*7c478bd9Sstevel@tonic-gate # if SASL >= 20000 4650*7c478bd9Sstevel@tonic-gate # if NETINET || NETINET6 4651*7c478bd9Sstevel@tonic-gate if (remoteip != NULL && *remoteip != '\0') 4652*7c478bd9Sstevel@tonic-gate result = sasl_setprop(*conn, SASL_IPREMOTEPORT, remoteip); 4653*7c478bd9Sstevel@tonic-gate if (result != SASL_OK) 4654*7c478bd9Sstevel@tonic-gate return result; 4655*7c478bd9Sstevel@tonic-gate 4656*7c478bd9Sstevel@tonic-gate if (localip != NULL && *localip != '\0') 4657*7c478bd9Sstevel@tonic-gate result = sasl_setprop(*conn, SASL_IPLOCALPORT, localip); 4658*7c478bd9Sstevel@tonic-gate if (result != SASL_OK) 4659*7c478bd9Sstevel@tonic-gate return result; 4660*7c478bd9Sstevel@tonic-gate # endif /* NETINET || NETINET6 */ 4661*7c478bd9Sstevel@tonic-gate 4662*7c478bd9Sstevel@tonic-gate result = sasl_setprop(*conn, SASL_SSF_EXTERNAL, ext_ssf); 4663*7c478bd9Sstevel@tonic-gate if (result != SASL_OK) 4664*7c478bd9Sstevel@tonic-gate return result; 4665*7c478bd9Sstevel@tonic-gate 4666*7c478bd9Sstevel@tonic-gate result = sasl_setprop(*conn, SASL_AUTH_EXTERNAL, auth_id); 4667*7c478bd9Sstevel@tonic-gate if (result != SASL_OK) 4668*7c478bd9Sstevel@tonic-gate return result; 4669*7c478bd9Sstevel@tonic-gate # else /* SASL >= 20000 */ 4670*7c478bd9Sstevel@tonic-gate # if NETINET 4671*7c478bd9Sstevel@tonic-gate if (saddr_r != NULL) 4672*7c478bd9Sstevel@tonic-gate result = sasl_setprop(*conn, SASL_IP_REMOTE, saddr_r); 4673*7c478bd9Sstevel@tonic-gate if (result != SASL_OK) 4674*7c478bd9Sstevel@tonic-gate return result; 4675*7c478bd9Sstevel@tonic-gate 4676*7c478bd9Sstevel@tonic-gate if (saddr_l != NULL) 4677*7c478bd9Sstevel@tonic-gate result = sasl_setprop(*conn, SASL_IP_LOCAL, saddr_l); 4678*7c478bd9Sstevel@tonic-gate if (result != SASL_OK) 4679*7c478bd9Sstevel@tonic-gate return result; 4680*7c478bd9Sstevel@tonic-gate # endif /* NETINET */ 4681*7c478bd9Sstevel@tonic-gate 4682*7c478bd9Sstevel@tonic-gate result = sasl_setprop(*conn, SASL_SSF_EXTERNAL, ext_ssf); 4683*7c478bd9Sstevel@tonic-gate if (result != SASL_OK) 4684*7c478bd9Sstevel@tonic-gate return result; 4685*7c478bd9Sstevel@tonic-gate # endif /* SASL >= 20000 */ 4686*7c478bd9Sstevel@tonic-gate return SASL_OK; 4687*7c478bd9Sstevel@tonic-gate } 4688*7c478bd9Sstevel@tonic-gate #endif /* SASL */ 4689