1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright (c) 1999-2005 Sendmail, Inc. and its suppliers. 3*7c478bd9Sstevel@tonic-gate * All rights reserved. 4*7c478bd9Sstevel@tonic-gate * 5*7c478bd9Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set 6*7c478bd9Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of 7*7c478bd9Sstevel@tonic-gate * the sendmail distribution. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate */ 10*7c478bd9Sstevel@tonic-gate 11*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 12*7c478bd9Sstevel@tonic-gate 13*7c478bd9Sstevel@tonic-gate #include <sendmail.h> 14*7c478bd9Sstevel@tonic-gate 15*7c478bd9Sstevel@tonic-gate SM_RCSID("@(#)$Id: milter.c,v 8.229 2005/03/02 02:32:34 ca Exp $") 16*7c478bd9Sstevel@tonic-gate 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 21*7c478bd9Sstevel@tonic-gate # include <errno.h> 22*7c478bd9Sstevel@tonic-gate # include <sys/time.h> 23*7c478bd9Sstevel@tonic-gate # include <sys/uio.h> 24*7c478bd9Sstevel@tonic-gate 25*7c478bd9Sstevel@tonic-gate # if NETINET || NETINET6 26*7c478bd9Sstevel@tonic-gate # include <arpa/inet.h> 27*7c478bd9Sstevel@tonic-gate # if _FFR_MILTER_NAGLE 28*7c478bd9Sstevel@tonic-gate # include <netinet/tcp.h> 29*7c478bd9Sstevel@tonic-gate # endif /* _FFR_MILTER_NAGLE */ 30*7c478bd9Sstevel@tonic-gate # endif /* NETINET || NETINET6 */ 31*7c478bd9Sstevel@tonic-gate 32*7c478bd9Sstevel@tonic-gate # include <sm/fdset.h> 33*7c478bd9Sstevel@tonic-gate 34*7c478bd9Sstevel@tonic-gate static void milter_connect_timeout __P((int)); 35*7c478bd9Sstevel@tonic-gate static void milter_error __P((struct milter *, ENVELOPE *)); 36*7c478bd9Sstevel@tonic-gate static int milter_open __P((struct milter *, bool, ENVELOPE *)); 37*7c478bd9Sstevel@tonic-gate static void milter_parse_timeouts __P((char *, struct milter *)); 38*7c478bd9Sstevel@tonic-gate 39*7c478bd9Sstevel@tonic-gate static char *MilterConnectMacros[MAXFILTERMACROS + 1]; 40*7c478bd9Sstevel@tonic-gate static char *MilterHeloMacros[MAXFILTERMACROS + 1]; 41*7c478bd9Sstevel@tonic-gate static char *MilterEnvFromMacros[MAXFILTERMACROS + 1]; 42*7c478bd9Sstevel@tonic-gate static char *MilterEnvRcptMacros[MAXFILTERMACROS + 1]; 43*7c478bd9Sstevel@tonic-gate static char *MilterDataMacros[MAXFILTERMACROS + 1]; 44*7c478bd9Sstevel@tonic-gate static char *MilterEOMMacros[MAXFILTERMACROS + 1]; 45*7c478bd9Sstevel@tonic-gate static size_t MilterMaxDataSize = MILTER_MAX_DATA_SIZE; 46*7c478bd9Sstevel@tonic-gate 47*7c478bd9Sstevel@tonic-gate # define MILTER_CHECK_DONE_MSG() \ 48*7c478bd9Sstevel@tonic-gate if (*state == SMFIR_REPLYCODE || \ 49*7c478bd9Sstevel@tonic-gate *state == SMFIR_REJECT || \ 50*7c478bd9Sstevel@tonic-gate *state == SMFIR_DISCARD || \ 51*7c478bd9Sstevel@tonic-gate *state == SMFIR_TEMPFAIL) \ 52*7c478bd9Sstevel@tonic-gate { \ 53*7c478bd9Sstevel@tonic-gate /* Abort the filters to let them know we are done with msg */ \ 54*7c478bd9Sstevel@tonic-gate milter_abort(e); \ 55*7c478bd9Sstevel@tonic-gate } 56*7c478bd9Sstevel@tonic-gate 57*7c478bd9Sstevel@tonic-gate # define MILTER_CHECK_ERROR(initial, action) \ 58*7c478bd9Sstevel@tonic-gate if (!initial && tTd(71, 100)) \ 59*7c478bd9Sstevel@tonic-gate { \ 60*7c478bd9Sstevel@tonic-gate if (e->e_quarmsg == NULL) \ 61*7c478bd9Sstevel@tonic-gate { \ 62*7c478bd9Sstevel@tonic-gate e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, \ 63*7c478bd9Sstevel@tonic-gate "filter failure"); \ 64*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), \ 65*7c478bd9Sstevel@tonic-gate e->e_quarmsg); \ 66*7c478bd9Sstevel@tonic-gate } \ 67*7c478bd9Sstevel@tonic-gate } \ 68*7c478bd9Sstevel@tonic-gate else if (tTd(71, 101)) \ 69*7c478bd9Sstevel@tonic-gate { \ 70*7c478bd9Sstevel@tonic-gate if (e->e_quarmsg == NULL) \ 71*7c478bd9Sstevel@tonic-gate { \ 72*7c478bd9Sstevel@tonic-gate e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, \ 73*7c478bd9Sstevel@tonic-gate "filter failure"); \ 74*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), \ 75*7c478bd9Sstevel@tonic-gate e->e_quarmsg); \ 76*7c478bd9Sstevel@tonic-gate } \ 77*7c478bd9Sstevel@tonic-gate } \ 78*7c478bd9Sstevel@tonic-gate else if (bitnset(SMF_TEMPFAIL, m->mf_flags)) \ 79*7c478bd9Sstevel@tonic-gate *state = SMFIR_TEMPFAIL; \ 80*7c478bd9Sstevel@tonic-gate else if (bitnset(SMF_TEMPDROP, m->mf_flags)) \ 81*7c478bd9Sstevel@tonic-gate *state = SMFIR_SHUTDOWN; \ 82*7c478bd9Sstevel@tonic-gate else if (bitnset(SMF_REJECT, m->mf_flags)) \ 83*7c478bd9Sstevel@tonic-gate *state = SMFIR_REJECT; \ 84*7c478bd9Sstevel@tonic-gate else \ 85*7c478bd9Sstevel@tonic-gate action; 86*7c478bd9Sstevel@tonic-gate 87*7c478bd9Sstevel@tonic-gate # define MILTER_CHECK_REPLYCODE(default) \ 88*7c478bd9Sstevel@tonic-gate if (response == NULL || \ 89*7c478bd9Sstevel@tonic-gate strlen(response) + 1 != (size_t) rlen || \ 90*7c478bd9Sstevel@tonic-gate rlen < 3 || \ 91*7c478bd9Sstevel@tonic-gate (response[0] != '4' && response[0] != '5') || \ 92*7c478bd9Sstevel@tonic-gate !isascii(response[1]) || !isdigit(response[1]) || \ 93*7c478bd9Sstevel@tonic-gate !isascii(response[2]) || !isdigit(response[2])) \ 94*7c478bd9Sstevel@tonic-gate { \ 95*7c478bd9Sstevel@tonic-gate if (response != NULL) \ 96*7c478bd9Sstevel@tonic-gate sm_free(response); /* XXX */ \ 97*7c478bd9Sstevel@tonic-gate response = newstr(default); \ 98*7c478bd9Sstevel@tonic-gate } \ 99*7c478bd9Sstevel@tonic-gate else \ 100*7c478bd9Sstevel@tonic-gate { \ 101*7c478bd9Sstevel@tonic-gate char *ptr = response; \ 102*7c478bd9Sstevel@tonic-gate \ 103*7c478bd9Sstevel@tonic-gate /* Check for unprotected %'s in the string */ \ 104*7c478bd9Sstevel@tonic-gate while (*ptr != '\0') \ 105*7c478bd9Sstevel@tonic-gate { \ 106*7c478bd9Sstevel@tonic-gate if (*ptr == '%' && *++ptr != '%') \ 107*7c478bd9Sstevel@tonic-gate { \ 108*7c478bd9Sstevel@tonic-gate sm_free(response); /* XXX */ \ 109*7c478bd9Sstevel@tonic-gate response = newstr(default); \ 110*7c478bd9Sstevel@tonic-gate break; \ 111*7c478bd9Sstevel@tonic-gate } \ 112*7c478bd9Sstevel@tonic-gate ptr++; \ 113*7c478bd9Sstevel@tonic-gate } \ 114*7c478bd9Sstevel@tonic-gate } 115*7c478bd9Sstevel@tonic-gate 116*7c478bd9Sstevel@tonic-gate # define MILTER_DF_ERROR(msg) \ 117*7c478bd9Sstevel@tonic-gate { \ 118*7c478bd9Sstevel@tonic-gate int save_errno = errno; \ 119*7c478bd9Sstevel@tonic-gate \ 120*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) \ 121*7c478bd9Sstevel@tonic-gate { \ 122*7c478bd9Sstevel@tonic-gate sm_dprintf(msg, dfname, sm_errstring(save_errno)); \ 123*7c478bd9Sstevel@tonic-gate sm_dprintf("\n"); \ 124*7c478bd9Sstevel@tonic-gate } \ 125*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) \ 126*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, msg, dfname, sm_errstring(save_errno)); \ 127*7c478bd9Sstevel@tonic-gate if (SuperSafe == SAFE_REALLY) \ 128*7c478bd9Sstevel@tonic-gate { \ 129*7c478bd9Sstevel@tonic-gate if (e->e_dfp != NULL) \ 130*7c478bd9Sstevel@tonic-gate { \ 131*7c478bd9Sstevel@tonic-gate (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT); \ 132*7c478bd9Sstevel@tonic-gate e->e_dfp = NULL; \ 133*7c478bd9Sstevel@tonic-gate } \ 134*7c478bd9Sstevel@tonic-gate e->e_flags &= ~EF_HAS_DF; \ 135*7c478bd9Sstevel@tonic-gate } \ 136*7c478bd9Sstevel@tonic-gate errno = save_errno; \ 137*7c478bd9Sstevel@tonic-gate } 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate /* 140*7c478bd9Sstevel@tonic-gate ** MILTER_TIMEOUT -- make sure socket is ready in time 141*7c478bd9Sstevel@tonic-gate ** 142*7c478bd9Sstevel@tonic-gate ** Parameters: 143*7c478bd9Sstevel@tonic-gate ** routine -- routine name for debug/logging 144*7c478bd9Sstevel@tonic-gate ** secs -- number of seconds in timeout 145*7c478bd9Sstevel@tonic-gate ** write -- waiting to read or write? 146*7c478bd9Sstevel@tonic-gate ** started -- whether this is part of a previous sequence 147*7c478bd9Sstevel@tonic-gate ** 148*7c478bd9Sstevel@tonic-gate ** Assumes 'm' is a milter structure for the current socket. 149*7c478bd9Sstevel@tonic-gate */ 150*7c478bd9Sstevel@tonic-gate 151*7c478bd9Sstevel@tonic-gate # define MILTER_TIMEOUT(routine, secs, write, started) \ 152*7c478bd9Sstevel@tonic-gate { \ 153*7c478bd9Sstevel@tonic-gate int ret; \ 154*7c478bd9Sstevel@tonic-gate int save_errno; \ 155*7c478bd9Sstevel@tonic-gate fd_set fds; \ 156*7c478bd9Sstevel@tonic-gate struct timeval tv; \ 157*7c478bd9Sstevel@tonic-gate \ 158*7c478bd9Sstevel@tonic-gate if (SM_FD_SETSIZE > 0 && m->mf_sock >= SM_FD_SETSIZE) \ 159*7c478bd9Sstevel@tonic-gate { \ 160*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) \ 161*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_%s(%s): socket %d is larger than FD_SETSIZE %d\n", \ 162*7c478bd9Sstevel@tonic-gate (routine), m->mf_name, m->mf_sock, \ 163*7c478bd9Sstevel@tonic-gate SM_FD_SETSIZE); \ 164*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) \ 165*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, \ 166*7c478bd9Sstevel@tonic-gate "Milter (%s): socket(%s) %d is larger than FD_SETSIZE %d", \ 167*7c478bd9Sstevel@tonic-gate m->mf_name, (routine), m->mf_sock, \ 168*7c478bd9Sstevel@tonic-gate SM_FD_SETSIZE); \ 169*7c478bd9Sstevel@tonic-gate milter_error(m, e); \ 170*7c478bd9Sstevel@tonic-gate return NULL; \ 171*7c478bd9Sstevel@tonic-gate } \ 172*7c478bd9Sstevel@tonic-gate \ 173*7c478bd9Sstevel@tonic-gate do \ 174*7c478bd9Sstevel@tonic-gate { \ 175*7c478bd9Sstevel@tonic-gate FD_ZERO(&fds); \ 176*7c478bd9Sstevel@tonic-gate SM_FD_SET(m->mf_sock, &fds); \ 177*7c478bd9Sstevel@tonic-gate tv.tv_sec = (secs); \ 178*7c478bd9Sstevel@tonic-gate tv.tv_usec = 0; \ 179*7c478bd9Sstevel@tonic-gate ret = select(m->mf_sock + 1, \ 180*7c478bd9Sstevel@tonic-gate (write) ? NULL : &fds, \ 181*7c478bd9Sstevel@tonic-gate (write) ? &fds : NULL, \ 182*7c478bd9Sstevel@tonic-gate NULL, &tv); \ 183*7c478bd9Sstevel@tonic-gate } while (ret < 0 && errno == EINTR); \ 184*7c478bd9Sstevel@tonic-gate \ 185*7c478bd9Sstevel@tonic-gate switch (ret) \ 186*7c478bd9Sstevel@tonic-gate { \ 187*7c478bd9Sstevel@tonic-gate case 0: \ 188*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) \ 189*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_%s(%s): timeout\n", (routine), \ 190*7c478bd9Sstevel@tonic-gate m->mf_name); \ 191*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) \ 192*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, \ 193*7c478bd9Sstevel@tonic-gate "Milter (%s): %s %s %s %s", \ 194*7c478bd9Sstevel@tonic-gate m->mf_name, "timeout", \ 195*7c478bd9Sstevel@tonic-gate started ? "during" : "before", \ 196*7c478bd9Sstevel@tonic-gate "data", (routine)); \ 197*7c478bd9Sstevel@tonic-gate milter_error(m, e); \ 198*7c478bd9Sstevel@tonic-gate return NULL; \ 199*7c478bd9Sstevel@tonic-gate \ 200*7c478bd9Sstevel@tonic-gate case -1: \ 201*7c478bd9Sstevel@tonic-gate save_errno = errno; \ 202*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) \ 203*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_%s(%s): select: %s\n", (routine), \ 204*7c478bd9Sstevel@tonic-gate m->mf_name, sm_errstring(save_errno)); \ 205*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) \ 206*7c478bd9Sstevel@tonic-gate { \ 207*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, \ 208*7c478bd9Sstevel@tonic-gate "Milter (%s): select(%s): %s", \ 209*7c478bd9Sstevel@tonic-gate m->mf_name, (routine), \ 210*7c478bd9Sstevel@tonic-gate sm_errstring(save_errno)); \ 211*7c478bd9Sstevel@tonic-gate } \ 212*7c478bd9Sstevel@tonic-gate milter_error(m, e); \ 213*7c478bd9Sstevel@tonic-gate return NULL; \ 214*7c478bd9Sstevel@tonic-gate \ 215*7c478bd9Sstevel@tonic-gate default: \ 216*7c478bd9Sstevel@tonic-gate if (SM_FD_ISSET(m->mf_sock, &fds)) \ 217*7c478bd9Sstevel@tonic-gate break; \ 218*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) \ 219*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_%s(%s): socket not ready\n", \ 220*7c478bd9Sstevel@tonic-gate (routine), m->mf_name); \ 221*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) \ 222*7c478bd9Sstevel@tonic-gate { \ 223*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, \ 224*7c478bd9Sstevel@tonic-gate "Milter (%s): socket(%s) not ready", \ 225*7c478bd9Sstevel@tonic-gate m->mf_name, (routine)); \ 226*7c478bd9Sstevel@tonic-gate } \ 227*7c478bd9Sstevel@tonic-gate milter_error(m, e); \ 228*7c478bd9Sstevel@tonic-gate return NULL; \ 229*7c478bd9Sstevel@tonic-gate } \ 230*7c478bd9Sstevel@tonic-gate } 231*7c478bd9Sstevel@tonic-gate 232*7c478bd9Sstevel@tonic-gate /* 233*7c478bd9Sstevel@tonic-gate ** Low level functions 234*7c478bd9Sstevel@tonic-gate */ 235*7c478bd9Sstevel@tonic-gate 236*7c478bd9Sstevel@tonic-gate /* 237*7c478bd9Sstevel@tonic-gate ** MILTER_READ -- read from a remote milter filter 238*7c478bd9Sstevel@tonic-gate ** 239*7c478bd9Sstevel@tonic-gate ** Parameters: 240*7c478bd9Sstevel@tonic-gate ** m -- milter to read from. 241*7c478bd9Sstevel@tonic-gate ** cmd -- return param for command read. 242*7c478bd9Sstevel@tonic-gate ** rlen -- return length of response string. 243*7c478bd9Sstevel@tonic-gate ** to -- timeout in seconds. 244*7c478bd9Sstevel@tonic-gate ** e -- current envelope. 245*7c478bd9Sstevel@tonic-gate ** 246*7c478bd9Sstevel@tonic-gate ** Returns: 247*7c478bd9Sstevel@tonic-gate ** response string (may be NULL) 248*7c478bd9Sstevel@tonic-gate */ 249*7c478bd9Sstevel@tonic-gate 250*7c478bd9Sstevel@tonic-gate static char * 251*7c478bd9Sstevel@tonic-gate milter_sysread(m, buf, sz, to, e) 252*7c478bd9Sstevel@tonic-gate struct milter *m; 253*7c478bd9Sstevel@tonic-gate char *buf; 254*7c478bd9Sstevel@tonic-gate ssize_t sz; 255*7c478bd9Sstevel@tonic-gate time_t to; 256*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 257*7c478bd9Sstevel@tonic-gate { 258*7c478bd9Sstevel@tonic-gate time_t readstart = 0; 259*7c478bd9Sstevel@tonic-gate ssize_t len, curl; 260*7c478bd9Sstevel@tonic-gate bool started = false; 261*7c478bd9Sstevel@tonic-gate 262*7c478bd9Sstevel@tonic-gate curl = 0; 263*7c478bd9Sstevel@tonic-gate 264*7c478bd9Sstevel@tonic-gate if (to > 0) 265*7c478bd9Sstevel@tonic-gate readstart = curtime(); 266*7c478bd9Sstevel@tonic-gate 267*7c478bd9Sstevel@tonic-gate for (;;) 268*7c478bd9Sstevel@tonic-gate { 269*7c478bd9Sstevel@tonic-gate if (to > 0) 270*7c478bd9Sstevel@tonic-gate { 271*7c478bd9Sstevel@tonic-gate time_t now; 272*7c478bd9Sstevel@tonic-gate 273*7c478bd9Sstevel@tonic-gate now = curtime(); 274*7c478bd9Sstevel@tonic-gate if (now - readstart >= to) 275*7c478bd9Sstevel@tonic-gate { 276*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 277*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_read (%s): %s %s %s", 278*7c478bd9Sstevel@tonic-gate m->mf_name, "timeout", 279*7c478bd9Sstevel@tonic-gate started ? "during" : "before", 280*7c478bd9Sstevel@tonic-gate "data read"); 281*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) 282*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 283*7c478bd9Sstevel@tonic-gate "Milter (%s): %s %s %s", 284*7c478bd9Sstevel@tonic-gate m->mf_name, "timeout", 285*7c478bd9Sstevel@tonic-gate started ? "during" : "before", 286*7c478bd9Sstevel@tonic-gate "data read"); 287*7c478bd9Sstevel@tonic-gate milter_error(m, e); 288*7c478bd9Sstevel@tonic-gate return NULL; 289*7c478bd9Sstevel@tonic-gate } 290*7c478bd9Sstevel@tonic-gate to -= now - readstart; 291*7c478bd9Sstevel@tonic-gate readstart = now; 292*7c478bd9Sstevel@tonic-gate MILTER_TIMEOUT("read", to, false, started); 293*7c478bd9Sstevel@tonic-gate } 294*7c478bd9Sstevel@tonic-gate 295*7c478bd9Sstevel@tonic-gate len = read(m->mf_sock, buf + curl, sz - curl); 296*7c478bd9Sstevel@tonic-gate 297*7c478bd9Sstevel@tonic-gate if (len < 0) 298*7c478bd9Sstevel@tonic-gate { 299*7c478bd9Sstevel@tonic-gate int save_errno = errno; 300*7c478bd9Sstevel@tonic-gate 301*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 302*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_read(%s): read returned %ld: %s\n", 303*7c478bd9Sstevel@tonic-gate m->mf_name, (long) len, 304*7c478bd9Sstevel@tonic-gate sm_errstring(save_errno)); 305*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) 306*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 307*7c478bd9Sstevel@tonic-gate "Milter (%s): read returned %ld: %s", 308*7c478bd9Sstevel@tonic-gate m->mf_name, (long) len, 309*7c478bd9Sstevel@tonic-gate sm_errstring(save_errno)); 310*7c478bd9Sstevel@tonic-gate milter_error(m, e); 311*7c478bd9Sstevel@tonic-gate return NULL; 312*7c478bd9Sstevel@tonic-gate } 313*7c478bd9Sstevel@tonic-gate 314*7c478bd9Sstevel@tonic-gate started = true; 315*7c478bd9Sstevel@tonic-gate curl += len; 316*7c478bd9Sstevel@tonic-gate if (len == 0 || curl >= sz) 317*7c478bd9Sstevel@tonic-gate break; 318*7c478bd9Sstevel@tonic-gate 319*7c478bd9Sstevel@tonic-gate } 320*7c478bd9Sstevel@tonic-gate 321*7c478bd9Sstevel@tonic-gate if (curl != sz) 322*7c478bd9Sstevel@tonic-gate { 323*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 324*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_read(%s): cmd read returned %ld, expecting %ld\n", 325*7c478bd9Sstevel@tonic-gate m->mf_name, (long) curl, (long) sz); 326*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) 327*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 328*7c478bd9Sstevel@tonic-gate "milter_read(%s): cmd read returned %ld, expecting %ld", 329*7c478bd9Sstevel@tonic-gate m->mf_name, (long) curl, (long) sz); 330*7c478bd9Sstevel@tonic-gate milter_error(m, e); 331*7c478bd9Sstevel@tonic-gate return NULL; 332*7c478bd9Sstevel@tonic-gate } 333*7c478bd9Sstevel@tonic-gate return buf; 334*7c478bd9Sstevel@tonic-gate } 335*7c478bd9Sstevel@tonic-gate 336*7c478bd9Sstevel@tonic-gate static char * 337*7c478bd9Sstevel@tonic-gate milter_read(m, cmd, rlen, to, e) 338*7c478bd9Sstevel@tonic-gate struct milter *m; 339*7c478bd9Sstevel@tonic-gate char *cmd; 340*7c478bd9Sstevel@tonic-gate ssize_t *rlen; 341*7c478bd9Sstevel@tonic-gate time_t to; 342*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 343*7c478bd9Sstevel@tonic-gate { 344*7c478bd9Sstevel@tonic-gate time_t readstart = 0; 345*7c478bd9Sstevel@tonic-gate ssize_t expl; 346*7c478bd9Sstevel@tonic-gate mi_int32 i; 347*7c478bd9Sstevel@tonic-gate # if _FFR_MILTER_NAGLE 348*7c478bd9Sstevel@tonic-gate # ifdef TCP_CORK 349*7c478bd9Sstevel@tonic-gate int cork = 0; 350*7c478bd9Sstevel@tonic-gate # endif 351*7c478bd9Sstevel@tonic-gate # endif /* _FFR_MILTER_NAGLE */ 352*7c478bd9Sstevel@tonic-gate char *buf; 353*7c478bd9Sstevel@tonic-gate char data[MILTER_LEN_BYTES + 1]; 354*7c478bd9Sstevel@tonic-gate 355*7c478bd9Sstevel@tonic-gate if (m->mf_sock < 0) 356*7c478bd9Sstevel@tonic-gate { 357*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) 358*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 359*7c478bd9Sstevel@tonic-gate "milter_read(%s): socket closed", 360*7c478bd9Sstevel@tonic-gate m->mf_name); 361*7c478bd9Sstevel@tonic-gate milter_error(m, e); 362*7c478bd9Sstevel@tonic-gate return NULL; 363*7c478bd9Sstevel@tonic-gate } 364*7c478bd9Sstevel@tonic-gate 365*7c478bd9Sstevel@tonic-gate *rlen = 0; 366*7c478bd9Sstevel@tonic-gate *cmd = '\0'; 367*7c478bd9Sstevel@tonic-gate 368*7c478bd9Sstevel@tonic-gate if (to > 0) 369*7c478bd9Sstevel@tonic-gate readstart = curtime(); 370*7c478bd9Sstevel@tonic-gate 371*7c478bd9Sstevel@tonic-gate # if _FFR_MILTER_NAGLE 372*7c478bd9Sstevel@tonic-gate # ifdef TCP_CORK 373*7c478bd9Sstevel@tonic-gate setsockopt(m->mf_sock, IPPROTO_TCP, TCP_CORK, (char *)&cork, 374*7c478bd9Sstevel@tonic-gate sizeof(cork)); 375*7c478bd9Sstevel@tonic-gate # endif 376*7c478bd9Sstevel@tonic-gate # endif /* _FFR_MILTER_NAGLE */ 377*7c478bd9Sstevel@tonic-gate 378*7c478bd9Sstevel@tonic-gate if (milter_sysread(m, data, sizeof data, to, e) == NULL) 379*7c478bd9Sstevel@tonic-gate return NULL; 380*7c478bd9Sstevel@tonic-gate 381*7c478bd9Sstevel@tonic-gate # if _FFR_MILTER_NAGLE 382*7c478bd9Sstevel@tonic-gate # ifdef TCP_CORK 383*7c478bd9Sstevel@tonic-gate cork = 1; 384*7c478bd9Sstevel@tonic-gate setsockopt(m->mf_sock, IPPROTO_TCP, TCP_CORK, (char *)&cork, 385*7c478bd9Sstevel@tonic-gate sizeof(cork)); 386*7c478bd9Sstevel@tonic-gate # endif 387*7c478bd9Sstevel@tonic-gate # endif /* _FFR_MILTER_NAGLE */ 388*7c478bd9Sstevel@tonic-gate 389*7c478bd9Sstevel@tonic-gate /* reset timeout */ 390*7c478bd9Sstevel@tonic-gate if (to > 0) 391*7c478bd9Sstevel@tonic-gate { 392*7c478bd9Sstevel@tonic-gate time_t now; 393*7c478bd9Sstevel@tonic-gate 394*7c478bd9Sstevel@tonic-gate now = curtime(); 395*7c478bd9Sstevel@tonic-gate if (now - readstart >= to) 396*7c478bd9Sstevel@tonic-gate { 397*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 398*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_read(%s): timeout before data read\n", 399*7c478bd9Sstevel@tonic-gate m->mf_name); 400*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) 401*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 402*7c478bd9Sstevel@tonic-gate "Milter read(%s): timeout before data read", 403*7c478bd9Sstevel@tonic-gate m->mf_name); 404*7c478bd9Sstevel@tonic-gate milter_error(m, e); 405*7c478bd9Sstevel@tonic-gate return NULL; 406*7c478bd9Sstevel@tonic-gate } 407*7c478bd9Sstevel@tonic-gate to -= now - readstart; 408*7c478bd9Sstevel@tonic-gate } 409*7c478bd9Sstevel@tonic-gate 410*7c478bd9Sstevel@tonic-gate *cmd = data[MILTER_LEN_BYTES]; 411*7c478bd9Sstevel@tonic-gate data[MILTER_LEN_BYTES] = '\0'; 412*7c478bd9Sstevel@tonic-gate (void) memcpy(&i, data, MILTER_LEN_BYTES); 413*7c478bd9Sstevel@tonic-gate expl = ntohl(i) - 1; 414*7c478bd9Sstevel@tonic-gate 415*7c478bd9Sstevel@tonic-gate if (tTd(64, 25)) 416*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_read(%s): expecting %ld bytes\n", 417*7c478bd9Sstevel@tonic-gate m->mf_name, (long) expl); 418*7c478bd9Sstevel@tonic-gate 419*7c478bd9Sstevel@tonic-gate if (expl < 0) 420*7c478bd9Sstevel@tonic-gate { 421*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 422*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_read(%s): read size %ld out of range\n", 423*7c478bd9Sstevel@tonic-gate m->mf_name, (long) expl); 424*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) 425*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 426*7c478bd9Sstevel@tonic-gate "milter_read(%s): read size %ld out of range", 427*7c478bd9Sstevel@tonic-gate m->mf_name, (long) expl); 428*7c478bd9Sstevel@tonic-gate milter_error(m, e); 429*7c478bd9Sstevel@tonic-gate return NULL; 430*7c478bd9Sstevel@tonic-gate } 431*7c478bd9Sstevel@tonic-gate 432*7c478bd9Sstevel@tonic-gate if (expl == 0) 433*7c478bd9Sstevel@tonic-gate return NULL; 434*7c478bd9Sstevel@tonic-gate 435*7c478bd9Sstevel@tonic-gate buf = (char *) xalloc(expl); 436*7c478bd9Sstevel@tonic-gate 437*7c478bd9Sstevel@tonic-gate if (milter_sysread(m, buf, expl, to, e) == NULL) 438*7c478bd9Sstevel@tonic-gate { 439*7c478bd9Sstevel@tonic-gate sm_free(buf); /* XXX */ 440*7c478bd9Sstevel@tonic-gate return NULL; 441*7c478bd9Sstevel@tonic-gate } 442*7c478bd9Sstevel@tonic-gate 443*7c478bd9Sstevel@tonic-gate if (tTd(64, 50)) 444*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_read(%s): Returning %*s\n", 445*7c478bd9Sstevel@tonic-gate m->mf_name, (int) expl, buf); 446*7c478bd9Sstevel@tonic-gate *rlen = expl; 447*7c478bd9Sstevel@tonic-gate return buf; 448*7c478bd9Sstevel@tonic-gate } 449*7c478bd9Sstevel@tonic-gate 450*7c478bd9Sstevel@tonic-gate /* 451*7c478bd9Sstevel@tonic-gate ** MILTER_WRITE -- write to a remote milter filter 452*7c478bd9Sstevel@tonic-gate ** 453*7c478bd9Sstevel@tonic-gate ** Parameters: 454*7c478bd9Sstevel@tonic-gate ** m -- milter to read from. 455*7c478bd9Sstevel@tonic-gate ** cmd -- command to send. 456*7c478bd9Sstevel@tonic-gate ** buf -- optional command data. 457*7c478bd9Sstevel@tonic-gate ** len -- length of buf. 458*7c478bd9Sstevel@tonic-gate ** to -- timeout in seconds. 459*7c478bd9Sstevel@tonic-gate ** e -- current envelope. 460*7c478bd9Sstevel@tonic-gate ** 461*7c478bd9Sstevel@tonic-gate ** Returns: 462*7c478bd9Sstevel@tonic-gate ** buf if successful, NULL otherwise 463*7c478bd9Sstevel@tonic-gate ** Not actually used anywhere but function prototype 464*7c478bd9Sstevel@tonic-gate ** must match milter_read() 465*7c478bd9Sstevel@tonic-gate */ 466*7c478bd9Sstevel@tonic-gate 467*7c478bd9Sstevel@tonic-gate static char * 468*7c478bd9Sstevel@tonic-gate milter_write(m, cmd, buf, len, to, e) 469*7c478bd9Sstevel@tonic-gate struct milter *m; 470*7c478bd9Sstevel@tonic-gate char cmd; 471*7c478bd9Sstevel@tonic-gate char *buf; 472*7c478bd9Sstevel@tonic-gate ssize_t len; 473*7c478bd9Sstevel@tonic-gate time_t to; 474*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 475*7c478bd9Sstevel@tonic-gate { 476*7c478bd9Sstevel@tonic-gate time_t writestart = (time_t) 0; 477*7c478bd9Sstevel@tonic-gate ssize_t sl, i; 478*7c478bd9Sstevel@tonic-gate int num_vectors; 479*7c478bd9Sstevel@tonic-gate mi_int32 nl; 480*7c478bd9Sstevel@tonic-gate char data[MILTER_LEN_BYTES + 1]; 481*7c478bd9Sstevel@tonic-gate bool started = false; 482*7c478bd9Sstevel@tonic-gate struct iovec vector[2]; 483*7c478bd9Sstevel@tonic-gate 484*7c478bd9Sstevel@tonic-gate /* 485*7c478bd9Sstevel@tonic-gate ** At most two buffers will be written, though 486*7c478bd9Sstevel@tonic-gate ** only one may actually be used (see num_vectors). 487*7c478bd9Sstevel@tonic-gate ** The first is the size/command and the second is the command data. 488*7c478bd9Sstevel@tonic-gate */ 489*7c478bd9Sstevel@tonic-gate 490*7c478bd9Sstevel@tonic-gate if (len < 0 || len > MilterMaxDataSize) 491*7c478bd9Sstevel@tonic-gate { 492*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 493*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_write(%s): length %ld out of range\n", 494*7c478bd9Sstevel@tonic-gate m->mf_name, (long) len); 495*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) 496*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 497*7c478bd9Sstevel@tonic-gate "milter_write(%s): length %ld out of range", 498*7c478bd9Sstevel@tonic-gate m->mf_name, (long) len); 499*7c478bd9Sstevel@tonic-gate milter_error(m, e); 500*7c478bd9Sstevel@tonic-gate return NULL; 501*7c478bd9Sstevel@tonic-gate } 502*7c478bd9Sstevel@tonic-gate if (m->mf_sock < 0) 503*7c478bd9Sstevel@tonic-gate { 504*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) 505*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 506*7c478bd9Sstevel@tonic-gate "milter_write(%s): socket closed", 507*7c478bd9Sstevel@tonic-gate m->mf_name); 508*7c478bd9Sstevel@tonic-gate milter_error(m, e); 509*7c478bd9Sstevel@tonic-gate return NULL; 510*7c478bd9Sstevel@tonic-gate } 511*7c478bd9Sstevel@tonic-gate 512*7c478bd9Sstevel@tonic-gate if (tTd(64, 20)) 513*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_write(%s): cmd %c, len %ld\n", 514*7c478bd9Sstevel@tonic-gate m->mf_name, cmd, (long) len); 515*7c478bd9Sstevel@tonic-gate 516*7c478bd9Sstevel@tonic-gate nl = htonl(len + 1); /* add 1 for the cmd char */ 517*7c478bd9Sstevel@tonic-gate (void) memcpy(data, (char *) &nl, MILTER_LEN_BYTES); 518*7c478bd9Sstevel@tonic-gate data[MILTER_LEN_BYTES] = cmd; 519*7c478bd9Sstevel@tonic-gate sl = MILTER_LEN_BYTES + 1; 520*7c478bd9Sstevel@tonic-gate 521*7c478bd9Sstevel@tonic-gate /* set up the vector for the size / command */ 522*7c478bd9Sstevel@tonic-gate vector[0].iov_base = (void *) data; 523*7c478bd9Sstevel@tonic-gate vector[0].iov_len = sl; 524*7c478bd9Sstevel@tonic-gate 525*7c478bd9Sstevel@tonic-gate /* 526*7c478bd9Sstevel@tonic-gate ** Determine if there is command data. If so, there will be two 527*7c478bd9Sstevel@tonic-gate ** vectors. If not, there will be only one. The vectors are set 528*7c478bd9Sstevel@tonic-gate ** up here and 'num_vectors' and 'sl' are set appropriately. 529*7c478bd9Sstevel@tonic-gate */ 530*7c478bd9Sstevel@tonic-gate 531*7c478bd9Sstevel@tonic-gate /* NOTE: len<0 has already been checked for. Pedantic */ 532*7c478bd9Sstevel@tonic-gate if (len <= 0 || buf == NULL) 533*7c478bd9Sstevel@tonic-gate { 534*7c478bd9Sstevel@tonic-gate /* There is no command data -- only a size / command data */ 535*7c478bd9Sstevel@tonic-gate num_vectors = 1; 536*7c478bd9Sstevel@tonic-gate } 537*7c478bd9Sstevel@tonic-gate else 538*7c478bd9Sstevel@tonic-gate { 539*7c478bd9Sstevel@tonic-gate /* 540*7c478bd9Sstevel@tonic-gate ** There is both size / command and command data. 541*7c478bd9Sstevel@tonic-gate ** Set up the vector for the command data. 542*7c478bd9Sstevel@tonic-gate */ 543*7c478bd9Sstevel@tonic-gate 544*7c478bd9Sstevel@tonic-gate num_vectors = 2; 545*7c478bd9Sstevel@tonic-gate sl += len; 546*7c478bd9Sstevel@tonic-gate vector[1].iov_base = (void *) buf; 547*7c478bd9Sstevel@tonic-gate vector[1].iov_len = len; 548*7c478bd9Sstevel@tonic-gate 549*7c478bd9Sstevel@tonic-gate if (tTd(64, 50)) 550*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_write(%s): Sending %*s\n", 551*7c478bd9Sstevel@tonic-gate m->mf_name, (int) len, buf); 552*7c478bd9Sstevel@tonic-gate } 553*7c478bd9Sstevel@tonic-gate 554*7c478bd9Sstevel@tonic-gate if (to > 0) 555*7c478bd9Sstevel@tonic-gate { 556*7c478bd9Sstevel@tonic-gate writestart = curtime(); 557*7c478bd9Sstevel@tonic-gate MILTER_TIMEOUT("write", to, true, started); 558*7c478bd9Sstevel@tonic-gate } 559*7c478bd9Sstevel@tonic-gate 560*7c478bd9Sstevel@tonic-gate /* write the vector(s) */ 561*7c478bd9Sstevel@tonic-gate i = writev(m->mf_sock, vector, num_vectors); 562*7c478bd9Sstevel@tonic-gate if (i != sl) 563*7c478bd9Sstevel@tonic-gate { 564*7c478bd9Sstevel@tonic-gate int save_errno = errno; 565*7c478bd9Sstevel@tonic-gate 566*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 567*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_write(%s): write(%c) returned %ld, expected %ld: %s\n", 568*7c478bd9Sstevel@tonic-gate m->mf_name, cmd, (long) i, (long) sl, 569*7c478bd9Sstevel@tonic-gate sm_errstring(save_errno)); 570*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) 571*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 572*7c478bd9Sstevel@tonic-gate "Milter (%s): write(%c) returned %ld, expected %ld: %s", 573*7c478bd9Sstevel@tonic-gate m->mf_name, cmd, (long) i, (long) sl, 574*7c478bd9Sstevel@tonic-gate sm_errstring(save_errno)); 575*7c478bd9Sstevel@tonic-gate milter_error(m, e); 576*7c478bd9Sstevel@tonic-gate return NULL; 577*7c478bd9Sstevel@tonic-gate } 578*7c478bd9Sstevel@tonic-gate return buf; 579*7c478bd9Sstevel@tonic-gate } 580*7c478bd9Sstevel@tonic-gate 581*7c478bd9Sstevel@tonic-gate /* 582*7c478bd9Sstevel@tonic-gate ** Utility functions 583*7c478bd9Sstevel@tonic-gate */ 584*7c478bd9Sstevel@tonic-gate 585*7c478bd9Sstevel@tonic-gate /* 586*7c478bd9Sstevel@tonic-gate ** MILTER_OPEN -- connect to remote milter filter 587*7c478bd9Sstevel@tonic-gate ** 588*7c478bd9Sstevel@tonic-gate ** Parameters: 589*7c478bd9Sstevel@tonic-gate ** m -- milter to connect to. 590*7c478bd9Sstevel@tonic-gate ** parseonly -- parse but don't connect. 591*7c478bd9Sstevel@tonic-gate ** e -- current envelope. 592*7c478bd9Sstevel@tonic-gate ** 593*7c478bd9Sstevel@tonic-gate ** Returns: 594*7c478bd9Sstevel@tonic-gate ** connected socket if successful && !parseonly, 595*7c478bd9Sstevel@tonic-gate ** 0 upon parse success if parseonly, 596*7c478bd9Sstevel@tonic-gate ** -1 otherwise. 597*7c478bd9Sstevel@tonic-gate */ 598*7c478bd9Sstevel@tonic-gate 599*7c478bd9Sstevel@tonic-gate static jmp_buf MilterConnectTimeout; 600*7c478bd9Sstevel@tonic-gate 601*7c478bd9Sstevel@tonic-gate static int 602*7c478bd9Sstevel@tonic-gate milter_open(m, parseonly, e) 603*7c478bd9Sstevel@tonic-gate struct milter *m; 604*7c478bd9Sstevel@tonic-gate bool parseonly; 605*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 606*7c478bd9Sstevel@tonic-gate { 607*7c478bd9Sstevel@tonic-gate int sock = 0; 608*7c478bd9Sstevel@tonic-gate SOCKADDR_LEN_T addrlen = 0; 609*7c478bd9Sstevel@tonic-gate int addrno = 0; 610*7c478bd9Sstevel@tonic-gate int save_errno; 611*7c478bd9Sstevel@tonic-gate char *p; 612*7c478bd9Sstevel@tonic-gate char *colon; 613*7c478bd9Sstevel@tonic-gate char *at; 614*7c478bd9Sstevel@tonic-gate struct hostent *hp = NULL; 615*7c478bd9Sstevel@tonic-gate SOCKADDR addr; 616*7c478bd9Sstevel@tonic-gate 617*7c478bd9Sstevel@tonic-gate if (m->mf_conn == NULL || m->mf_conn[0] == '\0') 618*7c478bd9Sstevel@tonic-gate { 619*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 620*7c478bd9Sstevel@tonic-gate sm_dprintf("X%s: empty or missing socket information\n", 621*7c478bd9Sstevel@tonic-gate m->mf_name); 622*7c478bd9Sstevel@tonic-gate if (parseonly) 623*7c478bd9Sstevel@tonic-gate syserr("X%s: empty or missing socket information", 624*7c478bd9Sstevel@tonic-gate m->mf_name); 625*7c478bd9Sstevel@tonic-gate else if (MilterLogLevel > 0) 626*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 627*7c478bd9Sstevel@tonic-gate "Milter (%s): empty or missing socket information", 628*7c478bd9Sstevel@tonic-gate m->mf_name); 629*7c478bd9Sstevel@tonic-gate milter_error(m, e); 630*7c478bd9Sstevel@tonic-gate return -1; 631*7c478bd9Sstevel@tonic-gate } 632*7c478bd9Sstevel@tonic-gate 633*7c478bd9Sstevel@tonic-gate /* protocol:filename or protocol:port@host */ 634*7c478bd9Sstevel@tonic-gate memset(&addr, '\0', sizeof addr); 635*7c478bd9Sstevel@tonic-gate p = m->mf_conn; 636*7c478bd9Sstevel@tonic-gate colon = strchr(p, ':'); 637*7c478bd9Sstevel@tonic-gate if (colon != NULL) 638*7c478bd9Sstevel@tonic-gate { 639*7c478bd9Sstevel@tonic-gate *colon = '\0'; 640*7c478bd9Sstevel@tonic-gate 641*7c478bd9Sstevel@tonic-gate if (*p == '\0') 642*7c478bd9Sstevel@tonic-gate { 643*7c478bd9Sstevel@tonic-gate # if NETUNIX 644*7c478bd9Sstevel@tonic-gate /* default to AF_UNIX */ 645*7c478bd9Sstevel@tonic-gate addr.sa.sa_family = AF_UNIX; 646*7c478bd9Sstevel@tonic-gate # else /* NETUNIX */ 647*7c478bd9Sstevel@tonic-gate # if NETINET 648*7c478bd9Sstevel@tonic-gate /* default to AF_INET */ 649*7c478bd9Sstevel@tonic-gate addr.sa.sa_family = AF_INET; 650*7c478bd9Sstevel@tonic-gate # else /* NETINET */ 651*7c478bd9Sstevel@tonic-gate # if NETINET6 652*7c478bd9Sstevel@tonic-gate /* default to AF_INET6 */ 653*7c478bd9Sstevel@tonic-gate addr.sa.sa_family = AF_INET6; 654*7c478bd9Sstevel@tonic-gate # else /* NETINET6 */ 655*7c478bd9Sstevel@tonic-gate /* no protocols available */ 656*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) 657*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 658*7c478bd9Sstevel@tonic-gate "Milter (%s): no valid socket protocols available", 659*7c478bd9Sstevel@tonic-gate m->mf_name); 660*7c478bd9Sstevel@tonic-gate milter_error(m, e); 661*7c478bd9Sstevel@tonic-gate return -1; 662*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 663*7c478bd9Sstevel@tonic-gate # endif /* NETINET */ 664*7c478bd9Sstevel@tonic-gate # endif /* NETUNIX */ 665*7c478bd9Sstevel@tonic-gate } 666*7c478bd9Sstevel@tonic-gate # if NETUNIX 667*7c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(p, "unix") == 0 || 668*7c478bd9Sstevel@tonic-gate sm_strcasecmp(p, "local") == 0) 669*7c478bd9Sstevel@tonic-gate addr.sa.sa_family = AF_UNIX; 670*7c478bd9Sstevel@tonic-gate # endif /* NETUNIX */ 671*7c478bd9Sstevel@tonic-gate # if NETINET 672*7c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(p, "inet") == 0) 673*7c478bd9Sstevel@tonic-gate addr.sa.sa_family = AF_INET; 674*7c478bd9Sstevel@tonic-gate # endif /* NETINET */ 675*7c478bd9Sstevel@tonic-gate # if NETINET6 676*7c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(p, "inet6") == 0) 677*7c478bd9Sstevel@tonic-gate addr.sa.sa_family = AF_INET6; 678*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 679*7c478bd9Sstevel@tonic-gate else 680*7c478bd9Sstevel@tonic-gate { 681*7c478bd9Sstevel@tonic-gate # ifdef EPROTONOSUPPORT 682*7c478bd9Sstevel@tonic-gate errno = EPROTONOSUPPORT; 683*7c478bd9Sstevel@tonic-gate # else /* EPROTONOSUPPORT */ 684*7c478bd9Sstevel@tonic-gate errno = EINVAL; 685*7c478bd9Sstevel@tonic-gate # endif /* EPROTONOSUPPORT */ 686*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 687*7c478bd9Sstevel@tonic-gate sm_dprintf("X%s: unknown socket type %s\n", 688*7c478bd9Sstevel@tonic-gate m->mf_name, p); 689*7c478bd9Sstevel@tonic-gate if (parseonly) 690*7c478bd9Sstevel@tonic-gate syserr("X%s: unknown socket type %s", 691*7c478bd9Sstevel@tonic-gate m->mf_name, p); 692*7c478bd9Sstevel@tonic-gate else if (MilterLogLevel > 0) 693*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 694*7c478bd9Sstevel@tonic-gate "Milter (%s): unknown socket type %s", 695*7c478bd9Sstevel@tonic-gate m->mf_name, p); 696*7c478bd9Sstevel@tonic-gate milter_error(m, e); 697*7c478bd9Sstevel@tonic-gate return -1; 698*7c478bd9Sstevel@tonic-gate } 699*7c478bd9Sstevel@tonic-gate *colon++ = ':'; 700*7c478bd9Sstevel@tonic-gate } 701*7c478bd9Sstevel@tonic-gate else 702*7c478bd9Sstevel@tonic-gate { 703*7c478bd9Sstevel@tonic-gate /* default to AF_UNIX */ 704*7c478bd9Sstevel@tonic-gate addr.sa.sa_family = AF_UNIX; 705*7c478bd9Sstevel@tonic-gate colon = p; 706*7c478bd9Sstevel@tonic-gate } 707*7c478bd9Sstevel@tonic-gate 708*7c478bd9Sstevel@tonic-gate # if NETUNIX 709*7c478bd9Sstevel@tonic-gate if (addr.sa.sa_family == AF_UNIX) 710*7c478bd9Sstevel@tonic-gate { 711*7c478bd9Sstevel@tonic-gate long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_EXECOK; 712*7c478bd9Sstevel@tonic-gate 713*7c478bd9Sstevel@tonic-gate at = colon; 714*7c478bd9Sstevel@tonic-gate if (strlen(colon) >= sizeof addr.sunix.sun_path) 715*7c478bd9Sstevel@tonic-gate { 716*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 717*7c478bd9Sstevel@tonic-gate sm_dprintf("X%s: local socket name %s too long\n", 718*7c478bd9Sstevel@tonic-gate m->mf_name, colon); 719*7c478bd9Sstevel@tonic-gate errno = EINVAL; 720*7c478bd9Sstevel@tonic-gate if (parseonly) 721*7c478bd9Sstevel@tonic-gate syserr("X%s: local socket name %s too long", 722*7c478bd9Sstevel@tonic-gate m->mf_name, colon); 723*7c478bd9Sstevel@tonic-gate else if (MilterLogLevel > 0) 724*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 725*7c478bd9Sstevel@tonic-gate "Milter (%s): local socket name %s too long", 726*7c478bd9Sstevel@tonic-gate m->mf_name, colon); 727*7c478bd9Sstevel@tonic-gate milter_error(m, e); 728*7c478bd9Sstevel@tonic-gate return -1; 729*7c478bd9Sstevel@tonic-gate } 730*7c478bd9Sstevel@tonic-gate errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff, 731*7c478bd9Sstevel@tonic-gate S_IRUSR|S_IWUSR, NULL); 732*7c478bd9Sstevel@tonic-gate 733*7c478bd9Sstevel@tonic-gate /* if just parsing .cf file, socket doesn't need to exist */ 734*7c478bd9Sstevel@tonic-gate if (parseonly && errno == ENOENT) 735*7c478bd9Sstevel@tonic-gate { 736*7c478bd9Sstevel@tonic-gate if (OpMode == MD_DAEMON || 737*7c478bd9Sstevel@tonic-gate OpMode == MD_FGDAEMON) 738*7c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 739*7c478bd9Sstevel@tonic-gate "WARNING: X%s: local socket name %s missing\n", 740*7c478bd9Sstevel@tonic-gate m->mf_name, colon); 741*7c478bd9Sstevel@tonic-gate } 742*7c478bd9Sstevel@tonic-gate else if (errno != 0) 743*7c478bd9Sstevel@tonic-gate { 744*7c478bd9Sstevel@tonic-gate /* if not safe, don't create */ 745*7c478bd9Sstevel@tonic-gate save_errno = errno; 746*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 747*7c478bd9Sstevel@tonic-gate sm_dprintf("X%s: local socket name %s unsafe\n", 748*7c478bd9Sstevel@tonic-gate m->mf_name, colon); 749*7c478bd9Sstevel@tonic-gate errno = save_errno; 750*7c478bd9Sstevel@tonic-gate if (parseonly) 751*7c478bd9Sstevel@tonic-gate { 752*7c478bd9Sstevel@tonic-gate if (OpMode == MD_DAEMON || 753*7c478bd9Sstevel@tonic-gate OpMode == MD_FGDAEMON || 754*7c478bd9Sstevel@tonic-gate OpMode == MD_SMTP) 755*7c478bd9Sstevel@tonic-gate syserr("X%s: local socket name %s unsafe", 756*7c478bd9Sstevel@tonic-gate m->mf_name, colon); 757*7c478bd9Sstevel@tonic-gate } 758*7c478bd9Sstevel@tonic-gate else if (MilterLogLevel > 0) 759*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 760*7c478bd9Sstevel@tonic-gate "Milter (%s): local socket name %s unsafe", 761*7c478bd9Sstevel@tonic-gate m->mf_name, colon); 762*7c478bd9Sstevel@tonic-gate milter_error(m, e); 763*7c478bd9Sstevel@tonic-gate return -1; 764*7c478bd9Sstevel@tonic-gate } 765*7c478bd9Sstevel@tonic-gate 766*7c478bd9Sstevel@tonic-gate (void) sm_strlcpy(addr.sunix.sun_path, colon, 767*7c478bd9Sstevel@tonic-gate sizeof addr.sunix.sun_path); 768*7c478bd9Sstevel@tonic-gate addrlen = sizeof (struct sockaddr_un); 769*7c478bd9Sstevel@tonic-gate } 770*7c478bd9Sstevel@tonic-gate else 771*7c478bd9Sstevel@tonic-gate # endif /* NETUNIX */ 772*7c478bd9Sstevel@tonic-gate # if NETINET || NETINET6 773*7c478bd9Sstevel@tonic-gate if (false 774*7c478bd9Sstevel@tonic-gate # if NETINET 775*7c478bd9Sstevel@tonic-gate || addr.sa.sa_family == AF_INET 776*7c478bd9Sstevel@tonic-gate # endif /* NETINET */ 777*7c478bd9Sstevel@tonic-gate # if NETINET6 778*7c478bd9Sstevel@tonic-gate || addr.sa.sa_family == AF_INET6 779*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 780*7c478bd9Sstevel@tonic-gate ) 781*7c478bd9Sstevel@tonic-gate { 782*7c478bd9Sstevel@tonic-gate unsigned short port; 783*7c478bd9Sstevel@tonic-gate 784*7c478bd9Sstevel@tonic-gate /* Parse port@host */ 785*7c478bd9Sstevel@tonic-gate at = strchr(colon, '@'); 786*7c478bd9Sstevel@tonic-gate if (at == NULL) 787*7c478bd9Sstevel@tonic-gate { 788*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 789*7c478bd9Sstevel@tonic-gate sm_dprintf("X%s: bad address %s (expected port@host)\n", 790*7c478bd9Sstevel@tonic-gate m->mf_name, colon); 791*7c478bd9Sstevel@tonic-gate if (parseonly) 792*7c478bd9Sstevel@tonic-gate syserr("X%s: bad address %s (expected port@host)", 793*7c478bd9Sstevel@tonic-gate m->mf_name, colon); 794*7c478bd9Sstevel@tonic-gate else if (MilterLogLevel > 0) 795*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 796*7c478bd9Sstevel@tonic-gate "Milter (%s): bad address %s (expected port@host)", 797*7c478bd9Sstevel@tonic-gate m->mf_name, colon); 798*7c478bd9Sstevel@tonic-gate milter_error(m, e); 799*7c478bd9Sstevel@tonic-gate return -1; 800*7c478bd9Sstevel@tonic-gate } 801*7c478bd9Sstevel@tonic-gate *at = '\0'; 802*7c478bd9Sstevel@tonic-gate if (isascii(*colon) && isdigit(*colon)) 803*7c478bd9Sstevel@tonic-gate port = htons((unsigned short) atoi(colon)); 804*7c478bd9Sstevel@tonic-gate else 805*7c478bd9Sstevel@tonic-gate { 806*7c478bd9Sstevel@tonic-gate # ifdef NO_GETSERVBYNAME 807*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 808*7c478bd9Sstevel@tonic-gate sm_dprintf("X%s: invalid port number %s\n", 809*7c478bd9Sstevel@tonic-gate m->mf_name, colon); 810*7c478bd9Sstevel@tonic-gate if (parseonly) 811*7c478bd9Sstevel@tonic-gate syserr("X%s: invalid port number %s", 812*7c478bd9Sstevel@tonic-gate m->mf_name, colon); 813*7c478bd9Sstevel@tonic-gate else if (MilterLogLevel > 0) 814*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 815*7c478bd9Sstevel@tonic-gate "Milter (%s): invalid port number %s", 816*7c478bd9Sstevel@tonic-gate m->mf_name, colon); 817*7c478bd9Sstevel@tonic-gate milter_error(m, e); 818*7c478bd9Sstevel@tonic-gate return -1; 819*7c478bd9Sstevel@tonic-gate # else /* NO_GETSERVBYNAME */ 820*7c478bd9Sstevel@tonic-gate register struct servent *sp; 821*7c478bd9Sstevel@tonic-gate 822*7c478bd9Sstevel@tonic-gate sp = getservbyname(colon, "tcp"); 823*7c478bd9Sstevel@tonic-gate if (sp == NULL) 824*7c478bd9Sstevel@tonic-gate { 825*7c478bd9Sstevel@tonic-gate save_errno = errno; 826*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 827*7c478bd9Sstevel@tonic-gate sm_dprintf("X%s: unknown port name %s\n", 828*7c478bd9Sstevel@tonic-gate m->mf_name, colon); 829*7c478bd9Sstevel@tonic-gate errno = save_errno; 830*7c478bd9Sstevel@tonic-gate if (parseonly) 831*7c478bd9Sstevel@tonic-gate syserr("X%s: unknown port name %s", 832*7c478bd9Sstevel@tonic-gate m->mf_name, colon); 833*7c478bd9Sstevel@tonic-gate else if (MilterLogLevel > 0) 834*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 835*7c478bd9Sstevel@tonic-gate "Milter (%s): unknown port name %s", 836*7c478bd9Sstevel@tonic-gate m->mf_name, colon); 837*7c478bd9Sstevel@tonic-gate milter_error(m, e); 838*7c478bd9Sstevel@tonic-gate return -1; 839*7c478bd9Sstevel@tonic-gate } 840*7c478bd9Sstevel@tonic-gate port = sp->s_port; 841*7c478bd9Sstevel@tonic-gate # endif /* NO_GETSERVBYNAME */ 842*7c478bd9Sstevel@tonic-gate } 843*7c478bd9Sstevel@tonic-gate *at++ = '@'; 844*7c478bd9Sstevel@tonic-gate if (*at == '[') 845*7c478bd9Sstevel@tonic-gate { 846*7c478bd9Sstevel@tonic-gate char *end; 847*7c478bd9Sstevel@tonic-gate 848*7c478bd9Sstevel@tonic-gate end = strchr(at, ']'); 849*7c478bd9Sstevel@tonic-gate if (end != NULL) 850*7c478bd9Sstevel@tonic-gate { 851*7c478bd9Sstevel@tonic-gate bool found = false; 852*7c478bd9Sstevel@tonic-gate # if NETINET 853*7c478bd9Sstevel@tonic-gate unsigned long hid = INADDR_NONE; 854*7c478bd9Sstevel@tonic-gate # endif /* NETINET */ 855*7c478bd9Sstevel@tonic-gate # if NETINET6 856*7c478bd9Sstevel@tonic-gate struct sockaddr_in6 hid6; 857*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 858*7c478bd9Sstevel@tonic-gate 859*7c478bd9Sstevel@tonic-gate *end = '\0'; 860*7c478bd9Sstevel@tonic-gate # if NETINET 861*7c478bd9Sstevel@tonic-gate if (addr.sa.sa_family == AF_INET && 862*7c478bd9Sstevel@tonic-gate (hid = inet_addr(&at[1])) != INADDR_NONE) 863*7c478bd9Sstevel@tonic-gate { 864*7c478bd9Sstevel@tonic-gate addr.sin.sin_addr.s_addr = hid; 865*7c478bd9Sstevel@tonic-gate addr.sin.sin_port = port; 866*7c478bd9Sstevel@tonic-gate found = true; 867*7c478bd9Sstevel@tonic-gate } 868*7c478bd9Sstevel@tonic-gate # endif /* NETINET */ 869*7c478bd9Sstevel@tonic-gate # if NETINET6 870*7c478bd9Sstevel@tonic-gate (void) memset(&hid6, '\0', sizeof hid6); 871*7c478bd9Sstevel@tonic-gate if (addr.sa.sa_family == AF_INET6 && 872*7c478bd9Sstevel@tonic-gate anynet_pton(AF_INET6, &at[1], 873*7c478bd9Sstevel@tonic-gate &hid6.sin6_addr) == 1) 874*7c478bd9Sstevel@tonic-gate { 875*7c478bd9Sstevel@tonic-gate addr.sin6.sin6_addr = hid6.sin6_addr; 876*7c478bd9Sstevel@tonic-gate addr.sin6.sin6_port = port; 877*7c478bd9Sstevel@tonic-gate found = true; 878*7c478bd9Sstevel@tonic-gate } 879*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 880*7c478bd9Sstevel@tonic-gate *end = ']'; 881*7c478bd9Sstevel@tonic-gate if (!found) 882*7c478bd9Sstevel@tonic-gate { 883*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 884*7c478bd9Sstevel@tonic-gate sm_dprintf("X%s: Invalid numeric domain spec \"%s\"\n", 885*7c478bd9Sstevel@tonic-gate m->mf_name, at); 886*7c478bd9Sstevel@tonic-gate if (parseonly) 887*7c478bd9Sstevel@tonic-gate syserr("X%s: Invalid numeric domain spec \"%s\"", 888*7c478bd9Sstevel@tonic-gate m->mf_name, at); 889*7c478bd9Sstevel@tonic-gate else if (MilterLogLevel > 0) 890*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 891*7c478bd9Sstevel@tonic-gate "Milter (%s): Invalid numeric domain spec \"%s\"", 892*7c478bd9Sstevel@tonic-gate m->mf_name, at); 893*7c478bd9Sstevel@tonic-gate milter_error(m, e); 894*7c478bd9Sstevel@tonic-gate return -1; 895*7c478bd9Sstevel@tonic-gate } 896*7c478bd9Sstevel@tonic-gate } 897*7c478bd9Sstevel@tonic-gate else 898*7c478bd9Sstevel@tonic-gate { 899*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 900*7c478bd9Sstevel@tonic-gate sm_dprintf("X%s: Invalid numeric domain spec \"%s\"\n", 901*7c478bd9Sstevel@tonic-gate m->mf_name, at); 902*7c478bd9Sstevel@tonic-gate if (parseonly) 903*7c478bd9Sstevel@tonic-gate syserr("X%s: Invalid numeric domain spec \"%s\"", 904*7c478bd9Sstevel@tonic-gate m->mf_name, at); 905*7c478bd9Sstevel@tonic-gate else if (MilterLogLevel > 0) 906*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 907*7c478bd9Sstevel@tonic-gate "Milter (%s): Invalid numeric domain spec \"%s\"", 908*7c478bd9Sstevel@tonic-gate m->mf_name, at); 909*7c478bd9Sstevel@tonic-gate milter_error(m, e); 910*7c478bd9Sstevel@tonic-gate return -1; 911*7c478bd9Sstevel@tonic-gate } 912*7c478bd9Sstevel@tonic-gate } 913*7c478bd9Sstevel@tonic-gate else 914*7c478bd9Sstevel@tonic-gate { 915*7c478bd9Sstevel@tonic-gate hp = sm_gethostbyname(at, addr.sa.sa_family); 916*7c478bd9Sstevel@tonic-gate if (hp == NULL) 917*7c478bd9Sstevel@tonic-gate { 918*7c478bd9Sstevel@tonic-gate save_errno = errno; 919*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 920*7c478bd9Sstevel@tonic-gate sm_dprintf("X%s: Unknown host name %s\n", 921*7c478bd9Sstevel@tonic-gate m->mf_name, at); 922*7c478bd9Sstevel@tonic-gate errno = save_errno; 923*7c478bd9Sstevel@tonic-gate if (parseonly) 924*7c478bd9Sstevel@tonic-gate syserr("X%s: Unknown host name %s", 925*7c478bd9Sstevel@tonic-gate m->mf_name, at); 926*7c478bd9Sstevel@tonic-gate else if (MilterLogLevel > 0) 927*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 928*7c478bd9Sstevel@tonic-gate "Milter (%s): Unknown host name %s", 929*7c478bd9Sstevel@tonic-gate m->mf_name, at); 930*7c478bd9Sstevel@tonic-gate milter_error(m, e); 931*7c478bd9Sstevel@tonic-gate return -1; 932*7c478bd9Sstevel@tonic-gate } 933*7c478bd9Sstevel@tonic-gate addr.sa.sa_family = hp->h_addrtype; 934*7c478bd9Sstevel@tonic-gate switch (hp->h_addrtype) 935*7c478bd9Sstevel@tonic-gate { 936*7c478bd9Sstevel@tonic-gate # if NETINET 937*7c478bd9Sstevel@tonic-gate case AF_INET: 938*7c478bd9Sstevel@tonic-gate memmove(&addr.sin.sin_addr, 939*7c478bd9Sstevel@tonic-gate hp->h_addr, INADDRSZ); 940*7c478bd9Sstevel@tonic-gate addr.sin.sin_port = port; 941*7c478bd9Sstevel@tonic-gate addrlen = sizeof (struct sockaddr_in); 942*7c478bd9Sstevel@tonic-gate addrno = 1; 943*7c478bd9Sstevel@tonic-gate break; 944*7c478bd9Sstevel@tonic-gate # endif /* NETINET */ 945*7c478bd9Sstevel@tonic-gate 946*7c478bd9Sstevel@tonic-gate # if NETINET6 947*7c478bd9Sstevel@tonic-gate case AF_INET6: 948*7c478bd9Sstevel@tonic-gate memmove(&addr.sin6.sin6_addr, 949*7c478bd9Sstevel@tonic-gate hp->h_addr, IN6ADDRSZ); 950*7c478bd9Sstevel@tonic-gate addr.sin6.sin6_port = port; 951*7c478bd9Sstevel@tonic-gate addrlen = sizeof (struct sockaddr_in6); 952*7c478bd9Sstevel@tonic-gate addrno = 1; 953*7c478bd9Sstevel@tonic-gate break; 954*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 955*7c478bd9Sstevel@tonic-gate 956*7c478bd9Sstevel@tonic-gate default: 957*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 958*7c478bd9Sstevel@tonic-gate sm_dprintf("X%s: Unknown protocol for %s (%d)\n", 959*7c478bd9Sstevel@tonic-gate m->mf_name, at, 960*7c478bd9Sstevel@tonic-gate hp->h_addrtype); 961*7c478bd9Sstevel@tonic-gate if (parseonly) 962*7c478bd9Sstevel@tonic-gate syserr("X%s: Unknown protocol for %s (%d)", 963*7c478bd9Sstevel@tonic-gate m->mf_name, at, hp->h_addrtype); 964*7c478bd9Sstevel@tonic-gate else if (MilterLogLevel > 0) 965*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 966*7c478bd9Sstevel@tonic-gate "Milter (%s): Unknown protocol for %s (%d)", 967*7c478bd9Sstevel@tonic-gate m->mf_name, at, 968*7c478bd9Sstevel@tonic-gate hp->h_addrtype); 969*7c478bd9Sstevel@tonic-gate milter_error(m, e); 970*7c478bd9Sstevel@tonic-gate # if NETINET6 971*7c478bd9Sstevel@tonic-gate freehostent(hp); 972*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 973*7c478bd9Sstevel@tonic-gate return -1; 974*7c478bd9Sstevel@tonic-gate } 975*7c478bd9Sstevel@tonic-gate } 976*7c478bd9Sstevel@tonic-gate } 977*7c478bd9Sstevel@tonic-gate else 978*7c478bd9Sstevel@tonic-gate # endif /* NETINET || NETINET6 */ 979*7c478bd9Sstevel@tonic-gate { 980*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 981*7c478bd9Sstevel@tonic-gate sm_dprintf("X%s: unknown socket protocol\n", 982*7c478bd9Sstevel@tonic-gate m->mf_name); 983*7c478bd9Sstevel@tonic-gate if (parseonly) 984*7c478bd9Sstevel@tonic-gate syserr("X%s: unknown socket protocol", m->mf_name); 985*7c478bd9Sstevel@tonic-gate else if (MilterLogLevel > 0) 986*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 987*7c478bd9Sstevel@tonic-gate "Milter (%s): unknown socket protocol", 988*7c478bd9Sstevel@tonic-gate m->mf_name); 989*7c478bd9Sstevel@tonic-gate milter_error(m, e); 990*7c478bd9Sstevel@tonic-gate return -1; 991*7c478bd9Sstevel@tonic-gate } 992*7c478bd9Sstevel@tonic-gate 993*7c478bd9Sstevel@tonic-gate /* just parsing through? */ 994*7c478bd9Sstevel@tonic-gate if (parseonly) 995*7c478bd9Sstevel@tonic-gate { 996*7c478bd9Sstevel@tonic-gate m->mf_state = SMFS_READY; 997*7c478bd9Sstevel@tonic-gate # if NETINET6 998*7c478bd9Sstevel@tonic-gate if (hp != NULL) 999*7c478bd9Sstevel@tonic-gate freehostent(hp); 1000*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 1001*7c478bd9Sstevel@tonic-gate return 0; 1002*7c478bd9Sstevel@tonic-gate } 1003*7c478bd9Sstevel@tonic-gate 1004*7c478bd9Sstevel@tonic-gate /* sanity check */ 1005*7c478bd9Sstevel@tonic-gate if (m->mf_state != SMFS_READY && 1006*7c478bd9Sstevel@tonic-gate m->mf_state != SMFS_CLOSED) 1007*7c478bd9Sstevel@tonic-gate { 1008*7c478bd9Sstevel@tonic-gate /* shouldn't happen */ 1009*7c478bd9Sstevel@tonic-gate if (tTd(64, 1)) 1010*7c478bd9Sstevel@tonic-gate sm_dprintf("Milter (%s): Trying to open filter in state %c\n", 1011*7c478bd9Sstevel@tonic-gate m->mf_name, (char) m->mf_state); 1012*7c478bd9Sstevel@tonic-gate milter_error(m, e); 1013*7c478bd9Sstevel@tonic-gate # if NETINET6 1014*7c478bd9Sstevel@tonic-gate if (hp != NULL) 1015*7c478bd9Sstevel@tonic-gate freehostent(hp); 1016*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 1017*7c478bd9Sstevel@tonic-gate return -1; 1018*7c478bd9Sstevel@tonic-gate } 1019*7c478bd9Sstevel@tonic-gate 1020*7c478bd9Sstevel@tonic-gate /* nope, actually connecting */ 1021*7c478bd9Sstevel@tonic-gate for (;;) 1022*7c478bd9Sstevel@tonic-gate { 1023*7c478bd9Sstevel@tonic-gate sock = socket(addr.sa.sa_family, SOCK_STREAM, 0); 1024*7c478bd9Sstevel@tonic-gate if (sock < 0) 1025*7c478bd9Sstevel@tonic-gate { 1026*7c478bd9Sstevel@tonic-gate save_errno = errno; 1027*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 1028*7c478bd9Sstevel@tonic-gate sm_dprintf("Milter (%s): error creating socket: %s\n", 1029*7c478bd9Sstevel@tonic-gate m->mf_name, 1030*7c478bd9Sstevel@tonic-gate sm_errstring(save_errno)); 1031*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) 1032*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 1033*7c478bd9Sstevel@tonic-gate "Milter (%s): error creating socket: %s", 1034*7c478bd9Sstevel@tonic-gate m->mf_name, sm_errstring(save_errno)); 1035*7c478bd9Sstevel@tonic-gate milter_error(m, e); 1036*7c478bd9Sstevel@tonic-gate # if NETINET6 1037*7c478bd9Sstevel@tonic-gate if (hp != NULL) 1038*7c478bd9Sstevel@tonic-gate freehostent(hp); 1039*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 1040*7c478bd9Sstevel@tonic-gate return -1; 1041*7c478bd9Sstevel@tonic-gate } 1042*7c478bd9Sstevel@tonic-gate 1043*7c478bd9Sstevel@tonic-gate if (setjmp(MilterConnectTimeout) == 0) 1044*7c478bd9Sstevel@tonic-gate { 1045*7c478bd9Sstevel@tonic-gate SM_EVENT *ev = NULL; 1046*7c478bd9Sstevel@tonic-gate int i; 1047*7c478bd9Sstevel@tonic-gate 1048*7c478bd9Sstevel@tonic-gate if (m->mf_timeout[SMFTO_CONNECT] > 0) 1049*7c478bd9Sstevel@tonic-gate ev = sm_setevent(m->mf_timeout[SMFTO_CONNECT], 1050*7c478bd9Sstevel@tonic-gate milter_connect_timeout, 0); 1051*7c478bd9Sstevel@tonic-gate 1052*7c478bd9Sstevel@tonic-gate i = connect(sock, (struct sockaddr *) &addr, addrlen); 1053*7c478bd9Sstevel@tonic-gate save_errno = errno; 1054*7c478bd9Sstevel@tonic-gate if (ev != NULL) 1055*7c478bd9Sstevel@tonic-gate sm_clrevent(ev); 1056*7c478bd9Sstevel@tonic-gate errno = save_errno; 1057*7c478bd9Sstevel@tonic-gate if (i >= 0) 1058*7c478bd9Sstevel@tonic-gate break; 1059*7c478bd9Sstevel@tonic-gate } 1060*7c478bd9Sstevel@tonic-gate 1061*7c478bd9Sstevel@tonic-gate /* couldn't connect.... try next address */ 1062*7c478bd9Sstevel@tonic-gate save_errno = errno; 1063*7c478bd9Sstevel@tonic-gate p = CurHostName; 1064*7c478bd9Sstevel@tonic-gate CurHostName = at; 1065*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 1066*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_open (%s): open %s failed: %s\n", 1067*7c478bd9Sstevel@tonic-gate m->mf_name, at, sm_errstring(save_errno)); 1068*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 13) 1069*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 1070*7c478bd9Sstevel@tonic-gate "Milter (%s): open %s failed: %s", 1071*7c478bd9Sstevel@tonic-gate m->mf_name, at, sm_errstring(save_errno)); 1072*7c478bd9Sstevel@tonic-gate CurHostName = p; 1073*7c478bd9Sstevel@tonic-gate (void) close(sock); 1074*7c478bd9Sstevel@tonic-gate 1075*7c478bd9Sstevel@tonic-gate /* try next address */ 1076*7c478bd9Sstevel@tonic-gate if (hp != NULL && hp->h_addr_list[addrno] != NULL) 1077*7c478bd9Sstevel@tonic-gate { 1078*7c478bd9Sstevel@tonic-gate switch (addr.sa.sa_family) 1079*7c478bd9Sstevel@tonic-gate { 1080*7c478bd9Sstevel@tonic-gate # if NETINET 1081*7c478bd9Sstevel@tonic-gate case AF_INET: 1082*7c478bd9Sstevel@tonic-gate memmove(&addr.sin.sin_addr, 1083*7c478bd9Sstevel@tonic-gate hp->h_addr_list[addrno++], 1084*7c478bd9Sstevel@tonic-gate INADDRSZ); 1085*7c478bd9Sstevel@tonic-gate break; 1086*7c478bd9Sstevel@tonic-gate # endif /* NETINET */ 1087*7c478bd9Sstevel@tonic-gate 1088*7c478bd9Sstevel@tonic-gate # if NETINET6 1089*7c478bd9Sstevel@tonic-gate case AF_INET6: 1090*7c478bd9Sstevel@tonic-gate memmove(&addr.sin6.sin6_addr, 1091*7c478bd9Sstevel@tonic-gate hp->h_addr_list[addrno++], 1092*7c478bd9Sstevel@tonic-gate IN6ADDRSZ); 1093*7c478bd9Sstevel@tonic-gate break; 1094*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 1095*7c478bd9Sstevel@tonic-gate 1096*7c478bd9Sstevel@tonic-gate default: 1097*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 1098*7c478bd9Sstevel@tonic-gate sm_dprintf("X%s: Unknown protocol for %s (%d)\n", 1099*7c478bd9Sstevel@tonic-gate m->mf_name, at, 1100*7c478bd9Sstevel@tonic-gate hp->h_addrtype); 1101*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) 1102*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 1103*7c478bd9Sstevel@tonic-gate "Milter (%s): Unknown protocol for %s (%d)", 1104*7c478bd9Sstevel@tonic-gate m->mf_name, at, 1105*7c478bd9Sstevel@tonic-gate hp->h_addrtype); 1106*7c478bd9Sstevel@tonic-gate milter_error(m, e); 1107*7c478bd9Sstevel@tonic-gate # if NETINET6 1108*7c478bd9Sstevel@tonic-gate freehostent(hp); 1109*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 1110*7c478bd9Sstevel@tonic-gate return -1; 1111*7c478bd9Sstevel@tonic-gate } 1112*7c478bd9Sstevel@tonic-gate continue; 1113*7c478bd9Sstevel@tonic-gate } 1114*7c478bd9Sstevel@tonic-gate p = CurHostName; 1115*7c478bd9Sstevel@tonic-gate CurHostName = at; 1116*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 1117*7c478bd9Sstevel@tonic-gate sm_dprintf("X%s: error connecting to filter: %s\n", 1118*7c478bd9Sstevel@tonic-gate m->mf_name, sm_errstring(save_errno)); 1119*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) 1120*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 1121*7c478bd9Sstevel@tonic-gate "Milter (%s): error connecting to filter: %s", 1122*7c478bd9Sstevel@tonic-gate m->mf_name, sm_errstring(save_errno)); 1123*7c478bd9Sstevel@tonic-gate CurHostName = p; 1124*7c478bd9Sstevel@tonic-gate milter_error(m, e); 1125*7c478bd9Sstevel@tonic-gate # if NETINET6 1126*7c478bd9Sstevel@tonic-gate if (hp != NULL) 1127*7c478bd9Sstevel@tonic-gate freehostent(hp); 1128*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 1129*7c478bd9Sstevel@tonic-gate return -1; 1130*7c478bd9Sstevel@tonic-gate } 1131*7c478bd9Sstevel@tonic-gate m->mf_state = SMFS_OPEN; 1132*7c478bd9Sstevel@tonic-gate # if NETINET6 1133*7c478bd9Sstevel@tonic-gate if (hp != NULL) 1134*7c478bd9Sstevel@tonic-gate { 1135*7c478bd9Sstevel@tonic-gate freehostent(hp); 1136*7c478bd9Sstevel@tonic-gate hp = NULL; 1137*7c478bd9Sstevel@tonic-gate } 1138*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 1139*7c478bd9Sstevel@tonic-gate # if _FFR_MILTER_NAGLE 1140*7c478bd9Sstevel@tonic-gate # ifndef TCP_CORK 1141*7c478bd9Sstevel@tonic-gate { 1142*7c478bd9Sstevel@tonic-gate int nodelay = 1; 1143*7c478bd9Sstevel@tonic-gate 1144*7c478bd9Sstevel@tonic-gate setsockopt(m->mf_sock, IPPROTO_TCP, TCP_NODELAY, 1145*7c478bd9Sstevel@tonic-gate (char *)&nodelay, sizeof(nodelay)); 1146*7c478bd9Sstevel@tonic-gate } 1147*7c478bd9Sstevel@tonic-gate # endif /* TCP_CORK */ 1148*7c478bd9Sstevel@tonic-gate # endif /* _FFR_MILTER_NAGLE */ 1149*7c478bd9Sstevel@tonic-gate return sock; 1150*7c478bd9Sstevel@tonic-gate } 1151*7c478bd9Sstevel@tonic-gate 1152*7c478bd9Sstevel@tonic-gate static void 1153*7c478bd9Sstevel@tonic-gate milter_connect_timeout(ignore) 1154*7c478bd9Sstevel@tonic-gate int ignore; 1155*7c478bd9Sstevel@tonic-gate { 1156*7c478bd9Sstevel@tonic-gate /* 1157*7c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 1158*7c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 1159*7c478bd9Sstevel@tonic-gate ** DOING. 1160*7c478bd9Sstevel@tonic-gate */ 1161*7c478bd9Sstevel@tonic-gate 1162*7c478bd9Sstevel@tonic-gate errno = ETIMEDOUT; 1163*7c478bd9Sstevel@tonic-gate longjmp(MilterConnectTimeout, 1); 1164*7c478bd9Sstevel@tonic-gate } 1165*7c478bd9Sstevel@tonic-gate /* 1166*7c478bd9Sstevel@tonic-gate ** MILTER_SETUP -- setup structure for a mail filter 1167*7c478bd9Sstevel@tonic-gate ** 1168*7c478bd9Sstevel@tonic-gate ** Parameters: 1169*7c478bd9Sstevel@tonic-gate ** line -- the options line. 1170*7c478bd9Sstevel@tonic-gate ** 1171*7c478bd9Sstevel@tonic-gate ** Returns: 1172*7c478bd9Sstevel@tonic-gate ** none 1173*7c478bd9Sstevel@tonic-gate */ 1174*7c478bd9Sstevel@tonic-gate 1175*7c478bd9Sstevel@tonic-gate void 1176*7c478bd9Sstevel@tonic-gate milter_setup(line) 1177*7c478bd9Sstevel@tonic-gate char *line; 1178*7c478bd9Sstevel@tonic-gate { 1179*7c478bd9Sstevel@tonic-gate char fcode; 1180*7c478bd9Sstevel@tonic-gate register char *p; 1181*7c478bd9Sstevel@tonic-gate register struct milter *m; 1182*7c478bd9Sstevel@tonic-gate STAB *s; 1183*7c478bd9Sstevel@tonic-gate 1184*7c478bd9Sstevel@tonic-gate /* collect the filter name */ 1185*7c478bd9Sstevel@tonic-gate for (p = line; 1186*7c478bd9Sstevel@tonic-gate *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); 1187*7c478bd9Sstevel@tonic-gate p++) 1188*7c478bd9Sstevel@tonic-gate continue; 1189*7c478bd9Sstevel@tonic-gate if (*p != '\0') 1190*7c478bd9Sstevel@tonic-gate *p++ = '\0'; 1191*7c478bd9Sstevel@tonic-gate if (line[0] == '\0') 1192*7c478bd9Sstevel@tonic-gate { 1193*7c478bd9Sstevel@tonic-gate syserr("name required for mail filter"); 1194*7c478bd9Sstevel@tonic-gate return; 1195*7c478bd9Sstevel@tonic-gate } 1196*7c478bd9Sstevel@tonic-gate m = (struct milter *) xalloc(sizeof *m); 1197*7c478bd9Sstevel@tonic-gate memset((char *) m, '\0', sizeof *m); 1198*7c478bd9Sstevel@tonic-gate m->mf_name = newstr(line); 1199*7c478bd9Sstevel@tonic-gate m->mf_state = SMFS_READY; 1200*7c478bd9Sstevel@tonic-gate m->mf_sock = -1; 1201*7c478bd9Sstevel@tonic-gate m->mf_timeout[SMFTO_CONNECT] = (time_t) 300; 1202*7c478bd9Sstevel@tonic-gate m->mf_timeout[SMFTO_WRITE] = (time_t) 10; 1203*7c478bd9Sstevel@tonic-gate m->mf_timeout[SMFTO_READ] = (time_t) 10; 1204*7c478bd9Sstevel@tonic-gate m->mf_timeout[SMFTO_EOM] = (time_t) 300; 1205*7c478bd9Sstevel@tonic-gate 1206*7c478bd9Sstevel@tonic-gate /* now scan through and assign info from the fields */ 1207*7c478bd9Sstevel@tonic-gate while (*p != '\0') 1208*7c478bd9Sstevel@tonic-gate { 1209*7c478bd9Sstevel@tonic-gate char *delimptr; 1210*7c478bd9Sstevel@tonic-gate 1211*7c478bd9Sstevel@tonic-gate while (*p != '\0' && 1212*7c478bd9Sstevel@tonic-gate (*p == ',' || (isascii(*p) && isspace(*p)))) 1213*7c478bd9Sstevel@tonic-gate p++; 1214*7c478bd9Sstevel@tonic-gate 1215*7c478bd9Sstevel@tonic-gate /* p now points to field code */ 1216*7c478bd9Sstevel@tonic-gate fcode = *p; 1217*7c478bd9Sstevel@tonic-gate while (*p != '\0' && *p != '=' && *p != ',') 1218*7c478bd9Sstevel@tonic-gate p++; 1219*7c478bd9Sstevel@tonic-gate if (*p++ != '=') 1220*7c478bd9Sstevel@tonic-gate { 1221*7c478bd9Sstevel@tonic-gate syserr("X%s: `=' expected", m->mf_name); 1222*7c478bd9Sstevel@tonic-gate return; 1223*7c478bd9Sstevel@tonic-gate } 1224*7c478bd9Sstevel@tonic-gate while (isascii(*p) && isspace(*p)) 1225*7c478bd9Sstevel@tonic-gate p++; 1226*7c478bd9Sstevel@tonic-gate 1227*7c478bd9Sstevel@tonic-gate /* p now points to the field body */ 1228*7c478bd9Sstevel@tonic-gate p = munchstring(p, &delimptr, ','); 1229*7c478bd9Sstevel@tonic-gate 1230*7c478bd9Sstevel@tonic-gate /* install the field into the filter struct */ 1231*7c478bd9Sstevel@tonic-gate switch (fcode) 1232*7c478bd9Sstevel@tonic-gate { 1233*7c478bd9Sstevel@tonic-gate case 'S': /* socket */ 1234*7c478bd9Sstevel@tonic-gate if (p == NULL) 1235*7c478bd9Sstevel@tonic-gate m->mf_conn = NULL; 1236*7c478bd9Sstevel@tonic-gate else 1237*7c478bd9Sstevel@tonic-gate m->mf_conn = newstr(p); 1238*7c478bd9Sstevel@tonic-gate break; 1239*7c478bd9Sstevel@tonic-gate 1240*7c478bd9Sstevel@tonic-gate case 'F': /* Milter flags configured on MTA */ 1241*7c478bd9Sstevel@tonic-gate for (; *p != '\0'; p++) 1242*7c478bd9Sstevel@tonic-gate { 1243*7c478bd9Sstevel@tonic-gate if (!(isascii(*p) && isspace(*p))) 1244*7c478bd9Sstevel@tonic-gate setbitn(bitidx(*p), m->mf_flags); 1245*7c478bd9Sstevel@tonic-gate } 1246*7c478bd9Sstevel@tonic-gate break; 1247*7c478bd9Sstevel@tonic-gate 1248*7c478bd9Sstevel@tonic-gate case 'T': /* timeouts */ 1249*7c478bd9Sstevel@tonic-gate milter_parse_timeouts(p, m); 1250*7c478bd9Sstevel@tonic-gate break; 1251*7c478bd9Sstevel@tonic-gate 1252*7c478bd9Sstevel@tonic-gate default: 1253*7c478bd9Sstevel@tonic-gate syserr("X%s: unknown filter equate %c=", 1254*7c478bd9Sstevel@tonic-gate m->mf_name, fcode); 1255*7c478bd9Sstevel@tonic-gate break; 1256*7c478bd9Sstevel@tonic-gate } 1257*7c478bd9Sstevel@tonic-gate p = delimptr; 1258*7c478bd9Sstevel@tonic-gate } 1259*7c478bd9Sstevel@tonic-gate 1260*7c478bd9Sstevel@tonic-gate /* early check for errors */ 1261*7c478bd9Sstevel@tonic-gate (void) milter_open(m, true, CurEnv); 1262*7c478bd9Sstevel@tonic-gate 1263*7c478bd9Sstevel@tonic-gate /* enter the filter into the symbol table */ 1264*7c478bd9Sstevel@tonic-gate s = stab(m->mf_name, ST_MILTER, ST_ENTER); 1265*7c478bd9Sstevel@tonic-gate if (s->s_milter != NULL) 1266*7c478bd9Sstevel@tonic-gate syserr("X%s: duplicate filter definition", m->mf_name); 1267*7c478bd9Sstevel@tonic-gate else 1268*7c478bd9Sstevel@tonic-gate s->s_milter = m; 1269*7c478bd9Sstevel@tonic-gate } 1270*7c478bd9Sstevel@tonic-gate /* 1271*7c478bd9Sstevel@tonic-gate ** MILTER_CONFIG -- parse option list into an array and check config 1272*7c478bd9Sstevel@tonic-gate ** 1273*7c478bd9Sstevel@tonic-gate ** Called when reading configuration file. 1274*7c478bd9Sstevel@tonic-gate ** 1275*7c478bd9Sstevel@tonic-gate ** Parameters: 1276*7c478bd9Sstevel@tonic-gate ** spec -- the filter list. 1277*7c478bd9Sstevel@tonic-gate ** list -- the array to fill in. 1278*7c478bd9Sstevel@tonic-gate ** max -- the maximum number of entries in list. 1279*7c478bd9Sstevel@tonic-gate ** 1280*7c478bd9Sstevel@tonic-gate ** Returns: 1281*7c478bd9Sstevel@tonic-gate ** none 1282*7c478bd9Sstevel@tonic-gate */ 1283*7c478bd9Sstevel@tonic-gate 1284*7c478bd9Sstevel@tonic-gate void 1285*7c478bd9Sstevel@tonic-gate milter_config(spec, list, max) 1286*7c478bd9Sstevel@tonic-gate char *spec; 1287*7c478bd9Sstevel@tonic-gate struct milter **list; 1288*7c478bd9Sstevel@tonic-gate int max; 1289*7c478bd9Sstevel@tonic-gate { 1290*7c478bd9Sstevel@tonic-gate int numitems = 0; 1291*7c478bd9Sstevel@tonic-gate register char *p; 1292*7c478bd9Sstevel@tonic-gate 1293*7c478bd9Sstevel@tonic-gate /* leave one for the NULL signifying the end of the list */ 1294*7c478bd9Sstevel@tonic-gate max--; 1295*7c478bd9Sstevel@tonic-gate 1296*7c478bd9Sstevel@tonic-gate for (p = spec; p != NULL; ) 1297*7c478bd9Sstevel@tonic-gate { 1298*7c478bd9Sstevel@tonic-gate STAB *s; 1299*7c478bd9Sstevel@tonic-gate 1300*7c478bd9Sstevel@tonic-gate while (isascii(*p) && isspace(*p)) 1301*7c478bd9Sstevel@tonic-gate p++; 1302*7c478bd9Sstevel@tonic-gate if (*p == '\0') 1303*7c478bd9Sstevel@tonic-gate break; 1304*7c478bd9Sstevel@tonic-gate spec = p; 1305*7c478bd9Sstevel@tonic-gate 1306*7c478bd9Sstevel@tonic-gate if (numitems >= max) 1307*7c478bd9Sstevel@tonic-gate { 1308*7c478bd9Sstevel@tonic-gate syserr("Too many filters defined, %d max", max); 1309*7c478bd9Sstevel@tonic-gate if (max > 0) 1310*7c478bd9Sstevel@tonic-gate list[0] = NULL; 1311*7c478bd9Sstevel@tonic-gate return; 1312*7c478bd9Sstevel@tonic-gate } 1313*7c478bd9Sstevel@tonic-gate p = strpbrk(p, ";,"); 1314*7c478bd9Sstevel@tonic-gate if (p != NULL) 1315*7c478bd9Sstevel@tonic-gate *p++ = '\0'; 1316*7c478bd9Sstevel@tonic-gate 1317*7c478bd9Sstevel@tonic-gate s = stab(spec, ST_MILTER, ST_FIND); 1318*7c478bd9Sstevel@tonic-gate if (s == NULL) 1319*7c478bd9Sstevel@tonic-gate { 1320*7c478bd9Sstevel@tonic-gate syserr("InputFilter %s not defined", spec); 1321*7c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG; 1322*7c478bd9Sstevel@tonic-gate return; 1323*7c478bd9Sstevel@tonic-gate } 1324*7c478bd9Sstevel@tonic-gate list[numitems++] = s->s_milter; 1325*7c478bd9Sstevel@tonic-gate } 1326*7c478bd9Sstevel@tonic-gate list[numitems] = NULL; 1327*7c478bd9Sstevel@tonic-gate 1328*7c478bd9Sstevel@tonic-gate /* if not set, set to LogLevel */ 1329*7c478bd9Sstevel@tonic-gate if (MilterLogLevel == -1) 1330*7c478bd9Sstevel@tonic-gate MilterLogLevel = LogLevel; 1331*7c478bd9Sstevel@tonic-gate } 1332*7c478bd9Sstevel@tonic-gate /* 1333*7c478bd9Sstevel@tonic-gate ** MILTER_PARSE_TIMEOUTS -- parse timeout list 1334*7c478bd9Sstevel@tonic-gate ** 1335*7c478bd9Sstevel@tonic-gate ** Called when reading configuration file. 1336*7c478bd9Sstevel@tonic-gate ** 1337*7c478bd9Sstevel@tonic-gate ** Parameters: 1338*7c478bd9Sstevel@tonic-gate ** spec -- the timeout list. 1339*7c478bd9Sstevel@tonic-gate ** m -- milter to set. 1340*7c478bd9Sstevel@tonic-gate ** 1341*7c478bd9Sstevel@tonic-gate ** Returns: 1342*7c478bd9Sstevel@tonic-gate ** none 1343*7c478bd9Sstevel@tonic-gate */ 1344*7c478bd9Sstevel@tonic-gate 1345*7c478bd9Sstevel@tonic-gate static void 1346*7c478bd9Sstevel@tonic-gate milter_parse_timeouts(spec, m) 1347*7c478bd9Sstevel@tonic-gate char *spec; 1348*7c478bd9Sstevel@tonic-gate struct milter *m; 1349*7c478bd9Sstevel@tonic-gate { 1350*7c478bd9Sstevel@tonic-gate char fcode; 1351*7c478bd9Sstevel@tonic-gate int tcode; 1352*7c478bd9Sstevel@tonic-gate register char *p; 1353*7c478bd9Sstevel@tonic-gate 1354*7c478bd9Sstevel@tonic-gate p = spec; 1355*7c478bd9Sstevel@tonic-gate 1356*7c478bd9Sstevel@tonic-gate /* now scan through and assign info from the fields */ 1357*7c478bd9Sstevel@tonic-gate while (*p != '\0') 1358*7c478bd9Sstevel@tonic-gate { 1359*7c478bd9Sstevel@tonic-gate char *delimptr; 1360*7c478bd9Sstevel@tonic-gate 1361*7c478bd9Sstevel@tonic-gate while (*p != '\0' && 1362*7c478bd9Sstevel@tonic-gate (*p == ';' || (isascii(*p) && isspace(*p)))) 1363*7c478bd9Sstevel@tonic-gate p++; 1364*7c478bd9Sstevel@tonic-gate 1365*7c478bd9Sstevel@tonic-gate /* p now points to field code */ 1366*7c478bd9Sstevel@tonic-gate fcode = *p; 1367*7c478bd9Sstevel@tonic-gate while (*p != '\0' && *p != ':') 1368*7c478bd9Sstevel@tonic-gate p++; 1369*7c478bd9Sstevel@tonic-gate if (*p++ != ':') 1370*7c478bd9Sstevel@tonic-gate { 1371*7c478bd9Sstevel@tonic-gate syserr("X%s, T=: `:' expected", m->mf_name); 1372*7c478bd9Sstevel@tonic-gate return; 1373*7c478bd9Sstevel@tonic-gate } 1374*7c478bd9Sstevel@tonic-gate while (isascii(*p) && isspace(*p)) 1375*7c478bd9Sstevel@tonic-gate p++; 1376*7c478bd9Sstevel@tonic-gate 1377*7c478bd9Sstevel@tonic-gate /* p now points to the field body */ 1378*7c478bd9Sstevel@tonic-gate p = munchstring(p, &delimptr, ';'); 1379*7c478bd9Sstevel@tonic-gate tcode = -1; 1380*7c478bd9Sstevel@tonic-gate 1381*7c478bd9Sstevel@tonic-gate /* install the field into the filter struct */ 1382*7c478bd9Sstevel@tonic-gate switch (fcode) 1383*7c478bd9Sstevel@tonic-gate { 1384*7c478bd9Sstevel@tonic-gate case 'C': 1385*7c478bd9Sstevel@tonic-gate tcode = SMFTO_CONNECT; 1386*7c478bd9Sstevel@tonic-gate break; 1387*7c478bd9Sstevel@tonic-gate 1388*7c478bd9Sstevel@tonic-gate case 'S': 1389*7c478bd9Sstevel@tonic-gate tcode = SMFTO_WRITE; 1390*7c478bd9Sstevel@tonic-gate break; 1391*7c478bd9Sstevel@tonic-gate 1392*7c478bd9Sstevel@tonic-gate case 'R': 1393*7c478bd9Sstevel@tonic-gate tcode = SMFTO_READ; 1394*7c478bd9Sstevel@tonic-gate break; 1395*7c478bd9Sstevel@tonic-gate 1396*7c478bd9Sstevel@tonic-gate case 'E': 1397*7c478bd9Sstevel@tonic-gate tcode = SMFTO_EOM; 1398*7c478bd9Sstevel@tonic-gate break; 1399*7c478bd9Sstevel@tonic-gate 1400*7c478bd9Sstevel@tonic-gate default: 1401*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 1402*7c478bd9Sstevel@tonic-gate sm_dprintf("X%s: %c unknown\n", 1403*7c478bd9Sstevel@tonic-gate m->mf_name, fcode); 1404*7c478bd9Sstevel@tonic-gate syserr("X%s: unknown filter timeout %c", 1405*7c478bd9Sstevel@tonic-gate m->mf_name, fcode); 1406*7c478bd9Sstevel@tonic-gate break; 1407*7c478bd9Sstevel@tonic-gate } 1408*7c478bd9Sstevel@tonic-gate if (tcode >= 0) 1409*7c478bd9Sstevel@tonic-gate { 1410*7c478bd9Sstevel@tonic-gate m->mf_timeout[tcode] = convtime(p, 's'); 1411*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 1412*7c478bd9Sstevel@tonic-gate sm_dprintf("X%s: %c=%ld\n", 1413*7c478bd9Sstevel@tonic-gate m->mf_name, fcode, 1414*7c478bd9Sstevel@tonic-gate (u_long) m->mf_timeout[tcode]); 1415*7c478bd9Sstevel@tonic-gate } 1416*7c478bd9Sstevel@tonic-gate p = delimptr; 1417*7c478bd9Sstevel@tonic-gate } 1418*7c478bd9Sstevel@tonic-gate } 1419*7c478bd9Sstevel@tonic-gate /* 1420*7c478bd9Sstevel@tonic-gate ** MILTER_SET_OPTION -- set an individual milter option 1421*7c478bd9Sstevel@tonic-gate ** 1422*7c478bd9Sstevel@tonic-gate ** Parameters: 1423*7c478bd9Sstevel@tonic-gate ** name -- the name of the option. 1424*7c478bd9Sstevel@tonic-gate ** val -- the value of the option. 1425*7c478bd9Sstevel@tonic-gate ** sticky -- if set, don't let other setoptions override 1426*7c478bd9Sstevel@tonic-gate ** this value. 1427*7c478bd9Sstevel@tonic-gate ** 1428*7c478bd9Sstevel@tonic-gate ** Returns: 1429*7c478bd9Sstevel@tonic-gate ** none. 1430*7c478bd9Sstevel@tonic-gate */ 1431*7c478bd9Sstevel@tonic-gate 1432*7c478bd9Sstevel@tonic-gate /* set if Milter sub-option is stuck */ 1433*7c478bd9Sstevel@tonic-gate static BITMAP256 StickyMilterOpt; 1434*7c478bd9Sstevel@tonic-gate 1435*7c478bd9Sstevel@tonic-gate static struct milteropt 1436*7c478bd9Sstevel@tonic-gate { 1437*7c478bd9Sstevel@tonic-gate char *mo_name; /* long name of milter option */ 1438*7c478bd9Sstevel@tonic-gate unsigned char mo_code; /* code for option */ 1439*7c478bd9Sstevel@tonic-gate } MilterOptTab[] = 1440*7c478bd9Sstevel@tonic-gate { 1441*7c478bd9Sstevel@tonic-gate # define MO_MACROS_CONNECT 0x01 1442*7c478bd9Sstevel@tonic-gate { "macros.connect", MO_MACROS_CONNECT }, 1443*7c478bd9Sstevel@tonic-gate # define MO_MACROS_HELO 0x02 1444*7c478bd9Sstevel@tonic-gate { "macros.helo", MO_MACROS_HELO }, 1445*7c478bd9Sstevel@tonic-gate # define MO_MACROS_ENVFROM 0x03 1446*7c478bd9Sstevel@tonic-gate { "macros.envfrom", MO_MACROS_ENVFROM }, 1447*7c478bd9Sstevel@tonic-gate # define MO_MACROS_ENVRCPT 0x04 1448*7c478bd9Sstevel@tonic-gate { "macros.envrcpt", MO_MACROS_ENVRCPT }, 1449*7c478bd9Sstevel@tonic-gate # define MO_MACROS_DATA 0x05 1450*7c478bd9Sstevel@tonic-gate { "macros.data", MO_MACROS_DATA }, 1451*7c478bd9Sstevel@tonic-gate # define MO_MACROS_EOM 0x06 1452*7c478bd9Sstevel@tonic-gate { "macros.eom", MO_MACROS_EOM }, 1453*7c478bd9Sstevel@tonic-gate # define MO_LOGLEVEL 0x07 1454*7c478bd9Sstevel@tonic-gate { "loglevel", MO_LOGLEVEL }, 1455*7c478bd9Sstevel@tonic-gate # if _FFR_MAXDATASIZE 1456*7c478bd9Sstevel@tonic-gate # define MO_MAXDATASIZE 0x08 1457*7c478bd9Sstevel@tonic-gate { "maxdatasize", MO_MAXDATASIZE }, 1458*7c478bd9Sstevel@tonic-gate # endif /* _FFR_MAXDATASIZE */ 1459*7c478bd9Sstevel@tonic-gate { NULL, 0 }, 1460*7c478bd9Sstevel@tonic-gate }; 1461*7c478bd9Sstevel@tonic-gate 1462*7c478bd9Sstevel@tonic-gate void 1463*7c478bd9Sstevel@tonic-gate milter_set_option(name, val, sticky) 1464*7c478bd9Sstevel@tonic-gate char *name; 1465*7c478bd9Sstevel@tonic-gate char *val; 1466*7c478bd9Sstevel@tonic-gate bool sticky; 1467*7c478bd9Sstevel@tonic-gate { 1468*7c478bd9Sstevel@tonic-gate int nummac = 0; 1469*7c478bd9Sstevel@tonic-gate register struct milteropt *mo; 1470*7c478bd9Sstevel@tonic-gate char *p; 1471*7c478bd9Sstevel@tonic-gate char **macros = NULL; 1472*7c478bd9Sstevel@tonic-gate 1473*7c478bd9Sstevel@tonic-gate if (tTd(37, 2) || tTd(64, 5)) 1474*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_set_option(%s = %s)", name, val); 1475*7c478bd9Sstevel@tonic-gate 1476*7c478bd9Sstevel@tonic-gate if (name == NULL) 1477*7c478bd9Sstevel@tonic-gate { 1478*7c478bd9Sstevel@tonic-gate syserr("milter_set_option: invalid Milter option, must specify suboption"); 1479*7c478bd9Sstevel@tonic-gate return; 1480*7c478bd9Sstevel@tonic-gate } 1481*7c478bd9Sstevel@tonic-gate 1482*7c478bd9Sstevel@tonic-gate for (mo = MilterOptTab; mo->mo_name != NULL; mo++) 1483*7c478bd9Sstevel@tonic-gate { 1484*7c478bd9Sstevel@tonic-gate if (sm_strcasecmp(mo->mo_name, name) == 0) 1485*7c478bd9Sstevel@tonic-gate break; 1486*7c478bd9Sstevel@tonic-gate } 1487*7c478bd9Sstevel@tonic-gate 1488*7c478bd9Sstevel@tonic-gate if (mo->mo_name == NULL) 1489*7c478bd9Sstevel@tonic-gate { 1490*7c478bd9Sstevel@tonic-gate syserr("milter_set_option: invalid Milter option %s", name); 1491*7c478bd9Sstevel@tonic-gate return; 1492*7c478bd9Sstevel@tonic-gate } 1493*7c478bd9Sstevel@tonic-gate 1494*7c478bd9Sstevel@tonic-gate /* 1495*7c478bd9Sstevel@tonic-gate ** See if this option is preset for us. 1496*7c478bd9Sstevel@tonic-gate */ 1497*7c478bd9Sstevel@tonic-gate 1498*7c478bd9Sstevel@tonic-gate if (!sticky && bitnset(mo->mo_code, StickyMilterOpt)) 1499*7c478bd9Sstevel@tonic-gate { 1500*7c478bd9Sstevel@tonic-gate if (tTd(37, 2) || tTd(64,5)) 1501*7c478bd9Sstevel@tonic-gate sm_dprintf(" (ignored)\n"); 1502*7c478bd9Sstevel@tonic-gate return; 1503*7c478bd9Sstevel@tonic-gate } 1504*7c478bd9Sstevel@tonic-gate 1505*7c478bd9Sstevel@tonic-gate if (tTd(37, 2) || tTd(64,5)) 1506*7c478bd9Sstevel@tonic-gate sm_dprintf("\n"); 1507*7c478bd9Sstevel@tonic-gate 1508*7c478bd9Sstevel@tonic-gate switch (mo->mo_code) 1509*7c478bd9Sstevel@tonic-gate { 1510*7c478bd9Sstevel@tonic-gate case MO_LOGLEVEL: 1511*7c478bd9Sstevel@tonic-gate MilterLogLevel = atoi(val); 1512*7c478bd9Sstevel@tonic-gate break; 1513*7c478bd9Sstevel@tonic-gate 1514*7c478bd9Sstevel@tonic-gate #if _FFR_MAXDATASIZE 1515*7c478bd9Sstevel@tonic-gate case MO_MAXDATASIZE: 1516*7c478bd9Sstevel@tonic-gate MilterMaxDataSize = (size_t)atol(val); 1517*7c478bd9Sstevel@tonic-gate break; 1518*7c478bd9Sstevel@tonic-gate #endif /* _FFR_MAXDATASIZE */ 1519*7c478bd9Sstevel@tonic-gate 1520*7c478bd9Sstevel@tonic-gate case MO_MACROS_CONNECT: 1521*7c478bd9Sstevel@tonic-gate if (macros == NULL) 1522*7c478bd9Sstevel@tonic-gate macros = MilterConnectMacros; 1523*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 1524*7c478bd9Sstevel@tonic-gate 1525*7c478bd9Sstevel@tonic-gate case MO_MACROS_HELO: 1526*7c478bd9Sstevel@tonic-gate if (macros == NULL) 1527*7c478bd9Sstevel@tonic-gate macros = MilterHeloMacros; 1528*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 1529*7c478bd9Sstevel@tonic-gate 1530*7c478bd9Sstevel@tonic-gate case MO_MACROS_ENVFROM: 1531*7c478bd9Sstevel@tonic-gate if (macros == NULL) 1532*7c478bd9Sstevel@tonic-gate macros = MilterEnvFromMacros; 1533*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 1534*7c478bd9Sstevel@tonic-gate 1535*7c478bd9Sstevel@tonic-gate case MO_MACROS_ENVRCPT: 1536*7c478bd9Sstevel@tonic-gate if (macros == NULL) 1537*7c478bd9Sstevel@tonic-gate macros = MilterEnvRcptMacros; 1538*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 1539*7c478bd9Sstevel@tonic-gate 1540*7c478bd9Sstevel@tonic-gate case MO_MACROS_EOM: 1541*7c478bd9Sstevel@tonic-gate if (macros == NULL) 1542*7c478bd9Sstevel@tonic-gate macros = MilterEOMMacros; 1543*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 1544*7c478bd9Sstevel@tonic-gate 1545*7c478bd9Sstevel@tonic-gate case MO_MACROS_DATA: 1546*7c478bd9Sstevel@tonic-gate if (macros == NULL) 1547*7c478bd9Sstevel@tonic-gate macros = MilterDataMacros; 1548*7c478bd9Sstevel@tonic-gate 1549*7c478bd9Sstevel@tonic-gate p = newstr(val); 1550*7c478bd9Sstevel@tonic-gate while (*p != '\0') 1551*7c478bd9Sstevel@tonic-gate { 1552*7c478bd9Sstevel@tonic-gate char *macro; 1553*7c478bd9Sstevel@tonic-gate 1554*7c478bd9Sstevel@tonic-gate /* Skip leading commas, spaces */ 1555*7c478bd9Sstevel@tonic-gate while (*p != '\0' && 1556*7c478bd9Sstevel@tonic-gate (*p == ',' || (isascii(*p) && isspace(*p)))) 1557*7c478bd9Sstevel@tonic-gate p++; 1558*7c478bd9Sstevel@tonic-gate 1559*7c478bd9Sstevel@tonic-gate if (*p == '\0') 1560*7c478bd9Sstevel@tonic-gate break; 1561*7c478bd9Sstevel@tonic-gate 1562*7c478bd9Sstevel@tonic-gate /* Find end of macro */ 1563*7c478bd9Sstevel@tonic-gate macro = p; 1564*7c478bd9Sstevel@tonic-gate while (*p != '\0' && *p != ',' && 1565*7c478bd9Sstevel@tonic-gate isascii(*p) && !isspace(*p)) 1566*7c478bd9Sstevel@tonic-gate p++; 1567*7c478bd9Sstevel@tonic-gate if (*p != '\0') 1568*7c478bd9Sstevel@tonic-gate *p++ = '\0'; 1569*7c478bd9Sstevel@tonic-gate 1570*7c478bd9Sstevel@tonic-gate if (nummac >= MAXFILTERMACROS) 1571*7c478bd9Sstevel@tonic-gate { 1572*7c478bd9Sstevel@tonic-gate syserr("milter_set_option: too many macros in Milter.%s (max %d)", 1573*7c478bd9Sstevel@tonic-gate name, MAXFILTERMACROS); 1574*7c478bd9Sstevel@tonic-gate macros[nummac] = NULL; 1575*7c478bd9Sstevel@tonic-gate break; 1576*7c478bd9Sstevel@tonic-gate } 1577*7c478bd9Sstevel@tonic-gate macros[nummac++] = macro; 1578*7c478bd9Sstevel@tonic-gate } 1579*7c478bd9Sstevel@tonic-gate macros[nummac] = NULL; 1580*7c478bd9Sstevel@tonic-gate break; 1581*7c478bd9Sstevel@tonic-gate 1582*7c478bd9Sstevel@tonic-gate default: 1583*7c478bd9Sstevel@tonic-gate syserr("milter_set_option: invalid Milter option %s", name); 1584*7c478bd9Sstevel@tonic-gate break; 1585*7c478bd9Sstevel@tonic-gate } 1586*7c478bd9Sstevel@tonic-gate if (sticky) 1587*7c478bd9Sstevel@tonic-gate setbitn(mo->mo_code, StickyMilterOpt); 1588*7c478bd9Sstevel@tonic-gate } 1589*7c478bd9Sstevel@tonic-gate /* 1590*7c478bd9Sstevel@tonic-gate ** MILTER_REOPEN_DF -- open & truncate the data file (for replbody) 1591*7c478bd9Sstevel@tonic-gate ** 1592*7c478bd9Sstevel@tonic-gate ** Parameters: 1593*7c478bd9Sstevel@tonic-gate ** e -- current envelope. 1594*7c478bd9Sstevel@tonic-gate ** 1595*7c478bd9Sstevel@tonic-gate ** Returns: 1596*7c478bd9Sstevel@tonic-gate ** 0 if succesful, -1 otherwise 1597*7c478bd9Sstevel@tonic-gate */ 1598*7c478bd9Sstevel@tonic-gate 1599*7c478bd9Sstevel@tonic-gate static int 1600*7c478bd9Sstevel@tonic-gate milter_reopen_df(e) 1601*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 1602*7c478bd9Sstevel@tonic-gate { 1603*7c478bd9Sstevel@tonic-gate char dfname[MAXPATHLEN]; 1604*7c478bd9Sstevel@tonic-gate 1605*7c478bd9Sstevel@tonic-gate (void) sm_strlcpy(dfname, queuename(e, DATAFL_LETTER), sizeof dfname); 1606*7c478bd9Sstevel@tonic-gate 1607*7c478bd9Sstevel@tonic-gate /* 1608*7c478bd9Sstevel@tonic-gate ** In SuperSafe == SAFE_REALLY mode, e->e_dfp is a read-only FP so 1609*7c478bd9Sstevel@tonic-gate ** close and reopen writable (later close and reopen 1610*7c478bd9Sstevel@tonic-gate ** read only again). 1611*7c478bd9Sstevel@tonic-gate ** 1612*7c478bd9Sstevel@tonic-gate ** In SuperSafe != SAFE_REALLY mode, e->e_dfp still points at the 1613*7c478bd9Sstevel@tonic-gate ** buffered file I/O descriptor, still open for writing so there 1614*7c478bd9Sstevel@tonic-gate ** isn't any work to do here (except checking for consistency). 1615*7c478bd9Sstevel@tonic-gate */ 1616*7c478bd9Sstevel@tonic-gate 1617*7c478bd9Sstevel@tonic-gate if (SuperSafe == SAFE_REALLY) 1618*7c478bd9Sstevel@tonic-gate { 1619*7c478bd9Sstevel@tonic-gate /* close read-only data file */ 1620*7c478bd9Sstevel@tonic-gate if (bitset(EF_HAS_DF, e->e_flags) && e->e_dfp != NULL) 1621*7c478bd9Sstevel@tonic-gate { 1622*7c478bd9Sstevel@tonic-gate (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT); 1623*7c478bd9Sstevel@tonic-gate e->e_flags &= ~EF_HAS_DF; 1624*7c478bd9Sstevel@tonic-gate } 1625*7c478bd9Sstevel@tonic-gate 1626*7c478bd9Sstevel@tonic-gate /* open writable */ 1627*7c478bd9Sstevel@tonic-gate if ((e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname, 1628*7c478bd9Sstevel@tonic-gate SM_IO_RDWR_B, NULL)) == NULL) 1629*7c478bd9Sstevel@tonic-gate { 1630*7c478bd9Sstevel@tonic-gate MILTER_DF_ERROR("milter_reopen_df: sm_io_open %s: %s"); 1631*7c478bd9Sstevel@tonic-gate return -1; 1632*7c478bd9Sstevel@tonic-gate } 1633*7c478bd9Sstevel@tonic-gate } 1634*7c478bd9Sstevel@tonic-gate else if (e->e_dfp == NULL) 1635*7c478bd9Sstevel@tonic-gate { 1636*7c478bd9Sstevel@tonic-gate /* shouldn't happen */ 1637*7c478bd9Sstevel@tonic-gate errno = ENOENT; 1638*7c478bd9Sstevel@tonic-gate MILTER_DF_ERROR("milter_reopen_df: NULL e_dfp (%s: %s)"); 1639*7c478bd9Sstevel@tonic-gate return -1; 1640*7c478bd9Sstevel@tonic-gate } 1641*7c478bd9Sstevel@tonic-gate return 0; 1642*7c478bd9Sstevel@tonic-gate } 1643*7c478bd9Sstevel@tonic-gate /* 1644*7c478bd9Sstevel@tonic-gate ** MILTER_RESET_DF -- re-open read-only the data file (for replbody) 1645*7c478bd9Sstevel@tonic-gate ** 1646*7c478bd9Sstevel@tonic-gate ** Parameters: 1647*7c478bd9Sstevel@tonic-gate ** e -- current envelope. 1648*7c478bd9Sstevel@tonic-gate ** 1649*7c478bd9Sstevel@tonic-gate ** Returns: 1650*7c478bd9Sstevel@tonic-gate ** 0 if succesful, -1 otherwise 1651*7c478bd9Sstevel@tonic-gate */ 1652*7c478bd9Sstevel@tonic-gate 1653*7c478bd9Sstevel@tonic-gate static int 1654*7c478bd9Sstevel@tonic-gate milter_reset_df(e) 1655*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 1656*7c478bd9Sstevel@tonic-gate { 1657*7c478bd9Sstevel@tonic-gate int afd; 1658*7c478bd9Sstevel@tonic-gate char dfname[MAXPATHLEN]; 1659*7c478bd9Sstevel@tonic-gate 1660*7c478bd9Sstevel@tonic-gate (void) sm_strlcpy(dfname, queuename(e, DATAFL_LETTER), sizeof dfname); 1661*7c478bd9Sstevel@tonic-gate 1662*7c478bd9Sstevel@tonic-gate if (sm_io_flush(e->e_dfp, SM_TIME_DEFAULT) != 0 || 1663*7c478bd9Sstevel@tonic-gate sm_io_error(e->e_dfp)) 1664*7c478bd9Sstevel@tonic-gate { 1665*7c478bd9Sstevel@tonic-gate MILTER_DF_ERROR("milter_reset_df: error writing/flushing %s: %s"); 1666*7c478bd9Sstevel@tonic-gate return -1; 1667*7c478bd9Sstevel@tonic-gate } 1668*7c478bd9Sstevel@tonic-gate else if (SuperSafe != SAFE_REALLY) 1669*7c478bd9Sstevel@tonic-gate { 1670*7c478bd9Sstevel@tonic-gate /* skip next few clauses */ 1671*7c478bd9Sstevel@tonic-gate /* EMPTY */ 1672*7c478bd9Sstevel@tonic-gate } 1673*7c478bd9Sstevel@tonic-gate else if ((afd = sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, NULL)) >= 0 1674*7c478bd9Sstevel@tonic-gate && fsync(afd) < 0) 1675*7c478bd9Sstevel@tonic-gate { 1676*7c478bd9Sstevel@tonic-gate MILTER_DF_ERROR("milter_reset_df: error sync'ing %s: %s"); 1677*7c478bd9Sstevel@tonic-gate return -1; 1678*7c478bd9Sstevel@tonic-gate } 1679*7c478bd9Sstevel@tonic-gate else if (sm_io_close(e->e_dfp, SM_TIME_DEFAULT) < 0) 1680*7c478bd9Sstevel@tonic-gate { 1681*7c478bd9Sstevel@tonic-gate MILTER_DF_ERROR("milter_reset_df: error closing %s: %s"); 1682*7c478bd9Sstevel@tonic-gate return -1; 1683*7c478bd9Sstevel@tonic-gate } 1684*7c478bd9Sstevel@tonic-gate else if ((e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname, 1685*7c478bd9Sstevel@tonic-gate SM_IO_RDONLY_B, NULL)) == NULL) 1686*7c478bd9Sstevel@tonic-gate { 1687*7c478bd9Sstevel@tonic-gate MILTER_DF_ERROR("milter_reset_df: error reopening %s: %s"); 1688*7c478bd9Sstevel@tonic-gate return -1; 1689*7c478bd9Sstevel@tonic-gate } 1690*7c478bd9Sstevel@tonic-gate else 1691*7c478bd9Sstevel@tonic-gate e->e_flags |= EF_HAS_DF; 1692*7c478bd9Sstevel@tonic-gate return 0; 1693*7c478bd9Sstevel@tonic-gate } 1694*7c478bd9Sstevel@tonic-gate /* 1695*7c478bd9Sstevel@tonic-gate ** MILTER_CAN_DELRCPTS -- can any milter filters delete recipients? 1696*7c478bd9Sstevel@tonic-gate ** 1697*7c478bd9Sstevel@tonic-gate ** Parameters: 1698*7c478bd9Sstevel@tonic-gate ** none 1699*7c478bd9Sstevel@tonic-gate ** 1700*7c478bd9Sstevel@tonic-gate ** Returns: 1701*7c478bd9Sstevel@tonic-gate ** true if any filter deletes recipients, false otherwise 1702*7c478bd9Sstevel@tonic-gate */ 1703*7c478bd9Sstevel@tonic-gate 1704*7c478bd9Sstevel@tonic-gate bool 1705*7c478bd9Sstevel@tonic-gate milter_can_delrcpts() 1706*7c478bd9Sstevel@tonic-gate { 1707*7c478bd9Sstevel@tonic-gate bool can = false; 1708*7c478bd9Sstevel@tonic-gate int i; 1709*7c478bd9Sstevel@tonic-gate 1710*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 1711*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_can_delrcpts:"); 1712*7c478bd9Sstevel@tonic-gate 1713*7c478bd9Sstevel@tonic-gate for (i = 0; InputFilters[i] != NULL; i++) 1714*7c478bd9Sstevel@tonic-gate { 1715*7c478bd9Sstevel@tonic-gate struct milter *m = InputFilters[i]; 1716*7c478bd9Sstevel@tonic-gate 1717*7c478bd9Sstevel@tonic-gate if (bitset(SMFIF_DELRCPT, m->mf_fflags)) 1718*7c478bd9Sstevel@tonic-gate { 1719*7c478bd9Sstevel@tonic-gate can = true; 1720*7c478bd9Sstevel@tonic-gate break; 1721*7c478bd9Sstevel@tonic-gate } 1722*7c478bd9Sstevel@tonic-gate } 1723*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 1724*7c478bd9Sstevel@tonic-gate sm_dprintf("%s\n", can ? "true" : "false"); 1725*7c478bd9Sstevel@tonic-gate 1726*7c478bd9Sstevel@tonic-gate return can; 1727*7c478bd9Sstevel@tonic-gate } 1728*7c478bd9Sstevel@tonic-gate /* 1729*7c478bd9Sstevel@tonic-gate ** MILTER_QUIT_FILTER -- close down a single filter 1730*7c478bd9Sstevel@tonic-gate ** 1731*7c478bd9Sstevel@tonic-gate ** Parameters: 1732*7c478bd9Sstevel@tonic-gate ** m -- milter structure of filter to close down. 1733*7c478bd9Sstevel@tonic-gate ** e -- current envelope. 1734*7c478bd9Sstevel@tonic-gate ** 1735*7c478bd9Sstevel@tonic-gate ** Returns: 1736*7c478bd9Sstevel@tonic-gate ** none 1737*7c478bd9Sstevel@tonic-gate */ 1738*7c478bd9Sstevel@tonic-gate 1739*7c478bd9Sstevel@tonic-gate static void 1740*7c478bd9Sstevel@tonic-gate milter_quit_filter(m, e) 1741*7c478bd9Sstevel@tonic-gate struct milter *m; 1742*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 1743*7c478bd9Sstevel@tonic-gate { 1744*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 1745*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_quit_filter(%s)\n", m->mf_name); 1746*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 18) 1747*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter (%s): quit filter", 1748*7c478bd9Sstevel@tonic-gate m->mf_name); 1749*7c478bd9Sstevel@tonic-gate 1750*7c478bd9Sstevel@tonic-gate /* Never replace error state */ 1751*7c478bd9Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR) 1752*7c478bd9Sstevel@tonic-gate return; 1753*7c478bd9Sstevel@tonic-gate 1754*7c478bd9Sstevel@tonic-gate if (m->mf_sock < 0 || 1755*7c478bd9Sstevel@tonic-gate m->mf_state == SMFS_CLOSED || 1756*7c478bd9Sstevel@tonic-gate m->mf_state == SMFS_READY) 1757*7c478bd9Sstevel@tonic-gate { 1758*7c478bd9Sstevel@tonic-gate m->mf_sock = -1; 1759*7c478bd9Sstevel@tonic-gate m->mf_state = SMFS_CLOSED; 1760*7c478bd9Sstevel@tonic-gate return; 1761*7c478bd9Sstevel@tonic-gate } 1762*7c478bd9Sstevel@tonic-gate 1763*7c478bd9Sstevel@tonic-gate (void) milter_write(m, SMFIC_QUIT, (char *) NULL, 0, 1764*7c478bd9Sstevel@tonic-gate m->mf_timeout[SMFTO_WRITE], e); 1765*7c478bd9Sstevel@tonic-gate if (m->mf_sock >= 0) 1766*7c478bd9Sstevel@tonic-gate { 1767*7c478bd9Sstevel@tonic-gate (void) close(m->mf_sock); 1768*7c478bd9Sstevel@tonic-gate m->mf_sock = -1; 1769*7c478bd9Sstevel@tonic-gate } 1770*7c478bd9Sstevel@tonic-gate if (m->mf_state != SMFS_ERROR) 1771*7c478bd9Sstevel@tonic-gate m->mf_state = SMFS_CLOSED; 1772*7c478bd9Sstevel@tonic-gate } 1773*7c478bd9Sstevel@tonic-gate /* 1774*7c478bd9Sstevel@tonic-gate ** MILTER_ABORT_FILTER -- tell filter to abort current message 1775*7c478bd9Sstevel@tonic-gate ** 1776*7c478bd9Sstevel@tonic-gate ** Parameters: 1777*7c478bd9Sstevel@tonic-gate ** m -- milter structure of filter to abort. 1778*7c478bd9Sstevel@tonic-gate ** e -- current envelope. 1779*7c478bd9Sstevel@tonic-gate ** 1780*7c478bd9Sstevel@tonic-gate ** Returns: 1781*7c478bd9Sstevel@tonic-gate ** none 1782*7c478bd9Sstevel@tonic-gate */ 1783*7c478bd9Sstevel@tonic-gate 1784*7c478bd9Sstevel@tonic-gate static void 1785*7c478bd9Sstevel@tonic-gate milter_abort_filter(m, e) 1786*7c478bd9Sstevel@tonic-gate struct milter *m; 1787*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 1788*7c478bd9Sstevel@tonic-gate { 1789*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 1790*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_abort_filter(%s)\n", m->mf_name); 1791*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 10) 1792*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter (%s): abort filter", 1793*7c478bd9Sstevel@tonic-gate m->mf_name); 1794*7c478bd9Sstevel@tonic-gate 1795*7c478bd9Sstevel@tonic-gate if (m->mf_sock < 0 || 1796*7c478bd9Sstevel@tonic-gate m->mf_state != SMFS_INMSG) 1797*7c478bd9Sstevel@tonic-gate return; 1798*7c478bd9Sstevel@tonic-gate 1799*7c478bd9Sstevel@tonic-gate (void) milter_write(m, SMFIC_ABORT, (char *) NULL, 0, 1800*7c478bd9Sstevel@tonic-gate m->mf_timeout[SMFTO_WRITE], e); 1801*7c478bd9Sstevel@tonic-gate if (m->mf_state != SMFS_ERROR) 1802*7c478bd9Sstevel@tonic-gate m->mf_state = SMFS_DONE; 1803*7c478bd9Sstevel@tonic-gate } 1804*7c478bd9Sstevel@tonic-gate /* 1805*7c478bd9Sstevel@tonic-gate ** MILTER_SEND_MACROS -- provide macros to the filters 1806*7c478bd9Sstevel@tonic-gate ** 1807*7c478bd9Sstevel@tonic-gate ** Parameters: 1808*7c478bd9Sstevel@tonic-gate ** m -- milter to send macros to. 1809*7c478bd9Sstevel@tonic-gate ** macros -- macros to send for filter smfi_getsymval(). 1810*7c478bd9Sstevel@tonic-gate ** cmd -- which command the macros are associated with. 1811*7c478bd9Sstevel@tonic-gate ** e -- current envelope (for macro access). 1812*7c478bd9Sstevel@tonic-gate ** 1813*7c478bd9Sstevel@tonic-gate ** Returns: 1814*7c478bd9Sstevel@tonic-gate ** none 1815*7c478bd9Sstevel@tonic-gate */ 1816*7c478bd9Sstevel@tonic-gate 1817*7c478bd9Sstevel@tonic-gate static void 1818*7c478bd9Sstevel@tonic-gate milter_send_macros(m, macros, cmd, e) 1819*7c478bd9Sstevel@tonic-gate struct milter *m; 1820*7c478bd9Sstevel@tonic-gate char **macros; 1821*7c478bd9Sstevel@tonic-gate char cmd; 1822*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 1823*7c478bd9Sstevel@tonic-gate { 1824*7c478bd9Sstevel@tonic-gate int i; 1825*7c478bd9Sstevel@tonic-gate int mid; 1826*7c478bd9Sstevel@tonic-gate char *v; 1827*7c478bd9Sstevel@tonic-gate char *buf, *bp; 1828*7c478bd9Sstevel@tonic-gate char exp[MAXLINE]; 1829*7c478bd9Sstevel@tonic-gate ssize_t s; 1830*7c478bd9Sstevel@tonic-gate 1831*7c478bd9Sstevel@tonic-gate /* sanity check */ 1832*7c478bd9Sstevel@tonic-gate if (macros == NULL || macros[0] == NULL) 1833*7c478bd9Sstevel@tonic-gate return; 1834*7c478bd9Sstevel@tonic-gate 1835*7c478bd9Sstevel@tonic-gate /* put together data */ 1836*7c478bd9Sstevel@tonic-gate s = 1; /* for the command character */ 1837*7c478bd9Sstevel@tonic-gate for (i = 0; macros[i] != NULL; i++) 1838*7c478bd9Sstevel@tonic-gate { 1839*7c478bd9Sstevel@tonic-gate mid = macid(macros[i]); 1840*7c478bd9Sstevel@tonic-gate if (mid == 0) 1841*7c478bd9Sstevel@tonic-gate continue; 1842*7c478bd9Sstevel@tonic-gate v = macvalue(mid, e); 1843*7c478bd9Sstevel@tonic-gate if (v == NULL) 1844*7c478bd9Sstevel@tonic-gate continue; 1845*7c478bd9Sstevel@tonic-gate expand(v, exp, sizeof(exp), e); 1846*7c478bd9Sstevel@tonic-gate s += strlen(macros[i]) + 1 + strlen(exp) + 1; 1847*7c478bd9Sstevel@tonic-gate } 1848*7c478bd9Sstevel@tonic-gate 1849*7c478bd9Sstevel@tonic-gate if (s < 0) 1850*7c478bd9Sstevel@tonic-gate return; 1851*7c478bd9Sstevel@tonic-gate 1852*7c478bd9Sstevel@tonic-gate buf = (char *) xalloc(s); 1853*7c478bd9Sstevel@tonic-gate bp = buf; 1854*7c478bd9Sstevel@tonic-gate *bp++ = cmd; 1855*7c478bd9Sstevel@tonic-gate for (i = 0; macros[i] != NULL; i++) 1856*7c478bd9Sstevel@tonic-gate { 1857*7c478bd9Sstevel@tonic-gate mid = macid(macros[i]); 1858*7c478bd9Sstevel@tonic-gate if (mid == 0) 1859*7c478bd9Sstevel@tonic-gate continue; 1860*7c478bd9Sstevel@tonic-gate v = macvalue(mid, e); 1861*7c478bd9Sstevel@tonic-gate if (v == NULL) 1862*7c478bd9Sstevel@tonic-gate continue; 1863*7c478bd9Sstevel@tonic-gate expand(v, exp, sizeof(exp), e); 1864*7c478bd9Sstevel@tonic-gate 1865*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 1866*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_send_macros(%s, %c): %s=%s\n", 1867*7c478bd9Sstevel@tonic-gate m->mf_name, cmd, macros[i], exp); 1868*7c478bd9Sstevel@tonic-gate 1869*7c478bd9Sstevel@tonic-gate (void) sm_strlcpy(bp, macros[i], s - (bp - buf)); 1870*7c478bd9Sstevel@tonic-gate bp += strlen(bp) + 1; 1871*7c478bd9Sstevel@tonic-gate (void) sm_strlcpy(bp, exp, s - (bp - buf)); 1872*7c478bd9Sstevel@tonic-gate bp += strlen(bp) + 1; 1873*7c478bd9Sstevel@tonic-gate } 1874*7c478bd9Sstevel@tonic-gate (void) milter_write(m, SMFIC_MACRO, buf, s, 1875*7c478bd9Sstevel@tonic-gate m->mf_timeout[SMFTO_WRITE], e); 1876*7c478bd9Sstevel@tonic-gate sm_free(buf); 1877*7c478bd9Sstevel@tonic-gate } 1878*7c478bd9Sstevel@tonic-gate 1879*7c478bd9Sstevel@tonic-gate /* 1880*7c478bd9Sstevel@tonic-gate ** MILTER_SEND_COMMAND -- send a command and return the response for a filter 1881*7c478bd9Sstevel@tonic-gate ** 1882*7c478bd9Sstevel@tonic-gate ** Parameters: 1883*7c478bd9Sstevel@tonic-gate ** m -- current milter filter 1884*7c478bd9Sstevel@tonic-gate ** command -- command to send. 1885*7c478bd9Sstevel@tonic-gate ** data -- optional command data. 1886*7c478bd9Sstevel@tonic-gate ** sz -- length of buf. 1887*7c478bd9Sstevel@tonic-gate ** e -- current envelope (for e->e_id). 1888*7c478bd9Sstevel@tonic-gate ** state -- return state word. 1889*7c478bd9Sstevel@tonic-gate ** 1890*7c478bd9Sstevel@tonic-gate ** Returns: 1891*7c478bd9Sstevel@tonic-gate ** response string (may be NULL) 1892*7c478bd9Sstevel@tonic-gate */ 1893*7c478bd9Sstevel@tonic-gate 1894*7c478bd9Sstevel@tonic-gate static char * 1895*7c478bd9Sstevel@tonic-gate milter_send_command(m, command, data, sz, e, state) 1896*7c478bd9Sstevel@tonic-gate struct milter *m; 1897*7c478bd9Sstevel@tonic-gate char command; 1898*7c478bd9Sstevel@tonic-gate void *data; 1899*7c478bd9Sstevel@tonic-gate ssize_t sz; 1900*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 1901*7c478bd9Sstevel@tonic-gate char *state; 1902*7c478bd9Sstevel@tonic-gate { 1903*7c478bd9Sstevel@tonic-gate char rcmd; 1904*7c478bd9Sstevel@tonic-gate ssize_t rlen; 1905*7c478bd9Sstevel@tonic-gate unsigned long skipflag; 1906*7c478bd9Sstevel@tonic-gate #if _FFR_MILTER_NOHDR_RESP 1907*7c478bd9Sstevel@tonic-gate unsigned long norespflag = 0; 1908*7c478bd9Sstevel@tonic-gate #endif /* _FFR_MILTER_NOHDR_RESP */ 1909*7c478bd9Sstevel@tonic-gate char *action; 1910*7c478bd9Sstevel@tonic-gate char *defresponse; 1911*7c478bd9Sstevel@tonic-gate char *response; 1912*7c478bd9Sstevel@tonic-gate 1913*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 1914*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_send_command(%s): cmd %c len %ld\n", 1915*7c478bd9Sstevel@tonic-gate m->mf_name, (char) command, (long) sz); 1916*7c478bd9Sstevel@tonic-gate 1917*7c478bd9Sstevel@tonic-gate /* find skip flag and default failure */ 1918*7c478bd9Sstevel@tonic-gate switch (command) 1919*7c478bd9Sstevel@tonic-gate { 1920*7c478bd9Sstevel@tonic-gate case SMFIC_CONNECT: 1921*7c478bd9Sstevel@tonic-gate skipflag = SMFIP_NOCONNECT; 1922*7c478bd9Sstevel@tonic-gate action = "connect"; 1923*7c478bd9Sstevel@tonic-gate defresponse = "554 Command rejected"; 1924*7c478bd9Sstevel@tonic-gate break; 1925*7c478bd9Sstevel@tonic-gate 1926*7c478bd9Sstevel@tonic-gate case SMFIC_HELO: 1927*7c478bd9Sstevel@tonic-gate skipflag = SMFIP_NOHELO; 1928*7c478bd9Sstevel@tonic-gate action = "helo"; 1929*7c478bd9Sstevel@tonic-gate defresponse = "550 Command rejected"; 1930*7c478bd9Sstevel@tonic-gate break; 1931*7c478bd9Sstevel@tonic-gate 1932*7c478bd9Sstevel@tonic-gate case SMFIC_MAIL: 1933*7c478bd9Sstevel@tonic-gate skipflag = SMFIP_NOMAIL; 1934*7c478bd9Sstevel@tonic-gate action = "mail"; 1935*7c478bd9Sstevel@tonic-gate defresponse = "550 5.7.1 Command rejected"; 1936*7c478bd9Sstevel@tonic-gate break; 1937*7c478bd9Sstevel@tonic-gate 1938*7c478bd9Sstevel@tonic-gate case SMFIC_RCPT: 1939*7c478bd9Sstevel@tonic-gate skipflag = SMFIP_NORCPT; 1940*7c478bd9Sstevel@tonic-gate action = "rcpt"; 1941*7c478bd9Sstevel@tonic-gate defresponse = "550 5.7.1 Command rejected"; 1942*7c478bd9Sstevel@tonic-gate break; 1943*7c478bd9Sstevel@tonic-gate 1944*7c478bd9Sstevel@tonic-gate case SMFIC_HEADER: 1945*7c478bd9Sstevel@tonic-gate skipflag = SMFIP_NOHDRS; 1946*7c478bd9Sstevel@tonic-gate #if _FFR_MILTER_NOHDR_RESP 1947*7c478bd9Sstevel@tonic-gate norespflag = SMFIP_NOHREPL; 1948*7c478bd9Sstevel@tonic-gate #endif /* _FFR_MILTER_NOHDR_RESP */ 1949*7c478bd9Sstevel@tonic-gate action = "header"; 1950*7c478bd9Sstevel@tonic-gate defresponse = "550 5.7.1 Command rejected"; 1951*7c478bd9Sstevel@tonic-gate break; 1952*7c478bd9Sstevel@tonic-gate 1953*7c478bd9Sstevel@tonic-gate case SMFIC_BODY: 1954*7c478bd9Sstevel@tonic-gate skipflag = SMFIP_NOBODY; 1955*7c478bd9Sstevel@tonic-gate action = "body"; 1956*7c478bd9Sstevel@tonic-gate defresponse = "554 5.7.1 Command rejected"; 1957*7c478bd9Sstevel@tonic-gate break; 1958*7c478bd9Sstevel@tonic-gate 1959*7c478bd9Sstevel@tonic-gate case SMFIC_EOH: 1960*7c478bd9Sstevel@tonic-gate skipflag = SMFIP_NOEOH; 1961*7c478bd9Sstevel@tonic-gate action = "eoh"; 1962*7c478bd9Sstevel@tonic-gate defresponse = "550 5.7.1 Command rejected"; 1963*7c478bd9Sstevel@tonic-gate break; 1964*7c478bd9Sstevel@tonic-gate 1965*7c478bd9Sstevel@tonic-gate #if SMFI_VERSION > 2 1966*7c478bd9Sstevel@tonic-gate case SMFIC_UNKNOWN: 1967*7c478bd9Sstevel@tonic-gate action = "unknown"; 1968*7c478bd9Sstevel@tonic-gate defresponse = "550 5.7.1 Command rejected"; 1969*7c478bd9Sstevel@tonic-gate break; 1970*7c478bd9Sstevel@tonic-gate #endif /* SMFI_VERSION > 2 */ 1971*7c478bd9Sstevel@tonic-gate 1972*7c478bd9Sstevel@tonic-gate case SMFIC_BODYEOB: 1973*7c478bd9Sstevel@tonic-gate case SMFIC_OPTNEG: 1974*7c478bd9Sstevel@tonic-gate case SMFIC_MACRO: 1975*7c478bd9Sstevel@tonic-gate case SMFIC_ABORT: 1976*7c478bd9Sstevel@tonic-gate case SMFIC_QUIT: 1977*7c478bd9Sstevel@tonic-gate /* NOTE: not handled by milter_send_command() */ 1978*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 1979*7c478bd9Sstevel@tonic-gate 1980*7c478bd9Sstevel@tonic-gate default: 1981*7c478bd9Sstevel@tonic-gate skipflag = 0; 1982*7c478bd9Sstevel@tonic-gate action = "default"; 1983*7c478bd9Sstevel@tonic-gate defresponse = "550 5.7.1 Command rejected"; 1984*7c478bd9Sstevel@tonic-gate break; 1985*7c478bd9Sstevel@tonic-gate } 1986*7c478bd9Sstevel@tonic-gate 1987*7c478bd9Sstevel@tonic-gate /* check if filter wants this command */ 1988*7c478bd9Sstevel@tonic-gate if (skipflag != 0 && 1989*7c478bd9Sstevel@tonic-gate bitset(skipflag, m->mf_pflags)) 1990*7c478bd9Sstevel@tonic-gate return NULL; 1991*7c478bd9Sstevel@tonic-gate 1992*7c478bd9Sstevel@tonic-gate /* send the command to the filter */ 1993*7c478bd9Sstevel@tonic-gate (void) milter_write(m, command, data, sz, 1994*7c478bd9Sstevel@tonic-gate m->mf_timeout[SMFTO_WRITE], e); 1995*7c478bd9Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR) 1996*7c478bd9Sstevel@tonic-gate { 1997*7c478bd9Sstevel@tonic-gate MILTER_CHECK_ERROR(false, return NULL); 1998*7c478bd9Sstevel@tonic-gate return NULL; 1999*7c478bd9Sstevel@tonic-gate } 2000*7c478bd9Sstevel@tonic-gate 2001*7c478bd9Sstevel@tonic-gate #if _FFR_MILTER_NOHDR_RESP 2002*7c478bd9Sstevel@tonic-gate /* check if filter sends response to this command */ 2003*7c478bd9Sstevel@tonic-gate if (norespflag != 0 && bitset(norespflag, m->mf_pflags)) 2004*7c478bd9Sstevel@tonic-gate return NULL; 2005*7c478bd9Sstevel@tonic-gate #endif /* _FFR_MILTER_NOHDR_RESP */ 2006*7c478bd9Sstevel@tonic-gate 2007*7c478bd9Sstevel@tonic-gate /* get the response from the filter */ 2008*7c478bd9Sstevel@tonic-gate response = milter_read(m, &rcmd, &rlen, 2009*7c478bd9Sstevel@tonic-gate m->mf_timeout[SMFTO_READ], e); 2010*7c478bd9Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR) 2011*7c478bd9Sstevel@tonic-gate { 2012*7c478bd9Sstevel@tonic-gate MILTER_CHECK_ERROR(false, return NULL); 2013*7c478bd9Sstevel@tonic-gate return NULL; 2014*7c478bd9Sstevel@tonic-gate } 2015*7c478bd9Sstevel@tonic-gate 2016*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 2017*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_send_command(%s): returned %c\n", 2018*7c478bd9Sstevel@tonic-gate m->mf_name, (char) rcmd); 2019*7c478bd9Sstevel@tonic-gate 2020*7c478bd9Sstevel@tonic-gate switch (rcmd) 2021*7c478bd9Sstevel@tonic-gate { 2022*7c478bd9Sstevel@tonic-gate case SMFIR_REPLYCODE: 2023*7c478bd9Sstevel@tonic-gate MILTER_CHECK_REPLYCODE(defresponse); 2024*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 10) 2025*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, reject=%s", 2026*7c478bd9Sstevel@tonic-gate m->mf_name, action, response); 2027*7c478bd9Sstevel@tonic-gate *state = rcmd; 2028*7c478bd9Sstevel@tonic-gate break; 2029*7c478bd9Sstevel@tonic-gate 2030*7c478bd9Sstevel@tonic-gate case SMFIR_REJECT: 2031*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 10) 2032*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, reject", 2033*7c478bd9Sstevel@tonic-gate m->mf_name, action); 2034*7c478bd9Sstevel@tonic-gate *state = rcmd; 2035*7c478bd9Sstevel@tonic-gate break; 2036*7c478bd9Sstevel@tonic-gate 2037*7c478bd9Sstevel@tonic-gate case SMFIR_DISCARD: 2038*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 10) 2039*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, discard", 2040*7c478bd9Sstevel@tonic-gate m->mf_name, action); 2041*7c478bd9Sstevel@tonic-gate *state = rcmd; 2042*7c478bd9Sstevel@tonic-gate break; 2043*7c478bd9Sstevel@tonic-gate 2044*7c478bd9Sstevel@tonic-gate case SMFIR_TEMPFAIL: 2045*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 10) 2046*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, tempfail", 2047*7c478bd9Sstevel@tonic-gate m->mf_name, action); 2048*7c478bd9Sstevel@tonic-gate *state = rcmd; 2049*7c478bd9Sstevel@tonic-gate break; 2050*7c478bd9Sstevel@tonic-gate 2051*7c478bd9Sstevel@tonic-gate case SMFIR_ACCEPT: 2052*7c478bd9Sstevel@tonic-gate /* this filter is done with message/connection */ 2053*7c478bd9Sstevel@tonic-gate if (command == SMFIC_HELO || 2054*7c478bd9Sstevel@tonic-gate command == SMFIC_CONNECT) 2055*7c478bd9Sstevel@tonic-gate m->mf_state = SMFS_CLOSABLE; 2056*7c478bd9Sstevel@tonic-gate else 2057*7c478bd9Sstevel@tonic-gate m->mf_state = SMFS_DONE; 2058*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 10) 2059*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, accepted", 2060*7c478bd9Sstevel@tonic-gate m->mf_name, action); 2061*7c478bd9Sstevel@tonic-gate break; 2062*7c478bd9Sstevel@tonic-gate 2063*7c478bd9Sstevel@tonic-gate case SMFIR_CONTINUE: 2064*7c478bd9Sstevel@tonic-gate /* if MAIL command is ok, filter is in message state */ 2065*7c478bd9Sstevel@tonic-gate if (command == SMFIC_MAIL) 2066*7c478bd9Sstevel@tonic-gate m->mf_state = SMFS_INMSG; 2067*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 12) 2068*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, continue", 2069*7c478bd9Sstevel@tonic-gate m->mf_name, action); 2070*7c478bd9Sstevel@tonic-gate break; 2071*7c478bd9Sstevel@tonic-gate 2072*7c478bd9Sstevel@tonic-gate default: 2073*7c478bd9Sstevel@tonic-gate /* Invalid response to command */ 2074*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) 2075*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 2076*7c478bd9Sstevel@tonic-gate "milter_send_command(%s): action=%s returned bogus response %c", 2077*7c478bd9Sstevel@tonic-gate m->mf_name, action, rcmd); 2078*7c478bd9Sstevel@tonic-gate milter_error(m, e); 2079*7c478bd9Sstevel@tonic-gate break; 2080*7c478bd9Sstevel@tonic-gate } 2081*7c478bd9Sstevel@tonic-gate 2082*7c478bd9Sstevel@tonic-gate if (*state != SMFIR_REPLYCODE && 2083*7c478bd9Sstevel@tonic-gate response != NULL) 2084*7c478bd9Sstevel@tonic-gate { 2085*7c478bd9Sstevel@tonic-gate sm_free(response); /* XXX */ 2086*7c478bd9Sstevel@tonic-gate response = NULL; 2087*7c478bd9Sstevel@tonic-gate } 2088*7c478bd9Sstevel@tonic-gate return response; 2089*7c478bd9Sstevel@tonic-gate } 2090*7c478bd9Sstevel@tonic-gate 2091*7c478bd9Sstevel@tonic-gate /* 2092*7c478bd9Sstevel@tonic-gate ** MILTER_COMMAND -- send a command and return the response for each filter 2093*7c478bd9Sstevel@tonic-gate ** 2094*7c478bd9Sstevel@tonic-gate ** Parameters: 2095*7c478bd9Sstevel@tonic-gate ** command -- command to send. 2096*7c478bd9Sstevel@tonic-gate ** data -- optional command data. 2097*7c478bd9Sstevel@tonic-gate ** sz -- length of buf. 2098*7c478bd9Sstevel@tonic-gate ** macros -- macros to send for filter smfi_getsymval(). 2099*7c478bd9Sstevel@tonic-gate ** e -- current envelope (for macro access). 2100*7c478bd9Sstevel@tonic-gate ** state -- return state word. 2101*7c478bd9Sstevel@tonic-gate ** 2102*7c478bd9Sstevel@tonic-gate ** Returns: 2103*7c478bd9Sstevel@tonic-gate ** response string (may be NULL) 2104*7c478bd9Sstevel@tonic-gate */ 2105*7c478bd9Sstevel@tonic-gate 2106*7c478bd9Sstevel@tonic-gate static char * 2107*7c478bd9Sstevel@tonic-gate milter_command(command, data, sz, macros, e, state) 2108*7c478bd9Sstevel@tonic-gate char command; 2109*7c478bd9Sstevel@tonic-gate void *data; 2110*7c478bd9Sstevel@tonic-gate ssize_t sz; 2111*7c478bd9Sstevel@tonic-gate char **macros; 2112*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 2113*7c478bd9Sstevel@tonic-gate char *state; 2114*7c478bd9Sstevel@tonic-gate { 2115*7c478bd9Sstevel@tonic-gate int i; 2116*7c478bd9Sstevel@tonic-gate char *response = NULL; 2117*7c478bd9Sstevel@tonic-gate time_t tn = 0; 2118*7c478bd9Sstevel@tonic-gate 2119*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 2120*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_command: cmd %c len %ld\n", 2121*7c478bd9Sstevel@tonic-gate (char) command, (long) sz); 2122*7c478bd9Sstevel@tonic-gate 2123*7c478bd9Sstevel@tonic-gate *state = SMFIR_CONTINUE; 2124*7c478bd9Sstevel@tonic-gate for (i = 0; InputFilters[i] != NULL; i++) 2125*7c478bd9Sstevel@tonic-gate { 2126*7c478bd9Sstevel@tonic-gate struct milter *m = InputFilters[i]; 2127*7c478bd9Sstevel@tonic-gate 2128*7c478bd9Sstevel@tonic-gate /* previous problem? */ 2129*7c478bd9Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR) 2130*7c478bd9Sstevel@tonic-gate { 2131*7c478bd9Sstevel@tonic-gate MILTER_CHECK_ERROR(false, continue); 2132*7c478bd9Sstevel@tonic-gate break; 2133*7c478bd9Sstevel@tonic-gate } 2134*7c478bd9Sstevel@tonic-gate 2135*7c478bd9Sstevel@tonic-gate /* sanity check */ 2136*7c478bd9Sstevel@tonic-gate if (m->mf_sock < 0 || 2137*7c478bd9Sstevel@tonic-gate (m->mf_state != SMFS_OPEN && m->mf_state != SMFS_INMSG)) 2138*7c478bd9Sstevel@tonic-gate continue; 2139*7c478bd9Sstevel@tonic-gate 2140*7c478bd9Sstevel@tonic-gate /* send macros (regardless of whether we send command) */ 2141*7c478bd9Sstevel@tonic-gate if (macros != NULL && macros[0] != NULL) 2142*7c478bd9Sstevel@tonic-gate { 2143*7c478bd9Sstevel@tonic-gate milter_send_macros(m, macros, command, e); 2144*7c478bd9Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR) 2145*7c478bd9Sstevel@tonic-gate { 2146*7c478bd9Sstevel@tonic-gate MILTER_CHECK_ERROR(false, continue); 2147*7c478bd9Sstevel@tonic-gate break; 2148*7c478bd9Sstevel@tonic-gate } 2149*7c478bd9Sstevel@tonic-gate } 2150*7c478bd9Sstevel@tonic-gate 2151*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 21) 2152*7c478bd9Sstevel@tonic-gate tn = curtime(); 2153*7c478bd9Sstevel@tonic-gate 2154*7c478bd9Sstevel@tonic-gate response = milter_send_command(m, command, data, sz, e, state); 2155*7c478bd9Sstevel@tonic-gate 2156*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 21) 2157*7c478bd9Sstevel@tonic-gate { 2158*7c478bd9Sstevel@tonic-gate /* log the time it took for the command per filter */ 2159*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 2160*7c478bd9Sstevel@tonic-gate "Milter (%s): time command (%c), %d", 2161*7c478bd9Sstevel@tonic-gate m->mf_name, command, (int) (tn - curtime())); 2162*7c478bd9Sstevel@tonic-gate } 2163*7c478bd9Sstevel@tonic-gate 2164*7c478bd9Sstevel@tonic-gate if (*state != SMFIR_CONTINUE) 2165*7c478bd9Sstevel@tonic-gate break; 2166*7c478bd9Sstevel@tonic-gate } 2167*7c478bd9Sstevel@tonic-gate return response; 2168*7c478bd9Sstevel@tonic-gate } 2169*7c478bd9Sstevel@tonic-gate /* 2170*7c478bd9Sstevel@tonic-gate ** MILTER_NEGOTIATE -- get version and flags from filter 2171*7c478bd9Sstevel@tonic-gate ** 2172*7c478bd9Sstevel@tonic-gate ** Parameters: 2173*7c478bd9Sstevel@tonic-gate ** m -- milter filter structure. 2174*7c478bd9Sstevel@tonic-gate ** e -- current envelope. 2175*7c478bd9Sstevel@tonic-gate ** 2176*7c478bd9Sstevel@tonic-gate ** Returns: 2177*7c478bd9Sstevel@tonic-gate ** 0 on success, -1 otherwise 2178*7c478bd9Sstevel@tonic-gate */ 2179*7c478bd9Sstevel@tonic-gate 2180*7c478bd9Sstevel@tonic-gate static int 2181*7c478bd9Sstevel@tonic-gate milter_negotiate(m, e) 2182*7c478bd9Sstevel@tonic-gate struct milter *m; 2183*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 2184*7c478bd9Sstevel@tonic-gate { 2185*7c478bd9Sstevel@tonic-gate char rcmd; 2186*7c478bd9Sstevel@tonic-gate mi_int32 fvers; 2187*7c478bd9Sstevel@tonic-gate mi_int32 fflags; 2188*7c478bd9Sstevel@tonic-gate mi_int32 pflags; 2189*7c478bd9Sstevel@tonic-gate char *response; 2190*7c478bd9Sstevel@tonic-gate ssize_t rlen; 2191*7c478bd9Sstevel@tonic-gate char data[MILTER_OPTLEN]; 2192*7c478bd9Sstevel@tonic-gate 2193*7c478bd9Sstevel@tonic-gate /* sanity check */ 2194*7c478bd9Sstevel@tonic-gate if (m->mf_sock < 0 || m->mf_state != SMFS_OPEN) 2195*7c478bd9Sstevel@tonic-gate { 2196*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) 2197*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 2198*7c478bd9Sstevel@tonic-gate "Milter (%s): negotiate, impossible state", 2199*7c478bd9Sstevel@tonic-gate m->mf_name); 2200*7c478bd9Sstevel@tonic-gate milter_error(m, e); 2201*7c478bd9Sstevel@tonic-gate return -1; 2202*7c478bd9Sstevel@tonic-gate } 2203*7c478bd9Sstevel@tonic-gate 2204*7c478bd9Sstevel@tonic-gate fvers = htonl(SMFI_VERSION); 2205*7c478bd9Sstevel@tonic-gate fflags = htonl(SMFI_CURR_ACTS); 2206*7c478bd9Sstevel@tonic-gate pflags = htonl(SMFI_CURR_PROT); 2207*7c478bd9Sstevel@tonic-gate (void) memcpy(data, (char *) &fvers, MILTER_LEN_BYTES); 2208*7c478bd9Sstevel@tonic-gate (void) memcpy(data + MILTER_LEN_BYTES, 2209*7c478bd9Sstevel@tonic-gate (char *) &fflags, MILTER_LEN_BYTES); 2210*7c478bd9Sstevel@tonic-gate (void) memcpy(data + (MILTER_LEN_BYTES * 2), 2211*7c478bd9Sstevel@tonic-gate (char *) &pflags, MILTER_LEN_BYTES); 2212*7c478bd9Sstevel@tonic-gate (void) milter_write(m, SMFIC_OPTNEG, data, sizeof data, 2213*7c478bd9Sstevel@tonic-gate m->mf_timeout[SMFTO_WRITE], e); 2214*7c478bd9Sstevel@tonic-gate 2215*7c478bd9Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR) 2216*7c478bd9Sstevel@tonic-gate return -1; 2217*7c478bd9Sstevel@tonic-gate 2218*7c478bd9Sstevel@tonic-gate response = milter_read(m, &rcmd, &rlen, m->mf_timeout[SMFTO_READ], e); 2219*7c478bd9Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR) 2220*7c478bd9Sstevel@tonic-gate return -1; 2221*7c478bd9Sstevel@tonic-gate 2222*7c478bd9Sstevel@tonic-gate if (rcmd != SMFIC_OPTNEG) 2223*7c478bd9Sstevel@tonic-gate { 2224*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 2225*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_negotiate(%s): returned %c instead of %c\n", 2226*7c478bd9Sstevel@tonic-gate m->mf_name, rcmd, SMFIC_OPTNEG); 2227*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) 2228*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 2229*7c478bd9Sstevel@tonic-gate "Milter (%s): negotiate: returned %c instead of %c", 2230*7c478bd9Sstevel@tonic-gate m->mf_name, rcmd, SMFIC_OPTNEG); 2231*7c478bd9Sstevel@tonic-gate if (response != NULL) 2232*7c478bd9Sstevel@tonic-gate sm_free(response); /* XXX */ 2233*7c478bd9Sstevel@tonic-gate milter_error(m, e); 2234*7c478bd9Sstevel@tonic-gate return -1; 2235*7c478bd9Sstevel@tonic-gate } 2236*7c478bd9Sstevel@tonic-gate 2237*7c478bd9Sstevel@tonic-gate /* Make sure we have enough bytes for the version */ 2238*7c478bd9Sstevel@tonic-gate if (response == NULL || rlen < MILTER_LEN_BYTES) 2239*7c478bd9Sstevel@tonic-gate { 2240*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 2241*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_negotiate(%s): did not return valid info\n", 2242*7c478bd9Sstevel@tonic-gate m->mf_name); 2243*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) 2244*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 2245*7c478bd9Sstevel@tonic-gate "Milter (%s): negotiate: did not return valid info", 2246*7c478bd9Sstevel@tonic-gate m->mf_name); 2247*7c478bd9Sstevel@tonic-gate if (response != NULL) 2248*7c478bd9Sstevel@tonic-gate sm_free(response); /* XXX */ 2249*7c478bd9Sstevel@tonic-gate milter_error(m, e); 2250*7c478bd9Sstevel@tonic-gate return -1; 2251*7c478bd9Sstevel@tonic-gate } 2252*7c478bd9Sstevel@tonic-gate 2253*7c478bd9Sstevel@tonic-gate /* extract information */ 2254*7c478bd9Sstevel@tonic-gate (void) memcpy((char *) &fvers, response, MILTER_LEN_BYTES); 2255*7c478bd9Sstevel@tonic-gate 2256*7c478bd9Sstevel@tonic-gate /* Now make sure we have enough for the feature bitmap */ 2257*7c478bd9Sstevel@tonic-gate if (rlen != MILTER_OPTLEN) 2258*7c478bd9Sstevel@tonic-gate { 2259*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 2260*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_negotiate(%s): did not return enough info\n", 2261*7c478bd9Sstevel@tonic-gate m->mf_name); 2262*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) 2263*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 2264*7c478bd9Sstevel@tonic-gate "Milter (%s): negotiate: did not return enough info", 2265*7c478bd9Sstevel@tonic-gate m->mf_name); 2266*7c478bd9Sstevel@tonic-gate if (response != NULL) 2267*7c478bd9Sstevel@tonic-gate sm_free(response); /* XXX */ 2268*7c478bd9Sstevel@tonic-gate milter_error(m, e); 2269*7c478bd9Sstevel@tonic-gate return -1; 2270*7c478bd9Sstevel@tonic-gate } 2271*7c478bd9Sstevel@tonic-gate 2272*7c478bd9Sstevel@tonic-gate (void) memcpy((char *) &fflags, response + MILTER_LEN_BYTES, 2273*7c478bd9Sstevel@tonic-gate MILTER_LEN_BYTES); 2274*7c478bd9Sstevel@tonic-gate (void) memcpy((char *) &pflags, response + (MILTER_LEN_BYTES * 2), 2275*7c478bd9Sstevel@tonic-gate MILTER_LEN_BYTES); 2276*7c478bd9Sstevel@tonic-gate sm_free(response); /* XXX */ 2277*7c478bd9Sstevel@tonic-gate response = NULL; 2278*7c478bd9Sstevel@tonic-gate 2279*7c478bd9Sstevel@tonic-gate m->mf_fvers = ntohl(fvers); 2280*7c478bd9Sstevel@tonic-gate m->mf_fflags = ntohl(fflags); 2281*7c478bd9Sstevel@tonic-gate m->mf_pflags = ntohl(pflags); 2282*7c478bd9Sstevel@tonic-gate 2283*7c478bd9Sstevel@tonic-gate /* check for version compatibility */ 2284*7c478bd9Sstevel@tonic-gate if (m->mf_fvers == 1 || 2285*7c478bd9Sstevel@tonic-gate m->mf_fvers > SMFI_VERSION) 2286*7c478bd9Sstevel@tonic-gate { 2287*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 2288*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_negotiate(%s): version %d != MTA milter version %d\n", 2289*7c478bd9Sstevel@tonic-gate m->mf_name, m->mf_fvers, SMFI_VERSION); 2290*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) 2291*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 2292*7c478bd9Sstevel@tonic-gate "Milter (%s): negotiate: version %d != MTA milter version %d", 2293*7c478bd9Sstevel@tonic-gate m->mf_name, m->mf_fvers, SMFI_VERSION); 2294*7c478bd9Sstevel@tonic-gate milter_error(m, e); 2295*7c478bd9Sstevel@tonic-gate return -1; 2296*7c478bd9Sstevel@tonic-gate } 2297*7c478bd9Sstevel@tonic-gate 2298*7c478bd9Sstevel@tonic-gate /* check for filter feature mismatch */ 2299*7c478bd9Sstevel@tonic-gate if ((m->mf_fflags & SMFI_CURR_ACTS) != m->mf_fflags) 2300*7c478bd9Sstevel@tonic-gate { 2301*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 2302*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_negotiate(%s): filter abilities 0x%x != MTA milter abilities 0x%lx\n", 2303*7c478bd9Sstevel@tonic-gate m->mf_name, m->mf_fflags, 2304*7c478bd9Sstevel@tonic-gate SMFI_CURR_ACTS); 2305*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) 2306*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 2307*7c478bd9Sstevel@tonic-gate "Milter (%s): negotiate: filter abilities 0x%x != MTA milter abilities 0x%lx", 2308*7c478bd9Sstevel@tonic-gate m->mf_name, m->mf_fflags, 2309*7c478bd9Sstevel@tonic-gate (unsigned long) SMFI_CURR_ACTS); 2310*7c478bd9Sstevel@tonic-gate milter_error(m, e); 2311*7c478bd9Sstevel@tonic-gate return -1; 2312*7c478bd9Sstevel@tonic-gate } 2313*7c478bd9Sstevel@tonic-gate 2314*7c478bd9Sstevel@tonic-gate /* check for protocol feature mismatch */ 2315*7c478bd9Sstevel@tonic-gate if ((m->mf_pflags & SMFI_CURR_PROT) != m->mf_pflags) 2316*7c478bd9Sstevel@tonic-gate { 2317*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 2318*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_negotiate(%s): protocol abilities 0x%x != MTA milter abilities 0x%lx\n", 2319*7c478bd9Sstevel@tonic-gate m->mf_name, m->mf_pflags, 2320*7c478bd9Sstevel@tonic-gate (unsigned long) SMFI_CURR_PROT); 2321*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) 2322*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 2323*7c478bd9Sstevel@tonic-gate "Milter (%s): negotiate: protocol abilities 0x%x != MTA milter abilities 0x%lx", 2324*7c478bd9Sstevel@tonic-gate m->mf_name, m->mf_pflags, 2325*7c478bd9Sstevel@tonic-gate (unsigned long) SMFI_CURR_PROT); 2326*7c478bd9Sstevel@tonic-gate milter_error(m, e); 2327*7c478bd9Sstevel@tonic-gate return -1; 2328*7c478bd9Sstevel@tonic-gate } 2329*7c478bd9Sstevel@tonic-gate 2330*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 2331*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_negotiate(%s): version %u, fflags 0x%x, pflags 0x%x\n", 2332*7c478bd9Sstevel@tonic-gate m->mf_name, m->mf_fvers, m->mf_fflags, m->mf_pflags); 2333*7c478bd9Sstevel@tonic-gate return 0; 2334*7c478bd9Sstevel@tonic-gate } 2335*7c478bd9Sstevel@tonic-gate /* 2336*7c478bd9Sstevel@tonic-gate ** MILTER_PER_CONNECTION_CHECK -- checks on per-connection commands 2337*7c478bd9Sstevel@tonic-gate ** 2338*7c478bd9Sstevel@tonic-gate ** Reduce code duplication by putting these checks in one place 2339*7c478bd9Sstevel@tonic-gate ** 2340*7c478bd9Sstevel@tonic-gate ** Parameters: 2341*7c478bd9Sstevel@tonic-gate ** e -- current envelope. 2342*7c478bd9Sstevel@tonic-gate ** 2343*7c478bd9Sstevel@tonic-gate ** Returns: 2344*7c478bd9Sstevel@tonic-gate ** none 2345*7c478bd9Sstevel@tonic-gate */ 2346*7c478bd9Sstevel@tonic-gate 2347*7c478bd9Sstevel@tonic-gate static void 2348*7c478bd9Sstevel@tonic-gate milter_per_connection_check(e) 2349*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 2350*7c478bd9Sstevel@tonic-gate { 2351*7c478bd9Sstevel@tonic-gate int i; 2352*7c478bd9Sstevel@tonic-gate 2353*7c478bd9Sstevel@tonic-gate /* see if we are done with any of the filters */ 2354*7c478bd9Sstevel@tonic-gate for (i = 0; InputFilters[i] != NULL; i++) 2355*7c478bd9Sstevel@tonic-gate { 2356*7c478bd9Sstevel@tonic-gate struct milter *m = InputFilters[i]; 2357*7c478bd9Sstevel@tonic-gate 2358*7c478bd9Sstevel@tonic-gate if (m->mf_state == SMFS_CLOSABLE) 2359*7c478bd9Sstevel@tonic-gate milter_quit_filter(m, e); 2360*7c478bd9Sstevel@tonic-gate } 2361*7c478bd9Sstevel@tonic-gate } 2362*7c478bd9Sstevel@tonic-gate /* 2363*7c478bd9Sstevel@tonic-gate ** MILTER_ERROR -- Put a milter filter into error state 2364*7c478bd9Sstevel@tonic-gate ** 2365*7c478bd9Sstevel@tonic-gate ** Parameters: 2366*7c478bd9Sstevel@tonic-gate ** m -- the broken filter. 2367*7c478bd9Sstevel@tonic-gate ** e -- current envelope. 2368*7c478bd9Sstevel@tonic-gate ** 2369*7c478bd9Sstevel@tonic-gate ** Returns: 2370*7c478bd9Sstevel@tonic-gate ** none 2371*7c478bd9Sstevel@tonic-gate */ 2372*7c478bd9Sstevel@tonic-gate 2373*7c478bd9Sstevel@tonic-gate static void 2374*7c478bd9Sstevel@tonic-gate milter_error(m, e) 2375*7c478bd9Sstevel@tonic-gate struct milter *m; 2376*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 2377*7c478bd9Sstevel@tonic-gate { 2378*7c478bd9Sstevel@tonic-gate /* 2379*7c478bd9Sstevel@tonic-gate ** We could send a quit here but we may have gotten here due to 2380*7c478bd9Sstevel@tonic-gate ** an I/O error so we don't want to try to make things worse. 2381*7c478bd9Sstevel@tonic-gate */ 2382*7c478bd9Sstevel@tonic-gate 2383*7c478bd9Sstevel@tonic-gate if (m->mf_sock >= 0) 2384*7c478bd9Sstevel@tonic-gate { 2385*7c478bd9Sstevel@tonic-gate (void) close(m->mf_sock); 2386*7c478bd9Sstevel@tonic-gate m->mf_sock = -1; 2387*7c478bd9Sstevel@tonic-gate } 2388*7c478bd9Sstevel@tonic-gate m->mf_state = SMFS_ERROR; 2389*7c478bd9Sstevel@tonic-gate 2390*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) 2391*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter (%s): to error state", 2392*7c478bd9Sstevel@tonic-gate m->mf_name); 2393*7c478bd9Sstevel@tonic-gate } 2394*7c478bd9Sstevel@tonic-gate /* 2395*7c478bd9Sstevel@tonic-gate ** MILTER_HEADERS -- send headers to a single milter filter 2396*7c478bd9Sstevel@tonic-gate ** 2397*7c478bd9Sstevel@tonic-gate ** Parameters: 2398*7c478bd9Sstevel@tonic-gate ** m -- current filter. 2399*7c478bd9Sstevel@tonic-gate ** e -- current envelope. 2400*7c478bd9Sstevel@tonic-gate ** state -- return state from response. 2401*7c478bd9Sstevel@tonic-gate ** 2402*7c478bd9Sstevel@tonic-gate ** Returns: 2403*7c478bd9Sstevel@tonic-gate ** response string (may be NULL) 2404*7c478bd9Sstevel@tonic-gate */ 2405*7c478bd9Sstevel@tonic-gate 2406*7c478bd9Sstevel@tonic-gate static char * 2407*7c478bd9Sstevel@tonic-gate milter_headers(m, e, state) 2408*7c478bd9Sstevel@tonic-gate struct milter *m; 2409*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 2410*7c478bd9Sstevel@tonic-gate char *state; 2411*7c478bd9Sstevel@tonic-gate { 2412*7c478bd9Sstevel@tonic-gate char *response = NULL; 2413*7c478bd9Sstevel@tonic-gate HDR *h; 2414*7c478bd9Sstevel@tonic-gate 2415*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 17) 2416*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter (%s): headers, send", 2417*7c478bd9Sstevel@tonic-gate m->mf_name); 2418*7c478bd9Sstevel@tonic-gate 2419*7c478bd9Sstevel@tonic-gate for (h = e->e_header; h != NULL; h = h->h_link) 2420*7c478bd9Sstevel@tonic-gate { 2421*7c478bd9Sstevel@tonic-gate char *buf; 2422*7c478bd9Sstevel@tonic-gate ssize_t s; 2423*7c478bd9Sstevel@tonic-gate 2424*7c478bd9Sstevel@tonic-gate /* don't send over deleted headers */ 2425*7c478bd9Sstevel@tonic-gate if (h->h_value == NULL) 2426*7c478bd9Sstevel@tonic-gate { 2427*7c478bd9Sstevel@tonic-gate /* strip H_USER so not counted in milter_changeheader() */ 2428*7c478bd9Sstevel@tonic-gate h->h_flags &= ~H_USER; 2429*7c478bd9Sstevel@tonic-gate continue; 2430*7c478bd9Sstevel@tonic-gate } 2431*7c478bd9Sstevel@tonic-gate 2432*7c478bd9Sstevel@tonic-gate /* skip auto-generated */ 2433*7c478bd9Sstevel@tonic-gate if (!bitset(H_USER, h->h_flags)) 2434*7c478bd9Sstevel@tonic-gate continue; 2435*7c478bd9Sstevel@tonic-gate 2436*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 2437*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_headers: %s: %s\n", 2438*7c478bd9Sstevel@tonic-gate h->h_field, h->h_value); 2439*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 21) 2440*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter (%s): header, %s", 2441*7c478bd9Sstevel@tonic-gate m->mf_name, h->h_field); 2442*7c478bd9Sstevel@tonic-gate 2443*7c478bd9Sstevel@tonic-gate s = strlen(h->h_field) + 1 + strlen(h->h_value) + 1; 2444*7c478bd9Sstevel@tonic-gate if (s < 0) 2445*7c478bd9Sstevel@tonic-gate continue; 2446*7c478bd9Sstevel@tonic-gate buf = (char *) xalloc(s); 2447*7c478bd9Sstevel@tonic-gate (void) sm_snprintf(buf, s, "%s%c%s", 2448*7c478bd9Sstevel@tonic-gate h->h_field, '\0', h->h_value); 2449*7c478bd9Sstevel@tonic-gate 2450*7c478bd9Sstevel@tonic-gate /* send it over */ 2451*7c478bd9Sstevel@tonic-gate response = milter_send_command(m, SMFIC_HEADER, buf, 2452*7c478bd9Sstevel@tonic-gate s, e, state); 2453*7c478bd9Sstevel@tonic-gate sm_free(buf); /* XXX */ 2454*7c478bd9Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR || 2455*7c478bd9Sstevel@tonic-gate m->mf_state == SMFS_DONE || 2456*7c478bd9Sstevel@tonic-gate *state != SMFIR_CONTINUE) 2457*7c478bd9Sstevel@tonic-gate break; 2458*7c478bd9Sstevel@tonic-gate } 2459*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 17) 2460*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter (%s): headers, sent", 2461*7c478bd9Sstevel@tonic-gate m->mf_name); 2462*7c478bd9Sstevel@tonic-gate return response; 2463*7c478bd9Sstevel@tonic-gate } 2464*7c478bd9Sstevel@tonic-gate /* 2465*7c478bd9Sstevel@tonic-gate ** MILTER_BODY -- send the body to a filter 2466*7c478bd9Sstevel@tonic-gate ** 2467*7c478bd9Sstevel@tonic-gate ** Parameters: 2468*7c478bd9Sstevel@tonic-gate ** m -- current filter. 2469*7c478bd9Sstevel@tonic-gate ** e -- current envelope. 2470*7c478bd9Sstevel@tonic-gate ** state -- return state from response. 2471*7c478bd9Sstevel@tonic-gate ** 2472*7c478bd9Sstevel@tonic-gate ** Returns: 2473*7c478bd9Sstevel@tonic-gate ** response string (may be NULL) 2474*7c478bd9Sstevel@tonic-gate */ 2475*7c478bd9Sstevel@tonic-gate 2476*7c478bd9Sstevel@tonic-gate static char * 2477*7c478bd9Sstevel@tonic-gate milter_body(m, e, state) 2478*7c478bd9Sstevel@tonic-gate struct milter *m; 2479*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 2480*7c478bd9Sstevel@tonic-gate char *state; 2481*7c478bd9Sstevel@tonic-gate { 2482*7c478bd9Sstevel@tonic-gate char bufchar = '\0'; 2483*7c478bd9Sstevel@tonic-gate char prevchar = '\0'; 2484*7c478bd9Sstevel@tonic-gate int c; 2485*7c478bd9Sstevel@tonic-gate char *response = NULL; 2486*7c478bd9Sstevel@tonic-gate char *bp; 2487*7c478bd9Sstevel@tonic-gate char buf[MILTER_CHUNK_SIZE]; 2488*7c478bd9Sstevel@tonic-gate 2489*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 2490*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_body\n"); 2491*7c478bd9Sstevel@tonic-gate 2492*7c478bd9Sstevel@tonic-gate if (bfrewind(e->e_dfp) < 0) 2493*7c478bd9Sstevel@tonic-gate { 2494*7c478bd9Sstevel@tonic-gate ExitStat = EX_IOERR; 2495*7c478bd9Sstevel@tonic-gate *state = SMFIR_TEMPFAIL; 2496*7c478bd9Sstevel@tonic-gate syserr("milter_body: %s/%cf%s: rewind error", 2497*7c478bd9Sstevel@tonic-gate qid_printqueue(e->e_qgrp, e->e_qdir), 2498*7c478bd9Sstevel@tonic-gate DATAFL_LETTER, e->e_id); 2499*7c478bd9Sstevel@tonic-gate return NULL; 2500*7c478bd9Sstevel@tonic-gate } 2501*7c478bd9Sstevel@tonic-gate 2502*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 17) 2503*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter (%s): body, send", 2504*7c478bd9Sstevel@tonic-gate m->mf_name); 2505*7c478bd9Sstevel@tonic-gate bp = buf; 2506*7c478bd9Sstevel@tonic-gate while ((c = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT)) != SM_IO_EOF) 2507*7c478bd9Sstevel@tonic-gate { 2508*7c478bd9Sstevel@tonic-gate /* Change LF to CRLF */ 2509*7c478bd9Sstevel@tonic-gate if (c == '\n') 2510*7c478bd9Sstevel@tonic-gate { 2511*7c478bd9Sstevel@tonic-gate /* Not a CRLF already? */ 2512*7c478bd9Sstevel@tonic-gate if (prevchar != '\r') 2513*7c478bd9Sstevel@tonic-gate { 2514*7c478bd9Sstevel@tonic-gate /* Room for CR now? */ 2515*7c478bd9Sstevel@tonic-gate if (bp + 2 > &buf[sizeof buf]) 2516*7c478bd9Sstevel@tonic-gate { 2517*7c478bd9Sstevel@tonic-gate /* No room, buffer LF */ 2518*7c478bd9Sstevel@tonic-gate bufchar = c; 2519*7c478bd9Sstevel@tonic-gate 2520*7c478bd9Sstevel@tonic-gate /* and send CR now */ 2521*7c478bd9Sstevel@tonic-gate c = '\r'; 2522*7c478bd9Sstevel@tonic-gate } 2523*7c478bd9Sstevel@tonic-gate else 2524*7c478bd9Sstevel@tonic-gate { 2525*7c478bd9Sstevel@tonic-gate /* Room to do it now */ 2526*7c478bd9Sstevel@tonic-gate *bp++ = '\r'; 2527*7c478bd9Sstevel@tonic-gate prevchar = '\r'; 2528*7c478bd9Sstevel@tonic-gate } 2529*7c478bd9Sstevel@tonic-gate } 2530*7c478bd9Sstevel@tonic-gate } 2531*7c478bd9Sstevel@tonic-gate *bp++ = (char) c; 2532*7c478bd9Sstevel@tonic-gate prevchar = c; 2533*7c478bd9Sstevel@tonic-gate if (bp >= &buf[sizeof buf]) 2534*7c478bd9Sstevel@tonic-gate { 2535*7c478bd9Sstevel@tonic-gate /* send chunk */ 2536*7c478bd9Sstevel@tonic-gate response = milter_send_command(m, SMFIC_BODY, buf, 2537*7c478bd9Sstevel@tonic-gate bp - buf, e, state); 2538*7c478bd9Sstevel@tonic-gate bp = buf; 2539*7c478bd9Sstevel@tonic-gate if (bufchar != '\0') 2540*7c478bd9Sstevel@tonic-gate { 2541*7c478bd9Sstevel@tonic-gate *bp++ = bufchar; 2542*7c478bd9Sstevel@tonic-gate bufchar = '\0'; 2543*7c478bd9Sstevel@tonic-gate prevchar = bufchar; 2544*7c478bd9Sstevel@tonic-gate } 2545*7c478bd9Sstevel@tonic-gate } 2546*7c478bd9Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR || 2547*7c478bd9Sstevel@tonic-gate m->mf_state == SMFS_DONE || 2548*7c478bd9Sstevel@tonic-gate *state != SMFIR_CONTINUE) 2549*7c478bd9Sstevel@tonic-gate break; 2550*7c478bd9Sstevel@tonic-gate } 2551*7c478bd9Sstevel@tonic-gate 2552*7c478bd9Sstevel@tonic-gate /* check for read errors */ 2553*7c478bd9Sstevel@tonic-gate if (sm_io_error(e->e_dfp)) 2554*7c478bd9Sstevel@tonic-gate { 2555*7c478bd9Sstevel@tonic-gate ExitStat = EX_IOERR; 2556*7c478bd9Sstevel@tonic-gate if (*state == SMFIR_CONTINUE || 2557*7c478bd9Sstevel@tonic-gate *state == SMFIR_ACCEPT) 2558*7c478bd9Sstevel@tonic-gate { 2559*7c478bd9Sstevel@tonic-gate *state = SMFIR_TEMPFAIL; 2560*7c478bd9Sstevel@tonic-gate if (response != NULL) 2561*7c478bd9Sstevel@tonic-gate { 2562*7c478bd9Sstevel@tonic-gate sm_free(response); /* XXX */ 2563*7c478bd9Sstevel@tonic-gate response = NULL; 2564*7c478bd9Sstevel@tonic-gate } 2565*7c478bd9Sstevel@tonic-gate } 2566*7c478bd9Sstevel@tonic-gate syserr("milter_body: %s/%cf%s: read error", 2567*7c478bd9Sstevel@tonic-gate qid_printqueue(e->e_qgrp, e->e_qdir), 2568*7c478bd9Sstevel@tonic-gate DATAFL_LETTER, e->e_id); 2569*7c478bd9Sstevel@tonic-gate return response; 2570*7c478bd9Sstevel@tonic-gate } 2571*7c478bd9Sstevel@tonic-gate 2572*7c478bd9Sstevel@tonic-gate /* send last body chunk */ 2573*7c478bd9Sstevel@tonic-gate if (bp > buf && 2574*7c478bd9Sstevel@tonic-gate m->mf_state != SMFS_ERROR && 2575*7c478bd9Sstevel@tonic-gate m->mf_state != SMFS_DONE && 2576*7c478bd9Sstevel@tonic-gate *state == SMFIR_CONTINUE) 2577*7c478bd9Sstevel@tonic-gate { 2578*7c478bd9Sstevel@tonic-gate /* send chunk */ 2579*7c478bd9Sstevel@tonic-gate response = milter_send_command(m, SMFIC_BODY, buf, bp - buf, 2580*7c478bd9Sstevel@tonic-gate e, state); 2581*7c478bd9Sstevel@tonic-gate bp = buf; 2582*7c478bd9Sstevel@tonic-gate } 2583*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 17) 2584*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter (%s): body, sent", 2585*7c478bd9Sstevel@tonic-gate m->mf_name); 2586*7c478bd9Sstevel@tonic-gate return response; 2587*7c478bd9Sstevel@tonic-gate } 2588*7c478bd9Sstevel@tonic-gate 2589*7c478bd9Sstevel@tonic-gate /* 2590*7c478bd9Sstevel@tonic-gate ** Actions 2591*7c478bd9Sstevel@tonic-gate */ 2592*7c478bd9Sstevel@tonic-gate 2593*7c478bd9Sstevel@tonic-gate /* 2594*7c478bd9Sstevel@tonic-gate ** MILTER_ADDHEADER -- Add the supplied header to the message 2595*7c478bd9Sstevel@tonic-gate ** 2596*7c478bd9Sstevel@tonic-gate ** Parameters: 2597*7c478bd9Sstevel@tonic-gate ** response -- encoded form of header/value. 2598*7c478bd9Sstevel@tonic-gate ** rlen -- length of response. 2599*7c478bd9Sstevel@tonic-gate ** e -- current envelope. 2600*7c478bd9Sstevel@tonic-gate ** 2601*7c478bd9Sstevel@tonic-gate ** Returns: 2602*7c478bd9Sstevel@tonic-gate ** none 2603*7c478bd9Sstevel@tonic-gate */ 2604*7c478bd9Sstevel@tonic-gate 2605*7c478bd9Sstevel@tonic-gate static void 2606*7c478bd9Sstevel@tonic-gate milter_addheader(response, rlen, e) 2607*7c478bd9Sstevel@tonic-gate char *response; 2608*7c478bd9Sstevel@tonic-gate ssize_t rlen; 2609*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 2610*7c478bd9Sstevel@tonic-gate { 2611*7c478bd9Sstevel@tonic-gate char *val; 2612*7c478bd9Sstevel@tonic-gate HDR *h; 2613*7c478bd9Sstevel@tonic-gate 2614*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 2615*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_addheader: "); 2616*7c478bd9Sstevel@tonic-gate 2617*7c478bd9Sstevel@tonic-gate /* sanity checks */ 2618*7c478bd9Sstevel@tonic-gate if (response == NULL) 2619*7c478bd9Sstevel@tonic-gate { 2620*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 2621*7c478bd9Sstevel@tonic-gate sm_dprintf("NULL response\n"); 2622*7c478bd9Sstevel@tonic-gate return; 2623*7c478bd9Sstevel@tonic-gate } 2624*7c478bd9Sstevel@tonic-gate 2625*7c478bd9Sstevel@tonic-gate if (rlen < 2 || strlen(response) + 1 >= (size_t) rlen) 2626*7c478bd9Sstevel@tonic-gate { 2627*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 2628*7c478bd9Sstevel@tonic-gate sm_dprintf("didn't follow protocol (total len)\n"); 2629*7c478bd9Sstevel@tonic-gate return; 2630*7c478bd9Sstevel@tonic-gate } 2631*7c478bd9Sstevel@tonic-gate 2632*7c478bd9Sstevel@tonic-gate /* Find separating NUL */ 2633*7c478bd9Sstevel@tonic-gate val = response + strlen(response) + 1; 2634*7c478bd9Sstevel@tonic-gate 2635*7c478bd9Sstevel@tonic-gate /* another sanity check */ 2636*7c478bd9Sstevel@tonic-gate if (strlen(response) + strlen(val) + 2 != (size_t) rlen) 2637*7c478bd9Sstevel@tonic-gate { 2638*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 2639*7c478bd9Sstevel@tonic-gate sm_dprintf("didn't follow protocol (part len)\n"); 2640*7c478bd9Sstevel@tonic-gate return; 2641*7c478bd9Sstevel@tonic-gate } 2642*7c478bd9Sstevel@tonic-gate 2643*7c478bd9Sstevel@tonic-gate if (*response == '\0') 2644*7c478bd9Sstevel@tonic-gate { 2645*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 2646*7c478bd9Sstevel@tonic-gate sm_dprintf("empty field name\n"); 2647*7c478bd9Sstevel@tonic-gate return; 2648*7c478bd9Sstevel@tonic-gate } 2649*7c478bd9Sstevel@tonic-gate 2650*7c478bd9Sstevel@tonic-gate for (h = e->e_header; h != NULL; h = h->h_link) 2651*7c478bd9Sstevel@tonic-gate { 2652*7c478bd9Sstevel@tonic-gate if (sm_strcasecmp(h->h_field, response) == 0 && 2653*7c478bd9Sstevel@tonic-gate !bitset(H_USER, h->h_flags) && 2654*7c478bd9Sstevel@tonic-gate !bitset(H_TRACE, h->h_flags)) 2655*7c478bd9Sstevel@tonic-gate break; 2656*7c478bd9Sstevel@tonic-gate } 2657*7c478bd9Sstevel@tonic-gate 2658*7c478bd9Sstevel@tonic-gate /* add to e_msgsize */ 2659*7c478bd9Sstevel@tonic-gate e->e_msgsize += strlen(response) + 2 + strlen(val); 2660*7c478bd9Sstevel@tonic-gate 2661*7c478bd9Sstevel@tonic-gate if (h != NULL) 2662*7c478bd9Sstevel@tonic-gate { 2663*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 2664*7c478bd9Sstevel@tonic-gate sm_dprintf("Replace default header %s value with %s\n", 2665*7c478bd9Sstevel@tonic-gate h->h_field, val); 2666*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 8) 2667*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 2668*7c478bd9Sstevel@tonic-gate "Milter change: default header %s value with %s", 2669*7c478bd9Sstevel@tonic-gate h->h_field, val); 2670*7c478bd9Sstevel@tonic-gate h->h_value = newstr(val); 2671*7c478bd9Sstevel@tonic-gate h->h_flags |= H_USER; 2672*7c478bd9Sstevel@tonic-gate } 2673*7c478bd9Sstevel@tonic-gate else 2674*7c478bd9Sstevel@tonic-gate { 2675*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 2676*7c478bd9Sstevel@tonic-gate sm_dprintf("Add %s: %s\n", response, val); 2677*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 8) 2678*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter add: header: %s: %s", 2679*7c478bd9Sstevel@tonic-gate response, val); 2680*7c478bd9Sstevel@tonic-gate addheader(newstr(response), val, H_USER, e); 2681*7c478bd9Sstevel@tonic-gate } 2682*7c478bd9Sstevel@tonic-gate } 2683*7c478bd9Sstevel@tonic-gate /* 2684*7c478bd9Sstevel@tonic-gate ** MILTER_INSHEADER -- Insert the supplied header 2685*7c478bd9Sstevel@tonic-gate ** 2686*7c478bd9Sstevel@tonic-gate ** Parameters: 2687*7c478bd9Sstevel@tonic-gate ** response -- encoded form of header/value. 2688*7c478bd9Sstevel@tonic-gate ** rlen -- length of response. 2689*7c478bd9Sstevel@tonic-gate ** e -- current envelope. 2690*7c478bd9Sstevel@tonic-gate ** 2691*7c478bd9Sstevel@tonic-gate ** Returns: 2692*7c478bd9Sstevel@tonic-gate ** none 2693*7c478bd9Sstevel@tonic-gate ** 2694*7c478bd9Sstevel@tonic-gate ** Notes: 2695*7c478bd9Sstevel@tonic-gate ** Unlike milter_addheader(), this does not attempt to determine 2696*7c478bd9Sstevel@tonic-gate ** if the header already exists in the envelope, even a 2697*7c478bd9Sstevel@tonic-gate ** deleted version. It just blindly inserts. 2698*7c478bd9Sstevel@tonic-gate */ 2699*7c478bd9Sstevel@tonic-gate 2700*7c478bd9Sstevel@tonic-gate static void 2701*7c478bd9Sstevel@tonic-gate milter_insheader(response, rlen, e) 2702*7c478bd9Sstevel@tonic-gate char *response; 2703*7c478bd9Sstevel@tonic-gate ssize_t rlen; 2704*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 2705*7c478bd9Sstevel@tonic-gate { 2706*7c478bd9Sstevel@tonic-gate mi_int32 idx, i; 2707*7c478bd9Sstevel@tonic-gate char *field; 2708*7c478bd9Sstevel@tonic-gate char *val; 2709*7c478bd9Sstevel@tonic-gate 2710*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 2711*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_insheader: "); 2712*7c478bd9Sstevel@tonic-gate 2713*7c478bd9Sstevel@tonic-gate /* sanity checks */ 2714*7c478bd9Sstevel@tonic-gate if (response == NULL) 2715*7c478bd9Sstevel@tonic-gate { 2716*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 2717*7c478bd9Sstevel@tonic-gate sm_dprintf("NULL response\n"); 2718*7c478bd9Sstevel@tonic-gate return; 2719*7c478bd9Sstevel@tonic-gate } 2720*7c478bd9Sstevel@tonic-gate 2721*7c478bd9Sstevel@tonic-gate if (rlen < 2 || strlen(response) + 1 >= (size_t) rlen) 2722*7c478bd9Sstevel@tonic-gate { 2723*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 2724*7c478bd9Sstevel@tonic-gate sm_dprintf("didn't follow protocol (total len)\n"); 2725*7c478bd9Sstevel@tonic-gate return; 2726*7c478bd9Sstevel@tonic-gate } 2727*7c478bd9Sstevel@tonic-gate 2728*7c478bd9Sstevel@tonic-gate /* decode */ 2729*7c478bd9Sstevel@tonic-gate (void) memcpy((char *) &i, response, MILTER_LEN_BYTES); 2730*7c478bd9Sstevel@tonic-gate idx = ntohl(i); 2731*7c478bd9Sstevel@tonic-gate field = response + MILTER_LEN_BYTES; 2732*7c478bd9Sstevel@tonic-gate val = field + strlen(field) + 1; 2733*7c478bd9Sstevel@tonic-gate 2734*7c478bd9Sstevel@tonic-gate /* another sanity check */ 2735*7c478bd9Sstevel@tonic-gate if (MILTER_LEN_BYTES + strlen(field) + 1 + 2736*7c478bd9Sstevel@tonic-gate strlen(val) + 1 != (size_t) rlen) 2737*7c478bd9Sstevel@tonic-gate { 2738*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 2739*7c478bd9Sstevel@tonic-gate sm_dprintf("didn't follow protocol (part len)\n"); 2740*7c478bd9Sstevel@tonic-gate return; 2741*7c478bd9Sstevel@tonic-gate } 2742*7c478bd9Sstevel@tonic-gate 2743*7c478bd9Sstevel@tonic-gate if (*field == '\0') 2744*7c478bd9Sstevel@tonic-gate { 2745*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 2746*7c478bd9Sstevel@tonic-gate sm_dprintf("empty field name\n"); 2747*7c478bd9Sstevel@tonic-gate return; 2748*7c478bd9Sstevel@tonic-gate } 2749*7c478bd9Sstevel@tonic-gate 2750*7c478bd9Sstevel@tonic-gate /* add to e_msgsize */ 2751*7c478bd9Sstevel@tonic-gate e->e_msgsize += strlen(response) + 2 + strlen(val); 2752*7c478bd9Sstevel@tonic-gate 2753*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 2754*7c478bd9Sstevel@tonic-gate sm_dprintf("Insert (%d) %s: %s\n", idx, response, val); 2755*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 8) 2756*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 2757*7c478bd9Sstevel@tonic-gate "Milter insert (%d): header: %s: %s", 2758*7c478bd9Sstevel@tonic-gate idx, field, val); 2759*7c478bd9Sstevel@tonic-gate insheader(idx, newstr(field), val, H_USER, e); 2760*7c478bd9Sstevel@tonic-gate } 2761*7c478bd9Sstevel@tonic-gate /* 2762*7c478bd9Sstevel@tonic-gate ** MILTER_CHANGEHEADER -- Change the supplied header in the message 2763*7c478bd9Sstevel@tonic-gate ** 2764*7c478bd9Sstevel@tonic-gate ** Parameters: 2765*7c478bd9Sstevel@tonic-gate ** response -- encoded form of header/index/value. 2766*7c478bd9Sstevel@tonic-gate ** rlen -- length of response. 2767*7c478bd9Sstevel@tonic-gate ** e -- current envelope. 2768*7c478bd9Sstevel@tonic-gate ** 2769*7c478bd9Sstevel@tonic-gate ** Returns: 2770*7c478bd9Sstevel@tonic-gate ** none 2771*7c478bd9Sstevel@tonic-gate */ 2772*7c478bd9Sstevel@tonic-gate 2773*7c478bd9Sstevel@tonic-gate static void 2774*7c478bd9Sstevel@tonic-gate milter_changeheader(response, rlen, e) 2775*7c478bd9Sstevel@tonic-gate char *response; 2776*7c478bd9Sstevel@tonic-gate ssize_t rlen; 2777*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 2778*7c478bd9Sstevel@tonic-gate { 2779*7c478bd9Sstevel@tonic-gate mi_int32 i, index; 2780*7c478bd9Sstevel@tonic-gate char *field, *val; 2781*7c478bd9Sstevel@tonic-gate HDR *h, *sysheader; 2782*7c478bd9Sstevel@tonic-gate 2783*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 2784*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_changeheader: "); 2785*7c478bd9Sstevel@tonic-gate 2786*7c478bd9Sstevel@tonic-gate /* sanity checks */ 2787*7c478bd9Sstevel@tonic-gate if (response == NULL) 2788*7c478bd9Sstevel@tonic-gate { 2789*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 2790*7c478bd9Sstevel@tonic-gate sm_dprintf("NULL response\n"); 2791*7c478bd9Sstevel@tonic-gate return; 2792*7c478bd9Sstevel@tonic-gate } 2793*7c478bd9Sstevel@tonic-gate 2794*7c478bd9Sstevel@tonic-gate if (rlen < 2 || strlen(response) + 1 >= (size_t) rlen) 2795*7c478bd9Sstevel@tonic-gate { 2796*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 2797*7c478bd9Sstevel@tonic-gate sm_dprintf("didn't follow protocol (total len)\n"); 2798*7c478bd9Sstevel@tonic-gate return; 2799*7c478bd9Sstevel@tonic-gate } 2800*7c478bd9Sstevel@tonic-gate 2801*7c478bd9Sstevel@tonic-gate /* Find separating NUL */ 2802*7c478bd9Sstevel@tonic-gate (void) memcpy((char *) &i, response, MILTER_LEN_BYTES); 2803*7c478bd9Sstevel@tonic-gate index = ntohl(i); 2804*7c478bd9Sstevel@tonic-gate field = response + MILTER_LEN_BYTES; 2805*7c478bd9Sstevel@tonic-gate val = field + strlen(field) + 1; 2806*7c478bd9Sstevel@tonic-gate 2807*7c478bd9Sstevel@tonic-gate /* another sanity check */ 2808*7c478bd9Sstevel@tonic-gate if (MILTER_LEN_BYTES + strlen(field) + 1 + 2809*7c478bd9Sstevel@tonic-gate strlen(val) + 1 != (size_t) rlen) 2810*7c478bd9Sstevel@tonic-gate { 2811*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 2812*7c478bd9Sstevel@tonic-gate sm_dprintf("didn't follow protocol (part len)\n"); 2813*7c478bd9Sstevel@tonic-gate return; 2814*7c478bd9Sstevel@tonic-gate } 2815*7c478bd9Sstevel@tonic-gate 2816*7c478bd9Sstevel@tonic-gate if (*field == '\0') 2817*7c478bd9Sstevel@tonic-gate { 2818*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 2819*7c478bd9Sstevel@tonic-gate sm_dprintf("empty field name\n"); 2820*7c478bd9Sstevel@tonic-gate return; 2821*7c478bd9Sstevel@tonic-gate } 2822*7c478bd9Sstevel@tonic-gate 2823*7c478bd9Sstevel@tonic-gate sysheader = NULL; 2824*7c478bd9Sstevel@tonic-gate for (h = e->e_header; h != NULL; h = h->h_link) 2825*7c478bd9Sstevel@tonic-gate { 2826*7c478bd9Sstevel@tonic-gate if (sm_strcasecmp(h->h_field, field) == 0) 2827*7c478bd9Sstevel@tonic-gate { 2828*7c478bd9Sstevel@tonic-gate if (bitset(H_USER, h->h_flags) && 2829*7c478bd9Sstevel@tonic-gate --index <= 0) 2830*7c478bd9Sstevel@tonic-gate { 2831*7c478bd9Sstevel@tonic-gate sysheader = NULL; 2832*7c478bd9Sstevel@tonic-gate break; 2833*7c478bd9Sstevel@tonic-gate } 2834*7c478bd9Sstevel@tonic-gate else if (!bitset(H_USER, h->h_flags) && 2835*7c478bd9Sstevel@tonic-gate !bitset(H_TRACE, h->h_flags)) 2836*7c478bd9Sstevel@tonic-gate { 2837*7c478bd9Sstevel@tonic-gate /* 2838*7c478bd9Sstevel@tonic-gate ** DRUMS msg-fmt draft says can only have 2839*7c478bd9Sstevel@tonic-gate ** multiple occurences of trace fields, 2840*7c478bd9Sstevel@tonic-gate ** so make sure we replace any non-trace, 2841*7c478bd9Sstevel@tonic-gate ** non-user field. 2842*7c478bd9Sstevel@tonic-gate */ 2843*7c478bd9Sstevel@tonic-gate 2844*7c478bd9Sstevel@tonic-gate sysheader = h; 2845*7c478bd9Sstevel@tonic-gate } 2846*7c478bd9Sstevel@tonic-gate } 2847*7c478bd9Sstevel@tonic-gate } 2848*7c478bd9Sstevel@tonic-gate 2849*7c478bd9Sstevel@tonic-gate /* if not found as user-provided header at index, use sysheader */ 2850*7c478bd9Sstevel@tonic-gate if (h == NULL) 2851*7c478bd9Sstevel@tonic-gate h = sysheader; 2852*7c478bd9Sstevel@tonic-gate 2853*7c478bd9Sstevel@tonic-gate if (h == NULL) 2854*7c478bd9Sstevel@tonic-gate { 2855*7c478bd9Sstevel@tonic-gate if (*val == '\0') 2856*7c478bd9Sstevel@tonic-gate { 2857*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 2858*7c478bd9Sstevel@tonic-gate sm_dprintf("Delete (noop) %s\n", field); 2859*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 8) 2860*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 2861*7c478bd9Sstevel@tonic-gate "Milter delete (noop): header: %s" 2862*7c478bd9Sstevel@tonic-gate , field); 2863*7c478bd9Sstevel@tonic-gate } 2864*7c478bd9Sstevel@tonic-gate else 2865*7c478bd9Sstevel@tonic-gate { 2866*7c478bd9Sstevel@tonic-gate /* treat modify value with no existing header as add */ 2867*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 2868*7c478bd9Sstevel@tonic-gate sm_dprintf("Add %s: %s\n", field, val); 2869*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 8) 2870*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 2871*7c478bd9Sstevel@tonic-gate "Milter change (add): header: %s: %s" 2872*7c478bd9Sstevel@tonic-gate , field, val); 2873*7c478bd9Sstevel@tonic-gate addheader(newstr(field), val, H_USER, e); 2874*7c478bd9Sstevel@tonic-gate } 2875*7c478bd9Sstevel@tonic-gate return; 2876*7c478bd9Sstevel@tonic-gate } 2877*7c478bd9Sstevel@tonic-gate 2878*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 2879*7c478bd9Sstevel@tonic-gate { 2880*7c478bd9Sstevel@tonic-gate if (*val == '\0') 2881*7c478bd9Sstevel@tonic-gate { 2882*7c478bd9Sstevel@tonic-gate sm_dprintf("Delete%s %s: %s\n", 2883*7c478bd9Sstevel@tonic-gate h == sysheader ? " (default header)" : "", 2884*7c478bd9Sstevel@tonic-gate field, 2885*7c478bd9Sstevel@tonic-gate h->h_value == NULL ? "<NULL>" : h->h_value); 2886*7c478bd9Sstevel@tonic-gate } 2887*7c478bd9Sstevel@tonic-gate else 2888*7c478bd9Sstevel@tonic-gate { 2889*7c478bd9Sstevel@tonic-gate sm_dprintf("Change%s %s: from %s to %s\n", 2890*7c478bd9Sstevel@tonic-gate h == sysheader ? " (default header)" : "", 2891*7c478bd9Sstevel@tonic-gate field, 2892*7c478bd9Sstevel@tonic-gate h->h_value == NULL ? "<NULL>" : h->h_value, 2893*7c478bd9Sstevel@tonic-gate val); 2894*7c478bd9Sstevel@tonic-gate } 2895*7c478bd9Sstevel@tonic-gate } 2896*7c478bd9Sstevel@tonic-gate 2897*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 8) 2898*7c478bd9Sstevel@tonic-gate { 2899*7c478bd9Sstevel@tonic-gate if (*val == '\0') 2900*7c478bd9Sstevel@tonic-gate { 2901*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 2902*7c478bd9Sstevel@tonic-gate "Milter delete: header%s %s: %s", 2903*7c478bd9Sstevel@tonic-gate h == sysheader ? " (default header)" : "", 2904*7c478bd9Sstevel@tonic-gate field, 2905*7c478bd9Sstevel@tonic-gate h->h_value == NULL ? "<NULL>" : h->h_value); 2906*7c478bd9Sstevel@tonic-gate } 2907*7c478bd9Sstevel@tonic-gate else 2908*7c478bd9Sstevel@tonic-gate { 2909*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 2910*7c478bd9Sstevel@tonic-gate "Milter change: header%s %s: from %s to %s", 2911*7c478bd9Sstevel@tonic-gate h == sysheader ? " (default header)" : "", 2912*7c478bd9Sstevel@tonic-gate field, 2913*7c478bd9Sstevel@tonic-gate h->h_value == NULL ? "<NULL>" : h->h_value, 2914*7c478bd9Sstevel@tonic-gate val); 2915*7c478bd9Sstevel@tonic-gate } 2916*7c478bd9Sstevel@tonic-gate } 2917*7c478bd9Sstevel@tonic-gate 2918*7c478bd9Sstevel@tonic-gate if (h != sysheader && h->h_value != NULL) 2919*7c478bd9Sstevel@tonic-gate { 2920*7c478bd9Sstevel@tonic-gate size_t l; 2921*7c478bd9Sstevel@tonic-gate 2922*7c478bd9Sstevel@tonic-gate l = strlen(h->h_value); 2923*7c478bd9Sstevel@tonic-gate if (l > e->e_msgsize) 2924*7c478bd9Sstevel@tonic-gate e->e_msgsize = 0; 2925*7c478bd9Sstevel@tonic-gate else 2926*7c478bd9Sstevel@tonic-gate e->e_msgsize -= l; 2927*7c478bd9Sstevel@tonic-gate /* rpool, don't free: sm_free(h->h_value); XXX */ 2928*7c478bd9Sstevel@tonic-gate } 2929*7c478bd9Sstevel@tonic-gate 2930*7c478bd9Sstevel@tonic-gate if (*val == '\0') 2931*7c478bd9Sstevel@tonic-gate { 2932*7c478bd9Sstevel@tonic-gate /* Remove "Field: " from message size */ 2933*7c478bd9Sstevel@tonic-gate if (h != sysheader) 2934*7c478bd9Sstevel@tonic-gate { 2935*7c478bd9Sstevel@tonic-gate size_t l; 2936*7c478bd9Sstevel@tonic-gate 2937*7c478bd9Sstevel@tonic-gate l = strlen(h->h_field) + 2; 2938*7c478bd9Sstevel@tonic-gate if (l > e->e_msgsize) 2939*7c478bd9Sstevel@tonic-gate e->e_msgsize = 0; 2940*7c478bd9Sstevel@tonic-gate else 2941*7c478bd9Sstevel@tonic-gate e->e_msgsize -= l; 2942*7c478bd9Sstevel@tonic-gate } 2943*7c478bd9Sstevel@tonic-gate h->h_value = NULL; 2944*7c478bd9Sstevel@tonic-gate } 2945*7c478bd9Sstevel@tonic-gate else 2946*7c478bd9Sstevel@tonic-gate { 2947*7c478bd9Sstevel@tonic-gate h->h_value = newstr(val); 2948*7c478bd9Sstevel@tonic-gate h->h_flags |= H_USER; 2949*7c478bd9Sstevel@tonic-gate e->e_msgsize += strlen(h->h_value); 2950*7c478bd9Sstevel@tonic-gate } 2951*7c478bd9Sstevel@tonic-gate } 2952*7c478bd9Sstevel@tonic-gate /* 2953*7c478bd9Sstevel@tonic-gate ** MILTER_ADDRCPT -- Add the supplied recipient to the message 2954*7c478bd9Sstevel@tonic-gate ** 2955*7c478bd9Sstevel@tonic-gate ** Parameters: 2956*7c478bd9Sstevel@tonic-gate ** response -- encoded form of recipient address. 2957*7c478bd9Sstevel@tonic-gate ** rlen -- length of response. 2958*7c478bd9Sstevel@tonic-gate ** e -- current envelope. 2959*7c478bd9Sstevel@tonic-gate ** 2960*7c478bd9Sstevel@tonic-gate ** Returns: 2961*7c478bd9Sstevel@tonic-gate ** none 2962*7c478bd9Sstevel@tonic-gate */ 2963*7c478bd9Sstevel@tonic-gate 2964*7c478bd9Sstevel@tonic-gate static void 2965*7c478bd9Sstevel@tonic-gate milter_addrcpt(response, rlen, e) 2966*7c478bd9Sstevel@tonic-gate char *response; 2967*7c478bd9Sstevel@tonic-gate ssize_t rlen; 2968*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 2969*7c478bd9Sstevel@tonic-gate { 2970*7c478bd9Sstevel@tonic-gate int olderrors; 2971*7c478bd9Sstevel@tonic-gate 2972*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 2973*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_addrcpt: "); 2974*7c478bd9Sstevel@tonic-gate 2975*7c478bd9Sstevel@tonic-gate /* sanity checks */ 2976*7c478bd9Sstevel@tonic-gate if (response == NULL) 2977*7c478bd9Sstevel@tonic-gate { 2978*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 2979*7c478bd9Sstevel@tonic-gate sm_dprintf("NULL response\n"); 2980*7c478bd9Sstevel@tonic-gate return; 2981*7c478bd9Sstevel@tonic-gate } 2982*7c478bd9Sstevel@tonic-gate 2983*7c478bd9Sstevel@tonic-gate if (*response == '\0' || 2984*7c478bd9Sstevel@tonic-gate strlen(response) + 1 != (size_t) rlen) 2985*7c478bd9Sstevel@tonic-gate { 2986*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 2987*7c478bd9Sstevel@tonic-gate sm_dprintf("didn't follow protocol (total len %d != rlen %d)\n", 2988*7c478bd9Sstevel@tonic-gate (int) strlen(response), (int) (rlen - 1)); 2989*7c478bd9Sstevel@tonic-gate return; 2990*7c478bd9Sstevel@tonic-gate } 2991*7c478bd9Sstevel@tonic-gate 2992*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 2993*7c478bd9Sstevel@tonic-gate sm_dprintf("%s\n", response); 2994*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 8) 2995*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter add: rcpt: %s", response); 2996*7c478bd9Sstevel@tonic-gate olderrors = Errors; 2997*7c478bd9Sstevel@tonic-gate (void) sendtolist(response, NULLADDR, &e->e_sendqueue, 0, e); 2998*7c478bd9Sstevel@tonic-gate Errors = olderrors; 2999*7c478bd9Sstevel@tonic-gate return; 3000*7c478bd9Sstevel@tonic-gate } 3001*7c478bd9Sstevel@tonic-gate /* 3002*7c478bd9Sstevel@tonic-gate ** MILTER_DELRCPT -- Delete the supplied recipient from the message 3003*7c478bd9Sstevel@tonic-gate ** 3004*7c478bd9Sstevel@tonic-gate ** Parameters: 3005*7c478bd9Sstevel@tonic-gate ** response -- encoded form of recipient address. 3006*7c478bd9Sstevel@tonic-gate ** rlen -- length of response. 3007*7c478bd9Sstevel@tonic-gate ** e -- current envelope. 3008*7c478bd9Sstevel@tonic-gate ** 3009*7c478bd9Sstevel@tonic-gate ** Returns: 3010*7c478bd9Sstevel@tonic-gate ** none 3011*7c478bd9Sstevel@tonic-gate */ 3012*7c478bd9Sstevel@tonic-gate 3013*7c478bd9Sstevel@tonic-gate static void 3014*7c478bd9Sstevel@tonic-gate milter_delrcpt(response, rlen, e) 3015*7c478bd9Sstevel@tonic-gate char *response; 3016*7c478bd9Sstevel@tonic-gate ssize_t rlen; 3017*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 3018*7c478bd9Sstevel@tonic-gate { 3019*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 3020*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_delrcpt: "); 3021*7c478bd9Sstevel@tonic-gate 3022*7c478bd9Sstevel@tonic-gate /* sanity checks */ 3023*7c478bd9Sstevel@tonic-gate if (response == NULL) 3024*7c478bd9Sstevel@tonic-gate { 3025*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 3026*7c478bd9Sstevel@tonic-gate sm_dprintf("NULL response\n"); 3027*7c478bd9Sstevel@tonic-gate return; 3028*7c478bd9Sstevel@tonic-gate } 3029*7c478bd9Sstevel@tonic-gate 3030*7c478bd9Sstevel@tonic-gate if (*response == '\0' || 3031*7c478bd9Sstevel@tonic-gate strlen(response) + 1 != (size_t) rlen) 3032*7c478bd9Sstevel@tonic-gate { 3033*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 3034*7c478bd9Sstevel@tonic-gate sm_dprintf("didn't follow protocol (total len)\n"); 3035*7c478bd9Sstevel@tonic-gate return; 3036*7c478bd9Sstevel@tonic-gate } 3037*7c478bd9Sstevel@tonic-gate 3038*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 3039*7c478bd9Sstevel@tonic-gate sm_dprintf("%s\n", response); 3040*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 8) 3041*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter delete: rcpt %s", 3042*7c478bd9Sstevel@tonic-gate response); 3043*7c478bd9Sstevel@tonic-gate (void) removefromlist(response, &e->e_sendqueue, e); 3044*7c478bd9Sstevel@tonic-gate return; 3045*7c478bd9Sstevel@tonic-gate } 3046*7c478bd9Sstevel@tonic-gate /* 3047*7c478bd9Sstevel@tonic-gate ** MILTER_REPLBODY -- Replace the current data file with new body 3048*7c478bd9Sstevel@tonic-gate ** 3049*7c478bd9Sstevel@tonic-gate ** Parameters: 3050*7c478bd9Sstevel@tonic-gate ** response -- encoded form of new body. 3051*7c478bd9Sstevel@tonic-gate ** rlen -- length of response. 3052*7c478bd9Sstevel@tonic-gate ** newfilter -- if first time called by a new filter 3053*7c478bd9Sstevel@tonic-gate ** e -- current envelope. 3054*7c478bd9Sstevel@tonic-gate ** 3055*7c478bd9Sstevel@tonic-gate ** Returns: 3056*7c478bd9Sstevel@tonic-gate ** 0 upon success, -1 upon failure 3057*7c478bd9Sstevel@tonic-gate */ 3058*7c478bd9Sstevel@tonic-gate 3059*7c478bd9Sstevel@tonic-gate static int 3060*7c478bd9Sstevel@tonic-gate milter_replbody(response, rlen, newfilter, e) 3061*7c478bd9Sstevel@tonic-gate char *response; 3062*7c478bd9Sstevel@tonic-gate ssize_t rlen; 3063*7c478bd9Sstevel@tonic-gate bool newfilter; 3064*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 3065*7c478bd9Sstevel@tonic-gate { 3066*7c478bd9Sstevel@tonic-gate static char prevchar; 3067*7c478bd9Sstevel@tonic-gate int i; 3068*7c478bd9Sstevel@tonic-gate 3069*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 3070*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_replbody\n"); 3071*7c478bd9Sstevel@tonic-gate 3072*7c478bd9Sstevel@tonic-gate /* If a new filter, reset previous character and truncate data file */ 3073*7c478bd9Sstevel@tonic-gate if (newfilter) 3074*7c478bd9Sstevel@tonic-gate { 3075*7c478bd9Sstevel@tonic-gate off_t prevsize; 3076*7c478bd9Sstevel@tonic-gate char dfname[MAXPATHLEN]; 3077*7c478bd9Sstevel@tonic-gate 3078*7c478bd9Sstevel@tonic-gate (void) sm_strlcpy(dfname, queuename(e, DATAFL_LETTER), 3079*7c478bd9Sstevel@tonic-gate sizeof dfname); 3080*7c478bd9Sstevel@tonic-gate 3081*7c478bd9Sstevel@tonic-gate /* Reset prevchar */ 3082*7c478bd9Sstevel@tonic-gate prevchar = '\0'; 3083*7c478bd9Sstevel@tonic-gate 3084*7c478bd9Sstevel@tonic-gate /* Get the current data file information */ 3085*7c478bd9Sstevel@tonic-gate prevsize = sm_io_getinfo(e->e_dfp, SM_IO_WHAT_SIZE, NULL); 3086*7c478bd9Sstevel@tonic-gate if (prevsize < 0) 3087*7c478bd9Sstevel@tonic-gate prevsize = 0; 3088*7c478bd9Sstevel@tonic-gate 3089*7c478bd9Sstevel@tonic-gate /* truncate current data file */ 3090*7c478bd9Sstevel@tonic-gate if (sm_io_getinfo(e->e_dfp, SM_IO_WHAT_ISTYPE, BF_FILE_TYPE)) 3091*7c478bd9Sstevel@tonic-gate { 3092*7c478bd9Sstevel@tonic-gate if (sm_io_setinfo(e->e_dfp, SM_BF_TRUNCATE, NULL) < 0) 3093*7c478bd9Sstevel@tonic-gate { 3094*7c478bd9Sstevel@tonic-gate MILTER_DF_ERROR("milter_replbody: sm_io truncate %s: %s"); 3095*7c478bd9Sstevel@tonic-gate return -1; 3096*7c478bd9Sstevel@tonic-gate } 3097*7c478bd9Sstevel@tonic-gate } 3098*7c478bd9Sstevel@tonic-gate else 3099*7c478bd9Sstevel@tonic-gate { 3100*7c478bd9Sstevel@tonic-gate int err; 3101*7c478bd9Sstevel@tonic-gate 3102*7c478bd9Sstevel@tonic-gate err = sm_io_error(e->e_dfp); 3103*7c478bd9Sstevel@tonic-gate (void) sm_io_flush(e->e_dfp, SM_TIME_DEFAULT); 3104*7c478bd9Sstevel@tonic-gate 3105*7c478bd9Sstevel@tonic-gate /* 3106*7c478bd9Sstevel@tonic-gate ** Clear error if tried to fflush() 3107*7c478bd9Sstevel@tonic-gate ** a read-only file pointer and 3108*7c478bd9Sstevel@tonic-gate ** there wasn't a previous error. 3109*7c478bd9Sstevel@tonic-gate */ 3110*7c478bd9Sstevel@tonic-gate 3111*7c478bd9Sstevel@tonic-gate if (err == 0) 3112*7c478bd9Sstevel@tonic-gate sm_io_clearerr(e->e_dfp); 3113*7c478bd9Sstevel@tonic-gate 3114*7c478bd9Sstevel@tonic-gate /* errno is set implicitly by fseek() before return */ 3115*7c478bd9Sstevel@tonic-gate err = sm_io_seek(e->e_dfp, SM_TIME_DEFAULT, 3116*7c478bd9Sstevel@tonic-gate 0, SEEK_SET); 3117*7c478bd9Sstevel@tonic-gate if (err < 0) 3118*7c478bd9Sstevel@tonic-gate { 3119*7c478bd9Sstevel@tonic-gate MILTER_DF_ERROR("milter_replbody: sm_io_seek %s: %s"); 3120*7c478bd9Sstevel@tonic-gate return -1; 3121*7c478bd9Sstevel@tonic-gate } 3122*7c478bd9Sstevel@tonic-gate # if NOFTRUNCATE 3123*7c478bd9Sstevel@tonic-gate /* XXX: Not much we can do except rewind it */ 3124*7c478bd9Sstevel@tonic-gate errno = EINVAL; 3125*7c478bd9Sstevel@tonic-gate MILTER_DF_ERROR("milter_replbody: ftruncate not available on this platform (%s:%s)"); 3126*7c478bd9Sstevel@tonic-gate return -1; 3127*7c478bd9Sstevel@tonic-gate # else /* NOFTRUNCATE */ 3128*7c478bd9Sstevel@tonic-gate err = ftruncate(sm_io_getinfo(e->e_dfp, 3129*7c478bd9Sstevel@tonic-gate SM_IO_WHAT_FD, NULL), 3130*7c478bd9Sstevel@tonic-gate 0); 3131*7c478bd9Sstevel@tonic-gate if (err < 0) 3132*7c478bd9Sstevel@tonic-gate { 3133*7c478bd9Sstevel@tonic-gate MILTER_DF_ERROR("milter_replbody: sm_io ftruncate %s: %s"); 3134*7c478bd9Sstevel@tonic-gate return -1; 3135*7c478bd9Sstevel@tonic-gate } 3136*7c478bd9Sstevel@tonic-gate # endif /* NOFTRUNCATE */ 3137*7c478bd9Sstevel@tonic-gate } 3138*7c478bd9Sstevel@tonic-gate 3139*7c478bd9Sstevel@tonic-gate if (prevsize > e->e_msgsize) 3140*7c478bd9Sstevel@tonic-gate e->e_msgsize = 0; 3141*7c478bd9Sstevel@tonic-gate else 3142*7c478bd9Sstevel@tonic-gate e->e_msgsize -= prevsize; 3143*7c478bd9Sstevel@tonic-gate } 3144*7c478bd9Sstevel@tonic-gate 3145*7c478bd9Sstevel@tonic-gate if (newfilter && MilterLogLevel > 8) 3146*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter message: body replaced"); 3147*7c478bd9Sstevel@tonic-gate 3148*7c478bd9Sstevel@tonic-gate if (response == NULL) 3149*7c478bd9Sstevel@tonic-gate { 3150*7c478bd9Sstevel@tonic-gate /* Flush the buffered '\r' */ 3151*7c478bd9Sstevel@tonic-gate if (prevchar == '\r') 3152*7c478bd9Sstevel@tonic-gate { 3153*7c478bd9Sstevel@tonic-gate (void) sm_io_putc(e->e_dfp, SM_TIME_DEFAULT, prevchar); 3154*7c478bd9Sstevel@tonic-gate e->e_msgsize++; 3155*7c478bd9Sstevel@tonic-gate } 3156*7c478bd9Sstevel@tonic-gate return 0; 3157*7c478bd9Sstevel@tonic-gate } 3158*7c478bd9Sstevel@tonic-gate 3159*7c478bd9Sstevel@tonic-gate for (i = 0; i < rlen; i++) 3160*7c478bd9Sstevel@tonic-gate { 3161*7c478bd9Sstevel@tonic-gate /* Buffered char from last chunk */ 3162*7c478bd9Sstevel@tonic-gate if (i == 0 && prevchar == '\r') 3163*7c478bd9Sstevel@tonic-gate { 3164*7c478bd9Sstevel@tonic-gate /* Not CRLF, output prevchar */ 3165*7c478bd9Sstevel@tonic-gate if (response[i] != '\n') 3166*7c478bd9Sstevel@tonic-gate { 3167*7c478bd9Sstevel@tonic-gate (void) sm_io_putc(e->e_dfp, SM_TIME_DEFAULT, 3168*7c478bd9Sstevel@tonic-gate prevchar); 3169*7c478bd9Sstevel@tonic-gate e->e_msgsize++; 3170*7c478bd9Sstevel@tonic-gate } 3171*7c478bd9Sstevel@tonic-gate prevchar = '\0'; 3172*7c478bd9Sstevel@tonic-gate } 3173*7c478bd9Sstevel@tonic-gate 3174*7c478bd9Sstevel@tonic-gate /* Turn CRLF into LF */ 3175*7c478bd9Sstevel@tonic-gate if (response[i] == '\r') 3176*7c478bd9Sstevel@tonic-gate { 3177*7c478bd9Sstevel@tonic-gate /* check if at end of chunk */ 3178*7c478bd9Sstevel@tonic-gate if (i + 1 < rlen) 3179*7c478bd9Sstevel@tonic-gate { 3180*7c478bd9Sstevel@tonic-gate /* If LF, strip CR */ 3181*7c478bd9Sstevel@tonic-gate if (response[i + 1] == '\n') 3182*7c478bd9Sstevel@tonic-gate i++; 3183*7c478bd9Sstevel@tonic-gate } 3184*7c478bd9Sstevel@tonic-gate else 3185*7c478bd9Sstevel@tonic-gate { 3186*7c478bd9Sstevel@tonic-gate /* check next chunk */ 3187*7c478bd9Sstevel@tonic-gate prevchar = '\r'; 3188*7c478bd9Sstevel@tonic-gate continue; 3189*7c478bd9Sstevel@tonic-gate } 3190*7c478bd9Sstevel@tonic-gate } 3191*7c478bd9Sstevel@tonic-gate (void) sm_io_putc(e->e_dfp, SM_TIME_DEFAULT, response[i]); 3192*7c478bd9Sstevel@tonic-gate e->e_msgsize++; 3193*7c478bd9Sstevel@tonic-gate } 3194*7c478bd9Sstevel@tonic-gate return 0; 3195*7c478bd9Sstevel@tonic-gate } 3196*7c478bd9Sstevel@tonic-gate 3197*7c478bd9Sstevel@tonic-gate /* 3198*7c478bd9Sstevel@tonic-gate ** MTA callouts 3199*7c478bd9Sstevel@tonic-gate */ 3200*7c478bd9Sstevel@tonic-gate 3201*7c478bd9Sstevel@tonic-gate /* 3202*7c478bd9Sstevel@tonic-gate ** MILTER_INIT -- open and negotiate with all of the filters 3203*7c478bd9Sstevel@tonic-gate ** 3204*7c478bd9Sstevel@tonic-gate ** Parameters: 3205*7c478bd9Sstevel@tonic-gate ** e -- current envelope. 3206*7c478bd9Sstevel@tonic-gate ** state -- return state from response. 3207*7c478bd9Sstevel@tonic-gate ** 3208*7c478bd9Sstevel@tonic-gate ** Returns: 3209*7c478bd9Sstevel@tonic-gate ** true iff at least one filter is active 3210*7c478bd9Sstevel@tonic-gate */ 3211*7c478bd9Sstevel@tonic-gate 3212*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 3213*7c478bd9Sstevel@tonic-gate bool 3214*7c478bd9Sstevel@tonic-gate milter_init(e, state) 3215*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 3216*7c478bd9Sstevel@tonic-gate char *state; 3217*7c478bd9Sstevel@tonic-gate { 3218*7c478bd9Sstevel@tonic-gate int i; 3219*7c478bd9Sstevel@tonic-gate 3220*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 3221*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_init\n"); 3222*7c478bd9Sstevel@tonic-gate 3223*7c478bd9Sstevel@tonic-gate *state = SMFIR_CONTINUE; 3224*7c478bd9Sstevel@tonic-gate if (InputFilters[0] == NULL) 3225*7c478bd9Sstevel@tonic-gate { 3226*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 10) 3227*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 3228*7c478bd9Sstevel@tonic-gate "Milter: no active filter"); 3229*7c478bd9Sstevel@tonic-gate return false; 3230*7c478bd9Sstevel@tonic-gate } 3231*7c478bd9Sstevel@tonic-gate 3232*7c478bd9Sstevel@tonic-gate for (i = 0; InputFilters[i] != NULL; i++) 3233*7c478bd9Sstevel@tonic-gate { 3234*7c478bd9Sstevel@tonic-gate struct milter *m = InputFilters[i]; 3235*7c478bd9Sstevel@tonic-gate 3236*7c478bd9Sstevel@tonic-gate m->mf_sock = milter_open(m, false, e); 3237*7c478bd9Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR) 3238*7c478bd9Sstevel@tonic-gate { 3239*7c478bd9Sstevel@tonic-gate MILTER_CHECK_ERROR(true, continue); 3240*7c478bd9Sstevel@tonic-gate break; 3241*7c478bd9Sstevel@tonic-gate } 3242*7c478bd9Sstevel@tonic-gate 3243*7c478bd9Sstevel@tonic-gate if (m->mf_sock < 0 || 3244*7c478bd9Sstevel@tonic-gate milter_negotiate(m, e) < 0 || 3245*7c478bd9Sstevel@tonic-gate m->mf_state == SMFS_ERROR) 3246*7c478bd9Sstevel@tonic-gate { 3247*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 3248*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_init(%s): failed to %s\n", 3249*7c478bd9Sstevel@tonic-gate m->mf_name, 3250*7c478bd9Sstevel@tonic-gate m->mf_sock < 0 ? "open" : 3251*7c478bd9Sstevel@tonic-gate "negotiate"); 3252*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) 3253*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 3254*7c478bd9Sstevel@tonic-gate "Milter (%s): init failed to %s", 3255*7c478bd9Sstevel@tonic-gate m->mf_name, 3256*7c478bd9Sstevel@tonic-gate m->mf_sock < 0 ? "open" : 3257*7c478bd9Sstevel@tonic-gate "negotiate"); 3258*7c478bd9Sstevel@tonic-gate 3259*7c478bd9Sstevel@tonic-gate /* if negotation failure, close socket */ 3260*7c478bd9Sstevel@tonic-gate milter_error(m, e); 3261*7c478bd9Sstevel@tonic-gate MILTER_CHECK_ERROR(true, continue); 3262*7c478bd9Sstevel@tonic-gate continue; 3263*7c478bd9Sstevel@tonic-gate } 3264*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 9) 3265*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 3266*7c478bd9Sstevel@tonic-gate "Milter (%s): init success to %s", 3267*7c478bd9Sstevel@tonic-gate m->mf_name, 3268*7c478bd9Sstevel@tonic-gate m->mf_sock < 0 ? "open" : "negotiate"); 3269*7c478bd9Sstevel@tonic-gate } 3270*7c478bd9Sstevel@tonic-gate 3271*7c478bd9Sstevel@tonic-gate /* 3272*7c478bd9Sstevel@tonic-gate ** If something temp/perm failed with one of the filters, 3273*7c478bd9Sstevel@tonic-gate ** we won't be using any of them, so clear any existing 3274*7c478bd9Sstevel@tonic-gate ** connections. 3275*7c478bd9Sstevel@tonic-gate */ 3276*7c478bd9Sstevel@tonic-gate 3277*7c478bd9Sstevel@tonic-gate if (*state != SMFIR_CONTINUE) 3278*7c478bd9Sstevel@tonic-gate milter_quit(e); 3279*7c478bd9Sstevel@tonic-gate 3280*7c478bd9Sstevel@tonic-gate return true; 3281*7c478bd9Sstevel@tonic-gate } 3282*7c478bd9Sstevel@tonic-gate /* 3283*7c478bd9Sstevel@tonic-gate ** MILTER_CONNECT -- send connection info to milter filters 3284*7c478bd9Sstevel@tonic-gate ** 3285*7c478bd9Sstevel@tonic-gate ** Parameters: 3286*7c478bd9Sstevel@tonic-gate ** hostname -- hostname of remote machine. 3287*7c478bd9Sstevel@tonic-gate ** addr -- address of remote machine. 3288*7c478bd9Sstevel@tonic-gate ** e -- current envelope. 3289*7c478bd9Sstevel@tonic-gate ** state -- return state from response. 3290*7c478bd9Sstevel@tonic-gate ** 3291*7c478bd9Sstevel@tonic-gate ** Returns: 3292*7c478bd9Sstevel@tonic-gate ** response string (may be NULL) 3293*7c478bd9Sstevel@tonic-gate */ 3294*7c478bd9Sstevel@tonic-gate 3295*7c478bd9Sstevel@tonic-gate char * 3296*7c478bd9Sstevel@tonic-gate milter_connect(hostname, addr, e, state) 3297*7c478bd9Sstevel@tonic-gate char *hostname; 3298*7c478bd9Sstevel@tonic-gate SOCKADDR addr; 3299*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 3300*7c478bd9Sstevel@tonic-gate char *state; 3301*7c478bd9Sstevel@tonic-gate { 3302*7c478bd9Sstevel@tonic-gate char family; 3303*7c478bd9Sstevel@tonic-gate unsigned short port; 3304*7c478bd9Sstevel@tonic-gate char *buf, *bp; 3305*7c478bd9Sstevel@tonic-gate char *response; 3306*7c478bd9Sstevel@tonic-gate char *sockinfo = NULL; 3307*7c478bd9Sstevel@tonic-gate ssize_t s; 3308*7c478bd9Sstevel@tonic-gate # if NETINET6 3309*7c478bd9Sstevel@tonic-gate char buf6[INET6_ADDRSTRLEN]; 3310*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 3311*7c478bd9Sstevel@tonic-gate 3312*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 3313*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_connect(%s)\n", hostname); 3314*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 9) 3315*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter: connect to filters"); 3316*7c478bd9Sstevel@tonic-gate 3317*7c478bd9Sstevel@tonic-gate /* gather data */ 3318*7c478bd9Sstevel@tonic-gate switch (addr.sa.sa_family) 3319*7c478bd9Sstevel@tonic-gate { 3320*7c478bd9Sstevel@tonic-gate # if NETUNIX 3321*7c478bd9Sstevel@tonic-gate case AF_UNIX: 3322*7c478bd9Sstevel@tonic-gate family = SMFIA_UNIX; 3323*7c478bd9Sstevel@tonic-gate port = htons(0); 3324*7c478bd9Sstevel@tonic-gate sockinfo = addr.sunix.sun_path; 3325*7c478bd9Sstevel@tonic-gate break; 3326*7c478bd9Sstevel@tonic-gate # endif /* NETUNIX */ 3327*7c478bd9Sstevel@tonic-gate 3328*7c478bd9Sstevel@tonic-gate # if NETINET 3329*7c478bd9Sstevel@tonic-gate case AF_INET: 3330*7c478bd9Sstevel@tonic-gate family = SMFIA_INET; 3331*7c478bd9Sstevel@tonic-gate port = addr.sin.sin_port; 3332*7c478bd9Sstevel@tonic-gate sockinfo = (char *) inet_ntoa(addr.sin.sin_addr); 3333*7c478bd9Sstevel@tonic-gate break; 3334*7c478bd9Sstevel@tonic-gate # endif /* NETINET */ 3335*7c478bd9Sstevel@tonic-gate 3336*7c478bd9Sstevel@tonic-gate # if NETINET6 3337*7c478bd9Sstevel@tonic-gate case AF_INET6: 3338*7c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(&addr.sin6.sin6_addr)) 3339*7c478bd9Sstevel@tonic-gate family = SMFIA_INET; 3340*7c478bd9Sstevel@tonic-gate else 3341*7c478bd9Sstevel@tonic-gate family = SMFIA_INET6; 3342*7c478bd9Sstevel@tonic-gate port = addr.sin6.sin6_port; 3343*7c478bd9Sstevel@tonic-gate sockinfo = anynet_ntop(&addr.sin6.sin6_addr, buf6, 3344*7c478bd9Sstevel@tonic-gate sizeof buf6); 3345*7c478bd9Sstevel@tonic-gate if (sockinfo == NULL) 3346*7c478bd9Sstevel@tonic-gate sockinfo = ""; 3347*7c478bd9Sstevel@tonic-gate break; 3348*7c478bd9Sstevel@tonic-gate # endif /* NETINET6 */ 3349*7c478bd9Sstevel@tonic-gate 3350*7c478bd9Sstevel@tonic-gate default: 3351*7c478bd9Sstevel@tonic-gate family = SMFIA_UNKNOWN; 3352*7c478bd9Sstevel@tonic-gate break; 3353*7c478bd9Sstevel@tonic-gate } 3354*7c478bd9Sstevel@tonic-gate 3355*7c478bd9Sstevel@tonic-gate s = strlen(hostname) + 1 + sizeof(family); 3356*7c478bd9Sstevel@tonic-gate if (family != SMFIA_UNKNOWN) 3357*7c478bd9Sstevel@tonic-gate s += sizeof(port) + strlen(sockinfo) + 1; 3358*7c478bd9Sstevel@tonic-gate 3359*7c478bd9Sstevel@tonic-gate buf = (char *) xalloc(s); 3360*7c478bd9Sstevel@tonic-gate bp = buf; 3361*7c478bd9Sstevel@tonic-gate 3362*7c478bd9Sstevel@tonic-gate /* put together data */ 3363*7c478bd9Sstevel@tonic-gate (void) memcpy(bp, hostname, strlen(hostname)); 3364*7c478bd9Sstevel@tonic-gate bp += strlen(hostname); 3365*7c478bd9Sstevel@tonic-gate *bp++ = '\0'; 3366*7c478bd9Sstevel@tonic-gate (void) memcpy(bp, &family, sizeof family); 3367*7c478bd9Sstevel@tonic-gate bp += sizeof family; 3368*7c478bd9Sstevel@tonic-gate if (family != SMFIA_UNKNOWN) 3369*7c478bd9Sstevel@tonic-gate { 3370*7c478bd9Sstevel@tonic-gate (void) memcpy(bp, &port, sizeof port); 3371*7c478bd9Sstevel@tonic-gate bp += sizeof port; 3372*7c478bd9Sstevel@tonic-gate 3373*7c478bd9Sstevel@tonic-gate /* include trailing '\0' */ 3374*7c478bd9Sstevel@tonic-gate (void) memcpy(bp, sockinfo, strlen(sockinfo) + 1); 3375*7c478bd9Sstevel@tonic-gate } 3376*7c478bd9Sstevel@tonic-gate 3377*7c478bd9Sstevel@tonic-gate response = milter_command(SMFIC_CONNECT, buf, s, 3378*7c478bd9Sstevel@tonic-gate MilterConnectMacros, e, state); 3379*7c478bd9Sstevel@tonic-gate sm_free(buf); /* XXX */ 3380*7c478bd9Sstevel@tonic-gate 3381*7c478bd9Sstevel@tonic-gate /* 3382*7c478bd9Sstevel@tonic-gate ** If this message connection is done for, 3383*7c478bd9Sstevel@tonic-gate ** close the filters. 3384*7c478bd9Sstevel@tonic-gate */ 3385*7c478bd9Sstevel@tonic-gate 3386*7c478bd9Sstevel@tonic-gate if (*state != SMFIR_CONTINUE) 3387*7c478bd9Sstevel@tonic-gate { 3388*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 9) 3389*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter: connect, ending"); 3390*7c478bd9Sstevel@tonic-gate milter_quit(e); 3391*7c478bd9Sstevel@tonic-gate } 3392*7c478bd9Sstevel@tonic-gate else 3393*7c478bd9Sstevel@tonic-gate milter_per_connection_check(e); 3394*7c478bd9Sstevel@tonic-gate 3395*7c478bd9Sstevel@tonic-gate /* 3396*7c478bd9Sstevel@tonic-gate ** SMFIR_REPLYCODE can't work with connect due to 3397*7c478bd9Sstevel@tonic-gate ** the requirements of SMTP. Therefore, ignore the 3398*7c478bd9Sstevel@tonic-gate ** reply code text but keep the state it would reflect. 3399*7c478bd9Sstevel@tonic-gate */ 3400*7c478bd9Sstevel@tonic-gate 3401*7c478bd9Sstevel@tonic-gate if (*state == SMFIR_REPLYCODE) 3402*7c478bd9Sstevel@tonic-gate { 3403*7c478bd9Sstevel@tonic-gate if (response != NULL && 3404*7c478bd9Sstevel@tonic-gate *response == '4') 3405*7c478bd9Sstevel@tonic-gate { 3406*7c478bd9Sstevel@tonic-gate if (strncmp(response, "421 ", 4) == 0) 3407*7c478bd9Sstevel@tonic-gate *state = SMFIR_SHUTDOWN; 3408*7c478bd9Sstevel@tonic-gate else 3409*7c478bd9Sstevel@tonic-gate *state = SMFIR_TEMPFAIL; 3410*7c478bd9Sstevel@tonic-gate } 3411*7c478bd9Sstevel@tonic-gate else 3412*7c478bd9Sstevel@tonic-gate *state = SMFIR_REJECT; 3413*7c478bd9Sstevel@tonic-gate if (response != NULL) 3414*7c478bd9Sstevel@tonic-gate { 3415*7c478bd9Sstevel@tonic-gate sm_free(response); /* XXX */ 3416*7c478bd9Sstevel@tonic-gate response = NULL; 3417*7c478bd9Sstevel@tonic-gate } 3418*7c478bd9Sstevel@tonic-gate } 3419*7c478bd9Sstevel@tonic-gate return response; 3420*7c478bd9Sstevel@tonic-gate } 3421*7c478bd9Sstevel@tonic-gate /* 3422*7c478bd9Sstevel@tonic-gate ** MILTER_HELO -- send SMTP HELO/EHLO command info to milter filters 3423*7c478bd9Sstevel@tonic-gate ** 3424*7c478bd9Sstevel@tonic-gate ** Parameters: 3425*7c478bd9Sstevel@tonic-gate ** helo -- argument to SMTP HELO/EHLO command. 3426*7c478bd9Sstevel@tonic-gate ** e -- current envelope. 3427*7c478bd9Sstevel@tonic-gate ** state -- return state from response. 3428*7c478bd9Sstevel@tonic-gate ** 3429*7c478bd9Sstevel@tonic-gate ** Returns: 3430*7c478bd9Sstevel@tonic-gate ** response string (may be NULL) 3431*7c478bd9Sstevel@tonic-gate */ 3432*7c478bd9Sstevel@tonic-gate 3433*7c478bd9Sstevel@tonic-gate char * 3434*7c478bd9Sstevel@tonic-gate milter_helo(helo, e, state) 3435*7c478bd9Sstevel@tonic-gate char *helo; 3436*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 3437*7c478bd9Sstevel@tonic-gate char *state; 3438*7c478bd9Sstevel@tonic-gate { 3439*7c478bd9Sstevel@tonic-gate int i; 3440*7c478bd9Sstevel@tonic-gate char *response; 3441*7c478bd9Sstevel@tonic-gate 3442*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 3443*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_helo(%s)\n", helo); 3444*7c478bd9Sstevel@tonic-gate 3445*7c478bd9Sstevel@tonic-gate /* HELO/EHLO can come at any point */ 3446*7c478bd9Sstevel@tonic-gate for (i = 0; InputFilters[i] != NULL; i++) 3447*7c478bd9Sstevel@tonic-gate { 3448*7c478bd9Sstevel@tonic-gate struct milter *m = InputFilters[i]; 3449*7c478bd9Sstevel@tonic-gate 3450*7c478bd9Sstevel@tonic-gate switch (m->mf_state) 3451*7c478bd9Sstevel@tonic-gate { 3452*7c478bd9Sstevel@tonic-gate case SMFS_INMSG: 3453*7c478bd9Sstevel@tonic-gate /* abort in message filters */ 3454*7c478bd9Sstevel@tonic-gate milter_abort_filter(m, e); 3455*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 3456*7c478bd9Sstevel@tonic-gate 3457*7c478bd9Sstevel@tonic-gate case SMFS_DONE: 3458*7c478bd9Sstevel@tonic-gate /* reset done filters */ 3459*7c478bd9Sstevel@tonic-gate m->mf_state = SMFS_OPEN; 3460*7c478bd9Sstevel@tonic-gate break; 3461*7c478bd9Sstevel@tonic-gate } 3462*7c478bd9Sstevel@tonic-gate } 3463*7c478bd9Sstevel@tonic-gate 3464*7c478bd9Sstevel@tonic-gate response = milter_command(SMFIC_HELO, helo, strlen(helo) + 1, 3465*7c478bd9Sstevel@tonic-gate MilterHeloMacros, e, state); 3466*7c478bd9Sstevel@tonic-gate milter_per_connection_check(e); 3467*7c478bd9Sstevel@tonic-gate return response; 3468*7c478bd9Sstevel@tonic-gate } 3469*7c478bd9Sstevel@tonic-gate /* 3470*7c478bd9Sstevel@tonic-gate ** MILTER_ENVFROM -- send SMTP MAIL command info to milter filters 3471*7c478bd9Sstevel@tonic-gate ** 3472*7c478bd9Sstevel@tonic-gate ** Parameters: 3473*7c478bd9Sstevel@tonic-gate ** args -- SMTP MAIL command args (args[0] == sender). 3474*7c478bd9Sstevel@tonic-gate ** e -- current envelope. 3475*7c478bd9Sstevel@tonic-gate ** state -- return state from response. 3476*7c478bd9Sstevel@tonic-gate ** 3477*7c478bd9Sstevel@tonic-gate ** Returns: 3478*7c478bd9Sstevel@tonic-gate ** response string (may be NULL) 3479*7c478bd9Sstevel@tonic-gate */ 3480*7c478bd9Sstevel@tonic-gate 3481*7c478bd9Sstevel@tonic-gate char * 3482*7c478bd9Sstevel@tonic-gate milter_envfrom(args, e, state) 3483*7c478bd9Sstevel@tonic-gate char **args; 3484*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 3485*7c478bd9Sstevel@tonic-gate char *state; 3486*7c478bd9Sstevel@tonic-gate { 3487*7c478bd9Sstevel@tonic-gate int i; 3488*7c478bd9Sstevel@tonic-gate char *buf, *bp; 3489*7c478bd9Sstevel@tonic-gate char *response; 3490*7c478bd9Sstevel@tonic-gate ssize_t s; 3491*7c478bd9Sstevel@tonic-gate 3492*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 3493*7c478bd9Sstevel@tonic-gate { 3494*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_envfrom:"); 3495*7c478bd9Sstevel@tonic-gate for (i = 0; args[i] != NULL; i++) 3496*7c478bd9Sstevel@tonic-gate sm_dprintf(" %s", args[i]); 3497*7c478bd9Sstevel@tonic-gate sm_dprintf("\n"); 3498*7c478bd9Sstevel@tonic-gate } 3499*7c478bd9Sstevel@tonic-gate 3500*7c478bd9Sstevel@tonic-gate /* sanity check */ 3501*7c478bd9Sstevel@tonic-gate if (args[0] == NULL) 3502*7c478bd9Sstevel@tonic-gate { 3503*7c478bd9Sstevel@tonic-gate *state = SMFIR_REJECT; 3504*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 10) 3505*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 3506*7c478bd9Sstevel@tonic-gate "Milter: reject, no sender"); 3507*7c478bd9Sstevel@tonic-gate return NULL; 3508*7c478bd9Sstevel@tonic-gate } 3509*7c478bd9Sstevel@tonic-gate 3510*7c478bd9Sstevel@tonic-gate /* new message, so ... */ 3511*7c478bd9Sstevel@tonic-gate for (i = 0; InputFilters[i] != NULL; i++) 3512*7c478bd9Sstevel@tonic-gate { 3513*7c478bd9Sstevel@tonic-gate struct milter *m = InputFilters[i]; 3514*7c478bd9Sstevel@tonic-gate 3515*7c478bd9Sstevel@tonic-gate switch (m->mf_state) 3516*7c478bd9Sstevel@tonic-gate { 3517*7c478bd9Sstevel@tonic-gate case SMFS_INMSG: 3518*7c478bd9Sstevel@tonic-gate /* abort in message filters */ 3519*7c478bd9Sstevel@tonic-gate milter_abort_filter(m, e); 3520*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 3521*7c478bd9Sstevel@tonic-gate 3522*7c478bd9Sstevel@tonic-gate case SMFS_DONE: 3523*7c478bd9Sstevel@tonic-gate /* reset done filters */ 3524*7c478bd9Sstevel@tonic-gate m->mf_state = SMFS_OPEN; 3525*7c478bd9Sstevel@tonic-gate break; 3526*7c478bd9Sstevel@tonic-gate } 3527*7c478bd9Sstevel@tonic-gate } 3528*7c478bd9Sstevel@tonic-gate 3529*7c478bd9Sstevel@tonic-gate /* put together data */ 3530*7c478bd9Sstevel@tonic-gate s = 0; 3531*7c478bd9Sstevel@tonic-gate for (i = 0; args[i] != NULL; i++) 3532*7c478bd9Sstevel@tonic-gate s += strlen(args[i]) + 1; 3533*7c478bd9Sstevel@tonic-gate 3534*7c478bd9Sstevel@tonic-gate if (s < 0) 3535*7c478bd9Sstevel@tonic-gate { 3536*7c478bd9Sstevel@tonic-gate *state = SMFIR_TEMPFAIL; 3537*7c478bd9Sstevel@tonic-gate return NULL; 3538*7c478bd9Sstevel@tonic-gate } 3539*7c478bd9Sstevel@tonic-gate 3540*7c478bd9Sstevel@tonic-gate buf = (char *) xalloc(s); 3541*7c478bd9Sstevel@tonic-gate bp = buf; 3542*7c478bd9Sstevel@tonic-gate for (i = 0; args[i] != NULL; i++) 3543*7c478bd9Sstevel@tonic-gate { 3544*7c478bd9Sstevel@tonic-gate (void) sm_strlcpy(bp, args[i], s - (bp - buf)); 3545*7c478bd9Sstevel@tonic-gate bp += strlen(bp) + 1; 3546*7c478bd9Sstevel@tonic-gate } 3547*7c478bd9Sstevel@tonic-gate 3548*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 14) 3549*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter: senders: %s", buf); 3550*7c478bd9Sstevel@tonic-gate 3551*7c478bd9Sstevel@tonic-gate /* send it over */ 3552*7c478bd9Sstevel@tonic-gate response = milter_command(SMFIC_MAIL, buf, s, 3553*7c478bd9Sstevel@tonic-gate MilterEnvFromMacros, e, state); 3554*7c478bd9Sstevel@tonic-gate sm_free(buf); /* XXX */ 3555*7c478bd9Sstevel@tonic-gate 3556*7c478bd9Sstevel@tonic-gate /* 3557*7c478bd9Sstevel@tonic-gate ** If filter rejects/discards a per message command, 3558*7c478bd9Sstevel@tonic-gate ** abort the other filters since we are done with the 3559*7c478bd9Sstevel@tonic-gate ** current message. 3560*7c478bd9Sstevel@tonic-gate */ 3561*7c478bd9Sstevel@tonic-gate 3562*7c478bd9Sstevel@tonic-gate MILTER_CHECK_DONE_MSG(); 3563*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 10 && *state == SMFIR_REJECT) 3564*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter: reject, senders"); 3565*7c478bd9Sstevel@tonic-gate return response; 3566*7c478bd9Sstevel@tonic-gate } 3567*7c478bd9Sstevel@tonic-gate 3568*7c478bd9Sstevel@tonic-gate /* 3569*7c478bd9Sstevel@tonic-gate ** MILTER_ENVRCPT -- send SMTP RCPT command info to milter filters 3570*7c478bd9Sstevel@tonic-gate ** 3571*7c478bd9Sstevel@tonic-gate ** Parameters: 3572*7c478bd9Sstevel@tonic-gate ** args -- SMTP MAIL command args (args[0] == recipient). 3573*7c478bd9Sstevel@tonic-gate ** e -- current envelope. 3574*7c478bd9Sstevel@tonic-gate ** state -- return state from response. 3575*7c478bd9Sstevel@tonic-gate ** 3576*7c478bd9Sstevel@tonic-gate ** Returns: 3577*7c478bd9Sstevel@tonic-gate ** response string (may be NULL) 3578*7c478bd9Sstevel@tonic-gate */ 3579*7c478bd9Sstevel@tonic-gate 3580*7c478bd9Sstevel@tonic-gate char * 3581*7c478bd9Sstevel@tonic-gate milter_envrcpt(args, e, state) 3582*7c478bd9Sstevel@tonic-gate char **args; 3583*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 3584*7c478bd9Sstevel@tonic-gate char *state; 3585*7c478bd9Sstevel@tonic-gate { 3586*7c478bd9Sstevel@tonic-gate int i; 3587*7c478bd9Sstevel@tonic-gate char *buf, *bp; 3588*7c478bd9Sstevel@tonic-gate char *response; 3589*7c478bd9Sstevel@tonic-gate ssize_t s; 3590*7c478bd9Sstevel@tonic-gate 3591*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 3592*7c478bd9Sstevel@tonic-gate { 3593*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_envrcpt:"); 3594*7c478bd9Sstevel@tonic-gate for (i = 0; args[i] != NULL; i++) 3595*7c478bd9Sstevel@tonic-gate sm_dprintf(" %s", args[i]); 3596*7c478bd9Sstevel@tonic-gate sm_dprintf("\n"); 3597*7c478bd9Sstevel@tonic-gate } 3598*7c478bd9Sstevel@tonic-gate 3599*7c478bd9Sstevel@tonic-gate /* sanity check */ 3600*7c478bd9Sstevel@tonic-gate if (args[0] == NULL) 3601*7c478bd9Sstevel@tonic-gate { 3602*7c478bd9Sstevel@tonic-gate *state = SMFIR_REJECT; 3603*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 10) 3604*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter: reject, no rcpt"); 3605*7c478bd9Sstevel@tonic-gate return NULL; 3606*7c478bd9Sstevel@tonic-gate } 3607*7c478bd9Sstevel@tonic-gate 3608*7c478bd9Sstevel@tonic-gate /* put together data */ 3609*7c478bd9Sstevel@tonic-gate s = 0; 3610*7c478bd9Sstevel@tonic-gate for (i = 0; args[i] != NULL; i++) 3611*7c478bd9Sstevel@tonic-gate s += strlen(args[i]) + 1; 3612*7c478bd9Sstevel@tonic-gate 3613*7c478bd9Sstevel@tonic-gate if (s < 0) 3614*7c478bd9Sstevel@tonic-gate { 3615*7c478bd9Sstevel@tonic-gate *state = SMFIR_TEMPFAIL; 3616*7c478bd9Sstevel@tonic-gate return NULL; 3617*7c478bd9Sstevel@tonic-gate } 3618*7c478bd9Sstevel@tonic-gate 3619*7c478bd9Sstevel@tonic-gate buf = (char *) xalloc(s); 3620*7c478bd9Sstevel@tonic-gate bp = buf; 3621*7c478bd9Sstevel@tonic-gate for (i = 0; args[i] != NULL; i++) 3622*7c478bd9Sstevel@tonic-gate { 3623*7c478bd9Sstevel@tonic-gate (void) sm_strlcpy(bp, args[i], s - (bp - buf)); 3624*7c478bd9Sstevel@tonic-gate bp += strlen(bp) + 1; 3625*7c478bd9Sstevel@tonic-gate } 3626*7c478bd9Sstevel@tonic-gate 3627*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 14) 3628*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter: rcpts: %s", buf); 3629*7c478bd9Sstevel@tonic-gate 3630*7c478bd9Sstevel@tonic-gate /* send it over */ 3631*7c478bd9Sstevel@tonic-gate response = milter_command(SMFIC_RCPT, buf, s, 3632*7c478bd9Sstevel@tonic-gate MilterEnvRcptMacros, e, state); 3633*7c478bd9Sstevel@tonic-gate sm_free(buf); /* XXX */ 3634*7c478bd9Sstevel@tonic-gate return response; 3635*7c478bd9Sstevel@tonic-gate } 3636*7c478bd9Sstevel@tonic-gate 3637*7c478bd9Sstevel@tonic-gate #if SMFI_VERSION > 3 3638*7c478bd9Sstevel@tonic-gate /* 3639*7c478bd9Sstevel@tonic-gate ** MILTER_DATA_CMD -- send SMTP DATA command info to milter filters 3640*7c478bd9Sstevel@tonic-gate ** 3641*7c478bd9Sstevel@tonic-gate ** Parameters: 3642*7c478bd9Sstevel@tonic-gate ** e -- current envelope. 3643*7c478bd9Sstevel@tonic-gate ** state -- return state from response. 3644*7c478bd9Sstevel@tonic-gate ** 3645*7c478bd9Sstevel@tonic-gate ** Returns: 3646*7c478bd9Sstevel@tonic-gate ** response string (may be NULL) 3647*7c478bd9Sstevel@tonic-gate */ 3648*7c478bd9Sstevel@tonic-gate 3649*7c478bd9Sstevel@tonic-gate char * 3650*7c478bd9Sstevel@tonic-gate milter_data_cmd(e, state) 3651*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 3652*7c478bd9Sstevel@tonic-gate char *state; 3653*7c478bd9Sstevel@tonic-gate { 3654*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 3655*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_data_cmd\n"); 3656*7c478bd9Sstevel@tonic-gate 3657*7c478bd9Sstevel@tonic-gate /* send it over */ 3658*7c478bd9Sstevel@tonic-gate return milter_command(SMFIC_DATA, NULL, 0, MilterDataMacros, e, state); 3659*7c478bd9Sstevel@tonic-gate } 3660*7c478bd9Sstevel@tonic-gate #endif /* SMFI_VERSION > 3 */ 3661*7c478bd9Sstevel@tonic-gate 3662*7c478bd9Sstevel@tonic-gate /* 3663*7c478bd9Sstevel@tonic-gate ** MILTER_DATA -- send message headers/body and gather final message results 3664*7c478bd9Sstevel@tonic-gate ** 3665*7c478bd9Sstevel@tonic-gate ** Parameters: 3666*7c478bd9Sstevel@tonic-gate ** e -- current envelope. 3667*7c478bd9Sstevel@tonic-gate ** state -- return state from response. 3668*7c478bd9Sstevel@tonic-gate ** 3669*7c478bd9Sstevel@tonic-gate ** Returns: 3670*7c478bd9Sstevel@tonic-gate ** response string (may be NULL) 3671*7c478bd9Sstevel@tonic-gate ** 3672*7c478bd9Sstevel@tonic-gate ** Side effects: 3673*7c478bd9Sstevel@tonic-gate ** - Uses e->e_dfp for access to the body 3674*7c478bd9Sstevel@tonic-gate ** - Can call the various milter action routines to 3675*7c478bd9Sstevel@tonic-gate ** modify the envelope or message. 3676*7c478bd9Sstevel@tonic-gate */ 3677*7c478bd9Sstevel@tonic-gate 3678*7c478bd9Sstevel@tonic-gate # define MILTER_CHECK_RESULTS() \ 3679*7c478bd9Sstevel@tonic-gate if (*state == SMFIR_ACCEPT || \ 3680*7c478bd9Sstevel@tonic-gate m->mf_state == SMFS_DONE || \ 3681*7c478bd9Sstevel@tonic-gate m->mf_state == SMFS_ERROR) \ 3682*7c478bd9Sstevel@tonic-gate { \ 3683*7c478bd9Sstevel@tonic-gate if (m->mf_state != SMFS_ERROR) \ 3684*7c478bd9Sstevel@tonic-gate m->mf_state = SMFS_DONE; \ 3685*7c478bd9Sstevel@tonic-gate continue; /* to next filter */ \ 3686*7c478bd9Sstevel@tonic-gate } \ 3687*7c478bd9Sstevel@tonic-gate if (*state != SMFIR_CONTINUE) \ 3688*7c478bd9Sstevel@tonic-gate { \ 3689*7c478bd9Sstevel@tonic-gate m->mf_state = SMFS_DONE; \ 3690*7c478bd9Sstevel@tonic-gate goto finishup; \ 3691*7c478bd9Sstevel@tonic-gate } 3692*7c478bd9Sstevel@tonic-gate 3693*7c478bd9Sstevel@tonic-gate char * 3694*7c478bd9Sstevel@tonic-gate milter_data(e, state) 3695*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 3696*7c478bd9Sstevel@tonic-gate char *state; 3697*7c478bd9Sstevel@tonic-gate { 3698*7c478bd9Sstevel@tonic-gate bool replbody = false; /* milter_replbody() called? */ 3699*7c478bd9Sstevel@tonic-gate bool replfailed = false; /* milter_replbody() failed? */ 3700*7c478bd9Sstevel@tonic-gate bool rewind = false; /* rewind data file? */ 3701*7c478bd9Sstevel@tonic-gate bool dfopen = false; /* data file open for writing? */ 3702*7c478bd9Sstevel@tonic-gate bool newfilter; /* reset on each new filter */ 3703*7c478bd9Sstevel@tonic-gate char rcmd; 3704*7c478bd9Sstevel@tonic-gate int i; 3705*7c478bd9Sstevel@tonic-gate int save_errno; 3706*7c478bd9Sstevel@tonic-gate char *response = NULL; 3707*7c478bd9Sstevel@tonic-gate time_t eomsent; 3708*7c478bd9Sstevel@tonic-gate ssize_t rlen; 3709*7c478bd9Sstevel@tonic-gate 3710*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 3711*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_data\n"); 3712*7c478bd9Sstevel@tonic-gate 3713*7c478bd9Sstevel@tonic-gate *state = SMFIR_CONTINUE; 3714*7c478bd9Sstevel@tonic-gate 3715*7c478bd9Sstevel@tonic-gate /* 3716*7c478bd9Sstevel@tonic-gate ** XXX: Should actually send body chunks to each filter 3717*7c478bd9Sstevel@tonic-gate ** a chunk at a time instead of sending the whole body to 3718*7c478bd9Sstevel@tonic-gate ** each filter in turn. However, only if the filters don't 3719*7c478bd9Sstevel@tonic-gate ** change the body. 3720*7c478bd9Sstevel@tonic-gate */ 3721*7c478bd9Sstevel@tonic-gate 3722*7c478bd9Sstevel@tonic-gate for (i = 0; InputFilters[i] != NULL; i++) 3723*7c478bd9Sstevel@tonic-gate { 3724*7c478bd9Sstevel@tonic-gate struct milter *m = InputFilters[i]; 3725*7c478bd9Sstevel@tonic-gate 3726*7c478bd9Sstevel@tonic-gate if (*state != SMFIR_CONTINUE && 3727*7c478bd9Sstevel@tonic-gate *state != SMFIR_ACCEPT) 3728*7c478bd9Sstevel@tonic-gate { 3729*7c478bd9Sstevel@tonic-gate /* 3730*7c478bd9Sstevel@tonic-gate ** A previous filter has dealt with the message, 3731*7c478bd9Sstevel@tonic-gate ** safe to stop processing the filters. 3732*7c478bd9Sstevel@tonic-gate */ 3733*7c478bd9Sstevel@tonic-gate 3734*7c478bd9Sstevel@tonic-gate break; 3735*7c478bd9Sstevel@tonic-gate } 3736*7c478bd9Sstevel@tonic-gate 3737*7c478bd9Sstevel@tonic-gate /* Now reset state for later evaluation */ 3738*7c478bd9Sstevel@tonic-gate *state = SMFIR_CONTINUE; 3739*7c478bd9Sstevel@tonic-gate newfilter = true; 3740*7c478bd9Sstevel@tonic-gate 3741*7c478bd9Sstevel@tonic-gate /* previous problem? */ 3742*7c478bd9Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR) 3743*7c478bd9Sstevel@tonic-gate { 3744*7c478bd9Sstevel@tonic-gate MILTER_CHECK_ERROR(false, continue); 3745*7c478bd9Sstevel@tonic-gate break; 3746*7c478bd9Sstevel@tonic-gate } 3747*7c478bd9Sstevel@tonic-gate 3748*7c478bd9Sstevel@tonic-gate /* sanity checks */ 3749*7c478bd9Sstevel@tonic-gate if (m->mf_sock < 0 || 3750*7c478bd9Sstevel@tonic-gate (m->mf_state != SMFS_OPEN && m->mf_state != SMFS_INMSG)) 3751*7c478bd9Sstevel@tonic-gate continue; 3752*7c478bd9Sstevel@tonic-gate 3753*7c478bd9Sstevel@tonic-gate m->mf_state = SMFS_INMSG; 3754*7c478bd9Sstevel@tonic-gate 3755*7c478bd9Sstevel@tonic-gate /* check if filter wants the headers */ 3756*7c478bd9Sstevel@tonic-gate if (!bitset(SMFIP_NOHDRS, m->mf_pflags)) 3757*7c478bd9Sstevel@tonic-gate { 3758*7c478bd9Sstevel@tonic-gate response = milter_headers(m, e, state); 3759*7c478bd9Sstevel@tonic-gate MILTER_CHECK_RESULTS(); 3760*7c478bd9Sstevel@tonic-gate } 3761*7c478bd9Sstevel@tonic-gate 3762*7c478bd9Sstevel@tonic-gate /* check if filter wants EOH */ 3763*7c478bd9Sstevel@tonic-gate if (!bitset(SMFIP_NOEOH, m->mf_pflags)) 3764*7c478bd9Sstevel@tonic-gate { 3765*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 3766*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_data: eoh\n"); 3767*7c478bd9Sstevel@tonic-gate 3768*7c478bd9Sstevel@tonic-gate /* send it over */ 3769*7c478bd9Sstevel@tonic-gate response = milter_send_command(m, SMFIC_EOH, NULL, 0, 3770*7c478bd9Sstevel@tonic-gate e, state); 3771*7c478bd9Sstevel@tonic-gate MILTER_CHECK_RESULTS(); 3772*7c478bd9Sstevel@tonic-gate } 3773*7c478bd9Sstevel@tonic-gate 3774*7c478bd9Sstevel@tonic-gate /* check if filter wants the body */ 3775*7c478bd9Sstevel@tonic-gate if (!bitset(SMFIP_NOBODY, m->mf_pflags) && 3776*7c478bd9Sstevel@tonic-gate e->e_dfp != NULL) 3777*7c478bd9Sstevel@tonic-gate { 3778*7c478bd9Sstevel@tonic-gate rewind = true; 3779*7c478bd9Sstevel@tonic-gate response = milter_body(m, e, state); 3780*7c478bd9Sstevel@tonic-gate MILTER_CHECK_RESULTS(); 3781*7c478bd9Sstevel@tonic-gate } 3782*7c478bd9Sstevel@tonic-gate 3783*7c478bd9Sstevel@tonic-gate if (MilterEOMMacros[0] != NULL) 3784*7c478bd9Sstevel@tonic-gate { 3785*7c478bd9Sstevel@tonic-gate milter_send_macros(m, MilterEOMMacros, 3786*7c478bd9Sstevel@tonic-gate SMFIC_BODYEOB, e); 3787*7c478bd9Sstevel@tonic-gate MILTER_CHECK_RESULTS(); 3788*7c478bd9Sstevel@tonic-gate } 3789*7c478bd9Sstevel@tonic-gate 3790*7c478bd9Sstevel@tonic-gate /* send the final body chunk */ 3791*7c478bd9Sstevel@tonic-gate (void) milter_write(m, SMFIC_BODYEOB, NULL, 0, 3792*7c478bd9Sstevel@tonic-gate m->mf_timeout[SMFTO_WRITE], e); 3793*7c478bd9Sstevel@tonic-gate 3794*7c478bd9Sstevel@tonic-gate /* Get time EOM sent for timeout */ 3795*7c478bd9Sstevel@tonic-gate eomsent = curtime(); 3796*7c478bd9Sstevel@tonic-gate 3797*7c478bd9Sstevel@tonic-gate /* deal with the possibility of multiple responses */ 3798*7c478bd9Sstevel@tonic-gate while (*state == SMFIR_CONTINUE) 3799*7c478bd9Sstevel@tonic-gate { 3800*7c478bd9Sstevel@tonic-gate /* Check total timeout from EOM to final ACK/NAK */ 3801*7c478bd9Sstevel@tonic-gate if (m->mf_timeout[SMFTO_EOM] > 0 && 3802*7c478bd9Sstevel@tonic-gate curtime() - eomsent >= m->mf_timeout[SMFTO_EOM]) 3803*7c478bd9Sstevel@tonic-gate { 3804*7c478bd9Sstevel@tonic-gate if (tTd(64, 5)) 3805*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_data(%s): EOM ACK/NAK timeout\n", 3806*7c478bd9Sstevel@tonic-gate m->mf_name); 3807*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) 3808*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 3809*7c478bd9Sstevel@tonic-gate "milter_data(%s): EOM ACK/NAK timeout", 3810*7c478bd9Sstevel@tonic-gate m->mf_name); 3811*7c478bd9Sstevel@tonic-gate milter_error(m, e); 3812*7c478bd9Sstevel@tonic-gate MILTER_CHECK_ERROR(false, break); 3813*7c478bd9Sstevel@tonic-gate break; 3814*7c478bd9Sstevel@tonic-gate } 3815*7c478bd9Sstevel@tonic-gate 3816*7c478bd9Sstevel@tonic-gate response = milter_read(m, &rcmd, &rlen, 3817*7c478bd9Sstevel@tonic-gate m->mf_timeout[SMFTO_READ], e); 3818*7c478bd9Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR) 3819*7c478bd9Sstevel@tonic-gate break; 3820*7c478bd9Sstevel@tonic-gate 3821*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 3822*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_data(%s): state %c\n", 3823*7c478bd9Sstevel@tonic-gate m->mf_name, (char) rcmd); 3824*7c478bd9Sstevel@tonic-gate 3825*7c478bd9Sstevel@tonic-gate switch (rcmd) 3826*7c478bd9Sstevel@tonic-gate { 3827*7c478bd9Sstevel@tonic-gate case SMFIR_REPLYCODE: 3828*7c478bd9Sstevel@tonic-gate MILTER_CHECK_REPLYCODE("554 5.7.1 Command rejected"); 3829*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 12) 3830*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "milter=%s, reject=%s", 3831*7c478bd9Sstevel@tonic-gate m->mf_name, response); 3832*7c478bd9Sstevel@tonic-gate *state = rcmd; 3833*7c478bd9Sstevel@tonic-gate m->mf_state = SMFS_DONE; 3834*7c478bd9Sstevel@tonic-gate break; 3835*7c478bd9Sstevel@tonic-gate 3836*7c478bd9Sstevel@tonic-gate case SMFIR_REJECT: /* log msg at end of function */ 3837*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 12) 3838*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "milter=%s, reject", 3839*7c478bd9Sstevel@tonic-gate m->mf_name); 3840*7c478bd9Sstevel@tonic-gate *state = rcmd; 3841*7c478bd9Sstevel@tonic-gate m->mf_state = SMFS_DONE; 3842*7c478bd9Sstevel@tonic-gate break; 3843*7c478bd9Sstevel@tonic-gate 3844*7c478bd9Sstevel@tonic-gate case SMFIR_DISCARD: 3845*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 12) 3846*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "milter=%s, discard", 3847*7c478bd9Sstevel@tonic-gate m->mf_name); 3848*7c478bd9Sstevel@tonic-gate *state = rcmd; 3849*7c478bd9Sstevel@tonic-gate m->mf_state = SMFS_DONE; 3850*7c478bd9Sstevel@tonic-gate break; 3851*7c478bd9Sstevel@tonic-gate 3852*7c478bd9Sstevel@tonic-gate case SMFIR_TEMPFAIL: 3853*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 12) 3854*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "milter=%s, tempfail", 3855*7c478bd9Sstevel@tonic-gate m->mf_name); 3856*7c478bd9Sstevel@tonic-gate *state = rcmd; 3857*7c478bd9Sstevel@tonic-gate m->mf_state = SMFS_DONE; 3858*7c478bd9Sstevel@tonic-gate break; 3859*7c478bd9Sstevel@tonic-gate 3860*7c478bd9Sstevel@tonic-gate case SMFIR_CONTINUE: 3861*7c478bd9Sstevel@tonic-gate case SMFIR_ACCEPT: 3862*7c478bd9Sstevel@tonic-gate /* this filter is done with message */ 3863*7c478bd9Sstevel@tonic-gate if (replfailed) 3864*7c478bd9Sstevel@tonic-gate *state = SMFIR_TEMPFAIL; 3865*7c478bd9Sstevel@tonic-gate else 3866*7c478bd9Sstevel@tonic-gate *state = SMFIR_ACCEPT; 3867*7c478bd9Sstevel@tonic-gate m->mf_state = SMFS_DONE; 3868*7c478bd9Sstevel@tonic-gate break; 3869*7c478bd9Sstevel@tonic-gate 3870*7c478bd9Sstevel@tonic-gate case SMFIR_PROGRESS: 3871*7c478bd9Sstevel@tonic-gate break; 3872*7c478bd9Sstevel@tonic-gate 3873*7c478bd9Sstevel@tonic-gate case SMFIR_QUARANTINE: 3874*7c478bd9Sstevel@tonic-gate if (!bitset(SMFIF_QUARANTINE, m->mf_fflags)) 3875*7c478bd9Sstevel@tonic-gate { 3876*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 9) 3877*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, e->e_id, 3878*7c478bd9Sstevel@tonic-gate "milter_data(%s): lied about quarantining, honoring request anyway", 3879*7c478bd9Sstevel@tonic-gate m->mf_name); 3880*7c478bd9Sstevel@tonic-gate } 3881*7c478bd9Sstevel@tonic-gate if (response == NULL) 3882*7c478bd9Sstevel@tonic-gate response = newstr(""); 3883*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 3) 3884*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 3885*7c478bd9Sstevel@tonic-gate "milter=%s, quarantine=%s", 3886*7c478bd9Sstevel@tonic-gate m->mf_name, response); 3887*7c478bd9Sstevel@tonic-gate e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, 3888*7c478bd9Sstevel@tonic-gate response); 3889*7c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 3890*7c478bd9Sstevel@tonic-gate macid("{quarantine}"), e->e_quarmsg); 3891*7c478bd9Sstevel@tonic-gate break; 3892*7c478bd9Sstevel@tonic-gate 3893*7c478bd9Sstevel@tonic-gate case SMFIR_ADDHEADER: 3894*7c478bd9Sstevel@tonic-gate if (!bitset(SMFIF_ADDHDRS, m->mf_fflags)) 3895*7c478bd9Sstevel@tonic-gate { 3896*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 9) 3897*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, e->e_id, 3898*7c478bd9Sstevel@tonic-gate "milter_data(%s): lied about adding headers, honoring request anyway", 3899*7c478bd9Sstevel@tonic-gate m->mf_name); 3900*7c478bd9Sstevel@tonic-gate } 3901*7c478bd9Sstevel@tonic-gate milter_addheader(response, rlen, e); 3902*7c478bd9Sstevel@tonic-gate break; 3903*7c478bd9Sstevel@tonic-gate 3904*7c478bd9Sstevel@tonic-gate case SMFIR_INSHEADER: 3905*7c478bd9Sstevel@tonic-gate if (!bitset(SMFIF_ADDHDRS, m->mf_fflags)) 3906*7c478bd9Sstevel@tonic-gate { 3907*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 9) 3908*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, e->e_id, 3909*7c478bd9Sstevel@tonic-gate "milter_data(%s): lied about adding headers, honoring request anyway", 3910*7c478bd9Sstevel@tonic-gate m->mf_name); 3911*7c478bd9Sstevel@tonic-gate } 3912*7c478bd9Sstevel@tonic-gate milter_insheader(response, rlen, e); 3913*7c478bd9Sstevel@tonic-gate break; 3914*7c478bd9Sstevel@tonic-gate 3915*7c478bd9Sstevel@tonic-gate case SMFIR_CHGHEADER: 3916*7c478bd9Sstevel@tonic-gate if (!bitset(SMFIF_CHGHDRS, m->mf_fflags)) 3917*7c478bd9Sstevel@tonic-gate { 3918*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 9) 3919*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, e->e_id, 3920*7c478bd9Sstevel@tonic-gate "milter_data(%s): lied about changing headers, honoring request anyway", 3921*7c478bd9Sstevel@tonic-gate m->mf_name); 3922*7c478bd9Sstevel@tonic-gate } 3923*7c478bd9Sstevel@tonic-gate milter_changeheader(response, rlen, e); 3924*7c478bd9Sstevel@tonic-gate break; 3925*7c478bd9Sstevel@tonic-gate 3926*7c478bd9Sstevel@tonic-gate case SMFIR_ADDRCPT: 3927*7c478bd9Sstevel@tonic-gate if (!bitset(SMFIF_ADDRCPT, m->mf_fflags)) 3928*7c478bd9Sstevel@tonic-gate { 3929*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 9) 3930*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, e->e_id, 3931*7c478bd9Sstevel@tonic-gate "milter_data(%s) lied about adding recipients, honoring request anyway", 3932*7c478bd9Sstevel@tonic-gate m->mf_name); 3933*7c478bd9Sstevel@tonic-gate } 3934*7c478bd9Sstevel@tonic-gate milter_addrcpt(response, rlen, e); 3935*7c478bd9Sstevel@tonic-gate break; 3936*7c478bd9Sstevel@tonic-gate 3937*7c478bd9Sstevel@tonic-gate case SMFIR_DELRCPT: 3938*7c478bd9Sstevel@tonic-gate if (!bitset(SMFIF_DELRCPT, m->mf_fflags)) 3939*7c478bd9Sstevel@tonic-gate { 3940*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 9) 3941*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, e->e_id, 3942*7c478bd9Sstevel@tonic-gate "milter_data(%s): lied about removing recipients, honoring request anyway", 3943*7c478bd9Sstevel@tonic-gate m->mf_name); 3944*7c478bd9Sstevel@tonic-gate } 3945*7c478bd9Sstevel@tonic-gate milter_delrcpt(response, rlen, e); 3946*7c478bd9Sstevel@tonic-gate break; 3947*7c478bd9Sstevel@tonic-gate 3948*7c478bd9Sstevel@tonic-gate case SMFIR_REPLBODY: 3949*7c478bd9Sstevel@tonic-gate if (!bitset(SMFIF_MODBODY, m->mf_fflags)) 3950*7c478bd9Sstevel@tonic-gate { 3951*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) 3952*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 3953*7c478bd9Sstevel@tonic-gate "milter_data(%s): lied about replacing body, rejecting request and tempfailing message", 3954*7c478bd9Sstevel@tonic-gate m->mf_name); 3955*7c478bd9Sstevel@tonic-gate replfailed = true; 3956*7c478bd9Sstevel@tonic-gate break; 3957*7c478bd9Sstevel@tonic-gate } 3958*7c478bd9Sstevel@tonic-gate 3959*7c478bd9Sstevel@tonic-gate /* already failed in attempt */ 3960*7c478bd9Sstevel@tonic-gate if (replfailed) 3961*7c478bd9Sstevel@tonic-gate break; 3962*7c478bd9Sstevel@tonic-gate 3963*7c478bd9Sstevel@tonic-gate if (!dfopen) 3964*7c478bd9Sstevel@tonic-gate { 3965*7c478bd9Sstevel@tonic-gate if (milter_reopen_df(e) < 0) 3966*7c478bd9Sstevel@tonic-gate { 3967*7c478bd9Sstevel@tonic-gate replfailed = true; 3968*7c478bd9Sstevel@tonic-gate break; 3969*7c478bd9Sstevel@tonic-gate } 3970*7c478bd9Sstevel@tonic-gate dfopen = true; 3971*7c478bd9Sstevel@tonic-gate rewind = true; 3972*7c478bd9Sstevel@tonic-gate } 3973*7c478bd9Sstevel@tonic-gate 3974*7c478bd9Sstevel@tonic-gate if (milter_replbody(response, rlen, 3975*7c478bd9Sstevel@tonic-gate newfilter, e) < 0) 3976*7c478bd9Sstevel@tonic-gate replfailed = true; 3977*7c478bd9Sstevel@tonic-gate newfilter = false; 3978*7c478bd9Sstevel@tonic-gate replbody = true; 3979*7c478bd9Sstevel@tonic-gate break; 3980*7c478bd9Sstevel@tonic-gate 3981*7c478bd9Sstevel@tonic-gate default: 3982*7c478bd9Sstevel@tonic-gate /* Invalid response to command */ 3983*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) 3984*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 3985*7c478bd9Sstevel@tonic-gate "milter_data(%s): returned bogus response %c", 3986*7c478bd9Sstevel@tonic-gate m->mf_name, rcmd); 3987*7c478bd9Sstevel@tonic-gate milter_error(m, e); 3988*7c478bd9Sstevel@tonic-gate break; 3989*7c478bd9Sstevel@tonic-gate } 3990*7c478bd9Sstevel@tonic-gate if (rcmd != SMFIR_REPLYCODE && response != NULL) 3991*7c478bd9Sstevel@tonic-gate { 3992*7c478bd9Sstevel@tonic-gate sm_free(response); /* XXX */ 3993*7c478bd9Sstevel@tonic-gate response = NULL; 3994*7c478bd9Sstevel@tonic-gate } 3995*7c478bd9Sstevel@tonic-gate 3996*7c478bd9Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR) 3997*7c478bd9Sstevel@tonic-gate break; 3998*7c478bd9Sstevel@tonic-gate } 3999*7c478bd9Sstevel@tonic-gate 4000*7c478bd9Sstevel@tonic-gate if (replbody && !replfailed) 4001*7c478bd9Sstevel@tonic-gate { 4002*7c478bd9Sstevel@tonic-gate /* flush possible buffered character */ 4003*7c478bd9Sstevel@tonic-gate milter_replbody(NULL, 0, !replbody, e); 4004*7c478bd9Sstevel@tonic-gate replbody = false; 4005*7c478bd9Sstevel@tonic-gate } 4006*7c478bd9Sstevel@tonic-gate 4007*7c478bd9Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR) 4008*7c478bd9Sstevel@tonic-gate { 4009*7c478bd9Sstevel@tonic-gate MILTER_CHECK_ERROR(false, continue); 4010*7c478bd9Sstevel@tonic-gate goto finishup; 4011*7c478bd9Sstevel@tonic-gate } 4012*7c478bd9Sstevel@tonic-gate } 4013*7c478bd9Sstevel@tonic-gate 4014*7c478bd9Sstevel@tonic-gate finishup: 4015*7c478bd9Sstevel@tonic-gate /* leave things in the expected state if we touched it */ 4016*7c478bd9Sstevel@tonic-gate if (replfailed) 4017*7c478bd9Sstevel@tonic-gate { 4018*7c478bd9Sstevel@tonic-gate if (*state == SMFIR_CONTINUE || 4019*7c478bd9Sstevel@tonic-gate *state == SMFIR_ACCEPT) 4020*7c478bd9Sstevel@tonic-gate { 4021*7c478bd9Sstevel@tonic-gate *state = SMFIR_TEMPFAIL; 4022*7c478bd9Sstevel@tonic-gate SM_FREE_CLR(response); 4023*7c478bd9Sstevel@tonic-gate } 4024*7c478bd9Sstevel@tonic-gate 4025*7c478bd9Sstevel@tonic-gate if (dfopen) 4026*7c478bd9Sstevel@tonic-gate { 4027*7c478bd9Sstevel@tonic-gate (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT); 4028*7c478bd9Sstevel@tonic-gate e->e_dfp = NULL; 4029*7c478bd9Sstevel@tonic-gate e->e_flags &= ~EF_HAS_DF; 4030*7c478bd9Sstevel@tonic-gate dfopen = false; 4031*7c478bd9Sstevel@tonic-gate } 4032*7c478bd9Sstevel@tonic-gate rewind = false; 4033*7c478bd9Sstevel@tonic-gate } 4034*7c478bd9Sstevel@tonic-gate 4035*7c478bd9Sstevel@tonic-gate if ((dfopen && milter_reset_df(e) < 0) || 4036*7c478bd9Sstevel@tonic-gate (rewind && bfrewind(e->e_dfp) < 0)) 4037*7c478bd9Sstevel@tonic-gate { 4038*7c478bd9Sstevel@tonic-gate save_errno = errno; 4039*7c478bd9Sstevel@tonic-gate ExitStat = EX_IOERR; 4040*7c478bd9Sstevel@tonic-gate 4041*7c478bd9Sstevel@tonic-gate /* 4042*7c478bd9Sstevel@tonic-gate ** If filter told us to keep message but we had 4043*7c478bd9Sstevel@tonic-gate ** an error, we can't really keep it, tempfail it. 4044*7c478bd9Sstevel@tonic-gate */ 4045*7c478bd9Sstevel@tonic-gate 4046*7c478bd9Sstevel@tonic-gate if (*state == SMFIR_CONTINUE || 4047*7c478bd9Sstevel@tonic-gate *state == SMFIR_ACCEPT) 4048*7c478bd9Sstevel@tonic-gate { 4049*7c478bd9Sstevel@tonic-gate *state = SMFIR_TEMPFAIL; 4050*7c478bd9Sstevel@tonic-gate SM_FREE_CLR(response); 4051*7c478bd9Sstevel@tonic-gate } 4052*7c478bd9Sstevel@tonic-gate 4053*7c478bd9Sstevel@tonic-gate errno = save_errno; 4054*7c478bd9Sstevel@tonic-gate syserr("milter_data: %s/%cf%s: read error", 4055*7c478bd9Sstevel@tonic-gate qid_printqueue(e->e_qgrp, e->e_qdir), 4056*7c478bd9Sstevel@tonic-gate DATAFL_LETTER, e->e_id); 4057*7c478bd9Sstevel@tonic-gate } 4058*7c478bd9Sstevel@tonic-gate 4059*7c478bd9Sstevel@tonic-gate MILTER_CHECK_DONE_MSG(); 4060*7c478bd9Sstevel@tonic-gate if (MilterLogLevel > 10 && *state == SMFIR_REJECT) 4061*7c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter: reject, data"); 4062*7c478bd9Sstevel@tonic-gate return response; 4063*7c478bd9Sstevel@tonic-gate } 4064*7c478bd9Sstevel@tonic-gate 4065*7c478bd9Sstevel@tonic-gate #if SMFI_VERSION > 2 4066*7c478bd9Sstevel@tonic-gate /* 4067*7c478bd9Sstevel@tonic-gate ** MILTER_UNKNOWN -- send any unrecognized or unimplemented command 4068*7c478bd9Sstevel@tonic-gate ** string to milter filters 4069*7c478bd9Sstevel@tonic-gate ** 4070*7c478bd9Sstevel@tonic-gate ** Parameters: 4071*7c478bd9Sstevel@tonic-gate ** cmd -- the string itself. 4072*7c478bd9Sstevel@tonic-gate ** e -- current envelope. 4073*7c478bd9Sstevel@tonic-gate ** state -- return state from response. 4074*7c478bd9Sstevel@tonic-gate ** 4075*7c478bd9Sstevel@tonic-gate ** 4076*7c478bd9Sstevel@tonic-gate ** Returns: 4077*7c478bd9Sstevel@tonic-gate ** response string (may be NULL) 4078*7c478bd9Sstevel@tonic-gate */ 4079*7c478bd9Sstevel@tonic-gate 4080*7c478bd9Sstevel@tonic-gate char * 4081*7c478bd9Sstevel@tonic-gate milter_unknown(cmd, e, state) 4082*7c478bd9Sstevel@tonic-gate char *cmd; 4083*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 4084*7c478bd9Sstevel@tonic-gate char *state; 4085*7c478bd9Sstevel@tonic-gate { 4086*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 4087*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_unknown(%s)\n", cmd); 4088*7c478bd9Sstevel@tonic-gate 4089*7c478bd9Sstevel@tonic-gate return milter_command(SMFIC_UNKNOWN, cmd, strlen(cmd) + 1, 4090*7c478bd9Sstevel@tonic-gate NULL, e, state); 4091*7c478bd9Sstevel@tonic-gate } 4092*7c478bd9Sstevel@tonic-gate #endif /* SMFI_VERSION > 2 */ 4093*7c478bd9Sstevel@tonic-gate 4094*7c478bd9Sstevel@tonic-gate /* 4095*7c478bd9Sstevel@tonic-gate ** MILTER_QUIT -- informs the filter(s) we are done and closes connection(s) 4096*7c478bd9Sstevel@tonic-gate ** 4097*7c478bd9Sstevel@tonic-gate ** Parameters: 4098*7c478bd9Sstevel@tonic-gate ** e -- current envelope. 4099*7c478bd9Sstevel@tonic-gate ** 4100*7c478bd9Sstevel@tonic-gate ** Returns: 4101*7c478bd9Sstevel@tonic-gate ** none 4102*7c478bd9Sstevel@tonic-gate */ 4103*7c478bd9Sstevel@tonic-gate 4104*7c478bd9Sstevel@tonic-gate void 4105*7c478bd9Sstevel@tonic-gate milter_quit(e) 4106*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 4107*7c478bd9Sstevel@tonic-gate { 4108*7c478bd9Sstevel@tonic-gate int i; 4109*7c478bd9Sstevel@tonic-gate 4110*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 4111*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_quit(%s)\n", e->e_id); 4112*7c478bd9Sstevel@tonic-gate 4113*7c478bd9Sstevel@tonic-gate for (i = 0; InputFilters[i] != NULL; i++) 4114*7c478bd9Sstevel@tonic-gate milter_quit_filter(InputFilters[i], e); 4115*7c478bd9Sstevel@tonic-gate } 4116*7c478bd9Sstevel@tonic-gate /* 4117*7c478bd9Sstevel@tonic-gate ** MILTER_ABORT -- informs the filter(s) that we are aborting current message 4118*7c478bd9Sstevel@tonic-gate ** 4119*7c478bd9Sstevel@tonic-gate ** Parameters: 4120*7c478bd9Sstevel@tonic-gate ** e -- current envelope. 4121*7c478bd9Sstevel@tonic-gate ** 4122*7c478bd9Sstevel@tonic-gate ** Returns: 4123*7c478bd9Sstevel@tonic-gate ** none 4124*7c478bd9Sstevel@tonic-gate */ 4125*7c478bd9Sstevel@tonic-gate 4126*7c478bd9Sstevel@tonic-gate void 4127*7c478bd9Sstevel@tonic-gate milter_abort(e) 4128*7c478bd9Sstevel@tonic-gate ENVELOPE *e; 4129*7c478bd9Sstevel@tonic-gate { 4130*7c478bd9Sstevel@tonic-gate int i; 4131*7c478bd9Sstevel@tonic-gate 4132*7c478bd9Sstevel@tonic-gate if (tTd(64, 10)) 4133*7c478bd9Sstevel@tonic-gate sm_dprintf("milter_abort\n"); 4134*7c478bd9Sstevel@tonic-gate 4135*7c478bd9Sstevel@tonic-gate for (i = 0; InputFilters[i] != NULL; i++) 4136*7c478bd9Sstevel@tonic-gate { 4137*7c478bd9Sstevel@tonic-gate struct milter *m = InputFilters[i]; 4138*7c478bd9Sstevel@tonic-gate 4139*7c478bd9Sstevel@tonic-gate /* sanity checks */ 4140*7c478bd9Sstevel@tonic-gate if (m->mf_sock < 0 || m->mf_state != SMFS_INMSG) 4141*7c478bd9Sstevel@tonic-gate continue; 4142*7c478bd9Sstevel@tonic-gate 4143*7c478bd9Sstevel@tonic-gate milter_abort_filter(m, e); 4144*7c478bd9Sstevel@tonic-gate } 4145*7c478bd9Sstevel@tonic-gate } 4146*7c478bd9Sstevel@tonic-gate #endif /* MILTER */ 4147