106f25ae9SGregory Neil Shapiro /* 2e92d3f3fSGregory Neil Shapiro * Copyright (c) 1999-2004 Sendmail, Inc. and its suppliers. 306f25ae9SGregory Neil Shapiro * All rights reserved. 406f25ae9SGregory Neil Shapiro * 506f25ae9SGregory Neil Shapiro * By using this file, you agree to the terms and conditions set 606f25ae9SGregory Neil Shapiro * forth in the LICENSE file which can be found at the top level of 706f25ae9SGregory Neil Shapiro * the sendmail distribution. 806f25ae9SGregory Neil Shapiro * 906f25ae9SGregory Neil Shapiro */ 1006f25ae9SGregory Neil Shapiro 1106f25ae9SGregory Neil Shapiro #include <sendmail.h> 1240266059SGregory Neil Shapiro 13b6bacd31SGregory Neil Shapiro SM_RCSID("@(#)$Id: milter.c,v 8.228 2004/11/09 18:54:55 ca Exp $") 1440266059SGregory Neil Shapiro 1540266059SGregory Neil Shapiro #if MILTER 1640266059SGregory Neil Shapiro # include <libmilter/mfapi.h> 1740266059SGregory Neil Shapiro # include <libmilter/mfdef.h> 1840266059SGregory Neil Shapiro 1906f25ae9SGregory Neil Shapiro # include <errno.h> 2006f25ae9SGregory Neil Shapiro # include <sys/time.h> 21e92d3f3fSGregory Neil Shapiro # include <sys/uio.h> 2206f25ae9SGregory Neil Shapiro 2306f25ae9SGregory Neil Shapiro # if NETINET || NETINET6 2406f25ae9SGregory Neil Shapiro # include <arpa/inet.h> 25e92d3f3fSGregory Neil Shapiro # if _FFR_MILTER_NAGLE 26e92d3f3fSGregory Neil Shapiro # include <netinet/tcp.h> 27e92d3f3fSGregory Neil Shapiro # endif /* _FFR_MILTER_NAGLE */ 2806f25ae9SGregory Neil Shapiro # endif /* NETINET || NETINET6 */ 2906f25ae9SGregory Neil Shapiro 3040266059SGregory Neil Shapiro # include <sm/fdset.h> 3106f25ae9SGregory Neil Shapiro 32b6bacd31SGregory Neil Shapiro static void milter_connect_timeout __P((int)); 3340266059SGregory Neil Shapiro static void milter_error __P((struct milter *, ENVELOPE *)); 3406f25ae9SGregory Neil Shapiro static int milter_open __P((struct milter *, bool, ENVELOPE *)); 3506f25ae9SGregory Neil Shapiro static void milter_parse_timeouts __P((char *, struct milter *)); 3606f25ae9SGregory Neil Shapiro 3706f25ae9SGregory Neil Shapiro static char *MilterConnectMacros[MAXFILTERMACROS + 1]; 3806f25ae9SGregory Neil Shapiro static char *MilterHeloMacros[MAXFILTERMACROS + 1]; 3906f25ae9SGregory Neil Shapiro static char *MilterEnvFromMacros[MAXFILTERMACROS + 1]; 4006f25ae9SGregory Neil Shapiro static char *MilterEnvRcptMacros[MAXFILTERMACROS + 1]; 41e92d3f3fSGregory Neil Shapiro static char *MilterDataMacros[MAXFILTERMACROS + 1]; 42323f6dcbSGregory Neil Shapiro static char *MilterEOMMacros[MAXFILTERMACROS + 1]; 43e92d3f3fSGregory Neil Shapiro static size_t MilterMaxDataSize = MILTER_MAX_DATA_SIZE; 4406f25ae9SGregory Neil Shapiro 4506f25ae9SGregory Neil Shapiro # define MILTER_CHECK_DONE_MSG() \ 4606f25ae9SGregory Neil Shapiro if (*state == SMFIR_REPLYCODE || \ 4706f25ae9SGregory Neil Shapiro *state == SMFIR_REJECT || \ 4806f25ae9SGregory Neil Shapiro *state == SMFIR_DISCARD || \ 4906f25ae9SGregory Neil Shapiro *state == SMFIR_TEMPFAIL) \ 5006f25ae9SGregory Neil Shapiro { \ 5106f25ae9SGregory Neil Shapiro /* Abort the filters to let them know we are done with msg */ \ 5206f25ae9SGregory Neil Shapiro milter_abort(e); \ 5306f25ae9SGregory Neil Shapiro } 5406f25ae9SGregory Neil Shapiro 555ef517c0SGregory Neil Shapiro # define MILTER_CHECK_ERROR(initial, action) \ 565ef517c0SGregory Neil Shapiro if (!initial && tTd(71, 100)) \ 575ef517c0SGregory Neil Shapiro { \ 585ef517c0SGregory Neil Shapiro if (e->e_quarmsg == NULL) \ 595ef517c0SGregory Neil Shapiro { \ 605ef517c0SGregory Neil Shapiro e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, \ 615ef517c0SGregory Neil Shapiro "filter failure"); \ 625ef517c0SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), \ 635ef517c0SGregory Neil Shapiro e->e_quarmsg); \ 645ef517c0SGregory Neil Shapiro } \ 655ef517c0SGregory Neil Shapiro } \ 665ef517c0SGregory Neil Shapiro else if (tTd(71, 101)) \ 67959366dcSGregory Neil Shapiro { \ 68959366dcSGregory Neil Shapiro if (e->e_quarmsg == NULL) \ 69959366dcSGregory Neil Shapiro { \ 70959366dcSGregory Neil Shapiro e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, \ 71959366dcSGregory Neil Shapiro "filter failure"); \ 72959366dcSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), \ 73959366dcSGregory Neil Shapiro e->e_quarmsg); \ 74959366dcSGregory Neil Shapiro } \ 75959366dcSGregory Neil Shapiro } \ 76959366dcSGregory Neil Shapiro else if (bitnset(SMF_TEMPFAIL, m->mf_flags)) \ 77959366dcSGregory Neil Shapiro *state = SMFIR_TEMPFAIL; \ 78b6bacd31SGregory Neil Shapiro else if (bitnset(SMF_TEMPDROP, m->mf_flags)) \ 79b6bacd31SGregory Neil Shapiro *state = SMFIR_SHUTDOWN; \ 80959366dcSGregory Neil Shapiro else if (bitnset(SMF_REJECT, m->mf_flags)) \ 81959366dcSGregory Neil Shapiro *state = SMFIR_REJECT; \ 82959366dcSGregory Neil Shapiro else \ 83959366dcSGregory Neil Shapiro action; 8406f25ae9SGregory Neil Shapiro 8506f25ae9SGregory Neil Shapiro # define MILTER_CHECK_REPLYCODE(default) \ 8606f25ae9SGregory Neil Shapiro if (response == NULL || \ 8706f25ae9SGregory Neil Shapiro strlen(response) + 1 != (size_t) rlen || \ 8806f25ae9SGregory Neil Shapiro rlen < 3 || \ 8906f25ae9SGregory Neil Shapiro (response[0] != '4' && response[0] != '5') || \ 9006f25ae9SGregory Neil Shapiro !isascii(response[1]) || !isdigit(response[1]) || \ 9106f25ae9SGregory Neil Shapiro !isascii(response[2]) || !isdigit(response[2])) \ 9206f25ae9SGregory Neil Shapiro { \ 9306f25ae9SGregory Neil Shapiro if (response != NULL) \ 9440266059SGregory Neil Shapiro sm_free(response); /* XXX */ \ 9506f25ae9SGregory Neil Shapiro response = newstr(default); \ 9606f25ae9SGregory Neil Shapiro } \ 9706f25ae9SGregory Neil Shapiro else \ 9806f25ae9SGregory Neil Shapiro { \ 9906f25ae9SGregory Neil Shapiro char *ptr = response; \ 10006f25ae9SGregory Neil Shapiro \ 10106f25ae9SGregory Neil Shapiro /* Check for unprotected %'s in the string */ \ 10206f25ae9SGregory Neil Shapiro while (*ptr != '\0') \ 10306f25ae9SGregory Neil Shapiro { \ 10406f25ae9SGregory Neil Shapiro if (*ptr == '%' && *++ptr != '%') \ 10506f25ae9SGregory Neil Shapiro { \ 10640266059SGregory Neil Shapiro sm_free(response); /* XXX */ \ 10706f25ae9SGregory Neil Shapiro response = newstr(default); \ 10806f25ae9SGregory Neil Shapiro break; \ 10906f25ae9SGregory Neil Shapiro } \ 11006f25ae9SGregory Neil Shapiro ptr++; \ 11106f25ae9SGregory Neil Shapiro } \ 11206f25ae9SGregory Neil Shapiro } 11306f25ae9SGregory Neil Shapiro 11406f25ae9SGregory Neil Shapiro # define MILTER_DF_ERROR(msg) \ 11506f25ae9SGregory Neil Shapiro { \ 11606f25ae9SGregory Neil Shapiro int save_errno = errno; \ 11706f25ae9SGregory Neil Shapiro \ 11806f25ae9SGregory Neil Shapiro if (tTd(64, 5)) \ 11906f25ae9SGregory Neil Shapiro { \ 12040266059SGregory Neil Shapiro sm_dprintf(msg, dfname, sm_errstring(save_errno)); \ 12140266059SGregory Neil Shapiro sm_dprintf("\n"); \ 12206f25ae9SGregory Neil Shapiro } \ 12340266059SGregory Neil Shapiro if (MilterLogLevel > 0) \ 12440266059SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, msg, dfname, sm_errstring(save_errno)); \ 12540266059SGregory Neil Shapiro if (SuperSafe == SAFE_REALLY) \ 12606f25ae9SGregory Neil Shapiro { \ 12706f25ae9SGregory Neil Shapiro if (e->e_dfp != NULL) \ 12806f25ae9SGregory Neil Shapiro { \ 12940266059SGregory Neil Shapiro (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT); \ 13006f25ae9SGregory Neil Shapiro e->e_dfp = NULL; \ 13106f25ae9SGregory Neil Shapiro } \ 13206f25ae9SGregory Neil Shapiro e->e_flags &= ~EF_HAS_DF; \ 13306f25ae9SGregory Neil Shapiro } \ 13406f25ae9SGregory Neil Shapiro errno = save_errno; \ 13506f25ae9SGregory Neil Shapiro } 13606f25ae9SGregory Neil Shapiro 13706f25ae9SGregory Neil Shapiro /* 13806f25ae9SGregory Neil Shapiro ** MILTER_TIMEOUT -- make sure socket is ready in time 13906f25ae9SGregory Neil Shapiro ** 14006f25ae9SGregory Neil Shapiro ** Parameters: 14106f25ae9SGregory Neil Shapiro ** routine -- routine name for debug/logging 14206f25ae9SGregory Neil Shapiro ** secs -- number of seconds in timeout 14306f25ae9SGregory Neil Shapiro ** write -- waiting to read or write? 14440266059SGregory Neil Shapiro ** started -- whether this is part of a previous sequence 14506f25ae9SGregory Neil Shapiro ** 14606f25ae9SGregory Neil Shapiro ** Assumes 'm' is a milter structure for the current socket. 14706f25ae9SGregory Neil Shapiro */ 14806f25ae9SGregory Neil Shapiro 14940266059SGregory Neil Shapiro # define MILTER_TIMEOUT(routine, secs, write, started) \ 15006f25ae9SGregory Neil Shapiro { \ 15106f25ae9SGregory Neil Shapiro int ret; \ 15206f25ae9SGregory Neil Shapiro int save_errno; \ 15306f25ae9SGregory Neil Shapiro fd_set fds; \ 15406f25ae9SGregory Neil Shapiro struct timeval tv; \ 15506f25ae9SGregory Neil Shapiro \ 15640266059SGregory Neil Shapiro if (SM_FD_SETSIZE > 0 && m->mf_sock >= SM_FD_SETSIZE) \ 15706f25ae9SGregory Neil Shapiro { \ 15806f25ae9SGregory Neil Shapiro if (tTd(64, 5)) \ 15940266059SGregory Neil Shapiro sm_dprintf("milter_%s(%s): socket %d is larger than FD_SETSIZE %d\n", \ 16040266059SGregory Neil Shapiro (routine), m->mf_name, m->mf_sock, \ 16140266059SGregory Neil Shapiro SM_FD_SETSIZE); \ 16240266059SGregory Neil Shapiro if (MilterLogLevel > 0) \ 16306f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, \ 16440266059SGregory Neil Shapiro "Milter (%s): socket(%s) %d is larger than FD_SETSIZE %d", \ 16540266059SGregory Neil Shapiro m->mf_name, (routine), m->mf_sock, \ 16640266059SGregory Neil Shapiro SM_FD_SETSIZE); \ 16740266059SGregory Neil Shapiro milter_error(m, e); \ 16806f25ae9SGregory Neil Shapiro return NULL; \ 16906f25ae9SGregory Neil Shapiro } \ 17006f25ae9SGregory Neil Shapiro \ 171605302a5SGregory Neil Shapiro do \ 172605302a5SGregory Neil Shapiro { \ 17306f25ae9SGregory Neil Shapiro FD_ZERO(&fds); \ 174193538b7SGregory Neil Shapiro SM_FD_SET(m->mf_sock, &fds); \ 17540266059SGregory Neil Shapiro tv.tv_sec = (secs); \ 17606f25ae9SGregory Neil Shapiro tv.tv_usec = 0; \ 17706f25ae9SGregory Neil Shapiro ret = select(m->mf_sock + 1, \ 17840266059SGregory Neil Shapiro (write) ? NULL : &fds, \ 17940266059SGregory Neil Shapiro (write) ? &fds : NULL, \ 18006f25ae9SGregory Neil Shapiro NULL, &tv); \ 181605302a5SGregory Neil Shapiro } while (ret < 0 && errno == EINTR); \ 18206f25ae9SGregory Neil Shapiro \ 18306f25ae9SGregory Neil Shapiro switch (ret) \ 18406f25ae9SGregory Neil Shapiro { \ 18506f25ae9SGregory Neil Shapiro case 0: \ 18606f25ae9SGregory Neil Shapiro if (tTd(64, 5)) \ 18740266059SGregory Neil Shapiro sm_dprintf("milter_%s(%s): timeout\n", (routine), \ 18840266059SGregory Neil Shapiro m->mf_name); \ 18940266059SGregory Neil Shapiro if (MilterLogLevel > 0) \ 19040266059SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, \ 19140266059SGregory Neil Shapiro "Milter (%s): %s %s %s %s", \ 19240266059SGregory Neil Shapiro m->mf_name, "timeout", \ 19340266059SGregory Neil Shapiro started ? "during" : "before", \ 19440266059SGregory Neil Shapiro "data", (routine)); \ 19540266059SGregory Neil Shapiro milter_error(m, e); \ 19606f25ae9SGregory Neil Shapiro return NULL; \ 19706f25ae9SGregory Neil Shapiro \ 19806f25ae9SGregory Neil Shapiro case -1: \ 19906f25ae9SGregory Neil Shapiro save_errno = errno; \ 20006f25ae9SGregory Neil Shapiro if (tTd(64, 5)) \ 20140266059SGregory Neil Shapiro sm_dprintf("milter_%s(%s): select: %s\n", (routine), \ 20240266059SGregory Neil Shapiro m->mf_name, sm_errstring(save_errno)); \ 20340266059SGregory Neil Shapiro if (MilterLogLevel > 0) \ 20440266059SGregory Neil Shapiro { \ 20506f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, \ 20640266059SGregory Neil Shapiro "Milter (%s): select(%s): %s", \ 20740266059SGregory Neil Shapiro m->mf_name, (routine), \ 20840266059SGregory Neil Shapiro sm_errstring(save_errno)); \ 20940266059SGregory Neil Shapiro } \ 21040266059SGregory Neil Shapiro milter_error(m, e); \ 21106f25ae9SGregory Neil Shapiro return NULL; \ 21206f25ae9SGregory Neil Shapiro \ 21306f25ae9SGregory Neil Shapiro default: \ 214193538b7SGregory Neil Shapiro if (SM_FD_ISSET(m->mf_sock, &fds)) \ 21506f25ae9SGregory Neil Shapiro break; \ 21606f25ae9SGregory Neil Shapiro if (tTd(64, 5)) \ 21740266059SGregory Neil Shapiro sm_dprintf("milter_%s(%s): socket not ready\n", \ 21840266059SGregory Neil Shapiro (routine), m->mf_name); \ 21940266059SGregory Neil Shapiro if (MilterLogLevel > 0) \ 22040266059SGregory Neil Shapiro { \ 22106f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, \ 22240266059SGregory Neil Shapiro "Milter (%s): socket(%s) not ready", \ 22340266059SGregory Neil Shapiro m->mf_name, (routine)); \ 22440266059SGregory Neil Shapiro } \ 22540266059SGregory Neil Shapiro milter_error(m, e); \ 22606f25ae9SGregory Neil Shapiro return NULL; \ 22706f25ae9SGregory Neil Shapiro } \ 22806f25ae9SGregory Neil Shapiro } 22906f25ae9SGregory Neil Shapiro 23006f25ae9SGregory Neil Shapiro /* 23106f25ae9SGregory Neil Shapiro ** Low level functions 23206f25ae9SGregory Neil Shapiro */ 23306f25ae9SGregory Neil Shapiro 23440266059SGregory Neil Shapiro /* 23506f25ae9SGregory Neil Shapiro ** MILTER_READ -- read from a remote milter filter 23606f25ae9SGregory Neil Shapiro ** 23706f25ae9SGregory Neil Shapiro ** Parameters: 23806f25ae9SGregory Neil Shapiro ** m -- milter to read from. 23906f25ae9SGregory Neil Shapiro ** cmd -- return param for command read. 24006f25ae9SGregory Neil Shapiro ** rlen -- return length of response string. 24106f25ae9SGregory Neil Shapiro ** to -- timeout in seconds. 24206f25ae9SGregory Neil Shapiro ** e -- current envelope. 24306f25ae9SGregory Neil Shapiro ** 24406f25ae9SGregory Neil Shapiro ** Returns: 24506f25ae9SGregory Neil Shapiro ** response string (may be NULL) 24606f25ae9SGregory Neil Shapiro */ 24706f25ae9SGregory Neil Shapiro 24806f25ae9SGregory Neil Shapiro static char * 24906f25ae9SGregory Neil Shapiro milter_sysread(m, buf, sz, to, e) 25006f25ae9SGregory Neil Shapiro struct milter *m; 25106f25ae9SGregory Neil Shapiro char *buf; 25206f25ae9SGregory Neil Shapiro ssize_t sz; 25306f25ae9SGregory Neil Shapiro time_t to; 25406f25ae9SGregory Neil Shapiro ENVELOPE *e; 25506f25ae9SGregory Neil Shapiro { 25642e5d165SGregory Neil Shapiro time_t readstart = 0; 25706f25ae9SGregory Neil Shapiro ssize_t len, curl; 25840266059SGregory Neil Shapiro bool started = false; 25906f25ae9SGregory Neil Shapiro 26006f25ae9SGregory Neil Shapiro curl = 0; 26106f25ae9SGregory Neil Shapiro 26206f25ae9SGregory Neil Shapiro if (to > 0) 26306f25ae9SGregory Neil Shapiro readstart = curtime(); 26406f25ae9SGregory Neil Shapiro 26506f25ae9SGregory Neil Shapiro for (;;) 26606f25ae9SGregory Neil Shapiro { 26706f25ae9SGregory Neil Shapiro if (to > 0) 26806f25ae9SGregory Neil Shapiro { 26906f25ae9SGregory Neil Shapiro time_t now; 27006f25ae9SGregory Neil Shapiro 27106f25ae9SGregory Neil Shapiro now = curtime(); 27206f25ae9SGregory Neil Shapiro if (now - readstart >= to) 27306f25ae9SGregory Neil Shapiro { 27406f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 27540266059SGregory Neil Shapiro sm_dprintf("milter_read (%s): %s %s %s", 27640266059SGregory Neil Shapiro m->mf_name, "timeout", 27740266059SGregory Neil Shapiro started ? "during" : "before", 27840266059SGregory Neil Shapiro "data read"); 27940266059SGregory Neil Shapiro if (MilterLogLevel > 0) 28006f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 28140266059SGregory Neil Shapiro "Milter (%s): %s %s %s", 28240266059SGregory Neil Shapiro m->mf_name, "timeout", 28340266059SGregory Neil Shapiro started ? "during" : "before", 28440266059SGregory Neil Shapiro "data read"); 28540266059SGregory Neil Shapiro milter_error(m, e); 28606f25ae9SGregory Neil Shapiro return NULL; 28706f25ae9SGregory Neil Shapiro } 28806f25ae9SGregory Neil Shapiro to -= now - readstart; 28906f25ae9SGregory Neil Shapiro readstart = now; 29040266059SGregory Neil Shapiro MILTER_TIMEOUT("read", to, false, started); 29106f25ae9SGregory Neil Shapiro } 29206f25ae9SGregory Neil Shapiro 29306f25ae9SGregory Neil Shapiro len = read(m->mf_sock, buf + curl, sz - curl); 29406f25ae9SGregory Neil Shapiro 29506f25ae9SGregory Neil Shapiro if (len < 0) 29606f25ae9SGregory Neil Shapiro { 29706f25ae9SGregory Neil Shapiro int save_errno = errno; 29806f25ae9SGregory Neil Shapiro 29906f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 30040266059SGregory Neil Shapiro sm_dprintf("milter_read(%s): read returned %ld: %s\n", 30106f25ae9SGregory Neil Shapiro m->mf_name, (long) len, 30240266059SGregory Neil Shapiro sm_errstring(save_errno)); 30340266059SGregory Neil Shapiro if (MilterLogLevel > 0) 30406f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 30540266059SGregory Neil Shapiro "Milter (%s): read returned %ld: %s", 30606f25ae9SGregory Neil Shapiro m->mf_name, (long) len, 30740266059SGregory Neil Shapiro sm_errstring(save_errno)); 30840266059SGregory Neil Shapiro milter_error(m, e); 30906f25ae9SGregory Neil Shapiro return NULL; 31006f25ae9SGregory Neil Shapiro } 31106f25ae9SGregory Neil Shapiro 31240266059SGregory Neil Shapiro started = true; 31306f25ae9SGregory Neil Shapiro curl += len; 314602a2b1bSGregory Neil Shapiro if (len == 0 || curl >= sz) 31506f25ae9SGregory Neil Shapiro break; 31606f25ae9SGregory Neil Shapiro 31706f25ae9SGregory Neil Shapiro } 31806f25ae9SGregory Neil Shapiro 31906f25ae9SGregory Neil Shapiro if (curl != sz) 32006f25ae9SGregory Neil Shapiro { 32106f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 32240266059SGregory Neil Shapiro sm_dprintf("milter_read(%s): cmd read returned %ld, expecting %ld\n", 32306f25ae9SGregory Neil Shapiro m->mf_name, (long) curl, (long) sz); 32440266059SGregory Neil Shapiro if (MilterLogLevel > 0) 32506f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 32640266059SGregory Neil Shapiro "milter_read(%s): cmd read returned %ld, expecting %ld", 32706f25ae9SGregory Neil Shapiro m->mf_name, (long) curl, (long) sz); 32840266059SGregory Neil Shapiro milter_error(m, e); 32906f25ae9SGregory Neil Shapiro return NULL; 33006f25ae9SGregory Neil Shapiro } 33106f25ae9SGregory Neil Shapiro return buf; 33206f25ae9SGregory Neil Shapiro } 33306f25ae9SGregory Neil Shapiro 33406f25ae9SGregory Neil Shapiro static char * 33506f25ae9SGregory Neil Shapiro milter_read(m, cmd, rlen, to, e) 33606f25ae9SGregory Neil Shapiro struct milter *m; 33706f25ae9SGregory Neil Shapiro char *cmd; 33806f25ae9SGregory Neil Shapiro ssize_t *rlen; 33906f25ae9SGregory Neil Shapiro time_t to; 34006f25ae9SGregory Neil Shapiro ENVELOPE *e; 34106f25ae9SGregory Neil Shapiro { 34242e5d165SGregory Neil Shapiro time_t readstart = 0; 34306f25ae9SGregory Neil Shapiro ssize_t expl; 34406f25ae9SGregory Neil Shapiro mi_int32 i; 345e92d3f3fSGregory Neil Shapiro # if _FFR_MILTER_NAGLE 346e92d3f3fSGregory Neil Shapiro # ifdef TCP_CORK 347e92d3f3fSGregory Neil Shapiro int cork = 0; 348e92d3f3fSGregory Neil Shapiro # endif 349e92d3f3fSGregory Neil Shapiro # endif /* _FFR_MILTER_NAGLE */ 35006f25ae9SGregory Neil Shapiro char *buf; 35106f25ae9SGregory Neil Shapiro char data[MILTER_LEN_BYTES + 1]; 35206f25ae9SGregory Neil Shapiro 35306f25ae9SGregory Neil Shapiro *rlen = 0; 35406f25ae9SGregory Neil Shapiro *cmd = '\0'; 35506f25ae9SGregory Neil Shapiro 35606f25ae9SGregory Neil Shapiro if (to > 0) 35706f25ae9SGregory Neil Shapiro readstart = curtime(); 35806f25ae9SGregory Neil Shapiro 359e92d3f3fSGregory Neil Shapiro # if _FFR_MILTER_NAGLE 360e92d3f3fSGregory Neil Shapiro # ifdef TCP_CORK 361e92d3f3fSGregory Neil Shapiro setsockopt(m->mf_sock, IPPROTO_TCP, TCP_CORK, (char *)&cork, 362e92d3f3fSGregory Neil Shapiro sizeof(cork)); 363e92d3f3fSGregory Neil Shapiro # endif 364e92d3f3fSGregory Neil Shapiro # endif /* _FFR_MILTER_NAGLE */ 365e92d3f3fSGregory Neil Shapiro 36606f25ae9SGregory Neil Shapiro if (milter_sysread(m, data, sizeof data, to, e) == NULL) 36706f25ae9SGregory Neil Shapiro return NULL; 36806f25ae9SGregory Neil Shapiro 369e92d3f3fSGregory Neil Shapiro # if _FFR_MILTER_NAGLE 370e92d3f3fSGregory Neil Shapiro # ifdef TCP_CORK 371e92d3f3fSGregory Neil Shapiro cork = 1; 372e92d3f3fSGregory Neil Shapiro setsockopt(m->mf_sock, IPPROTO_TCP, TCP_CORK, (char *)&cork, 373e92d3f3fSGregory Neil Shapiro sizeof(cork)); 374e92d3f3fSGregory Neil Shapiro # endif 375e92d3f3fSGregory Neil Shapiro # endif /* _FFR_MILTER_NAGLE */ 376e92d3f3fSGregory Neil Shapiro 37706f25ae9SGregory Neil Shapiro /* reset timeout */ 37806f25ae9SGregory Neil Shapiro if (to > 0) 37906f25ae9SGregory Neil Shapiro { 38006f25ae9SGregory Neil Shapiro time_t now; 38106f25ae9SGregory Neil Shapiro 38206f25ae9SGregory Neil Shapiro now = curtime(); 38306f25ae9SGregory Neil Shapiro if (now - readstart >= to) 38406f25ae9SGregory Neil Shapiro { 38506f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 38640266059SGregory Neil Shapiro sm_dprintf("milter_read(%s): timeout before data read\n", 38706f25ae9SGregory Neil Shapiro m->mf_name); 38840266059SGregory Neil Shapiro if (MilterLogLevel > 0) 38906f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 39040266059SGregory Neil Shapiro "Milter read(%s): timeout before data read", 39106f25ae9SGregory Neil Shapiro m->mf_name); 39240266059SGregory Neil Shapiro milter_error(m, e); 39306f25ae9SGregory Neil Shapiro return NULL; 39406f25ae9SGregory Neil Shapiro } 39506f25ae9SGregory Neil Shapiro to -= now - readstart; 39606f25ae9SGregory Neil Shapiro } 39706f25ae9SGregory Neil Shapiro 39806f25ae9SGregory Neil Shapiro *cmd = data[MILTER_LEN_BYTES]; 39906f25ae9SGregory Neil Shapiro data[MILTER_LEN_BYTES] = '\0'; 40006f25ae9SGregory Neil Shapiro (void) memcpy(&i, data, MILTER_LEN_BYTES); 40106f25ae9SGregory Neil Shapiro expl = ntohl(i) - 1; 40206f25ae9SGregory Neil Shapiro 40306f25ae9SGregory Neil Shapiro if (tTd(64, 25)) 40440266059SGregory Neil Shapiro sm_dprintf("milter_read(%s): expecting %ld bytes\n", 40506f25ae9SGregory Neil Shapiro m->mf_name, (long) expl); 40606f25ae9SGregory Neil Shapiro 40706f25ae9SGregory Neil Shapiro if (expl < 0) 40806f25ae9SGregory Neil Shapiro { 40906f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 41040266059SGregory Neil Shapiro sm_dprintf("milter_read(%s): read size %ld out of range\n", 41106f25ae9SGregory Neil Shapiro m->mf_name, (long) expl); 41240266059SGregory Neil Shapiro if (MilterLogLevel > 0) 41306f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 41406f25ae9SGregory Neil Shapiro "milter_read(%s): read size %ld out of range", 41506f25ae9SGregory Neil Shapiro m->mf_name, (long) expl); 41640266059SGregory Neil Shapiro milter_error(m, e); 41706f25ae9SGregory Neil Shapiro return NULL; 41806f25ae9SGregory Neil Shapiro } 41906f25ae9SGregory Neil Shapiro 42006f25ae9SGregory Neil Shapiro if (expl == 0) 42106f25ae9SGregory Neil Shapiro return NULL; 42206f25ae9SGregory Neil Shapiro 42306f25ae9SGregory Neil Shapiro buf = (char *) xalloc(expl); 42406f25ae9SGregory Neil Shapiro 42506f25ae9SGregory Neil Shapiro if (milter_sysread(m, buf, expl, to, e) == NULL) 42606f25ae9SGregory Neil Shapiro { 42740266059SGregory Neil Shapiro sm_free(buf); /* XXX */ 42806f25ae9SGregory Neil Shapiro return NULL; 42906f25ae9SGregory Neil Shapiro } 43006f25ae9SGregory Neil Shapiro 43106f25ae9SGregory Neil Shapiro if (tTd(64, 50)) 43240266059SGregory Neil Shapiro sm_dprintf("milter_read(%s): Returning %*s\n", 43306f25ae9SGregory Neil Shapiro m->mf_name, (int) expl, buf); 43406f25ae9SGregory Neil Shapiro *rlen = expl; 43506f25ae9SGregory Neil Shapiro return buf; 43606f25ae9SGregory Neil Shapiro } 437e92d3f3fSGregory Neil Shapiro 43840266059SGregory Neil Shapiro /* 43906f25ae9SGregory Neil Shapiro ** MILTER_WRITE -- write to a remote milter filter 44006f25ae9SGregory Neil Shapiro ** 44106f25ae9SGregory Neil Shapiro ** Parameters: 44206f25ae9SGregory Neil Shapiro ** m -- milter to read from. 44306f25ae9SGregory Neil Shapiro ** cmd -- command to send. 44406f25ae9SGregory Neil Shapiro ** buf -- optional command data. 44506f25ae9SGregory Neil Shapiro ** len -- length of buf. 44606f25ae9SGregory Neil Shapiro ** to -- timeout in seconds. 44706f25ae9SGregory Neil Shapiro ** e -- current envelope. 44806f25ae9SGregory Neil Shapiro ** 44906f25ae9SGregory Neil Shapiro ** Returns: 45006f25ae9SGregory Neil Shapiro ** buf if successful, NULL otherwise 45106f25ae9SGregory Neil Shapiro ** Not actually used anywhere but function prototype 45206f25ae9SGregory Neil Shapiro ** must match milter_read() 45306f25ae9SGregory Neil Shapiro */ 45406f25ae9SGregory Neil Shapiro 45506f25ae9SGregory Neil Shapiro static char * 45606f25ae9SGregory Neil Shapiro milter_write(m, cmd, buf, len, to, e) 45706f25ae9SGregory Neil Shapiro struct milter *m; 45806f25ae9SGregory Neil Shapiro char cmd; 45906f25ae9SGregory Neil Shapiro char *buf; 46006f25ae9SGregory Neil Shapiro ssize_t len; 46106f25ae9SGregory Neil Shapiro time_t to; 46206f25ae9SGregory Neil Shapiro ENVELOPE *e; 46306f25ae9SGregory Neil Shapiro { 46406f25ae9SGregory Neil Shapiro time_t writestart = (time_t) 0; 46506f25ae9SGregory Neil Shapiro ssize_t sl, i; 466e92d3f3fSGregory Neil Shapiro int num_vectors; 46706f25ae9SGregory Neil Shapiro mi_int32 nl; 46806f25ae9SGregory Neil Shapiro char data[MILTER_LEN_BYTES + 1]; 46940266059SGregory Neil Shapiro bool started = false; 470e92d3f3fSGregory Neil Shapiro struct iovec vector[2]; 47106f25ae9SGregory Neil Shapiro 472e92d3f3fSGregory Neil Shapiro /* 473e92d3f3fSGregory Neil Shapiro ** At most two buffers will be written, though 474e92d3f3fSGregory Neil Shapiro ** only one may actually be used (see num_vectors). 475e92d3f3fSGregory Neil Shapiro ** The first is the size/command and the second is the command data. 476e92d3f3fSGregory Neil Shapiro */ 477e92d3f3fSGregory Neil Shapiro 478e92d3f3fSGregory Neil Shapiro if (len < 0 || len > MilterMaxDataSize) 47906f25ae9SGregory Neil Shapiro { 48006f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 48140266059SGregory Neil Shapiro sm_dprintf("milter_write(%s): length %ld out of range\n", 48206f25ae9SGregory Neil Shapiro m->mf_name, (long) len); 48340266059SGregory Neil Shapiro if (MilterLogLevel > 0) 48406f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 48506f25ae9SGregory Neil Shapiro "milter_write(%s): length %ld out of range", 48606f25ae9SGregory Neil Shapiro m->mf_name, (long) len); 48740266059SGregory Neil Shapiro milter_error(m, e); 48806f25ae9SGregory Neil Shapiro return NULL; 48906f25ae9SGregory Neil Shapiro } 49006f25ae9SGregory Neil Shapiro 49106f25ae9SGregory Neil Shapiro if (tTd(64, 20)) 49240266059SGregory Neil Shapiro sm_dprintf("milter_write(%s): cmd %c, len %ld\n", 49306f25ae9SGregory Neil Shapiro m->mf_name, cmd, (long) len); 49406f25ae9SGregory Neil Shapiro 49506f25ae9SGregory Neil Shapiro nl = htonl(len + 1); /* add 1 for the cmd char */ 49606f25ae9SGregory Neil Shapiro (void) memcpy(data, (char *) &nl, MILTER_LEN_BYTES); 49706f25ae9SGregory Neil Shapiro data[MILTER_LEN_BYTES] = cmd; 49806f25ae9SGregory Neil Shapiro sl = MILTER_LEN_BYTES + 1; 49906f25ae9SGregory Neil Shapiro 500e92d3f3fSGregory Neil Shapiro /* set up the vector for the size / command */ 501e92d3f3fSGregory Neil Shapiro vector[0].iov_base = (void *) data; 502e92d3f3fSGregory Neil Shapiro vector[0].iov_len = sl; 503e92d3f3fSGregory Neil Shapiro 504e92d3f3fSGregory Neil Shapiro /* 505e92d3f3fSGregory Neil Shapiro ** Determine if there is command data. If so, there will be two 506e92d3f3fSGregory Neil Shapiro ** vectors. If not, there will be only one. The vectors are set 507e92d3f3fSGregory Neil Shapiro ** up here and 'num_vectors' and 'sl' are set appropriately. 508e92d3f3fSGregory Neil Shapiro */ 509e92d3f3fSGregory Neil Shapiro 510e92d3f3fSGregory Neil Shapiro /* NOTE: len<0 has already been checked for. Pedantic */ 511e92d3f3fSGregory Neil Shapiro if (len <= 0 || buf == NULL) 512e92d3f3fSGregory Neil Shapiro { 513e92d3f3fSGregory Neil Shapiro /* There is no command data -- only a size / command data */ 514e92d3f3fSGregory Neil Shapiro num_vectors = 1; 515e92d3f3fSGregory Neil Shapiro } 516e92d3f3fSGregory Neil Shapiro else 517e92d3f3fSGregory Neil Shapiro { 518e92d3f3fSGregory Neil Shapiro /* 519e92d3f3fSGregory Neil Shapiro ** There is both size / command and command data. 520e92d3f3fSGregory Neil Shapiro ** Set up the vector for the command data. 521e92d3f3fSGregory Neil Shapiro */ 522e92d3f3fSGregory Neil Shapiro 523e92d3f3fSGregory Neil Shapiro num_vectors = 2; 524e92d3f3fSGregory Neil Shapiro sl += len; 525e92d3f3fSGregory Neil Shapiro vector[1].iov_base = (void *) buf; 526e92d3f3fSGregory Neil Shapiro vector[1].iov_len = len; 527e92d3f3fSGregory Neil Shapiro 528e92d3f3fSGregory Neil Shapiro if (tTd(64, 50)) 529e92d3f3fSGregory Neil Shapiro sm_dprintf("milter_write(%s): Sending %*s\n", 530e92d3f3fSGregory Neil Shapiro m->mf_name, (int) len, buf); 531e92d3f3fSGregory Neil Shapiro } 532e92d3f3fSGregory Neil Shapiro 53306f25ae9SGregory Neil Shapiro if (to > 0) 53406f25ae9SGregory Neil Shapiro { 53506f25ae9SGregory Neil Shapiro writestart = curtime(); 53640266059SGregory Neil Shapiro MILTER_TIMEOUT("write", to, true, started); 53706f25ae9SGregory Neil Shapiro } 53806f25ae9SGregory Neil Shapiro 539e92d3f3fSGregory Neil Shapiro /* write the vector(s) */ 540e92d3f3fSGregory Neil Shapiro i = writev(m->mf_sock, vector, num_vectors); 54106f25ae9SGregory Neil Shapiro if (i != sl) 54206f25ae9SGregory Neil Shapiro { 54306f25ae9SGregory Neil Shapiro int save_errno = errno; 54406f25ae9SGregory Neil Shapiro 54506f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 54640266059SGregory Neil Shapiro sm_dprintf("milter_write(%s): write(%c) returned %ld, expected %ld: %s\n", 54706f25ae9SGregory Neil Shapiro m->mf_name, cmd, (long) i, (long) sl, 54840266059SGregory Neil Shapiro sm_errstring(save_errno)); 54940266059SGregory Neil Shapiro if (MilterLogLevel > 0) 55006f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 55140266059SGregory Neil Shapiro "Milter (%s): write(%c) returned %ld, expected %ld: %s", 55206f25ae9SGregory Neil Shapiro m->mf_name, cmd, (long) i, (long) sl, 55340266059SGregory Neil Shapiro sm_errstring(save_errno)); 55440266059SGregory Neil Shapiro milter_error(m, e); 55506f25ae9SGregory Neil Shapiro return NULL; 55606f25ae9SGregory Neil Shapiro } 55706f25ae9SGregory Neil Shapiro return buf; 55806f25ae9SGregory Neil Shapiro } 55906f25ae9SGregory Neil Shapiro 56006f25ae9SGregory Neil Shapiro /* 56106f25ae9SGregory Neil Shapiro ** Utility functions 56206f25ae9SGregory Neil Shapiro */ 56306f25ae9SGregory Neil Shapiro 56440266059SGregory Neil Shapiro /* 56506f25ae9SGregory Neil Shapiro ** MILTER_OPEN -- connect to remote milter filter 56606f25ae9SGregory Neil Shapiro ** 56706f25ae9SGregory Neil Shapiro ** Parameters: 56806f25ae9SGregory Neil Shapiro ** m -- milter to connect to. 56906f25ae9SGregory Neil Shapiro ** parseonly -- parse but don't connect. 57006f25ae9SGregory Neil Shapiro ** e -- current envelope. 57106f25ae9SGregory Neil Shapiro ** 57206f25ae9SGregory Neil Shapiro ** Returns: 573d9986b26SGregory Neil Shapiro ** connected socket if successful && !parseonly, 57406f25ae9SGregory Neil Shapiro ** 0 upon parse success if parseonly, 57506f25ae9SGregory Neil Shapiro ** -1 otherwise. 57606f25ae9SGregory Neil Shapiro */ 57706f25ae9SGregory Neil Shapiro 57813058a91SGregory Neil Shapiro static jmp_buf MilterConnectTimeout; 57913058a91SGregory Neil Shapiro 58006f25ae9SGregory Neil Shapiro static int 58106f25ae9SGregory Neil Shapiro milter_open(m, parseonly, e) 58206f25ae9SGregory Neil Shapiro struct milter *m; 58306f25ae9SGregory Neil Shapiro bool parseonly; 58406f25ae9SGregory Neil Shapiro ENVELOPE *e; 58506f25ae9SGregory Neil Shapiro { 58606f25ae9SGregory Neil Shapiro int sock = 0; 58706f25ae9SGregory Neil Shapiro SOCKADDR_LEN_T addrlen = 0; 58806f25ae9SGregory Neil Shapiro int addrno = 0; 58906f25ae9SGregory Neil Shapiro int save_errno; 59006f25ae9SGregory Neil Shapiro char *p; 59106f25ae9SGregory Neil Shapiro char *colon; 59206f25ae9SGregory Neil Shapiro char *at; 59306f25ae9SGregory Neil Shapiro struct hostent *hp = NULL; 59406f25ae9SGregory Neil Shapiro SOCKADDR addr; 59506f25ae9SGregory Neil Shapiro 59606f25ae9SGregory Neil Shapiro if (m->mf_conn == NULL || m->mf_conn[0] == '\0') 59706f25ae9SGregory Neil Shapiro { 59806f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 59940266059SGregory Neil Shapiro sm_dprintf("X%s: empty or missing socket information\n", 60006f25ae9SGregory Neil Shapiro m->mf_name); 60106f25ae9SGregory Neil Shapiro if (parseonly) 60206f25ae9SGregory Neil Shapiro syserr("X%s: empty or missing socket information", 60306f25ae9SGregory Neil Shapiro m->mf_name); 60413bd1963SGregory Neil Shapiro else if (MilterLogLevel > 0) 60506f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 60640266059SGregory Neil Shapiro "Milter (%s): empty or missing socket information", 60706f25ae9SGregory Neil Shapiro m->mf_name); 60840266059SGregory Neil Shapiro milter_error(m, e); 60906f25ae9SGregory Neil Shapiro return -1; 61006f25ae9SGregory Neil Shapiro } 61106f25ae9SGregory Neil Shapiro 61206f25ae9SGregory Neil Shapiro /* protocol:filename or protocol:port@host */ 613605302a5SGregory Neil Shapiro memset(&addr, '\0', sizeof addr); 61406f25ae9SGregory Neil Shapiro p = m->mf_conn; 61506f25ae9SGregory Neil Shapiro colon = strchr(p, ':'); 61606f25ae9SGregory Neil Shapiro if (colon != NULL) 61706f25ae9SGregory Neil Shapiro { 61806f25ae9SGregory Neil Shapiro *colon = '\0'; 61906f25ae9SGregory Neil Shapiro 62006f25ae9SGregory Neil Shapiro if (*p == '\0') 62106f25ae9SGregory Neil Shapiro { 62206f25ae9SGregory Neil Shapiro # if NETUNIX 62306f25ae9SGregory Neil Shapiro /* default to AF_UNIX */ 62406f25ae9SGregory Neil Shapiro addr.sa.sa_family = AF_UNIX; 62506f25ae9SGregory Neil Shapiro # else /* NETUNIX */ 62606f25ae9SGregory Neil Shapiro # if NETINET 62706f25ae9SGregory Neil Shapiro /* default to AF_INET */ 62806f25ae9SGregory Neil Shapiro addr.sa.sa_family = AF_INET; 62906f25ae9SGregory Neil Shapiro # else /* NETINET */ 63006f25ae9SGregory Neil Shapiro # if NETINET6 63106f25ae9SGregory Neil Shapiro /* default to AF_INET6 */ 63206f25ae9SGregory Neil Shapiro addr.sa.sa_family = AF_INET6; 63306f25ae9SGregory Neil Shapiro # else /* NETINET6 */ 63406f25ae9SGregory Neil Shapiro /* no protocols available */ 63513bd1963SGregory Neil Shapiro if (MilterLogLevel > 0) 63606f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 63740266059SGregory Neil Shapiro "Milter (%s): no valid socket protocols available", 63806f25ae9SGregory Neil Shapiro m->mf_name); 63940266059SGregory Neil Shapiro milter_error(m, e); 64006f25ae9SGregory Neil Shapiro return -1; 64106f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 64206f25ae9SGregory Neil Shapiro # endif /* NETINET */ 64306f25ae9SGregory Neil Shapiro # endif /* NETUNIX */ 64406f25ae9SGregory Neil Shapiro } 64506f25ae9SGregory Neil Shapiro # if NETUNIX 64640266059SGregory Neil Shapiro else if (sm_strcasecmp(p, "unix") == 0 || 64740266059SGregory Neil Shapiro sm_strcasecmp(p, "local") == 0) 64806f25ae9SGregory Neil Shapiro addr.sa.sa_family = AF_UNIX; 64906f25ae9SGregory Neil Shapiro # endif /* NETUNIX */ 65006f25ae9SGregory Neil Shapiro # if NETINET 65140266059SGregory Neil Shapiro else if (sm_strcasecmp(p, "inet") == 0) 65206f25ae9SGregory Neil Shapiro addr.sa.sa_family = AF_INET; 65306f25ae9SGregory Neil Shapiro # endif /* NETINET */ 65406f25ae9SGregory Neil Shapiro # if NETINET6 65540266059SGregory Neil Shapiro else if (sm_strcasecmp(p, "inet6") == 0) 65606f25ae9SGregory Neil Shapiro addr.sa.sa_family = AF_INET6; 65706f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 65806f25ae9SGregory Neil Shapiro else 65906f25ae9SGregory Neil Shapiro { 66006f25ae9SGregory Neil Shapiro # ifdef EPROTONOSUPPORT 66106f25ae9SGregory Neil Shapiro errno = EPROTONOSUPPORT; 66206f25ae9SGregory Neil Shapiro # else /* EPROTONOSUPPORT */ 66306f25ae9SGregory Neil Shapiro errno = EINVAL; 66406f25ae9SGregory Neil Shapiro # endif /* EPROTONOSUPPORT */ 66506f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 66640266059SGregory Neil Shapiro sm_dprintf("X%s: unknown socket type %s\n", 66706f25ae9SGregory Neil Shapiro m->mf_name, p); 66806f25ae9SGregory Neil Shapiro if (parseonly) 66906f25ae9SGregory Neil Shapiro syserr("X%s: unknown socket type %s", 67006f25ae9SGregory Neil Shapiro m->mf_name, p); 67113bd1963SGregory Neil Shapiro else if (MilterLogLevel > 0) 67206f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 67340266059SGregory Neil Shapiro "Milter (%s): unknown socket type %s", 67406f25ae9SGregory Neil Shapiro m->mf_name, p); 67540266059SGregory Neil Shapiro milter_error(m, e); 67606f25ae9SGregory Neil Shapiro return -1; 67706f25ae9SGregory Neil Shapiro } 67806f25ae9SGregory Neil Shapiro *colon++ = ':'; 67906f25ae9SGregory Neil Shapiro } 68006f25ae9SGregory Neil Shapiro else 68106f25ae9SGregory Neil Shapiro { 68206f25ae9SGregory Neil Shapiro /* default to AF_UNIX */ 68306f25ae9SGregory Neil Shapiro addr.sa.sa_family = AF_UNIX; 68406f25ae9SGregory Neil Shapiro colon = p; 68506f25ae9SGregory Neil Shapiro } 68606f25ae9SGregory Neil Shapiro 68706f25ae9SGregory Neil Shapiro # if NETUNIX 68806f25ae9SGregory Neil Shapiro if (addr.sa.sa_family == AF_UNIX) 68906f25ae9SGregory Neil Shapiro { 69006f25ae9SGregory Neil Shapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_EXECOK; 69106f25ae9SGregory Neil Shapiro 69206f25ae9SGregory Neil Shapiro at = colon; 69306f25ae9SGregory Neil Shapiro if (strlen(colon) >= sizeof addr.sunix.sun_path) 69406f25ae9SGregory Neil Shapiro { 69506f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 69640266059SGregory Neil Shapiro sm_dprintf("X%s: local socket name %s too long\n", 69706f25ae9SGregory Neil Shapiro m->mf_name, colon); 69806f25ae9SGregory Neil Shapiro errno = EINVAL; 69906f25ae9SGregory Neil Shapiro if (parseonly) 70006f25ae9SGregory Neil Shapiro syserr("X%s: local socket name %s too long", 70106f25ae9SGregory Neil Shapiro m->mf_name, colon); 70213bd1963SGregory Neil Shapiro else if (MilterLogLevel > 0) 70306f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 70440266059SGregory Neil Shapiro "Milter (%s): local socket name %s too long", 70506f25ae9SGregory Neil Shapiro m->mf_name, colon); 70640266059SGregory Neil Shapiro milter_error(m, e); 70706f25ae9SGregory Neil Shapiro return -1; 70806f25ae9SGregory Neil Shapiro } 70906f25ae9SGregory Neil Shapiro errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff, 71006f25ae9SGregory Neil Shapiro S_IRUSR|S_IWUSR, NULL); 71106f25ae9SGregory Neil Shapiro 71206f25ae9SGregory Neil Shapiro /* if just parsing .cf file, socket doesn't need to exist */ 71306f25ae9SGregory Neil Shapiro if (parseonly && errno == ENOENT) 71406f25ae9SGregory Neil Shapiro { 71506f25ae9SGregory Neil Shapiro if (OpMode == MD_DAEMON || 71606f25ae9SGregory Neil Shapiro OpMode == MD_FGDAEMON) 71740266059SGregory Neil Shapiro (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 71806f25ae9SGregory Neil Shapiro "WARNING: X%s: local socket name %s missing\n", 71906f25ae9SGregory Neil Shapiro m->mf_name, colon); 72006f25ae9SGregory Neil Shapiro } 72106f25ae9SGregory Neil Shapiro else if (errno != 0) 72206f25ae9SGregory Neil Shapiro { 72306f25ae9SGregory Neil Shapiro /* if not safe, don't create */ 72406f25ae9SGregory Neil Shapiro save_errno = errno; 72506f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 72640266059SGregory Neil Shapiro sm_dprintf("X%s: local socket name %s unsafe\n", 72706f25ae9SGregory Neil Shapiro m->mf_name, colon); 72806f25ae9SGregory Neil Shapiro errno = save_errno; 72906f25ae9SGregory Neil Shapiro if (parseonly) 73006f25ae9SGregory Neil Shapiro { 73106f25ae9SGregory Neil Shapiro if (OpMode == MD_DAEMON || 73206f25ae9SGregory Neil Shapiro OpMode == MD_FGDAEMON || 73306f25ae9SGregory Neil Shapiro OpMode == MD_SMTP) 73406f25ae9SGregory Neil Shapiro syserr("X%s: local socket name %s unsafe", 73506f25ae9SGregory Neil Shapiro m->mf_name, colon); 73606f25ae9SGregory Neil Shapiro } 73713bd1963SGregory Neil Shapiro else if (MilterLogLevel > 0) 73806f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 73940266059SGregory Neil Shapiro "Milter (%s): local socket name %s unsafe", 74006f25ae9SGregory Neil Shapiro m->mf_name, colon); 74140266059SGregory Neil Shapiro milter_error(m, e); 74206f25ae9SGregory Neil Shapiro return -1; 74306f25ae9SGregory Neil Shapiro } 74406f25ae9SGregory Neil Shapiro 74540266059SGregory Neil Shapiro (void) sm_strlcpy(addr.sunix.sun_path, colon, 74606f25ae9SGregory Neil Shapiro sizeof addr.sunix.sun_path); 74706f25ae9SGregory Neil Shapiro addrlen = sizeof (struct sockaddr_un); 74806f25ae9SGregory Neil Shapiro } 74906f25ae9SGregory Neil Shapiro else 75006f25ae9SGregory Neil Shapiro # endif /* NETUNIX */ 75106f25ae9SGregory Neil Shapiro # if NETINET || NETINET6 75240266059SGregory Neil Shapiro if (false 75306f25ae9SGregory Neil Shapiro # if NETINET 75406f25ae9SGregory Neil Shapiro || addr.sa.sa_family == AF_INET 75506f25ae9SGregory Neil Shapiro # endif /* NETINET */ 75606f25ae9SGregory Neil Shapiro # if NETINET6 75706f25ae9SGregory Neil Shapiro || addr.sa.sa_family == AF_INET6 75806f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 75906f25ae9SGregory Neil Shapiro ) 76006f25ae9SGregory Neil Shapiro { 76140266059SGregory Neil Shapiro unsigned short port; 76206f25ae9SGregory Neil Shapiro 76306f25ae9SGregory Neil Shapiro /* Parse port@host */ 76406f25ae9SGregory Neil Shapiro at = strchr(colon, '@'); 76506f25ae9SGregory Neil Shapiro if (at == NULL) 76606f25ae9SGregory Neil Shapiro { 76706f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 76840266059SGregory Neil Shapiro sm_dprintf("X%s: bad address %s (expected port@host)\n", 76906f25ae9SGregory Neil Shapiro m->mf_name, colon); 77006f25ae9SGregory Neil Shapiro if (parseonly) 77106f25ae9SGregory Neil Shapiro syserr("X%s: bad address %s (expected port@host)", 77206f25ae9SGregory Neil Shapiro m->mf_name, colon); 77313bd1963SGregory Neil Shapiro else if (MilterLogLevel > 0) 77406f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 77540266059SGregory Neil Shapiro "Milter (%s): bad address %s (expected port@host)", 77606f25ae9SGregory Neil Shapiro m->mf_name, colon); 77740266059SGregory Neil Shapiro milter_error(m, e); 77806f25ae9SGregory Neil Shapiro return -1; 77906f25ae9SGregory Neil Shapiro } 78006f25ae9SGregory Neil Shapiro *at = '\0'; 78106f25ae9SGregory Neil Shapiro if (isascii(*colon) && isdigit(*colon)) 78240266059SGregory Neil Shapiro port = htons((unsigned short) atoi(colon)); 78306f25ae9SGregory Neil Shapiro else 78406f25ae9SGregory Neil Shapiro { 78506f25ae9SGregory Neil Shapiro # ifdef NO_GETSERVBYNAME 78606f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 78740266059SGregory Neil Shapiro sm_dprintf("X%s: invalid port number %s\n", 78806f25ae9SGregory Neil Shapiro m->mf_name, colon); 78906f25ae9SGregory Neil Shapiro if (parseonly) 79006f25ae9SGregory Neil Shapiro syserr("X%s: invalid port number %s", 79106f25ae9SGregory Neil Shapiro m->mf_name, colon); 79213bd1963SGregory Neil Shapiro else if (MilterLogLevel > 0) 79306f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 79440266059SGregory Neil Shapiro "Milter (%s): invalid port number %s", 79506f25ae9SGregory Neil Shapiro m->mf_name, colon); 79640266059SGregory Neil Shapiro milter_error(m, e); 79706f25ae9SGregory Neil Shapiro return -1; 79806f25ae9SGregory Neil Shapiro # else /* NO_GETSERVBYNAME */ 79906f25ae9SGregory Neil Shapiro register struct servent *sp; 80006f25ae9SGregory Neil Shapiro 80106f25ae9SGregory Neil Shapiro sp = getservbyname(colon, "tcp"); 80206f25ae9SGregory Neil Shapiro if (sp == NULL) 80306f25ae9SGregory Neil Shapiro { 80406f25ae9SGregory Neil Shapiro save_errno = errno; 80506f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 80640266059SGregory Neil Shapiro sm_dprintf("X%s: unknown port name %s\n", 80706f25ae9SGregory Neil Shapiro m->mf_name, colon); 80806f25ae9SGregory Neil Shapiro errno = save_errno; 80906f25ae9SGregory Neil Shapiro if (parseonly) 81006f25ae9SGregory Neil Shapiro syserr("X%s: unknown port name %s", 81106f25ae9SGregory Neil Shapiro m->mf_name, colon); 81213bd1963SGregory Neil Shapiro else if (MilterLogLevel > 0) 81306f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 81440266059SGregory Neil Shapiro "Milter (%s): unknown port name %s", 81506f25ae9SGregory Neil Shapiro m->mf_name, colon); 81640266059SGregory Neil Shapiro milter_error(m, e); 81706f25ae9SGregory Neil Shapiro return -1; 81806f25ae9SGregory Neil Shapiro } 81906f25ae9SGregory Neil Shapiro port = sp->s_port; 82006f25ae9SGregory Neil Shapiro # endif /* NO_GETSERVBYNAME */ 82106f25ae9SGregory Neil Shapiro } 82206f25ae9SGregory Neil Shapiro *at++ = '@'; 82306f25ae9SGregory Neil Shapiro if (*at == '[') 82406f25ae9SGregory Neil Shapiro { 82506f25ae9SGregory Neil Shapiro char *end; 82606f25ae9SGregory Neil Shapiro 82706f25ae9SGregory Neil Shapiro end = strchr(at, ']'); 82806f25ae9SGregory Neil Shapiro if (end != NULL) 82906f25ae9SGregory Neil Shapiro { 83040266059SGregory Neil Shapiro bool found = false; 83106f25ae9SGregory Neil Shapiro # if NETINET 83206f25ae9SGregory Neil Shapiro unsigned long hid = INADDR_NONE; 83306f25ae9SGregory Neil Shapiro # endif /* NETINET */ 83406f25ae9SGregory Neil Shapiro # if NETINET6 83506f25ae9SGregory Neil Shapiro struct sockaddr_in6 hid6; 83606f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 83706f25ae9SGregory Neil Shapiro 83806f25ae9SGregory Neil Shapiro *end = '\0'; 83906f25ae9SGregory Neil Shapiro # if NETINET 84006f25ae9SGregory Neil Shapiro if (addr.sa.sa_family == AF_INET && 84106f25ae9SGregory Neil Shapiro (hid = inet_addr(&at[1])) != INADDR_NONE) 84206f25ae9SGregory Neil Shapiro { 84306f25ae9SGregory Neil Shapiro addr.sin.sin_addr.s_addr = hid; 84406f25ae9SGregory Neil Shapiro addr.sin.sin_port = port; 84540266059SGregory Neil Shapiro found = true; 84606f25ae9SGregory Neil Shapiro } 84706f25ae9SGregory Neil Shapiro # endif /* NETINET */ 84806f25ae9SGregory Neil Shapiro # if NETINET6 84906f25ae9SGregory Neil Shapiro (void) memset(&hid6, '\0', sizeof hid6); 85006f25ae9SGregory Neil Shapiro if (addr.sa.sa_family == AF_INET6 && 85140266059SGregory Neil Shapiro anynet_pton(AF_INET6, &at[1], 85206f25ae9SGregory Neil Shapiro &hid6.sin6_addr) == 1) 85306f25ae9SGregory Neil Shapiro { 85406f25ae9SGregory Neil Shapiro addr.sin6.sin6_addr = hid6.sin6_addr; 85506f25ae9SGregory Neil Shapiro addr.sin6.sin6_port = port; 85640266059SGregory Neil Shapiro found = true; 85706f25ae9SGregory Neil Shapiro } 85806f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 85906f25ae9SGregory Neil Shapiro *end = ']'; 86006f25ae9SGregory Neil Shapiro if (!found) 86106f25ae9SGregory Neil Shapiro { 86206f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 86340266059SGregory Neil Shapiro sm_dprintf("X%s: Invalid numeric domain spec \"%s\"\n", 86406f25ae9SGregory Neil Shapiro m->mf_name, at); 86506f25ae9SGregory Neil Shapiro if (parseonly) 86606f25ae9SGregory Neil Shapiro syserr("X%s: Invalid numeric domain spec \"%s\"", 86706f25ae9SGregory Neil Shapiro m->mf_name, at); 86813bd1963SGregory Neil Shapiro else if (MilterLogLevel > 0) 86906f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 87040266059SGregory Neil Shapiro "Milter (%s): Invalid numeric domain spec \"%s\"", 87106f25ae9SGregory Neil Shapiro m->mf_name, at); 87240266059SGregory Neil Shapiro milter_error(m, e); 87306f25ae9SGregory Neil Shapiro return -1; 87406f25ae9SGregory Neil Shapiro } 87506f25ae9SGregory Neil Shapiro } 87606f25ae9SGregory Neil Shapiro else 87706f25ae9SGregory Neil Shapiro { 87806f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 87940266059SGregory Neil Shapiro sm_dprintf("X%s: Invalid numeric domain spec \"%s\"\n", 88006f25ae9SGregory Neil Shapiro m->mf_name, at); 88106f25ae9SGregory Neil Shapiro if (parseonly) 88206f25ae9SGregory Neil Shapiro syserr("X%s: Invalid numeric domain spec \"%s\"", 88306f25ae9SGregory Neil Shapiro m->mf_name, at); 88413bd1963SGregory Neil Shapiro else if (MilterLogLevel > 0) 88506f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 88640266059SGregory Neil Shapiro "Milter (%s): Invalid numeric domain spec \"%s\"", 88706f25ae9SGregory Neil Shapiro m->mf_name, at); 88840266059SGregory Neil Shapiro milter_error(m, e); 88906f25ae9SGregory Neil Shapiro return -1; 89006f25ae9SGregory Neil Shapiro } 89106f25ae9SGregory Neil Shapiro } 89206f25ae9SGregory Neil Shapiro else 89306f25ae9SGregory Neil Shapiro { 89406f25ae9SGregory Neil Shapiro hp = sm_gethostbyname(at, addr.sa.sa_family); 89506f25ae9SGregory Neil Shapiro if (hp == NULL) 89606f25ae9SGregory Neil Shapiro { 89706f25ae9SGregory Neil Shapiro save_errno = errno; 89806f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 89940266059SGregory Neil Shapiro sm_dprintf("X%s: Unknown host name %s\n", 90006f25ae9SGregory Neil Shapiro m->mf_name, at); 90106f25ae9SGregory Neil Shapiro errno = save_errno; 90206f25ae9SGregory Neil Shapiro if (parseonly) 90306f25ae9SGregory Neil Shapiro syserr("X%s: Unknown host name %s", 90406f25ae9SGregory Neil Shapiro m->mf_name, at); 90513bd1963SGregory Neil Shapiro else if (MilterLogLevel > 0) 90606f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 90740266059SGregory Neil Shapiro "Milter (%s): Unknown host name %s", 90806f25ae9SGregory Neil Shapiro m->mf_name, at); 90940266059SGregory Neil Shapiro milter_error(m, e); 91006f25ae9SGregory Neil Shapiro return -1; 91106f25ae9SGregory Neil Shapiro } 91206f25ae9SGregory Neil Shapiro addr.sa.sa_family = hp->h_addrtype; 91306f25ae9SGregory Neil Shapiro switch (hp->h_addrtype) 91406f25ae9SGregory Neil Shapiro { 91506f25ae9SGregory Neil Shapiro # if NETINET 91606f25ae9SGregory Neil Shapiro case AF_INET: 91706f25ae9SGregory Neil Shapiro memmove(&addr.sin.sin_addr, 91840266059SGregory Neil Shapiro hp->h_addr, INADDRSZ); 91906f25ae9SGregory Neil Shapiro addr.sin.sin_port = port; 92006f25ae9SGregory Neil Shapiro addrlen = sizeof (struct sockaddr_in); 92106f25ae9SGregory Neil Shapiro addrno = 1; 92206f25ae9SGregory Neil Shapiro break; 92306f25ae9SGregory Neil Shapiro # endif /* NETINET */ 92406f25ae9SGregory Neil Shapiro 92506f25ae9SGregory Neil Shapiro # if NETINET6 92606f25ae9SGregory Neil Shapiro case AF_INET6: 92706f25ae9SGregory Neil Shapiro memmove(&addr.sin6.sin6_addr, 92840266059SGregory Neil Shapiro hp->h_addr, IN6ADDRSZ); 92906f25ae9SGregory Neil Shapiro addr.sin6.sin6_port = port; 93006f25ae9SGregory Neil Shapiro addrlen = sizeof (struct sockaddr_in6); 93106f25ae9SGregory Neil Shapiro addrno = 1; 93206f25ae9SGregory Neil Shapiro break; 93306f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 93406f25ae9SGregory Neil Shapiro 93506f25ae9SGregory Neil Shapiro default: 93606f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 93740266059SGregory Neil Shapiro sm_dprintf("X%s: Unknown protocol for %s (%d)\n", 93806f25ae9SGregory Neil Shapiro m->mf_name, at, 93906f25ae9SGregory Neil Shapiro hp->h_addrtype); 94006f25ae9SGregory Neil Shapiro if (parseonly) 94106f25ae9SGregory Neil Shapiro syserr("X%s: Unknown protocol for %s (%d)", 94206f25ae9SGregory Neil Shapiro m->mf_name, at, hp->h_addrtype); 94313bd1963SGregory Neil Shapiro else if (MilterLogLevel > 0) 94406f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 94540266059SGregory Neil Shapiro "Milter (%s): Unknown protocol for %s (%d)", 94606f25ae9SGregory Neil Shapiro m->mf_name, at, 94706f25ae9SGregory Neil Shapiro hp->h_addrtype); 94840266059SGregory Neil Shapiro milter_error(m, e); 94940266059SGregory Neil Shapiro # if NETINET6 950193538b7SGregory Neil Shapiro freehostent(hp); 95140266059SGregory Neil Shapiro # endif /* NETINET6 */ 95206f25ae9SGregory Neil Shapiro return -1; 95306f25ae9SGregory Neil Shapiro } 95406f25ae9SGregory Neil Shapiro } 95506f25ae9SGregory Neil Shapiro } 95606f25ae9SGregory Neil Shapiro else 95706f25ae9SGregory Neil Shapiro # endif /* NETINET || NETINET6 */ 95806f25ae9SGregory Neil Shapiro { 95906f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 96040266059SGregory Neil Shapiro sm_dprintf("X%s: unknown socket protocol\n", 96140266059SGregory Neil Shapiro m->mf_name); 96206f25ae9SGregory Neil Shapiro if (parseonly) 96306f25ae9SGregory Neil Shapiro syserr("X%s: unknown socket protocol", m->mf_name); 96413bd1963SGregory Neil Shapiro else if (MilterLogLevel > 0) 96506f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 96640266059SGregory Neil Shapiro "Milter (%s): unknown socket protocol", 96740266059SGregory Neil Shapiro m->mf_name); 96840266059SGregory Neil Shapiro milter_error(m, e); 96906f25ae9SGregory Neil Shapiro return -1; 97006f25ae9SGregory Neil Shapiro } 97106f25ae9SGregory Neil Shapiro 97206f25ae9SGregory Neil Shapiro /* just parsing through? */ 97306f25ae9SGregory Neil Shapiro if (parseonly) 97406f25ae9SGregory Neil Shapiro { 97506f25ae9SGregory Neil Shapiro m->mf_state = SMFS_READY; 97640266059SGregory Neil Shapiro # if NETINET6 977193538b7SGregory Neil Shapiro if (hp != NULL) 978193538b7SGregory Neil Shapiro freehostent(hp); 97940266059SGregory Neil Shapiro # endif /* NETINET6 */ 98006f25ae9SGregory Neil Shapiro return 0; 98106f25ae9SGregory Neil Shapiro } 98206f25ae9SGregory Neil Shapiro 98306f25ae9SGregory Neil Shapiro /* sanity check */ 98406f25ae9SGregory Neil Shapiro if (m->mf_state != SMFS_READY && 98506f25ae9SGregory Neil Shapiro m->mf_state != SMFS_CLOSED) 98606f25ae9SGregory Neil Shapiro { 98706f25ae9SGregory Neil Shapiro /* shouldn't happen */ 98806f25ae9SGregory Neil Shapiro if (tTd(64, 1)) 98940266059SGregory Neil Shapiro sm_dprintf("Milter (%s): Trying to open filter in state %c\n", 99006f25ae9SGregory Neil Shapiro m->mf_name, (char) m->mf_state); 99140266059SGregory Neil Shapiro milter_error(m, e); 99240266059SGregory Neil Shapiro # if NETINET6 993193538b7SGregory Neil Shapiro if (hp != NULL) 994193538b7SGregory Neil Shapiro freehostent(hp); 99540266059SGregory Neil Shapiro # endif /* NETINET6 */ 99606f25ae9SGregory Neil Shapiro return -1; 99706f25ae9SGregory Neil Shapiro } 99806f25ae9SGregory Neil Shapiro 99906f25ae9SGregory Neil Shapiro /* nope, actually connecting */ 100006f25ae9SGregory Neil Shapiro for (;;) 100106f25ae9SGregory Neil Shapiro { 100206f25ae9SGregory Neil Shapiro sock = socket(addr.sa.sa_family, SOCK_STREAM, 0); 100306f25ae9SGregory Neil Shapiro if (sock < 0) 100406f25ae9SGregory Neil Shapiro { 100506f25ae9SGregory Neil Shapiro save_errno = errno; 100606f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 100740266059SGregory Neil Shapiro sm_dprintf("Milter (%s): error creating socket: %s\n", 100840266059SGregory Neil Shapiro m->mf_name, 100940266059SGregory Neil Shapiro sm_errstring(save_errno)); 101040266059SGregory Neil Shapiro if (MilterLogLevel > 0) 101106f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 101240266059SGregory Neil Shapiro "Milter (%s): error creating socket: %s", 101340266059SGregory Neil Shapiro m->mf_name, sm_errstring(save_errno)); 101440266059SGregory Neil Shapiro milter_error(m, e); 101540266059SGregory Neil Shapiro # if NETINET6 1016193538b7SGregory Neil Shapiro if (hp != NULL) 1017193538b7SGregory Neil Shapiro freehostent(hp); 101840266059SGregory Neil Shapiro # endif /* NETINET6 */ 101906f25ae9SGregory Neil Shapiro return -1; 102006f25ae9SGregory Neil Shapiro } 102106f25ae9SGregory Neil Shapiro 102213058a91SGregory Neil Shapiro if (setjmp(MilterConnectTimeout) == 0) 102313058a91SGregory Neil Shapiro { 102440266059SGregory Neil Shapiro SM_EVENT *ev = NULL; 102513058a91SGregory Neil Shapiro int i; 102613058a91SGregory Neil Shapiro 102713058a91SGregory Neil Shapiro if (m->mf_timeout[SMFTO_CONNECT] > 0) 102840266059SGregory Neil Shapiro ev = sm_setevent(m->mf_timeout[SMFTO_CONNECT], 102913058a91SGregory Neil Shapiro milter_connect_timeout, 0); 103013058a91SGregory Neil Shapiro 103113058a91SGregory Neil Shapiro i = connect(sock, (struct sockaddr *) &addr, addrlen); 103213058a91SGregory Neil Shapiro save_errno = errno; 103313058a91SGregory Neil Shapiro if (ev != NULL) 103440266059SGregory Neil Shapiro sm_clrevent(ev); 103513058a91SGregory Neil Shapiro errno = save_errno; 103613058a91SGregory Neil Shapiro if (i >= 0) 103706f25ae9SGregory Neil Shapiro break; 103813058a91SGregory Neil Shapiro } 103906f25ae9SGregory Neil Shapiro 104006f25ae9SGregory Neil Shapiro /* couldn't connect.... try next address */ 104106f25ae9SGregory Neil Shapiro save_errno = errno; 104242e5d165SGregory Neil Shapiro p = CurHostName; 104342e5d165SGregory Neil Shapiro CurHostName = at; 104406f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 104540266059SGregory Neil Shapiro sm_dprintf("milter_open (%s): open %s failed: %s\n", 104640266059SGregory Neil Shapiro m->mf_name, at, sm_errstring(save_errno)); 104740266059SGregory Neil Shapiro if (MilterLogLevel > 13) 104806f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, 104940266059SGregory Neil Shapiro "Milter (%s): open %s failed: %s", 105040266059SGregory Neil Shapiro m->mf_name, at, sm_errstring(save_errno)); 105142e5d165SGregory Neil Shapiro CurHostName = p; 105206f25ae9SGregory Neil Shapiro (void) close(sock); 105306f25ae9SGregory Neil Shapiro 105406f25ae9SGregory Neil Shapiro /* try next address */ 105506f25ae9SGregory Neil Shapiro if (hp != NULL && hp->h_addr_list[addrno] != NULL) 105606f25ae9SGregory Neil Shapiro { 105706f25ae9SGregory Neil Shapiro switch (addr.sa.sa_family) 105806f25ae9SGregory Neil Shapiro { 105906f25ae9SGregory Neil Shapiro # if NETINET 106006f25ae9SGregory Neil Shapiro case AF_INET: 106106f25ae9SGregory Neil Shapiro memmove(&addr.sin.sin_addr, 106206f25ae9SGregory Neil Shapiro hp->h_addr_list[addrno++], 106306f25ae9SGregory Neil Shapiro INADDRSZ); 106406f25ae9SGregory Neil Shapiro break; 106506f25ae9SGregory Neil Shapiro # endif /* NETINET */ 106606f25ae9SGregory Neil Shapiro 106706f25ae9SGregory Neil Shapiro # if NETINET6 106806f25ae9SGregory Neil Shapiro case AF_INET6: 106906f25ae9SGregory Neil Shapiro memmove(&addr.sin6.sin6_addr, 107006f25ae9SGregory Neil Shapiro hp->h_addr_list[addrno++], 107106f25ae9SGregory Neil Shapiro IN6ADDRSZ); 107206f25ae9SGregory Neil Shapiro break; 107306f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 107406f25ae9SGregory Neil Shapiro 107506f25ae9SGregory Neil Shapiro default: 107606f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 107740266059SGregory Neil Shapiro sm_dprintf("X%s: Unknown protocol for %s (%d)\n", 107806f25ae9SGregory Neil Shapiro m->mf_name, at, 107906f25ae9SGregory Neil Shapiro hp->h_addrtype); 108040266059SGregory Neil Shapiro if (MilterLogLevel > 0) 108106f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 108240266059SGregory Neil Shapiro "Milter (%s): Unknown protocol for %s (%d)", 108306f25ae9SGregory Neil Shapiro m->mf_name, at, 108406f25ae9SGregory Neil Shapiro hp->h_addrtype); 108540266059SGregory Neil Shapiro milter_error(m, e); 108640266059SGregory Neil Shapiro # if NETINET6 1087193538b7SGregory Neil Shapiro freehostent(hp); 108840266059SGregory Neil Shapiro # endif /* NETINET6 */ 108906f25ae9SGregory Neil Shapiro return -1; 109006f25ae9SGregory Neil Shapiro } 109106f25ae9SGregory Neil Shapiro continue; 109206f25ae9SGregory Neil Shapiro } 109313058a91SGregory Neil Shapiro p = CurHostName; 109413058a91SGregory Neil Shapiro CurHostName = at; 109506f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 109640266059SGregory Neil Shapiro sm_dprintf("X%s: error connecting to filter: %s\n", 109740266059SGregory Neil Shapiro m->mf_name, sm_errstring(save_errno)); 109840266059SGregory Neil Shapiro if (MilterLogLevel > 0) 109906f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 110040266059SGregory Neil Shapiro "Milter (%s): error connecting to filter: %s", 110140266059SGregory Neil Shapiro m->mf_name, sm_errstring(save_errno)); 110213058a91SGregory Neil Shapiro CurHostName = p; 110340266059SGregory Neil Shapiro milter_error(m, e); 110440266059SGregory Neil Shapiro # if NETINET6 1105193538b7SGregory Neil Shapiro if (hp != NULL) 1106193538b7SGregory Neil Shapiro freehostent(hp); 110740266059SGregory Neil Shapiro # endif /* NETINET6 */ 110806f25ae9SGregory Neil Shapiro return -1; 110906f25ae9SGregory Neil Shapiro } 111006f25ae9SGregory Neil Shapiro m->mf_state = SMFS_OPEN; 111140266059SGregory Neil Shapiro # if NETINET6 1112193538b7SGregory Neil Shapiro if (hp != NULL) 1113193538b7SGregory Neil Shapiro { 1114193538b7SGregory Neil Shapiro freehostent(hp); 1115193538b7SGregory Neil Shapiro hp = NULL; 1116193538b7SGregory Neil Shapiro } 111740266059SGregory Neil Shapiro # endif /* NETINET6 */ 1118e92d3f3fSGregory Neil Shapiro # if _FFR_MILTER_NAGLE 1119e92d3f3fSGregory Neil Shapiro # ifndef TCP_CORK 1120e92d3f3fSGregory Neil Shapiro { 1121e92d3f3fSGregory Neil Shapiro int nodelay = 1; 1122e92d3f3fSGregory Neil Shapiro 1123e92d3f3fSGregory Neil Shapiro setsockopt(m->mf_sock, IPPROTO_TCP, TCP_NODELAY, 1124e92d3f3fSGregory Neil Shapiro (char *)&nodelay, sizeof(nodelay)); 1125e92d3f3fSGregory Neil Shapiro } 1126e92d3f3fSGregory Neil Shapiro # endif /* TCP_CORK */ 1127e92d3f3fSGregory Neil Shapiro # endif /* _FFR_MILTER_NAGLE */ 112806f25ae9SGregory Neil Shapiro return sock; 112906f25ae9SGregory Neil Shapiro } 113013058a91SGregory Neil Shapiro 113113058a91SGregory Neil Shapiro static void 1132b6bacd31SGregory Neil Shapiro milter_connect_timeout(ignore) 1133b6bacd31SGregory Neil Shapiro int ignore; 113413058a91SGregory Neil Shapiro { 113513058a91SGregory Neil Shapiro /* 113613058a91SGregory Neil Shapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 113713058a91SGregory Neil Shapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 113813058a91SGregory Neil Shapiro ** DOING. 113913058a91SGregory Neil Shapiro */ 114013058a91SGregory Neil Shapiro 114113058a91SGregory Neil Shapiro errno = ETIMEDOUT; 114213058a91SGregory Neil Shapiro longjmp(MilterConnectTimeout, 1); 114313058a91SGregory Neil Shapiro } 114440266059SGregory Neil Shapiro /* 114506f25ae9SGregory Neil Shapiro ** MILTER_SETUP -- setup structure for a mail filter 114606f25ae9SGregory Neil Shapiro ** 114706f25ae9SGregory Neil Shapiro ** Parameters: 114806f25ae9SGregory Neil Shapiro ** line -- the options line. 114906f25ae9SGregory Neil Shapiro ** 115006f25ae9SGregory Neil Shapiro ** Returns: 115106f25ae9SGregory Neil Shapiro ** none 115206f25ae9SGregory Neil Shapiro */ 115306f25ae9SGregory Neil Shapiro 115406f25ae9SGregory Neil Shapiro void 115506f25ae9SGregory Neil Shapiro milter_setup(line) 115606f25ae9SGregory Neil Shapiro char *line; 115706f25ae9SGregory Neil Shapiro { 115806f25ae9SGregory Neil Shapiro char fcode; 115906f25ae9SGregory Neil Shapiro register char *p; 116006f25ae9SGregory Neil Shapiro register struct milter *m; 116106f25ae9SGregory Neil Shapiro STAB *s; 116206f25ae9SGregory Neil Shapiro 116342e5d165SGregory Neil Shapiro /* collect the filter name */ 116406f25ae9SGregory Neil Shapiro for (p = line; 116506f25ae9SGregory Neil Shapiro *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); 116606f25ae9SGregory Neil Shapiro p++) 116706f25ae9SGregory Neil Shapiro continue; 116806f25ae9SGregory Neil Shapiro if (*p != '\0') 116906f25ae9SGregory Neil Shapiro *p++ = '\0'; 117006f25ae9SGregory Neil Shapiro if (line[0] == '\0') 117106f25ae9SGregory Neil Shapiro { 117206f25ae9SGregory Neil Shapiro syserr("name required for mail filter"); 117306f25ae9SGregory Neil Shapiro return; 117406f25ae9SGregory Neil Shapiro } 117506f25ae9SGregory Neil Shapiro m = (struct milter *) xalloc(sizeof *m); 117606f25ae9SGregory Neil Shapiro memset((char *) m, '\0', sizeof *m); 117706f25ae9SGregory Neil Shapiro m->mf_name = newstr(line); 117806f25ae9SGregory Neil Shapiro m->mf_state = SMFS_READY; 117906f25ae9SGregory Neil Shapiro m->mf_sock = -1; 118040266059SGregory Neil Shapiro m->mf_timeout[SMFTO_CONNECT] = (time_t) 300; 118106f25ae9SGregory Neil Shapiro m->mf_timeout[SMFTO_WRITE] = (time_t) 10; 118206f25ae9SGregory Neil Shapiro m->mf_timeout[SMFTO_READ] = (time_t) 10; 118306f25ae9SGregory Neil Shapiro m->mf_timeout[SMFTO_EOM] = (time_t) 300; 118406f25ae9SGregory Neil Shapiro 118506f25ae9SGregory Neil Shapiro /* now scan through and assign info from the fields */ 118606f25ae9SGregory Neil Shapiro while (*p != '\0') 118706f25ae9SGregory Neil Shapiro { 118806f25ae9SGregory Neil Shapiro char *delimptr; 118906f25ae9SGregory Neil Shapiro 119006f25ae9SGregory Neil Shapiro while (*p != '\0' && 119106f25ae9SGregory Neil Shapiro (*p == ',' || (isascii(*p) && isspace(*p)))) 119206f25ae9SGregory Neil Shapiro p++; 119306f25ae9SGregory Neil Shapiro 119406f25ae9SGregory Neil Shapiro /* p now points to field code */ 119506f25ae9SGregory Neil Shapiro fcode = *p; 119606f25ae9SGregory Neil Shapiro while (*p != '\0' && *p != '=' && *p != ',') 119706f25ae9SGregory Neil Shapiro p++; 119806f25ae9SGregory Neil Shapiro if (*p++ != '=') 119906f25ae9SGregory Neil Shapiro { 120006f25ae9SGregory Neil Shapiro syserr("X%s: `=' expected", m->mf_name); 120106f25ae9SGregory Neil Shapiro return; 120206f25ae9SGregory Neil Shapiro } 120306f25ae9SGregory Neil Shapiro while (isascii(*p) && isspace(*p)) 120406f25ae9SGregory Neil Shapiro p++; 120506f25ae9SGregory Neil Shapiro 120606f25ae9SGregory Neil Shapiro /* p now points to the field body */ 120706f25ae9SGregory Neil Shapiro p = munchstring(p, &delimptr, ','); 120806f25ae9SGregory Neil Shapiro 120942e5d165SGregory Neil Shapiro /* install the field into the filter struct */ 121006f25ae9SGregory Neil Shapiro switch (fcode) 121106f25ae9SGregory Neil Shapiro { 121206f25ae9SGregory Neil Shapiro case 'S': /* socket */ 121306f25ae9SGregory Neil Shapiro if (p == NULL) 121406f25ae9SGregory Neil Shapiro m->mf_conn = NULL; 121506f25ae9SGregory Neil Shapiro else 121606f25ae9SGregory Neil Shapiro m->mf_conn = newstr(p); 121706f25ae9SGregory Neil Shapiro break; 121806f25ae9SGregory Neil Shapiro 121906f25ae9SGregory Neil Shapiro case 'F': /* Milter flags configured on MTA */ 122006f25ae9SGregory Neil Shapiro for (; *p != '\0'; p++) 122106f25ae9SGregory Neil Shapiro { 122206f25ae9SGregory Neil Shapiro if (!(isascii(*p) && isspace(*p))) 1223193538b7SGregory Neil Shapiro setbitn(bitidx(*p), m->mf_flags); 122406f25ae9SGregory Neil Shapiro } 122506f25ae9SGregory Neil Shapiro break; 122606f25ae9SGregory Neil Shapiro 122706f25ae9SGregory Neil Shapiro case 'T': /* timeouts */ 122806f25ae9SGregory Neil Shapiro milter_parse_timeouts(p, m); 122906f25ae9SGregory Neil Shapiro break; 123006f25ae9SGregory Neil Shapiro 123106f25ae9SGregory Neil Shapiro default: 123206f25ae9SGregory Neil Shapiro syserr("X%s: unknown filter equate %c=", 123306f25ae9SGregory Neil Shapiro m->mf_name, fcode); 123406f25ae9SGregory Neil Shapiro break; 123506f25ae9SGregory Neil Shapiro } 123606f25ae9SGregory Neil Shapiro p = delimptr; 123706f25ae9SGregory Neil Shapiro } 123806f25ae9SGregory Neil Shapiro 123906f25ae9SGregory Neil Shapiro /* early check for errors */ 124040266059SGregory Neil Shapiro (void) milter_open(m, true, CurEnv); 124106f25ae9SGregory Neil Shapiro 124242e5d165SGregory Neil Shapiro /* enter the filter into the symbol table */ 124306f25ae9SGregory Neil Shapiro s = stab(m->mf_name, ST_MILTER, ST_ENTER); 124406f25ae9SGregory Neil Shapiro if (s->s_milter != NULL) 124506f25ae9SGregory Neil Shapiro syserr("X%s: duplicate filter definition", m->mf_name); 124606f25ae9SGregory Neil Shapiro else 124706f25ae9SGregory Neil Shapiro s->s_milter = m; 124806f25ae9SGregory Neil Shapiro } 124940266059SGregory Neil Shapiro /* 125040266059SGregory Neil Shapiro ** MILTER_CONFIG -- parse option list into an array and check config 125106f25ae9SGregory Neil Shapiro ** 125206f25ae9SGregory Neil Shapiro ** Called when reading configuration file. 125306f25ae9SGregory Neil Shapiro ** 125406f25ae9SGregory Neil Shapiro ** Parameters: 125506f25ae9SGregory Neil Shapiro ** spec -- the filter list. 125606f25ae9SGregory Neil Shapiro ** list -- the array to fill in. 125706f25ae9SGregory Neil Shapiro ** max -- the maximum number of entries in list. 125806f25ae9SGregory Neil Shapiro ** 125906f25ae9SGregory Neil Shapiro ** Returns: 126006f25ae9SGregory Neil Shapiro ** none 126106f25ae9SGregory Neil Shapiro */ 126206f25ae9SGregory Neil Shapiro 126306f25ae9SGregory Neil Shapiro void 126440266059SGregory Neil Shapiro milter_config(spec, list, max) 126506f25ae9SGregory Neil Shapiro char *spec; 126606f25ae9SGregory Neil Shapiro struct milter **list; 126706f25ae9SGregory Neil Shapiro int max; 126806f25ae9SGregory Neil Shapiro { 126906f25ae9SGregory Neil Shapiro int numitems = 0; 127006f25ae9SGregory Neil Shapiro register char *p; 127106f25ae9SGregory Neil Shapiro 127206f25ae9SGregory Neil Shapiro /* leave one for the NULL signifying the end of the list */ 127306f25ae9SGregory Neil Shapiro max--; 127406f25ae9SGregory Neil Shapiro 127506f25ae9SGregory Neil Shapiro for (p = spec; p != NULL; ) 127606f25ae9SGregory Neil Shapiro { 127706f25ae9SGregory Neil Shapiro STAB *s; 127806f25ae9SGregory Neil Shapiro 127906f25ae9SGregory Neil Shapiro while (isascii(*p) && isspace(*p)) 128006f25ae9SGregory Neil Shapiro p++; 128106f25ae9SGregory Neil Shapiro if (*p == '\0') 128206f25ae9SGregory Neil Shapiro break; 128306f25ae9SGregory Neil Shapiro spec = p; 128406f25ae9SGregory Neil Shapiro 128506f25ae9SGregory Neil Shapiro if (numitems >= max) 128606f25ae9SGregory Neil Shapiro { 128706f25ae9SGregory Neil Shapiro syserr("Too many filters defined, %d max", max); 128806f25ae9SGregory Neil Shapiro if (max > 0) 128906f25ae9SGregory Neil Shapiro list[0] = NULL; 129006f25ae9SGregory Neil Shapiro return; 129106f25ae9SGregory Neil Shapiro } 129240266059SGregory Neil Shapiro p = strpbrk(p, ";,"); 129306f25ae9SGregory Neil Shapiro if (p != NULL) 129406f25ae9SGregory Neil Shapiro *p++ = '\0'; 129506f25ae9SGregory Neil Shapiro 129606f25ae9SGregory Neil Shapiro s = stab(spec, ST_MILTER, ST_FIND); 129706f25ae9SGregory Neil Shapiro if (s == NULL) 129806f25ae9SGregory Neil Shapiro { 129906f25ae9SGregory Neil Shapiro syserr("InputFilter %s not defined", spec); 130006f25ae9SGregory Neil Shapiro ExitStat = EX_CONFIG; 130106f25ae9SGregory Neil Shapiro return; 130206f25ae9SGregory Neil Shapiro } 130306f25ae9SGregory Neil Shapiro list[numitems++] = s->s_milter; 130406f25ae9SGregory Neil Shapiro } 130506f25ae9SGregory Neil Shapiro list[numitems] = NULL; 130640266059SGregory Neil Shapiro 130740266059SGregory Neil Shapiro /* if not set, set to LogLevel */ 130840266059SGregory Neil Shapiro if (MilterLogLevel == -1) 130940266059SGregory Neil Shapiro MilterLogLevel = LogLevel; 131006f25ae9SGregory Neil Shapiro } 131140266059SGregory Neil Shapiro /* 131206f25ae9SGregory Neil Shapiro ** MILTER_PARSE_TIMEOUTS -- parse timeout list 131306f25ae9SGregory Neil Shapiro ** 131406f25ae9SGregory Neil Shapiro ** Called when reading configuration file. 131506f25ae9SGregory Neil Shapiro ** 131606f25ae9SGregory Neil Shapiro ** Parameters: 131706f25ae9SGregory Neil Shapiro ** spec -- the timeout list. 131806f25ae9SGregory Neil Shapiro ** m -- milter to set. 131906f25ae9SGregory Neil Shapiro ** 132006f25ae9SGregory Neil Shapiro ** Returns: 132106f25ae9SGregory Neil Shapiro ** none 132206f25ae9SGregory Neil Shapiro */ 132306f25ae9SGregory Neil Shapiro 132406f25ae9SGregory Neil Shapiro static void 132506f25ae9SGregory Neil Shapiro milter_parse_timeouts(spec, m) 132606f25ae9SGregory Neil Shapiro char *spec; 132706f25ae9SGregory Neil Shapiro struct milter *m; 132806f25ae9SGregory Neil Shapiro { 132906f25ae9SGregory Neil Shapiro char fcode; 1330e92d3f3fSGregory Neil Shapiro int tcode; 133106f25ae9SGregory Neil Shapiro register char *p; 133206f25ae9SGregory Neil Shapiro 133306f25ae9SGregory Neil Shapiro p = spec; 133406f25ae9SGregory Neil Shapiro 133506f25ae9SGregory Neil Shapiro /* now scan through and assign info from the fields */ 133606f25ae9SGregory Neil Shapiro while (*p != '\0') 133706f25ae9SGregory Neil Shapiro { 133806f25ae9SGregory Neil Shapiro char *delimptr; 133906f25ae9SGregory Neil Shapiro 134006f25ae9SGregory Neil Shapiro while (*p != '\0' && 134106f25ae9SGregory Neil Shapiro (*p == ';' || (isascii(*p) && isspace(*p)))) 134206f25ae9SGregory Neil Shapiro p++; 134306f25ae9SGregory Neil Shapiro 134406f25ae9SGregory Neil Shapiro /* p now points to field code */ 134506f25ae9SGregory Neil Shapiro fcode = *p; 134606f25ae9SGregory Neil Shapiro while (*p != '\0' && *p != ':') 134706f25ae9SGregory Neil Shapiro p++; 134806f25ae9SGregory Neil Shapiro if (*p++ != ':') 134906f25ae9SGregory Neil Shapiro { 135006f25ae9SGregory Neil Shapiro syserr("X%s, T=: `:' expected", m->mf_name); 135106f25ae9SGregory Neil Shapiro return; 135206f25ae9SGregory Neil Shapiro } 135306f25ae9SGregory Neil Shapiro while (isascii(*p) && isspace(*p)) 135406f25ae9SGregory Neil Shapiro p++; 135506f25ae9SGregory Neil Shapiro 135606f25ae9SGregory Neil Shapiro /* p now points to the field body */ 135706f25ae9SGregory Neil Shapiro p = munchstring(p, &delimptr, ';'); 1358e92d3f3fSGregory Neil Shapiro tcode = -1; 135906f25ae9SGregory Neil Shapiro 136042e5d165SGregory Neil Shapiro /* install the field into the filter struct */ 136106f25ae9SGregory Neil Shapiro switch (fcode) 136206f25ae9SGregory Neil Shapiro { 1363c86d5965SGregory Neil Shapiro case 'C': 1364e92d3f3fSGregory Neil Shapiro tcode = SMFTO_CONNECT; 1365c86d5965SGregory Neil Shapiro break; 1366c86d5965SGregory Neil Shapiro 136706f25ae9SGregory Neil Shapiro case 'S': 1368e92d3f3fSGregory Neil Shapiro tcode = SMFTO_WRITE; 136906f25ae9SGregory Neil Shapiro break; 137006f25ae9SGregory Neil Shapiro 137106f25ae9SGregory Neil Shapiro case 'R': 1372e92d3f3fSGregory Neil Shapiro tcode = SMFTO_READ; 137306f25ae9SGregory Neil Shapiro break; 137406f25ae9SGregory Neil Shapiro 137506f25ae9SGregory Neil Shapiro case 'E': 1376e92d3f3fSGregory Neil Shapiro tcode = SMFTO_EOM; 137706f25ae9SGregory Neil Shapiro break; 137806f25ae9SGregory Neil Shapiro 137906f25ae9SGregory Neil Shapiro default: 138006f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 138140266059SGregory Neil Shapiro sm_dprintf("X%s: %c unknown\n", 138206f25ae9SGregory Neil Shapiro m->mf_name, fcode); 138306f25ae9SGregory Neil Shapiro syserr("X%s: unknown filter timeout %c", 138406f25ae9SGregory Neil Shapiro m->mf_name, fcode); 138506f25ae9SGregory Neil Shapiro break; 138606f25ae9SGregory Neil Shapiro } 1387e92d3f3fSGregory Neil Shapiro if (tcode >= 0) 1388e92d3f3fSGregory Neil Shapiro { 1389e92d3f3fSGregory Neil Shapiro m->mf_timeout[tcode] = convtime(p, 's'); 1390e92d3f3fSGregory Neil Shapiro if (tTd(64, 5)) 1391e92d3f3fSGregory Neil Shapiro sm_dprintf("X%s: %c=%ld\n", 1392e92d3f3fSGregory Neil Shapiro m->mf_name, fcode, 1393e92d3f3fSGregory Neil Shapiro (u_long) m->mf_timeout[tcode]); 1394e92d3f3fSGregory Neil Shapiro } 139506f25ae9SGregory Neil Shapiro p = delimptr; 139606f25ae9SGregory Neil Shapiro } 139706f25ae9SGregory Neil Shapiro } 139840266059SGregory Neil Shapiro /* 139906f25ae9SGregory Neil Shapiro ** MILTER_SET_OPTION -- set an individual milter option 140006f25ae9SGregory Neil Shapiro ** 140106f25ae9SGregory Neil Shapiro ** Parameters: 140206f25ae9SGregory Neil Shapiro ** name -- the name of the option. 140306f25ae9SGregory Neil Shapiro ** val -- the value of the option. 140406f25ae9SGregory Neil Shapiro ** sticky -- if set, don't let other setoptions override 140506f25ae9SGregory Neil Shapiro ** this value. 140606f25ae9SGregory Neil Shapiro ** 140706f25ae9SGregory Neil Shapiro ** Returns: 140806f25ae9SGregory Neil Shapiro ** none. 140906f25ae9SGregory Neil Shapiro */ 141006f25ae9SGregory Neil Shapiro 141106f25ae9SGregory Neil Shapiro /* set if Milter sub-option is stuck */ 141206f25ae9SGregory Neil Shapiro static BITMAP256 StickyMilterOpt; 141306f25ae9SGregory Neil Shapiro 141406f25ae9SGregory Neil Shapiro static struct milteropt 141506f25ae9SGregory Neil Shapiro { 141606f25ae9SGregory Neil Shapiro char *mo_name; /* long name of milter option */ 141740266059SGregory Neil Shapiro unsigned char mo_code; /* code for option */ 141806f25ae9SGregory Neil Shapiro } MilterOptTab[] = 141906f25ae9SGregory Neil Shapiro { 142006f25ae9SGregory Neil Shapiro # define MO_MACROS_CONNECT 0x01 142106f25ae9SGregory Neil Shapiro { "macros.connect", MO_MACROS_CONNECT }, 142206f25ae9SGregory Neil Shapiro # define MO_MACROS_HELO 0x02 142306f25ae9SGregory Neil Shapiro { "macros.helo", MO_MACROS_HELO }, 142406f25ae9SGregory Neil Shapiro # define MO_MACROS_ENVFROM 0x03 142506f25ae9SGregory Neil Shapiro { "macros.envfrom", MO_MACROS_ENVFROM }, 142606f25ae9SGregory Neil Shapiro # define MO_MACROS_ENVRCPT 0x04 142706f25ae9SGregory Neil Shapiro { "macros.envrcpt", MO_MACROS_ENVRCPT }, 1428e92d3f3fSGregory Neil Shapiro # define MO_MACROS_DATA 0x05 1429e92d3f3fSGregory Neil Shapiro { "macros.data", MO_MACROS_DATA }, 1430323f6dcbSGregory Neil Shapiro # define MO_MACROS_EOM 0x06 1431323f6dcbSGregory Neil Shapiro { "macros.eom", MO_MACROS_EOM }, 1432e92d3f3fSGregory Neil Shapiro # define MO_LOGLEVEL 0x07 1433e92d3f3fSGregory Neil Shapiro { "loglevel", MO_LOGLEVEL }, 1434e92d3f3fSGregory Neil Shapiro # if _FFR_MAXDATASIZE 1435e92d3f3fSGregory Neil Shapiro # define MO_MAXDATASIZE 0x08 1436e92d3f3fSGregory Neil Shapiro { "maxdatasize", MO_MAXDATASIZE }, 1437e92d3f3fSGregory Neil Shapiro # endif /* _FFR_MAXDATASIZE */ 143806f25ae9SGregory Neil Shapiro { NULL, 0 }, 143906f25ae9SGregory Neil Shapiro }; 144006f25ae9SGregory Neil Shapiro 144106f25ae9SGregory Neil Shapiro void 144206f25ae9SGregory Neil Shapiro milter_set_option(name, val, sticky) 144306f25ae9SGregory Neil Shapiro char *name; 144406f25ae9SGregory Neil Shapiro char *val; 144506f25ae9SGregory Neil Shapiro bool sticky; 144606f25ae9SGregory Neil Shapiro { 144706f25ae9SGregory Neil Shapiro int nummac = 0; 144806f25ae9SGregory Neil Shapiro register struct milteropt *mo; 144906f25ae9SGregory Neil Shapiro char *p; 145006f25ae9SGregory Neil Shapiro char **macros = NULL; 145106f25ae9SGregory Neil Shapiro 145206f25ae9SGregory Neil Shapiro if (tTd(37, 2) || tTd(64, 5)) 145340266059SGregory Neil Shapiro sm_dprintf("milter_set_option(%s = %s)", name, val); 145406f25ae9SGregory Neil Shapiro 1455739ac4d4SGregory Neil Shapiro if (name == NULL) 1456739ac4d4SGregory Neil Shapiro { 1457739ac4d4SGregory Neil Shapiro syserr("milter_set_option: invalid Milter option, must specify suboption"); 1458739ac4d4SGregory Neil Shapiro return; 1459739ac4d4SGregory Neil Shapiro } 1460739ac4d4SGregory Neil Shapiro 146106f25ae9SGregory Neil Shapiro for (mo = MilterOptTab; mo->mo_name != NULL; mo++) 146206f25ae9SGregory Neil Shapiro { 146340266059SGregory Neil Shapiro if (sm_strcasecmp(mo->mo_name, name) == 0) 146406f25ae9SGregory Neil Shapiro break; 146506f25ae9SGregory Neil Shapiro } 146606f25ae9SGregory Neil Shapiro 146706f25ae9SGregory Neil Shapiro if (mo->mo_name == NULL) 146840266059SGregory Neil Shapiro { 146906f25ae9SGregory Neil Shapiro syserr("milter_set_option: invalid Milter option %s", name); 147040266059SGregory Neil Shapiro return; 147140266059SGregory Neil Shapiro } 147206f25ae9SGregory Neil Shapiro 147306f25ae9SGregory Neil Shapiro /* 147406f25ae9SGregory Neil Shapiro ** See if this option is preset for us. 147506f25ae9SGregory Neil Shapiro */ 147606f25ae9SGregory Neil Shapiro 147706f25ae9SGregory Neil Shapiro if (!sticky && bitnset(mo->mo_code, StickyMilterOpt)) 147806f25ae9SGregory Neil Shapiro { 147906f25ae9SGregory Neil Shapiro if (tTd(37, 2) || tTd(64,5)) 148040266059SGregory Neil Shapiro sm_dprintf(" (ignored)\n"); 148106f25ae9SGregory Neil Shapiro return; 148206f25ae9SGregory Neil Shapiro } 148306f25ae9SGregory Neil Shapiro 148406f25ae9SGregory Neil Shapiro if (tTd(37, 2) || tTd(64,5)) 148540266059SGregory Neil Shapiro sm_dprintf("\n"); 148606f25ae9SGregory Neil Shapiro 148706f25ae9SGregory Neil Shapiro switch (mo->mo_code) 148806f25ae9SGregory Neil Shapiro { 148940266059SGregory Neil Shapiro case MO_LOGLEVEL: 149040266059SGregory Neil Shapiro MilterLogLevel = atoi(val); 149140266059SGregory Neil Shapiro break; 149240266059SGregory Neil Shapiro 1493e92d3f3fSGregory Neil Shapiro #if _FFR_MAXDATASIZE 1494e92d3f3fSGregory Neil Shapiro case MO_MAXDATASIZE: 1495e92d3f3fSGregory Neil Shapiro MilterMaxDataSize = (size_t)atol(val); 1496e92d3f3fSGregory Neil Shapiro break; 1497e92d3f3fSGregory Neil Shapiro #endif /* _FFR_MAXDATASIZE */ 1498e92d3f3fSGregory Neil Shapiro 149906f25ae9SGregory Neil Shapiro case MO_MACROS_CONNECT: 150006f25ae9SGregory Neil Shapiro if (macros == NULL) 150106f25ae9SGregory Neil Shapiro macros = MilterConnectMacros; 150206f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 150306f25ae9SGregory Neil Shapiro 150406f25ae9SGregory Neil Shapiro case MO_MACROS_HELO: 150506f25ae9SGregory Neil Shapiro if (macros == NULL) 150606f25ae9SGregory Neil Shapiro macros = MilterHeloMacros; 150706f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 150806f25ae9SGregory Neil Shapiro 150906f25ae9SGregory Neil Shapiro case MO_MACROS_ENVFROM: 151006f25ae9SGregory Neil Shapiro if (macros == NULL) 151106f25ae9SGregory Neil Shapiro macros = MilterEnvFromMacros; 151206f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 151306f25ae9SGregory Neil Shapiro 151406f25ae9SGregory Neil Shapiro case MO_MACROS_ENVRCPT: 151506f25ae9SGregory Neil Shapiro if (macros == NULL) 151606f25ae9SGregory Neil Shapiro macros = MilterEnvRcptMacros; 1517323f6dcbSGregory Neil Shapiro /* FALLTHROUGH */ 1518323f6dcbSGregory Neil Shapiro 1519323f6dcbSGregory Neil Shapiro case MO_MACROS_EOM: 1520323f6dcbSGregory Neil Shapiro if (macros == NULL) 1521323f6dcbSGregory Neil Shapiro macros = MilterEOMMacros; 1522e92d3f3fSGregory Neil Shapiro /* FALLTHROUGH */ 1523e92d3f3fSGregory Neil Shapiro 1524e92d3f3fSGregory Neil Shapiro case MO_MACROS_DATA: 1525e92d3f3fSGregory Neil Shapiro if (macros == NULL) 1526e92d3f3fSGregory Neil Shapiro macros = MilterDataMacros; 152706f25ae9SGregory Neil Shapiro 152806f25ae9SGregory Neil Shapiro p = newstr(val); 152906f25ae9SGregory Neil Shapiro while (*p != '\0') 153006f25ae9SGregory Neil Shapiro { 153106f25ae9SGregory Neil Shapiro char *macro; 153206f25ae9SGregory Neil Shapiro 153306f25ae9SGregory Neil Shapiro /* Skip leading commas, spaces */ 153406f25ae9SGregory Neil Shapiro while (*p != '\0' && 153506f25ae9SGregory Neil Shapiro (*p == ',' || (isascii(*p) && isspace(*p)))) 153606f25ae9SGregory Neil Shapiro p++; 153706f25ae9SGregory Neil Shapiro 153806f25ae9SGregory Neil Shapiro if (*p == '\0') 153906f25ae9SGregory Neil Shapiro break; 154006f25ae9SGregory Neil Shapiro 154106f25ae9SGregory Neil Shapiro /* Find end of macro */ 154206f25ae9SGregory Neil Shapiro macro = p; 154306f25ae9SGregory Neil Shapiro while (*p != '\0' && *p != ',' && 154406f25ae9SGregory Neil Shapiro isascii(*p) && !isspace(*p)) 154506f25ae9SGregory Neil Shapiro p++; 154606f25ae9SGregory Neil Shapiro if (*p != '\0') 154706f25ae9SGregory Neil Shapiro *p++ = '\0'; 154806f25ae9SGregory Neil Shapiro 154906f25ae9SGregory Neil Shapiro if (nummac >= MAXFILTERMACROS) 155006f25ae9SGregory Neil Shapiro { 155106f25ae9SGregory Neil Shapiro syserr("milter_set_option: too many macros in Milter.%s (max %d)", 155206f25ae9SGregory Neil Shapiro name, MAXFILTERMACROS); 155306f25ae9SGregory Neil Shapiro macros[nummac] = NULL; 155406f25ae9SGregory Neil Shapiro break; 155506f25ae9SGregory Neil Shapiro } 155606f25ae9SGregory Neil Shapiro macros[nummac++] = macro; 155706f25ae9SGregory Neil Shapiro } 155806f25ae9SGregory Neil Shapiro macros[nummac] = NULL; 155906f25ae9SGregory Neil Shapiro break; 156006f25ae9SGregory Neil Shapiro 156106f25ae9SGregory Neil Shapiro default: 156206f25ae9SGregory Neil Shapiro syserr("milter_set_option: invalid Milter option %s", name); 156306f25ae9SGregory Neil Shapiro break; 156406f25ae9SGregory Neil Shapiro } 156506f25ae9SGregory Neil Shapiro if (sticky) 156606f25ae9SGregory Neil Shapiro setbitn(mo->mo_code, StickyMilterOpt); 156706f25ae9SGregory Neil Shapiro } 156840266059SGregory Neil Shapiro /* 156940266059SGregory Neil Shapiro ** MILTER_REOPEN_DF -- open & truncate the data file (for replbody) 157006f25ae9SGregory Neil Shapiro ** 157106f25ae9SGregory Neil Shapiro ** Parameters: 157206f25ae9SGregory Neil Shapiro ** e -- current envelope. 157306f25ae9SGregory Neil Shapiro ** 157406f25ae9SGregory Neil Shapiro ** Returns: 157506f25ae9SGregory Neil Shapiro ** 0 if succesful, -1 otherwise 157606f25ae9SGregory Neil Shapiro */ 157706f25ae9SGregory Neil Shapiro 157806f25ae9SGregory Neil Shapiro static int 157906f25ae9SGregory Neil Shapiro milter_reopen_df(e) 158006f25ae9SGregory Neil Shapiro ENVELOPE *e; 158106f25ae9SGregory Neil Shapiro { 158206f25ae9SGregory Neil Shapiro char dfname[MAXPATHLEN]; 158306f25ae9SGregory Neil Shapiro 158440266059SGregory Neil Shapiro (void) sm_strlcpy(dfname, queuename(e, DATAFL_LETTER), sizeof dfname); 158506f25ae9SGregory Neil Shapiro 158606f25ae9SGregory Neil Shapiro /* 158740266059SGregory Neil Shapiro ** In SuperSafe == SAFE_REALLY mode, e->e_dfp is a read-only FP so 158806f25ae9SGregory Neil Shapiro ** close and reopen writable (later close and reopen 158906f25ae9SGregory Neil Shapiro ** read only again). 159006f25ae9SGregory Neil Shapiro ** 159140266059SGregory Neil Shapiro ** In SuperSafe != SAFE_REALLY mode, e->e_dfp still points at the 1592e92d3f3fSGregory Neil Shapiro ** buffered file I/O descriptor, still open for writing so there 1593e92d3f3fSGregory Neil Shapiro ** isn't any work to do here (except checking for consistency). 159406f25ae9SGregory Neil Shapiro */ 159506f25ae9SGregory Neil Shapiro 159640266059SGregory Neil Shapiro if (SuperSafe == SAFE_REALLY) 159706f25ae9SGregory Neil Shapiro { 159840266059SGregory Neil Shapiro /* close read-only data file */ 159906f25ae9SGregory Neil Shapiro if (bitset(EF_HAS_DF, e->e_flags) && e->e_dfp != NULL) 160006f25ae9SGregory Neil Shapiro { 160140266059SGregory Neil Shapiro (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT); 160206f25ae9SGregory Neil Shapiro e->e_flags &= ~EF_HAS_DF; 160306f25ae9SGregory Neil Shapiro } 160406f25ae9SGregory Neil Shapiro 160506f25ae9SGregory Neil Shapiro /* open writable */ 160640266059SGregory Neil Shapiro if ((e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname, 1607a7ec597cSGregory Neil Shapiro SM_IO_RDWR_B, NULL)) == NULL) 160806f25ae9SGregory Neil Shapiro { 160940266059SGregory Neil Shapiro MILTER_DF_ERROR("milter_reopen_df: sm_io_open %s: %s"); 161006f25ae9SGregory Neil Shapiro return -1; 161106f25ae9SGregory Neil Shapiro } 161206f25ae9SGregory Neil Shapiro } 161306f25ae9SGregory Neil Shapiro else if (e->e_dfp == NULL) 161406f25ae9SGregory Neil Shapiro { 161506f25ae9SGregory Neil Shapiro /* shouldn't happen */ 161606f25ae9SGregory Neil Shapiro errno = ENOENT; 161706f25ae9SGregory Neil Shapiro MILTER_DF_ERROR("milter_reopen_df: NULL e_dfp (%s: %s)"); 161806f25ae9SGregory Neil Shapiro return -1; 161906f25ae9SGregory Neil Shapiro } 162006f25ae9SGregory Neil Shapiro return 0; 162106f25ae9SGregory Neil Shapiro } 162240266059SGregory Neil Shapiro /* 162340266059SGregory Neil Shapiro ** MILTER_RESET_DF -- re-open read-only the data file (for replbody) 162406f25ae9SGregory Neil Shapiro ** 162506f25ae9SGregory Neil Shapiro ** Parameters: 162606f25ae9SGregory Neil Shapiro ** e -- current envelope. 162706f25ae9SGregory Neil Shapiro ** 162806f25ae9SGregory Neil Shapiro ** Returns: 162906f25ae9SGregory Neil Shapiro ** 0 if succesful, -1 otherwise 163006f25ae9SGregory Neil Shapiro */ 163106f25ae9SGregory Neil Shapiro 163206f25ae9SGregory Neil Shapiro static int 163306f25ae9SGregory Neil Shapiro milter_reset_df(e) 163406f25ae9SGregory Neil Shapiro ENVELOPE *e; 163506f25ae9SGregory Neil Shapiro { 163606f25ae9SGregory Neil Shapiro int afd; 163706f25ae9SGregory Neil Shapiro char dfname[MAXPATHLEN]; 163806f25ae9SGregory Neil Shapiro 163940266059SGregory Neil Shapiro (void) sm_strlcpy(dfname, queuename(e, DATAFL_LETTER), sizeof dfname); 164006f25ae9SGregory Neil Shapiro 164140266059SGregory Neil Shapiro if (sm_io_flush(e->e_dfp, SM_TIME_DEFAULT) != 0 || 164240266059SGregory Neil Shapiro sm_io_error(e->e_dfp)) 164306f25ae9SGregory Neil Shapiro { 164406f25ae9SGregory Neil Shapiro MILTER_DF_ERROR("milter_reset_df: error writing/flushing %s: %s"); 164506f25ae9SGregory Neil Shapiro return -1; 164606f25ae9SGregory Neil Shapiro } 164740266059SGregory Neil Shapiro else if (SuperSafe != SAFE_REALLY) 164806f25ae9SGregory Neil Shapiro { 164906f25ae9SGregory Neil Shapiro /* skip next few clauses */ 165006f25ae9SGregory Neil Shapiro /* EMPTY */ 165106f25ae9SGregory Neil Shapiro } 165240266059SGregory Neil Shapiro else if ((afd = sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, NULL)) >= 0 165340266059SGregory Neil Shapiro && fsync(afd) < 0) 165406f25ae9SGregory Neil Shapiro { 165506f25ae9SGregory Neil Shapiro MILTER_DF_ERROR("milter_reset_df: error sync'ing %s: %s"); 165606f25ae9SGregory Neil Shapiro return -1; 165706f25ae9SGregory Neil Shapiro } 165840266059SGregory Neil Shapiro else if (sm_io_close(e->e_dfp, SM_TIME_DEFAULT) < 0) 165906f25ae9SGregory Neil Shapiro { 166006f25ae9SGregory Neil Shapiro MILTER_DF_ERROR("milter_reset_df: error closing %s: %s"); 166106f25ae9SGregory Neil Shapiro return -1; 166206f25ae9SGregory Neil Shapiro } 166340266059SGregory Neil Shapiro else if ((e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname, 1664a7ec597cSGregory Neil Shapiro SM_IO_RDONLY_B, NULL)) == NULL) 166506f25ae9SGregory Neil Shapiro { 166606f25ae9SGregory Neil Shapiro MILTER_DF_ERROR("milter_reset_df: error reopening %s: %s"); 166706f25ae9SGregory Neil Shapiro return -1; 166806f25ae9SGregory Neil Shapiro } 166906f25ae9SGregory Neil Shapiro else 167006f25ae9SGregory Neil Shapiro e->e_flags |= EF_HAS_DF; 167106f25ae9SGregory Neil Shapiro return 0; 167206f25ae9SGregory Neil Shapiro } 167340266059SGregory Neil Shapiro /* 167406f25ae9SGregory Neil Shapiro ** MILTER_CAN_DELRCPTS -- can any milter filters delete recipients? 167506f25ae9SGregory Neil Shapiro ** 167606f25ae9SGregory Neil Shapiro ** Parameters: 167706f25ae9SGregory Neil Shapiro ** none 167806f25ae9SGregory Neil Shapiro ** 167906f25ae9SGregory Neil Shapiro ** Returns: 168040266059SGregory Neil Shapiro ** true if any filter deletes recipients, false otherwise 168106f25ae9SGregory Neil Shapiro */ 168206f25ae9SGregory Neil Shapiro 168306f25ae9SGregory Neil Shapiro bool 168406f25ae9SGregory Neil Shapiro milter_can_delrcpts() 168506f25ae9SGregory Neil Shapiro { 168640266059SGregory Neil Shapiro bool can = false; 168706f25ae9SGregory Neil Shapiro int i; 168806f25ae9SGregory Neil Shapiro 168906f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 169040266059SGregory Neil Shapiro sm_dprintf("milter_can_delrcpts:"); 169106f25ae9SGregory Neil Shapiro 169206f25ae9SGregory Neil Shapiro for (i = 0; InputFilters[i] != NULL; i++) 169306f25ae9SGregory Neil Shapiro { 169406f25ae9SGregory Neil Shapiro struct milter *m = InputFilters[i]; 169506f25ae9SGregory Neil Shapiro 169606f25ae9SGregory Neil Shapiro if (bitset(SMFIF_DELRCPT, m->mf_fflags)) 169706f25ae9SGregory Neil Shapiro { 169840266059SGregory Neil Shapiro can = true; 169906f25ae9SGregory Neil Shapiro break; 170006f25ae9SGregory Neil Shapiro } 170106f25ae9SGregory Neil Shapiro } 170206f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 170340266059SGregory Neil Shapiro sm_dprintf("%s\n", can ? "true" : "false"); 170406f25ae9SGregory Neil Shapiro 170506f25ae9SGregory Neil Shapiro return can; 170606f25ae9SGregory Neil Shapiro } 170740266059SGregory Neil Shapiro /* 170806f25ae9SGregory Neil Shapiro ** MILTER_QUIT_FILTER -- close down a single filter 170906f25ae9SGregory Neil Shapiro ** 171006f25ae9SGregory Neil Shapiro ** Parameters: 171106f25ae9SGregory Neil Shapiro ** m -- milter structure of filter to close down. 171206f25ae9SGregory Neil Shapiro ** e -- current envelope. 171306f25ae9SGregory Neil Shapiro ** 171406f25ae9SGregory Neil Shapiro ** Returns: 171506f25ae9SGregory Neil Shapiro ** none 171606f25ae9SGregory Neil Shapiro */ 171706f25ae9SGregory Neil Shapiro 171806f25ae9SGregory Neil Shapiro static void 171906f25ae9SGregory Neil Shapiro milter_quit_filter(m, e) 172006f25ae9SGregory Neil Shapiro struct milter *m; 172106f25ae9SGregory Neil Shapiro ENVELOPE *e; 172206f25ae9SGregory Neil Shapiro { 172306f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 172440266059SGregory Neil Shapiro sm_dprintf("milter_quit_filter(%s)\n", m->mf_name); 172540266059SGregory Neil Shapiro if (MilterLogLevel > 18) 172640266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter (%s): quit filter", 172740266059SGregory Neil Shapiro m->mf_name); 172806f25ae9SGregory Neil Shapiro 172906f25ae9SGregory Neil Shapiro /* Never replace error state */ 173006f25ae9SGregory Neil Shapiro if (m->mf_state == SMFS_ERROR) 173106f25ae9SGregory Neil Shapiro return; 173206f25ae9SGregory Neil Shapiro 173306f25ae9SGregory Neil Shapiro if (m->mf_sock < 0 || 173406f25ae9SGregory Neil Shapiro m->mf_state == SMFS_CLOSED || 173506f25ae9SGregory Neil Shapiro m->mf_state == SMFS_READY) 173606f25ae9SGregory Neil Shapiro { 173706f25ae9SGregory Neil Shapiro m->mf_sock = -1; 173806f25ae9SGregory Neil Shapiro m->mf_state = SMFS_CLOSED; 173906f25ae9SGregory Neil Shapiro return; 174006f25ae9SGregory Neil Shapiro } 174106f25ae9SGregory Neil Shapiro 174206f25ae9SGregory Neil Shapiro (void) milter_write(m, SMFIC_QUIT, (char *) NULL, 0, 174306f25ae9SGregory Neil Shapiro m->mf_timeout[SMFTO_WRITE], e); 1744193538b7SGregory Neil Shapiro if (m->mf_sock >= 0) 1745193538b7SGregory Neil Shapiro { 174606f25ae9SGregory Neil Shapiro (void) close(m->mf_sock); 174706f25ae9SGregory Neil Shapiro m->mf_sock = -1; 1748193538b7SGregory Neil Shapiro } 174906f25ae9SGregory Neil Shapiro if (m->mf_state != SMFS_ERROR) 175006f25ae9SGregory Neil Shapiro m->mf_state = SMFS_CLOSED; 175106f25ae9SGregory Neil Shapiro } 175240266059SGregory Neil Shapiro /* 175306f25ae9SGregory Neil Shapiro ** MILTER_ABORT_FILTER -- tell filter to abort current message 175406f25ae9SGregory Neil Shapiro ** 175506f25ae9SGregory Neil Shapiro ** Parameters: 175606f25ae9SGregory Neil Shapiro ** m -- milter structure of filter to abort. 175706f25ae9SGregory Neil Shapiro ** e -- current envelope. 175806f25ae9SGregory Neil Shapiro ** 175906f25ae9SGregory Neil Shapiro ** Returns: 176006f25ae9SGregory Neil Shapiro ** none 176106f25ae9SGregory Neil Shapiro */ 176206f25ae9SGregory Neil Shapiro 176306f25ae9SGregory Neil Shapiro static void 176406f25ae9SGregory Neil Shapiro milter_abort_filter(m, e) 176506f25ae9SGregory Neil Shapiro struct milter *m; 176606f25ae9SGregory Neil Shapiro ENVELOPE *e; 176706f25ae9SGregory Neil Shapiro { 176806f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 176940266059SGregory Neil Shapiro sm_dprintf("milter_abort_filter(%s)\n", m->mf_name); 177040266059SGregory Neil Shapiro if (MilterLogLevel > 10) 177140266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter (%s): abort filter", 177240266059SGregory Neil Shapiro m->mf_name); 177306f25ae9SGregory Neil Shapiro 177406f25ae9SGregory Neil Shapiro if (m->mf_sock < 0 || 177506f25ae9SGregory Neil Shapiro m->mf_state != SMFS_INMSG) 177606f25ae9SGregory Neil Shapiro return; 177706f25ae9SGregory Neil Shapiro 177806f25ae9SGregory Neil Shapiro (void) milter_write(m, SMFIC_ABORT, (char *) NULL, 0, 177906f25ae9SGregory Neil Shapiro m->mf_timeout[SMFTO_WRITE], e); 178006f25ae9SGregory Neil Shapiro if (m->mf_state != SMFS_ERROR) 178106f25ae9SGregory Neil Shapiro m->mf_state = SMFS_DONE; 178206f25ae9SGregory Neil Shapiro } 178340266059SGregory Neil Shapiro /* 178406f25ae9SGregory Neil Shapiro ** MILTER_SEND_MACROS -- provide macros to the filters 178506f25ae9SGregory Neil Shapiro ** 178606f25ae9SGregory Neil Shapiro ** Parameters: 178706f25ae9SGregory Neil Shapiro ** m -- milter to send macros to. 178806f25ae9SGregory Neil Shapiro ** macros -- macros to send for filter smfi_getsymval(). 178906f25ae9SGregory Neil Shapiro ** cmd -- which command the macros are associated with. 179006f25ae9SGregory Neil Shapiro ** e -- current envelope (for macro access). 179106f25ae9SGregory Neil Shapiro ** 179206f25ae9SGregory Neil Shapiro ** Returns: 179306f25ae9SGregory Neil Shapiro ** none 179406f25ae9SGregory Neil Shapiro */ 179506f25ae9SGregory Neil Shapiro 179606f25ae9SGregory Neil Shapiro static void 179706f25ae9SGregory Neil Shapiro milter_send_macros(m, macros, cmd, e) 179806f25ae9SGregory Neil Shapiro struct milter *m; 179906f25ae9SGregory Neil Shapiro char **macros; 180006f25ae9SGregory Neil Shapiro char cmd; 180106f25ae9SGregory Neil Shapiro ENVELOPE *e; 180206f25ae9SGregory Neil Shapiro { 180306f25ae9SGregory Neil Shapiro int i; 180406f25ae9SGregory Neil Shapiro int mid; 180506f25ae9SGregory Neil Shapiro char *v; 180606f25ae9SGregory Neil Shapiro char *buf, *bp; 18076a2f2ff3SGregory Neil Shapiro char exp[MAXLINE]; 180806f25ae9SGregory Neil Shapiro ssize_t s; 180906f25ae9SGregory Neil Shapiro 181006f25ae9SGregory Neil Shapiro /* sanity check */ 181106f25ae9SGregory Neil Shapiro if (macros == NULL || macros[0] == NULL) 181206f25ae9SGregory Neil Shapiro return; 181306f25ae9SGregory Neil Shapiro 181406f25ae9SGregory Neil Shapiro /* put together data */ 181506f25ae9SGregory Neil Shapiro s = 1; /* for the command character */ 181606f25ae9SGregory Neil Shapiro for (i = 0; macros[i] != NULL; i++) 181706f25ae9SGregory Neil Shapiro { 181840266059SGregory Neil Shapiro mid = macid(macros[i]); 1819193538b7SGregory Neil Shapiro if (mid == 0) 182006f25ae9SGregory Neil Shapiro continue; 182106f25ae9SGregory Neil Shapiro v = macvalue(mid, e); 182206f25ae9SGregory Neil Shapiro if (v == NULL) 182306f25ae9SGregory Neil Shapiro continue; 18246a2f2ff3SGregory Neil Shapiro expand(v, exp, sizeof(exp), e); 18256a2f2ff3SGregory Neil Shapiro s += strlen(macros[i]) + 1 + strlen(exp) + 1; 182606f25ae9SGregory Neil Shapiro } 182706f25ae9SGregory Neil Shapiro 182840266059SGregory Neil Shapiro if (s < 0) 182940266059SGregory Neil Shapiro return; 183040266059SGregory Neil Shapiro 183106f25ae9SGregory Neil Shapiro buf = (char *) xalloc(s); 183206f25ae9SGregory Neil Shapiro bp = buf; 183306f25ae9SGregory Neil Shapiro *bp++ = cmd; 183406f25ae9SGregory Neil Shapiro for (i = 0; macros[i] != NULL; i++) 183506f25ae9SGregory Neil Shapiro { 183640266059SGregory Neil Shapiro mid = macid(macros[i]); 1837193538b7SGregory Neil Shapiro if (mid == 0) 183806f25ae9SGregory Neil Shapiro continue; 183906f25ae9SGregory Neil Shapiro v = macvalue(mid, e); 184006f25ae9SGregory Neil Shapiro if (v == NULL) 184106f25ae9SGregory Neil Shapiro continue; 18426a2f2ff3SGregory Neil Shapiro expand(v, exp, sizeof(exp), e); 184306f25ae9SGregory Neil Shapiro 184406f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 184540266059SGregory Neil Shapiro sm_dprintf("milter_send_macros(%s, %c): %s=%s\n", 18466a2f2ff3SGregory Neil Shapiro m->mf_name, cmd, macros[i], exp); 184706f25ae9SGregory Neil Shapiro 184840266059SGregory Neil Shapiro (void) sm_strlcpy(bp, macros[i], s - (bp - buf)); 184906f25ae9SGregory Neil Shapiro bp += strlen(bp) + 1; 18506a2f2ff3SGregory Neil Shapiro (void) sm_strlcpy(bp, exp, s - (bp - buf)); 185106f25ae9SGregory Neil Shapiro bp += strlen(bp) + 1; 185206f25ae9SGregory Neil Shapiro } 185306f25ae9SGregory Neil Shapiro (void) milter_write(m, SMFIC_MACRO, buf, s, 185406f25ae9SGregory Neil Shapiro m->mf_timeout[SMFTO_WRITE], e); 185540266059SGregory Neil Shapiro sm_free(buf); /* XXX */ 185606f25ae9SGregory Neil Shapiro } 185706f25ae9SGregory Neil Shapiro 185840266059SGregory Neil Shapiro /* 185906f25ae9SGregory Neil Shapiro ** MILTER_SEND_COMMAND -- send a command and return the response for a filter 186006f25ae9SGregory Neil Shapiro ** 186106f25ae9SGregory Neil Shapiro ** Parameters: 186206f25ae9SGregory Neil Shapiro ** m -- current milter filter 186306f25ae9SGregory Neil Shapiro ** command -- command to send. 186406f25ae9SGregory Neil Shapiro ** data -- optional command data. 186506f25ae9SGregory Neil Shapiro ** sz -- length of buf. 186606f25ae9SGregory Neil Shapiro ** e -- current envelope (for e->e_id). 186706f25ae9SGregory Neil Shapiro ** state -- return state word. 186806f25ae9SGregory Neil Shapiro ** 186906f25ae9SGregory Neil Shapiro ** Returns: 187006f25ae9SGregory Neil Shapiro ** response string (may be NULL) 187106f25ae9SGregory Neil Shapiro */ 187206f25ae9SGregory Neil Shapiro 187306f25ae9SGregory Neil Shapiro static char * 187406f25ae9SGregory Neil Shapiro milter_send_command(m, command, data, sz, e, state) 187506f25ae9SGregory Neil Shapiro struct milter *m; 187606f25ae9SGregory Neil Shapiro char command; 187706f25ae9SGregory Neil Shapiro void *data; 187806f25ae9SGregory Neil Shapiro ssize_t sz; 187906f25ae9SGregory Neil Shapiro ENVELOPE *e; 188006f25ae9SGregory Neil Shapiro char *state; 188106f25ae9SGregory Neil Shapiro { 188206f25ae9SGregory Neil Shapiro char rcmd; 188306f25ae9SGregory Neil Shapiro ssize_t rlen; 188440266059SGregory Neil Shapiro unsigned long skipflag; 1885e92d3f3fSGregory Neil Shapiro #if _FFR_MILTER_NOHDR_RESP 1886e92d3f3fSGregory Neil Shapiro unsigned long norespflag = 0; 1887e92d3f3fSGregory Neil Shapiro #endif /* _FFR_MILTER_NOHDR_RESP */ 188840266059SGregory Neil Shapiro char *action; 188906f25ae9SGregory Neil Shapiro char *defresponse; 189006f25ae9SGregory Neil Shapiro char *response; 189106f25ae9SGregory Neil Shapiro 189206f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 189340266059SGregory Neil Shapiro sm_dprintf("milter_send_command(%s): cmd %c len %ld\n", 189406f25ae9SGregory Neil Shapiro m->mf_name, (char) command, (long) sz); 189506f25ae9SGregory Neil Shapiro 189606f25ae9SGregory Neil Shapiro /* find skip flag and default failure */ 189706f25ae9SGregory Neil Shapiro switch (command) 189806f25ae9SGregory Neil Shapiro { 189906f25ae9SGregory Neil Shapiro case SMFIC_CONNECT: 190006f25ae9SGregory Neil Shapiro skipflag = SMFIP_NOCONNECT; 190140266059SGregory Neil Shapiro action = "connect"; 190206f25ae9SGregory Neil Shapiro defresponse = "554 Command rejected"; 190306f25ae9SGregory Neil Shapiro break; 190406f25ae9SGregory Neil Shapiro 190506f25ae9SGregory Neil Shapiro case SMFIC_HELO: 190606f25ae9SGregory Neil Shapiro skipflag = SMFIP_NOHELO; 190740266059SGregory Neil Shapiro action = "helo"; 190806f25ae9SGregory Neil Shapiro defresponse = "550 Command rejected"; 190906f25ae9SGregory Neil Shapiro break; 191006f25ae9SGregory Neil Shapiro 191106f25ae9SGregory Neil Shapiro case SMFIC_MAIL: 191206f25ae9SGregory Neil Shapiro skipflag = SMFIP_NOMAIL; 191340266059SGregory Neil Shapiro action = "mail"; 191406f25ae9SGregory Neil Shapiro defresponse = "550 5.7.1 Command rejected"; 191506f25ae9SGregory Neil Shapiro break; 191606f25ae9SGregory Neil Shapiro 191706f25ae9SGregory Neil Shapiro case SMFIC_RCPT: 191806f25ae9SGregory Neil Shapiro skipflag = SMFIP_NORCPT; 191940266059SGregory Neil Shapiro action = "rcpt"; 192006f25ae9SGregory Neil Shapiro defresponse = "550 5.7.1 Command rejected"; 192106f25ae9SGregory Neil Shapiro break; 192206f25ae9SGregory Neil Shapiro 192306f25ae9SGregory Neil Shapiro case SMFIC_HEADER: 192406f25ae9SGregory Neil Shapiro skipflag = SMFIP_NOHDRS; 1925e92d3f3fSGregory Neil Shapiro #if _FFR_MILTER_NOHDR_RESP 1926e92d3f3fSGregory Neil Shapiro norespflag = SMFIP_NOHREPL; 1927e92d3f3fSGregory Neil Shapiro #endif /* _FFR_MILTER_NOHDR_RESP */ 192840266059SGregory Neil Shapiro action = "header"; 192906f25ae9SGregory Neil Shapiro defresponse = "550 5.7.1 Command rejected"; 193006f25ae9SGregory Neil Shapiro break; 193106f25ae9SGregory Neil Shapiro 193206f25ae9SGregory Neil Shapiro case SMFIC_BODY: 193306f25ae9SGregory Neil Shapiro skipflag = SMFIP_NOBODY; 193440266059SGregory Neil Shapiro action = "body"; 193506f25ae9SGregory Neil Shapiro defresponse = "554 5.7.1 Command rejected"; 193606f25ae9SGregory Neil Shapiro break; 193706f25ae9SGregory Neil Shapiro 193806f25ae9SGregory Neil Shapiro case SMFIC_EOH: 193906f25ae9SGregory Neil Shapiro skipflag = SMFIP_NOEOH; 194040266059SGregory Neil Shapiro action = "eoh"; 194106f25ae9SGregory Neil Shapiro defresponse = "550 5.7.1 Command rejected"; 194206f25ae9SGregory Neil Shapiro break; 194306f25ae9SGregory Neil Shapiro 1944e92d3f3fSGregory Neil Shapiro #if SMFI_VERSION > 2 1945e92d3f3fSGregory Neil Shapiro case SMFIC_UNKNOWN: 1946e92d3f3fSGregory Neil Shapiro action = "unknown"; 1947e92d3f3fSGregory Neil Shapiro defresponse = "550 5.7.1 Command rejected"; 1948e92d3f3fSGregory Neil Shapiro break; 1949e92d3f3fSGregory Neil Shapiro #endif /* SMFI_VERSION > 2 */ 1950e92d3f3fSGregory Neil Shapiro 195106f25ae9SGregory Neil Shapiro case SMFIC_BODYEOB: 195206f25ae9SGregory Neil Shapiro case SMFIC_OPTNEG: 195306f25ae9SGregory Neil Shapiro case SMFIC_MACRO: 195406f25ae9SGregory Neil Shapiro case SMFIC_ABORT: 195506f25ae9SGregory Neil Shapiro case SMFIC_QUIT: 195606f25ae9SGregory Neil Shapiro /* NOTE: not handled by milter_send_command() */ 195706f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 195806f25ae9SGregory Neil Shapiro 195906f25ae9SGregory Neil Shapiro default: 196006f25ae9SGregory Neil Shapiro skipflag = 0; 196140266059SGregory Neil Shapiro action = "default"; 196206f25ae9SGregory Neil Shapiro defresponse = "550 5.7.1 Command rejected"; 196306f25ae9SGregory Neil Shapiro break; 196406f25ae9SGregory Neil Shapiro } 196506f25ae9SGregory Neil Shapiro 196606f25ae9SGregory Neil Shapiro /* check if filter wants this command */ 196706f25ae9SGregory Neil Shapiro if (skipflag != 0 && 196806f25ae9SGregory Neil Shapiro bitset(skipflag, m->mf_pflags)) 196906f25ae9SGregory Neil Shapiro return NULL; 197006f25ae9SGregory Neil Shapiro 197140266059SGregory Neil Shapiro /* send the command to the filter */ 197206f25ae9SGregory Neil Shapiro (void) milter_write(m, command, data, sz, 197306f25ae9SGregory Neil Shapiro m->mf_timeout[SMFTO_WRITE], e); 197406f25ae9SGregory Neil Shapiro if (m->mf_state == SMFS_ERROR) 197506f25ae9SGregory Neil Shapiro { 19765ef517c0SGregory Neil Shapiro MILTER_CHECK_ERROR(false, return NULL); 197706f25ae9SGregory Neil Shapiro return NULL; 197806f25ae9SGregory Neil Shapiro } 197906f25ae9SGregory Neil Shapiro 1980e92d3f3fSGregory Neil Shapiro #if _FFR_MILTER_NOHDR_RESP 1981e92d3f3fSGregory Neil Shapiro /* check if filter sends response to this command */ 1982e92d3f3fSGregory Neil Shapiro if (norespflag != 0 && bitset(norespflag, m->mf_pflags)) 1983e92d3f3fSGregory Neil Shapiro return NULL; 1984e92d3f3fSGregory Neil Shapiro #endif /* _FFR_MILTER_NOHDR_RESP */ 1985e92d3f3fSGregory Neil Shapiro 198640266059SGregory Neil Shapiro /* get the response from the filter */ 198706f25ae9SGregory Neil Shapiro response = milter_read(m, &rcmd, &rlen, 198806f25ae9SGregory Neil Shapiro m->mf_timeout[SMFTO_READ], e); 198906f25ae9SGregory Neil Shapiro if (m->mf_state == SMFS_ERROR) 199006f25ae9SGregory Neil Shapiro { 19915ef517c0SGregory Neil Shapiro MILTER_CHECK_ERROR(false, return NULL); 199206f25ae9SGregory Neil Shapiro return NULL; 199306f25ae9SGregory Neil Shapiro } 199406f25ae9SGregory Neil Shapiro 199506f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 199640266059SGregory Neil Shapiro sm_dprintf("milter_send_command(%s): returned %c\n", 199706f25ae9SGregory Neil Shapiro m->mf_name, (char) rcmd); 199806f25ae9SGregory Neil Shapiro 199906f25ae9SGregory Neil Shapiro switch (rcmd) 200006f25ae9SGregory Neil Shapiro { 200106f25ae9SGregory Neil Shapiro case SMFIR_REPLYCODE: 200206f25ae9SGregory Neil Shapiro MILTER_CHECK_REPLYCODE(defresponse); 200340266059SGregory Neil Shapiro if (MilterLogLevel > 10) 200440266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, reject=%s", 200540266059SGregory Neil Shapiro m->mf_name, action, response); 200640266059SGregory Neil Shapiro *state = rcmd; 200740266059SGregory Neil Shapiro break; 200806f25ae9SGregory Neil Shapiro 200906f25ae9SGregory Neil Shapiro case SMFIR_REJECT: 201040266059SGregory Neil Shapiro if (MilterLogLevel > 10) 201140266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, reject", 201240266059SGregory Neil Shapiro m->mf_name, action); 201340266059SGregory Neil Shapiro *state = rcmd; 201440266059SGregory Neil Shapiro break; 201540266059SGregory Neil Shapiro 201606f25ae9SGregory Neil Shapiro case SMFIR_DISCARD: 201740266059SGregory Neil Shapiro if (MilterLogLevel > 10) 201840266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, discard", 201940266059SGregory Neil Shapiro m->mf_name, action); 202040266059SGregory Neil Shapiro *state = rcmd; 202140266059SGregory Neil Shapiro break; 202240266059SGregory Neil Shapiro 202306f25ae9SGregory Neil Shapiro case SMFIR_TEMPFAIL: 202440266059SGregory Neil Shapiro if (MilterLogLevel > 10) 202540266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, tempfail", 202640266059SGregory Neil Shapiro m->mf_name, action); 202706f25ae9SGregory Neil Shapiro *state = rcmd; 202806f25ae9SGregory Neil Shapiro break; 202906f25ae9SGregory Neil Shapiro 203006f25ae9SGregory Neil Shapiro case SMFIR_ACCEPT: 203106f25ae9SGregory Neil Shapiro /* this filter is done with message/connection */ 2032602a2b1bSGregory Neil Shapiro if (command == SMFIC_HELO || 2033602a2b1bSGregory Neil Shapiro command == SMFIC_CONNECT) 2034602a2b1bSGregory Neil Shapiro m->mf_state = SMFS_CLOSABLE; 2035602a2b1bSGregory Neil Shapiro else 203606f25ae9SGregory Neil Shapiro m->mf_state = SMFS_DONE; 203740266059SGregory Neil Shapiro if (MilterLogLevel > 10) 203840266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, accepted", 203940266059SGregory Neil Shapiro m->mf_name, action); 204006f25ae9SGregory Neil Shapiro break; 204106f25ae9SGregory Neil Shapiro 204206f25ae9SGregory Neil Shapiro case SMFIR_CONTINUE: 204306f25ae9SGregory Neil Shapiro /* if MAIL command is ok, filter is in message state */ 204406f25ae9SGregory Neil Shapiro if (command == SMFIC_MAIL) 204506f25ae9SGregory Neil Shapiro m->mf_state = SMFS_INMSG; 204640266059SGregory Neil Shapiro if (MilterLogLevel > 12) 204740266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "milter=%s, action=%s, continue", 204840266059SGregory Neil Shapiro m->mf_name, action); 204906f25ae9SGregory Neil Shapiro break; 205006f25ae9SGregory Neil Shapiro 205106f25ae9SGregory Neil Shapiro default: 205206f25ae9SGregory Neil Shapiro /* Invalid response to command */ 205340266059SGregory Neil Shapiro if (MilterLogLevel > 0) 205406f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 205540266059SGregory Neil Shapiro "milter_send_command(%s): action=%s returned bogus response %c", 205640266059SGregory Neil Shapiro m->mf_name, action, rcmd); 205740266059SGregory Neil Shapiro milter_error(m, e); 205806f25ae9SGregory Neil Shapiro break; 205906f25ae9SGregory Neil Shapiro } 206006f25ae9SGregory Neil Shapiro 206106f25ae9SGregory Neil Shapiro if (*state != SMFIR_REPLYCODE && 206206f25ae9SGregory Neil Shapiro response != NULL) 206306f25ae9SGregory Neil Shapiro { 206440266059SGregory Neil Shapiro sm_free(response); /* XXX */ 206506f25ae9SGregory Neil Shapiro response = NULL; 206606f25ae9SGregory Neil Shapiro } 206706f25ae9SGregory Neil Shapiro return response; 206806f25ae9SGregory Neil Shapiro } 206906f25ae9SGregory Neil Shapiro 207040266059SGregory Neil Shapiro /* 207106f25ae9SGregory Neil Shapiro ** MILTER_COMMAND -- send a command and return the response for each filter 207206f25ae9SGregory Neil Shapiro ** 207306f25ae9SGregory Neil Shapiro ** Parameters: 207406f25ae9SGregory Neil Shapiro ** command -- command to send. 207506f25ae9SGregory Neil Shapiro ** data -- optional command data. 207606f25ae9SGregory Neil Shapiro ** sz -- length of buf. 207706f25ae9SGregory Neil Shapiro ** macros -- macros to send for filter smfi_getsymval(). 207806f25ae9SGregory Neil Shapiro ** e -- current envelope (for macro access). 207906f25ae9SGregory Neil Shapiro ** state -- return state word. 208006f25ae9SGregory Neil Shapiro ** 208106f25ae9SGregory Neil Shapiro ** Returns: 208206f25ae9SGregory Neil Shapiro ** response string (may be NULL) 208306f25ae9SGregory Neil Shapiro */ 208406f25ae9SGregory Neil Shapiro 208506f25ae9SGregory Neil Shapiro static char * 208606f25ae9SGregory Neil Shapiro milter_command(command, data, sz, macros, e, state) 208706f25ae9SGregory Neil Shapiro char command; 208806f25ae9SGregory Neil Shapiro void *data; 208906f25ae9SGregory Neil Shapiro ssize_t sz; 209006f25ae9SGregory Neil Shapiro char **macros; 209106f25ae9SGregory Neil Shapiro ENVELOPE *e; 209206f25ae9SGregory Neil Shapiro char *state; 209306f25ae9SGregory Neil Shapiro { 209406f25ae9SGregory Neil Shapiro int i; 209506f25ae9SGregory Neil Shapiro char *response = NULL; 209640266059SGregory Neil Shapiro time_t tn = 0; 209706f25ae9SGregory Neil Shapiro 209806f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 209940266059SGregory Neil Shapiro sm_dprintf("milter_command: cmd %c len %ld\n", 210006f25ae9SGregory Neil Shapiro (char) command, (long) sz); 210106f25ae9SGregory Neil Shapiro 210206f25ae9SGregory Neil Shapiro *state = SMFIR_CONTINUE; 210306f25ae9SGregory Neil Shapiro for (i = 0; InputFilters[i] != NULL; i++) 210406f25ae9SGregory Neil Shapiro { 210506f25ae9SGregory Neil Shapiro struct milter *m = InputFilters[i]; 210606f25ae9SGregory Neil Shapiro 2107193538b7SGregory Neil Shapiro /* previous problem? */ 2108193538b7SGregory Neil Shapiro if (m->mf_state == SMFS_ERROR) 2109193538b7SGregory Neil Shapiro { 21105ef517c0SGregory Neil Shapiro MILTER_CHECK_ERROR(false, continue); 2111193538b7SGregory Neil Shapiro break; 2112193538b7SGregory Neil Shapiro } 2113193538b7SGregory Neil Shapiro 211406f25ae9SGregory Neil Shapiro /* sanity check */ 211506f25ae9SGregory Neil Shapiro if (m->mf_sock < 0 || 211606f25ae9SGregory Neil Shapiro (m->mf_state != SMFS_OPEN && m->mf_state != SMFS_INMSG)) 211706f25ae9SGregory Neil Shapiro continue; 211806f25ae9SGregory Neil Shapiro 211906f25ae9SGregory Neil Shapiro /* send macros (regardless of whether we send command) */ 212006f25ae9SGregory Neil Shapiro if (macros != NULL && macros[0] != NULL) 212106f25ae9SGregory Neil Shapiro { 212206f25ae9SGregory Neil Shapiro milter_send_macros(m, macros, command, e); 212306f25ae9SGregory Neil Shapiro if (m->mf_state == SMFS_ERROR) 212406f25ae9SGregory Neil Shapiro { 21255ef517c0SGregory Neil Shapiro MILTER_CHECK_ERROR(false, continue); 212606f25ae9SGregory Neil Shapiro break; 212706f25ae9SGregory Neil Shapiro } 212806f25ae9SGregory Neil Shapiro } 212906f25ae9SGregory Neil Shapiro 213040266059SGregory Neil Shapiro if (MilterLogLevel > 21) 213140266059SGregory Neil Shapiro tn = curtime(); 213240266059SGregory Neil Shapiro 213306f25ae9SGregory Neil Shapiro response = milter_send_command(m, command, data, sz, e, state); 213440266059SGregory Neil Shapiro 213540266059SGregory Neil Shapiro if (MilterLogLevel > 21) 213640266059SGregory Neil Shapiro { 213740266059SGregory Neil Shapiro /* log the time it took for the command per filter */ 213840266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, 213940266059SGregory Neil Shapiro "Milter (%s): time command (%c), %d", 214040266059SGregory Neil Shapiro m->mf_name, command, (int) (tn - curtime())); 214140266059SGregory Neil Shapiro } 214240266059SGregory Neil Shapiro 214306f25ae9SGregory Neil Shapiro if (*state != SMFIR_CONTINUE) 214406f25ae9SGregory Neil Shapiro break; 214506f25ae9SGregory Neil Shapiro } 214606f25ae9SGregory Neil Shapiro return response; 214706f25ae9SGregory Neil Shapiro } 214840266059SGregory Neil Shapiro /* 214906f25ae9SGregory Neil Shapiro ** MILTER_NEGOTIATE -- get version and flags from filter 215006f25ae9SGregory Neil Shapiro ** 215106f25ae9SGregory Neil Shapiro ** Parameters: 215206f25ae9SGregory Neil Shapiro ** m -- milter filter structure. 215306f25ae9SGregory Neil Shapiro ** e -- current envelope. 215406f25ae9SGregory Neil Shapiro ** 215506f25ae9SGregory Neil Shapiro ** Returns: 215606f25ae9SGregory Neil Shapiro ** 0 on success, -1 otherwise 215706f25ae9SGregory Neil Shapiro */ 215806f25ae9SGregory Neil Shapiro 215906f25ae9SGregory Neil Shapiro static int 216006f25ae9SGregory Neil Shapiro milter_negotiate(m, e) 216106f25ae9SGregory Neil Shapiro struct milter *m; 216206f25ae9SGregory Neil Shapiro ENVELOPE *e; 216306f25ae9SGregory Neil Shapiro { 216406f25ae9SGregory Neil Shapiro char rcmd; 216506f25ae9SGregory Neil Shapiro mi_int32 fvers; 216606f25ae9SGregory Neil Shapiro mi_int32 fflags; 216706f25ae9SGregory Neil Shapiro mi_int32 pflags; 216806f25ae9SGregory Neil Shapiro char *response; 216906f25ae9SGregory Neil Shapiro ssize_t rlen; 217006f25ae9SGregory Neil Shapiro char data[MILTER_OPTLEN]; 217106f25ae9SGregory Neil Shapiro 217206f25ae9SGregory Neil Shapiro /* sanity check */ 217306f25ae9SGregory Neil Shapiro if (m->mf_sock < 0 || m->mf_state != SMFS_OPEN) 217406f25ae9SGregory Neil Shapiro { 217540266059SGregory Neil Shapiro if (MilterLogLevel > 0) 217606f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 217740266059SGregory Neil Shapiro "Milter (%s): negotiate, impossible state", 217806f25ae9SGregory Neil Shapiro m->mf_name); 217940266059SGregory Neil Shapiro milter_error(m, e); 218006f25ae9SGregory Neil Shapiro return -1; 218106f25ae9SGregory Neil Shapiro } 218206f25ae9SGregory Neil Shapiro 218306f25ae9SGregory Neil Shapiro fvers = htonl(SMFI_VERSION); 218406f25ae9SGregory Neil Shapiro fflags = htonl(SMFI_CURR_ACTS); 218506f25ae9SGregory Neil Shapiro pflags = htonl(SMFI_CURR_PROT); 218606f25ae9SGregory Neil Shapiro (void) memcpy(data, (char *) &fvers, MILTER_LEN_BYTES); 218706f25ae9SGregory Neil Shapiro (void) memcpy(data + MILTER_LEN_BYTES, 218806f25ae9SGregory Neil Shapiro (char *) &fflags, MILTER_LEN_BYTES); 218906f25ae9SGregory Neil Shapiro (void) memcpy(data + (MILTER_LEN_BYTES * 2), 219006f25ae9SGregory Neil Shapiro (char *) &pflags, MILTER_LEN_BYTES); 219106f25ae9SGregory Neil Shapiro (void) milter_write(m, SMFIC_OPTNEG, data, sizeof data, 219206f25ae9SGregory Neil Shapiro m->mf_timeout[SMFTO_WRITE], e); 219306f25ae9SGregory Neil Shapiro 219406f25ae9SGregory Neil Shapiro if (m->mf_state == SMFS_ERROR) 219506f25ae9SGregory Neil Shapiro return -1; 219606f25ae9SGregory Neil Shapiro 219706f25ae9SGregory Neil Shapiro response = milter_read(m, &rcmd, &rlen, m->mf_timeout[SMFTO_READ], e); 219806f25ae9SGregory Neil Shapiro if (m->mf_state == SMFS_ERROR) 219906f25ae9SGregory Neil Shapiro return -1; 220006f25ae9SGregory Neil Shapiro 220106f25ae9SGregory Neil Shapiro if (rcmd != SMFIC_OPTNEG) 220206f25ae9SGregory Neil Shapiro { 220306f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 220440266059SGregory Neil Shapiro sm_dprintf("milter_negotiate(%s): returned %c instead of %c\n", 220506f25ae9SGregory Neil Shapiro m->mf_name, rcmd, SMFIC_OPTNEG); 220640266059SGregory Neil Shapiro if (MilterLogLevel > 0) 220706f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 220840266059SGregory Neil Shapiro "Milter (%s): negotiate: returned %c instead of %c", 220906f25ae9SGregory Neil Shapiro m->mf_name, rcmd, SMFIC_OPTNEG); 221006f25ae9SGregory Neil Shapiro if (response != NULL) 221140266059SGregory Neil Shapiro sm_free(response); /* XXX */ 221240266059SGregory Neil Shapiro milter_error(m, e); 221306f25ae9SGregory Neil Shapiro return -1; 221406f25ae9SGregory Neil Shapiro } 221506f25ae9SGregory Neil Shapiro 221606f25ae9SGregory Neil Shapiro /* Make sure we have enough bytes for the version */ 221706f25ae9SGregory Neil Shapiro if (response == NULL || rlen < MILTER_LEN_BYTES) 221806f25ae9SGregory Neil Shapiro { 221906f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 222040266059SGregory Neil Shapiro sm_dprintf("milter_negotiate(%s): did not return valid info\n", 222106f25ae9SGregory Neil Shapiro m->mf_name); 222240266059SGregory Neil Shapiro if (MilterLogLevel > 0) 222306f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 222440266059SGregory Neil Shapiro "Milter (%s): negotiate: did not return valid info", 222506f25ae9SGregory Neil Shapiro m->mf_name); 222606f25ae9SGregory Neil Shapiro if (response != NULL) 222740266059SGregory Neil Shapiro sm_free(response); /* XXX */ 222840266059SGregory Neil Shapiro milter_error(m, e); 222906f25ae9SGregory Neil Shapiro return -1; 223006f25ae9SGregory Neil Shapiro } 223106f25ae9SGregory Neil Shapiro 223206f25ae9SGregory Neil Shapiro /* extract information */ 223306f25ae9SGregory Neil Shapiro (void) memcpy((char *) &fvers, response, MILTER_LEN_BYTES); 223406f25ae9SGregory Neil Shapiro 223506f25ae9SGregory Neil Shapiro /* Now make sure we have enough for the feature bitmap */ 223606f25ae9SGregory Neil Shapiro if (rlen != MILTER_OPTLEN) 223706f25ae9SGregory Neil Shapiro { 223806f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 223940266059SGregory Neil Shapiro sm_dprintf("milter_negotiate(%s): did not return enough info\n", 224006f25ae9SGregory Neil Shapiro m->mf_name); 224140266059SGregory Neil Shapiro if (MilterLogLevel > 0) 224206f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 224340266059SGregory Neil Shapiro "Milter (%s): negotiate: did not return enough info", 224406f25ae9SGregory Neil Shapiro m->mf_name); 224506f25ae9SGregory Neil Shapiro if (response != NULL) 224640266059SGregory Neil Shapiro sm_free(response); /* XXX */ 224740266059SGregory Neil Shapiro milter_error(m, e); 224806f25ae9SGregory Neil Shapiro return -1; 224906f25ae9SGregory Neil Shapiro } 225006f25ae9SGregory Neil Shapiro 225106f25ae9SGregory Neil Shapiro (void) memcpy((char *) &fflags, response + MILTER_LEN_BYTES, 225206f25ae9SGregory Neil Shapiro MILTER_LEN_BYTES); 225306f25ae9SGregory Neil Shapiro (void) memcpy((char *) &pflags, response + (MILTER_LEN_BYTES * 2), 225406f25ae9SGregory Neil Shapiro MILTER_LEN_BYTES); 225540266059SGregory Neil Shapiro sm_free(response); /* XXX */ 225606f25ae9SGregory Neil Shapiro response = NULL; 225706f25ae9SGregory Neil Shapiro 225806f25ae9SGregory Neil Shapiro m->mf_fvers = ntohl(fvers); 225906f25ae9SGregory Neil Shapiro m->mf_fflags = ntohl(fflags); 226006f25ae9SGregory Neil Shapiro m->mf_pflags = ntohl(pflags); 226106f25ae9SGregory Neil Shapiro 226206f25ae9SGregory Neil Shapiro /* check for version compatibility */ 226306f25ae9SGregory Neil Shapiro if (m->mf_fvers == 1 || 226406f25ae9SGregory Neil Shapiro m->mf_fvers > SMFI_VERSION) 226506f25ae9SGregory Neil Shapiro { 226606f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 2267605302a5SGregory Neil Shapiro sm_dprintf("milter_negotiate(%s): version %d != MTA milter version %d\n", 226806f25ae9SGregory Neil Shapiro m->mf_name, m->mf_fvers, SMFI_VERSION); 226940266059SGregory Neil Shapiro if (MilterLogLevel > 0) 227006f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 2271605302a5SGregory Neil Shapiro "Milter (%s): negotiate: version %d != MTA milter version %d", 227206f25ae9SGregory Neil Shapiro m->mf_name, m->mf_fvers, SMFI_VERSION); 227340266059SGregory Neil Shapiro milter_error(m, e); 227406f25ae9SGregory Neil Shapiro return -1; 227506f25ae9SGregory Neil Shapiro } 227606f25ae9SGregory Neil Shapiro 227706f25ae9SGregory Neil Shapiro /* check for filter feature mismatch */ 227806f25ae9SGregory Neil Shapiro if ((m->mf_fflags & SMFI_CURR_ACTS) != m->mf_fflags) 227906f25ae9SGregory Neil Shapiro { 228006f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 2281605302a5SGregory Neil Shapiro sm_dprintf("milter_negotiate(%s): filter abilities 0x%x != MTA milter abilities 0x%lx\n", 228206f25ae9SGregory Neil Shapiro m->mf_name, m->mf_fflags, 2283605302a5SGregory Neil Shapiro SMFI_CURR_ACTS); 228440266059SGregory Neil Shapiro if (MilterLogLevel > 0) 228506f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 2286605302a5SGregory Neil Shapiro "Milter (%s): negotiate: filter abilities 0x%x != MTA milter abilities 0x%lx", 228706f25ae9SGregory Neil Shapiro m->mf_name, m->mf_fflags, 228840266059SGregory Neil Shapiro (unsigned long) SMFI_CURR_ACTS); 228940266059SGregory Neil Shapiro milter_error(m, e); 229006f25ae9SGregory Neil Shapiro return -1; 229106f25ae9SGregory Neil Shapiro } 229206f25ae9SGregory Neil Shapiro 229306f25ae9SGregory Neil Shapiro /* check for protocol feature mismatch */ 229406f25ae9SGregory Neil Shapiro if ((m->mf_pflags & SMFI_CURR_PROT) != m->mf_pflags) 229506f25ae9SGregory Neil Shapiro { 229606f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 2297605302a5SGregory Neil Shapiro sm_dprintf("milter_negotiate(%s): protocol abilities 0x%x != MTA milter abilities 0x%lx\n", 229806f25ae9SGregory Neil Shapiro m->mf_name, m->mf_pflags, 229940266059SGregory Neil Shapiro (unsigned long) SMFI_CURR_PROT); 230040266059SGregory Neil Shapiro if (MilterLogLevel > 0) 230106f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 2302605302a5SGregory Neil Shapiro "Milter (%s): negotiate: protocol abilities 0x%x != MTA milter abilities 0x%lx", 230306f25ae9SGregory Neil Shapiro m->mf_name, m->mf_pflags, 230440266059SGregory Neil Shapiro (unsigned long) SMFI_CURR_PROT); 230540266059SGregory Neil Shapiro milter_error(m, e); 230606f25ae9SGregory Neil Shapiro return -1; 230706f25ae9SGregory Neil Shapiro } 230806f25ae9SGregory Neil Shapiro 230906f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 2310605302a5SGregory Neil Shapiro sm_dprintf("milter_negotiate(%s): version %u, fflags 0x%x, pflags 0x%x\n", 231106f25ae9SGregory Neil Shapiro m->mf_name, m->mf_fvers, m->mf_fflags, m->mf_pflags); 231206f25ae9SGregory Neil Shapiro return 0; 231306f25ae9SGregory Neil Shapiro } 231440266059SGregory Neil Shapiro /* 231506f25ae9SGregory Neil Shapiro ** MILTER_PER_CONNECTION_CHECK -- checks on per-connection commands 231606f25ae9SGregory Neil Shapiro ** 231706f25ae9SGregory Neil Shapiro ** Reduce code duplication by putting these checks in one place 231806f25ae9SGregory Neil Shapiro ** 231906f25ae9SGregory Neil Shapiro ** Parameters: 232006f25ae9SGregory Neil Shapiro ** e -- current envelope. 232106f25ae9SGregory Neil Shapiro ** 232206f25ae9SGregory Neil Shapiro ** Returns: 232306f25ae9SGregory Neil Shapiro ** none 232406f25ae9SGregory Neil Shapiro */ 232506f25ae9SGregory Neil Shapiro 232606f25ae9SGregory Neil Shapiro static void 232706f25ae9SGregory Neil Shapiro milter_per_connection_check(e) 232806f25ae9SGregory Neil Shapiro ENVELOPE *e; 232906f25ae9SGregory Neil Shapiro { 233006f25ae9SGregory Neil Shapiro int i; 233106f25ae9SGregory Neil Shapiro 233206f25ae9SGregory Neil Shapiro /* see if we are done with any of the filters */ 233306f25ae9SGregory Neil Shapiro for (i = 0; InputFilters[i] != NULL; i++) 233406f25ae9SGregory Neil Shapiro { 233506f25ae9SGregory Neil Shapiro struct milter *m = InputFilters[i]; 233606f25ae9SGregory Neil Shapiro 2337602a2b1bSGregory Neil Shapiro if (m->mf_state == SMFS_CLOSABLE) 233806f25ae9SGregory Neil Shapiro milter_quit_filter(m, e); 233906f25ae9SGregory Neil Shapiro } 234006f25ae9SGregory Neil Shapiro } 234140266059SGregory Neil Shapiro /* 234206f25ae9SGregory Neil Shapiro ** MILTER_ERROR -- Put a milter filter into error state 234306f25ae9SGregory Neil Shapiro ** 234406f25ae9SGregory Neil Shapiro ** Parameters: 234506f25ae9SGregory Neil Shapiro ** m -- the broken filter. 2346b6bacd31SGregory Neil Shapiro ** e -- current envelope. 234706f25ae9SGregory Neil Shapiro ** 234806f25ae9SGregory Neil Shapiro ** Returns: 234906f25ae9SGregory Neil Shapiro ** none 235006f25ae9SGregory Neil Shapiro */ 235106f25ae9SGregory Neil Shapiro 235206f25ae9SGregory Neil Shapiro static void 235340266059SGregory Neil Shapiro milter_error(m, e) 235406f25ae9SGregory Neil Shapiro struct milter *m; 235540266059SGregory Neil Shapiro ENVELOPE *e; 235606f25ae9SGregory Neil Shapiro { 235706f25ae9SGregory Neil Shapiro /* 2358b6bacd31SGregory Neil Shapiro ** We could send a quit here but we may have gotten here due to 2359b6bacd31SGregory Neil Shapiro ** an I/O error so we don't want to try to make things worse. 236006f25ae9SGregory Neil Shapiro */ 236106f25ae9SGregory Neil Shapiro 236206f25ae9SGregory Neil Shapiro if (m->mf_sock >= 0) 236306f25ae9SGregory Neil Shapiro { 236406f25ae9SGregory Neil Shapiro (void) close(m->mf_sock); 236506f25ae9SGregory Neil Shapiro m->mf_sock = -1; 236606f25ae9SGregory Neil Shapiro } 236706f25ae9SGregory Neil Shapiro m->mf_state = SMFS_ERROR; 236840266059SGregory Neil Shapiro 236940266059SGregory Neil Shapiro if (MilterLogLevel > 0) 237040266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter (%s): to error state", 237140266059SGregory Neil Shapiro m->mf_name); 237206f25ae9SGregory Neil Shapiro } 237340266059SGregory Neil Shapiro /* 237406f25ae9SGregory Neil Shapiro ** MILTER_HEADERS -- send headers to a single milter filter 237506f25ae9SGregory Neil Shapiro ** 237606f25ae9SGregory Neil Shapiro ** Parameters: 237706f25ae9SGregory Neil Shapiro ** m -- current filter. 237806f25ae9SGregory Neil Shapiro ** e -- current envelope. 237906f25ae9SGregory Neil Shapiro ** state -- return state from response. 238006f25ae9SGregory Neil Shapiro ** 238106f25ae9SGregory Neil Shapiro ** Returns: 238206f25ae9SGregory Neil Shapiro ** response string (may be NULL) 238306f25ae9SGregory Neil Shapiro */ 238406f25ae9SGregory Neil Shapiro 238506f25ae9SGregory Neil Shapiro static char * 238606f25ae9SGregory Neil Shapiro milter_headers(m, e, state) 238706f25ae9SGregory Neil Shapiro struct milter *m; 238806f25ae9SGregory Neil Shapiro ENVELOPE *e; 238906f25ae9SGregory Neil Shapiro char *state; 239006f25ae9SGregory Neil Shapiro { 239106f25ae9SGregory Neil Shapiro char *response = NULL; 239206f25ae9SGregory Neil Shapiro HDR *h; 239306f25ae9SGregory Neil Shapiro 239440266059SGregory Neil Shapiro if (MilterLogLevel > 17) 239540266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter (%s): headers, send", 239640266059SGregory Neil Shapiro m->mf_name); 239740266059SGregory Neil Shapiro 239806f25ae9SGregory Neil Shapiro for (h = e->e_header; h != NULL; h = h->h_link) 239906f25ae9SGregory Neil Shapiro { 240006f25ae9SGregory Neil Shapiro char *buf; 240106f25ae9SGregory Neil Shapiro ssize_t s; 240206f25ae9SGregory Neil Shapiro 240306f25ae9SGregory Neil Shapiro /* don't send over deleted headers */ 240406f25ae9SGregory Neil Shapiro if (h->h_value == NULL) 240506f25ae9SGregory Neil Shapiro { 2406e92d3f3fSGregory Neil Shapiro /* strip H_USER so not counted in milter_changeheader() */ 240706f25ae9SGregory Neil Shapiro h->h_flags &= ~H_USER; 240806f25ae9SGregory Neil Shapiro continue; 240906f25ae9SGregory Neil Shapiro } 241006f25ae9SGregory Neil Shapiro 241106f25ae9SGregory Neil Shapiro /* skip auto-generated */ 241206f25ae9SGregory Neil Shapiro if (!bitset(H_USER, h->h_flags)) 241306f25ae9SGregory Neil Shapiro continue; 241406f25ae9SGregory Neil Shapiro 241506f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 241640266059SGregory Neil Shapiro sm_dprintf("milter_headers: %s: %s\n", 241706f25ae9SGregory Neil Shapiro h->h_field, h->h_value); 241840266059SGregory Neil Shapiro if (MilterLogLevel > 21) 241940266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter (%s): header, %s", 242040266059SGregory Neil Shapiro m->mf_name, h->h_field); 242106f25ae9SGregory Neil Shapiro 242240266059SGregory Neil Shapiro s = strlen(h->h_field) + 1 + strlen(h->h_value) + 1; 242340266059SGregory Neil Shapiro if (s < 0) 242440266059SGregory Neil Shapiro continue; 242506f25ae9SGregory Neil Shapiro buf = (char *) xalloc(s); 242640266059SGregory Neil Shapiro (void) sm_snprintf(buf, s, "%s%c%s", 242740266059SGregory Neil Shapiro h->h_field, '\0', h->h_value); 242806f25ae9SGregory Neil Shapiro 242906f25ae9SGregory Neil Shapiro /* send it over */ 243006f25ae9SGregory Neil Shapiro response = milter_send_command(m, SMFIC_HEADER, buf, 243106f25ae9SGregory Neil Shapiro s, e, state); 243240266059SGregory Neil Shapiro sm_free(buf); /* XXX */ 243306f25ae9SGregory Neil Shapiro if (m->mf_state == SMFS_ERROR || 243406f25ae9SGregory Neil Shapiro m->mf_state == SMFS_DONE || 243506f25ae9SGregory Neil Shapiro *state != SMFIR_CONTINUE) 243606f25ae9SGregory Neil Shapiro break; 243706f25ae9SGregory Neil Shapiro } 243840266059SGregory Neil Shapiro if (MilterLogLevel > 17) 243940266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter (%s): headers, sent", 244040266059SGregory Neil Shapiro m->mf_name); 244106f25ae9SGregory Neil Shapiro return response; 244206f25ae9SGregory Neil Shapiro } 244340266059SGregory Neil Shapiro /* 244406f25ae9SGregory Neil Shapiro ** MILTER_BODY -- send the body to a filter 244506f25ae9SGregory Neil Shapiro ** 244606f25ae9SGregory Neil Shapiro ** Parameters: 244706f25ae9SGregory Neil Shapiro ** m -- current filter. 244806f25ae9SGregory Neil Shapiro ** e -- current envelope. 244906f25ae9SGregory Neil Shapiro ** state -- return state from response. 245006f25ae9SGregory Neil Shapiro ** 245106f25ae9SGregory Neil Shapiro ** Returns: 245206f25ae9SGregory Neil Shapiro ** response string (may be NULL) 245306f25ae9SGregory Neil Shapiro */ 245406f25ae9SGregory Neil Shapiro 245506f25ae9SGregory Neil Shapiro static char * 245606f25ae9SGregory Neil Shapiro milter_body(m, e, state) 245706f25ae9SGregory Neil Shapiro struct milter *m; 245806f25ae9SGregory Neil Shapiro ENVELOPE *e; 245906f25ae9SGregory Neil Shapiro char *state; 246006f25ae9SGregory Neil Shapiro { 246106f25ae9SGregory Neil Shapiro char bufchar = '\0'; 246206f25ae9SGregory Neil Shapiro char prevchar = '\0'; 246306f25ae9SGregory Neil Shapiro int c; 246406f25ae9SGregory Neil Shapiro char *response = NULL; 246506f25ae9SGregory Neil Shapiro char *bp; 246606f25ae9SGregory Neil Shapiro char buf[MILTER_CHUNK_SIZE]; 246706f25ae9SGregory Neil Shapiro 246806f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 246940266059SGregory Neil Shapiro sm_dprintf("milter_body\n"); 247006f25ae9SGregory Neil Shapiro 247106f25ae9SGregory Neil Shapiro if (bfrewind(e->e_dfp) < 0) 247206f25ae9SGregory Neil Shapiro { 247306f25ae9SGregory Neil Shapiro ExitStat = EX_IOERR; 247406f25ae9SGregory Neil Shapiro *state = SMFIR_TEMPFAIL; 247540266059SGregory Neil Shapiro syserr("milter_body: %s/%cf%s: rewind error", 247640266059SGregory Neil Shapiro qid_printqueue(e->e_qgrp, e->e_qdir), 247740266059SGregory Neil Shapiro DATAFL_LETTER, e->e_id); 247806f25ae9SGregory Neil Shapiro return NULL; 247906f25ae9SGregory Neil Shapiro } 248006f25ae9SGregory Neil Shapiro 248140266059SGregory Neil Shapiro if (MilterLogLevel > 17) 248240266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter (%s): body, send", 248340266059SGregory Neil Shapiro m->mf_name); 248406f25ae9SGregory Neil Shapiro bp = buf; 248540266059SGregory Neil Shapiro while ((c = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT)) != SM_IO_EOF) 248606f25ae9SGregory Neil Shapiro { 248706f25ae9SGregory Neil Shapiro /* Change LF to CRLF */ 248806f25ae9SGregory Neil Shapiro if (c == '\n') 248906f25ae9SGregory Neil Shapiro { 249006f25ae9SGregory Neil Shapiro /* Not a CRLF already? */ 249106f25ae9SGregory Neil Shapiro if (prevchar != '\r') 249206f25ae9SGregory Neil Shapiro { 249306f25ae9SGregory Neil Shapiro /* Room for CR now? */ 249406f25ae9SGregory Neil Shapiro if (bp + 2 > &buf[sizeof buf]) 249506f25ae9SGregory Neil Shapiro { 249606f25ae9SGregory Neil Shapiro /* No room, buffer LF */ 249706f25ae9SGregory Neil Shapiro bufchar = c; 249806f25ae9SGregory Neil Shapiro 249906f25ae9SGregory Neil Shapiro /* and send CR now */ 250006f25ae9SGregory Neil Shapiro c = '\r'; 250106f25ae9SGregory Neil Shapiro } 250206f25ae9SGregory Neil Shapiro else 250306f25ae9SGregory Neil Shapiro { 250406f25ae9SGregory Neil Shapiro /* Room to do it now */ 250506f25ae9SGregory Neil Shapiro *bp++ = '\r'; 250606f25ae9SGregory Neil Shapiro prevchar = '\r'; 250706f25ae9SGregory Neil Shapiro } 250806f25ae9SGregory Neil Shapiro } 250906f25ae9SGregory Neil Shapiro } 251006f25ae9SGregory Neil Shapiro *bp++ = (char) c; 251106f25ae9SGregory Neil Shapiro prevchar = c; 251206f25ae9SGregory Neil Shapiro if (bp >= &buf[sizeof buf]) 251306f25ae9SGregory Neil Shapiro { 251406f25ae9SGregory Neil Shapiro /* send chunk */ 251506f25ae9SGregory Neil Shapiro response = milter_send_command(m, SMFIC_BODY, buf, 251606f25ae9SGregory Neil Shapiro bp - buf, e, state); 251706f25ae9SGregory Neil Shapiro bp = buf; 251806f25ae9SGregory Neil Shapiro if (bufchar != '\0') 251906f25ae9SGregory Neil Shapiro { 252006f25ae9SGregory Neil Shapiro *bp++ = bufchar; 252106f25ae9SGregory Neil Shapiro bufchar = '\0'; 252206f25ae9SGregory Neil Shapiro prevchar = bufchar; 252306f25ae9SGregory Neil Shapiro } 252406f25ae9SGregory Neil Shapiro } 252506f25ae9SGregory Neil Shapiro if (m->mf_state == SMFS_ERROR || 252606f25ae9SGregory Neil Shapiro m->mf_state == SMFS_DONE || 252706f25ae9SGregory Neil Shapiro *state != SMFIR_CONTINUE) 252806f25ae9SGregory Neil Shapiro break; 252906f25ae9SGregory Neil Shapiro } 253006f25ae9SGregory Neil Shapiro 253106f25ae9SGregory Neil Shapiro /* check for read errors */ 253240266059SGregory Neil Shapiro if (sm_io_error(e->e_dfp)) 253306f25ae9SGregory Neil Shapiro { 253406f25ae9SGregory Neil Shapiro ExitStat = EX_IOERR; 253506f25ae9SGregory Neil Shapiro if (*state == SMFIR_CONTINUE || 253606f25ae9SGregory Neil Shapiro *state == SMFIR_ACCEPT) 253706f25ae9SGregory Neil Shapiro { 253806f25ae9SGregory Neil Shapiro *state = SMFIR_TEMPFAIL; 253906f25ae9SGregory Neil Shapiro if (response != NULL) 254006f25ae9SGregory Neil Shapiro { 254140266059SGregory Neil Shapiro sm_free(response); /* XXX */ 254206f25ae9SGregory Neil Shapiro response = NULL; 254306f25ae9SGregory Neil Shapiro } 254406f25ae9SGregory Neil Shapiro } 254540266059SGregory Neil Shapiro syserr("milter_body: %s/%cf%s: read error", 254640266059SGregory Neil Shapiro qid_printqueue(e->e_qgrp, e->e_qdir), 254740266059SGregory Neil Shapiro DATAFL_LETTER, e->e_id); 254806f25ae9SGregory Neil Shapiro return response; 254906f25ae9SGregory Neil Shapiro } 255006f25ae9SGregory Neil Shapiro 255106f25ae9SGregory Neil Shapiro /* send last body chunk */ 255206f25ae9SGregory Neil Shapiro if (bp > buf && 255306f25ae9SGregory Neil Shapiro m->mf_state != SMFS_ERROR && 255406f25ae9SGregory Neil Shapiro m->mf_state != SMFS_DONE && 255506f25ae9SGregory Neil Shapiro *state == SMFIR_CONTINUE) 255606f25ae9SGregory Neil Shapiro { 255706f25ae9SGregory Neil Shapiro /* send chunk */ 255806f25ae9SGregory Neil Shapiro response = milter_send_command(m, SMFIC_BODY, buf, bp - buf, 255906f25ae9SGregory Neil Shapiro e, state); 256006f25ae9SGregory Neil Shapiro bp = buf; 256106f25ae9SGregory Neil Shapiro } 256240266059SGregory Neil Shapiro if (MilterLogLevel > 17) 256340266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter (%s): body, sent", 256440266059SGregory Neil Shapiro m->mf_name); 256506f25ae9SGregory Neil Shapiro return response; 256606f25ae9SGregory Neil Shapiro } 256706f25ae9SGregory Neil Shapiro 256806f25ae9SGregory Neil Shapiro /* 256906f25ae9SGregory Neil Shapiro ** Actions 257006f25ae9SGregory Neil Shapiro */ 257106f25ae9SGregory Neil Shapiro 257240266059SGregory Neil Shapiro /* 257306f25ae9SGregory Neil Shapiro ** MILTER_ADDHEADER -- Add the supplied header to the message 257406f25ae9SGregory Neil Shapiro ** 257506f25ae9SGregory Neil Shapiro ** Parameters: 257606f25ae9SGregory Neil Shapiro ** response -- encoded form of header/value. 257706f25ae9SGregory Neil Shapiro ** rlen -- length of response. 257806f25ae9SGregory Neil Shapiro ** e -- current envelope. 257906f25ae9SGregory Neil Shapiro ** 258006f25ae9SGregory Neil Shapiro ** Returns: 258106f25ae9SGregory Neil Shapiro ** none 258206f25ae9SGregory Neil Shapiro */ 258306f25ae9SGregory Neil Shapiro 258406f25ae9SGregory Neil Shapiro static void 258506f25ae9SGregory Neil Shapiro milter_addheader(response, rlen, e) 258606f25ae9SGregory Neil Shapiro char *response; 258706f25ae9SGregory Neil Shapiro ssize_t rlen; 258806f25ae9SGregory Neil Shapiro ENVELOPE *e; 258906f25ae9SGregory Neil Shapiro { 259006f25ae9SGregory Neil Shapiro char *val; 2591193538b7SGregory Neil Shapiro HDR *h; 259206f25ae9SGregory Neil Shapiro 259306f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 259440266059SGregory Neil Shapiro sm_dprintf("milter_addheader: "); 259506f25ae9SGregory Neil Shapiro 259606f25ae9SGregory Neil Shapiro /* sanity checks */ 259706f25ae9SGregory Neil Shapiro if (response == NULL) 259806f25ae9SGregory Neil Shapiro { 259906f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 260040266059SGregory Neil Shapiro sm_dprintf("NULL response\n"); 260106f25ae9SGregory Neil Shapiro return; 260206f25ae9SGregory Neil Shapiro } 260306f25ae9SGregory Neil Shapiro 260406f25ae9SGregory Neil Shapiro if (rlen < 2 || strlen(response) + 1 >= (size_t) rlen) 260506f25ae9SGregory Neil Shapiro { 260606f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 260740266059SGregory Neil Shapiro sm_dprintf("didn't follow protocol (total len)\n"); 260806f25ae9SGregory Neil Shapiro return; 260906f25ae9SGregory Neil Shapiro } 261006f25ae9SGregory Neil Shapiro 261106f25ae9SGregory Neil Shapiro /* Find separating NUL */ 261206f25ae9SGregory Neil Shapiro val = response + strlen(response) + 1; 261306f25ae9SGregory Neil Shapiro 261406f25ae9SGregory Neil Shapiro /* another sanity check */ 261506f25ae9SGregory Neil Shapiro if (strlen(response) + strlen(val) + 2 != (size_t) rlen) 261606f25ae9SGregory Neil Shapiro { 261706f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 261840266059SGregory Neil Shapiro sm_dprintf("didn't follow protocol (part len)\n"); 261906f25ae9SGregory Neil Shapiro return; 262006f25ae9SGregory Neil Shapiro } 262106f25ae9SGregory Neil Shapiro 262206f25ae9SGregory Neil Shapiro if (*response == '\0') 262306f25ae9SGregory Neil Shapiro { 262406f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 262540266059SGregory Neil Shapiro sm_dprintf("empty field name\n"); 262606f25ae9SGregory Neil Shapiro return; 262706f25ae9SGregory Neil Shapiro } 262806f25ae9SGregory Neil Shapiro 2629193538b7SGregory Neil Shapiro for (h = e->e_header; h != NULL; h = h->h_link) 2630193538b7SGregory Neil Shapiro { 263140266059SGregory Neil Shapiro if (sm_strcasecmp(h->h_field, response) == 0 && 2632193538b7SGregory Neil Shapiro !bitset(H_USER, h->h_flags) && 2633193538b7SGregory Neil Shapiro !bitset(H_TRACE, h->h_flags)) 2634193538b7SGregory Neil Shapiro break; 2635193538b7SGregory Neil Shapiro } 2636193538b7SGregory Neil Shapiro 263706f25ae9SGregory Neil Shapiro /* add to e_msgsize */ 263806f25ae9SGregory Neil Shapiro e->e_msgsize += strlen(response) + 2 + strlen(val); 263906f25ae9SGregory Neil Shapiro 2640193538b7SGregory Neil Shapiro if (h != NULL) 2641193538b7SGregory Neil Shapiro { 2642193538b7SGregory Neil Shapiro if (tTd(64, 10)) 264340266059SGregory Neil Shapiro sm_dprintf("Replace default header %s value with %s\n", 264440266059SGregory Neil Shapiro h->h_field, val); 264540266059SGregory Neil Shapiro if (MilterLogLevel > 8) 264640266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, 264740266059SGregory Neil Shapiro "Milter change: default header %s value with %s", 2648193538b7SGregory Neil Shapiro h->h_field, val); 2649193538b7SGregory Neil Shapiro h->h_value = newstr(val); 2650193538b7SGregory Neil Shapiro h->h_flags |= H_USER; 2651193538b7SGregory Neil Shapiro } 2652193538b7SGregory Neil Shapiro else 2653193538b7SGregory Neil Shapiro { 265406f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 265540266059SGregory Neil Shapiro sm_dprintf("Add %s: %s\n", response, val); 265640266059SGregory Neil Shapiro if (MilterLogLevel > 8) 265740266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter add: header: %s: %s", 265840266059SGregory Neil Shapiro response, val); 265940266059SGregory Neil Shapiro addheader(newstr(response), val, H_USER, e); 266006f25ae9SGregory Neil Shapiro } 2661193538b7SGregory Neil Shapiro } 266240266059SGregory Neil Shapiro /* 2663e92d3f3fSGregory Neil Shapiro ** MILTER_INSHEADER -- Insert the supplied header 2664e92d3f3fSGregory Neil Shapiro ** 2665e92d3f3fSGregory Neil Shapiro ** Parameters: 2666e92d3f3fSGregory Neil Shapiro ** response -- encoded form of header/value. 2667e92d3f3fSGregory Neil Shapiro ** rlen -- length of response. 2668e92d3f3fSGregory Neil Shapiro ** e -- current envelope. 2669e92d3f3fSGregory Neil Shapiro ** 2670e92d3f3fSGregory Neil Shapiro ** Returns: 2671e92d3f3fSGregory Neil Shapiro ** none 2672e92d3f3fSGregory Neil Shapiro ** 2673e92d3f3fSGregory Neil Shapiro ** Notes: 2674e92d3f3fSGregory Neil Shapiro ** Unlike milter_addheader(), this does not attempt to determine 2675e92d3f3fSGregory Neil Shapiro ** if the header already exists in the envelope, even a 2676e92d3f3fSGregory Neil Shapiro ** deleted version. It just blindly inserts. 2677e92d3f3fSGregory Neil Shapiro */ 2678e92d3f3fSGregory Neil Shapiro 2679e92d3f3fSGregory Neil Shapiro static void 2680e92d3f3fSGregory Neil Shapiro milter_insheader(response, rlen, e) 2681e92d3f3fSGregory Neil Shapiro char *response; 2682e92d3f3fSGregory Neil Shapiro ssize_t rlen; 2683e92d3f3fSGregory Neil Shapiro ENVELOPE *e; 2684e92d3f3fSGregory Neil Shapiro { 2685e92d3f3fSGregory Neil Shapiro mi_int32 idx, i; 2686e92d3f3fSGregory Neil Shapiro char *field; 2687e92d3f3fSGregory Neil Shapiro char *val; 2688e92d3f3fSGregory Neil Shapiro 2689e92d3f3fSGregory Neil Shapiro if (tTd(64, 10)) 2690e92d3f3fSGregory Neil Shapiro sm_dprintf("milter_insheader: "); 2691e92d3f3fSGregory Neil Shapiro 2692e92d3f3fSGregory Neil Shapiro /* sanity checks */ 2693e92d3f3fSGregory Neil Shapiro if (response == NULL) 2694e92d3f3fSGregory Neil Shapiro { 2695e92d3f3fSGregory Neil Shapiro if (tTd(64, 10)) 2696e92d3f3fSGregory Neil Shapiro sm_dprintf("NULL response\n"); 2697e92d3f3fSGregory Neil Shapiro return; 2698e92d3f3fSGregory Neil Shapiro } 2699e92d3f3fSGregory Neil Shapiro 2700e92d3f3fSGregory Neil Shapiro if (rlen < 2 || strlen(response) + 1 >= (size_t) rlen) 2701e92d3f3fSGregory Neil Shapiro { 2702e92d3f3fSGregory Neil Shapiro if (tTd(64, 10)) 2703e92d3f3fSGregory Neil Shapiro sm_dprintf("didn't follow protocol (total len)\n"); 2704e92d3f3fSGregory Neil Shapiro return; 2705e92d3f3fSGregory Neil Shapiro } 2706e92d3f3fSGregory Neil Shapiro 2707e92d3f3fSGregory Neil Shapiro /* decode */ 2708e92d3f3fSGregory Neil Shapiro (void) memcpy((char *) &i, response, MILTER_LEN_BYTES); 2709e92d3f3fSGregory Neil Shapiro idx = ntohl(i); 2710e92d3f3fSGregory Neil Shapiro field = response + MILTER_LEN_BYTES; 2711e92d3f3fSGregory Neil Shapiro val = field + strlen(field) + 1; 2712e92d3f3fSGregory Neil Shapiro 2713e92d3f3fSGregory Neil Shapiro /* another sanity check */ 2714e92d3f3fSGregory Neil Shapiro if (MILTER_LEN_BYTES + strlen(field) + 1 + 2715e92d3f3fSGregory Neil Shapiro strlen(val) + 1 != (size_t) rlen) 2716e92d3f3fSGregory Neil Shapiro { 2717e92d3f3fSGregory Neil Shapiro if (tTd(64, 10)) 2718e92d3f3fSGregory Neil Shapiro sm_dprintf("didn't follow protocol (part len)\n"); 2719e92d3f3fSGregory Neil Shapiro return; 2720e92d3f3fSGregory Neil Shapiro } 2721e92d3f3fSGregory Neil Shapiro 2722e92d3f3fSGregory Neil Shapiro if (*field == '\0') 2723e92d3f3fSGregory Neil Shapiro { 2724e92d3f3fSGregory Neil Shapiro if (tTd(64, 10)) 2725e92d3f3fSGregory Neil Shapiro sm_dprintf("empty field name\n"); 2726e92d3f3fSGregory Neil Shapiro return; 2727e92d3f3fSGregory Neil Shapiro } 2728e92d3f3fSGregory Neil Shapiro 2729e92d3f3fSGregory Neil Shapiro /* add to e_msgsize */ 2730e92d3f3fSGregory Neil Shapiro e->e_msgsize += strlen(response) + 2 + strlen(val); 2731e92d3f3fSGregory Neil Shapiro 2732e92d3f3fSGregory Neil Shapiro if (tTd(64, 10)) 2733e92d3f3fSGregory Neil Shapiro sm_dprintf("Insert (%d) %s: %s\n", idx, response, val); 2734e92d3f3fSGregory Neil Shapiro if (MilterLogLevel > 8) 2735e92d3f3fSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, 2736e92d3f3fSGregory Neil Shapiro "Milter insert (%d): header: %s: %s", 2737e92d3f3fSGregory Neil Shapiro idx, field, val); 2738e92d3f3fSGregory Neil Shapiro insheader(idx, newstr(field), val, H_USER, e); 2739e92d3f3fSGregory Neil Shapiro } 2740e92d3f3fSGregory Neil Shapiro /* 274106f25ae9SGregory Neil Shapiro ** MILTER_CHANGEHEADER -- Change the supplied header in the message 274206f25ae9SGregory Neil Shapiro ** 274306f25ae9SGregory Neil Shapiro ** Parameters: 274406f25ae9SGregory Neil Shapiro ** response -- encoded form of header/index/value. 274506f25ae9SGregory Neil Shapiro ** rlen -- length of response. 274606f25ae9SGregory Neil Shapiro ** e -- current envelope. 274706f25ae9SGregory Neil Shapiro ** 274806f25ae9SGregory Neil Shapiro ** Returns: 274906f25ae9SGregory Neil Shapiro ** none 275006f25ae9SGregory Neil Shapiro */ 275106f25ae9SGregory Neil Shapiro 275206f25ae9SGregory Neil Shapiro static void 275306f25ae9SGregory Neil Shapiro milter_changeheader(response, rlen, e) 275406f25ae9SGregory Neil Shapiro char *response; 275506f25ae9SGregory Neil Shapiro ssize_t rlen; 275606f25ae9SGregory Neil Shapiro ENVELOPE *e; 275706f25ae9SGregory Neil Shapiro { 275806f25ae9SGregory Neil Shapiro mi_int32 i, index; 275906f25ae9SGregory Neil Shapiro char *field, *val; 2760193538b7SGregory Neil Shapiro HDR *h, *sysheader; 276106f25ae9SGregory Neil Shapiro 276206f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 276340266059SGregory Neil Shapiro sm_dprintf("milter_changeheader: "); 276406f25ae9SGregory Neil Shapiro 276506f25ae9SGregory Neil Shapiro /* sanity checks */ 276606f25ae9SGregory Neil Shapiro if (response == NULL) 276706f25ae9SGregory Neil Shapiro { 276806f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 276940266059SGregory Neil Shapiro sm_dprintf("NULL response\n"); 277006f25ae9SGregory Neil Shapiro return; 277106f25ae9SGregory Neil Shapiro } 277206f25ae9SGregory Neil Shapiro 277306f25ae9SGregory Neil Shapiro if (rlen < 2 || strlen(response) + 1 >= (size_t) rlen) 277406f25ae9SGregory Neil Shapiro { 277506f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 277640266059SGregory Neil Shapiro sm_dprintf("didn't follow protocol (total len)\n"); 277706f25ae9SGregory Neil Shapiro return; 277806f25ae9SGregory Neil Shapiro } 277906f25ae9SGregory Neil Shapiro 278006f25ae9SGregory Neil Shapiro /* Find separating NUL */ 278106f25ae9SGregory Neil Shapiro (void) memcpy((char *) &i, response, MILTER_LEN_BYTES); 278206f25ae9SGregory Neil Shapiro index = ntohl(i); 278306f25ae9SGregory Neil Shapiro field = response + MILTER_LEN_BYTES; 278406f25ae9SGregory Neil Shapiro val = field + strlen(field) + 1; 278506f25ae9SGregory Neil Shapiro 278606f25ae9SGregory Neil Shapiro /* another sanity check */ 278706f25ae9SGregory Neil Shapiro if (MILTER_LEN_BYTES + strlen(field) + 1 + 278806f25ae9SGregory Neil Shapiro strlen(val) + 1 != (size_t) rlen) 278906f25ae9SGregory Neil Shapiro { 279006f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 279140266059SGregory Neil Shapiro sm_dprintf("didn't follow protocol (part len)\n"); 279206f25ae9SGregory Neil Shapiro return; 279306f25ae9SGregory Neil Shapiro } 279406f25ae9SGregory Neil Shapiro 279506f25ae9SGregory Neil Shapiro if (*field == '\0') 279606f25ae9SGregory Neil Shapiro { 279706f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 279840266059SGregory Neil Shapiro sm_dprintf("empty field name\n"); 279906f25ae9SGregory Neil Shapiro return; 280006f25ae9SGregory Neil Shapiro } 280106f25ae9SGregory Neil Shapiro 2802193538b7SGregory Neil Shapiro sysheader = NULL; 280306f25ae9SGregory Neil Shapiro for (h = e->e_header; h != NULL; h = h->h_link) 280406f25ae9SGregory Neil Shapiro { 280540266059SGregory Neil Shapiro if (sm_strcasecmp(h->h_field, field) == 0) 2806193538b7SGregory Neil Shapiro { 280706f25ae9SGregory Neil Shapiro if (bitset(H_USER, h->h_flags) && 280806f25ae9SGregory Neil Shapiro --index <= 0) 2809193538b7SGregory Neil Shapiro { 2810193538b7SGregory Neil Shapiro sysheader = NULL; 281106f25ae9SGregory Neil Shapiro break; 281206f25ae9SGregory Neil Shapiro } 2813193538b7SGregory Neil Shapiro else if (!bitset(H_USER, h->h_flags) && 2814193538b7SGregory Neil Shapiro !bitset(H_TRACE, h->h_flags)) 2815193538b7SGregory Neil Shapiro { 2816193538b7SGregory Neil Shapiro /* 2817193538b7SGregory Neil Shapiro ** DRUMS msg-fmt draft says can only have 2818193538b7SGregory Neil Shapiro ** multiple occurences of trace fields, 2819193538b7SGregory Neil Shapiro ** so make sure we replace any non-trace, 2820193538b7SGregory Neil Shapiro ** non-user field. 2821193538b7SGregory Neil Shapiro */ 2822193538b7SGregory Neil Shapiro 2823193538b7SGregory Neil Shapiro sysheader = h; 2824193538b7SGregory Neil Shapiro } 2825193538b7SGregory Neil Shapiro } 2826193538b7SGregory Neil Shapiro } 2827193538b7SGregory Neil Shapiro 2828193538b7SGregory Neil Shapiro /* if not found as user-provided header at index, use sysheader */ 2829193538b7SGregory Neil Shapiro if (h == NULL) 2830193538b7SGregory Neil Shapiro h = sysheader; 283106f25ae9SGregory Neil Shapiro 283206f25ae9SGregory Neil Shapiro if (h == NULL) 283306f25ae9SGregory Neil Shapiro { 283406f25ae9SGregory Neil Shapiro if (*val == '\0') 283506f25ae9SGregory Neil Shapiro { 283606f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 2837b6bacd31SGregory Neil Shapiro sm_dprintf("Delete (noop) %s\n", field); 2838b6bacd31SGregory Neil Shapiro if (MilterLogLevel > 8) 2839b6bacd31SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, 2840b6bacd31SGregory Neil Shapiro "Milter delete (noop): header: %s" 2841b6bacd31SGregory Neil Shapiro , field); 284206f25ae9SGregory Neil Shapiro } 284306f25ae9SGregory Neil Shapiro else 284406f25ae9SGregory Neil Shapiro { 284506f25ae9SGregory Neil Shapiro /* treat modify value with no existing header as add */ 284606f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 284740266059SGregory Neil Shapiro sm_dprintf("Add %s: %s\n", field, val); 2848b6bacd31SGregory Neil Shapiro if (MilterLogLevel > 8) 2849b6bacd31SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, 2850b6bacd31SGregory Neil Shapiro "Milter change (add): header: %s: %s" 2851b6bacd31SGregory Neil Shapiro , field, val); 285240266059SGregory Neil Shapiro addheader(newstr(field), val, H_USER, e); 285306f25ae9SGregory Neil Shapiro } 285406f25ae9SGregory Neil Shapiro return; 285506f25ae9SGregory Neil Shapiro } 285606f25ae9SGregory Neil Shapiro 285706f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 285806f25ae9SGregory Neil Shapiro { 285906f25ae9SGregory Neil Shapiro if (*val == '\0') 286006f25ae9SGregory Neil Shapiro { 286140266059SGregory Neil Shapiro sm_dprintf("Delete%s %s: %s\n", 2862193538b7SGregory Neil Shapiro h == sysheader ? " (default header)" : "", 2863193538b7SGregory Neil Shapiro field, 286406f25ae9SGregory Neil Shapiro h->h_value == NULL ? "<NULL>" : h->h_value); 286506f25ae9SGregory Neil Shapiro } 286606f25ae9SGregory Neil Shapiro else 286706f25ae9SGregory Neil Shapiro { 286840266059SGregory Neil Shapiro sm_dprintf("Change%s %s: from %s to %s\n", 286940266059SGregory Neil Shapiro h == sysheader ? " (default header)" : "", 287040266059SGregory Neil Shapiro field, 287140266059SGregory Neil Shapiro h->h_value == NULL ? "<NULL>" : h->h_value, 287240266059SGregory Neil Shapiro val); 287340266059SGregory Neil Shapiro } 287440266059SGregory Neil Shapiro } 287540266059SGregory Neil Shapiro 287640266059SGregory Neil Shapiro if (MilterLogLevel > 8) 287740266059SGregory Neil Shapiro { 287840266059SGregory Neil Shapiro if (*val == '\0') 287940266059SGregory Neil Shapiro { 288040266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, 288140266059SGregory Neil Shapiro "Milter delete: header%s %s: %s", 288240266059SGregory Neil Shapiro h == sysheader ? " (default header)" : "", 288340266059SGregory Neil Shapiro field, 288440266059SGregory Neil Shapiro h->h_value == NULL ? "<NULL>" : h->h_value); 288540266059SGregory Neil Shapiro } 288640266059SGregory Neil Shapiro else 288740266059SGregory Neil Shapiro { 288840266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, 288940266059SGregory Neil Shapiro "Milter change: header%s %s: from %s to %s", 2890193538b7SGregory Neil Shapiro h == sysheader ? " (default header)" : "", 289106f25ae9SGregory Neil Shapiro field, 289206f25ae9SGregory Neil Shapiro h->h_value == NULL ? "<NULL>" : h->h_value, 289306f25ae9SGregory Neil Shapiro val); 289406f25ae9SGregory Neil Shapiro } 289506f25ae9SGregory Neil Shapiro } 289606f25ae9SGregory Neil Shapiro 2897193538b7SGregory Neil Shapiro if (h != sysheader && h->h_value != NULL) 289806f25ae9SGregory Neil Shapiro { 289940266059SGregory Neil Shapiro size_t l; 290040266059SGregory Neil Shapiro 290140266059SGregory Neil Shapiro l = strlen(h->h_value); 290240266059SGregory Neil Shapiro if (l > e->e_msgsize) 290340266059SGregory Neil Shapiro e->e_msgsize = 0; 290440266059SGregory Neil Shapiro else 290540266059SGregory Neil Shapiro e->e_msgsize -= l; 290640266059SGregory Neil Shapiro /* rpool, don't free: sm_free(h->h_value); XXX */ 290706f25ae9SGregory Neil Shapiro } 290806f25ae9SGregory Neil Shapiro 290906f25ae9SGregory Neil Shapiro if (*val == '\0') 291006f25ae9SGregory Neil Shapiro { 291106f25ae9SGregory Neil Shapiro /* Remove "Field: " from message size */ 2912193538b7SGregory Neil Shapiro if (h != sysheader) 291340266059SGregory Neil Shapiro { 291440266059SGregory Neil Shapiro size_t l; 291540266059SGregory Neil Shapiro 291640266059SGregory Neil Shapiro l = strlen(h->h_field) + 2; 291740266059SGregory Neil Shapiro if (l > e->e_msgsize) 291840266059SGregory Neil Shapiro e->e_msgsize = 0; 291940266059SGregory Neil Shapiro else 292040266059SGregory Neil Shapiro e->e_msgsize -= l; 292140266059SGregory Neil Shapiro } 292206f25ae9SGregory Neil Shapiro h->h_value = NULL; 292306f25ae9SGregory Neil Shapiro } 292406f25ae9SGregory Neil Shapiro else 292506f25ae9SGregory Neil Shapiro { 292606f25ae9SGregory Neil Shapiro h->h_value = newstr(val); 2927193538b7SGregory Neil Shapiro h->h_flags |= H_USER; 292806f25ae9SGregory Neil Shapiro e->e_msgsize += strlen(h->h_value); 292906f25ae9SGregory Neil Shapiro } 293006f25ae9SGregory Neil Shapiro } 293140266059SGregory Neil Shapiro /* 293206f25ae9SGregory Neil Shapiro ** MILTER_ADDRCPT -- Add the supplied recipient to the message 293306f25ae9SGregory Neil Shapiro ** 293406f25ae9SGregory Neil Shapiro ** Parameters: 293506f25ae9SGregory Neil Shapiro ** response -- encoded form of recipient address. 293606f25ae9SGregory Neil Shapiro ** rlen -- length of response. 293706f25ae9SGregory Neil Shapiro ** e -- current envelope. 293806f25ae9SGregory Neil Shapiro ** 293906f25ae9SGregory Neil Shapiro ** Returns: 294006f25ae9SGregory Neil Shapiro ** none 294106f25ae9SGregory Neil Shapiro */ 294206f25ae9SGregory Neil Shapiro 294306f25ae9SGregory Neil Shapiro static void 294406f25ae9SGregory Neil Shapiro milter_addrcpt(response, rlen, e) 294506f25ae9SGregory Neil Shapiro char *response; 294606f25ae9SGregory Neil Shapiro ssize_t rlen; 294706f25ae9SGregory Neil Shapiro ENVELOPE *e; 294806f25ae9SGregory Neil Shapiro { 2949a7ec597cSGregory Neil Shapiro int olderrors; 2950a7ec597cSGregory Neil Shapiro 295106f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 295240266059SGregory Neil Shapiro sm_dprintf("milter_addrcpt: "); 295306f25ae9SGregory Neil Shapiro 295406f25ae9SGregory Neil Shapiro /* sanity checks */ 295506f25ae9SGregory Neil Shapiro if (response == NULL) 295606f25ae9SGregory Neil Shapiro { 295706f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 295840266059SGregory Neil Shapiro sm_dprintf("NULL response\n"); 295906f25ae9SGregory Neil Shapiro return; 296006f25ae9SGregory Neil Shapiro } 296106f25ae9SGregory Neil Shapiro 296206f25ae9SGregory Neil Shapiro if (*response == '\0' || 296306f25ae9SGregory Neil Shapiro strlen(response) + 1 != (size_t) rlen) 296406f25ae9SGregory Neil Shapiro { 296506f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 296640266059SGregory Neil Shapiro sm_dprintf("didn't follow protocol (total len %d != rlen %d)\n", 296740266059SGregory Neil Shapiro (int) strlen(response), (int) (rlen - 1)); 296806f25ae9SGregory Neil Shapiro return; 296906f25ae9SGregory Neil Shapiro } 297006f25ae9SGregory Neil Shapiro 297106f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 297240266059SGregory Neil Shapiro sm_dprintf("%s\n", response); 297340266059SGregory Neil Shapiro if (MilterLogLevel > 8) 297440266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter add: rcpt: %s", response); 2975a7ec597cSGregory Neil Shapiro olderrors = Errors; 297606f25ae9SGregory Neil Shapiro (void) sendtolist(response, NULLADDR, &e->e_sendqueue, 0, e); 2977a7ec597cSGregory Neil Shapiro Errors = olderrors; 297806f25ae9SGregory Neil Shapiro return; 297906f25ae9SGregory Neil Shapiro } 298040266059SGregory Neil Shapiro /* 298106f25ae9SGregory Neil Shapiro ** MILTER_DELRCPT -- Delete the supplied recipient from the message 298206f25ae9SGregory Neil Shapiro ** 298306f25ae9SGregory Neil Shapiro ** Parameters: 298406f25ae9SGregory Neil Shapiro ** response -- encoded form of recipient address. 298506f25ae9SGregory Neil Shapiro ** rlen -- length of response. 298606f25ae9SGregory Neil Shapiro ** e -- current envelope. 298706f25ae9SGregory Neil Shapiro ** 298806f25ae9SGregory Neil Shapiro ** Returns: 298906f25ae9SGregory Neil Shapiro ** none 299006f25ae9SGregory Neil Shapiro */ 299106f25ae9SGregory Neil Shapiro 299206f25ae9SGregory Neil Shapiro static void 299306f25ae9SGregory Neil Shapiro milter_delrcpt(response, rlen, e) 299406f25ae9SGregory Neil Shapiro char *response; 299506f25ae9SGregory Neil Shapiro ssize_t rlen; 299606f25ae9SGregory Neil Shapiro ENVELOPE *e; 299706f25ae9SGregory Neil Shapiro { 299806f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 299940266059SGregory Neil Shapiro sm_dprintf("milter_delrcpt: "); 300006f25ae9SGregory Neil Shapiro 300106f25ae9SGregory Neil Shapiro /* sanity checks */ 300206f25ae9SGregory Neil Shapiro if (response == NULL) 300306f25ae9SGregory Neil Shapiro { 300406f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 300540266059SGregory Neil Shapiro sm_dprintf("NULL response\n"); 300606f25ae9SGregory Neil Shapiro return; 300706f25ae9SGregory Neil Shapiro } 300806f25ae9SGregory Neil Shapiro 300906f25ae9SGregory Neil Shapiro if (*response == '\0' || 301006f25ae9SGregory Neil Shapiro strlen(response) + 1 != (size_t) rlen) 301106f25ae9SGregory Neil Shapiro { 301206f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 301340266059SGregory Neil Shapiro sm_dprintf("didn't follow protocol (total len)\n"); 301406f25ae9SGregory Neil Shapiro return; 301506f25ae9SGregory Neil Shapiro } 301606f25ae9SGregory Neil Shapiro 301706f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 301840266059SGregory Neil Shapiro sm_dprintf("%s\n", response); 301940266059SGregory Neil Shapiro if (MilterLogLevel > 8) 302040266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter delete: rcpt %s", 302140266059SGregory Neil Shapiro response); 302206f25ae9SGregory Neil Shapiro (void) removefromlist(response, &e->e_sendqueue, e); 302306f25ae9SGregory Neil Shapiro return; 302406f25ae9SGregory Neil Shapiro } 302540266059SGregory Neil Shapiro /* 302640266059SGregory Neil Shapiro ** MILTER_REPLBODY -- Replace the current data file with new body 302706f25ae9SGregory Neil Shapiro ** 302806f25ae9SGregory Neil Shapiro ** Parameters: 302906f25ae9SGregory Neil Shapiro ** response -- encoded form of new body. 303006f25ae9SGregory Neil Shapiro ** rlen -- length of response. 303106f25ae9SGregory Neil Shapiro ** newfilter -- if first time called by a new filter 303206f25ae9SGregory Neil Shapiro ** e -- current envelope. 303306f25ae9SGregory Neil Shapiro ** 303406f25ae9SGregory Neil Shapiro ** Returns: 303506f25ae9SGregory Neil Shapiro ** 0 upon success, -1 upon failure 303606f25ae9SGregory Neil Shapiro */ 303706f25ae9SGregory Neil Shapiro 303806f25ae9SGregory Neil Shapiro static int 303906f25ae9SGregory Neil Shapiro milter_replbody(response, rlen, newfilter, e) 304006f25ae9SGregory Neil Shapiro char *response; 304106f25ae9SGregory Neil Shapiro ssize_t rlen; 304206f25ae9SGregory Neil Shapiro bool newfilter; 304306f25ae9SGregory Neil Shapiro ENVELOPE *e; 304406f25ae9SGregory Neil Shapiro { 304506f25ae9SGregory Neil Shapiro static char prevchar; 304606f25ae9SGregory Neil Shapiro int i; 304706f25ae9SGregory Neil Shapiro 304806f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 304940266059SGregory Neil Shapiro sm_dprintf("milter_replbody\n"); 305006f25ae9SGregory Neil Shapiro 305140266059SGregory Neil Shapiro /* If a new filter, reset previous character and truncate data file */ 305206f25ae9SGregory Neil Shapiro if (newfilter) 305306f25ae9SGregory Neil Shapiro { 3054605302a5SGregory Neil Shapiro off_t prevsize; 305506f25ae9SGregory Neil Shapiro char dfname[MAXPATHLEN]; 305606f25ae9SGregory Neil Shapiro 305740266059SGregory Neil Shapiro (void) sm_strlcpy(dfname, queuename(e, DATAFL_LETTER), 305840266059SGregory Neil Shapiro sizeof dfname); 305906f25ae9SGregory Neil Shapiro 306006f25ae9SGregory Neil Shapiro /* Reset prevchar */ 306106f25ae9SGregory Neil Shapiro prevchar = '\0'; 306206f25ae9SGregory Neil Shapiro 306340266059SGregory Neil Shapiro /* Get the current data file information */ 3064605302a5SGregory Neil Shapiro prevsize = sm_io_getinfo(e->e_dfp, SM_IO_WHAT_SIZE, NULL); 3065605302a5SGregory Neil Shapiro if (prevsize < 0) 3066605302a5SGregory Neil Shapiro prevsize = 0; 306706f25ae9SGregory Neil Shapiro 306840266059SGregory Neil Shapiro /* truncate current data file */ 306940266059SGregory Neil Shapiro if (sm_io_getinfo(e->e_dfp, SM_IO_WHAT_ISTYPE, BF_FILE_TYPE)) 307006f25ae9SGregory Neil Shapiro { 307140266059SGregory Neil Shapiro if (sm_io_setinfo(e->e_dfp, SM_BF_TRUNCATE, NULL) < 0) 307240266059SGregory Neil Shapiro { 307340266059SGregory Neil Shapiro MILTER_DF_ERROR("milter_replbody: sm_io truncate %s: %s"); 307406f25ae9SGregory Neil Shapiro return -1; 307506f25ae9SGregory Neil Shapiro } 307640266059SGregory Neil Shapiro } 307706f25ae9SGregory Neil Shapiro else 307806f25ae9SGregory Neil Shapiro { 307940266059SGregory Neil Shapiro int err; 308040266059SGregory Neil Shapiro 308140266059SGregory Neil Shapiro err = sm_io_error(e->e_dfp); 308240266059SGregory Neil Shapiro (void) sm_io_flush(e->e_dfp, SM_TIME_DEFAULT); 308340266059SGregory Neil Shapiro 308440266059SGregory Neil Shapiro /* 308540266059SGregory Neil Shapiro ** Clear error if tried to fflush() 308640266059SGregory Neil Shapiro ** a read-only file pointer and 308740266059SGregory Neil Shapiro ** there wasn't a previous error. 308840266059SGregory Neil Shapiro */ 308940266059SGregory Neil Shapiro 309040266059SGregory Neil Shapiro if (err == 0) 309140266059SGregory Neil Shapiro sm_io_clearerr(e->e_dfp); 309240266059SGregory Neil Shapiro 309340266059SGregory Neil Shapiro /* errno is set implicitly by fseek() before return */ 309440266059SGregory Neil Shapiro err = sm_io_seek(e->e_dfp, SM_TIME_DEFAULT, 309540266059SGregory Neil Shapiro 0, SEEK_SET); 30966a2f2ff3SGregory Neil Shapiro if (err < 0) 30976a2f2ff3SGregory Neil Shapiro { 30986a2f2ff3SGregory Neil Shapiro MILTER_DF_ERROR("milter_replbody: sm_io_seek %s: %s"); 30996a2f2ff3SGregory Neil Shapiro return -1; 31006a2f2ff3SGregory Neil Shapiro } 31016a2f2ff3SGregory Neil Shapiro # if NOFTRUNCATE 31026a2f2ff3SGregory Neil Shapiro /* XXX: Not much we can do except rewind it */ 31036a2f2ff3SGregory Neil Shapiro errno = EINVAL; 31046a2f2ff3SGregory Neil Shapiro MILTER_DF_ERROR("milter_replbody: ftruncate not available on this platform (%s:%s)"); 31056a2f2ff3SGregory Neil Shapiro return -1; 310640266059SGregory Neil Shapiro # else /* NOFTRUNCATE */ 310740266059SGregory Neil Shapiro err = ftruncate(sm_io_getinfo(e->e_dfp, 310840266059SGregory Neil Shapiro SM_IO_WHAT_FD, NULL), 310940266059SGregory Neil Shapiro 0); 311040266059SGregory Neil Shapiro if (err < 0) 311140266059SGregory Neil Shapiro { 311240266059SGregory Neil Shapiro MILTER_DF_ERROR("milter_replbody: sm_io ftruncate %s: %s"); 311340266059SGregory Neil Shapiro return -1; 311440266059SGregory Neil Shapiro } 31156a2f2ff3SGregory Neil Shapiro # endif /* NOFTRUNCATE */ 311640266059SGregory Neil Shapiro } 311740266059SGregory Neil Shapiro 311806f25ae9SGregory Neil Shapiro if (prevsize > e->e_msgsize) 311906f25ae9SGregory Neil Shapiro e->e_msgsize = 0; 312006f25ae9SGregory Neil Shapiro else 312106f25ae9SGregory Neil Shapiro e->e_msgsize -= prevsize; 312206f25ae9SGregory Neil Shapiro } 312340266059SGregory Neil Shapiro 312440266059SGregory Neil Shapiro if (newfilter && MilterLogLevel > 8) 312540266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter message: body replaced"); 312606f25ae9SGregory Neil Shapiro 312706f25ae9SGregory Neil Shapiro if (response == NULL) 312806f25ae9SGregory Neil Shapiro { 312906f25ae9SGregory Neil Shapiro /* Flush the buffered '\r' */ 313006f25ae9SGregory Neil Shapiro if (prevchar == '\r') 313106f25ae9SGregory Neil Shapiro { 313240266059SGregory Neil Shapiro (void) sm_io_putc(e->e_dfp, SM_TIME_DEFAULT, prevchar); 313306f25ae9SGregory Neil Shapiro e->e_msgsize++; 313406f25ae9SGregory Neil Shapiro } 313506f25ae9SGregory Neil Shapiro return 0; 313606f25ae9SGregory Neil Shapiro } 313706f25ae9SGregory Neil Shapiro 313806f25ae9SGregory Neil Shapiro for (i = 0; i < rlen; i++) 313906f25ae9SGregory Neil Shapiro { 314006f25ae9SGregory Neil Shapiro /* Buffered char from last chunk */ 314106f25ae9SGregory Neil Shapiro if (i == 0 && prevchar == '\r') 314206f25ae9SGregory Neil Shapiro { 314306f25ae9SGregory Neil Shapiro /* Not CRLF, output prevchar */ 314406f25ae9SGregory Neil Shapiro if (response[i] != '\n') 314506f25ae9SGregory Neil Shapiro { 314640266059SGregory Neil Shapiro (void) sm_io_putc(e->e_dfp, SM_TIME_DEFAULT, 314740266059SGregory Neil Shapiro prevchar); 314806f25ae9SGregory Neil Shapiro e->e_msgsize++; 314906f25ae9SGregory Neil Shapiro } 315006f25ae9SGregory Neil Shapiro prevchar = '\0'; 315106f25ae9SGregory Neil Shapiro } 315206f25ae9SGregory Neil Shapiro 315306f25ae9SGregory Neil Shapiro /* Turn CRLF into LF */ 315406f25ae9SGregory Neil Shapiro if (response[i] == '\r') 315506f25ae9SGregory Neil Shapiro { 315606f25ae9SGregory Neil Shapiro /* check if at end of chunk */ 315706f25ae9SGregory Neil Shapiro if (i + 1 < rlen) 315806f25ae9SGregory Neil Shapiro { 315906f25ae9SGregory Neil Shapiro /* If LF, strip CR */ 316006f25ae9SGregory Neil Shapiro if (response[i + 1] == '\n') 316106f25ae9SGregory Neil Shapiro i++; 316206f25ae9SGregory Neil Shapiro } 316306f25ae9SGregory Neil Shapiro else 316406f25ae9SGregory Neil Shapiro { 316506f25ae9SGregory Neil Shapiro /* check next chunk */ 316606f25ae9SGregory Neil Shapiro prevchar = '\r'; 316706f25ae9SGregory Neil Shapiro continue; 316806f25ae9SGregory Neil Shapiro } 316906f25ae9SGregory Neil Shapiro } 317040266059SGregory Neil Shapiro (void) sm_io_putc(e->e_dfp, SM_TIME_DEFAULT, response[i]); 317106f25ae9SGregory Neil Shapiro e->e_msgsize++; 317206f25ae9SGregory Neil Shapiro } 317306f25ae9SGregory Neil Shapiro return 0; 317406f25ae9SGregory Neil Shapiro } 317506f25ae9SGregory Neil Shapiro 317606f25ae9SGregory Neil Shapiro /* 317706f25ae9SGregory Neil Shapiro ** MTA callouts 317806f25ae9SGregory Neil Shapiro */ 317906f25ae9SGregory Neil Shapiro 318040266059SGregory Neil Shapiro /* 318106f25ae9SGregory Neil Shapiro ** MILTER_INIT -- open and negotiate with all of the filters 318206f25ae9SGregory Neil Shapiro ** 318306f25ae9SGregory Neil Shapiro ** Parameters: 318406f25ae9SGregory Neil Shapiro ** e -- current envelope. 318506f25ae9SGregory Neil Shapiro ** state -- return state from response. 318606f25ae9SGregory Neil Shapiro ** 318706f25ae9SGregory Neil Shapiro ** Returns: 318840266059SGregory Neil Shapiro ** true iff at least one filter is active 318906f25ae9SGregory Neil Shapiro */ 319006f25ae9SGregory Neil Shapiro 319106f25ae9SGregory Neil Shapiro /* ARGSUSED */ 319240266059SGregory Neil Shapiro bool 319306f25ae9SGregory Neil Shapiro milter_init(e, state) 319406f25ae9SGregory Neil Shapiro ENVELOPE *e; 319506f25ae9SGregory Neil Shapiro char *state; 319606f25ae9SGregory Neil Shapiro { 319706f25ae9SGregory Neil Shapiro int i; 319806f25ae9SGregory Neil Shapiro 319906f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 320040266059SGregory Neil Shapiro sm_dprintf("milter_init\n"); 320106f25ae9SGregory Neil Shapiro 320206f25ae9SGregory Neil Shapiro *state = SMFIR_CONTINUE; 320340266059SGregory Neil Shapiro if (InputFilters[0] == NULL) 320440266059SGregory Neil Shapiro { 320540266059SGregory Neil Shapiro if (MilterLogLevel > 10) 320640266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, 320740266059SGregory Neil Shapiro "Milter: no active filter"); 320840266059SGregory Neil Shapiro return false; 320940266059SGregory Neil Shapiro } 321040266059SGregory Neil Shapiro 321106f25ae9SGregory Neil Shapiro for (i = 0; InputFilters[i] != NULL; i++) 321206f25ae9SGregory Neil Shapiro { 321306f25ae9SGregory Neil Shapiro struct milter *m = InputFilters[i]; 321406f25ae9SGregory Neil Shapiro 321540266059SGregory Neil Shapiro m->mf_sock = milter_open(m, false, e); 321606f25ae9SGregory Neil Shapiro if (m->mf_state == SMFS_ERROR) 321706f25ae9SGregory Neil Shapiro { 32185ef517c0SGregory Neil Shapiro MILTER_CHECK_ERROR(true, continue); 321906f25ae9SGregory Neil Shapiro break; 322006f25ae9SGregory Neil Shapiro } 322106f25ae9SGregory Neil Shapiro 322206f25ae9SGregory Neil Shapiro if (m->mf_sock < 0 || 322306f25ae9SGregory Neil Shapiro milter_negotiate(m, e) < 0 || 322406f25ae9SGregory Neil Shapiro m->mf_state == SMFS_ERROR) 322506f25ae9SGregory Neil Shapiro { 322606f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 322740266059SGregory Neil Shapiro sm_dprintf("milter_init(%s): failed to %s\n", 322806f25ae9SGregory Neil Shapiro m->mf_name, 322940266059SGregory Neil Shapiro m->mf_sock < 0 ? "open" : 323040266059SGregory Neil Shapiro "negotiate"); 323140266059SGregory Neil Shapiro if (MilterLogLevel > 0) 323240266059SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 323340266059SGregory Neil Shapiro "Milter (%s): init failed to %s", 323440266059SGregory Neil Shapiro m->mf_name, 323540266059SGregory Neil Shapiro m->mf_sock < 0 ? "open" : 323640266059SGregory Neil Shapiro "negotiate"); 323706f25ae9SGregory Neil Shapiro 323806f25ae9SGregory Neil Shapiro /* if negotation failure, close socket */ 323940266059SGregory Neil Shapiro milter_error(m, e); 32405ef517c0SGregory Neil Shapiro MILTER_CHECK_ERROR(true, continue); 3241e92d3f3fSGregory Neil Shapiro continue; 324206f25ae9SGregory Neil Shapiro } 324340266059SGregory Neil Shapiro if (MilterLogLevel > 9) 324440266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, 324540266059SGregory Neil Shapiro "Milter (%s): init success to %s", 324640266059SGregory Neil Shapiro m->mf_name, 324740266059SGregory Neil Shapiro m->mf_sock < 0 ? "open" : "negotiate"); 324806f25ae9SGregory Neil Shapiro } 324906f25ae9SGregory Neil Shapiro 325006f25ae9SGregory Neil Shapiro /* 325106f25ae9SGregory Neil Shapiro ** If something temp/perm failed with one of the filters, 325206f25ae9SGregory Neil Shapiro ** we won't be using any of them, so clear any existing 325306f25ae9SGregory Neil Shapiro ** connections. 325406f25ae9SGregory Neil Shapiro */ 325506f25ae9SGregory Neil Shapiro 325606f25ae9SGregory Neil Shapiro if (*state != SMFIR_CONTINUE) 325706f25ae9SGregory Neil Shapiro milter_quit(e); 325840266059SGregory Neil Shapiro 325940266059SGregory Neil Shapiro return true; 326006f25ae9SGregory Neil Shapiro } 326140266059SGregory Neil Shapiro /* 326206f25ae9SGregory Neil Shapiro ** MILTER_CONNECT -- send connection info to milter filters 326306f25ae9SGregory Neil Shapiro ** 326406f25ae9SGregory Neil Shapiro ** Parameters: 326506f25ae9SGregory Neil Shapiro ** hostname -- hostname of remote machine. 326606f25ae9SGregory Neil Shapiro ** addr -- address of remote machine. 326706f25ae9SGregory Neil Shapiro ** e -- current envelope. 326806f25ae9SGregory Neil Shapiro ** state -- return state from response. 326906f25ae9SGregory Neil Shapiro ** 327006f25ae9SGregory Neil Shapiro ** Returns: 327106f25ae9SGregory Neil Shapiro ** response string (may be NULL) 327206f25ae9SGregory Neil Shapiro */ 327306f25ae9SGregory Neil Shapiro 327406f25ae9SGregory Neil Shapiro char * 327506f25ae9SGregory Neil Shapiro milter_connect(hostname, addr, e, state) 327606f25ae9SGregory Neil Shapiro char *hostname; 327706f25ae9SGregory Neil Shapiro SOCKADDR addr; 327806f25ae9SGregory Neil Shapiro ENVELOPE *e; 327906f25ae9SGregory Neil Shapiro char *state; 328006f25ae9SGregory Neil Shapiro { 328106f25ae9SGregory Neil Shapiro char family; 328240266059SGregory Neil Shapiro unsigned short port; 328306f25ae9SGregory Neil Shapiro char *buf, *bp; 328406f25ae9SGregory Neil Shapiro char *response; 328506f25ae9SGregory Neil Shapiro char *sockinfo = NULL; 328606f25ae9SGregory Neil Shapiro ssize_t s; 328706f25ae9SGregory Neil Shapiro # if NETINET6 328806f25ae9SGregory Neil Shapiro char buf6[INET6_ADDRSTRLEN]; 328906f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 329006f25ae9SGregory Neil Shapiro 329106f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 329240266059SGregory Neil Shapiro sm_dprintf("milter_connect(%s)\n", hostname); 329340266059SGregory Neil Shapiro if (MilterLogLevel > 9) 329440266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter: connect to filters"); 329506f25ae9SGregory Neil Shapiro 329606f25ae9SGregory Neil Shapiro /* gather data */ 329706f25ae9SGregory Neil Shapiro switch (addr.sa.sa_family) 329806f25ae9SGregory Neil Shapiro { 329906f25ae9SGregory Neil Shapiro # if NETUNIX 330006f25ae9SGregory Neil Shapiro case AF_UNIX: 330106f25ae9SGregory Neil Shapiro family = SMFIA_UNIX; 330206f25ae9SGregory Neil Shapiro port = htons(0); 330306f25ae9SGregory Neil Shapiro sockinfo = addr.sunix.sun_path; 330406f25ae9SGregory Neil Shapiro break; 330506f25ae9SGregory Neil Shapiro # endif /* NETUNIX */ 330606f25ae9SGregory Neil Shapiro 330706f25ae9SGregory Neil Shapiro # if NETINET 330806f25ae9SGregory Neil Shapiro case AF_INET: 330906f25ae9SGregory Neil Shapiro family = SMFIA_INET; 3310605302a5SGregory Neil Shapiro port = addr.sin.sin_port; 331106f25ae9SGregory Neil Shapiro sockinfo = (char *) inet_ntoa(addr.sin.sin_addr); 331206f25ae9SGregory Neil Shapiro break; 331306f25ae9SGregory Neil Shapiro # endif /* NETINET */ 331406f25ae9SGregory Neil Shapiro 331506f25ae9SGregory Neil Shapiro # if NETINET6 331606f25ae9SGregory Neil Shapiro case AF_INET6: 331713058a91SGregory Neil Shapiro if (IN6_IS_ADDR_V4MAPPED(&addr.sin6.sin6_addr)) 331813058a91SGregory Neil Shapiro family = SMFIA_INET; 331913058a91SGregory Neil Shapiro else 332006f25ae9SGregory Neil Shapiro family = SMFIA_INET6; 3321605302a5SGregory Neil Shapiro port = addr.sin6.sin6_port; 332206f25ae9SGregory Neil Shapiro sockinfo = anynet_ntop(&addr.sin6.sin6_addr, buf6, 332306f25ae9SGregory Neil Shapiro sizeof buf6); 332406f25ae9SGregory Neil Shapiro if (sockinfo == NULL) 332506f25ae9SGregory Neil Shapiro sockinfo = ""; 332606f25ae9SGregory Neil Shapiro break; 332706f25ae9SGregory Neil Shapiro # endif /* NETINET6 */ 332806f25ae9SGregory Neil Shapiro 332906f25ae9SGregory Neil Shapiro default: 333006f25ae9SGregory Neil Shapiro family = SMFIA_UNKNOWN; 333106f25ae9SGregory Neil Shapiro break; 333206f25ae9SGregory Neil Shapiro } 333306f25ae9SGregory Neil Shapiro 333406f25ae9SGregory Neil Shapiro s = strlen(hostname) + 1 + sizeof(family); 333506f25ae9SGregory Neil Shapiro if (family != SMFIA_UNKNOWN) 333606f25ae9SGregory Neil Shapiro s += sizeof(port) + strlen(sockinfo) + 1; 333706f25ae9SGregory Neil Shapiro 333806f25ae9SGregory Neil Shapiro buf = (char *) xalloc(s); 333906f25ae9SGregory Neil Shapiro bp = buf; 334006f25ae9SGregory Neil Shapiro 334106f25ae9SGregory Neil Shapiro /* put together data */ 334206f25ae9SGregory Neil Shapiro (void) memcpy(bp, hostname, strlen(hostname)); 334306f25ae9SGregory Neil Shapiro bp += strlen(hostname); 334406f25ae9SGregory Neil Shapiro *bp++ = '\0'; 334506f25ae9SGregory Neil Shapiro (void) memcpy(bp, &family, sizeof family); 334606f25ae9SGregory Neil Shapiro bp += sizeof family; 334706f25ae9SGregory Neil Shapiro if (family != SMFIA_UNKNOWN) 334806f25ae9SGregory Neil Shapiro { 334906f25ae9SGregory Neil Shapiro (void) memcpy(bp, &port, sizeof port); 335006f25ae9SGregory Neil Shapiro bp += sizeof port; 335106f25ae9SGregory Neil Shapiro 335206f25ae9SGregory Neil Shapiro /* include trailing '\0' */ 335306f25ae9SGregory Neil Shapiro (void) memcpy(bp, sockinfo, strlen(sockinfo) + 1); 335406f25ae9SGregory Neil Shapiro } 335506f25ae9SGregory Neil Shapiro 335606f25ae9SGregory Neil Shapiro response = milter_command(SMFIC_CONNECT, buf, s, 335706f25ae9SGregory Neil Shapiro MilterConnectMacros, e, state); 335840266059SGregory Neil Shapiro sm_free(buf); /* XXX */ 335906f25ae9SGregory Neil Shapiro 336006f25ae9SGregory Neil Shapiro /* 336106f25ae9SGregory Neil Shapiro ** If this message connection is done for, 336206f25ae9SGregory Neil Shapiro ** close the filters. 336306f25ae9SGregory Neil Shapiro */ 336406f25ae9SGregory Neil Shapiro 336506f25ae9SGregory Neil Shapiro if (*state != SMFIR_CONTINUE) 336640266059SGregory Neil Shapiro { 336740266059SGregory Neil Shapiro if (MilterLogLevel > 9) 336840266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter: connect, ending"); 336906f25ae9SGregory Neil Shapiro milter_quit(e); 337040266059SGregory Neil Shapiro } 337106f25ae9SGregory Neil Shapiro else 337206f25ae9SGregory Neil Shapiro milter_per_connection_check(e); 337306f25ae9SGregory Neil Shapiro 337406f25ae9SGregory Neil Shapiro /* 337506f25ae9SGregory Neil Shapiro ** SMFIR_REPLYCODE can't work with connect due to 337606f25ae9SGregory Neil Shapiro ** the requirements of SMTP. Therefore, ignore the 337706f25ae9SGregory Neil Shapiro ** reply code text but keep the state it would reflect. 337806f25ae9SGregory Neil Shapiro */ 337906f25ae9SGregory Neil Shapiro 338006f25ae9SGregory Neil Shapiro if (*state == SMFIR_REPLYCODE) 338106f25ae9SGregory Neil Shapiro { 338206f25ae9SGregory Neil Shapiro if (response != NULL && 338306f25ae9SGregory Neil Shapiro *response == '4') 338413bd1963SGregory Neil Shapiro { 338513bd1963SGregory Neil Shapiro if (strncmp(response, "421 ", 4) == 0) 338613bd1963SGregory Neil Shapiro *state = SMFIR_SHUTDOWN; 338713bd1963SGregory Neil Shapiro else 338806f25ae9SGregory Neil Shapiro *state = SMFIR_TEMPFAIL; 338913bd1963SGregory Neil Shapiro } 339006f25ae9SGregory Neil Shapiro else 339106f25ae9SGregory Neil Shapiro *state = SMFIR_REJECT; 339206f25ae9SGregory Neil Shapiro if (response != NULL) 339306f25ae9SGregory Neil Shapiro { 339440266059SGregory Neil Shapiro sm_free(response); /* XXX */ 339506f25ae9SGregory Neil Shapiro response = NULL; 339606f25ae9SGregory Neil Shapiro } 339706f25ae9SGregory Neil Shapiro } 339806f25ae9SGregory Neil Shapiro return response; 339906f25ae9SGregory Neil Shapiro } 340040266059SGregory Neil Shapiro /* 340106f25ae9SGregory Neil Shapiro ** MILTER_HELO -- send SMTP HELO/EHLO command info to milter filters 340206f25ae9SGregory Neil Shapiro ** 340306f25ae9SGregory Neil Shapiro ** Parameters: 340406f25ae9SGregory Neil Shapiro ** helo -- argument to SMTP HELO/EHLO command. 340506f25ae9SGregory Neil Shapiro ** e -- current envelope. 340606f25ae9SGregory Neil Shapiro ** state -- return state from response. 340706f25ae9SGregory Neil Shapiro ** 340806f25ae9SGregory Neil Shapiro ** Returns: 340906f25ae9SGregory Neil Shapiro ** response string (may be NULL) 341006f25ae9SGregory Neil Shapiro */ 341106f25ae9SGregory Neil Shapiro 341206f25ae9SGregory Neil Shapiro char * 341306f25ae9SGregory Neil Shapiro milter_helo(helo, e, state) 341406f25ae9SGregory Neil Shapiro char *helo; 341506f25ae9SGregory Neil Shapiro ENVELOPE *e; 341606f25ae9SGregory Neil Shapiro char *state; 341706f25ae9SGregory Neil Shapiro { 3418602a2b1bSGregory Neil Shapiro int i; 341906f25ae9SGregory Neil Shapiro char *response; 342006f25ae9SGregory Neil Shapiro 342106f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 342240266059SGregory Neil Shapiro sm_dprintf("milter_helo(%s)\n", helo); 342306f25ae9SGregory Neil Shapiro 342440266059SGregory Neil Shapiro /* HELO/EHLO can come at any point */ 3425602a2b1bSGregory Neil Shapiro for (i = 0; InputFilters[i] != NULL; i++) 3426602a2b1bSGregory Neil Shapiro { 3427602a2b1bSGregory Neil Shapiro struct milter *m = InputFilters[i]; 3428602a2b1bSGregory Neil Shapiro 3429602a2b1bSGregory Neil Shapiro switch (m->mf_state) 3430602a2b1bSGregory Neil Shapiro { 3431602a2b1bSGregory Neil Shapiro case SMFS_INMSG: 3432602a2b1bSGregory Neil Shapiro /* abort in message filters */ 3433602a2b1bSGregory Neil Shapiro milter_abort_filter(m, e); 3434602a2b1bSGregory Neil Shapiro /* FALLTHROUGH */ 3435602a2b1bSGregory Neil Shapiro 3436602a2b1bSGregory Neil Shapiro case SMFS_DONE: 3437602a2b1bSGregory Neil Shapiro /* reset done filters */ 3438602a2b1bSGregory Neil Shapiro m->mf_state = SMFS_OPEN; 3439602a2b1bSGregory Neil Shapiro break; 3440602a2b1bSGregory Neil Shapiro } 3441602a2b1bSGregory Neil Shapiro } 3442602a2b1bSGregory Neil Shapiro 344306f25ae9SGregory Neil Shapiro response = milter_command(SMFIC_HELO, helo, strlen(helo) + 1, 344406f25ae9SGregory Neil Shapiro MilterHeloMacros, e, state); 344506f25ae9SGregory Neil Shapiro milter_per_connection_check(e); 344606f25ae9SGregory Neil Shapiro return response; 344706f25ae9SGregory Neil Shapiro } 344840266059SGregory Neil Shapiro /* 344906f25ae9SGregory Neil Shapiro ** MILTER_ENVFROM -- send SMTP MAIL command info to milter filters 345006f25ae9SGregory Neil Shapiro ** 345106f25ae9SGregory Neil Shapiro ** Parameters: 345206f25ae9SGregory Neil Shapiro ** args -- SMTP MAIL command args (args[0] == sender). 345306f25ae9SGregory Neil Shapiro ** e -- current envelope. 345406f25ae9SGregory Neil Shapiro ** state -- return state from response. 345506f25ae9SGregory Neil Shapiro ** 345606f25ae9SGregory Neil Shapiro ** Returns: 345706f25ae9SGregory Neil Shapiro ** response string (may be NULL) 345806f25ae9SGregory Neil Shapiro */ 345906f25ae9SGregory Neil Shapiro 346006f25ae9SGregory Neil Shapiro char * 346106f25ae9SGregory Neil Shapiro milter_envfrom(args, e, state) 346206f25ae9SGregory Neil Shapiro char **args; 346306f25ae9SGregory Neil Shapiro ENVELOPE *e; 346406f25ae9SGregory Neil Shapiro char *state; 346506f25ae9SGregory Neil Shapiro { 346606f25ae9SGregory Neil Shapiro int i; 346706f25ae9SGregory Neil Shapiro char *buf, *bp; 346806f25ae9SGregory Neil Shapiro char *response; 346906f25ae9SGregory Neil Shapiro ssize_t s; 347006f25ae9SGregory Neil Shapiro 347106f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 347206f25ae9SGregory Neil Shapiro { 347340266059SGregory Neil Shapiro sm_dprintf("milter_envfrom:"); 347406f25ae9SGregory Neil Shapiro for (i = 0; args[i] != NULL; i++) 347540266059SGregory Neil Shapiro sm_dprintf(" %s", args[i]); 347640266059SGregory Neil Shapiro sm_dprintf("\n"); 347706f25ae9SGregory Neil Shapiro } 347806f25ae9SGregory Neil Shapiro 347906f25ae9SGregory Neil Shapiro /* sanity check */ 348006f25ae9SGregory Neil Shapiro if (args[0] == NULL) 348106f25ae9SGregory Neil Shapiro { 348206f25ae9SGregory Neil Shapiro *state = SMFIR_REJECT; 348340266059SGregory Neil Shapiro if (MilterLogLevel > 10) 348440266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, 348540266059SGregory Neil Shapiro "Milter: reject, no sender"); 348606f25ae9SGregory Neil Shapiro return NULL; 348706f25ae9SGregory Neil Shapiro } 348806f25ae9SGregory Neil Shapiro 348906f25ae9SGregory Neil Shapiro /* new message, so ... */ 349006f25ae9SGregory Neil Shapiro for (i = 0; InputFilters[i] != NULL; i++) 349106f25ae9SGregory Neil Shapiro { 349206f25ae9SGregory Neil Shapiro struct milter *m = InputFilters[i]; 349306f25ae9SGregory Neil Shapiro 349406f25ae9SGregory Neil Shapiro switch (m->mf_state) 349506f25ae9SGregory Neil Shapiro { 349606f25ae9SGregory Neil Shapiro case SMFS_INMSG: 349706f25ae9SGregory Neil Shapiro /* abort in message filters */ 349806f25ae9SGregory Neil Shapiro milter_abort_filter(m, e); 349906f25ae9SGregory Neil Shapiro /* FALLTHROUGH */ 350006f25ae9SGregory Neil Shapiro 350106f25ae9SGregory Neil Shapiro case SMFS_DONE: 350206f25ae9SGregory Neil Shapiro /* reset done filters */ 350306f25ae9SGregory Neil Shapiro m->mf_state = SMFS_OPEN; 350406f25ae9SGregory Neil Shapiro break; 350506f25ae9SGregory Neil Shapiro } 350606f25ae9SGregory Neil Shapiro } 350706f25ae9SGregory Neil Shapiro 350806f25ae9SGregory Neil Shapiro /* put together data */ 350906f25ae9SGregory Neil Shapiro s = 0; 351006f25ae9SGregory Neil Shapiro for (i = 0; args[i] != NULL; i++) 351106f25ae9SGregory Neil Shapiro s += strlen(args[i]) + 1; 351240266059SGregory Neil Shapiro 351340266059SGregory Neil Shapiro if (s < 0) 351440266059SGregory Neil Shapiro { 351540266059SGregory Neil Shapiro *state = SMFIR_TEMPFAIL; 351640266059SGregory Neil Shapiro return NULL; 351740266059SGregory Neil Shapiro } 351840266059SGregory Neil Shapiro 351906f25ae9SGregory Neil Shapiro buf = (char *) xalloc(s); 352006f25ae9SGregory Neil Shapiro bp = buf; 352106f25ae9SGregory Neil Shapiro for (i = 0; args[i] != NULL; i++) 352206f25ae9SGregory Neil Shapiro { 352340266059SGregory Neil Shapiro (void) sm_strlcpy(bp, args[i], s - (bp - buf)); 352406f25ae9SGregory Neil Shapiro bp += strlen(bp) + 1; 352506f25ae9SGregory Neil Shapiro } 352606f25ae9SGregory Neil Shapiro 352740266059SGregory Neil Shapiro if (MilterLogLevel > 14) 352840266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter: senders: %s", buf); 352940266059SGregory Neil Shapiro 353006f25ae9SGregory Neil Shapiro /* send it over */ 353106f25ae9SGregory Neil Shapiro response = milter_command(SMFIC_MAIL, buf, s, 353206f25ae9SGregory Neil Shapiro MilterEnvFromMacros, e, state); 353340266059SGregory Neil Shapiro sm_free(buf); /* XXX */ 353406f25ae9SGregory Neil Shapiro 353506f25ae9SGregory Neil Shapiro /* 353606f25ae9SGregory Neil Shapiro ** If filter rejects/discards a per message command, 353706f25ae9SGregory Neil Shapiro ** abort the other filters since we are done with the 353806f25ae9SGregory Neil Shapiro ** current message. 353906f25ae9SGregory Neil Shapiro */ 354006f25ae9SGregory Neil Shapiro 354106f25ae9SGregory Neil Shapiro MILTER_CHECK_DONE_MSG(); 354240266059SGregory Neil Shapiro if (MilterLogLevel > 10 && *state == SMFIR_REJECT) 354340266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter: reject, senders"); 354406f25ae9SGregory Neil Shapiro return response; 354506f25ae9SGregory Neil Shapiro } 3546e92d3f3fSGregory Neil Shapiro 354740266059SGregory Neil Shapiro /* 354806f25ae9SGregory Neil Shapiro ** MILTER_ENVRCPT -- send SMTP RCPT command info to milter filters 354906f25ae9SGregory Neil Shapiro ** 355006f25ae9SGregory Neil Shapiro ** Parameters: 355106f25ae9SGregory Neil Shapiro ** args -- SMTP MAIL command args (args[0] == recipient). 355206f25ae9SGregory Neil Shapiro ** e -- current envelope. 355306f25ae9SGregory Neil Shapiro ** state -- return state from response. 355406f25ae9SGregory Neil Shapiro ** 355506f25ae9SGregory Neil Shapiro ** Returns: 355606f25ae9SGregory Neil Shapiro ** response string (may be NULL) 355706f25ae9SGregory Neil Shapiro */ 355806f25ae9SGregory Neil Shapiro 355906f25ae9SGregory Neil Shapiro char * 356006f25ae9SGregory Neil Shapiro milter_envrcpt(args, e, state) 356106f25ae9SGregory Neil Shapiro char **args; 356206f25ae9SGregory Neil Shapiro ENVELOPE *e; 356306f25ae9SGregory Neil Shapiro char *state; 356406f25ae9SGregory Neil Shapiro { 356506f25ae9SGregory Neil Shapiro int i; 356606f25ae9SGregory Neil Shapiro char *buf, *bp; 356706f25ae9SGregory Neil Shapiro char *response; 356806f25ae9SGregory Neil Shapiro ssize_t s; 356906f25ae9SGregory Neil Shapiro 357006f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 357106f25ae9SGregory Neil Shapiro { 357240266059SGregory Neil Shapiro sm_dprintf("milter_envrcpt:"); 357306f25ae9SGregory Neil Shapiro for (i = 0; args[i] != NULL; i++) 357440266059SGregory Neil Shapiro sm_dprintf(" %s", args[i]); 357540266059SGregory Neil Shapiro sm_dprintf("\n"); 357606f25ae9SGregory Neil Shapiro } 357706f25ae9SGregory Neil Shapiro 357806f25ae9SGregory Neil Shapiro /* sanity check */ 357906f25ae9SGregory Neil Shapiro if (args[0] == NULL) 358006f25ae9SGregory Neil Shapiro { 358106f25ae9SGregory Neil Shapiro *state = SMFIR_REJECT; 358240266059SGregory Neil Shapiro if (MilterLogLevel > 10) 358340266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter: reject, no rcpt"); 358406f25ae9SGregory Neil Shapiro return NULL; 358506f25ae9SGregory Neil Shapiro } 358606f25ae9SGregory Neil Shapiro 358706f25ae9SGregory Neil Shapiro /* put together data */ 358806f25ae9SGregory Neil Shapiro s = 0; 358906f25ae9SGregory Neil Shapiro for (i = 0; args[i] != NULL; i++) 359006f25ae9SGregory Neil Shapiro s += strlen(args[i]) + 1; 359140266059SGregory Neil Shapiro 359240266059SGregory Neil Shapiro if (s < 0) 359340266059SGregory Neil Shapiro { 359440266059SGregory Neil Shapiro *state = SMFIR_TEMPFAIL; 359540266059SGregory Neil Shapiro return NULL; 359640266059SGregory Neil Shapiro } 359740266059SGregory Neil Shapiro 359806f25ae9SGregory Neil Shapiro buf = (char *) xalloc(s); 359906f25ae9SGregory Neil Shapiro bp = buf; 360006f25ae9SGregory Neil Shapiro for (i = 0; args[i] != NULL; i++) 360106f25ae9SGregory Neil Shapiro { 360240266059SGregory Neil Shapiro (void) sm_strlcpy(bp, args[i], s - (bp - buf)); 360306f25ae9SGregory Neil Shapiro bp += strlen(bp) + 1; 360406f25ae9SGregory Neil Shapiro } 360506f25ae9SGregory Neil Shapiro 360640266059SGregory Neil Shapiro if (MilterLogLevel > 14) 360740266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter: rcpts: %s", buf); 360840266059SGregory Neil Shapiro 360906f25ae9SGregory Neil Shapiro /* send it over */ 361006f25ae9SGregory Neil Shapiro response = milter_command(SMFIC_RCPT, buf, s, 361106f25ae9SGregory Neil Shapiro MilterEnvRcptMacros, e, state); 361240266059SGregory Neil Shapiro sm_free(buf); /* XXX */ 361306f25ae9SGregory Neil Shapiro return response; 361406f25ae9SGregory Neil Shapiro } 3615e92d3f3fSGregory Neil Shapiro 3616e92d3f3fSGregory Neil Shapiro #if SMFI_VERSION > 3 3617e92d3f3fSGregory Neil Shapiro /* 3618e92d3f3fSGregory Neil Shapiro ** MILTER_DATA_CMD -- send SMTP DATA command info to milter filters 3619e92d3f3fSGregory Neil Shapiro ** 3620e92d3f3fSGregory Neil Shapiro ** Parameters: 3621e92d3f3fSGregory Neil Shapiro ** e -- current envelope. 3622e92d3f3fSGregory Neil Shapiro ** state -- return state from response. 3623e92d3f3fSGregory Neil Shapiro ** 3624e92d3f3fSGregory Neil Shapiro ** Returns: 3625e92d3f3fSGregory Neil Shapiro ** response string (may be NULL) 3626e92d3f3fSGregory Neil Shapiro */ 3627e92d3f3fSGregory Neil Shapiro 3628e92d3f3fSGregory Neil Shapiro char * 3629e92d3f3fSGregory Neil Shapiro milter_data_cmd(e, state) 3630e92d3f3fSGregory Neil Shapiro ENVELOPE *e; 3631e92d3f3fSGregory Neil Shapiro char *state; 3632e92d3f3fSGregory Neil Shapiro { 3633e92d3f3fSGregory Neil Shapiro if (tTd(64, 10)) 3634e92d3f3fSGregory Neil Shapiro sm_dprintf("milter_data_cmd\n"); 3635e92d3f3fSGregory Neil Shapiro 3636e92d3f3fSGregory Neil Shapiro /* send it over */ 3637e92d3f3fSGregory Neil Shapiro return milter_command(SMFIC_DATA, NULL, 0, MilterDataMacros, e, state); 3638e92d3f3fSGregory Neil Shapiro } 3639e92d3f3fSGregory Neil Shapiro #endif /* SMFI_VERSION > 3 */ 3640e92d3f3fSGregory Neil Shapiro 364140266059SGregory Neil Shapiro /* 364206f25ae9SGregory Neil Shapiro ** MILTER_DATA -- send message headers/body and gather final message results 364306f25ae9SGregory Neil Shapiro ** 364406f25ae9SGregory Neil Shapiro ** Parameters: 364506f25ae9SGregory Neil Shapiro ** e -- current envelope. 364606f25ae9SGregory Neil Shapiro ** state -- return state from response. 364706f25ae9SGregory Neil Shapiro ** 364806f25ae9SGregory Neil Shapiro ** Returns: 364906f25ae9SGregory Neil Shapiro ** response string (may be NULL) 365006f25ae9SGregory Neil Shapiro ** 365106f25ae9SGregory Neil Shapiro ** Side effects: 365206f25ae9SGregory Neil Shapiro ** - Uses e->e_dfp for access to the body 365306f25ae9SGregory Neil Shapiro ** - Can call the various milter action routines to 365406f25ae9SGregory Neil Shapiro ** modify the envelope or message. 365506f25ae9SGregory Neil Shapiro */ 365606f25ae9SGregory Neil Shapiro 365706f25ae9SGregory Neil Shapiro # define MILTER_CHECK_RESULTS() \ 365806f25ae9SGregory Neil Shapiro if (*state == SMFIR_ACCEPT || \ 365906f25ae9SGregory Neil Shapiro m->mf_state == SMFS_DONE || \ 366006f25ae9SGregory Neil Shapiro m->mf_state == SMFS_ERROR) \ 366106f25ae9SGregory Neil Shapiro { \ 366206f25ae9SGregory Neil Shapiro if (m->mf_state != SMFS_ERROR) \ 366306f25ae9SGregory Neil Shapiro m->mf_state = SMFS_DONE; \ 366406f25ae9SGregory Neil Shapiro continue; /* to next filter */ \ 366506f25ae9SGregory Neil Shapiro } \ 366606f25ae9SGregory Neil Shapiro if (*state != SMFIR_CONTINUE) \ 366706f25ae9SGregory Neil Shapiro { \ 366806f25ae9SGregory Neil Shapiro m->mf_state = SMFS_DONE; \ 366906f25ae9SGregory Neil Shapiro goto finishup; \ 367006f25ae9SGregory Neil Shapiro } 367106f25ae9SGregory Neil Shapiro 367206f25ae9SGregory Neil Shapiro char * 367306f25ae9SGregory Neil Shapiro milter_data(e, state) 367406f25ae9SGregory Neil Shapiro ENVELOPE *e; 367506f25ae9SGregory Neil Shapiro char *state; 367606f25ae9SGregory Neil Shapiro { 367740266059SGregory Neil Shapiro bool replbody = false; /* milter_replbody() called? */ 367840266059SGregory Neil Shapiro bool replfailed = false; /* milter_replbody() failed? */ 367940266059SGregory Neil Shapiro bool rewind = false; /* rewind data file? */ 368040266059SGregory Neil Shapiro bool dfopen = false; /* data file open for writing? */ 368106f25ae9SGregory Neil Shapiro bool newfilter; /* reset on each new filter */ 368206f25ae9SGregory Neil Shapiro char rcmd; 368306f25ae9SGregory Neil Shapiro int i; 368406f25ae9SGregory Neil Shapiro int save_errno; 368506f25ae9SGregory Neil Shapiro char *response = NULL; 368606f25ae9SGregory Neil Shapiro time_t eomsent; 368706f25ae9SGregory Neil Shapiro ssize_t rlen; 368806f25ae9SGregory Neil Shapiro 368906f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 369040266059SGregory Neil Shapiro sm_dprintf("milter_data\n"); 369106f25ae9SGregory Neil Shapiro 369206f25ae9SGregory Neil Shapiro *state = SMFIR_CONTINUE; 369306f25ae9SGregory Neil Shapiro 369406f25ae9SGregory Neil Shapiro /* 369506f25ae9SGregory Neil Shapiro ** XXX: Should actually send body chunks to each filter 369606f25ae9SGregory Neil Shapiro ** a chunk at a time instead of sending the whole body to 369706f25ae9SGregory Neil Shapiro ** each filter in turn. However, only if the filters don't 369806f25ae9SGregory Neil Shapiro ** change the body. 369906f25ae9SGregory Neil Shapiro */ 370006f25ae9SGregory Neil Shapiro 370106f25ae9SGregory Neil Shapiro for (i = 0; InputFilters[i] != NULL; i++) 370206f25ae9SGregory Neil Shapiro { 370306f25ae9SGregory Neil Shapiro struct milter *m = InputFilters[i]; 370406f25ae9SGregory Neil Shapiro 370506f25ae9SGregory Neil Shapiro if (*state != SMFIR_CONTINUE && 370606f25ae9SGregory Neil Shapiro *state != SMFIR_ACCEPT) 370706f25ae9SGregory Neil Shapiro { 370806f25ae9SGregory Neil Shapiro /* 370906f25ae9SGregory Neil Shapiro ** A previous filter has dealt with the message, 371006f25ae9SGregory Neil Shapiro ** safe to stop processing the filters. 371106f25ae9SGregory Neil Shapiro */ 371206f25ae9SGregory Neil Shapiro 371306f25ae9SGregory Neil Shapiro break; 371406f25ae9SGregory Neil Shapiro } 371506f25ae9SGregory Neil Shapiro 371606f25ae9SGregory Neil Shapiro /* Now reset state for later evaluation */ 371706f25ae9SGregory Neil Shapiro *state = SMFIR_CONTINUE; 371840266059SGregory Neil Shapiro newfilter = true; 371906f25ae9SGregory Neil Shapiro 3720193538b7SGregory Neil Shapiro /* previous problem? */ 3721193538b7SGregory Neil Shapiro if (m->mf_state == SMFS_ERROR) 3722193538b7SGregory Neil Shapiro { 37235ef517c0SGregory Neil Shapiro MILTER_CHECK_ERROR(false, continue); 3724193538b7SGregory Neil Shapiro break; 3725193538b7SGregory Neil Shapiro } 3726193538b7SGregory Neil Shapiro 372706f25ae9SGregory Neil Shapiro /* sanity checks */ 372806f25ae9SGregory Neil Shapiro if (m->mf_sock < 0 || 372906f25ae9SGregory Neil Shapiro (m->mf_state != SMFS_OPEN && m->mf_state != SMFS_INMSG)) 373006f25ae9SGregory Neil Shapiro continue; 373106f25ae9SGregory Neil Shapiro 373206f25ae9SGregory Neil Shapiro m->mf_state = SMFS_INMSG; 373306f25ae9SGregory Neil Shapiro 373406f25ae9SGregory Neil Shapiro /* check if filter wants the headers */ 373506f25ae9SGregory Neil Shapiro if (!bitset(SMFIP_NOHDRS, m->mf_pflags)) 373606f25ae9SGregory Neil Shapiro { 373706f25ae9SGregory Neil Shapiro response = milter_headers(m, e, state); 373806f25ae9SGregory Neil Shapiro MILTER_CHECK_RESULTS(); 373906f25ae9SGregory Neil Shapiro } 374006f25ae9SGregory Neil Shapiro 374106f25ae9SGregory Neil Shapiro /* check if filter wants EOH */ 374206f25ae9SGregory Neil Shapiro if (!bitset(SMFIP_NOEOH, m->mf_pflags)) 374306f25ae9SGregory Neil Shapiro { 374406f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 374540266059SGregory Neil Shapiro sm_dprintf("milter_data: eoh\n"); 374606f25ae9SGregory Neil Shapiro 374706f25ae9SGregory Neil Shapiro /* send it over */ 374806f25ae9SGregory Neil Shapiro response = milter_send_command(m, SMFIC_EOH, NULL, 0, 374906f25ae9SGregory Neil Shapiro e, state); 375006f25ae9SGregory Neil Shapiro MILTER_CHECK_RESULTS(); 375106f25ae9SGregory Neil Shapiro } 375206f25ae9SGregory Neil Shapiro 375306f25ae9SGregory Neil Shapiro /* check if filter wants the body */ 375406f25ae9SGregory Neil Shapiro if (!bitset(SMFIP_NOBODY, m->mf_pflags) && 375506f25ae9SGregory Neil Shapiro e->e_dfp != NULL) 375606f25ae9SGregory Neil Shapiro { 375740266059SGregory Neil Shapiro rewind = true; 375806f25ae9SGregory Neil Shapiro response = milter_body(m, e, state); 375906f25ae9SGregory Neil Shapiro MILTER_CHECK_RESULTS(); 376006f25ae9SGregory Neil Shapiro } 376106f25ae9SGregory Neil Shapiro 3762323f6dcbSGregory Neil Shapiro if (MilterEOMMacros[0] != NULL) 3763e92d3f3fSGregory Neil Shapiro milter_send_macros(m, MilterEOMMacros, 3764e92d3f3fSGregory Neil Shapiro SMFIC_BODYEOB, e); 3765323f6dcbSGregory Neil Shapiro 376606f25ae9SGregory Neil Shapiro /* send the final body chunk */ 376706f25ae9SGregory Neil Shapiro (void) milter_write(m, SMFIC_BODYEOB, NULL, 0, 376806f25ae9SGregory Neil Shapiro m->mf_timeout[SMFTO_WRITE], e); 376906f25ae9SGregory Neil Shapiro 377006f25ae9SGregory Neil Shapiro /* Get time EOM sent for timeout */ 377106f25ae9SGregory Neil Shapiro eomsent = curtime(); 377206f25ae9SGregory Neil Shapiro 377306f25ae9SGregory Neil Shapiro /* deal with the possibility of multiple responses */ 377406f25ae9SGregory Neil Shapiro while (*state == SMFIR_CONTINUE) 377506f25ae9SGregory Neil Shapiro { 377606f25ae9SGregory Neil Shapiro /* Check total timeout from EOM to final ACK/NAK */ 377706f25ae9SGregory Neil Shapiro if (m->mf_timeout[SMFTO_EOM] > 0 && 377806f25ae9SGregory Neil Shapiro curtime() - eomsent >= m->mf_timeout[SMFTO_EOM]) 377906f25ae9SGregory Neil Shapiro { 378006f25ae9SGregory Neil Shapiro if (tTd(64, 5)) 378140266059SGregory Neil Shapiro sm_dprintf("milter_data(%s): EOM ACK/NAK timeout\n", 378206f25ae9SGregory Neil Shapiro m->mf_name); 378340266059SGregory Neil Shapiro if (MilterLogLevel > 0) 378406f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 378540266059SGregory Neil Shapiro "milter_data(%s): EOM ACK/NAK timeout", 378606f25ae9SGregory Neil Shapiro m->mf_name); 378740266059SGregory Neil Shapiro milter_error(m, e); 37885ef517c0SGregory Neil Shapiro MILTER_CHECK_ERROR(false, break); 378906f25ae9SGregory Neil Shapiro break; 379006f25ae9SGregory Neil Shapiro } 379106f25ae9SGregory Neil Shapiro 379206f25ae9SGregory Neil Shapiro response = milter_read(m, &rcmd, &rlen, 379306f25ae9SGregory Neil Shapiro m->mf_timeout[SMFTO_READ], e); 379406f25ae9SGregory Neil Shapiro if (m->mf_state == SMFS_ERROR) 379506f25ae9SGregory Neil Shapiro break; 379606f25ae9SGregory Neil Shapiro 379706f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 379840266059SGregory Neil Shapiro sm_dprintf("milter_data(%s): state %c\n", 379906f25ae9SGregory Neil Shapiro m->mf_name, (char) rcmd); 380006f25ae9SGregory Neil Shapiro 380106f25ae9SGregory Neil Shapiro switch (rcmd) 380206f25ae9SGregory Neil Shapiro { 380306f25ae9SGregory Neil Shapiro case SMFIR_REPLYCODE: 380406f25ae9SGregory Neil Shapiro MILTER_CHECK_REPLYCODE("554 5.7.1 Command rejected"); 380540266059SGregory Neil Shapiro if (MilterLogLevel > 12) 380640266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "milter=%s, reject=%s", 380740266059SGregory Neil Shapiro m->mf_name, response); 380806f25ae9SGregory Neil Shapiro *state = rcmd; 380906f25ae9SGregory Neil Shapiro m->mf_state = SMFS_DONE; 381006f25ae9SGregory Neil Shapiro break; 381106f25ae9SGregory Neil Shapiro 381240266059SGregory Neil Shapiro case SMFIR_REJECT: /* log msg at end of function */ 381340266059SGregory Neil Shapiro if (MilterLogLevel > 12) 381440266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "milter=%s, reject", 381540266059SGregory Neil Shapiro m->mf_name); 381640266059SGregory Neil Shapiro *state = rcmd; 381740266059SGregory Neil Shapiro m->mf_state = SMFS_DONE; 381840266059SGregory Neil Shapiro break; 381940266059SGregory Neil Shapiro 382006f25ae9SGregory Neil Shapiro case SMFIR_DISCARD: 382140266059SGregory Neil Shapiro if (MilterLogLevel > 12) 382240266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "milter=%s, discard", 382340266059SGregory Neil Shapiro m->mf_name); 382440266059SGregory Neil Shapiro *state = rcmd; 382540266059SGregory Neil Shapiro m->mf_state = SMFS_DONE; 382640266059SGregory Neil Shapiro break; 382740266059SGregory Neil Shapiro 382806f25ae9SGregory Neil Shapiro case SMFIR_TEMPFAIL: 382940266059SGregory Neil Shapiro if (MilterLogLevel > 12) 383040266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "milter=%s, tempfail", 383140266059SGregory Neil Shapiro m->mf_name); 383206f25ae9SGregory Neil Shapiro *state = rcmd; 383306f25ae9SGregory Neil Shapiro m->mf_state = SMFS_DONE; 383406f25ae9SGregory Neil Shapiro break; 383506f25ae9SGregory Neil Shapiro 383606f25ae9SGregory Neil Shapiro case SMFIR_CONTINUE: 383706f25ae9SGregory Neil Shapiro case SMFIR_ACCEPT: 383806f25ae9SGregory Neil Shapiro /* this filter is done with message */ 383906f25ae9SGregory Neil Shapiro if (replfailed) 384006f25ae9SGregory Neil Shapiro *state = SMFIR_TEMPFAIL; 384106f25ae9SGregory Neil Shapiro else 384206f25ae9SGregory Neil Shapiro *state = SMFIR_ACCEPT; 384306f25ae9SGregory Neil Shapiro m->mf_state = SMFS_DONE; 384406f25ae9SGregory Neil Shapiro break; 384506f25ae9SGregory Neil Shapiro 384606f25ae9SGregory Neil Shapiro case SMFIR_PROGRESS: 384706f25ae9SGregory Neil Shapiro break; 384806f25ae9SGregory Neil Shapiro 384940266059SGregory Neil Shapiro case SMFIR_QUARANTINE: 385040266059SGregory Neil Shapiro if (!bitset(SMFIF_QUARANTINE, m->mf_fflags)) 385140266059SGregory Neil Shapiro { 385240266059SGregory Neil Shapiro if (MilterLogLevel > 9) 385340266059SGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id, 385440266059SGregory Neil Shapiro "milter_data(%s): lied about quarantining, honoring request anyway", 385540266059SGregory Neil Shapiro m->mf_name); 385640266059SGregory Neil Shapiro } 385740266059SGregory Neil Shapiro if (response == NULL) 385840266059SGregory Neil Shapiro response = newstr(""); 385940266059SGregory Neil Shapiro if (MilterLogLevel > 3) 386040266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, 386140266059SGregory Neil Shapiro "milter=%s, quarantine=%s", 386240266059SGregory Neil Shapiro m->mf_name, response); 386340266059SGregory Neil Shapiro e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, 386440266059SGregory Neil Shapiro response); 386540266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, 386640266059SGregory Neil Shapiro macid("{quarantine}"), e->e_quarmsg); 386740266059SGregory Neil Shapiro break; 386840266059SGregory Neil Shapiro 386906f25ae9SGregory Neil Shapiro case SMFIR_ADDHEADER: 387006f25ae9SGregory Neil Shapiro if (!bitset(SMFIF_ADDHDRS, m->mf_fflags)) 387106f25ae9SGregory Neil Shapiro { 387240266059SGregory Neil Shapiro if (MilterLogLevel > 9) 387306f25ae9SGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id, 387406f25ae9SGregory Neil Shapiro "milter_data(%s): lied about adding headers, honoring request anyway", 387506f25ae9SGregory Neil Shapiro m->mf_name); 387606f25ae9SGregory Neil Shapiro } 387706f25ae9SGregory Neil Shapiro milter_addheader(response, rlen, e); 387806f25ae9SGregory Neil Shapiro break; 387906f25ae9SGregory Neil Shapiro 3880e92d3f3fSGregory Neil Shapiro case SMFIR_INSHEADER: 3881e92d3f3fSGregory Neil Shapiro if (!bitset(SMFIF_ADDHDRS, m->mf_fflags)) 3882e92d3f3fSGregory Neil Shapiro { 3883e92d3f3fSGregory Neil Shapiro if (MilterLogLevel > 9) 3884e92d3f3fSGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id, 3885e92d3f3fSGregory Neil Shapiro "milter_data(%s): lied about adding headers, honoring request anyway", 3886e92d3f3fSGregory Neil Shapiro m->mf_name); 3887e92d3f3fSGregory Neil Shapiro } 3888e92d3f3fSGregory Neil Shapiro milter_insheader(response, rlen, e); 3889e92d3f3fSGregory Neil Shapiro break; 3890e92d3f3fSGregory Neil Shapiro 389106f25ae9SGregory Neil Shapiro case SMFIR_CHGHEADER: 389206f25ae9SGregory Neil Shapiro if (!bitset(SMFIF_CHGHDRS, m->mf_fflags)) 389306f25ae9SGregory Neil Shapiro { 389440266059SGregory Neil Shapiro if (MilterLogLevel > 9) 389506f25ae9SGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id, 389606f25ae9SGregory Neil Shapiro "milter_data(%s): lied about changing headers, honoring request anyway", 389706f25ae9SGregory Neil Shapiro m->mf_name); 389806f25ae9SGregory Neil Shapiro } 389906f25ae9SGregory Neil Shapiro milter_changeheader(response, rlen, e); 390006f25ae9SGregory Neil Shapiro break; 390106f25ae9SGregory Neil Shapiro 390206f25ae9SGregory Neil Shapiro case SMFIR_ADDRCPT: 390306f25ae9SGregory Neil Shapiro if (!bitset(SMFIF_ADDRCPT, m->mf_fflags)) 390406f25ae9SGregory Neil Shapiro { 390540266059SGregory Neil Shapiro if (MilterLogLevel > 9) 390606f25ae9SGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id, 390706f25ae9SGregory Neil Shapiro "milter_data(%s) lied about adding recipients, honoring request anyway", 390806f25ae9SGregory Neil Shapiro m->mf_name); 390906f25ae9SGregory Neil Shapiro } 391006f25ae9SGregory Neil Shapiro milter_addrcpt(response, rlen, e); 391106f25ae9SGregory Neil Shapiro break; 391206f25ae9SGregory Neil Shapiro 391306f25ae9SGregory Neil Shapiro case SMFIR_DELRCPT: 391406f25ae9SGregory Neil Shapiro if (!bitset(SMFIF_DELRCPT, m->mf_fflags)) 391506f25ae9SGregory Neil Shapiro { 391640266059SGregory Neil Shapiro if (MilterLogLevel > 9) 391706f25ae9SGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id, 391806f25ae9SGregory Neil Shapiro "milter_data(%s): lied about removing recipients, honoring request anyway", 391906f25ae9SGregory Neil Shapiro m->mf_name); 392006f25ae9SGregory Neil Shapiro } 392106f25ae9SGregory Neil Shapiro milter_delrcpt(response, rlen, e); 392206f25ae9SGregory Neil Shapiro break; 392306f25ae9SGregory Neil Shapiro 392406f25ae9SGregory Neil Shapiro case SMFIR_REPLBODY: 392506f25ae9SGregory Neil Shapiro if (!bitset(SMFIF_MODBODY, m->mf_fflags)) 392606f25ae9SGregory Neil Shapiro { 3927e92d3f3fSGregory Neil Shapiro if (MilterLogLevel > 0) 392806f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 392906f25ae9SGregory Neil Shapiro "milter_data(%s): lied about replacing body, rejecting request and tempfailing message", 393006f25ae9SGregory Neil Shapiro m->mf_name); 393140266059SGregory Neil Shapiro replfailed = true; 393206f25ae9SGregory Neil Shapiro break; 393306f25ae9SGregory Neil Shapiro } 393406f25ae9SGregory Neil Shapiro 393506f25ae9SGregory Neil Shapiro /* already failed in attempt */ 393606f25ae9SGregory Neil Shapiro if (replfailed) 393706f25ae9SGregory Neil Shapiro break; 393806f25ae9SGregory Neil Shapiro 393906f25ae9SGregory Neil Shapiro if (!dfopen) 394006f25ae9SGregory Neil Shapiro { 394106f25ae9SGregory Neil Shapiro if (milter_reopen_df(e) < 0) 394206f25ae9SGregory Neil Shapiro { 394340266059SGregory Neil Shapiro replfailed = true; 394406f25ae9SGregory Neil Shapiro break; 394506f25ae9SGregory Neil Shapiro } 394640266059SGregory Neil Shapiro dfopen = true; 394740266059SGregory Neil Shapiro rewind = true; 394806f25ae9SGregory Neil Shapiro } 394906f25ae9SGregory Neil Shapiro 395006f25ae9SGregory Neil Shapiro if (milter_replbody(response, rlen, 395106f25ae9SGregory Neil Shapiro newfilter, e) < 0) 395240266059SGregory Neil Shapiro replfailed = true; 395340266059SGregory Neil Shapiro newfilter = false; 395440266059SGregory Neil Shapiro replbody = true; 395506f25ae9SGregory Neil Shapiro break; 395606f25ae9SGregory Neil Shapiro 395706f25ae9SGregory Neil Shapiro default: 395806f25ae9SGregory Neil Shapiro /* Invalid response to command */ 395940266059SGregory Neil Shapiro if (MilterLogLevel > 0) 396006f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, 396106f25ae9SGregory Neil Shapiro "milter_data(%s): returned bogus response %c", 396206f25ae9SGregory Neil Shapiro m->mf_name, rcmd); 396340266059SGregory Neil Shapiro milter_error(m, e); 396406f25ae9SGregory Neil Shapiro break; 396506f25ae9SGregory Neil Shapiro } 396640266059SGregory Neil Shapiro if (rcmd != SMFIR_REPLYCODE && response != NULL) 396706f25ae9SGregory Neil Shapiro { 396840266059SGregory Neil Shapiro sm_free(response); /* XXX */ 396906f25ae9SGregory Neil Shapiro response = NULL; 397006f25ae9SGregory Neil Shapiro } 397106f25ae9SGregory Neil Shapiro 397206f25ae9SGregory Neil Shapiro if (m->mf_state == SMFS_ERROR) 397306f25ae9SGregory Neil Shapiro break; 397406f25ae9SGregory Neil Shapiro } 397506f25ae9SGregory Neil Shapiro 397606f25ae9SGregory Neil Shapiro if (replbody && !replfailed) 397706f25ae9SGregory Neil Shapiro { 397806f25ae9SGregory Neil Shapiro /* flush possible buffered character */ 397906f25ae9SGregory Neil Shapiro milter_replbody(NULL, 0, !replbody, e); 398040266059SGregory Neil Shapiro replbody = false; 398106f25ae9SGregory Neil Shapiro } 398206f25ae9SGregory Neil Shapiro 398306f25ae9SGregory Neil Shapiro if (m->mf_state == SMFS_ERROR) 398406f25ae9SGregory Neil Shapiro { 39855ef517c0SGregory Neil Shapiro MILTER_CHECK_ERROR(false, continue); 398606f25ae9SGregory Neil Shapiro goto finishup; 398706f25ae9SGregory Neil Shapiro } 398806f25ae9SGregory Neil Shapiro } 398906f25ae9SGregory Neil Shapiro 399006f25ae9SGregory Neil Shapiro finishup: 399106f25ae9SGregory Neil Shapiro /* leave things in the expected state if we touched it */ 399206f25ae9SGregory Neil Shapiro if (replfailed) 399306f25ae9SGregory Neil Shapiro { 399406f25ae9SGregory Neil Shapiro if (*state == SMFIR_CONTINUE || 399506f25ae9SGregory Neil Shapiro *state == SMFIR_ACCEPT) 399606f25ae9SGregory Neil Shapiro { 399706f25ae9SGregory Neil Shapiro *state = SMFIR_TEMPFAIL; 399840266059SGregory Neil Shapiro SM_FREE_CLR(response); 399906f25ae9SGregory Neil Shapiro } 400006f25ae9SGregory Neil Shapiro 400106f25ae9SGregory Neil Shapiro if (dfopen) 400206f25ae9SGregory Neil Shapiro { 400340266059SGregory Neil Shapiro (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT); 400406f25ae9SGregory Neil Shapiro e->e_dfp = NULL; 400506f25ae9SGregory Neil Shapiro e->e_flags &= ~EF_HAS_DF; 400640266059SGregory Neil Shapiro dfopen = false; 400706f25ae9SGregory Neil Shapiro } 400840266059SGregory Neil Shapiro rewind = false; 400906f25ae9SGregory Neil Shapiro } 401006f25ae9SGregory Neil Shapiro 401106f25ae9SGregory Neil Shapiro if ((dfopen && milter_reset_df(e) < 0) || 401206f25ae9SGregory Neil Shapiro (rewind && bfrewind(e->e_dfp) < 0)) 401306f25ae9SGregory Neil Shapiro { 401406f25ae9SGregory Neil Shapiro save_errno = errno; 401506f25ae9SGregory Neil Shapiro ExitStat = EX_IOERR; 401606f25ae9SGregory Neil Shapiro 401706f25ae9SGregory Neil Shapiro /* 401806f25ae9SGregory Neil Shapiro ** If filter told us to keep message but we had 401906f25ae9SGregory Neil Shapiro ** an error, we can't really keep it, tempfail it. 402006f25ae9SGregory Neil Shapiro */ 402106f25ae9SGregory Neil Shapiro 402206f25ae9SGregory Neil Shapiro if (*state == SMFIR_CONTINUE || 402306f25ae9SGregory Neil Shapiro *state == SMFIR_ACCEPT) 402406f25ae9SGregory Neil Shapiro { 402506f25ae9SGregory Neil Shapiro *state = SMFIR_TEMPFAIL; 402640266059SGregory Neil Shapiro SM_FREE_CLR(response); 402706f25ae9SGregory Neil Shapiro } 402806f25ae9SGregory Neil Shapiro 402906f25ae9SGregory Neil Shapiro errno = save_errno; 403040266059SGregory Neil Shapiro syserr("milter_data: %s/%cf%s: read error", 403140266059SGregory Neil Shapiro qid_printqueue(e->e_qgrp, e->e_qdir), 403240266059SGregory Neil Shapiro DATAFL_LETTER, e->e_id); 403306f25ae9SGregory Neil Shapiro } 403440266059SGregory Neil Shapiro 403506f25ae9SGregory Neil Shapiro MILTER_CHECK_DONE_MSG(); 403640266059SGregory Neil Shapiro if (MilterLogLevel > 10 && *state == SMFIR_REJECT) 403740266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter: reject, data"); 403806f25ae9SGregory Neil Shapiro return response; 403906f25ae9SGregory Neil Shapiro } 4040e92d3f3fSGregory Neil Shapiro 4041e92d3f3fSGregory Neil Shapiro #if SMFI_VERSION > 2 4042e92d3f3fSGregory Neil Shapiro /* 4043e92d3f3fSGregory Neil Shapiro ** MILTER_UNKNOWN -- send any unrecognized or unimplemented command 4044e92d3f3fSGregory Neil Shapiro ** string to milter filters 4045e92d3f3fSGregory Neil Shapiro ** 4046e92d3f3fSGregory Neil Shapiro ** Parameters: 4047e92d3f3fSGregory Neil Shapiro ** cmd -- the string itself. 4048e92d3f3fSGregory Neil Shapiro ** e -- current envelope. 4049e92d3f3fSGregory Neil Shapiro ** state -- return state from response. 4050e92d3f3fSGregory Neil Shapiro ** 4051e92d3f3fSGregory Neil Shapiro ** 4052e92d3f3fSGregory Neil Shapiro ** Returns: 4053e92d3f3fSGregory Neil Shapiro ** response string (may be NULL) 4054e92d3f3fSGregory Neil Shapiro */ 4055e92d3f3fSGregory Neil Shapiro 4056e92d3f3fSGregory Neil Shapiro char * 4057e92d3f3fSGregory Neil Shapiro milter_unknown(cmd, e, state) 4058e92d3f3fSGregory Neil Shapiro char *cmd; 4059e92d3f3fSGregory Neil Shapiro ENVELOPE *e; 4060e92d3f3fSGregory Neil Shapiro char *state; 4061e92d3f3fSGregory Neil Shapiro { 4062e92d3f3fSGregory Neil Shapiro if (tTd(64, 10)) 4063e92d3f3fSGregory Neil Shapiro sm_dprintf("milter_unknown(%s)\n", cmd); 4064e92d3f3fSGregory Neil Shapiro 4065e92d3f3fSGregory Neil Shapiro return milter_command(SMFIC_UNKNOWN, cmd, strlen(cmd) + 1, 4066e92d3f3fSGregory Neil Shapiro NULL, e, state); 4067e92d3f3fSGregory Neil Shapiro } 4068e92d3f3fSGregory Neil Shapiro #endif /* SMFI_VERSION > 2 */ 4069e92d3f3fSGregory Neil Shapiro 407040266059SGregory Neil Shapiro /* 407106f25ae9SGregory Neil Shapiro ** MILTER_QUIT -- informs the filter(s) we are done and closes connection(s) 407206f25ae9SGregory Neil Shapiro ** 407306f25ae9SGregory Neil Shapiro ** Parameters: 407406f25ae9SGregory Neil Shapiro ** e -- current envelope. 407506f25ae9SGregory Neil Shapiro ** 407606f25ae9SGregory Neil Shapiro ** Returns: 407706f25ae9SGregory Neil Shapiro ** none 407806f25ae9SGregory Neil Shapiro */ 407906f25ae9SGregory Neil Shapiro 408006f25ae9SGregory Neil Shapiro void 408106f25ae9SGregory Neil Shapiro milter_quit(e) 408206f25ae9SGregory Neil Shapiro ENVELOPE *e; 408306f25ae9SGregory Neil Shapiro { 408406f25ae9SGregory Neil Shapiro int i; 408506f25ae9SGregory Neil Shapiro 408606f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 408740266059SGregory Neil Shapiro sm_dprintf("milter_quit(%s)\n", e->e_id); 408806f25ae9SGregory Neil Shapiro 408906f25ae9SGregory Neil Shapiro for (i = 0; InputFilters[i] != NULL; i++) 409006f25ae9SGregory Neil Shapiro milter_quit_filter(InputFilters[i], e); 409106f25ae9SGregory Neil Shapiro } 409240266059SGregory Neil Shapiro /* 409306f25ae9SGregory Neil Shapiro ** MILTER_ABORT -- informs the filter(s) that we are aborting current message 409406f25ae9SGregory Neil Shapiro ** 409506f25ae9SGregory Neil Shapiro ** Parameters: 409606f25ae9SGregory Neil Shapiro ** e -- current envelope. 409706f25ae9SGregory Neil Shapiro ** 409806f25ae9SGregory Neil Shapiro ** Returns: 409906f25ae9SGregory Neil Shapiro ** none 410006f25ae9SGregory Neil Shapiro */ 410106f25ae9SGregory Neil Shapiro 410206f25ae9SGregory Neil Shapiro void 410306f25ae9SGregory Neil Shapiro milter_abort(e) 410406f25ae9SGregory Neil Shapiro ENVELOPE *e; 410506f25ae9SGregory Neil Shapiro { 410606f25ae9SGregory Neil Shapiro int i; 410706f25ae9SGregory Neil Shapiro 410806f25ae9SGregory Neil Shapiro if (tTd(64, 10)) 410940266059SGregory Neil Shapiro sm_dprintf("milter_abort\n"); 411006f25ae9SGregory Neil Shapiro 411106f25ae9SGregory Neil Shapiro for (i = 0; InputFilters[i] != NULL; i++) 411206f25ae9SGregory Neil Shapiro { 411306f25ae9SGregory Neil Shapiro struct milter *m = InputFilters[i]; 411406f25ae9SGregory Neil Shapiro 411506f25ae9SGregory Neil Shapiro /* sanity checks */ 411606f25ae9SGregory Neil Shapiro if (m->mf_sock < 0 || m->mf_state != SMFS_INMSG) 411706f25ae9SGregory Neil Shapiro continue; 411806f25ae9SGregory Neil Shapiro 411906f25ae9SGregory Neil Shapiro milter_abort_filter(m, e); 412006f25ae9SGregory Neil Shapiro } 412106f25ae9SGregory Neil Shapiro } 412240266059SGregory Neil Shapiro #endif /* MILTER */ 4123