106f25ae9SGregory Neil Shapiro /*
25dd76dd0SGregory Neil Shapiro * Copyright (c) 1999-2009, 2012, 2013 Proofpoint, 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
134313cc83SGregory Neil Shapiro SM_RCSID("@(#)$Id: milter.c,v 8.281 2013-11-22 20:51:56 ca Exp $")
1440266059SGregory Neil Shapiro
1540266059SGregory Neil Shapiro #if MILTER
16d0cef73dSGregory Neil Shapiro # include <sm/sendmail.h>
1740266059SGregory Neil Shapiro # include <libmilter/mfapi.h>
1840266059SGregory Neil Shapiro # include <libmilter/mfdef.h>
192fb4f839SGregory Neil Shapiro # if _FFR_8BITENVADDR
202fb4f839SGregory Neil Shapiro # include <sm/ixlen.h>
212fb4f839SGregory Neil Shapiro # endif
2240266059SGregory Neil Shapiro
2306f25ae9SGregory Neil Shapiro # include <errno.h>
244e4196cbSGregory Neil Shapiro # include <sm/time.h>
25e92d3f3fSGregory Neil Shapiro # include <sys/uio.h>
2606f25ae9SGregory Neil Shapiro
2706f25ae9SGregory Neil Shapiro # if NETINET || NETINET6
2806f25ae9SGregory Neil Shapiro # include <arpa/inet.h>
29d0cef73dSGregory Neil Shapiro # if MILTER_NO_NAGLE
30e92d3f3fSGregory Neil Shapiro # include <netinet/tcp.h>
315b0945b5SGregory Neil Shapiro # endif
3206f25ae9SGregory Neil Shapiro # endif /* NETINET || NETINET6 */
3306f25ae9SGregory Neil Shapiro
3440266059SGregory Neil Shapiro # include <sm/fdset.h>
3506f25ae9SGregory Neil Shapiro
36b6bacd31SGregory Neil Shapiro static void milter_connect_timeout __P((int));
3740266059SGregory Neil Shapiro static void milter_error __P((struct milter *, ENVELOPE *));
3806f25ae9SGregory Neil Shapiro static int milter_open __P((struct milter *, bool, ENVELOPE *));
3906f25ae9SGregory Neil Shapiro static void milter_parse_timeouts __P((char *, struct milter *));
40d0cef73dSGregory Neil Shapiro static char *milter_sysread __P((struct milter *, char *, ssize_t, time_t,
41d0cef73dSGregory Neil Shapiro ENVELOPE *, const char *));
42d0cef73dSGregory Neil Shapiro static char *milter_read __P((struct milter *, char *, ssize_t *, time_t,
43d0cef73dSGregory Neil Shapiro ENVELOPE *, const char *));
44d0cef73dSGregory Neil Shapiro static char *milter_write __P((struct milter *, int, char *, ssize_t,
45d0cef73dSGregory Neil Shapiro time_t, ENVELOPE *, const char *));
46d0cef73dSGregory Neil Shapiro static char *milter_send_command __P((struct milter *, int, void *,
47d0cef73dSGregory Neil Shapiro ssize_t, ENVELOPE *, char *, const char *));
48ba00ec3dSGregory Neil Shapiro static char *milter_command __P((int, void *, ssize_t, int,
49d0cef73dSGregory Neil Shapiro ENVELOPE *, char *, const char *, bool));
50d0cef73dSGregory Neil Shapiro static char *milter_body __P((struct milter *, ENVELOPE *, char *));
51d0cef73dSGregory Neil Shapiro static int milter_reopen_df __P((ENVELOPE *));
52d0cef73dSGregory Neil Shapiro static int milter_reset_df __P((ENVELOPE *));
53d0cef73dSGregory Neil Shapiro static void milter_quit_filter __P((struct milter *, ENVELOPE *));
54d0cef73dSGregory Neil Shapiro static void milter_abort_filter __P((struct milter *, ENVELOPE *));
55d0cef73dSGregory Neil Shapiro static void milter_send_macros __P((struct milter *, char **, int,
56d0cef73dSGregory Neil Shapiro ENVELOPE *));
57ffb83623SGregory Neil Shapiro static int milter_negotiate __P((struct milter *, ENVELOPE *,
58ffb83623SGregory Neil Shapiro milters_T *));
59d0cef73dSGregory Neil Shapiro static void milter_per_connection_check __P((ENVELOPE *));
60d0cef73dSGregory Neil Shapiro static char *milter_headers __P((struct milter *, ENVELOPE *, char *));
61d0cef73dSGregory Neil Shapiro static void milter_addheader __P((struct milter *, char *, ssize_t,
62d0cef73dSGregory Neil Shapiro ENVELOPE *));
63d0cef73dSGregory Neil Shapiro static void milter_insheader __P((struct milter *, char *, ssize_t,
64d0cef73dSGregory Neil Shapiro ENVELOPE *));
65d0cef73dSGregory Neil Shapiro static void milter_changeheader __P((struct milter *, char *, ssize_t,
66d0cef73dSGregory Neil Shapiro ENVELOPE *));
675b0945b5SGregory Neil Shapiro static void milter_chgfrom __P((char *, ssize_t, ENVELOPE *, const char *));
685b0945b5SGregory Neil Shapiro static void milter_addrcpt __P((char *, ssize_t, ENVELOPE *, const char *));
695b0945b5SGregory Neil Shapiro static void milter_addrcpt_par __P((char *, ssize_t, ENVELOPE *, const char *));
705b0945b5SGregory Neil Shapiro static void milter_delrcpt __P((char *, ssize_t, ENVELOPE *, const char *));
715b0945b5SGregory Neil Shapiro static int milter_replbody __P((char *, ssize_t, bool, ENVELOPE *, const char *));
72d0cef73dSGregory Neil Shapiro static int milter_set_macros __P((char *, char **, char *, int));
73d0cef73dSGregory Neil Shapiro
74d0cef73dSGregory Neil Shapiro /* milter states */
75d0cef73dSGregory Neil Shapiro # define SMFS_CLOSED 'C' /* closed for all further actions */
76d0cef73dSGregory Neil Shapiro # define SMFS_OPEN 'O' /* connected to remote milter filter */
77d0cef73dSGregory Neil Shapiro # define SMFS_INMSG 'M' /* currently servicing a message */
78d0cef73dSGregory Neil Shapiro # define SMFS_DONE 'D' /* done with current message */
79d0cef73dSGregory Neil Shapiro # define SMFS_CLOSABLE 'Q' /* done with current connection */
80d0cef73dSGregory Neil Shapiro # define SMFS_ERROR 'E' /* error state */
81d0cef73dSGregory Neil Shapiro # define SMFS_READY 'R' /* ready for action */
82d0cef73dSGregory Neil Shapiro # define SMFS_SKIP 'S' /* skip body */
8306f25ae9SGregory Neil Shapiro
84ba00ec3dSGregory Neil Shapiro /*
85ba00ec3dSGregory Neil Shapiro ** MilterMacros contains the milter macros for each milter and each stage.
86ba00ec3dSGregory Neil Shapiro ** indices are (in order): stages, milter-index, macro
87ba00ec3dSGregory Neil Shapiro ** milter-index == 0: "global" macros (not for a specific milter).
88ba00ec3dSGregory Neil Shapiro */
89ba00ec3dSGregory Neil Shapiro
90ba00ec3dSGregory Neil Shapiro static char *MilterMacros[SMFIM_LAST + 1][MAXFILTERS + 1][MAXFILTERMACROS + 1];
91e92d3f3fSGregory Neil Shapiro static size_t MilterMaxDataSize = MILTER_MAX_DATA_SIZE;
9206f25ae9SGregory Neil Shapiro
9306f25ae9SGregory Neil Shapiro # define MILTER_CHECK_DONE_MSG() \
9406f25ae9SGregory Neil Shapiro if (*state == SMFIR_REPLYCODE || \
9506f25ae9SGregory Neil Shapiro *state == SMFIR_REJECT || \
9606f25ae9SGregory Neil Shapiro *state == SMFIR_DISCARD || \
9706f25ae9SGregory Neil Shapiro *state == SMFIR_TEMPFAIL) \
9806f25ae9SGregory Neil Shapiro { \
9906f25ae9SGregory Neil Shapiro /* Abort the filters to let them know we are done with msg */ \
10006f25ae9SGregory Neil Shapiro milter_abort(e); \
10106f25ae9SGregory Neil Shapiro }
10206f25ae9SGregory Neil Shapiro
103ba00ec3dSGregory Neil Shapiro /* set state in case of an error */
104ba00ec3dSGregory Neil Shapiro # define MILTER_SET_STATE \
105ba00ec3dSGregory Neil Shapiro if (bitnset(SMF_TEMPFAIL, m->mf_flags)) \
106ba00ec3dSGregory Neil Shapiro *state = SMFIR_TEMPFAIL; \
107ba00ec3dSGregory Neil Shapiro else if (bitnset(SMF_TEMPDROP, m->mf_flags)) \
108ba00ec3dSGregory Neil Shapiro *state = SMFIR_SHUTDOWN; \
109ba00ec3dSGregory Neil Shapiro else if (bitnset(SMF_REJECT, m->mf_flags)) \
110ba00ec3dSGregory Neil Shapiro *state = SMFIR_REJECT
111ba00ec3dSGregory Neil Shapiro
112ba00ec3dSGregory Neil Shapiro /* flow through code maybe using continue; don't wrap in do {} while */
1135ef517c0SGregory Neil Shapiro # define MILTER_CHECK_ERROR(initial, action) \
1145ef517c0SGregory Neil Shapiro if (!initial && tTd(71, 100)) \
1155ef517c0SGregory Neil Shapiro { \
1165ef517c0SGregory Neil Shapiro if (e->e_quarmsg == NULL) \
1175ef517c0SGregory Neil Shapiro { \
1185ef517c0SGregory Neil Shapiro e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, \
1195ef517c0SGregory Neil Shapiro "filter failure"); \
1205ef517c0SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), \
1215ef517c0SGregory Neil Shapiro e->e_quarmsg); \
1225ef517c0SGregory Neil Shapiro } \
1235ef517c0SGregory Neil Shapiro } \
1245ef517c0SGregory Neil Shapiro else if (tTd(71, 101)) \
125959366dcSGregory Neil Shapiro { \
126959366dcSGregory Neil Shapiro if (e->e_quarmsg == NULL) \
127959366dcSGregory Neil Shapiro { \
128959366dcSGregory Neil Shapiro e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, \
129959366dcSGregory Neil Shapiro "filter failure"); \
130959366dcSGregory Neil Shapiro macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), \
131959366dcSGregory Neil Shapiro e->e_quarmsg); \
132959366dcSGregory Neil Shapiro } \
133959366dcSGregory Neil Shapiro } \
134ba00ec3dSGregory Neil Shapiro else MILTER_SET_STATE; \
135959366dcSGregory Neil Shapiro else \
136959366dcSGregory Neil Shapiro action;
13706f25ae9SGregory Neil Shapiro
13806f25ae9SGregory Neil Shapiro # define MILTER_CHECK_REPLYCODE(default) \
13906f25ae9SGregory Neil Shapiro if (response == NULL || \
14006f25ae9SGregory Neil Shapiro strlen(response) + 1 != (size_t) rlen || \
14106f25ae9SGregory Neil Shapiro rlen < 3 || \
14206f25ae9SGregory Neil Shapiro (response[0] != '4' && response[0] != '5') || \
14306f25ae9SGregory Neil Shapiro !isascii(response[1]) || !isdigit(response[1]) || \
14406f25ae9SGregory Neil Shapiro !isascii(response[2]) || !isdigit(response[2])) \
14506f25ae9SGregory Neil Shapiro { \
14606f25ae9SGregory Neil Shapiro if (response != NULL) \
14740266059SGregory Neil Shapiro sm_free(response); /* XXX */ \
14806f25ae9SGregory Neil Shapiro response = newstr(default); \
14906f25ae9SGregory Neil Shapiro } \
15006f25ae9SGregory Neil Shapiro else \
15106f25ae9SGregory Neil Shapiro { \
15206f25ae9SGregory Neil Shapiro char *ptr = response; \
15306f25ae9SGregory Neil Shapiro \
15406f25ae9SGregory Neil Shapiro /* Check for unprotected %'s in the string */ \
15506f25ae9SGregory Neil Shapiro while (*ptr != '\0') \
15606f25ae9SGregory Neil Shapiro { \
15706f25ae9SGregory Neil Shapiro if (*ptr == '%' && *++ptr != '%') \
15806f25ae9SGregory Neil Shapiro { \
15940266059SGregory Neil Shapiro sm_free(response); /* XXX */ \
16006f25ae9SGregory Neil Shapiro response = newstr(default); \
16106f25ae9SGregory Neil Shapiro break; \
16206f25ae9SGregory Neil Shapiro } \
16306f25ae9SGregory Neil Shapiro ptr++; \
16406f25ae9SGregory Neil Shapiro } \
16506f25ae9SGregory Neil Shapiro }
16606f25ae9SGregory Neil Shapiro
16706f25ae9SGregory Neil Shapiro # define MILTER_DF_ERROR(msg) \
16806f25ae9SGregory Neil Shapiro { \
16906f25ae9SGregory Neil Shapiro int save_errno = errno; \
17006f25ae9SGregory Neil Shapiro \
17106f25ae9SGregory Neil Shapiro if (tTd(64, 5)) \
17206f25ae9SGregory Neil Shapiro { \
17340266059SGregory Neil Shapiro sm_dprintf(msg, dfname, sm_errstring(save_errno)); \
17440266059SGregory Neil Shapiro sm_dprintf("\n"); \
17506f25ae9SGregory Neil Shapiro } \
17640266059SGregory Neil Shapiro if (MilterLogLevel > 0) \
17740266059SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, msg, dfname, sm_errstring(save_errno)); \
17840266059SGregory Neil Shapiro if (SuperSafe == SAFE_REALLY) \
17906f25ae9SGregory Neil Shapiro { \
1802fb4f839SGregory Neil Shapiro SM_CLOSE_FP(e->e_dfp); \
18106f25ae9SGregory Neil Shapiro e->e_flags &= ~EF_HAS_DF; \
18206f25ae9SGregory Neil Shapiro } \
18306f25ae9SGregory Neil Shapiro errno = save_errno; \
18406f25ae9SGregory Neil Shapiro }
18506f25ae9SGregory Neil Shapiro
18606f25ae9SGregory Neil Shapiro /*
18706f25ae9SGregory Neil Shapiro ** MILTER_TIMEOUT -- make sure socket is ready in time
18806f25ae9SGregory Neil Shapiro **
18906f25ae9SGregory Neil Shapiro ** Parameters:
19006f25ae9SGregory Neil Shapiro ** routine -- routine name for debug/logging
19106f25ae9SGregory Neil Shapiro ** secs -- number of seconds in timeout
19206f25ae9SGregory Neil Shapiro ** write -- waiting to read or write?
19340266059SGregory Neil Shapiro ** started -- whether this is part of a previous sequence
19406f25ae9SGregory Neil Shapiro **
19506f25ae9SGregory Neil Shapiro ** Assumes 'm' is a milter structure for the current socket.
19606f25ae9SGregory Neil Shapiro */
19706f25ae9SGregory Neil Shapiro
198d0cef73dSGregory Neil Shapiro # define MILTER_TIMEOUT(routine, secs, write, started, function) \
19906f25ae9SGregory Neil Shapiro { \
20006f25ae9SGregory Neil Shapiro int ret; \
20106f25ae9SGregory Neil Shapiro int save_errno; \
20206f25ae9SGregory Neil Shapiro fd_set fds; \
20306f25ae9SGregory Neil Shapiro struct timeval tv; \
20406f25ae9SGregory Neil Shapiro \
205da7d7b9cSGregory Neil Shapiro if (!SM_FD_OK_SELECT(m->mf_sock)) \
20606f25ae9SGregory Neil Shapiro { \
20706f25ae9SGregory Neil Shapiro if (tTd(64, 5)) \
20840266059SGregory Neil Shapiro sm_dprintf("milter_%s(%s): socket %d is larger than FD_SETSIZE %d\n", \
20940266059SGregory Neil Shapiro (routine), m->mf_name, m->mf_sock, \
21040266059SGregory Neil Shapiro SM_FD_SETSIZE); \
21140266059SGregory Neil Shapiro if (MilterLogLevel > 0) \
21206f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, \
21340266059SGregory Neil Shapiro "Milter (%s): socket(%s) %d is larger than FD_SETSIZE %d", \
21440266059SGregory Neil Shapiro m->mf_name, (routine), m->mf_sock, \
21540266059SGregory Neil Shapiro SM_FD_SETSIZE); \
21640266059SGregory Neil Shapiro milter_error(m, e); \
21706f25ae9SGregory Neil Shapiro return NULL; \
21806f25ae9SGregory Neil Shapiro } \
21906f25ae9SGregory Neil Shapiro \
220605302a5SGregory Neil Shapiro do \
221605302a5SGregory Neil Shapiro { \
22206f25ae9SGregory Neil Shapiro FD_ZERO(&fds); \
223193538b7SGregory Neil Shapiro SM_FD_SET(m->mf_sock, &fds); \
22440266059SGregory Neil Shapiro tv.tv_sec = (secs); \
22506f25ae9SGregory Neil Shapiro tv.tv_usec = 0; \
22606f25ae9SGregory Neil Shapiro ret = select(m->mf_sock + 1, \
22740266059SGregory Neil Shapiro (write) ? NULL : &fds, \
22840266059SGregory Neil Shapiro (write) ? &fds : NULL, \
22906f25ae9SGregory Neil Shapiro NULL, &tv); \
230605302a5SGregory Neil Shapiro } while (ret < 0 && errno == EINTR); \
23106f25ae9SGregory Neil Shapiro \
23206f25ae9SGregory Neil Shapiro switch (ret) \
23306f25ae9SGregory Neil Shapiro { \
23406f25ae9SGregory Neil Shapiro case 0: \
23506f25ae9SGregory Neil Shapiro if (tTd(64, 5)) \
236d0cef73dSGregory Neil Shapiro sm_dprintf("milter_%s(%s): timeout, where=%s\n", \
237d0cef73dSGregory Neil Shapiro (routine), m->mf_name, (function)); \
23840266059SGregory Neil Shapiro if (MilterLogLevel > 0) \
23940266059SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, \
240d0cef73dSGregory Neil Shapiro "Milter (%s): timeout %s data %s, where=%s", \
241d0cef73dSGregory Neil Shapiro m->mf_name, \
24240266059SGregory Neil Shapiro started ? "during" : "before", \
243d0cef73dSGregory Neil Shapiro (routine), (function)); \
24440266059SGregory Neil Shapiro milter_error(m, e); \
24506f25ae9SGregory Neil Shapiro return NULL; \
24606f25ae9SGregory Neil Shapiro \
24706f25ae9SGregory Neil Shapiro case -1: \
24806f25ae9SGregory Neil Shapiro save_errno = errno; \
24906f25ae9SGregory Neil Shapiro if (tTd(64, 5)) \
25040266059SGregory Neil Shapiro sm_dprintf("milter_%s(%s): select: %s\n", (routine), \
25140266059SGregory Neil Shapiro m->mf_name, sm_errstring(save_errno)); \
25240266059SGregory Neil Shapiro if (MilterLogLevel > 0) \
25340266059SGregory Neil Shapiro { \
25406f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, \
25540266059SGregory Neil Shapiro "Milter (%s): select(%s): %s", \
25640266059SGregory Neil Shapiro m->mf_name, (routine), \
25740266059SGregory Neil Shapiro sm_errstring(save_errno)); \
25840266059SGregory Neil Shapiro } \
25940266059SGregory Neil Shapiro milter_error(m, e); \
26006f25ae9SGregory Neil Shapiro return NULL; \
26106f25ae9SGregory Neil Shapiro \
26206f25ae9SGregory Neil Shapiro default: \
263193538b7SGregory Neil Shapiro if (SM_FD_ISSET(m->mf_sock, &fds)) \
26406f25ae9SGregory Neil Shapiro break; \
26506f25ae9SGregory Neil Shapiro if (tTd(64, 5)) \
26640266059SGregory Neil Shapiro sm_dprintf("milter_%s(%s): socket not ready\n", \
26740266059SGregory Neil Shapiro (routine), m->mf_name); \
26840266059SGregory Neil Shapiro if (MilterLogLevel > 0) \
26940266059SGregory Neil Shapiro { \
27006f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id, \
27140266059SGregory Neil Shapiro "Milter (%s): socket(%s) not ready", \
27240266059SGregory Neil Shapiro m->mf_name, (routine)); \
27340266059SGregory Neil Shapiro } \
27440266059SGregory Neil Shapiro milter_error(m, e); \
27506f25ae9SGregory Neil Shapiro return NULL; \
27606f25ae9SGregory Neil Shapiro } \
27706f25ae9SGregory Neil Shapiro }
27806f25ae9SGregory Neil Shapiro
27906f25ae9SGregory Neil Shapiro /*
28006f25ae9SGregory Neil Shapiro ** Low level functions
28106f25ae9SGregory Neil Shapiro */
28206f25ae9SGregory Neil Shapiro
28340266059SGregory Neil Shapiro /*
28406f25ae9SGregory Neil Shapiro ** MILTER_READ -- read from a remote milter filter
28506f25ae9SGregory Neil Shapiro **
28606f25ae9SGregory Neil Shapiro ** Parameters:
28706f25ae9SGregory Neil Shapiro ** m -- milter to read from.
28806f25ae9SGregory Neil Shapiro ** cmd -- return param for command read.
28906f25ae9SGregory Neil Shapiro ** rlen -- return length of response string.
29006f25ae9SGregory Neil Shapiro ** to -- timeout in seconds.
29106f25ae9SGregory Neil Shapiro ** e -- current envelope.
29206f25ae9SGregory Neil Shapiro **
29306f25ae9SGregory Neil Shapiro ** Returns:
29406f25ae9SGregory Neil Shapiro ** response string (may be NULL)
29506f25ae9SGregory Neil Shapiro */
29606f25ae9SGregory Neil Shapiro
29706f25ae9SGregory Neil Shapiro static char *
milter_sysread(m,buf,sz,to,e,where)298d0cef73dSGregory Neil Shapiro milter_sysread(m, buf, sz, to, e, where)
29906f25ae9SGregory Neil Shapiro struct milter *m;
30006f25ae9SGregory Neil Shapiro char *buf;
30106f25ae9SGregory Neil Shapiro ssize_t sz;
30206f25ae9SGregory Neil Shapiro time_t to;
30306f25ae9SGregory Neil Shapiro ENVELOPE *e;
304d0cef73dSGregory Neil Shapiro const char *where;
30506f25ae9SGregory Neil Shapiro {
30642e5d165SGregory Neil Shapiro time_t readstart = 0;
30706f25ae9SGregory Neil Shapiro ssize_t len, curl;
30840266059SGregory Neil Shapiro bool started = false;
30906f25ae9SGregory Neil Shapiro
31006f25ae9SGregory Neil Shapiro curl = 0;
31106f25ae9SGregory Neil Shapiro
31206f25ae9SGregory Neil Shapiro if (to > 0)
31306f25ae9SGregory Neil Shapiro readstart = curtime();
31406f25ae9SGregory Neil Shapiro
31506f25ae9SGregory Neil Shapiro for (;;)
31606f25ae9SGregory Neil Shapiro {
31706f25ae9SGregory Neil Shapiro if (to > 0)
31806f25ae9SGregory Neil Shapiro {
31906f25ae9SGregory Neil Shapiro time_t now;
32006f25ae9SGregory Neil Shapiro
32106f25ae9SGregory Neil Shapiro now = curtime();
32206f25ae9SGregory Neil Shapiro if (now - readstart >= to)
32306f25ae9SGregory Neil Shapiro {
32406f25ae9SGregory Neil Shapiro if (tTd(64, 5))
325d0cef73dSGregory Neil Shapiro sm_dprintf("milter_sys_read (%s): timeout %s data read in %s",
326d0cef73dSGregory Neil Shapiro m->mf_name,
32740266059SGregory Neil Shapiro started ? "during" : "before",
328d0cef73dSGregory Neil Shapiro where);
32940266059SGregory Neil Shapiro if (MilterLogLevel > 0)
33006f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
331d0cef73dSGregory Neil Shapiro "Milter (%s): timeout %s data read in %s",
332d0cef73dSGregory Neil Shapiro m->mf_name,
33340266059SGregory Neil Shapiro started ? "during" : "before",
334d0cef73dSGregory Neil Shapiro where);
33540266059SGregory Neil Shapiro milter_error(m, e);
33606f25ae9SGregory Neil Shapiro return NULL;
33706f25ae9SGregory Neil Shapiro }
33806f25ae9SGregory Neil Shapiro to -= now - readstart;
33906f25ae9SGregory Neil Shapiro readstart = now;
340d0cef73dSGregory Neil Shapiro MILTER_TIMEOUT("read", to, false, started, where);
34106f25ae9SGregory Neil Shapiro }
34206f25ae9SGregory Neil Shapiro
34306f25ae9SGregory Neil Shapiro len = read(m->mf_sock, buf + curl, sz - curl);
34406f25ae9SGregory Neil Shapiro
34506f25ae9SGregory Neil Shapiro if (len < 0)
34606f25ae9SGregory Neil Shapiro {
34706f25ae9SGregory Neil Shapiro int save_errno = errno;
34806f25ae9SGregory Neil Shapiro
34906f25ae9SGregory Neil Shapiro if (tTd(64, 5))
350d0cef73dSGregory Neil Shapiro sm_dprintf("milter_sys_read(%s): read returned %ld: %s\n",
35106f25ae9SGregory Neil Shapiro m->mf_name, (long) len,
35240266059SGregory Neil Shapiro sm_errstring(save_errno));
35340266059SGregory Neil Shapiro if (MilterLogLevel > 0)
35406f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
35540266059SGregory Neil Shapiro "Milter (%s): read returned %ld: %s",
35606f25ae9SGregory Neil Shapiro m->mf_name, (long) len,
35740266059SGregory Neil Shapiro sm_errstring(save_errno));
35840266059SGregory Neil Shapiro milter_error(m, e);
35906f25ae9SGregory Neil Shapiro return NULL;
36006f25ae9SGregory Neil Shapiro }
36106f25ae9SGregory Neil Shapiro
36240266059SGregory Neil Shapiro started = true;
36306f25ae9SGregory Neil Shapiro curl += len;
364602a2b1bSGregory Neil Shapiro if (len == 0 || curl >= sz)
36506f25ae9SGregory Neil Shapiro break;
36606f25ae9SGregory Neil Shapiro
36706f25ae9SGregory Neil Shapiro }
36806f25ae9SGregory Neil Shapiro
36906f25ae9SGregory Neil Shapiro if (curl != sz)
37006f25ae9SGregory Neil Shapiro {
37106f25ae9SGregory Neil Shapiro if (tTd(64, 5))
372d0cef73dSGregory Neil Shapiro sm_dprintf("milter_sys_read(%s): cmd read returned %ld, expecting %ld\n",
37306f25ae9SGregory Neil Shapiro m->mf_name, (long) curl, (long) sz);
37440266059SGregory Neil Shapiro if (MilterLogLevel > 0)
37506f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
376d0cef73dSGregory Neil Shapiro "milter_sys_read(%s): cmd read returned %ld, expecting %ld",
37706f25ae9SGregory Neil Shapiro m->mf_name, (long) curl, (long) sz);
37840266059SGregory Neil Shapiro milter_error(m, e);
37906f25ae9SGregory Neil Shapiro return NULL;
38006f25ae9SGregory Neil Shapiro }
38106f25ae9SGregory Neil Shapiro return buf;
38206f25ae9SGregory Neil Shapiro }
38306f25ae9SGregory Neil Shapiro
38406f25ae9SGregory Neil Shapiro static char *
milter_read(m,cmd,rlen,to,e,where)385d0cef73dSGregory Neil Shapiro milter_read(m, cmd, rlen, to, e, where)
38606f25ae9SGregory Neil Shapiro struct milter *m;
38706f25ae9SGregory Neil Shapiro char *cmd;
38806f25ae9SGregory Neil Shapiro ssize_t *rlen;
38906f25ae9SGregory Neil Shapiro time_t to;
39006f25ae9SGregory Neil Shapiro ENVELOPE *e;
391d0cef73dSGregory Neil Shapiro const char *where;
39206f25ae9SGregory Neil Shapiro {
39342e5d165SGregory Neil Shapiro time_t readstart = 0;
39406f25ae9SGregory Neil Shapiro ssize_t expl;
39506f25ae9SGregory Neil Shapiro mi_int32 i;
396d0cef73dSGregory Neil Shapiro # if MILTER_NO_NAGLE && defined(TCP_CORK)
397e92d3f3fSGregory Neil Shapiro int cork = 0;
3985b0945b5SGregory Neil Shapiro # endif
39906f25ae9SGregory Neil Shapiro char *buf;
40006f25ae9SGregory Neil Shapiro char data[MILTER_LEN_BYTES + 1];
40106f25ae9SGregory Neil Shapiro
40213d88268SGregory Neil Shapiro if (m->mf_sock < 0)
40313d88268SGregory Neil Shapiro {
40413d88268SGregory Neil Shapiro if (MilterLogLevel > 0)
40513d88268SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
406d0cef73dSGregory Neil Shapiro "milter_read(%s): socket closed, where=%s",
407d0cef73dSGregory Neil Shapiro m->mf_name, where);
40813d88268SGregory Neil Shapiro milter_error(m, e);
40913d88268SGregory Neil Shapiro return NULL;
41013d88268SGregory Neil Shapiro }
41113d88268SGregory Neil Shapiro
41206f25ae9SGregory Neil Shapiro *rlen = 0;
41306f25ae9SGregory Neil Shapiro *cmd = '\0';
41406f25ae9SGregory Neil Shapiro
41506f25ae9SGregory Neil Shapiro if (to > 0)
41606f25ae9SGregory Neil Shapiro readstart = curtime();
41706f25ae9SGregory Neil Shapiro
418d0cef73dSGregory Neil Shapiro # if MILTER_NO_NAGLE && defined(TCP_CORK)
419e92d3f3fSGregory Neil Shapiro setsockopt(m->mf_sock, IPPROTO_TCP, TCP_CORK, (char *)&cork,
420e92d3f3fSGregory Neil Shapiro sizeof(cork));
4215b0945b5SGregory Neil Shapiro # endif
422e92d3f3fSGregory Neil Shapiro
423d0cef73dSGregory Neil Shapiro if (milter_sysread(m, data, sizeof(data), to, e, where) == NULL)
42406f25ae9SGregory Neil Shapiro return NULL;
42506f25ae9SGregory Neil Shapiro
426d0cef73dSGregory Neil Shapiro # if MILTER_NO_NAGLE && defined(TCP_CORK)
427e92d3f3fSGregory Neil Shapiro cork = 1;
428e92d3f3fSGregory Neil Shapiro setsockopt(m->mf_sock, IPPROTO_TCP, TCP_CORK, (char *)&cork,
429e92d3f3fSGregory Neil Shapiro sizeof(cork));
4305b0945b5SGregory Neil Shapiro # endif
431e92d3f3fSGregory Neil Shapiro
43206f25ae9SGregory Neil Shapiro /* reset timeout */
43306f25ae9SGregory Neil Shapiro if (to > 0)
43406f25ae9SGregory Neil Shapiro {
43506f25ae9SGregory Neil Shapiro time_t now;
43606f25ae9SGregory Neil Shapiro
43706f25ae9SGregory Neil Shapiro now = curtime();
43806f25ae9SGregory Neil Shapiro if (now - readstart >= to)
43906f25ae9SGregory Neil Shapiro {
44006f25ae9SGregory Neil Shapiro if (tTd(64, 5))
441d0cef73dSGregory Neil Shapiro sm_dprintf("milter_read(%s): timeout before data read, where=%s\n",
442d0cef73dSGregory Neil Shapiro m->mf_name, where);
44340266059SGregory Neil Shapiro if (MilterLogLevel > 0)
44406f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
445d0cef73dSGregory Neil Shapiro "Milter read(%s): timeout before data read, where=%s",
446d0cef73dSGregory Neil Shapiro m->mf_name, where);
44740266059SGregory Neil Shapiro milter_error(m, e);
44806f25ae9SGregory Neil Shapiro return NULL;
44906f25ae9SGregory Neil Shapiro }
45006f25ae9SGregory Neil Shapiro to -= now - readstart;
45106f25ae9SGregory Neil Shapiro }
45206f25ae9SGregory Neil Shapiro
45306f25ae9SGregory Neil Shapiro *cmd = data[MILTER_LEN_BYTES];
45406f25ae9SGregory Neil Shapiro data[MILTER_LEN_BYTES] = '\0';
45506f25ae9SGregory Neil Shapiro (void) memcpy(&i, data, MILTER_LEN_BYTES);
45606f25ae9SGregory Neil Shapiro expl = ntohl(i) - 1;
45706f25ae9SGregory Neil Shapiro
45806f25ae9SGregory Neil Shapiro if (tTd(64, 25))
45940266059SGregory Neil Shapiro sm_dprintf("milter_read(%s): expecting %ld bytes\n",
46006f25ae9SGregory Neil Shapiro m->mf_name, (long) expl);
46106f25ae9SGregory Neil Shapiro
46206f25ae9SGregory Neil Shapiro if (expl < 0)
46306f25ae9SGregory Neil Shapiro {
46406f25ae9SGregory Neil Shapiro if (tTd(64, 5))
465d0cef73dSGregory Neil Shapiro sm_dprintf("milter_read(%s): read size %ld out of range, where=%s\n",
466d0cef73dSGregory Neil Shapiro m->mf_name, (long) expl, where);
46740266059SGregory Neil Shapiro if (MilterLogLevel > 0)
46806f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
469d0cef73dSGregory Neil Shapiro "milter_read(%s): read size %ld out of range, where=%s",
470d0cef73dSGregory Neil Shapiro m->mf_name, (long) expl, where);
47140266059SGregory Neil Shapiro milter_error(m, e);
47206f25ae9SGregory Neil Shapiro return NULL;
47306f25ae9SGregory Neil Shapiro }
47406f25ae9SGregory Neil Shapiro
47506f25ae9SGregory Neil Shapiro if (expl == 0)
47606f25ae9SGregory Neil Shapiro return NULL;
47706f25ae9SGregory Neil Shapiro
47806f25ae9SGregory Neil Shapiro buf = (char *) xalloc(expl);
47906f25ae9SGregory Neil Shapiro
480d0cef73dSGregory Neil Shapiro if (milter_sysread(m, buf, expl, to, e, where) == NULL)
48106f25ae9SGregory Neil Shapiro {
48240266059SGregory Neil Shapiro sm_free(buf); /* XXX */
48306f25ae9SGregory Neil Shapiro return NULL;
48406f25ae9SGregory Neil Shapiro }
48506f25ae9SGregory Neil Shapiro
48606f25ae9SGregory Neil Shapiro if (tTd(64, 50))
48740266059SGregory Neil Shapiro sm_dprintf("milter_read(%s): Returning %*s\n",
48806f25ae9SGregory Neil Shapiro m->mf_name, (int) expl, buf);
48906f25ae9SGregory Neil Shapiro *rlen = expl;
49006f25ae9SGregory Neil Shapiro return buf;
49106f25ae9SGregory Neil Shapiro }
492e92d3f3fSGregory Neil Shapiro
49340266059SGregory Neil Shapiro /*
49406f25ae9SGregory Neil Shapiro ** MILTER_WRITE -- write to a remote milter filter
49506f25ae9SGregory Neil Shapiro **
49606f25ae9SGregory Neil Shapiro ** Parameters:
49706f25ae9SGregory Neil Shapiro ** m -- milter to read from.
49806f25ae9SGregory Neil Shapiro ** cmd -- command to send.
49906f25ae9SGregory Neil Shapiro ** buf -- optional command data.
50006f25ae9SGregory Neil Shapiro ** len -- length of buf.
50106f25ae9SGregory Neil Shapiro ** to -- timeout in seconds.
50206f25ae9SGregory Neil Shapiro ** e -- current envelope.
50306f25ae9SGregory Neil Shapiro **
50406f25ae9SGregory Neil Shapiro ** Returns:
50506f25ae9SGregory Neil Shapiro ** buf if successful, NULL otherwise
50606f25ae9SGregory Neil Shapiro ** Not actually used anywhere but function prototype
50706f25ae9SGregory Neil Shapiro ** must match milter_read()
50806f25ae9SGregory Neil Shapiro */
50906f25ae9SGregory Neil Shapiro
51006f25ae9SGregory Neil Shapiro static char *
milter_write(m,cmd,buf,len,to,e,where)511d0cef73dSGregory Neil Shapiro milter_write(m, cmd, buf, len, to, e, where)
51206f25ae9SGregory Neil Shapiro struct milter *m;
513d0cef73dSGregory Neil Shapiro int cmd;
51406f25ae9SGregory Neil Shapiro char *buf;
51506f25ae9SGregory Neil Shapiro ssize_t len;
51606f25ae9SGregory Neil Shapiro time_t to;
51706f25ae9SGregory Neil Shapiro ENVELOPE *e;
518d0cef73dSGregory Neil Shapiro const char *where;
51906f25ae9SGregory Neil Shapiro {
52006f25ae9SGregory Neil Shapiro ssize_t sl, i;
521e92d3f3fSGregory Neil Shapiro int num_vectors;
52206f25ae9SGregory Neil Shapiro mi_int32 nl;
523d0cef73dSGregory Neil Shapiro char command = (char) cmd;
52406f25ae9SGregory Neil Shapiro char data[MILTER_LEN_BYTES + 1];
52540266059SGregory Neil Shapiro bool started = false;
526e92d3f3fSGregory Neil Shapiro struct iovec vector[2];
52706f25ae9SGregory Neil Shapiro
528e92d3f3fSGregory Neil Shapiro /*
529e92d3f3fSGregory Neil Shapiro ** At most two buffers will be written, though
530e92d3f3fSGregory Neil Shapiro ** only one may actually be used (see num_vectors).
531e92d3f3fSGregory Neil Shapiro ** The first is the size/command and the second is the command data.
532e92d3f3fSGregory Neil Shapiro */
533e92d3f3fSGregory Neil Shapiro
534e92d3f3fSGregory Neil Shapiro if (len < 0 || len > MilterMaxDataSize)
53506f25ae9SGregory Neil Shapiro {
53606f25ae9SGregory Neil Shapiro if (tTd(64, 5))
5379bd497b8SGregory Neil Shapiro {
5382fb4f839SGregory Neil Shapiro sm_dprintf("milter_write(%s): length %ld out of range, mds=%ld, cmd=%c\n",
5392fb4f839SGregory Neil Shapiro m->mf_name, (long) len,
5402fb4f839SGregory Neil Shapiro (long) MilterMaxDataSize, command);
5419bd497b8SGregory Neil Shapiro sm_dprintf("milter_write(%s): buf=%s\n",
5429bd497b8SGregory Neil Shapiro m->mf_name, str2prt(buf));
5439bd497b8SGregory Neil Shapiro }
54440266059SGregory Neil Shapiro if (MilterLogLevel > 0)
54506f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
5469bd497b8SGregory Neil Shapiro "milter_write(%s): length %ld out of range, cmd=%c",
5479bd497b8SGregory Neil Shapiro m->mf_name, (long) len, command);
54840266059SGregory Neil Shapiro milter_error(m, e);
54906f25ae9SGregory Neil Shapiro return NULL;
55006f25ae9SGregory Neil Shapiro }
55113d88268SGregory Neil Shapiro if (m->mf_sock < 0)
55213d88268SGregory Neil Shapiro {
55313d88268SGregory Neil Shapiro if (MilterLogLevel > 0)
55413d88268SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
55513d88268SGregory Neil Shapiro "milter_write(%s): socket closed",
55613d88268SGregory Neil Shapiro m->mf_name);
55713d88268SGregory Neil Shapiro milter_error(m, e);
55813d88268SGregory Neil Shapiro return NULL;
55913d88268SGregory Neil Shapiro }
56006f25ae9SGregory Neil Shapiro
56106f25ae9SGregory Neil Shapiro if (tTd(64, 20))
56240266059SGregory Neil Shapiro sm_dprintf("milter_write(%s): cmd %c, len %ld\n",
563d0cef73dSGregory Neil Shapiro m->mf_name, command, (long) len);
56406f25ae9SGregory Neil Shapiro
565d0cef73dSGregory Neil Shapiro nl = htonl(len + 1); /* add 1 for the command char */
56606f25ae9SGregory Neil Shapiro (void) memcpy(data, (char *) &nl, MILTER_LEN_BYTES);
567d0cef73dSGregory Neil Shapiro data[MILTER_LEN_BYTES] = command;
56806f25ae9SGregory Neil Shapiro sl = MILTER_LEN_BYTES + 1;
56906f25ae9SGregory Neil Shapiro
570e92d3f3fSGregory Neil Shapiro /* set up the vector for the size / command */
571e92d3f3fSGregory Neil Shapiro vector[0].iov_base = (void *) data;
572e92d3f3fSGregory Neil Shapiro vector[0].iov_len = sl;
573e92d3f3fSGregory Neil Shapiro
574e92d3f3fSGregory Neil Shapiro /*
575e92d3f3fSGregory Neil Shapiro ** Determine if there is command data. If so, there will be two
576e92d3f3fSGregory Neil Shapiro ** vectors. If not, there will be only one. The vectors are set
577e92d3f3fSGregory Neil Shapiro ** up here and 'num_vectors' and 'sl' are set appropriately.
578e92d3f3fSGregory Neil Shapiro */
579e92d3f3fSGregory Neil Shapiro
580e92d3f3fSGregory Neil Shapiro /* NOTE: len<0 has already been checked for. Pedantic */
581e92d3f3fSGregory Neil Shapiro if (len <= 0 || buf == NULL)
582e92d3f3fSGregory Neil Shapiro {
583e92d3f3fSGregory Neil Shapiro /* There is no command data -- only a size / command data */
584e92d3f3fSGregory Neil Shapiro num_vectors = 1;
585e92d3f3fSGregory Neil Shapiro }
586e92d3f3fSGregory Neil Shapiro else
587e92d3f3fSGregory Neil Shapiro {
588e92d3f3fSGregory Neil Shapiro /*
589e92d3f3fSGregory Neil Shapiro ** There is both size / command and command data.
590e92d3f3fSGregory Neil Shapiro ** Set up the vector for the command data.
591e92d3f3fSGregory Neil Shapiro */
592e92d3f3fSGregory Neil Shapiro
593e92d3f3fSGregory Neil Shapiro num_vectors = 2;
594e92d3f3fSGregory Neil Shapiro sl += len;
595e92d3f3fSGregory Neil Shapiro vector[1].iov_base = (void *) buf;
596e92d3f3fSGregory Neil Shapiro vector[1].iov_len = len;
597e92d3f3fSGregory Neil Shapiro
598e92d3f3fSGregory Neil Shapiro if (tTd(64, 50))
599e92d3f3fSGregory Neil Shapiro sm_dprintf("milter_write(%s): Sending %*s\n",
600e92d3f3fSGregory Neil Shapiro m->mf_name, (int) len, buf);
601e92d3f3fSGregory Neil Shapiro }
602e92d3f3fSGregory Neil Shapiro
60306f25ae9SGregory Neil Shapiro if (to > 0)
604d0cef73dSGregory Neil Shapiro MILTER_TIMEOUT("write", to, true, started, where);
60506f25ae9SGregory Neil Shapiro
606e92d3f3fSGregory Neil Shapiro /* write the vector(s) */
607e92d3f3fSGregory Neil Shapiro i = writev(m->mf_sock, vector, num_vectors);
60806f25ae9SGregory Neil Shapiro if (i != sl)
60906f25ae9SGregory Neil Shapiro {
61006f25ae9SGregory Neil Shapiro int save_errno = errno;
61106f25ae9SGregory Neil Shapiro
61206f25ae9SGregory Neil Shapiro if (tTd(64, 5))
61340266059SGregory Neil Shapiro sm_dprintf("milter_write(%s): write(%c) returned %ld, expected %ld: %s\n",
614d0cef73dSGregory Neil Shapiro m->mf_name, command, (long) i, (long) sl,
61540266059SGregory Neil Shapiro sm_errstring(save_errno));
61640266059SGregory Neil Shapiro if (MilterLogLevel > 0)
61706f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
61840266059SGregory Neil Shapiro "Milter (%s): write(%c) returned %ld, expected %ld: %s",
619d0cef73dSGregory Neil Shapiro m->mf_name, command, (long) i, (long) sl,
62040266059SGregory Neil Shapiro sm_errstring(save_errno));
62140266059SGregory Neil Shapiro milter_error(m, e);
62206f25ae9SGregory Neil Shapiro return NULL;
62306f25ae9SGregory Neil Shapiro }
62406f25ae9SGregory Neil Shapiro return buf;
62506f25ae9SGregory Neil Shapiro }
62606f25ae9SGregory Neil Shapiro
62706f25ae9SGregory Neil Shapiro /*
62806f25ae9SGregory Neil Shapiro ** Utility functions
62906f25ae9SGregory Neil Shapiro */
63006f25ae9SGregory Neil Shapiro
63140266059SGregory Neil Shapiro /*
63206f25ae9SGregory Neil Shapiro ** MILTER_OPEN -- connect to remote milter filter
63306f25ae9SGregory Neil Shapiro **
63406f25ae9SGregory Neil Shapiro ** Parameters:
63506f25ae9SGregory Neil Shapiro ** m -- milter to connect to.
63606f25ae9SGregory Neil Shapiro ** parseonly -- parse but don't connect.
63706f25ae9SGregory Neil Shapiro ** e -- current envelope.
63806f25ae9SGregory Neil Shapiro **
63906f25ae9SGregory Neil Shapiro ** Returns:
640d9986b26SGregory Neil Shapiro ** connected socket if successful && !parseonly,
64106f25ae9SGregory Neil Shapiro ** 0 upon parse success if parseonly,
64206f25ae9SGregory Neil Shapiro ** -1 otherwise.
64306f25ae9SGregory Neil Shapiro */
64406f25ae9SGregory Neil Shapiro
64513058a91SGregory Neil Shapiro static jmp_buf MilterConnectTimeout;
64613058a91SGregory Neil Shapiro
64706f25ae9SGregory Neil Shapiro static int
milter_open(m,parseonly,e)64806f25ae9SGregory Neil Shapiro milter_open(m, parseonly, e)
64906f25ae9SGregory Neil Shapiro struct milter *m;
65006f25ae9SGregory Neil Shapiro bool parseonly;
65106f25ae9SGregory Neil Shapiro ENVELOPE *e;
65206f25ae9SGregory Neil Shapiro {
65306f25ae9SGregory Neil Shapiro int sock = 0;
65406f25ae9SGregory Neil Shapiro SOCKADDR_LEN_T addrlen = 0;
65506f25ae9SGregory Neil Shapiro int addrno = 0;
65606f25ae9SGregory Neil Shapiro int save_errno;
65706f25ae9SGregory Neil Shapiro char *p;
65806f25ae9SGregory Neil Shapiro char *colon;
65906f25ae9SGregory Neil Shapiro char *at;
66006f25ae9SGregory Neil Shapiro struct hostent *hp = NULL;
66106f25ae9SGregory Neil Shapiro SOCKADDR addr;
66206f25ae9SGregory Neil Shapiro
6632fb4f839SGregory Neil Shapiro if (SM_IS_EMPTY(m->mf_conn))
66406f25ae9SGregory Neil Shapiro {
66506f25ae9SGregory Neil Shapiro if (tTd(64, 5))
66640266059SGregory Neil Shapiro sm_dprintf("X%s: empty or missing socket information\n",
66706f25ae9SGregory Neil Shapiro m->mf_name);
66806f25ae9SGregory Neil Shapiro if (parseonly)
66906f25ae9SGregory Neil Shapiro syserr("X%s: empty or missing socket information",
67006f25ae9SGregory Neil Shapiro m->mf_name);
67113bd1963SGregory Neil Shapiro else if (MilterLogLevel > 0)
67206f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
67340266059SGregory Neil Shapiro "Milter (%s): empty or missing socket information",
67406f25ae9SGregory Neil Shapiro m->mf_name);
67540266059SGregory Neil Shapiro milter_error(m, e);
67606f25ae9SGregory Neil Shapiro return -1;
67706f25ae9SGregory Neil Shapiro }
67806f25ae9SGregory Neil Shapiro
67906f25ae9SGregory Neil Shapiro /* protocol:filename or protocol:port@host */
680d0cef73dSGregory Neil Shapiro memset(&addr, '\0', sizeof(addr));
68106f25ae9SGregory Neil Shapiro p = m->mf_conn;
68206f25ae9SGregory Neil Shapiro colon = strchr(p, ':');
68306f25ae9SGregory Neil Shapiro if (colon != NULL)
68406f25ae9SGregory Neil Shapiro {
68506f25ae9SGregory Neil Shapiro *colon = '\0';
68606f25ae9SGregory Neil Shapiro
68706f25ae9SGregory Neil Shapiro if (*p == '\0')
68806f25ae9SGregory Neil Shapiro {
68906f25ae9SGregory Neil Shapiro # if NETUNIX
69006f25ae9SGregory Neil Shapiro /* default to AF_UNIX */
69106f25ae9SGregory Neil Shapiro addr.sa.sa_family = AF_UNIX;
6925b0945b5SGregory Neil Shapiro # else
69306f25ae9SGregory Neil Shapiro # if NETINET
69406f25ae9SGregory Neil Shapiro /* default to AF_INET */
69506f25ae9SGregory Neil Shapiro addr.sa.sa_family = AF_INET;
69606f25ae9SGregory Neil Shapiro # else /* NETINET */
69706f25ae9SGregory Neil Shapiro # if NETINET6
69806f25ae9SGregory Neil Shapiro /* default to AF_INET6 */
69906f25ae9SGregory Neil Shapiro addr.sa.sa_family = AF_INET6;
70006f25ae9SGregory Neil Shapiro # else /* NETINET6 */
70106f25ae9SGregory Neil Shapiro /* no protocols available */
70213bd1963SGregory Neil Shapiro if (MilterLogLevel > 0)
70306f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
70440266059SGregory Neil Shapiro "Milter (%s): no valid socket protocols available",
70506f25ae9SGregory Neil Shapiro m->mf_name);
70640266059SGregory Neil Shapiro milter_error(m, e);
70706f25ae9SGregory Neil Shapiro return -1;
70806f25ae9SGregory Neil Shapiro # endif /* NETINET6 */
70906f25ae9SGregory Neil Shapiro # endif /* NETINET */
71006f25ae9SGregory Neil Shapiro # endif /* NETUNIX */
71106f25ae9SGregory Neil Shapiro }
71206f25ae9SGregory Neil Shapiro # if NETUNIX
7132fb4f839SGregory Neil Shapiro else if (SM_STRCASEEQ(p, "unix") ||
7142fb4f839SGregory Neil Shapiro SM_STRCASEEQ(p, "local"))
71506f25ae9SGregory Neil Shapiro addr.sa.sa_family = AF_UNIX;
7165b0945b5SGregory Neil Shapiro # endif
71706f25ae9SGregory Neil Shapiro # if NETINET
7182fb4f839SGregory Neil Shapiro else if (SM_STRCASEEQ(p, "inet"))
71906f25ae9SGregory Neil Shapiro addr.sa.sa_family = AF_INET;
7205b0945b5SGregory Neil Shapiro # endif
72106f25ae9SGregory Neil Shapiro # if NETINET6
7222fb4f839SGregory Neil Shapiro else if (SM_STRCASEEQ(p, "inet6"))
72306f25ae9SGregory Neil Shapiro addr.sa.sa_family = AF_INET6;
7245b0945b5SGregory Neil Shapiro # endif
72506f25ae9SGregory Neil Shapiro else
72606f25ae9SGregory Neil Shapiro {
72706f25ae9SGregory Neil Shapiro # ifdef EPROTONOSUPPORT
72806f25ae9SGregory Neil Shapiro errno = EPROTONOSUPPORT;
7295b0945b5SGregory Neil Shapiro # else
73006f25ae9SGregory Neil Shapiro errno = EINVAL;
7315b0945b5SGregory Neil Shapiro # endif
73206f25ae9SGregory Neil Shapiro if (tTd(64, 5))
73340266059SGregory Neil Shapiro sm_dprintf("X%s: unknown socket type %s\n",
73406f25ae9SGregory Neil Shapiro m->mf_name, p);
73506f25ae9SGregory Neil Shapiro if (parseonly)
73606f25ae9SGregory Neil Shapiro syserr("X%s: unknown socket type %s",
73706f25ae9SGregory Neil Shapiro m->mf_name, p);
73813bd1963SGregory Neil Shapiro else if (MilterLogLevel > 0)
73906f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
74040266059SGregory Neil Shapiro "Milter (%s): unknown socket type %s",
74106f25ae9SGregory Neil Shapiro m->mf_name, p);
74240266059SGregory Neil Shapiro milter_error(m, e);
74306f25ae9SGregory Neil Shapiro return -1;
74406f25ae9SGregory Neil Shapiro }
74506f25ae9SGregory Neil Shapiro *colon++ = ':';
74606f25ae9SGregory Neil Shapiro }
74706f25ae9SGregory Neil Shapiro else
74806f25ae9SGregory Neil Shapiro {
74906f25ae9SGregory Neil Shapiro /* default to AF_UNIX */
75006f25ae9SGregory Neil Shapiro addr.sa.sa_family = AF_UNIX;
75106f25ae9SGregory Neil Shapiro colon = p;
75206f25ae9SGregory Neil Shapiro }
75306f25ae9SGregory Neil Shapiro
75406f25ae9SGregory Neil Shapiro # if NETUNIX
75506f25ae9SGregory Neil Shapiro if (addr.sa.sa_family == AF_UNIX)
75606f25ae9SGregory Neil Shapiro {
75706f25ae9SGregory Neil Shapiro long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_EXECOK;
75806f25ae9SGregory Neil Shapiro
75906f25ae9SGregory Neil Shapiro at = colon;
760d0cef73dSGregory Neil Shapiro if (strlen(colon) >= sizeof(addr.sunix.sun_path))
76106f25ae9SGregory Neil Shapiro {
76206f25ae9SGregory Neil Shapiro if (tTd(64, 5))
76340266059SGregory Neil Shapiro sm_dprintf("X%s: local socket name %s too long\n",
76406f25ae9SGregory Neil Shapiro m->mf_name, colon);
76506f25ae9SGregory Neil Shapiro errno = EINVAL;
76606f25ae9SGregory Neil Shapiro if (parseonly)
76706f25ae9SGregory Neil Shapiro syserr("X%s: local socket name %s too long",
76806f25ae9SGregory Neil Shapiro m->mf_name, colon);
76913bd1963SGregory Neil Shapiro else if (MilterLogLevel > 0)
77006f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
77140266059SGregory Neil Shapiro "Milter (%s): local socket name %s too long",
77206f25ae9SGregory Neil Shapiro m->mf_name, colon);
77340266059SGregory Neil Shapiro milter_error(m, e);
77406f25ae9SGregory Neil Shapiro return -1;
77506f25ae9SGregory Neil Shapiro }
77606f25ae9SGregory Neil Shapiro errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff,
77706f25ae9SGregory Neil Shapiro S_IRUSR|S_IWUSR, NULL);
77806f25ae9SGregory Neil Shapiro
77906f25ae9SGregory Neil Shapiro /* if just parsing .cf file, socket doesn't need to exist */
78006f25ae9SGregory Neil Shapiro if (parseonly && errno == ENOENT)
78106f25ae9SGregory Neil Shapiro {
78206f25ae9SGregory Neil Shapiro if (OpMode == MD_DAEMON ||
78306f25ae9SGregory Neil Shapiro OpMode == MD_FGDAEMON)
78440266059SGregory Neil Shapiro (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
78506f25ae9SGregory Neil Shapiro "WARNING: X%s: local socket name %s missing\n",
78606f25ae9SGregory Neil Shapiro m->mf_name, colon);
78706f25ae9SGregory Neil Shapiro }
78806f25ae9SGregory Neil Shapiro else if (errno != 0)
78906f25ae9SGregory Neil Shapiro {
79006f25ae9SGregory Neil Shapiro /* if not safe, don't create */
79106f25ae9SGregory Neil Shapiro save_errno = errno;
79206f25ae9SGregory Neil Shapiro if (tTd(64, 5))
79340266059SGregory Neil Shapiro sm_dprintf("X%s: local socket name %s unsafe\n",
79406f25ae9SGregory Neil Shapiro m->mf_name, colon);
79506f25ae9SGregory Neil Shapiro errno = save_errno;
79606f25ae9SGregory Neil Shapiro if (parseonly)
79706f25ae9SGregory Neil Shapiro {
79806f25ae9SGregory Neil Shapiro if (OpMode == MD_DAEMON ||
79906f25ae9SGregory Neil Shapiro OpMode == MD_FGDAEMON ||
80006f25ae9SGregory Neil Shapiro OpMode == MD_SMTP)
80106f25ae9SGregory Neil Shapiro syserr("X%s: local socket name %s unsafe",
80206f25ae9SGregory Neil Shapiro m->mf_name, colon);
80306f25ae9SGregory Neil Shapiro }
80413bd1963SGregory Neil Shapiro else if (MilterLogLevel > 0)
80506f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
80640266059SGregory Neil Shapiro "Milter (%s): local socket name %s unsafe",
80706f25ae9SGregory Neil Shapiro m->mf_name, colon);
80840266059SGregory Neil Shapiro milter_error(m, e);
80906f25ae9SGregory Neil Shapiro return -1;
81006f25ae9SGregory Neil Shapiro }
81106f25ae9SGregory Neil Shapiro
81240266059SGregory Neil Shapiro (void) sm_strlcpy(addr.sunix.sun_path, colon,
813d0cef73dSGregory Neil Shapiro sizeof(addr.sunix.sun_path));
81406f25ae9SGregory Neil Shapiro addrlen = sizeof(struct sockaddr_un);
81506f25ae9SGregory Neil Shapiro }
81606f25ae9SGregory Neil Shapiro else
81706f25ae9SGregory Neil Shapiro # endif /* NETUNIX */
81806f25ae9SGregory Neil Shapiro # if NETINET || NETINET6
81940266059SGregory Neil Shapiro if (false
82006f25ae9SGregory Neil Shapiro # if NETINET
82106f25ae9SGregory Neil Shapiro || addr.sa.sa_family == AF_INET
8225b0945b5SGregory Neil Shapiro # endif
82306f25ae9SGregory Neil Shapiro # if NETINET6
82406f25ae9SGregory Neil Shapiro || addr.sa.sa_family == AF_INET6
8255b0945b5SGregory Neil Shapiro # endif
82606f25ae9SGregory Neil Shapiro )
82706f25ae9SGregory Neil Shapiro {
82840266059SGregory Neil Shapiro unsigned short port;
82906f25ae9SGregory Neil Shapiro
83006f25ae9SGregory Neil Shapiro /* Parse port@host */
83106f25ae9SGregory Neil Shapiro at = strchr(colon, '@');
83206f25ae9SGregory Neil Shapiro if (at == NULL)
83306f25ae9SGregory Neil Shapiro {
83406f25ae9SGregory Neil Shapiro if (tTd(64, 5))
83540266059SGregory Neil Shapiro sm_dprintf("X%s: bad address %s (expected port@host)\n",
83606f25ae9SGregory Neil Shapiro m->mf_name, colon);
83706f25ae9SGregory Neil Shapiro if (parseonly)
83806f25ae9SGregory Neil Shapiro syserr("X%s: bad address %s (expected port@host)",
83906f25ae9SGregory Neil Shapiro m->mf_name, colon);
84013bd1963SGregory Neil Shapiro else if (MilterLogLevel > 0)
84106f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
84240266059SGregory Neil Shapiro "Milter (%s): bad address %s (expected port@host)",
84306f25ae9SGregory Neil Shapiro m->mf_name, colon);
84440266059SGregory Neil Shapiro milter_error(m, e);
84506f25ae9SGregory Neil Shapiro return -1;
84606f25ae9SGregory Neil Shapiro }
84706f25ae9SGregory Neil Shapiro *at = '\0';
84806f25ae9SGregory Neil Shapiro if (isascii(*colon) && isdigit(*colon))
84940266059SGregory Neil Shapiro port = htons((unsigned short) atoi(colon));
85006f25ae9SGregory Neil Shapiro else
85106f25ae9SGregory Neil Shapiro {
85206f25ae9SGregory Neil Shapiro # ifdef NO_GETSERVBYNAME
85306f25ae9SGregory Neil Shapiro if (tTd(64, 5))
85440266059SGregory Neil Shapiro sm_dprintf("X%s: invalid port number %s\n",
85506f25ae9SGregory Neil Shapiro m->mf_name, colon);
85606f25ae9SGregory Neil Shapiro if (parseonly)
85706f25ae9SGregory Neil Shapiro syserr("X%s: invalid port number %s",
85806f25ae9SGregory Neil Shapiro m->mf_name, colon);
85913bd1963SGregory Neil Shapiro else if (MilterLogLevel > 0)
86006f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
86140266059SGregory Neil Shapiro "Milter (%s): invalid port number %s",
86206f25ae9SGregory Neil Shapiro m->mf_name, colon);
86340266059SGregory Neil Shapiro milter_error(m, e);
86406f25ae9SGregory Neil Shapiro return -1;
86506f25ae9SGregory Neil Shapiro # else /* NO_GETSERVBYNAME */
866d0cef73dSGregory Neil Shapiro struct servent *sp;
86706f25ae9SGregory Neil Shapiro
86806f25ae9SGregory Neil Shapiro sp = getservbyname(colon, "tcp");
86906f25ae9SGregory Neil Shapiro if (sp == NULL)
87006f25ae9SGregory Neil Shapiro {
87106f25ae9SGregory Neil Shapiro save_errno = errno;
87206f25ae9SGregory Neil Shapiro if (tTd(64, 5))
87340266059SGregory Neil Shapiro sm_dprintf("X%s: unknown port name %s\n",
87406f25ae9SGregory Neil Shapiro m->mf_name, colon);
87506f25ae9SGregory Neil Shapiro errno = save_errno;
87606f25ae9SGregory Neil Shapiro if (parseonly)
87706f25ae9SGregory Neil Shapiro syserr("X%s: unknown port name %s",
87806f25ae9SGregory Neil Shapiro m->mf_name, colon);
87913bd1963SGregory Neil Shapiro else if (MilterLogLevel > 0)
88006f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
88140266059SGregory Neil Shapiro "Milter (%s): unknown port name %s",
88206f25ae9SGregory Neil Shapiro m->mf_name, colon);
88340266059SGregory Neil Shapiro milter_error(m, e);
88406f25ae9SGregory Neil Shapiro return -1;
88506f25ae9SGregory Neil Shapiro }
88606f25ae9SGregory Neil Shapiro port = sp->s_port;
88706f25ae9SGregory Neil Shapiro # endif /* NO_GETSERVBYNAME */
88806f25ae9SGregory Neil Shapiro }
88906f25ae9SGregory Neil Shapiro *at++ = '@';
89006f25ae9SGregory Neil Shapiro if (*at == '[')
89106f25ae9SGregory Neil Shapiro {
89206f25ae9SGregory Neil Shapiro char *end;
89306f25ae9SGregory Neil Shapiro
89406f25ae9SGregory Neil Shapiro end = strchr(at, ']');
89506f25ae9SGregory Neil Shapiro if (end != NULL)
89606f25ae9SGregory Neil Shapiro {
89740266059SGregory Neil Shapiro bool found = false;
89806f25ae9SGregory Neil Shapiro # if NETINET
89906f25ae9SGregory Neil Shapiro unsigned long hid = INADDR_NONE;
9005b0945b5SGregory Neil Shapiro # endif
90106f25ae9SGregory Neil Shapiro # if NETINET6
90206f25ae9SGregory Neil Shapiro struct sockaddr_in6 hid6;
9035b0945b5SGregory Neil Shapiro # endif
90406f25ae9SGregory Neil Shapiro
90506f25ae9SGregory Neil Shapiro *end = '\0';
90606f25ae9SGregory Neil Shapiro # if NETINET
90706f25ae9SGregory Neil Shapiro if (addr.sa.sa_family == AF_INET &&
90806f25ae9SGregory Neil Shapiro (hid = inet_addr(&at[1])) != INADDR_NONE)
90906f25ae9SGregory Neil Shapiro {
91006f25ae9SGregory Neil Shapiro addr.sin.sin_addr.s_addr = hid;
91106f25ae9SGregory Neil Shapiro addr.sin.sin_port = port;
91240266059SGregory Neil Shapiro found = true;
91306f25ae9SGregory Neil Shapiro }
91406f25ae9SGregory Neil Shapiro # endif /* NETINET */
91506f25ae9SGregory Neil Shapiro # if NETINET6
916d0cef73dSGregory Neil Shapiro (void) memset(&hid6, '\0', sizeof(hid6));
91706f25ae9SGregory Neil Shapiro if (addr.sa.sa_family == AF_INET6 &&
91840266059SGregory Neil Shapiro anynet_pton(AF_INET6, &at[1],
91906f25ae9SGregory Neil Shapiro &hid6.sin6_addr) == 1)
92006f25ae9SGregory Neil Shapiro {
92106f25ae9SGregory Neil Shapiro addr.sin6.sin6_addr = hid6.sin6_addr;
92206f25ae9SGregory Neil Shapiro addr.sin6.sin6_port = port;
92340266059SGregory Neil Shapiro found = true;
92406f25ae9SGregory Neil Shapiro }
92506f25ae9SGregory Neil Shapiro # endif /* NETINET6 */
92606f25ae9SGregory Neil Shapiro *end = ']';
92706f25ae9SGregory Neil Shapiro if (!found)
92806f25ae9SGregory Neil Shapiro {
92906f25ae9SGregory Neil Shapiro if (tTd(64, 5))
93040266059SGregory Neil Shapiro sm_dprintf("X%s: Invalid numeric domain spec \"%s\"\n",
93106f25ae9SGregory Neil Shapiro m->mf_name, at);
93206f25ae9SGregory Neil Shapiro if (parseonly)
93306f25ae9SGregory Neil Shapiro syserr("X%s: Invalid numeric domain spec \"%s\"",
93406f25ae9SGregory Neil Shapiro m->mf_name, at);
93513bd1963SGregory Neil Shapiro else if (MilterLogLevel > 0)
93606f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
93740266059SGregory Neil Shapiro "Milter (%s): Invalid numeric domain spec \"%s\"",
93806f25ae9SGregory Neil Shapiro m->mf_name, at);
93940266059SGregory Neil Shapiro milter_error(m, e);
94006f25ae9SGregory Neil Shapiro return -1;
94106f25ae9SGregory Neil Shapiro }
94206f25ae9SGregory Neil Shapiro }
94306f25ae9SGregory Neil Shapiro else
94406f25ae9SGregory Neil Shapiro {
94506f25ae9SGregory Neil Shapiro if (tTd(64, 5))
94640266059SGregory Neil Shapiro sm_dprintf("X%s: Invalid numeric domain spec \"%s\"\n",
94706f25ae9SGregory Neil Shapiro m->mf_name, at);
94806f25ae9SGregory Neil Shapiro if (parseonly)
94906f25ae9SGregory Neil Shapiro syserr("X%s: Invalid numeric domain spec \"%s\"",
95006f25ae9SGregory Neil Shapiro m->mf_name, at);
95113bd1963SGregory Neil Shapiro else if (MilterLogLevel > 0)
95206f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
95340266059SGregory Neil Shapiro "Milter (%s): Invalid numeric domain spec \"%s\"",
95406f25ae9SGregory Neil Shapiro m->mf_name, at);
95540266059SGregory Neil Shapiro milter_error(m, e);
95606f25ae9SGregory Neil Shapiro return -1;
95706f25ae9SGregory Neil Shapiro }
95806f25ae9SGregory Neil Shapiro }
95906f25ae9SGregory Neil Shapiro else
96006f25ae9SGregory Neil Shapiro {
96106f25ae9SGregory Neil Shapiro hp = sm_gethostbyname(at, addr.sa.sa_family);
96206f25ae9SGregory Neil Shapiro if (hp == NULL)
96306f25ae9SGregory Neil Shapiro {
96406f25ae9SGregory Neil Shapiro save_errno = errno;
96506f25ae9SGregory Neil Shapiro if (tTd(64, 5))
96640266059SGregory Neil Shapiro sm_dprintf("X%s: Unknown host name %s\n",
96706f25ae9SGregory Neil Shapiro m->mf_name, at);
96806f25ae9SGregory Neil Shapiro errno = save_errno;
96906f25ae9SGregory Neil Shapiro if (parseonly)
97006f25ae9SGregory Neil Shapiro syserr("X%s: Unknown host name %s",
97106f25ae9SGregory Neil Shapiro m->mf_name, at);
97213bd1963SGregory Neil Shapiro else if (MilterLogLevel > 0)
97306f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
97440266059SGregory Neil Shapiro "Milter (%s): Unknown host name %s",
97506f25ae9SGregory Neil Shapiro m->mf_name, at);
97640266059SGregory Neil Shapiro milter_error(m, e);
97706f25ae9SGregory Neil Shapiro return -1;
97806f25ae9SGregory Neil Shapiro }
97906f25ae9SGregory Neil Shapiro addr.sa.sa_family = hp->h_addrtype;
98006f25ae9SGregory Neil Shapiro switch (hp->h_addrtype)
98106f25ae9SGregory Neil Shapiro {
98206f25ae9SGregory Neil Shapiro # if NETINET
98306f25ae9SGregory Neil Shapiro case AF_INET:
98406f25ae9SGregory Neil Shapiro memmove(&addr.sin.sin_addr,
98540266059SGregory Neil Shapiro hp->h_addr, INADDRSZ);
98606f25ae9SGregory Neil Shapiro addr.sin.sin_port = port;
98706f25ae9SGregory Neil Shapiro addrlen = sizeof(struct sockaddr_in);
98806f25ae9SGregory Neil Shapiro addrno = 1;
98906f25ae9SGregory Neil Shapiro break;
99006f25ae9SGregory Neil Shapiro # endif /* NETINET */
99106f25ae9SGregory Neil Shapiro
99206f25ae9SGregory Neil Shapiro # if NETINET6
99306f25ae9SGregory Neil Shapiro case AF_INET6:
99406f25ae9SGregory Neil Shapiro memmove(&addr.sin6.sin6_addr,
99540266059SGregory Neil Shapiro hp->h_addr, IN6ADDRSZ);
99606f25ae9SGregory Neil Shapiro addr.sin6.sin6_port = port;
99706f25ae9SGregory Neil Shapiro addrlen = sizeof(struct sockaddr_in6);
99806f25ae9SGregory Neil Shapiro addrno = 1;
99906f25ae9SGregory Neil Shapiro break;
100006f25ae9SGregory Neil Shapiro # endif /* NETINET6 */
100106f25ae9SGregory Neil Shapiro
100206f25ae9SGregory Neil Shapiro default:
100306f25ae9SGregory Neil Shapiro if (tTd(64, 5))
100440266059SGregory Neil Shapiro sm_dprintf("X%s: Unknown protocol for %s (%d)\n",
100506f25ae9SGregory Neil Shapiro m->mf_name, at,
100606f25ae9SGregory Neil Shapiro hp->h_addrtype);
100706f25ae9SGregory Neil Shapiro if (parseonly)
100806f25ae9SGregory Neil Shapiro syserr("X%s: Unknown protocol for %s (%d)",
100906f25ae9SGregory Neil Shapiro m->mf_name, at, hp->h_addrtype);
101013bd1963SGregory Neil Shapiro else if (MilterLogLevel > 0)
101106f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
101240266059SGregory Neil Shapiro "Milter (%s): Unknown protocol for %s (%d)",
101306f25ae9SGregory Neil Shapiro m->mf_name, at,
101406f25ae9SGregory Neil Shapiro hp->h_addrtype);
101540266059SGregory Neil Shapiro milter_error(m, e);
101640266059SGregory Neil Shapiro # if NETINET6
1017193538b7SGregory Neil Shapiro freehostent(hp);
10185b0945b5SGregory Neil Shapiro # endif
101906f25ae9SGregory Neil Shapiro return -1;
102006f25ae9SGregory Neil Shapiro }
102106f25ae9SGregory Neil Shapiro }
102206f25ae9SGregory Neil Shapiro }
102306f25ae9SGregory Neil Shapiro else
102406f25ae9SGregory Neil Shapiro # endif /* NETINET || NETINET6 */
102506f25ae9SGregory Neil Shapiro {
102606f25ae9SGregory Neil Shapiro if (tTd(64, 5))
102740266059SGregory Neil Shapiro sm_dprintf("X%s: unknown socket protocol\n",
102840266059SGregory Neil Shapiro m->mf_name);
102906f25ae9SGregory Neil Shapiro if (parseonly)
103006f25ae9SGregory Neil Shapiro syserr("X%s: unknown socket protocol", m->mf_name);
103113bd1963SGregory Neil Shapiro else if (MilterLogLevel > 0)
103206f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
103340266059SGregory Neil Shapiro "Milter (%s): unknown socket protocol",
103440266059SGregory Neil Shapiro m->mf_name);
103540266059SGregory Neil Shapiro milter_error(m, e);
103606f25ae9SGregory Neil Shapiro return -1;
103706f25ae9SGregory Neil Shapiro }
103806f25ae9SGregory Neil Shapiro
103906f25ae9SGregory Neil Shapiro /* just parsing through? */
104006f25ae9SGregory Neil Shapiro if (parseonly)
104106f25ae9SGregory Neil Shapiro {
104206f25ae9SGregory Neil Shapiro m->mf_state = SMFS_READY;
104340266059SGregory Neil Shapiro # if NETINET6
1044193538b7SGregory Neil Shapiro if (hp != NULL)
1045193538b7SGregory Neil Shapiro freehostent(hp);
10465b0945b5SGregory Neil Shapiro # endif
104706f25ae9SGregory Neil Shapiro return 0;
104806f25ae9SGregory Neil Shapiro }
104906f25ae9SGregory Neil Shapiro
105006f25ae9SGregory Neil Shapiro /* sanity check */
105106f25ae9SGregory Neil Shapiro if (m->mf_state != SMFS_READY &&
105206f25ae9SGregory Neil Shapiro m->mf_state != SMFS_CLOSED)
105306f25ae9SGregory Neil Shapiro {
105406f25ae9SGregory Neil Shapiro /* shouldn't happen */
105506f25ae9SGregory Neil Shapiro if (tTd(64, 1))
105640266059SGregory Neil Shapiro sm_dprintf("Milter (%s): Trying to open filter in state %c\n",
105706f25ae9SGregory Neil Shapiro m->mf_name, (char) m->mf_state);
105840266059SGregory Neil Shapiro milter_error(m, e);
105940266059SGregory Neil Shapiro # if NETINET6
1060193538b7SGregory Neil Shapiro if (hp != NULL)
1061193538b7SGregory Neil Shapiro freehostent(hp);
10625b0945b5SGregory Neil Shapiro # endif
106306f25ae9SGregory Neil Shapiro return -1;
106406f25ae9SGregory Neil Shapiro }
106506f25ae9SGregory Neil Shapiro
106606f25ae9SGregory Neil Shapiro /* nope, actually connecting */
106706f25ae9SGregory Neil Shapiro for (;;)
106806f25ae9SGregory Neil Shapiro {
106906f25ae9SGregory Neil Shapiro sock = socket(addr.sa.sa_family, SOCK_STREAM, 0);
107006f25ae9SGregory Neil Shapiro if (sock < 0)
107106f25ae9SGregory Neil Shapiro {
107206f25ae9SGregory Neil Shapiro save_errno = errno;
107306f25ae9SGregory Neil Shapiro if (tTd(64, 5))
107440266059SGregory Neil Shapiro sm_dprintf("Milter (%s): error creating socket: %s\n",
107540266059SGregory Neil Shapiro m->mf_name,
107640266059SGregory Neil Shapiro sm_errstring(save_errno));
107740266059SGregory Neil Shapiro if (MilterLogLevel > 0)
107806f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
107940266059SGregory Neil Shapiro "Milter (%s): error creating socket: %s",
108040266059SGregory Neil Shapiro m->mf_name, sm_errstring(save_errno));
108140266059SGregory Neil Shapiro milter_error(m, e);
108240266059SGregory Neil Shapiro # if NETINET6
1083193538b7SGregory Neil Shapiro if (hp != NULL)
1084193538b7SGregory Neil Shapiro freehostent(hp);
10855b0945b5SGregory Neil Shapiro # endif
108606f25ae9SGregory Neil Shapiro return -1;
108706f25ae9SGregory Neil Shapiro }
108806f25ae9SGregory Neil Shapiro
108913058a91SGregory Neil Shapiro if (setjmp(MilterConnectTimeout) == 0)
109013058a91SGregory Neil Shapiro {
109140266059SGregory Neil Shapiro SM_EVENT *ev = NULL;
109213058a91SGregory Neil Shapiro int i;
109313058a91SGregory Neil Shapiro
109413058a91SGregory Neil Shapiro if (m->mf_timeout[SMFTO_CONNECT] > 0)
109540266059SGregory Neil Shapiro ev = sm_setevent(m->mf_timeout[SMFTO_CONNECT],
109613058a91SGregory Neil Shapiro milter_connect_timeout, 0);
109713058a91SGregory Neil Shapiro
109813058a91SGregory Neil Shapiro i = connect(sock, (struct sockaddr *) &addr, addrlen);
109913058a91SGregory Neil Shapiro save_errno = errno;
110013058a91SGregory Neil Shapiro if (ev != NULL)
110140266059SGregory Neil Shapiro sm_clrevent(ev);
110213058a91SGregory Neil Shapiro errno = save_errno;
110313058a91SGregory Neil Shapiro if (i >= 0)
110406f25ae9SGregory Neil Shapiro break;
110513058a91SGregory Neil Shapiro }
110606f25ae9SGregory Neil Shapiro
110706f25ae9SGregory Neil Shapiro /* couldn't connect.... try next address */
110806f25ae9SGregory Neil Shapiro save_errno = errno;
110942e5d165SGregory Neil Shapiro p = CurHostName;
111042e5d165SGregory Neil Shapiro CurHostName = at;
111106f25ae9SGregory Neil Shapiro if (tTd(64, 5))
111240266059SGregory Neil Shapiro sm_dprintf("milter_open (%s): open %s failed: %s\n",
111340266059SGregory Neil Shapiro m->mf_name, at, sm_errstring(save_errno));
111440266059SGregory Neil Shapiro if (MilterLogLevel > 13)
111506f25ae9SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
111640266059SGregory Neil Shapiro "Milter (%s): open %s failed: %s",
111740266059SGregory Neil Shapiro m->mf_name, at, sm_errstring(save_errno));
111842e5d165SGregory Neil Shapiro CurHostName = p;
111906f25ae9SGregory Neil Shapiro (void) close(sock);
112006f25ae9SGregory Neil Shapiro
112106f25ae9SGregory Neil Shapiro /* try next address */
112206f25ae9SGregory Neil Shapiro if (hp != NULL && hp->h_addr_list[addrno] != NULL)
112306f25ae9SGregory Neil Shapiro {
112406f25ae9SGregory Neil Shapiro switch (addr.sa.sa_family)
112506f25ae9SGregory Neil Shapiro {
112606f25ae9SGregory Neil Shapiro # if NETINET
112706f25ae9SGregory Neil Shapiro case AF_INET:
112806f25ae9SGregory Neil Shapiro memmove(&addr.sin.sin_addr,
112906f25ae9SGregory Neil Shapiro hp->h_addr_list[addrno++],
113006f25ae9SGregory Neil Shapiro INADDRSZ);
113106f25ae9SGregory Neil Shapiro break;
113206f25ae9SGregory Neil Shapiro # endif /* NETINET */
113306f25ae9SGregory Neil Shapiro
113406f25ae9SGregory Neil Shapiro # if NETINET6
113506f25ae9SGregory Neil Shapiro case AF_INET6:
113606f25ae9SGregory Neil Shapiro memmove(&addr.sin6.sin6_addr,
113706f25ae9SGregory Neil Shapiro hp->h_addr_list[addrno++],
113806f25ae9SGregory Neil Shapiro IN6ADDRSZ);
113906f25ae9SGregory Neil Shapiro break;
114006f25ae9SGregory Neil Shapiro # endif /* NETINET6 */
114106f25ae9SGregory Neil Shapiro
114206f25ae9SGregory Neil Shapiro default:
114306f25ae9SGregory Neil Shapiro if (tTd(64, 5))
114440266059SGregory Neil Shapiro sm_dprintf("X%s: Unknown protocol for %s (%d)\n",
114506f25ae9SGregory Neil Shapiro m->mf_name, at,
114606f25ae9SGregory Neil Shapiro hp->h_addrtype);
114740266059SGregory Neil Shapiro if (MilterLogLevel > 0)
114806f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
114940266059SGregory Neil Shapiro "Milter (%s): Unknown protocol for %s (%d)",
115006f25ae9SGregory Neil Shapiro m->mf_name, at,
115106f25ae9SGregory Neil Shapiro hp->h_addrtype);
115240266059SGregory Neil Shapiro milter_error(m, e);
115340266059SGregory Neil Shapiro # if NETINET6
1154193538b7SGregory Neil Shapiro freehostent(hp);
11555b0945b5SGregory Neil Shapiro # endif
115606f25ae9SGregory Neil Shapiro return -1;
115706f25ae9SGregory Neil Shapiro }
115806f25ae9SGregory Neil Shapiro continue;
115906f25ae9SGregory Neil Shapiro }
116013058a91SGregory Neil Shapiro p = CurHostName;
116113058a91SGregory Neil Shapiro CurHostName = at;
116206f25ae9SGregory Neil Shapiro if (tTd(64, 5))
116340266059SGregory Neil Shapiro sm_dprintf("X%s: error connecting to filter: %s\n",
116440266059SGregory Neil Shapiro m->mf_name, sm_errstring(save_errno));
116540266059SGregory Neil Shapiro if (MilterLogLevel > 0)
116606f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
116740266059SGregory Neil Shapiro "Milter (%s): error connecting to filter: %s",
116840266059SGregory Neil Shapiro m->mf_name, sm_errstring(save_errno));
116913058a91SGregory Neil Shapiro CurHostName = p;
117040266059SGregory Neil Shapiro milter_error(m, e);
117140266059SGregory Neil Shapiro # if NETINET6
1172193538b7SGregory Neil Shapiro if (hp != NULL)
1173193538b7SGregory Neil Shapiro freehostent(hp);
11745b0945b5SGregory Neil Shapiro # endif
117506f25ae9SGregory Neil Shapiro return -1;
117606f25ae9SGregory Neil Shapiro }
117706f25ae9SGregory Neil Shapiro m->mf_state = SMFS_OPEN;
117840266059SGregory Neil Shapiro # if NETINET6
1179193538b7SGregory Neil Shapiro if (hp != NULL)
1180193538b7SGregory Neil Shapiro {
1181193538b7SGregory Neil Shapiro freehostent(hp);
1182193538b7SGregory Neil Shapiro hp = NULL;
1183193538b7SGregory Neil Shapiro }
118440266059SGregory Neil Shapiro # endif /* NETINET6 */
1185d0cef73dSGregory Neil Shapiro # if MILTER_NO_NAGLE && !defined(TCP_CORK)
1186e92d3f3fSGregory Neil Shapiro {
1187e92d3f3fSGregory Neil Shapiro int nodelay = 1;
1188e92d3f3fSGregory Neil Shapiro
1189e92d3f3fSGregory Neil Shapiro setsockopt(m->mf_sock, IPPROTO_TCP, TCP_NODELAY,
1190e92d3f3fSGregory Neil Shapiro (char *)&nodelay, sizeof(nodelay));
1191e92d3f3fSGregory Neil Shapiro }
1192d0cef73dSGregory Neil Shapiro # endif /* MILTER_NO_NAGLE && !defined(TCP_CORK) */
119306f25ae9SGregory Neil Shapiro return sock;
119406f25ae9SGregory Neil Shapiro }
119513058a91SGregory Neil Shapiro
119613058a91SGregory Neil Shapiro static void
milter_connect_timeout(ignore)1197b6bacd31SGregory Neil Shapiro milter_connect_timeout(ignore)
1198b6bacd31SGregory Neil Shapiro int ignore;
119913058a91SGregory Neil Shapiro {
120013058a91SGregory Neil Shapiro /*
120113058a91SGregory Neil Shapiro ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
120213058a91SGregory Neil Shapiro ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
120313058a91SGregory Neil Shapiro ** DOING.
120413058a91SGregory Neil Shapiro */
120513058a91SGregory Neil Shapiro
120613058a91SGregory Neil Shapiro errno = ETIMEDOUT;
120713058a91SGregory Neil Shapiro longjmp(MilterConnectTimeout, 1);
120813058a91SGregory Neil Shapiro }
1209d0cef73dSGregory Neil Shapiro
121040266059SGregory Neil Shapiro /*
121106f25ae9SGregory Neil Shapiro ** MILTER_SETUP -- setup structure for a mail filter
121206f25ae9SGregory Neil Shapiro **
121306f25ae9SGregory Neil Shapiro ** Parameters:
121406f25ae9SGregory Neil Shapiro ** line -- the options line.
121506f25ae9SGregory Neil Shapiro **
121606f25ae9SGregory Neil Shapiro ** Returns:
121706f25ae9SGregory Neil Shapiro ** none
121806f25ae9SGregory Neil Shapiro */
121906f25ae9SGregory Neil Shapiro
122006f25ae9SGregory Neil Shapiro void
milter_setup(line)122106f25ae9SGregory Neil Shapiro milter_setup(line)
122206f25ae9SGregory Neil Shapiro char *line;
122306f25ae9SGregory Neil Shapiro {
122406f25ae9SGregory Neil Shapiro char fcode;
1225d0cef73dSGregory Neil Shapiro char *p;
1226d0cef73dSGregory Neil Shapiro struct milter *m;
122706f25ae9SGregory Neil Shapiro STAB *s;
1228ba00ec3dSGregory Neil Shapiro static int idx = 0;
122906f25ae9SGregory Neil Shapiro
123042e5d165SGregory Neil Shapiro /* collect the filter name */
123106f25ae9SGregory Neil Shapiro for (p = line;
12325b0945b5SGregory Neil Shapiro *p != '\0' && *p != ',' && !(SM_ISSPACE(*p));
123306f25ae9SGregory Neil Shapiro p++)
123406f25ae9SGregory Neil Shapiro continue;
123506f25ae9SGregory Neil Shapiro if (*p != '\0')
123606f25ae9SGregory Neil Shapiro *p++ = '\0';
123706f25ae9SGregory Neil Shapiro if (line[0] == '\0')
123806f25ae9SGregory Neil Shapiro {
123906f25ae9SGregory Neil Shapiro syserr("name required for mail filter");
124006f25ae9SGregory Neil Shapiro return;
124106f25ae9SGregory Neil Shapiro }
1242d0cef73dSGregory Neil Shapiro m = (struct milter *) xalloc(sizeof(*m));
1243d0cef73dSGregory Neil Shapiro memset((char *) m, '\0', sizeof(*m));
124406f25ae9SGregory Neil Shapiro m->mf_name = newstr(line);
124506f25ae9SGregory Neil Shapiro m->mf_state = SMFS_READY;
124606f25ae9SGregory Neil Shapiro m->mf_sock = -1;
124740266059SGregory Neil Shapiro m->mf_timeout[SMFTO_CONNECT] = (time_t) 300;
124806f25ae9SGregory Neil Shapiro m->mf_timeout[SMFTO_WRITE] = (time_t) 10;
124906f25ae9SGregory Neil Shapiro m->mf_timeout[SMFTO_READ] = (time_t) 10;
125006f25ae9SGregory Neil Shapiro m->mf_timeout[SMFTO_EOM] = (time_t) 300;
1251d0cef73dSGregory Neil Shapiro # if _FFR_MILTER_CHECK
1252d0cef73dSGregory Neil Shapiro m->mf_mta_prot_version = SMFI_PROT_VERSION;
1253d0cef73dSGregory Neil Shapiro m->mf_mta_prot_flags = SMFI_CURR_PROT;
1254d0cef73dSGregory Neil Shapiro m->mf_mta_actions = SMFI_CURR_ACTS;
1255d0cef73dSGregory Neil Shapiro # endif /* _FFR_MILTER_CHECK */
125606f25ae9SGregory Neil Shapiro
125706f25ae9SGregory Neil Shapiro /* now scan through and assign info from the fields */
125806f25ae9SGregory Neil Shapiro while (*p != '\0')
125906f25ae9SGregory Neil Shapiro {
126006f25ae9SGregory Neil Shapiro char *delimptr;
126106f25ae9SGregory Neil Shapiro
126206f25ae9SGregory Neil Shapiro while (*p != '\0' &&
12635b0945b5SGregory Neil Shapiro (*p == ',' || (SM_ISSPACE(*p))))
126406f25ae9SGregory Neil Shapiro p++;
126506f25ae9SGregory Neil Shapiro
126606f25ae9SGregory Neil Shapiro /* p now points to field code */
126706f25ae9SGregory Neil Shapiro fcode = *p;
126806f25ae9SGregory Neil Shapiro while (*p != '\0' && *p != '=' && *p != ',')
126906f25ae9SGregory Neil Shapiro p++;
127006f25ae9SGregory Neil Shapiro if (*p++ != '=')
127106f25ae9SGregory Neil Shapiro {
127206f25ae9SGregory Neil Shapiro syserr("X%s: `=' expected", m->mf_name);
12732fb4f839SGregory Neil Shapiro /* this should not be reached, but just in case */
12742fb4f839SGregory Neil Shapiro SM_FREE(m);
127506f25ae9SGregory Neil Shapiro return;
127606f25ae9SGregory Neil Shapiro }
12775b0945b5SGregory Neil Shapiro while (SM_ISSPACE(*p))
127806f25ae9SGregory Neil Shapiro p++;
127906f25ae9SGregory Neil Shapiro
128006f25ae9SGregory Neil Shapiro /* p now points to the field body */
128106f25ae9SGregory Neil Shapiro p = munchstring(p, &delimptr, ',');
128206f25ae9SGregory Neil Shapiro
128342e5d165SGregory Neil Shapiro /* install the field into the filter struct */
128406f25ae9SGregory Neil Shapiro switch (fcode)
128506f25ae9SGregory Neil Shapiro {
128606f25ae9SGregory Neil Shapiro case 'S': /* socket */
128706f25ae9SGregory Neil Shapiro if (p == NULL)
128806f25ae9SGregory Neil Shapiro m->mf_conn = NULL;
128906f25ae9SGregory Neil Shapiro else
129006f25ae9SGregory Neil Shapiro m->mf_conn = newstr(p);
129106f25ae9SGregory Neil Shapiro break;
129206f25ae9SGregory Neil Shapiro
129306f25ae9SGregory Neil Shapiro case 'F': /* Milter flags configured on MTA */
129406f25ae9SGregory Neil Shapiro for (; *p != '\0'; p++)
129506f25ae9SGregory Neil Shapiro {
12965b0945b5SGregory Neil Shapiro if (!(SM_ISSPACE(*p)))
1297193538b7SGregory Neil Shapiro setbitn(bitidx(*p), m->mf_flags);
129806f25ae9SGregory Neil Shapiro }
129906f25ae9SGregory Neil Shapiro break;
130006f25ae9SGregory Neil Shapiro
130106f25ae9SGregory Neil Shapiro case 'T': /* timeouts */
130206f25ae9SGregory Neil Shapiro milter_parse_timeouts(p, m);
130306f25ae9SGregory Neil Shapiro break;
130406f25ae9SGregory Neil Shapiro
1305d0cef73dSGregory Neil Shapiro # if _FFR_MILTER_CHECK
1306d0cef73dSGregory Neil Shapiro case 'a':
1307d0cef73dSGregory Neil Shapiro m->mf_mta_actions = strtoul(p, NULL, 0);
1308d0cef73dSGregory Neil Shapiro break;
1309d0cef73dSGregory Neil Shapiro case 'f':
1310d0cef73dSGregory Neil Shapiro m->mf_mta_prot_flags = strtoul(p, NULL, 0);
1311d0cef73dSGregory Neil Shapiro break;
1312d0cef73dSGregory Neil Shapiro case 'v':
1313d0cef73dSGregory Neil Shapiro m->mf_mta_prot_version = strtoul(p, NULL, 0);
1314d0cef73dSGregory Neil Shapiro break;
1315d0cef73dSGregory Neil Shapiro # endif /* _FFR_MILTER_CHECK */
1316d0cef73dSGregory Neil Shapiro
131706f25ae9SGregory Neil Shapiro default:
131806f25ae9SGregory Neil Shapiro syserr("X%s: unknown filter equate %c=",
131906f25ae9SGregory Neil Shapiro m->mf_name, fcode);
132006f25ae9SGregory Neil Shapiro break;
132106f25ae9SGregory Neil Shapiro }
132206f25ae9SGregory Neil Shapiro p = delimptr;
132306f25ae9SGregory Neil Shapiro }
132406f25ae9SGregory Neil Shapiro
132506f25ae9SGregory Neil Shapiro /* early check for errors */
132640266059SGregory Neil Shapiro (void) milter_open(m, true, CurEnv);
132706f25ae9SGregory Neil Shapiro
132842e5d165SGregory Neil Shapiro /* enter the filter into the symbol table */
132906f25ae9SGregory Neil Shapiro s = stab(m->mf_name, ST_MILTER, ST_ENTER);
133006f25ae9SGregory Neil Shapiro if (s->s_milter != NULL)
133106f25ae9SGregory Neil Shapiro syserr("X%s: duplicate filter definition", m->mf_name);
133206f25ae9SGregory Neil Shapiro else
1333ba00ec3dSGregory Neil Shapiro {
133406f25ae9SGregory Neil Shapiro s->s_milter = m;
1335ba00ec3dSGregory Neil Shapiro m->mf_idx = ++idx;
1336ba00ec3dSGregory Neil Shapiro }
133706f25ae9SGregory Neil Shapiro }
1338d0cef73dSGregory Neil Shapiro
133940266059SGregory Neil Shapiro /*
134040266059SGregory Neil Shapiro ** MILTER_CONFIG -- parse option list into an array and check config
134106f25ae9SGregory Neil Shapiro **
134206f25ae9SGregory Neil Shapiro ** Called when reading configuration file.
134306f25ae9SGregory Neil Shapiro **
134406f25ae9SGregory Neil Shapiro ** Parameters:
134506f25ae9SGregory Neil Shapiro ** spec -- the filter list.
134606f25ae9SGregory Neil Shapiro ** list -- the array to fill in.
134706f25ae9SGregory Neil Shapiro ** max -- the maximum number of entries in list.
134806f25ae9SGregory Neil Shapiro **
134906f25ae9SGregory Neil Shapiro ** Returns:
135006f25ae9SGregory Neil Shapiro ** none
135106f25ae9SGregory Neil Shapiro */
135206f25ae9SGregory Neil Shapiro
135306f25ae9SGregory Neil Shapiro void
milter_config(spec,list,max)135440266059SGregory Neil Shapiro milter_config(spec, list, max)
135506f25ae9SGregory Neil Shapiro char *spec;
135606f25ae9SGregory Neil Shapiro struct milter **list;
135706f25ae9SGregory Neil Shapiro int max;
135806f25ae9SGregory Neil Shapiro {
135906f25ae9SGregory Neil Shapiro int numitems = 0;
1360d0cef73dSGregory Neil Shapiro char *p;
136106f25ae9SGregory Neil Shapiro
136206f25ae9SGregory Neil Shapiro /* leave one for the NULL signifying the end of the list */
136306f25ae9SGregory Neil Shapiro max--;
136406f25ae9SGregory Neil Shapiro
136506f25ae9SGregory Neil Shapiro for (p = spec; p != NULL; )
136606f25ae9SGregory Neil Shapiro {
136706f25ae9SGregory Neil Shapiro STAB *s;
136806f25ae9SGregory Neil Shapiro
13695b0945b5SGregory Neil Shapiro while (SM_ISSPACE(*p))
137006f25ae9SGregory Neil Shapiro p++;
137106f25ae9SGregory Neil Shapiro if (*p == '\0')
137206f25ae9SGregory Neil Shapiro break;
137306f25ae9SGregory Neil Shapiro spec = p;
137406f25ae9SGregory Neil Shapiro
137506f25ae9SGregory Neil Shapiro if (numitems >= max)
137606f25ae9SGregory Neil Shapiro {
137706f25ae9SGregory Neil Shapiro syserr("Too many filters defined, %d max", max);
137806f25ae9SGregory Neil Shapiro if (max > 0)
137906f25ae9SGregory Neil Shapiro list[0] = NULL;
138006f25ae9SGregory Neil Shapiro return;
138106f25ae9SGregory Neil Shapiro }
138240266059SGregory Neil Shapiro p = strpbrk(p, ";,");
138306f25ae9SGregory Neil Shapiro if (p != NULL)
138406f25ae9SGregory Neil Shapiro *p++ = '\0';
138506f25ae9SGregory Neil Shapiro
138606f25ae9SGregory Neil Shapiro s = stab(spec, ST_MILTER, ST_FIND);
138706f25ae9SGregory Neil Shapiro if (s == NULL)
138806f25ae9SGregory Neil Shapiro {
138906f25ae9SGregory Neil Shapiro syserr("InputFilter %s not defined", spec);
139006f25ae9SGregory Neil Shapiro ExitStat = EX_CONFIG;
139106f25ae9SGregory Neil Shapiro return;
139206f25ae9SGregory Neil Shapiro }
139306f25ae9SGregory Neil Shapiro list[numitems++] = s->s_milter;
139406f25ae9SGregory Neil Shapiro }
139506f25ae9SGregory Neil Shapiro list[numitems] = NULL;
139640266059SGregory Neil Shapiro
139740266059SGregory Neil Shapiro /* if not set, set to LogLevel */
139840266059SGregory Neil Shapiro if (MilterLogLevel == -1)
139940266059SGregory Neil Shapiro MilterLogLevel = LogLevel;
140006f25ae9SGregory Neil Shapiro }
1401d0cef73dSGregory Neil Shapiro
140240266059SGregory Neil Shapiro /*
140306f25ae9SGregory Neil Shapiro ** MILTER_PARSE_TIMEOUTS -- parse timeout list
140406f25ae9SGregory Neil Shapiro **
140506f25ae9SGregory Neil Shapiro ** Called when reading configuration file.
140606f25ae9SGregory Neil Shapiro **
140706f25ae9SGregory Neil Shapiro ** Parameters:
140806f25ae9SGregory Neil Shapiro ** spec -- the timeout list.
140906f25ae9SGregory Neil Shapiro ** m -- milter to set.
141006f25ae9SGregory Neil Shapiro **
141106f25ae9SGregory Neil Shapiro ** Returns:
141206f25ae9SGregory Neil Shapiro ** none
141306f25ae9SGregory Neil Shapiro */
141406f25ae9SGregory Neil Shapiro
141506f25ae9SGregory Neil Shapiro static void
milter_parse_timeouts(spec,m)141606f25ae9SGregory Neil Shapiro milter_parse_timeouts(spec, m)
141706f25ae9SGregory Neil Shapiro char *spec;
141806f25ae9SGregory Neil Shapiro struct milter *m;
141906f25ae9SGregory Neil Shapiro {
142006f25ae9SGregory Neil Shapiro char fcode;
1421e92d3f3fSGregory Neil Shapiro int tcode;
1422d0cef73dSGregory Neil Shapiro char *p;
142306f25ae9SGregory Neil Shapiro
142406f25ae9SGregory Neil Shapiro p = spec;
142506f25ae9SGregory Neil Shapiro
142606f25ae9SGregory Neil Shapiro /* now scan through and assign info from the fields */
142706f25ae9SGregory Neil Shapiro while (*p != '\0')
142806f25ae9SGregory Neil Shapiro {
142906f25ae9SGregory Neil Shapiro char *delimptr;
143006f25ae9SGregory Neil Shapiro
14315b0945b5SGregory Neil Shapiro while (*p != '\0' && (*p == ';' || (SM_ISSPACE(*p))))
143206f25ae9SGregory Neil Shapiro p++;
143306f25ae9SGregory Neil Shapiro
143406f25ae9SGregory Neil Shapiro /* p now points to field code */
143506f25ae9SGregory Neil Shapiro fcode = *p;
143606f25ae9SGregory Neil Shapiro while (*p != '\0' && *p != ':')
143706f25ae9SGregory Neil Shapiro p++;
143806f25ae9SGregory Neil Shapiro if (*p++ != ':')
143906f25ae9SGregory Neil Shapiro {
144006f25ae9SGregory Neil Shapiro syserr("X%s, T=: `:' expected", m->mf_name);
144106f25ae9SGregory Neil Shapiro return;
144206f25ae9SGregory Neil Shapiro }
14435b0945b5SGregory Neil Shapiro while (SM_ISSPACE(*p))
144406f25ae9SGregory Neil Shapiro p++;
144506f25ae9SGregory Neil Shapiro
144606f25ae9SGregory Neil Shapiro /* p now points to the field body */
144706f25ae9SGregory Neil Shapiro p = munchstring(p, &delimptr, ';');
1448e92d3f3fSGregory Neil Shapiro tcode = -1;
144906f25ae9SGregory Neil Shapiro
145042e5d165SGregory Neil Shapiro /* install the field into the filter struct */
145106f25ae9SGregory Neil Shapiro switch (fcode)
145206f25ae9SGregory Neil Shapiro {
1453c86d5965SGregory Neil Shapiro case 'C':
1454e92d3f3fSGregory Neil Shapiro tcode = SMFTO_CONNECT;
1455c86d5965SGregory Neil Shapiro break;
1456c86d5965SGregory Neil Shapiro
145706f25ae9SGregory Neil Shapiro case 'S':
1458e92d3f3fSGregory Neil Shapiro tcode = SMFTO_WRITE;
145906f25ae9SGregory Neil Shapiro break;
146006f25ae9SGregory Neil Shapiro
146106f25ae9SGregory Neil Shapiro case 'R':
1462e92d3f3fSGregory Neil Shapiro tcode = SMFTO_READ;
146306f25ae9SGregory Neil Shapiro break;
146406f25ae9SGregory Neil Shapiro
146506f25ae9SGregory Neil Shapiro case 'E':
1466e92d3f3fSGregory Neil Shapiro tcode = SMFTO_EOM;
146706f25ae9SGregory Neil Shapiro break;
146806f25ae9SGregory Neil Shapiro
146906f25ae9SGregory Neil Shapiro default:
147006f25ae9SGregory Neil Shapiro if (tTd(64, 5))
147140266059SGregory Neil Shapiro sm_dprintf("X%s: %c unknown\n",
147206f25ae9SGregory Neil Shapiro m->mf_name, fcode);
147306f25ae9SGregory Neil Shapiro syserr("X%s: unknown filter timeout %c",
147406f25ae9SGregory Neil Shapiro m->mf_name, fcode);
147506f25ae9SGregory Neil Shapiro break;
147606f25ae9SGregory Neil Shapiro }
1477e92d3f3fSGregory Neil Shapiro if (tcode >= 0)
1478e92d3f3fSGregory Neil Shapiro {
1479e92d3f3fSGregory Neil Shapiro m->mf_timeout[tcode] = convtime(p, 's');
1480e92d3f3fSGregory Neil Shapiro if (tTd(64, 5))
1481e92d3f3fSGregory Neil Shapiro sm_dprintf("X%s: %c=%ld\n",
1482e92d3f3fSGregory Neil Shapiro m->mf_name, fcode,
1483e92d3f3fSGregory Neil Shapiro (u_long) m->mf_timeout[tcode]);
1484e92d3f3fSGregory Neil Shapiro }
148506f25ae9SGregory Neil Shapiro p = delimptr;
148606f25ae9SGregory Neil Shapiro }
148706f25ae9SGregory Neil Shapiro }
1488d0cef73dSGregory Neil Shapiro
1489d0cef73dSGregory Neil Shapiro /*
1490d0cef73dSGregory Neil Shapiro ** MILTER_SET_MACROS -- set milter macros
1491d0cef73dSGregory Neil Shapiro **
1492d0cef73dSGregory Neil Shapiro ** Parameters:
1493d0cef73dSGregory Neil Shapiro ** name -- name of milter.
1494d0cef73dSGregory Neil Shapiro ** macros -- where to store macros.
1495d0cef73dSGregory Neil Shapiro ** val -- the value of the option.
1496d0cef73dSGregory Neil Shapiro ** nummac -- current number of macros
1497d0cef73dSGregory Neil Shapiro **
1498d0cef73dSGregory Neil Shapiro ** Returns:
1499d0cef73dSGregory Neil Shapiro ** new number of macros
1500d0cef73dSGregory Neil Shapiro */
1501d0cef73dSGregory Neil Shapiro
1502d0cef73dSGregory Neil Shapiro static int
milter_set_macros(name,macros,val,nummac)1503d0cef73dSGregory Neil Shapiro milter_set_macros(name, macros, val, nummac)
1504d0cef73dSGregory Neil Shapiro char *name;
1505d0cef73dSGregory Neil Shapiro char **macros;
1506d0cef73dSGregory Neil Shapiro char *val;
1507d0cef73dSGregory Neil Shapiro int nummac;
1508d0cef73dSGregory Neil Shapiro {
1509d0cef73dSGregory Neil Shapiro char *p;
1510d0cef73dSGregory Neil Shapiro
1511d0cef73dSGregory Neil Shapiro p = newstr(val);
1512d0cef73dSGregory Neil Shapiro while (*p != '\0')
1513d0cef73dSGregory Neil Shapiro {
1514d0cef73dSGregory Neil Shapiro char *macro;
1515d0cef73dSGregory Neil Shapiro
1516d0cef73dSGregory Neil Shapiro /* Skip leading commas, spaces */
15175b0945b5SGregory Neil Shapiro while (*p != '\0' && (*p == ',' || (SM_ISSPACE(*p))))
1518d0cef73dSGregory Neil Shapiro p++;
1519d0cef73dSGregory Neil Shapiro
1520d0cef73dSGregory Neil Shapiro if (*p == '\0')
1521d0cef73dSGregory Neil Shapiro break;
1522d0cef73dSGregory Neil Shapiro
1523d0cef73dSGregory Neil Shapiro /* Find end of macro */
1524d0cef73dSGregory Neil Shapiro macro = p;
1525d0cef73dSGregory Neil Shapiro while (*p != '\0' && *p != ',' &&
1526d0cef73dSGregory Neil Shapiro isascii(*p) && !isspace(*p))
1527d0cef73dSGregory Neil Shapiro p++;
1528d0cef73dSGregory Neil Shapiro if (*p != '\0')
1529d0cef73dSGregory Neil Shapiro *p++ = '\0';
1530d0cef73dSGregory Neil Shapiro
1531d0cef73dSGregory Neil Shapiro if (nummac >= MAXFILTERMACROS)
1532d0cef73dSGregory Neil Shapiro {
1533d0cef73dSGregory Neil Shapiro syserr("milter_set_option: too many macros in Milter.%s (max %d)",
1534d0cef73dSGregory Neil Shapiro name, MAXFILTERMACROS);
1535d0cef73dSGregory Neil Shapiro macros[nummac] = NULL;
1536d0cef73dSGregory Neil Shapiro return -1;
1537d0cef73dSGregory Neil Shapiro }
1538d0cef73dSGregory Neil Shapiro macros[nummac++] = macro;
1539d0cef73dSGregory Neil Shapiro }
1540d0cef73dSGregory Neil Shapiro macros[nummac] = NULL;
1541d0cef73dSGregory Neil Shapiro return nummac;
1542d0cef73dSGregory Neil Shapiro }
1543d0cef73dSGregory Neil Shapiro
154440266059SGregory Neil Shapiro /*
154506f25ae9SGregory Neil Shapiro ** MILTER_SET_OPTION -- set an individual milter option
154606f25ae9SGregory Neil Shapiro **
154706f25ae9SGregory Neil Shapiro ** Parameters:
154806f25ae9SGregory Neil Shapiro ** name -- the name of the option.
154906f25ae9SGregory Neil Shapiro ** val -- the value of the option.
155006f25ae9SGregory Neil Shapiro ** sticky -- if set, don't let other setoptions override
155106f25ae9SGregory Neil Shapiro ** this value.
155206f25ae9SGregory Neil Shapiro **
155306f25ae9SGregory Neil Shapiro ** Returns:
155406f25ae9SGregory Neil Shapiro ** none.
155506f25ae9SGregory Neil Shapiro */
155606f25ae9SGregory Neil Shapiro
155706f25ae9SGregory Neil Shapiro /* set if Milter sub-option is stuck */
155806f25ae9SGregory Neil Shapiro static BITMAP256 StickyMilterOpt;
155906f25ae9SGregory Neil Shapiro
156006f25ae9SGregory Neil Shapiro static struct milteropt
156106f25ae9SGregory Neil Shapiro {
156206f25ae9SGregory Neil Shapiro char *mo_name; /* long name of milter option */
156340266059SGregory Neil Shapiro unsigned char mo_code; /* code for option */
156406f25ae9SGregory Neil Shapiro } MilterOptTab[] =
156506f25ae9SGregory Neil Shapiro {
1566ba00ec3dSGregory Neil Shapiro { "macros.connect", SMFIM_CONNECT },
1567ba00ec3dSGregory Neil Shapiro { "macros.helo", SMFIM_HELO },
1568ba00ec3dSGregory Neil Shapiro { "macros.envfrom", SMFIM_ENVFROM },
1569ba00ec3dSGregory Neil Shapiro { "macros.envrcpt", SMFIM_ENVRCPT },
1570ba00ec3dSGregory Neil Shapiro { "macros.data", SMFIM_DATA },
1571ba00ec3dSGregory Neil Shapiro { "macros.eom", SMFIM_EOM },
1572ba00ec3dSGregory Neil Shapiro { "macros.eoh", SMFIM_EOH },
1573d0cef73dSGregory Neil Shapiro
1574e92d3f3fSGregory Neil Shapiro # define MO_LOGLEVEL 0x07
1575e92d3f3fSGregory Neil Shapiro { "loglevel", MO_LOGLEVEL },
15769bd497b8SGregory Neil Shapiro # if _FFR_MAXDATASIZE || _FFR_MDS_NEGOTIATE
1577e92d3f3fSGregory Neil Shapiro # define MO_MAXDATASIZE 0x08
1578e92d3f3fSGregory Neil Shapiro { "maxdatasize", MO_MAXDATASIZE },
15795b0945b5SGregory Neil Shapiro # endif
1580d0cef73dSGregory Neil Shapiro { NULL, (unsigned char)-1 },
158106f25ae9SGregory Neil Shapiro };
158206f25ae9SGregory Neil Shapiro
158306f25ae9SGregory Neil Shapiro void
milter_set_option(name,val,sticky)158406f25ae9SGregory Neil Shapiro milter_set_option(name, val, sticky)
158506f25ae9SGregory Neil Shapiro char *name;
158606f25ae9SGregory Neil Shapiro char *val;
158706f25ae9SGregory Neil Shapiro bool sticky;
158806f25ae9SGregory Neil Shapiro {
1589d0cef73dSGregory Neil Shapiro int nummac, r;
1590d0cef73dSGregory Neil Shapiro struct milteropt *mo;
159106f25ae9SGregory Neil Shapiro char **macros = NULL;
159206f25ae9SGregory Neil Shapiro
1593d0cef73dSGregory Neil Shapiro nummac = 0;
159406f25ae9SGregory Neil Shapiro if (tTd(37, 2) || tTd(64, 5))
159540266059SGregory Neil Shapiro sm_dprintf("milter_set_option(%s = %s)", name, val);
159606f25ae9SGregory Neil Shapiro
1597739ac4d4SGregory Neil Shapiro if (name == NULL)
1598739ac4d4SGregory Neil Shapiro {
1599739ac4d4SGregory Neil Shapiro syserr("milter_set_option: invalid Milter option, must specify suboption");
1600739ac4d4SGregory Neil Shapiro return;
1601739ac4d4SGregory Neil Shapiro }
1602739ac4d4SGregory Neil Shapiro
160306f25ae9SGregory Neil Shapiro for (mo = MilterOptTab; mo->mo_name != NULL; mo++)
160406f25ae9SGregory Neil Shapiro {
16052fb4f839SGregory Neil Shapiro if (SM_STRCASEEQ(mo->mo_name, name))
160606f25ae9SGregory Neil Shapiro break;
160706f25ae9SGregory Neil Shapiro }
160806f25ae9SGregory Neil Shapiro
160906f25ae9SGregory Neil Shapiro if (mo->mo_name == NULL)
161040266059SGregory Neil Shapiro {
161106f25ae9SGregory Neil Shapiro syserr("milter_set_option: invalid Milter option %s", name);
161240266059SGregory Neil Shapiro return;
161340266059SGregory Neil Shapiro }
161406f25ae9SGregory Neil Shapiro
161506f25ae9SGregory Neil Shapiro /*
161606f25ae9SGregory Neil Shapiro ** See if this option is preset for us.
161706f25ae9SGregory Neil Shapiro */
161806f25ae9SGregory Neil Shapiro
161906f25ae9SGregory Neil Shapiro if (!sticky && bitnset(mo->mo_code, StickyMilterOpt))
162006f25ae9SGregory Neil Shapiro {
162106f25ae9SGregory Neil Shapiro if (tTd(37, 2) || tTd(64,5))
162240266059SGregory Neil Shapiro sm_dprintf(" (ignored)\n");
162306f25ae9SGregory Neil Shapiro return;
162406f25ae9SGregory Neil Shapiro }
162506f25ae9SGregory Neil Shapiro
162606f25ae9SGregory Neil Shapiro if (tTd(37, 2) || tTd(64,5))
162740266059SGregory Neil Shapiro sm_dprintf("\n");
162806f25ae9SGregory Neil Shapiro
162906f25ae9SGregory Neil Shapiro switch (mo->mo_code)
163006f25ae9SGregory Neil Shapiro {
163140266059SGregory Neil Shapiro case MO_LOGLEVEL:
163240266059SGregory Neil Shapiro MilterLogLevel = atoi(val);
163340266059SGregory Neil Shapiro break;
163440266059SGregory Neil Shapiro
16359bd497b8SGregory Neil Shapiro # if _FFR_MAXDATASIZE || _FFR_MDS_NEGOTIATE
1636e92d3f3fSGregory Neil Shapiro case MO_MAXDATASIZE:
16379bd497b8SGregory Neil Shapiro # if _FFR_MDS_NEGOTIATE
1638e92d3f3fSGregory Neil Shapiro MilterMaxDataSize = (size_t)atol(val);
16399bd497b8SGregory Neil Shapiro if (MilterMaxDataSize != MILTER_MDS_64K &&
16409bd497b8SGregory Neil Shapiro MilterMaxDataSize != MILTER_MDS_256K &&
16419bd497b8SGregory Neil Shapiro MilterMaxDataSize != MILTER_MDS_1M)
16429bd497b8SGregory Neil Shapiro {
16439bd497b8SGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID,
1644da7d7b9cSGregory Neil Shapiro "WARNING: Milter.%s=%lu, allowed are only %d, %d, and %d",
1645da7d7b9cSGregory Neil Shapiro name, (unsigned long) MilterMaxDataSize,
16469bd497b8SGregory Neil Shapiro MILTER_MDS_64K, MILTER_MDS_256K,
16479bd497b8SGregory Neil Shapiro MILTER_MDS_1M);
16489bd497b8SGregory Neil Shapiro if (MilterMaxDataSize < MILTER_MDS_64K)
16499bd497b8SGregory Neil Shapiro MilterMaxDataSize = MILTER_MDS_64K;
16509bd497b8SGregory Neil Shapiro else if (MilterMaxDataSize < MILTER_MDS_256K)
16519bd497b8SGregory Neil Shapiro MilterMaxDataSize = MILTER_MDS_256K;
16529bd497b8SGregory Neil Shapiro else
16539bd497b8SGregory Neil Shapiro MilterMaxDataSize = MILTER_MDS_1M;
16549bd497b8SGregory Neil Shapiro }
16559bd497b8SGregory Neil Shapiro # endif /* _FFR_MDS_NEGOTIATE */
1656e92d3f3fSGregory Neil Shapiro break;
16579bd497b8SGregory Neil Shapiro # endif /* _FFR_MAXDATASIZE || _FFR_MDS_NEGOTIATE */
1658e92d3f3fSGregory Neil Shapiro
1659ba00ec3dSGregory Neil Shapiro case SMFIM_CONNECT:
1660ba00ec3dSGregory Neil Shapiro case SMFIM_HELO:
1661ba00ec3dSGregory Neil Shapiro case SMFIM_ENVFROM:
1662ba00ec3dSGregory Neil Shapiro case SMFIM_ENVRCPT:
1663ba00ec3dSGregory Neil Shapiro case SMFIM_EOH:
1664ba00ec3dSGregory Neil Shapiro case SMFIM_EOM:
1665ba00ec3dSGregory Neil Shapiro case SMFIM_DATA:
1666ba00ec3dSGregory Neil Shapiro macros = MilterMacros[mo->mo_code][0];
166706f25ae9SGregory Neil Shapiro
1668d0cef73dSGregory Neil Shapiro r = milter_set_macros(name, macros, val, nummac);
1669d0cef73dSGregory Neil Shapiro if (r >= 0)
1670d0cef73dSGregory Neil Shapiro nummac = r;
167106f25ae9SGregory Neil Shapiro break;
167206f25ae9SGregory Neil Shapiro
167306f25ae9SGregory Neil Shapiro default:
167406f25ae9SGregory Neil Shapiro syserr("milter_set_option: invalid Milter option %s", name);
167506f25ae9SGregory Neil Shapiro break;
167606f25ae9SGregory Neil Shapiro }
167706f25ae9SGregory Neil Shapiro if (sticky)
167806f25ae9SGregory Neil Shapiro setbitn(mo->mo_code, StickyMilterOpt);
167906f25ae9SGregory Neil Shapiro }
1680d0cef73dSGregory Neil Shapiro
168140266059SGregory Neil Shapiro /*
168240266059SGregory Neil Shapiro ** MILTER_REOPEN_DF -- open & truncate the data file (for replbody)
168306f25ae9SGregory Neil Shapiro **
168406f25ae9SGregory Neil Shapiro ** Parameters:
168506f25ae9SGregory Neil Shapiro ** e -- current envelope.
168606f25ae9SGregory Neil Shapiro **
168706f25ae9SGregory Neil Shapiro ** Returns:
16885b0945b5SGregory Neil Shapiro ** 0 if successful, -1 otherwise
168906f25ae9SGregory Neil Shapiro */
169006f25ae9SGregory Neil Shapiro
169106f25ae9SGregory Neil Shapiro static int
milter_reopen_df(e)169206f25ae9SGregory Neil Shapiro milter_reopen_df(e)
169306f25ae9SGregory Neil Shapiro ENVELOPE *e;
169406f25ae9SGregory Neil Shapiro {
169506f25ae9SGregory Neil Shapiro char dfname[MAXPATHLEN];
169606f25ae9SGregory Neil Shapiro
1697d0cef73dSGregory Neil Shapiro (void) sm_strlcpy(dfname, queuename(e, DATAFL_LETTER), sizeof(dfname));
169806f25ae9SGregory Neil Shapiro
169906f25ae9SGregory Neil Shapiro /*
170040266059SGregory Neil Shapiro ** In SuperSafe == SAFE_REALLY mode, e->e_dfp is a read-only FP so
170106f25ae9SGregory Neil Shapiro ** close and reopen writable (later close and reopen
170206f25ae9SGregory Neil Shapiro ** read only again).
170306f25ae9SGregory Neil Shapiro **
170440266059SGregory Neil Shapiro ** In SuperSafe != SAFE_REALLY mode, e->e_dfp still points at the
1705e92d3f3fSGregory Neil Shapiro ** buffered file I/O descriptor, still open for writing so there
1706e92d3f3fSGregory Neil Shapiro ** isn't any work to do here (except checking for consistency).
170706f25ae9SGregory Neil Shapiro */
170806f25ae9SGregory Neil Shapiro
170940266059SGregory Neil Shapiro if (SuperSafe == SAFE_REALLY)
171006f25ae9SGregory Neil Shapiro {
171140266059SGregory Neil Shapiro /* close read-only data file */
171206f25ae9SGregory Neil Shapiro if (bitset(EF_HAS_DF, e->e_flags) && e->e_dfp != NULL)
171306f25ae9SGregory Neil Shapiro {
17142fb4f839SGregory Neil Shapiro SM_CLOSE_FP(e->e_dfp);
171506f25ae9SGregory Neil Shapiro e->e_flags &= ~EF_HAS_DF;
171606f25ae9SGregory Neil Shapiro }
171706f25ae9SGregory Neil Shapiro
171806f25ae9SGregory Neil Shapiro /* open writable */
171940266059SGregory Neil Shapiro if ((e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname,
1720a7ec597cSGregory Neil Shapiro SM_IO_RDWR_B, NULL)) == NULL)
172106f25ae9SGregory Neil Shapiro {
172240266059SGregory Neil Shapiro MILTER_DF_ERROR("milter_reopen_df: sm_io_open %s: %s");
172306f25ae9SGregory Neil Shapiro return -1;
172406f25ae9SGregory Neil Shapiro }
172506f25ae9SGregory Neil Shapiro }
172606f25ae9SGregory Neil Shapiro else if (e->e_dfp == NULL)
172706f25ae9SGregory Neil Shapiro {
172806f25ae9SGregory Neil Shapiro /* shouldn't happen */
172906f25ae9SGregory Neil Shapiro errno = ENOENT;
173006f25ae9SGregory Neil Shapiro MILTER_DF_ERROR("milter_reopen_df: NULL e_dfp (%s: %s)");
173106f25ae9SGregory Neil Shapiro return -1;
173206f25ae9SGregory Neil Shapiro }
173306f25ae9SGregory Neil Shapiro return 0;
173406f25ae9SGregory Neil Shapiro }
1735d0cef73dSGregory Neil Shapiro
173640266059SGregory Neil Shapiro /*
173740266059SGregory Neil Shapiro ** MILTER_RESET_DF -- re-open read-only the data file (for replbody)
173806f25ae9SGregory Neil Shapiro **
173906f25ae9SGregory Neil Shapiro ** Parameters:
174006f25ae9SGregory Neil Shapiro ** e -- current envelope.
174106f25ae9SGregory Neil Shapiro **
174206f25ae9SGregory Neil Shapiro ** Returns:
17435b0945b5SGregory Neil Shapiro ** 0 if successful, -1 otherwise
174406f25ae9SGregory Neil Shapiro */
174506f25ae9SGregory Neil Shapiro
174606f25ae9SGregory Neil Shapiro static int
milter_reset_df(e)174706f25ae9SGregory Neil Shapiro milter_reset_df(e)
174806f25ae9SGregory Neil Shapiro ENVELOPE *e;
174906f25ae9SGregory Neil Shapiro {
175006f25ae9SGregory Neil Shapiro int afd;
175106f25ae9SGregory Neil Shapiro char dfname[MAXPATHLEN];
175206f25ae9SGregory Neil Shapiro
1753d0cef73dSGregory Neil Shapiro (void) sm_strlcpy(dfname, queuename(e, DATAFL_LETTER), sizeof(dfname));
175406f25ae9SGregory Neil Shapiro
175540266059SGregory Neil Shapiro if (sm_io_flush(e->e_dfp, SM_TIME_DEFAULT) != 0 ||
175640266059SGregory Neil Shapiro sm_io_error(e->e_dfp))
175706f25ae9SGregory Neil Shapiro {
175806f25ae9SGregory Neil Shapiro MILTER_DF_ERROR("milter_reset_df: error writing/flushing %s: %s");
175906f25ae9SGregory Neil Shapiro return -1;
176006f25ae9SGregory Neil Shapiro }
176140266059SGregory Neil Shapiro else if (SuperSafe != SAFE_REALLY)
176206f25ae9SGregory Neil Shapiro {
176306f25ae9SGregory Neil Shapiro /* skip next few clauses */
176406f25ae9SGregory Neil Shapiro /* EMPTY */
176506f25ae9SGregory Neil Shapiro }
176640266059SGregory Neil Shapiro else if ((afd = sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, NULL)) >= 0
176740266059SGregory Neil Shapiro && fsync(afd) < 0)
176806f25ae9SGregory Neil Shapiro {
176906f25ae9SGregory Neil Shapiro MILTER_DF_ERROR("milter_reset_df: error sync'ing %s: %s");
177006f25ae9SGregory Neil Shapiro return -1;
177106f25ae9SGregory Neil Shapiro }
177240266059SGregory Neil Shapiro else if (sm_io_close(e->e_dfp, SM_TIME_DEFAULT) < 0)
177306f25ae9SGregory Neil Shapiro {
177406f25ae9SGregory Neil Shapiro MILTER_DF_ERROR("milter_reset_df: error closing %s: %s");
177506f25ae9SGregory Neil Shapiro return -1;
177606f25ae9SGregory Neil Shapiro }
177740266059SGregory Neil Shapiro else if ((e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname,
1778a7ec597cSGregory Neil Shapiro SM_IO_RDONLY_B, NULL)) == NULL)
177906f25ae9SGregory Neil Shapiro {
178006f25ae9SGregory Neil Shapiro MILTER_DF_ERROR("milter_reset_df: error reopening %s: %s");
178106f25ae9SGregory Neil Shapiro return -1;
178206f25ae9SGregory Neil Shapiro }
178306f25ae9SGregory Neil Shapiro else
178406f25ae9SGregory Neil Shapiro e->e_flags |= EF_HAS_DF;
178506f25ae9SGregory Neil Shapiro return 0;
178606f25ae9SGregory Neil Shapiro }
1787d0cef73dSGregory Neil Shapiro
178840266059SGregory Neil Shapiro /*
178906f25ae9SGregory Neil Shapiro ** MILTER_QUIT_FILTER -- close down a single filter
179006f25ae9SGregory Neil Shapiro **
179106f25ae9SGregory Neil Shapiro ** Parameters:
179206f25ae9SGregory Neil Shapiro ** m -- milter structure of filter to close down.
179306f25ae9SGregory Neil Shapiro ** e -- current envelope.
179406f25ae9SGregory Neil Shapiro **
179506f25ae9SGregory Neil Shapiro ** Returns:
179606f25ae9SGregory Neil Shapiro ** none
179706f25ae9SGregory Neil Shapiro */
179806f25ae9SGregory Neil Shapiro
179906f25ae9SGregory Neil Shapiro static void
milter_quit_filter(m,e)180006f25ae9SGregory Neil Shapiro milter_quit_filter(m, e)
180106f25ae9SGregory Neil Shapiro struct milter *m;
180206f25ae9SGregory Neil Shapiro ENVELOPE *e;
180306f25ae9SGregory Neil Shapiro {
180406f25ae9SGregory Neil Shapiro if (tTd(64, 10))
180540266059SGregory Neil Shapiro sm_dprintf("milter_quit_filter(%s)\n", m->mf_name);
180640266059SGregory Neil Shapiro if (MilterLogLevel > 18)
180740266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter (%s): quit filter",
180840266059SGregory Neil Shapiro m->mf_name);
180906f25ae9SGregory Neil Shapiro
181006f25ae9SGregory Neil Shapiro /* Never replace error state */
181106f25ae9SGregory Neil Shapiro if (m->mf_state == SMFS_ERROR)
181206f25ae9SGregory Neil Shapiro return;
181306f25ae9SGregory Neil Shapiro
181406f25ae9SGregory Neil Shapiro if (m->mf_sock < 0 ||
181506f25ae9SGregory Neil Shapiro m->mf_state == SMFS_CLOSED ||
181606f25ae9SGregory Neil Shapiro m->mf_state == SMFS_READY)
181706f25ae9SGregory Neil Shapiro {
181806f25ae9SGregory Neil Shapiro m->mf_sock = -1;
181906f25ae9SGregory Neil Shapiro m->mf_state = SMFS_CLOSED;
182006f25ae9SGregory Neil Shapiro return;
182106f25ae9SGregory Neil Shapiro }
182206f25ae9SGregory Neil Shapiro
182306f25ae9SGregory Neil Shapiro (void) milter_write(m, SMFIC_QUIT, (char *) NULL, 0,
1824d0cef73dSGregory Neil Shapiro m->mf_timeout[SMFTO_WRITE], e, "quit_filter");
1825193538b7SGregory Neil Shapiro if (m->mf_sock >= 0)
1826193538b7SGregory Neil Shapiro {
182706f25ae9SGregory Neil Shapiro (void) close(m->mf_sock);
182806f25ae9SGregory Neil Shapiro m->mf_sock = -1;
1829193538b7SGregory Neil Shapiro }
183006f25ae9SGregory Neil Shapiro if (m->mf_state != SMFS_ERROR)
183106f25ae9SGregory Neil Shapiro m->mf_state = SMFS_CLOSED;
183206f25ae9SGregory Neil Shapiro }
1833d0cef73dSGregory Neil Shapiro
183440266059SGregory Neil Shapiro /*
183506f25ae9SGregory Neil Shapiro ** MILTER_ABORT_FILTER -- tell filter to abort current message
183606f25ae9SGregory Neil Shapiro **
183706f25ae9SGregory Neil Shapiro ** Parameters:
183806f25ae9SGregory Neil Shapiro ** m -- milter structure of filter to abort.
183906f25ae9SGregory Neil Shapiro ** e -- current envelope.
184006f25ae9SGregory Neil Shapiro **
184106f25ae9SGregory Neil Shapiro ** Returns:
184206f25ae9SGregory Neil Shapiro ** none
184306f25ae9SGregory Neil Shapiro */
184406f25ae9SGregory Neil Shapiro
184506f25ae9SGregory Neil Shapiro static void
milter_abort_filter(m,e)184606f25ae9SGregory Neil Shapiro milter_abort_filter(m, e)
184706f25ae9SGregory Neil Shapiro struct milter *m;
184806f25ae9SGregory Neil Shapiro ENVELOPE *e;
184906f25ae9SGregory Neil Shapiro {
185006f25ae9SGregory Neil Shapiro if (tTd(64, 10))
185140266059SGregory Neil Shapiro sm_dprintf("milter_abort_filter(%s)\n", m->mf_name);
185240266059SGregory Neil Shapiro if (MilterLogLevel > 10)
185340266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter (%s): abort filter",
185440266059SGregory Neil Shapiro m->mf_name);
185506f25ae9SGregory Neil Shapiro
185606f25ae9SGregory Neil Shapiro if (m->mf_sock < 0 ||
185706f25ae9SGregory Neil Shapiro m->mf_state != SMFS_INMSG)
185806f25ae9SGregory Neil Shapiro return;
185906f25ae9SGregory Neil Shapiro
186006f25ae9SGregory Neil Shapiro (void) milter_write(m, SMFIC_ABORT, (char *) NULL, 0,
1861d0cef73dSGregory Neil Shapiro m->mf_timeout[SMFTO_WRITE], e, "abort_filter");
186206f25ae9SGregory Neil Shapiro if (m->mf_state != SMFS_ERROR)
186306f25ae9SGregory Neil Shapiro m->mf_state = SMFS_DONE;
186406f25ae9SGregory Neil Shapiro }
1865d0cef73dSGregory Neil Shapiro
186640266059SGregory Neil Shapiro /*
186706f25ae9SGregory Neil Shapiro ** MILTER_SEND_MACROS -- provide macros to the filters
186806f25ae9SGregory Neil Shapiro **
186906f25ae9SGregory Neil Shapiro ** Parameters:
187006f25ae9SGregory Neil Shapiro ** m -- milter to send macros to.
187106f25ae9SGregory Neil Shapiro ** macros -- macros to send for filter smfi_getsymval().
187206f25ae9SGregory Neil Shapiro ** cmd -- which command the macros are associated with.
187306f25ae9SGregory Neil Shapiro ** e -- current envelope (for macro access).
187406f25ae9SGregory Neil Shapiro **
187506f25ae9SGregory Neil Shapiro ** Returns:
187606f25ae9SGregory Neil Shapiro ** none
187706f25ae9SGregory Neil Shapiro */
187806f25ae9SGregory Neil Shapiro
1879*d39bd2c1SGregory Neil Shapiro #if _FFR_TESTS
1880*d39bd2c1SGregory Neil Shapiro # define TST_EO \
1881*d39bd2c1SGregory Neil Shapiro do \
1882*d39bd2c1SGregory Neil Shapiro { \
1883*d39bd2c1SGregory Neil Shapiro if (tTd(86, 100) && \
1884*d39bd2c1SGregory Neil Shapiro (SMFIC_EOH == cmd || SMFIC_BODYEOB == cmd) && \
1885*d39bd2c1SGregory Neil Shapiro strncmp(macros[i], "{EO", 3) == 0) \
1886*d39bd2c1SGregory Neil Shapiro { \
1887*d39bd2c1SGregory Neil Shapiro if (SMFIC_EOH == cmd) \
1888*d39bd2c1SGregory Neil Shapiro v = "at_EOH"; \
1889*d39bd2c1SGregory Neil Shapiro else if (SMFIC_BODYEOB == cmd) \
1890*d39bd2c1SGregory Neil Shapiro v = "at_EOM"; \
1891*d39bd2c1SGregory Neil Shapiro } \
1892*d39bd2c1SGregory Neil Shapiro } while (0)
1893*d39bd2c1SGregory Neil Shapiro #else
1894*d39bd2c1SGregory Neil Shapiro # define TST_EO ((void) 0)
1895*d39bd2c1SGregory Neil Shapiro #endif
1896*d39bd2c1SGregory Neil Shapiro
189706f25ae9SGregory Neil Shapiro static void
milter_send_macros(m,macros,cmd,e)189806f25ae9SGregory Neil Shapiro milter_send_macros(m, macros, cmd, e)
189906f25ae9SGregory Neil Shapiro struct milter *m;
190006f25ae9SGregory Neil Shapiro char **macros;
1901d0cef73dSGregory Neil Shapiro int cmd;
190206f25ae9SGregory Neil Shapiro ENVELOPE *e;
190306f25ae9SGregory Neil Shapiro {
190406f25ae9SGregory Neil Shapiro int i;
190506f25ae9SGregory Neil Shapiro int mid;
1906d0cef73dSGregory Neil Shapiro char command = (char) cmd;
190706f25ae9SGregory Neil Shapiro char *v;
190806f25ae9SGregory Neil Shapiro char *buf, *bp;
19096a2f2ff3SGregory Neil Shapiro char exp[MAXLINE];
191006f25ae9SGregory Neil Shapiro ssize_t s;
191106f25ae9SGregory Neil Shapiro
191206f25ae9SGregory Neil Shapiro /* sanity check */
19132fb4f839SGregory Neil Shapiro if (NULL == macros || NULL == macros[0])
191406f25ae9SGregory Neil Shapiro return;
191506f25ae9SGregory Neil Shapiro
191606f25ae9SGregory Neil Shapiro /* put together data */
191706f25ae9SGregory Neil Shapiro s = 1; /* for the command character */
191806f25ae9SGregory Neil Shapiro for (i = 0; macros[i] != NULL; i++)
191906f25ae9SGregory Neil Shapiro {
192040266059SGregory Neil Shapiro mid = macid(macros[i]);
1921193538b7SGregory Neil Shapiro if (mid == 0)
192206f25ae9SGregory Neil Shapiro continue;
192306f25ae9SGregory Neil Shapiro v = macvalue(mid, e);
1924*d39bd2c1SGregory Neil Shapiro TST_EO;
192506f25ae9SGregory Neil Shapiro if (v == NULL)
192606f25ae9SGregory Neil Shapiro continue;
19276a2f2ff3SGregory Neil Shapiro expand(v, exp, sizeof(exp), e);
19282fb4f839SGregory Neil Shapiro s += strlen(macros[i]) + 1 +
19292fb4f839SGregory Neil Shapiro # if _FFR_8BITENVADDR
19302fb4f839SGregory Neil Shapiro ilenx(exp)
19312fb4f839SGregory Neil Shapiro # else
19322fb4f839SGregory Neil Shapiro strlen(exp)
19332fb4f839SGregory Neil Shapiro # endif
19342fb4f839SGregory Neil Shapiro + 1;
193506f25ae9SGregory Neil Shapiro }
193606f25ae9SGregory Neil Shapiro
193740266059SGregory Neil Shapiro if (s < 0)
193840266059SGregory Neil Shapiro return;
193940266059SGregory Neil Shapiro
194006f25ae9SGregory Neil Shapiro buf = (char *) xalloc(s);
194106f25ae9SGregory Neil Shapiro bp = buf;
1942d0cef73dSGregory Neil Shapiro *bp++ = command;
194306f25ae9SGregory Neil Shapiro for (i = 0; macros[i] != NULL; i++)
194406f25ae9SGregory Neil Shapiro {
194540266059SGregory Neil Shapiro mid = macid(macros[i]);
1946193538b7SGregory Neil Shapiro if (mid == 0)
194706f25ae9SGregory Neil Shapiro continue;
194806f25ae9SGregory Neil Shapiro v = macvalue(mid, e);
1949*d39bd2c1SGregory Neil Shapiro TST_EO;
195006f25ae9SGregory Neil Shapiro if (v == NULL)
195106f25ae9SGregory Neil Shapiro continue;
19526a2f2ff3SGregory Neil Shapiro expand(v, exp, sizeof(exp), e);
19532fb4f839SGregory Neil Shapiro # if _FFR_8BITENVADDR
19542fb4f839SGregory Neil Shapiro dequote_internal_chars(exp, exp, sizeof(exp));
19552fb4f839SGregory Neil Shapiro # endif
195606f25ae9SGregory Neil Shapiro
195706f25ae9SGregory Neil Shapiro if (tTd(64, 10))
195840266059SGregory Neil Shapiro sm_dprintf("milter_send_macros(%s, %c): %s=%s\n",
1959d0cef73dSGregory Neil Shapiro m->mf_name, command, macros[i], exp);
196006f25ae9SGregory Neil Shapiro
196140266059SGregory Neil Shapiro (void) sm_strlcpy(bp, macros[i], s - (bp - buf));
196206f25ae9SGregory Neil Shapiro bp += strlen(bp) + 1;
19636a2f2ff3SGregory Neil Shapiro (void) sm_strlcpy(bp, exp, s - (bp - buf));
196406f25ae9SGregory Neil Shapiro bp += strlen(bp) + 1;
196506f25ae9SGregory Neil Shapiro }
196606f25ae9SGregory Neil Shapiro (void) milter_write(m, SMFIC_MACRO, buf, s,
1967d0cef73dSGregory Neil Shapiro m->mf_timeout[SMFTO_WRITE], e, "send_macros");
196813d88268SGregory Neil Shapiro sm_free(buf);
196906f25ae9SGregory Neil Shapiro }
197006f25ae9SGregory Neil Shapiro
197140266059SGregory Neil Shapiro /*
197206f25ae9SGregory Neil Shapiro ** MILTER_SEND_COMMAND -- send a command and return the response for a filter
197306f25ae9SGregory Neil Shapiro **
197406f25ae9SGregory Neil Shapiro ** Parameters:
197506f25ae9SGregory Neil Shapiro ** m -- current milter filter
1976d0cef73dSGregory Neil Shapiro ** cmd -- command to send.
197706f25ae9SGregory Neil Shapiro ** data -- optional command data.
197806f25ae9SGregory Neil Shapiro ** sz -- length of buf.
197906f25ae9SGregory Neil Shapiro ** e -- current envelope (for e->e_id).
198006f25ae9SGregory Neil Shapiro ** state -- return state word.
198106f25ae9SGregory Neil Shapiro **
198206f25ae9SGregory Neil Shapiro ** Returns:
198306f25ae9SGregory Neil Shapiro ** response string (may be NULL)
198406f25ae9SGregory Neil Shapiro */
198506f25ae9SGregory Neil Shapiro
198606f25ae9SGregory Neil Shapiro static char *
milter_send_command(m,cmd,data,sz,e,state,where)1987d0cef73dSGregory Neil Shapiro milter_send_command(m, cmd, data, sz, e, state, where)
198806f25ae9SGregory Neil Shapiro struct milter *m;
1989d0cef73dSGregory Neil Shapiro int cmd;
199006f25ae9SGregory Neil Shapiro void *data;
199106f25ae9SGregory Neil Shapiro ssize_t sz;
199206f25ae9SGregory Neil Shapiro ENVELOPE *e;
199306f25ae9SGregory Neil Shapiro char *state;
1994d0cef73dSGregory Neil Shapiro const char *where;
199506f25ae9SGregory Neil Shapiro {
199606f25ae9SGregory Neil Shapiro char rcmd;
199706f25ae9SGregory Neil Shapiro ssize_t rlen;
199840266059SGregory Neil Shapiro unsigned long skipflag;
1999e92d3f3fSGregory Neil Shapiro unsigned long norespflag = 0;
2000d0cef73dSGregory Neil Shapiro char command = (char) cmd;
200140266059SGregory Neil Shapiro char *action;
200206f25ae9SGregory Neil Shapiro char *defresponse;
200306f25ae9SGregory Neil Shapiro char *response;
200406f25ae9SGregory Neil Shapiro
200506f25ae9SGregory Neil Shapiro if (tTd(64, 10))
200640266059SGregory Neil Shapiro sm_dprintf("milter_send_command(%s): cmd %c len %ld\n",
200706f25ae9SGregory Neil Shapiro m->mf_name, (char) command, (long) sz);
200806f25ae9SGregory Neil Shapiro
200906f25ae9SGregory Neil Shapiro /* find skip flag and default failure */
201006f25ae9SGregory Neil Shapiro switch (command)
201106f25ae9SGregory Neil Shapiro {
201206f25ae9SGregory Neil Shapiro case SMFIC_CONNECT:
201306f25ae9SGregory Neil Shapiro skipflag = SMFIP_NOCONNECT;
2014d0cef73dSGregory Neil Shapiro norespflag = SMFIP_NR_CONN;
201540266059SGregory Neil Shapiro action = "connect";
201606f25ae9SGregory Neil Shapiro defresponse = "554 Command rejected";
201706f25ae9SGregory Neil Shapiro break;
201806f25ae9SGregory Neil Shapiro
201906f25ae9SGregory Neil Shapiro case SMFIC_HELO:
202006f25ae9SGregory Neil Shapiro skipflag = SMFIP_NOHELO;
2021d0cef73dSGregory Neil Shapiro norespflag = SMFIP_NR_HELO;
202240266059SGregory Neil Shapiro action = "helo";
202306f25ae9SGregory Neil Shapiro defresponse = "550 Command rejected";
202406f25ae9SGregory Neil Shapiro break;
202506f25ae9SGregory Neil Shapiro
202606f25ae9SGregory Neil Shapiro case SMFIC_MAIL:
202706f25ae9SGregory Neil Shapiro skipflag = SMFIP_NOMAIL;
2028d0cef73dSGregory Neil Shapiro norespflag = SMFIP_NR_MAIL;
202940266059SGregory Neil Shapiro action = "mail";
203006f25ae9SGregory Neil Shapiro defresponse = "550 5.7.1 Command rejected";
203106f25ae9SGregory Neil Shapiro break;
203206f25ae9SGregory Neil Shapiro
203306f25ae9SGregory Neil Shapiro case SMFIC_RCPT:
203406f25ae9SGregory Neil Shapiro skipflag = SMFIP_NORCPT;
2035d0cef73dSGregory Neil Shapiro norespflag = SMFIP_NR_RCPT;
203640266059SGregory Neil Shapiro action = "rcpt";
203706f25ae9SGregory Neil Shapiro defresponse = "550 5.7.1 Command rejected";
203806f25ae9SGregory Neil Shapiro break;
203906f25ae9SGregory Neil Shapiro
204006f25ae9SGregory Neil Shapiro case SMFIC_HEADER:
204106f25ae9SGregory Neil Shapiro skipflag = SMFIP_NOHDRS;
2042d0cef73dSGregory Neil Shapiro norespflag = SMFIP_NR_HDR;
204340266059SGregory Neil Shapiro action = "header";
204406f25ae9SGregory Neil Shapiro defresponse = "550 5.7.1 Command rejected";
204506f25ae9SGregory Neil Shapiro break;
204606f25ae9SGregory Neil Shapiro
204706f25ae9SGregory Neil Shapiro case SMFIC_BODY:
204806f25ae9SGregory Neil Shapiro skipflag = SMFIP_NOBODY;
2049d0cef73dSGregory Neil Shapiro norespflag = SMFIP_NR_BODY;
205040266059SGregory Neil Shapiro action = "body";
205106f25ae9SGregory Neil Shapiro defresponse = "554 5.7.1 Command rejected";
205206f25ae9SGregory Neil Shapiro break;
205306f25ae9SGregory Neil Shapiro
205406f25ae9SGregory Neil Shapiro case SMFIC_EOH:
205506f25ae9SGregory Neil Shapiro skipflag = SMFIP_NOEOH;
2056d0cef73dSGregory Neil Shapiro norespflag = SMFIP_NR_EOH;
205740266059SGregory Neil Shapiro action = "eoh";
205806f25ae9SGregory Neil Shapiro defresponse = "550 5.7.1 Command rejected";
205906f25ae9SGregory Neil Shapiro break;
206006f25ae9SGregory Neil Shapiro
2061e92d3f3fSGregory Neil Shapiro case SMFIC_UNKNOWN:
20624e4196cbSGregory Neil Shapiro skipflag = SMFIP_NOUNKNOWN;
2063d0cef73dSGregory Neil Shapiro norespflag = SMFIP_NR_UNKN;
2064e92d3f3fSGregory Neil Shapiro action = "unknown";
2065e92d3f3fSGregory Neil Shapiro defresponse = "550 5.7.1 Command rejected";
2066e92d3f3fSGregory Neil Shapiro break;
2067e92d3f3fSGregory Neil Shapiro
20684e4196cbSGregory Neil Shapiro case SMFIC_DATA:
20694e4196cbSGregory Neil Shapiro skipflag = SMFIP_NODATA;
2070d0cef73dSGregory Neil Shapiro norespflag = SMFIP_NR_DATA;
20714e4196cbSGregory Neil Shapiro action = "data";
20724e4196cbSGregory Neil Shapiro defresponse = "550 5.7.1 Command rejected";
20734e4196cbSGregory Neil Shapiro break;
20744e4196cbSGregory Neil Shapiro
207506f25ae9SGregory Neil Shapiro case SMFIC_BODYEOB:
207606f25ae9SGregory Neil Shapiro case SMFIC_OPTNEG:
207706f25ae9SGregory Neil Shapiro case SMFIC_MACRO:
207806f25ae9SGregory Neil Shapiro case SMFIC_ABORT:
207906f25ae9SGregory Neil Shapiro case SMFIC_QUIT:
208006f25ae9SGregory Neil Shapiro /* NOTE: not handled by milter_send_command() */
208106f25ae9SGregory Neil Shapiro /* FALLTHROUGH */
208206f25ae9SGregory Neil Shapiro
208306f25ae9SGregory Neil Shapiro default:
208406f25ae9SGregory Neil Shapiro skipflag = 0;
208540266059SGregory Neil Shapiro action = "default";
208606f25ae9SGregory Neil Shapiro defresponse = "550 5.7.1 Command rejected";
208706f25ae9SGregory Neil Shapiro break;
208806f25ae9SGregory Neil Shapiro }
208906f25ae9SGregory Neil Shapiro
2090d0cef73dSGregory Neil Shapiro if (tTd(64, 10))
2091d0cef73dSGregory Neil Shapiro sm_dprintf("milter_send_command(%s): skip=%lx, pflags=%x\n",
2092d0cef73dSGregory Neil Shapiro m->mf_name, skipflag, m->mf_pflags);
2093d0cef73dSGregory Neil Shapiro
209406f25ae9SGregory Neil Shapiro /* check if filter wants this command */
2095d0cef73dSGregory Neil Shapiro if (skipflag != 0 && bitset(skipflag, m->mf_pflags))
209606f25ae9SGregory Neil Shapiro return NULL;
209706f25ae9SGregory Neil Shapiro
209840266059SGregory Neil Shapiro /* send the command to the filter */
209906f25ae9SGregory Neil Shapiro (void) milter_write(m, command, data, sz,
2100d0cef73dSGregory Neil Shapiro m->mf_timeout[SMFTO_WRITE], e, where);
210106f25ae9SGregory Neil Shapiro if (m->mf_state == SMFS_ERROR)
210206f25ae9SGregory Neil Shapiro {
21035ef517c0SGregory Neil Shapiro MILTER_CHECK_ERROR(false, return NULL);
210406f25ae9SGregory Neil Shapiro return NULL;
210506f25ae9SGregory Neil Shapiro }
210606f25ae9SGregory Neil Shapiro
2107e92d3f3fSGregory Neil Shapiro /* check if filter sends response to this command */
2108e92d3f3fSGregory Neil Shapiro if (norespflag != 0 && bitset(norespflag, m->mf_pflags))
2109e92d3f3fSGregory Neil Shapiro return NULL;
2110e92d3f3fSGregory Neil Shapiro
211140266059SGregory Neil Shapiro /* get the response from the filter */
211206f25ae9SGregory Neil Shapiro response = milter_read(m, &rcmd, &rlen,
2113d0cef73dSGregory Neil Shapiro m->mf_timeout[SMFTO_READ], e, where);
211406f25ae9SGregory Neil Shapiro if (m->mf_state == SMFS_ERROR)
211506f25ae9SGregory Neil Shapiro {
21165ef517c0SGregory Neil Shapiro MILTER_CHECK_ERROR(false, return NULL);
211706f25ae9SGregory Neil Shapiro return NULL;
211806f25ae9SGregory Neil Shapiro }
211906f25ae9SGregory Neil Shapiro
212006f25ae9SGregory Neil Shapiro if (tTd(64, 10))
212140266059SGregory Neil Shapiro sm_dprintf("milter_send_command(%s): returned %c\n",
212206f25ae9SGregory Neil Shapiro m->mf_name, (char) rcmd);
212306f25ae9SGregory Neil Shapiro
212406f25ae9SGregory Neil Shapiro switch (rcmd)
212506f25ae9SGregory Neil Shapiro {
212606f25ae9SGregory Neil Shapiro case SMFIR_REPLYCODE:
212706f25ae9SGregory Neil Shapiro MILTER_CHECK_REPLYCODE(defresponse);
212840266059SGregory Neil Shapiro if (MilterLogLevel > 10)
2129d0cef73dSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
2130d0cef73dSGregory Neil Shapiro "milter=%s, action=%s, reject=%s",
213140266059SGregory Neil Shapiro m->mf_name, action, response);
213240266059SGregory Neil Shapiro *state = rcmd;
213340266059SGregory Neil Shapiro break;
213406f25ae9SGregory Neil Shapiro
213506f25ae9SGregory Neil Shapiro case SMFIR_REJECT:
213640266059SGregory Neil Shapiro if (MilterLogLevel > 10)
2137d0cef73dSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
2138d0cef73dSGregory Neil Shapiro "milter=%s, action=%s, reject",
213940266059SGregory Neil Shapiro m->mf_name, action);
214040266059SGregory Neil Shapiro *state = rcmd;
214140266059SGregory Neil Shapiro break;
214240266059SGregory Neil Shapiro
214306f25ae9SGregory Neil Shapiro case SMFIR_DISCARD:
214440266059SGregory Neil Shapiro if (MilterLogLevel > 10)
2145d0cef73dSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
2146d0cef73dSGregory Neil Shapiro "milter=%s, action=%s, discard",
214740266059SGregory Neil Shapiro m->mf_name, action);
214840266059SGregory Neil Shapiro *state = rcmd;
214940266059SGregory Neil Shapiro break;
215040266059SGregory Neil Shapiro
215106f25ae9SGregory Neil Shapiro case SMFIR_TEMPFAIL:
215240266059SGregory Neil Shapiro if (MilterLogLevel > 10)
2153d0cef73dSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
2154d0cef73dSGregory Neil Shapiro "milter=%s, action=%s, tempfail",
215540266059SGregory Neil Shapiro m->mf_name, action);
215606f25ae9SGregory Neil Shapiro *state = rcmd;
215706f25ae9SGregory Neil Shapiro break;
215806f25ae9SGregory Neil Shapiro
215906f25ae9SGregory Neil Shapiro case SMFIR_ACCEPT:
216006f25ae9SGregory Neil Shapiro /* this filter is done with message/connection */
2161602a2b1bSGregory Neil Shapiro if (command == SMFIC_HELO ||
2162602a2b1bSGregory Neil Shapiro command == SMFIC_CONNECT)
2163602a2b1bSGregory Neil Shapiro m->mf_state = SMFS_CLOSABLE;
2164602a2b1bSGregory Neil Shapiro else
216506f25ae9SGregory Neil Shapiro m->mf_state = SMFS_DONE;
216640266059SGregory Neil Shapiro if (MilterLogLevel > 10)
2167d0cef73dSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
2168d0cef73dSGregory Neil Shapiro "milter=%s, action=%s, accepted",
216940266059SGregory Neil Shapiro m->mf_name, action);
217006f25ae9SGregory Neil Shapiro break;
217106f25ae9SGregory Neil Shapiro
217206f25ae9SGregory Neil Shapiro case SMFIR_CONTINUE:
217306f25ae9SGregory Neil Shapiro /* if MAIL command is ok, filter is in message state */
217406f25ae9SGregory Neil Shapiro if (command == SMFIC_MAIL)
217506f25ae9SGregory Neil Shapiro m->mf_state = SMFS_INMSG;
217640266059SGregory Neil Shapiro if (MilterLogLevel > 12)
2177d0cef73dSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
2178d0cef73dSGregory Neil Shapiro "milter=%s, action=%s, continue",
217940266059SGregory Neil Shapiro m->mf_name, action);
218006f25ae9SGregory Neil Shapiro break;
218106f25ae9SGregory Neil Shapiro
2182d0cef73dSGregory Neil Shapiro case SMFIR_SKIP:
2183d0cef73dSGregory Neil Shapiro if (MilterLogLevel > 12)
2184d0cef73dSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
2185d0cef73dSGregory Neil Shapiro "milter=%s, action=%s, skip",
2186d0cef73dSGregory Neil Shapiro m->mf_name, action);
2187d0cef73dSGregory Neil Shapiro m->mf_state = SMFS_SKIP;
2188d0cef73dSGregory Neil Shapiro break;
2189d0cef73dSGregory Neil Shapiro
219006f25ae9SGregory Neil Shapiro default:
219106f25ae9SGregory Neil Shapiro /* Invalid response to command */
219240266059SGregory Neil Shapiro if (MilterLogLevel > 0)
219306f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
219440266059SGregory Neil Shapiro "milter_send_command(%s): action=%s returned bogus response %c",
219540266059SGregory Neil Shapiro m->mf_name, action, rcmd);
2196ba00ec3dSGregory Neil Shapiro milter_error(m, e); /* NO ERROR CHECK? */
219706f25ae9SGregory Neil Shapiro break;
219806f25ae9SGregory Neil Shapiro }
219906f25ae9SGregory Neil Shapiro
2200d0cef73dSGregory Neil Shapiro if (*state != SMFIR_REPLYCODE && response != NULL)
220106f25ae9SGregory Neil Shapiro {
220240266059SGregory Neil Shapiro sm_free(response); /* XXX */
220306f25ae9SGregory Neil Shapiro response = NULL;
220406f25ae9SGregory Neil Shapiro }
220506f25ae9SGregory Neil Shapiro return response;
220606f25ae9SGregory Neil Shapiro }
220706f25ae9SGregory Neil Shapiro
220840266059SGregory Neil Shapiro /*
220906f25ae9SGregory Neil Shapiro ** MILTER_COMMAND -- send a command and return the response for each filter
221006f25ae9SGregory Neil Shapiro **
221106f25ae9SGregory Neil Shapiro ** Parameters:
2212d0cef73dSGregory Neil Shapiro ** cmd -- command to send.
221306f25ae9SGregory Neil Shapiro ** data -- optional command data.
221406f25ae9SGregory Neil Shapiro ** sz -- length of buf.
2215552d4955SGregory Neil Shapiro ** stage -- index of macros to send for filter smfi_getsymval().
221606f25ae9SGregory Neil Shapiro ** e -- current envelope (for macro access).
221706f25ae9SGregory Neil Shapiro ** state -- return state word.
2218d0cef73dSGregory Neil Shapiro ** where -- description of calling function (logging).
2219d0cef73dSGregory Neil Shapiro ** cmd_error -- did the SMTP command cause an error?
222006f25ae9SGregory Neil Shapiro **
222106f25ae9SGregory Neil Shapiro ** Returns:
222206f25ae9SGregory Neil Shapiro ** response string (may be NULL)
222306f25ae9SGregory Neil Shapiro */
222406f25ae9SGregory Neil Shapiro
222506f25ae9SGregory Neil Shapiro static char *
milter_command(cmd,data,sz,stage,e,state,where,cmd_error)2226ba00ec3dSGregory Neil Shapiro milter_command(cmd, data, sz, stage, e, state, where, cmd_error)
2227d0cef73dSGregory Neil Shapiro int cmd;
222806f25ae9SGregory Neil Shapiro void *data;
222906f25ae9SGregory Neil Shapiro ssize_t sz;
2230ba00ec3dSGregory Neil Shapiro int stage;
223106f25ae9SGregory Neil Shapiro ENVELOPE *e;
223206f25ae9SGregory Neil Shapiro char *state;
2233d0cef73dSGregory Neil Shapiro const char *where;
2234d0cef73dSGregory Neil Shapiro bool cmd_error;
223506f25ae9SGregory Neil Shapiro {
223606f25ae9SGregory Neil Shapiro int i;
2237d0cef73dSGregory Neil Shapiro char command = (char) cmd;
223806f25ae9SGregory Neil Shapiro char *response = NULL;
223940266059SGregory Neil Shapiro time_t tn = 0;
224006f25ae9SGregory Neil Shapiro
224106f25ae9SGregory Neil Shapiro if (tTd(64, 10))
224240266059SGregory Neil Shapiro sm_dprintf("milter_command: cmd %c len %ld\n",
2243d0cef73dSGregory Neil Shapiro command, (long) sz);
224406f25ae9SGregory Neil Shapiro
224506f25ae9SGregory Neil Shapiro *state = SMFIR_CONTINUE;
224606f25ae9SGregory Neil Shapiro for (i = 0; InputFilters[i] != NULL; i++)
224706f25ae9SGregory Neil Shapiro {
224806f25ae9SGregory Neil Shapiro struct milter *m = InputFilters[i];
224906f25ae9SGregory Neil Shapiro
2250193538b7SGregory Neil Shapiro /* previous problem? */
2251193538b7SGregory Neil Shapiro if (m->mf_state == SMFS_ERROR)
2252193538b7SGregory Neil Shapiro {
22535ef517c0SGregory Neil Shapiro MILTER_CHECK_ERROR(false, continue);
2254193538b7SGregory Neil Shapiro break;
2255193538b7SGregory Neil Shapiro }
2256193538b7SGregory Neil Shapiro
225706f25ae9SGregory Neil Shapiro /* sanity check */
225806f25ae9SGregory Neil Shapiro if (m->mf_sock < 0 ||
225906f25ae9SGregory Neil Shapiro (m->mf_state != SMFS_OPEN && m->mf_state != SMFS_INMSG))
226006f25ae9SGregory Neil Shapiro continue;
226106f25ae9SGregory Neil Shapiro
2262ba00ec3dSGregory Neil Shapiro if (stage >= SMFIM_FIRST && stage <= SMFIM_LAST)
2263ba00ec3dSGregory Neil Shapiro {
2264ba00ec3dSGregory Neil Shapiro int idx;
2265ba00ec3dSGregory Neil Shapiro char **macros;
2266ba00ec3dSGregory Neil Shapiro
2267ba00ec3dSGregory Neil Shapiro if ((m->mf_lflags & MI_LFLAGS_SYM(stage)) != 0)
2268ba00ec3dSGregory Neil Shapiro idx = m->mf_idx;
2269ba00ec3dSGregory Neil Shapiro else
2270ba00ec3dSGregory Neil Shapiro idx = 0;
2271ba00ec3dSGregory Neil Shapiro SM_ASSERT(idx >= 0 && idx <= MAXFILTERS);
2272ba00ec3dSGregory Neil Shapiro macros = MilterMacros[stage][idx];
2273ba00ec3dSGregory Neil Shapiro
2274ba00ec3dSGregory Neil Shapiro /* send macros (regardless of whether we send cmd) */
227506f25ae9SGregory Neil Shapiro if (macros != NULL && macros[0] != NULL)
227606f25ae9SGregory Neil Shapiro {
227706f25ae9SGregory Neil Shapiro milter_send_macros(m, macros, command, e);
227806f25ae9SGregory Neil Shapiro if (m->mf_state == SMFS_ERROR)
227906f25ae9SGregory Neil Shapiro {
22805ef517c0SGregory Neil Shapiro MILTER_CHECK_ERROR(false, continue);
228106f25ae9SGregory Neil Shapiro break;
228206f25ae9SGregory Neil Shapiro }
228306f25ae9SGregory Neil Shapiro }
2284ba00ec3dSGregory Neil Shapiro }
228506f25ae9SGregory Neil Shapiro
228640266059SGregory Neil Shapiro if (MilterLogLevel > 21)
228740266059SGregory Neil Shapiro tn = curtime();
228840266059SGregory Neil Shapiro
2289d0cef73dSGregory Neil Shapiro /*
2290d0cef73dSGregory Neil Shapiro ** send the command if
2291d0cef73dSGregory Neil Shapiro ** there is no error
2292d0cef73dSGregory Neil Shapiro ** or it's RCPT and the client asked for it:
2293d0cef73dSGregory Neil Shapiro ** !cmd_error ||
2294d0cef73dSGregory Neil Shapiro ** where == "rcpt" && m->mf_pflags & SMFIP_RCPT_REJ != 0
2295d0cef73dSGregory Neil Shapiro ** negate that condition and use continue
2296d0cef73dSGregory Neil Shapiro */
2297d0cef73dSGregory Neil Shapiro
2298d0cef73dSGregory Neil Shapiro if (cmd_error &&
2299d0cef73dSGregory Neil Shapiro (strcmp(where, "rcpt") != 0 ||
2300d0cef73dSGregory Neil Shapiro (m->mf_pflags & SMFIP_RCPT_REJ) == 0))
2301d0cef73dSGregory Neil Shapiro continue;
2302d0cef73dSGregory Neil Shapiro
2303d0cef73dSGregory Neil Shapiro response = milter_send_command(m, command, data, sz, e, state,
2304d0cef73dSGregory Neil Shapiro where);
230540266059SGregory Neil Shapiro
230640266059SGregory Neil Shapiro if (MilterLogLevel > 21)
230740266059SGregory Neil Shapiro {
230840266059SGregory Neil Shapiro /* log the time it took for the command per filter */
230940266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
231040266059SGregory Neil Shapiro "Milter (%s): time command (%c), %d",
2311*d39bd2c1SGregory Neil Shapiro m->mf_name, command, (int) (curtime() - tn));
231240266059SGregory Neil Shapiro }
231340266059SGregory Neil Shapiro
231406f25ae9SGregory Neil Shapiro if (*state != SMFIR_CONTINUE)
231506f25ae9SGregory Neil Shapiro break;
231606f25ae9SGregory Neil Shapiro }
231706f25ae9SGregory Neil Shapiro return response;
231806f25ae9SGregory Neil Shapiro }
2319d0cef73dSGregory Neil Shapiro
2320d0cef73dSGregory Neil Shapiro static int milter_getsymlist __P((struct milter *, char *, int, int));
2321d0cef73dSGregory Neil Shapiro
2322d0cef73dSGregory Neil Shapiro static int
milter_getsymlist(m,buf,rlen,offset)2323d0cef73dSGregory Neil Shapiro milter_getsymlist(m, buf, rlen, offset)
2324d0cef73dSGregory Neil Shapiro struct milter *m;
2325d0cef73dSGregory Neil Shapiro char *buf;
2326d0cef73dSGregory Neil Shapiro int rlen;
2327d0cef73dSGregory Neil Shapiro int offset;
2328d0cef73dSGregory Neil Shapiro {
2329d0cef73dSGregory Neil Shapiro int i, r, nummac;
2330d0cef73dSGregory Neil Shapiro mi_int32 v;
2331d0cef73dSGregory Neil Shapiro
2332d0cef73dSGregory Neil Shapiro SM_ASSERT(m != NULL);
2333d0cef73dSGregory Neil Shapiro SM_ASSERT(buf != NULL);
2334d0cef73dSGregory Neil Shapiro
2335d0cef73dSGregory Neil Shapiro while (offset + MILTER_LEN_BYTES < rlen)
2336d0cef73dSGregory Neil Shapiro {
2337d0cef73dSGregory Neil Shapiro size_t len;
2338d0cef73dSGregory Neil Shapiro char **macros;
2339d0cef73dSGregory Neil Shapiro
2340d0cef73dSGregory Neil Shapiro nummac = 0;
2341d0cef73dSGregory Neil Shapiro (void) memcpy((char *) &v, buf + offset, MILTER_LEN_BYTES);
2342d0cef73dSGregory Neil Shapiro i = ntohl(v);
2343d0cef73dSGregory Neil Shapiro if (i < SMFIM_FIRST || i > SMFIM_LAST)
2344d0cef73dSGregory Neil Shapiro return -1;
2345d0cef73dSGregory Neil Shapiro offset += MILTER_LEN_BYTES;
2346d0cef73dSGregory Neil Shapiro macros = NULL;
2347d0cef73dSGregory Neil Shapiro
2348da7d7b9cSGregory Neil Shapiro #define SM_M_MACRO_NAME(i) (((i) < SM_ARRAY_SIZE(MilterOptTab) && (i) >= 0) \
2349da7d7b9cSGregory Neil Shapiro ? MilterOptTab[i].mo_name : "?")
2350d0cef73dSGregory Neil Shapiro switch (i)
2351d0cef73dSGregory Neil Shapiro {
2352ba00ec3dSGregory Neil Shapiro case SMFIM_CONNECT:
2353ba00ec3dSGregory Neil Shapiro case SMFIM_HELO:
2354ba00ec3dSGregory Neil Shapiro case SMFIM_ENVFROM:
2355ba00ec3dSGregory Neil Shapiro case SMFIM_ENVRCPT:
2356ba00ec3dSGregory Neil Shapiro case SMFIM_EOH:
2357ba00ec3dSGregory Neil Shapiro case SMFIM_EOM:
2358ba00ec3dSGregory Neil Shapiro case SMFIM_DATA:
2359ba00ec3dSGregory Neil Shapiro SM_ASSERT(m->mf_idx > 0 && m->mf_idx < MAXFILTERS);
2360ba00ec3dSGregory Neil Shapiro macros = MilterMacros[i][m->mf_idx];
2361ba00ec3dSGregory Neil Shapiro m->mf_lflags |= MI_LFLAGS_SYM(i);
2362d0cef73dSGregory Neil Shapiro len = strlen(buf + offset);
23635b0945b5SGregory Neil Shapiro r = milter_set_macros(m->mf_name, macros, buf + offset,
23645b0945b5SGregory Neil Shapiro nummac);
2365d0cef73dSGregory Neil Shapiro if (r >= 0)
2366d0cef73dSGregory Neil Shapiro nummac = r;
2367ba00ec3dSGregory Neil Shapiro if (tTd(64, 5))
2368da7d7b9cSGregory Neil Shapiro sm_dprintf("milter_getsymlist(%s, %s, \"%s\")=%d\n",
23695b0945b5SGregory Neil Shapiro m->mf_name, SM_M_MACRO_NAME(i),
2370da7d7b9cSGregory Neil Shapiro buf + offset, r);
2371d0cef73dSGregory Neil Shapiro break;
2372d0cef73dSGregory Neil Shapiro
2373d0cef73dSGregory Neil Shapiro default:
2374d0cef73dSGregory Neil Shapiro return -1;
2375d0cef73dSGregory Neil Shapiro }
2376d0cef73dSGregory Neil Shapiro offset += len + 1;
2377d0cef73dSGregory Neil Shapiro }
2378d0cef73dSGregory Neil Shapiro
2379d0cef73dSGregory Neil Shapiro return 0;
2380d0cef73dSGregory Neil Shapiro }
2381d0cef73dSGregory Neil Shapiro
238240266059SGregory Neil Shapiro /*
238306f25ae9SGregory Neil Shapiro ** MILTER_NEGOTIATE -- get version and flags from filter
238406f25ae9SGregory Neil Shapiro **
238506f25ae9SGregory Neil Shapiro ** Parameters:
238606f25ae9SGregory Neil Shapiro ** m -- milter filter structure.
238706f25ae9SGregory Neil Shapiro ** e -- current envelope.
2388ffb83623SGregory Neil Shapiro ** milters -- milters structure.
238906f25ae9SGregory Neil Shapiro **
239006f25ae9SGregory Neil Shapiro ** Returns:
239106f25ae9SGregory Neil Shapiro ** 0 on success, -1 otherwise
239206f25ae9SGregory Neil Shapiro */
239306f25ae9SGregory Neil Shapiro
239406f25ae9SGregory Neil Shapiro static int
milter_negotiate(m,e,milters)2395ffb83623SGregory Neil Shapiro milter_negotiate(m, e, milters)
239606f25ae9SGregory Neil Shapiro struct milter *m;
239706f25ae9SGregory Neil Shapiro ENVELOPE *e;
2398ffb83623SGregory Neil Shapiro milters_T *milters;
239906f25ae9SGregory Neil Shapiro {
240006f25ae9SGregory Neil Shapiro char rcmd;
2401d0cef73dSGregory Neil Shapiro mi_int32 fvers, fflags, pflags;
2402d0cef73dSGregory Neil Shapiro mi_int32 mta_prot_vers, mta_prot_flags, mta_actions;
240306f25ae9SGregory Neil Shapiro ssize_t rlen;
24044e4196cbSGregory Neil Shapiro char *response;
240506f25ae9SGregory Neil Shapiro char data[MILTER_OPTLEN];
240606f25ae9SGregory Neil Shapiro
240706f25ae9SGregory Neil Shapiro /* sanity check */
240806f25ae9SGregory Neil Shapiro if (m->mf_sock < 0 || m->mf_state != SMFS_OPEN)
240906f25ae9SGregory Neil Shapiro {
241040266059SGregory Neil Shapiro if (MilterLogLevel > 0)
241106f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
241240266059SGregory Neil Shapiro "Milter (%s): negotiate, impossible state",
241306f25ae9SGregory Neil Shapiro m->mf_name);
241440266059SGregory Neil Shapiro milter_error(m, e);
241506f25ae9SGregory Neil Shapiro return -1;
241606f25ae9SGregory Neil Shapiro }
241706f25ae9SGregory Neil Shapiro
2418d0cef73dSGregory Neil Shapiro # if _FFR_MILTER_CHECK
2419d0cef73dSGregory Neil Shapiro mta_prot_vers = m->mf_mta_prot_version;
2420d0cef73dSGregory Neil Shapiro mta_prot_flags = m->mf_mta_prot_flags;
2421d0cef73dSGregory Neil Shapiro mta_actions = m->mf_mta_actions;
2422d0cef73dSGregory Neil Shapiro # else /* _FFR_MILTER_CHECK */
2423d0cef73dSGregory Neil Shapiro mta_prot_vers = SMFI_PROT_VERSION;
2424d0cef73dSGregory Neil Shapiro mta_prot_flags = SMFI_CURR_PROT;
2425d0cef73dSGregory Neil Shapiro mta_actions = SMFI_CURR_ACTS;
2426d0cef73dSGregory Neil Shapiro # endif /* _FFR_MILTER_CHECK */
24279bd497b8SGregory Neil Shapiro # if _FFR_MDS_NEGOTIATE
24289bd497b8SGregory Neil Shapiro if (MilterMaxDataSize == MILTER_MDS_256K)
24299bd497b8SGregory Neil Shapiro mta_prot_flags |= SMFIP_MDS_256K;
24309bd497b8SGregory Neil Shapiro else if (MilterMaxDataSize == MILTER_MDS_1M)
24319bd497b8SGregory Neil Shapiro mta_prot_flags |= SMFIP_MDS_1M;
24329bd497b8SGregory Neil Shapiro # endif /* _FFR_MDS_NEGOTIATE */
2433d0cef73dSGregory Neil Shapiro
2434d0cef73dSGregory Neil Shapiro fvers = htonl(mta_prot_vers);
2435d0cef73dSGregory Neil Shapiro pflags = htonl(mta_prot_flags);
2436d0cef73dSGregory Neil Shapiro fflags = htonl(mta_actions);
243706f25ae9SGregory Neil Shapiro (void) memcpy(data, (char *) &fvers, MILTER_LEN_BYTES);
243806f25ae9SGregory Neil Shapiro (void) memcpy(data + MILTER_LEN_BYTES,
243906f25ae9SGregory Neil Shapiro (char *) &fflags, MILTER_LEN_BYTES);
244006f25ae9SGregory Neil Shapiro (void) memcpy(data + (MILTER_LEN_BYTES * 2),
244106f25ae9SGregory Neil Shapiro (char *) &pflags, MILTER_LEN_BYTES);
2442d0cef73dSGregory Neil Shapiro (void) milter_write(m, SMFIC_OPTNEG, data, sizeof(data),
2443d0cef73dSGregory Neil Shapiro m->mf_timeout[SMFTO_WRITE], e, "negotiate");
244406f25ae9SGregory Neil Shapiro
244506f25ae9SGregory Neil Shapiro if (m->mf_state == SMFS_ERROR)
244606f25ae9SGregory Neil Shapiro return -1;
244706f25ae9SGregory Neil Shapiro
2448d0cef73dSGregory Neil Shapiro if (tTd(64, 5))
2449d0cef73dSGregory Neil Shapiro sm_dprintf("milter_negotiate(%s): send: version %lu, fflags 0x%lx, pflags 0x%lx\n",
2450da7d7b9cSGregory Neil Shapiro m->mf_name, (unsigned long) ntohl(fvers),
2451da7d7b9cSGregory Neil Shapiro (unsigned long) ntohl(fflags),
2452da7d7b9cSGregory Neil Shapiro (unsigned long) ntohl(pflags));
2453d0cef73dSGregory Neil Shapiro
2454d0cef73dSGregory Neil Shapiro response = milter_read(m, &rcmd, &rlen, m->mf_timeout[SMFTO_READ], e,
2455d0cef73dSGregory Neil Shapiro "negotiate");
245606f25ae9SGregory Neil Shapiro if (m->mf_state == SMFS_ERROR)
24572fb4f839SGregory Neil Shapiro {
24582fb4f839SGregory Neil Shapiro SM_FREE(response);
245906f25ae9SGregory Neil Shapiro return -1;
24602fb4f839SGregory Neil Shapiro }
246106f25ae9SGregory Neil Shapiro
246206f25ae9SGregory Neil Shapiro if (rcmd != SMFIC_OPTNEG)
246306f25ae9SGregory Neil Shapiro {
246406f25ae9SGregory Neil Shapiro if (tTd(64, 5))
246540266059SGregory Neil Shapiro sm_dprintf("milter_negotiate(%s): returned %c instead of %c\n",
246606f25ae9SGregory Neil Shapiro m->mf_name, rcmd, SMFIC_OPTNEG);
246740266059SGregory Neil Shapiro if (MilterLogLevel > 0)
246806f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
246940266059SGregory Neil Shapiro "Milter (%s): negotiate: returned %c instead of %c",
247006f25ae9SGregory Neil Shapiro m->mf_name, rcmd, SMFIC_OPTNEG);
24715b0945b5SGregory Neil Shapiro SM_FREE(response);
247240266059SGregory Neil Shapiro milter_error(m, e);
247306f25ae9SGregory Neil Shapiro return -1;
247406f25ae9SGregory Neil Shapiro }
247506f25ae9SGregory Neil Shapiro
247606f25ae9SGregory Neil Shapiro /* Make sure we have enough bytes for the version */
247706f25ae9SGregory Neil Shapiro if (response == NULL || rlen < MILTER_LEN_BYTES)
247806f25ae9SGregory Neil Shapiro {
247906f25ae9SGregory Neil Shapiro if (tTd(64, 5))
248040266059SGregory Neil Shapiro sm_dprintf("milter_negotiate(%s): did not return valid info\n",
248106f25ae9SGregory Neil Shapiro m->mf_name);
248240266059SGregory Neil Shapiro if (MilterLogLevel > 0)
248306f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
248440266059SGregory Neil Shapiro "Milter (%s): negotiate: did not return valid info",
248506f25ae9SGregory Neil Shapiro m->mf_name);
24865b0945b5SGregory Neil Shapiro SM_FREE(response);
248740266059SGregory Neil Shapiro milter_error(m, e);
248806f25ae9SGregory Neil Shapiro return -1;
248906f25ae9SGregory Neil Shapiro }
249006f25ae9SGregory Neil Shapiro
249106f25ae9SGregory Neil Shapiro /* extract information */
249206f25ae9SGregory Neil Shapiro (void) memcpy((char *) &fvers, response, MILTER_LEN_BYTES);
249306f25ae9SGregory Neil Shapiro
249406f25ae9SGregory Neil Shapiro /* Now make sure we have enough for the feature bitmap */
2495d0cef73dSGregory Neil Shapiro if (rlen < MILTER_OPTLEN)
249606f25ae9SGregory Neil Shapiro {
249706f25ae9SGregory Neil Shapiro if (tTd(64, 5))
249840266059SGregory Neil Shapiro sm_dprintf("milter_negotiate(%s): did not return enough info\n",
249906f25ae9SGregory Neil Shapiro m->mf_name);
250040266059SGregory Neil Shapiro if (MilterLogLevel > 0)
250106f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
250240266059SGregory Neil Shapiro "Milter (%s): negotiate: did not return enough info",
250306f25ae9SGregory Neil Shapiro m->mf_name);
25045b0945b5SGregory Neil Shapiro SM_FREE(response);
250540266059SGregory Neil Shapiro milter_error(m, e);
250606f25ae9SGregory Neil Shapiro return -1;
250706f25ae9SGregory Neil Shapiro }
250806f25ae9SGregory Neil Shapiro
250906f25ae9SGregory Neil Shapiro (void) memcpy((char *) &fflags, response + MILTER_LEN_BYTES,
251006f25ae9SGregory Neil Shapiro MILTER_LEN_BYTES);
251106f25ae9SGregory Neil Shapiro (void) memcpy((char *) &pflags, response + (MILTER_LEN_BYTES * 2),
251206f25ae9SGregory Neil Shapiro MILTER_LEN_BYTES);
251306f25ae9SGregory Neil Shapiro
251406f25ae9SGregory Neil Shapiro m->mf_fvers = ntohl(fvers);
251506f25ae9SGregory Neil Shapiro m->mf_fflags = ntohl(fflags);
251606f25ae9SGregory Neil Shapiro m->mf_pflags = ntohl(pflags);
251706f25ae9SGregory Neil Shapiro
251806f25ae9SGregory Neil Shapiro /* check for version compatibility */
251906f25ae9SGregory Neil Shapiro if (m->mf_fvers == 1 ||
252006f25ae9SGregory Neil Shapiro m->mf_fvers > SMFI_VERSION)
252106f25ae9SGregory Neil Shapiro {
252206f25ae9SGregory Neil Shapiro if (tTd(64, 5))
2523605302a5SGregory Neil Shapiro sm_dprintf("milter_negotiate(%s): version %d != MTA milter version %d\n",
252406f25ae9SGregory Neil Shapiro m->mf_name, m->mf_fvers, SMFI_VERSION);
252540266059SGregory Neil Shapiro if (MilterLogLevel > 0)
252606f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
2527605302a5SGregory Neil Shapiro "Milter (%s): negotiate: version %d != MTA milter version %d",
252806f25ae9SGregory Neil Shapiro m->mf_name, m->mf_fvers, SMFI_VERSION);
252940266059SGregory Neil Shapiro milter_error(m, e);
2530d0cef73dSGregory Neil Shapiro goto error;
253106f25ae9SGregory Neil Shapiro }
253206f25ae9SGregory Neil Shapiro
253306f25ae9SGregory Neil Shapiro /* check for filter feature mismatch */
2534d0cef73dSGregory Neil Shapiro if ((m->mf_fflags & mta_actions) != m->mf_fflags)
253506f25ae9SGregory Neil Shapiro {
253606f25ae9SGregory Neil Shapiro if (tTd(64, 5))
2537605302a5SGregory Neil Shapiro sm_dprintf("milter_negotiate(%s): filter abilities 0x%x != MTA milter abilities 0x%lx\n",
253806f25ae9SGregory Neil Shapiro m->mf_name, m->mf_fflags,
2539d0cef73dSGregory Neil Shapiro (unsigned long) mta_actions);
254040266059SGregory Neil Shapiro if (MilterLogLevel > 0)
254106f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
2542605302a5SGregory Neil Shapiro "Milter (%s): negotiate: filter abilities 0x%x != MTA milter abilities 0x%lx",
254306f25ae9SGregory Neil Shapiro m->mf_name, m->mf_fflags,
2544d0cef73dSGregory Neil Shapiro (unsigned long) mta_actions);
254540266059SGregory Neil Shapiro milter_error(m, e);
2546d0cef73dSGregory Neil Shapiro goto error;
254706f25ae9SGregory Neil Shapiro }
254806f25ae9SGregory Neil Shapiro
25499bd497b8SGregory Neil Shapiro # if _FFR_MDS_NEGOTIATE
25505b0945b5SGregory Neil Shapiro # define MDSWARNING(sz) \
25515b0945b5SGregory Neil Shapiro do \
25525b0945b5SGregory Neil Shapiro { \
25535b0945b5SGregory Neil Shapiro sm_syslog(LOG_WARNING, NOQID, \
25545b0945b5SGregory Neil Shapiro "WARNING: Milter.maxdatasize: configured=%lu, set by milter(%s)=%d", \
25555b0945b5SGregory Neil Shapiro (unsigned long) MilterMaxDataSize, m->mf_name, sz); \
25565b0945b5SGregory Neil Shapiro MilterMaxDataSize = sz; \
25575b0945b5SGregory Neil Shapiro } while (0)
25585b0945b5SGregory Neil Shapiro
25599bd497b8SGregory Neil Shapiro /* use a table instead of sequence? */
25609bd497b8SGregory Neil Shapiro if (bitset(SMFIP_MDS_1M, m->mf_pflags))
25619bd497b8SGregory Neil Shapiro {
25629bd497b8SGregory Neil Shapiro if (MilterMaxDataSize != MILTER_MDS_1M)
25635b0945b5SGregory Neil Shapiro MDSWARNING(MILTER_MDS_1M);
25649bd497b8SGregory Neil Shapiro }
25659bd497b8SGregory Neil Shapiro else if (bitset(SMFIP_MDS_256K, m->mf_pflags))
25669bd497b8SGregory Neil Shapiro {
25679bd497b8SGregory Neil Shapiro if (MilterMaxDataSize != MILTER_MDS_256K)
25685b0945b5SGregory Neil Shapiro MDSWARNING(MILTER_MDS_256K);
25699bd497b8SGregory Neil Shapiro }
25705b0945b5SGregory Neil Shapiro
25715b0945b5SGregory Neil Shapiro /*
25725b0945b5SGregory Neil Shapiro ** Note: it is not possible to distinguish between
25735b0945b5SGregory Neil Shapiro ** - milter requested 64K
25745b0945b5SGregory Neil Shapiro ** - milter did not request anything
25755b0945b5SGregory Neil Shapiro ** as there is no SMFIP_MDS_64K flag.
25765b0945b5SGregory Neil Shapiro */
25775b0945b5SGregory Neil Shapiro
25789bd497b8SGregory Neil Shapiro else if (MilterMaxDataSize != MILTER_MDS_64K)
25795b0945b5SGregory Neil Shapiro MDSWARNING(MILTER_MDS_64K);
25809bd497b8SGregory Neil Shapiro m->mf_pflags &= ~SMFI_INTERNAL;
25819bd497b8SGregory Neil Shapiro # endif /* _FFR_MDS_NEGOTIATE */
25829bd497b8SGregory Neil Shapiro
258306f25ae9SGregory Neil Shapiro /* check for protocol feature mismatch */
2584d0cef73dSGregory Neil Shapiro if ((m->mf_pflags & mta_prot_flags) != m->mf_pflags)
258506f25ae9SGregory Neil Shapiro {
258606f25ae9SGregory Neil Shapiro if (tTd(64, 5))
2587605302a5SGregory Neil Shapiro sm_dprintf("milter_negotiate(%s): protocol abilities 0x%x != MTA milter abilities 0x%lx\n",
258806f25ae9SGregory Neil Shapiro m->mf_name, m->mf_pflags,
2589d0cef73dSGregory Neil Shapiro (unsigned long) mta_prot_flags);
259040266059SGregory Neil Shapiro if (MilterLogLevel > 0)
259106f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
2592605302a5SGregory Neil Shapiro "Milter (%s): negotiate: protocol abilities 0x%x != MTA milter abilities 0x%lx",
259306f25ae9SGregory Neil Shapiro m->mf_name, m->mf_pflags,
2594d0cef73dSGregory Neil Shapiro (unsigned long) mta_prot_flags);
259540266059SGregory Neil Shapiro milter_error(m, e);
2596d0cef73dSGregory Neil Shapiro goto error;
259706f25ae9SGregory Neil Shapiro }
259806f25ae9SGregory Neil Shapiro
25994e4196cbSGregory Neil Shapiro if (m->mf_fvers <= 2)
26004e4196cbSGregory Neil Shapiro m->mf_pflags |= SMFIP_NOUNKNOWN;
26014e4196cbSGregory Neil Shapiro if (m->mf_fvers <= 3)
26024e4196cbSGregory Neil Shapiro m->mf_pflags |= SMFIP_NODATA;
26034e4196cbSGregory Neil Shapiro
2604d0cef73dSGregory Neil Shapiro if (rlen > MILTER_OPTLEN)
2605d0cef73dSGregory Neil Shapiro {
2606d0cef73dSGregory Neil Shapiro milter_getsymlist(m, response, rlen, MILTER_OPTLEN);
2607d0cef73dSGregory Neil Shapiro }
2608d0cef73dSGregory Neil Shapiro
2609ffb83623SGregory Neil Shapiro if (bitset(SMFIF_DELRCPT, m->mf_fflags))
2610ffb83623SGregory Neil Shapiro milters->mis_flags |= MIS_FL_DEL_RCPT;
2611ffb83623SGregory Neil Shapiro if (!bitset(SMFIP_NORCPT, m->mf_pflags) &&
2612ffb83623SGregory Neil Shapiro !bitset(SMFIP_NR_RCPT, m->mf_pflags))
2613ffb83623SGregory Neil Shapiro milters->mis_flags |= MIS_FL_REJ_RCPT;
2614ffb83623SGregory Neil Shapiro
261506f25ae9SGregory Neil Shapiro if (tTd(64, 5))
2616d0cef73dSGregory Neil Shapiro sm_dprintf("milter_negotiate(%s): received: version %u, fflags 0x%x, pflags 0x%x\n",
261706f25ae9SGregory Neil Shapiro m->mf_name, m->mf_fvers, m->mf_fflags, m->mf_pflags);
26185b0945b5SGregory Neil Shapiro SM_FREE(response);
261906f25ae9SGregory Neil Shapiro return 0;
2620d0cef73dSGregory Neil Shapiro
2621d0cef73dSGregory Neil Shapiro error:
26225b0945b5SGregory Neil Shapiro SM_FREE(response);
2623d0cef73dSGregory Neil Shapiro return -1;
262406f25ae9SGregory Neil Shapiro }
2625d0cef73dSGregory Neil Shapiro
262640266059SGregory Neil Shapiro /*
262706f25ae9SGregory Neil Shapiro ** MILTER_PER_CONNECTION_CHECK -- checks on per-connection commands
262806f25ae9SGregory Neil Shapiro **
262906f25ae9SGregory Neil Shapiro ** Reduce code duplication by putting these checks in one place
263006f25ae9SGregory Neil Shapiro **
263106f25ae9SGregory Neil Shapiro ** Parameters:
263206f25ae9SGregory Neil Shapiro ** e -- current envelope.
263306f25ae9SGregory Neil Shapiro **
263406f25ae9SGregory Neil Shapiro ** Returns:
263506f25ae9SGregory Neil Shapiro ** none
263606f25ae9SGregory Neil Shapiro */
263706f25ae9SGregory Neil Shapiro
263806f25ae9SGregory Neil Shapiro static void
milter_per_connection_check(e)263906f25ae9SGregory Neil Shapiro milter_per_connection_check(e)
264006f25ae9SGregory Neil Shapiro ENVELOPE *e;
264106f25ae9SGregory Neil Shapiro {
264206f25ae9SGregory Neil Shapiro int i;
264306f25ae9SGregory Neil Shapiro
264406f25ae9SGregory Neil Shapiro /* see if we are done with any of the filters */
264506f25ae9SGregory Neil Shapiro for (i = 0; InputFilters[i] != NULL; i++)
264606f25ae9SGregory Neil Shapiro {
264706f25ae9SGregory Neil Shapiro struct milter *m = InputFilters[i];
264806f25ae9SGregory Neil Shapiro
2649602a2b1bSGregory Neil Shapiro if (m->mf_state == SMFS_CLOSABLE)
265006f25ae9SGregory Neil Shapiro milter_quit_filter(m, e);
265106f25ae9SGregory Neil Shapiro }
265206f25ae9SGregory Neil Shapiro }
2653d0cef73dSGregory Neil Shapiro
265440266059SGregory Neil Shapiro /*
265506f25ae9SGregory Neil Shapiro ** MILTER_ERROR -- Put a milter filter into error state
265606f25ae9SGregory Neil Shapiro **
265706f25ae9SGregory Neil Shapiro ** Parameters:
265806f25ae9SGregory Neil Shapiro ** m -- the broken filter.
2659b6bacd31SGregory Neil Shapiro ** e -- current envelope.
266006f25ae9SGregory Neil Shapiro **
266106f25ae9SGregory Neil Shapiro ** Returns:
266206f25ae9SGregory Neil Shapiro ** none
266306f25ae9SGregory Neil Shapiro */
266406f25ae9SGregory Neil Shapiro
266506f25ae9SGregory Neil Shapiro static void
milter_error(m,e)266640266059SGregory Neil Shapiro milter_error(m, e)
266706f25ae9SGregory Neil Shapiro struct milter *m;
266840266059SGregory Neil Shapiro ENVELOPE *e;
266906f25ae9SGregory Neil Shapiro {
267006f25ae9SGregory Neil Shapiro /*
2671b6bacd31SGregory Neil Shapiro ** We could send a quit here but we may have gotten here due to
2672b6bacd31SGregory Neil Shapiro ** an I/O error so we don't want to try to make things worse.
267306f25ae9SGregory Neil Shapiro */
267406f25ae9SGregory Neil Shapiro
267506f25ae9SGregory Neil Shapiro if (m->mf_sock >= 0)
267606f25ae9SGregory Neil Shapiro {
267706f25ae9SGregory Neil Shapiro (void) close(m->mf_sock);
267806f25ae9SGregory Neil Shapiro m->mf_sock = -1;
267906f25ae9SGregory Neil Shapiro }
268006f25ae9SGregory Neil Shapiro m->mf_state = SMFS_ERROR;
268140266059SGregory Neil Shapiro
268240266059SGregory Neil Shapiro if (MilterLogLevel > 0)
268340266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter (%s): to error state",
268440266059SGregory Neil Shapiro m->mf_name);
268506f25ae9SGregory Neil Shapiro }
2686d0cef73dSGregory Neil Shapiro
268740266059SGregory Neil Shapiro /*
268806f25ae9SGregory Neil Shapiro ** MILTER_HEADERS -- send headers to a single milter filter
268906f25ae9SGregory Neil Shapiro **
269006f25ae9SGregory Neil Shapiro ** Parameters:
269106f25ae9SGregory Neil Shapiro ** m -- current filter.
269206f25ae9SGregory Neil Shapiro ** e -- current envelope.
269306f25ae9SGregory Neil Shapiro ** state -- return state from response.
269406f25ae9SGregory Neil Shapiro **
269506f25ae9SGregory Neil Shapiro ** Returns:
269606f25ae9SGregory Neil Shapiro ** response string (may be NULL)
269706f25ae9SGregory Neil Shapiro */
269806f25ae9SGregory Neil Shapiro
269906f25ae9SGregory Neil Shapiro static char *
milter_headers(m,e,state)270006f25ae9SGregory Neil Shapiro milter_headers(m, e, state)
270106f25ae9SGregory Neil Shapiro struct milter *m;
270206f25ae9SGregory Neil Shapiro ENVELOPE *e;
270306f25ae9SGregory Neil Shapiro char *state;
270406f25ae9SGregory Neil Shapiro {
270506f25ae9SGregory Neil Shapiro char *response = NULL;
270606f25ae9SGregory Neil Shapiro HDR *h;
270706f25ae9SGregory Neil Shapiro
270840266059SGregory Neil Shapiro if (MilterLogLevel > 17)
270940266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter (%s): headers, send",
271040266059SGregory Neil Shapiro m->mf_name);
271140266059SGregory Neil Shapiro
271206f25ae9SGregory Neil Shapiro for (h = e->e_header; h != NULL; h = h->h_link)
271306f25ae9SGregory Neil Shapiro {
2714d0cef73dSGregory Neil Shapiro int len_n, len_v, len_t, len_f;
2715d0cef73dSGregory Neil Shapiro char *buf, *hv;
271606f25ae9SGregory Neil Shapiro
271706f25ae9SGregory Neil Shapiro /* don't send over deleted headers */
271806f25ae9SGregory Neil Shapiro if (h->h_value == NULL)
271906f25ae9SGregory Neil Shapiro {
2720e92d3f3fSGregory Neil Shapiro /* strip H_USER so not counted in milter_changeheader() */
272106f25ae9SGregory Neil Shapiro h->h_flags &= ~H_USER;
272206f25ae9SGregory Neil Shapiro continue;
272306f25ae9SGregory Neil Shapiro }
272406f25ae9SGregory Neil Shapiro
272506f25ae9SGregory Neil Shapiro /* skip auto-generated */
272606f25ae9SGregory Neil Shapiro if (!bitset(H_USER, h->h_flags))
272706f25ae9SGregory Neil Shapiro continue;
272806f25ae9SGregory Neil Shapiro
272906f25ae9SGregory Neil Shapiro if (tTd(64, 10))
273040266059SGregory Neil Shapiro sm_dprintf("milter_headers: %s:%s\n",
273106f25ae9SGregory Neil Shapiro h->h_field, h->h_value);
273240266059SGregory Neil Shapiro if (MilterLogLevel > 21)
273340266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter (%s): header, %s",
273440266059SGregory Neil Shapiro m->mf_name, h->h_field);
273506f25ae9SGregory Neil Shapiro
2736d0cef73dSGregory Neil Shapiro if (bitset(SMFIP_HDR_LEADSPC, m->mf_pflags)
2737d0cef73dSGregory Neil Shapiro || *(h->h_value) != ' ')
2738d0cef73dSGregory Neil Shapiro hv = h->h_value;
2739d0cef73dSGregory Neil Shapiro else
2740d0cef73dSGregory Neil Shapiro hv = h->h_value + 1;
2741d0cef73dSGregory Neil Shapiro len_f = strlen(h->h_field) + 1;
2742d0cef73dSGregory Neil Shapiro len_t = len_f + strlen(hv) + 1;
2743d0cef73dSGregory Neil Shapiro if (len_t < 0)
274440266059SGregory Neil Shapiro continue;
2745d0cef73dSGregory Neil Shapiro buf = (char *) xalloc(len_t);
2746d0cef73dSGregory Neil Shapiro
2747d0cef73dSGregory Neil Shapiro /*
2748d0cef73dSGregory Neil Shapiro ** Note: currently the call to dequote_internal_chars()
2749d0cef73dSGregory Neil Shapiro ** is not required as h_field is supposed to be 7-bit US-ASCII.
2750d0cef73dSGregory Neil Shapiro */
2751d0cef73dSGregory Neil Shapiro
2752d0cef73dSGregory Neil Shapiro len_n = dequote_internal_chars(h->h_field, buf, len_f);
2753d0cef73dSGregory Neil Shapiro SM_ASSERT(len_n < len_f);
2754d0cef73dSGregory Neil Shapiro len_v = dequote_internal_chars(hv, buf + len_n + 1,
2755d0cef73dSGregory Neil Shapiro len_t - len_n - 1);
2756d0cef73dSGregory Neil Shapiro SM_ASSERT(len_t >= len_n + 1 + len_v + 1);
2757d0cef73dSGregory Neil Shapiro len_t = len_n + 1 + len_v + 1;
275806f25ae9SGregory Neil Shapiro
275906f25ae9SGregory Neil Shapiro /* send it over */
276006f25ae9SGregory Neil Shapiro response = milter_send_command(m, SMFIC_HEADER, buf,
2761d0cef73dSGregory Neil Shapiro len_t, e, state, "header");
2762d0cef73dSGregory Neil Shapiro sm_free(buf);
276306f25ae9SGregory Neil Shapiro if (m->mf_state == SMFS_ERROR ||
276406f25ae9SGregory Neil Shapiro m->mf_state == SMFS_DONE ||
276506f25ae9SGregory Neil Shapiro *state != SMFIR_CONTINUE)
276606f25ae9SGregory Neil Shapiro break;
276706f25ae9SGregory Neil Shapiro }
276840266059SGregory Neil Shapiro if (MilterLogLevel > 17)
276940266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter (%s): headers, sent",
277040266059SGregory Neil Shapiro m->mf_name);
277106f25ae9SGregory Neil Shapiro return response;
277206f25ae9SGregory Neil Shapiro }
2773d0cef73dSGregory Neil Shapiro
277440266059SGregory Neil Shapiro /*
277506f25ae9SGregory Neil Shapiro ** MILTER_BODY -- send the body to a filter
277606f25ae9SGregory Neil Shapiro **
277706f25ae9SGregory Neil Shapiro ** Parameters:
277806f25ae9SGregory Neil Shapiro ** m -- current filter.
277906f25ae9SGregory Neil Shapiro ** e -- current envelope.
278006f25ae9SGregory Neil Shapiro ** state -- return state from response.
278106f25ae9SGregory Neil Shapiro **
278206f25ae9SGregory Neil Shapiro ** Returns:
278306f25ae9SGregory Neil Shapiro ** response string (may be NULL)
278406f25ae9SGregory Neil Shapiro */
278506f25ae9SGregory Neil Shapiro
278606f25ae9SGregory Neil Shapiro static char *
milter_body(m,e,state)278706f25ae9SGregory Neil Shapiro milter_body(m, e, state)
278806f25ae9SGregory Neil Shapiro struct milter *m;
278906f25ae9SGregory Neil Shapiro ENVELOPE *e;
279006f25ae9SGregory Neil Shapiro char *state;
279106f25ae9SGregory Neil Shapiro {
279206f25ae9SGregory Neil Shapiro char bufchar = '\0';
279306f25ae9SGregory Neil Shapiro char prevchar = '\0';
279406f25ae9SGregory Neil Shapiro int c;
279506f25ae9SGregory Neil Shapiro char *response = NULL;
279606f25ae9SGregory Neil Shapiro char *bp;
279706f25ae9SGregory Neil Shapiro char buf[MILTER_CHUNK_SIZE];
279806f25ae9SGregory Neil Shapiro
279906f25ae9SGregory Neil Shapiro if (tTd(64, 10))
280040266059SGregory Neil Shapiro sm_dprintf("milter_body\n");
280106f25ae9SGregory Neil Shapiro
280206f25ae9SGregory Neil Shapiro if (bfrewind(e->e_dfp) < 0)
280306f25ae9SGregory Neil Shapiro {
280406f25ae9SGregory Neil Shapiro ExitStat = EX_IOERR;
280506f25ae9SGregory Neil Shapiro *state = SMFIR_TEMPFAIL;
280640266059SGregory Neil Shapiro syserr("milter_body: %s/%cf%s: rewind error",
280740266059SGregory Neil Shapiro qid_printqueue(e->e_qgrp, e->e_qdir),
280840266059SGregory Neil Shapiro DATAFL_LETTER, e->e_id);
280906f25ae9SGregory Neil Shapiro return NULL;
281006f25ae9SGregory Neil Shapiro }
281106f25ae9SGregory Neil Shapiro
281240266059SGregory Neil Shapiro if (MilterLogLevel > 17)
281340266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter (%s): body, send",
281440266059SGregory Neil Shapiro m->mf_name);
281506f25ae9SGregory Neil Shapiro bp = buf;
281640266059SGregory Neil Shapiro while ((c = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT)) != SM_IO_EOF)
281706f25ae9SGregory Neil Shapiro {
281806f25ae9SGregory Neil Shapiro /* Change LF to CRLF */
281906f25ae9SGregory Neil Shapiro if (c == '\n')
282006f25ae9SGregory Neil Shapiro {
2821d0cef73dSGregory Neil Shapiro # if !_FFR_MILTER_CONVERT_ALL_LF_TO_CRLF
282206f25ae9SGregory Neil Shapiro /* Not a CRLF already? */
282306f25ae9SGregory Neil Shapiro if (prevchar != '\r')
28245b0945b5SGregory Neil Shapiro # endif
282506f25ae9SGregory Neil Shapiro {
282606f25ae9SGregory Neil Shapiro /* Room for CR now? */
2827d0cef73dSGregory Neil Shapiro if (bp + 2 > &buf[sizeof(buf)])
282806f25ae9SGregory Neil Shapiro {
282906f25ae9SGregory Neil Shapiro /* No room, buffer LF */
283006f25ae9SGregory Neil Shapiro bufchar = c;
283106f25ae9SGregory Neil Shapiro
283206f25ae9SGregory Neil Shapiro /* and send CR now */
283306f25ae9SGregory Neil Shapiro c = '\r';
283406f25ae9SGregory Neil Shapiro }
283506f25ae9SGregory Neil Shapiro else
283606f25ae9SGregory Neil Shapiro {
283706f25ae9SGregory Neil Shapiro /* Room to do it now */
283806f25ae9SGregory Neil Shapiro *bp++ = '\r';
283906f25ae9SGregory Neil Shapiro prevchar = '\r';
284006f25ae9SGregory Neil Shapiro }
284106f25ae9SGregory Neil Shapiro }
284206f25ae9SGregory Neil Shapiro }
284306f25ae9SGregory Neil Shapiro *bp++ = (char) c;
284406f25ae9SGregory Neil Shapiro prevchar = c;
2845d0cef73dSGregory Neil Shapiro if (bp >= &buf[sizeof(buf)])
284606f25ae9SGregory Neil Shapiro {
284706f25ae9SGregory Neil Shapiro /* send chunk */
284806f25ae9SGregory Neil Shapiro response = milter_send_command(m, SMFIC_BODY, buf,
2849d0cef73dSGregory Neil Shapiro bp - buf, e, state,
2850d0cef73dSGregory Neil Shapiro "body chunk");
285106f25ae9SGregory Neil Shapiro bp = buf;
285206f25ae9SGregory Neil Shapiro if (bufchar != '\0')
285306f25ae9SGregory Neil Shapiro {
285406f25ae9SGregory Neil Shapiro *bp++ = bufchar;
285506f25ae9SGregory Neil Shapiro bufchar = '\0';
285606f25ae9SGregory Neil Shapiro prevchar = bufchar;
285706f25ae9SGregory Neil Shapiro }
285806f25ae9SGregory Neil Shapiro }
285906f25ae9SGregory Neil Shapiro if (m->mf_state == SMFS_ERROR ||
286006f25ae9SGregory Neil Shapiro m->mf_state == SMFS_DONE ||
2861d0cef73dSGregory Neil Shapiro m->mf_state == SMFS_SKIP ||
286206f25ae9SGregory Neil Shapiro *state != SMFIR_CONTINUE)
286306f25ae9SGregory Neil Shapiro break;
286406f25ae9SGregory Neil Shapiro }
286506f25ae9SGregory Neil Shapiro
286606f25ae9SGregory Neil Shapiro /* check for read errors */
286740266059SGregory Neil Shapiro if (sm_io_error(e->e_dfp))
286806f25ae9SGregory Neil Shapiro {
286906f25ae9SGregory Neil Shapiro ExitStat = EX_IOERR;
287006f25ae9SGregory Neil Shapiro if (*state == SMFIR_CONTINUE ||
2871d0cef73dSGregory Neil Shapiro *state == SMFIR_ACCEPT ||
2872d0cef73dSGregory Neil Shapiro m->mf_state == SMFS_SKIP)
287306f25ae9SGregory Neil Shapiro {
287406f25ae9SGregory Neil Shapiro *state = SMFIR_TEMPFAIL;
287506f25ae9SGregory Neil Shapiro if (response != NULL)
287606f25ae9SGregory Neil Shapiro {
287740266059SGregory Neil Shapiro sm_free(response); /* XXX */
287806f25ae9SGregory Neil Shapiro response = NULL;
287906f25ae9SGregory Neil Shapiro }
288006f25ae9SGregory Neil Shapiro }
288140266059SGregory Neil Shapiro syserr("milter_body: %s/%cf%s: read error",
288240266059SGregory Neil Shapiro qid_printqueue(e->e_qgrp, e->e_qdir),
288340266059SGregory Neil Shapiro DATAFL_LETTER, e->e_id);
288406f25ae9SGregory Neil Shapiro return response;
288506f25ae9SGregory Neil Shapiro }
288606f25ae9SGregory Neil Shapiro
288706f25ae9SGregory Neil Shapiro /* send last body chunk */
288806f25ae9SGregory Neil Shapiro if (bp > buf &&
288906f25ae9SGregory Neil Shapiro m->mf_state != SMFS_ERROR &&
289006f25ae9SGregory Neil Shapiro m->mf_state != SMFS_DONE &&
2891d0cef73dSGregory Neil Shapiro m->mf_state != SMFS_SKIP &&
289206f25ae9SGregory Neil Shapiro *state == SMFIR_CONTINUE)
289306f25ae9SGregory Neil Shapiro {
289406f25ae9SGregory Neil Shapiro /* send chunk */
289506f25ae9SGregory Neil Shapiro response = milter_send_command(m, SMFIC_BODY, buf, bp - buf,
2896d0cef73dSGregory Neil Shapiro e, state, "last body chunk");
289706f25ae9SGregory Neil Shapiro bp = buf;
289806f25ae9SGregory Neil Shapiro }
289940266059SGregory Neil Shapiro if (MilterLogLevel > 17)
290040266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter (%s): body, sent",
290140266059SGregory Neil Shapiro m->mf_name);
2902d0cef73dSGregory Neil Shapiro if (m->mf_state == SMFS_SKIP)
2903d0cef73dSGregory Neil Shapiro {
2904d0cef73dSGregory Neil Shapiro *state = SMFIR_CONTINUE;
2905d0cef73dSGregory Neil Shapiro m->mf_state = SMFS_READY;
2906d0cef73dSGregory Neil Shapiro }
2907d0cef73dSGregory Neil Shapiro
290806f25ae9SGregory Neil Shapiro return response;
290906f25ae9SGregory Neil Shapiro }
291006f25ae9SGregory Neil Shapiro
291106f25ae9SGregory Neil Shapiro /*
291206f25ae9SGregory Neil Shapiro ** Actions
291306f25ae9SGregory Neil Shapiro */
291406f25ae9SGregory Neil Shapiro
291540266059SGregory Neil Shapiro /*
2916d0cef73dSGregory Neil Shapiro ** ADDLEADINGSPACE -- Add a leading space to a string
2917d0cef73dSGregory Neil Shapiro **
2918d0cef73dSGregory Neil Shapiro ** Parameters:
2919d0cef73dSGregory Neil Shapiro ** str -- string
2920d0cef73dSGregory Neil Shapiro ** rp -- resource pool for allocations
2921d0cef73dSGregory Neil Shapiro **
2922d0cef73dSGregory Neil Shapiro ** Returns:
2923d0cef73dSGregory Neil Shapiro ** pointer to new string
2924d0cef73dSGregory Neil Shapiro */
2925d0cef73dSGregory Neil Shapiro
2926d0cef73dSGregory Neil Shapiro static char *addleadingspace __P((char *, SM_RPOOL_T *));
2927d0cef73dSGregory Neil Shapiro
2928d0cef73dSGregory Neil Shapiro static char *
addleadingspace(str,rp)2929d0cef73dSGregory Neil Shapiro addleadingspace(str, rp)
2930d0cef73dSGregory Neil Shapiro char *str;
2931d0cef73dSGregory Neil Shapiro SM_RPOOL_T *rp;
2932d0cef73dSGregory Neil Shapiro {
2933d0cef73dSGregory Neil Shapiro size_t l;
2934d0cef73dSGregory Neil Shapiro char *new;
2935d0cef73dSGregory Neil Shapiro
2936d0cef73dSGregory Neil Shapiro SM_ASSERT(str != NULL);
2937d0cef73dSGregory Neil Shapiro l = strlen(str);
2938d0cef73dSGregory Neil Shapiro SM_ASSERT(l + 2 > l);
2939d0cef73dSGregory Neil Shapiro new = sm_rpool_malloc_x(rp, l + 2);
2940d0cef73dSGregory Neil Shapiro new[0] = ' ';
2941d0cef73dSGregory Neil Shapiro new[1] = '\0';
2942d0cef73dSGregory Neil Shapiro sm_strlcpy(new + 1, str, l + 1);
2943d0cef73dSGregory Neil Shapiro return new;
2944d0cef73dSGregory Neil Shapiro }
2945d0cef73dSGregory Neil Shapiro
2946d0cef73dSGregory Neil Shapiro /*
294706f25ae9SGregory Neil Shapiro ** MILTER_ADDHEADER -- Add the supplied header to the message
294806f25ae9SGregory Neil Shapiro **
294906f25ae9SGregory Neil Shapiro ** Parameters:
2950d0cef73dSGregory Neil Shapiro ** m -- current filter.
295106f25ae9SGregory Neil Shapiro ** response -- encoded form of header/value.
295206f25ae9SGregory Neil Shapiro ** rlen -- length of response.
295306f25ae9SGregory Neil Shapiro ** e -- current envelope.
295406f25ae9SGregory Neil Shapiro **
295506f25ae9SGregory Neil Shapiro ** Returns:
295606f25ae9SGregory Neil Shapiro ** none
295706f25ae9SGregory Neil Shapiro */
295806f25ae9SGregory Neil Shapiro
295906f25ae9SGregory Neil Shapiro static void
milter_addheader(m,response,rlen,e)2960d0cef73dSGregory Neil Shapiro milter_addheader(m, response, rlen, e)
2961d0cef73dSGregory Neil Shapiro struct milter *m;
296206f25ae9SGregory Neil Shapiro char *response;
296306f25ae9SGregory Neil Shapiro ssize_t rlen;
296406f25ae9SGregory Neil Shapiro ENVELOPE *e;
296506f25ae9SGregory Neil Shapiro {
2966d0cef73dSGregory Neil Shapiro int mh_v_len;
2967d0cef73dSGregory Neil Shapiro char *val, *mh_value;
2968193538b7SGregory Neil Shapiro HDR *h;
296906f25ae9SGregory Neil Shapiro
297006f25ae9SGregory Neil Shapiro if (tTd(64, 10))
297140266059SGregory Neil Shapiro sm_dprintf("milter_addheader: ");
297206f25ae9SGregory Neil Shapiro
297306f25ae9SGregory Neil Shapiro /* sanity checks */
297406f25ae9SGregory Neil Shapiro if (response == NULL)
297506f25ae9SGregory Neil Shapiro {
297606f25ae9SGregory Neil Shapiro if (tTd(64, 10))
297740266059SGregory Neil Shapiro sm_dprintf("NULL response\n");
297806f25ae9SGregory Neil Shapiro return;
297906f25ae9SGregory Neil Shapiro }
298006f25ae9SGregory Neil Shapiro
298106f25ae9SGregory Neil Shapiro if (rlen < 2 || strlen(response) + 1 >= (size_t) rlen)
298206f25ae9SGregory Neil Shapiro {
298306f25ae9SGregory Neil Shapiro if (tTd(64, 10))
2984d0cef73dSGregory Neil Shapiro sm_dprintf("didn't follow protocol (total len %d != rlen %d)\n",
2985d0cef73dSGregory Neil Shapiro (int) strlen(response), (int) (rlen - 1));
298606f25ae9SGregory Neil Shapiro return;
298706f25ae9SGregory Neil Shapiro }
298806f25ae9SGregory Neil Shapiro
298906f25ae9SGregory Neil Shapiro /* Find separating NUL */
299006f25ae9SGregory Neil Shapiro val = response + strlen(response) + 1;
299106f25ae9SGregory Neil Shapiro
299206f25ae9SGregory Neil Shapiro /* another sanity check */
299306f25ae9SGregory Neil Shapiro if (strlen(response) + strlen(val) + 2 != (size_t) rlen)
299406f25ae9SGregory Neil Shapiro {
299506f25ae9SGregory Neil Shapiro if (tTd(64, 10))
299640266059SGregory Neil Shapiro sm_dprintf("didn't follow protocol (part len)\n");
299706f25ae9SGregory Neil Shapiro return;
299806f25ae9SGregory Neil Shapiro }
299906f25ae9SGregory Neil Shapiro
300006f25ae9SGregory Neil Shapiro if (*response == '\0')
300106f25ae9SGregory Neil Shapiro {
300206f25ae9SGregory Neil Shapiro if (tTd(64, 10))
300340266059SGregory Neil Shapiro sm_dprintf("empty field name\n");
300406f25ae9SGregory Neil Shapiro return;
300506f25ae9SGregory Neil Shapiro }
300606f25ae9SGregory Neil Shapiro
3007193538b7SGregory Neil Shapiro for (h = e->e_header; h != NULL; h = h->h_link)
3008193538b7SGregory Neil Shapiro {
30092fb4f839SGregory Neil Shapiro if (SM_STRCASEEQ(h->h_field, response) &&
3010193538b7SGregory Neil Shapiro !bitset(H_USER, h->h_flags) &&
3011193538b7SGregory Neil Shapiro !bitset(H_TRACE, h->h_flags))
3012193538b7SGregory Neil Shapiro break;
3013193538b7SGregory Neil Shapiro }
3014193538b7SGregory Neil Shapiro
3015d0cef73dSGregory Neil Shapiro mh_v_len = 0;
30162fb4f839SGregory Neil Shapiro mh_value = quote_internal_chars(val, NULL, &mh_v_len, NULL);
3017d0cef73dSGregory Neil Shapiro
301806f25ae9SGregory Neil Shapiro /* add to e_msgsize */
301906f25ae9SGregory Neil Shapiro e->e_msgsize += strlen(response) + 2 + strlen(val);
302006f25ae9SGregory Neil Shapiro
3021193538b7SGregory Neil Shapiro if (h != NULL)
3022193538b7SGregory Neil Shapiro {
3023193538b7SGregory Neil Shapiro if (tTd(64, 10))
302440266059SGregory Neil Shapiro sm_dprintf("Replace default header %s value with %s\n",
3025d0cef73dSGregory Neil Shapiro h->h_field, mh_value);
302640266059SGregory Neil Shapiro if (MilterLogLevel > 8)
302740266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
30285b0945b5SGregory Neil Shapiro "Milter (%s) change: default header %s value with %s",
30295b0945b5SGregory Neil Shapiro m->mf_name, h->h_field, mh_value);
3030d0cef73dSGregory Neil Shapiro if (bitset(SMFIP_HDR_LEADSPC, m->mf_pflags))
30312fb4f839SGregory Neil Shapiro h->h_value = mh_value; /* XXX must be allocated from rpool? */
3032d0cef73dSGregory Neil Shapiro else
3033d0cef73dSGregory Neil Shapiro {
3034d0cef73dSGregory Neil Shapiro h->h_value = addleadingspace(mh_value, e->e_rpool);
3035d0cef73dSGregory Neil Shapiro SM_FREE(mh_value);
3036d0cef73dSGregory Neil Shapiro }
3037193538b7SGregory Neil Shapiro h->h_flags |= H_USER;
3038193538b7SGregory Neil Shapiro }
3039193538b7SGregory Neil Shapiro else
3040193538b7SGregory Neil Shapiro {
304106f25ae9SGregory Neil Shapiro if (tTd(64, 10))
3042d0cef73dSGregory Neil Shapiro sm_dprintf("Add %s: %s\n", response, mh_value);
304340266059SGregory Neil Shapiro if (MilterLogLevel > 8)
3044d0cef73dSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
30455b0945b5SGregory Neil Shapiro "Milter (%s) add: header: %s: %s",
30465b0945b5SGregory Neil Shapiro m->mf_name, response, mh_value);
3047d0cef73dSGregory Neil Shapiro addheader(newstr(response), mh_value, H_USER, e,
3048d0cef73dSGregory Neil Shapiro !bitset(SMFIP_HDR_LEADSPC, m->mf_pflags));
3049d0cef73dSGregory Neil Shapiro SM_FREE(mh_value);
305006f25ae9SGregory Neil Shapiro }
3051193538b7SGregory Neil Shapiro }
3052d0cef73dSGregory Neil Shapiro
305340266059SGregory Neil Shapiro /*
3054e92d3f3fSGregory Neil Shapiro ** MILTER_INSHEADER -- Insert the supplied header
3055e92d3f3fSGregory Neil Shapiro **
3056e92d3f3fSGregory Neil Shapiro ** Parameters:
3057d0cef73dSGregory Neil Shapiro ** m -- current filter.
3058e92d3f3fSGregory Neil Shapiro ** response -- encoded form of header/value.
3059e92d3f3fSGregory Neil Shapiro ** rlen -- length of response.
3060e92d3f3fSGregory Neil Shapiro ** e -- current envelope.
3061e92d3f3fSGregory Neil Shapiro **
3062e92d3f3fSGregory Neil Shapiro ** Returns:
3063e92d3f3fSGregory Neil Shapiro ** none
3064e92d3f3fSGregory Neil Shapiro **
3065e92d3f3fSGregory Neil Shapiro ** Notes:
3066e92d3f3fSGregory Neil Shapiro ** Unlike milter_addheader(), this does not attempt to determine
3067e92d3f3fSGregory Neil Shapiro ** if the header already exists in the envelope, even a
3068e92d3f3fSGregory Neil Shapiro ** deleted version. It just blindly inserts.
3069e92d3f3fSGregory Neil Shapiro */
3070e92d3f3fSGregory Neil Shapiro
3071e92d3f3fSGregory Neil Shapiro static void
milter_insheader(m,response,rlen,e)3072d0cef73dSGregory Neil Shapiro milter_insheader(m, response, rlen, e)
3073d0cef73dSGregory Neil Shapiro struct milter *m;
3074e92d3f3fSGregory Neil Shapiro char *response;
3075e92d3f3fSGregory Neil Shapiro ssize_t rlen;
3076e92d3f3fSGregory Neil Shapiro ENVELOPE *e;
3077e92d3f3fSGregory Neil Shapiro {
3078e92d3f3fSGregory Neil Shapiro mi_int32 idx, i;
3079d0cef73dSGregory Neil Shapiro int mh_v_len;
3080d0cef73dSGregory Neil Shapiro char *field, *val, *mh_value;
3081e92d3f3fSGregory Neil Shapiro
3082e92d3f3fSGregory Neil Shapiro if (tTd(64, 10))
3083e92d3f3fSGregory Neil Shapiro sm_dprintf("milter_insheader: ");
3084e92d3f3fSGregory Neil Shapiro
3085e92d3f3fSGregory Neil Shapiro /* sanity checks */
3086e92d3f3fSGregory Neil Shapiro if (response == NULL)
3087e92d3f3fSGregory Neil Shapiro {
3088e92d3f3fSGregory Neil Shapiro if (tTd(64, 10))
3089e92d3f3fSGregory Neil Shapiro sm_dprintf("NULL response\n");
3090e92d3f3fSGregory Neil Shapiro return;
3091e92d3f3fSGregory Neil Shapiro }
3092e92d3f3fSGregory Neil Shapiro
3093e92d3f3fSGregory Neil Shapiro if (rlen < 2 || strlen(response) + 1 >= (size_t) rlen)
3094e92d3f3fSGregory Neil Shapiro {
3095e92d3f3fSGregory Neil Shapiro if (tTd(64, 10))
3096e92d3f3fSGregory Neil Shapiro sm_dprintf("didn't follow protocol (total len)\n");
3097e92d3f3fSGregory Neil Shapiro return;
3098e92d3f3fSGregory Neil Shapiro }
3099e92d3f3fSGregory Neil Shapiro
3100e92d3f3fSGregory Neil Shapiro /* decode */
3101e92d3f3fSGregory Neil Shapiro (void) memcpy((char *) &i, response, MILTER_LEN_BYTES);
3102e92d3f3fSGregory Neil Shapiro idx = ntohl(i);
3103e92d3f3fSGregory Neil Shapiro field = response + MILTER_LEN_BYTES;
3104e92d3f3fSGregory Neil Shapiro val = field + strlen(field) + 1;
3105e92d3f3fSGregory Neil Shapiro
3106e92d3f3fSGregory Neil Shapiro /* another sanity check */
3107e92d3f3fSGregory Neil Shapiro if (MILTER_LEN_BYTES + strlen(field) + 1 +
3108e92d3f3fSGregory Neil Shapiro strlen(val) + 1 != (size_t) rlen)
3109e92d3f3fSGregory Neil Shapiro {
3110e92d3f3fSGregory Neil Shapiro if (tTd(64, 10))
3111e92d3f3fSGregory Neil Shapiro sm_dprintf("didn't follow protocol (part len)\n");
3112e92d3f3fSGregory Neil Shapiro return;
3113e92d3f3fSGregory Neil Shapiro }
3114e92d3f3fSGregory Neil Shapiro
3115e92d3f3fSGregory Neil Shapiro if (*field == '\0')
3116e92d3f3fSGregory Neil Shapiro {
3117e92d3f3fSGregory Neil Shapiro if (tTd(64, 10))
3118e92d3f3fSGregory Neil Shapiro sm_dprintf("empty field name\n");
3119e92d3f3fSGregory Neil Shapiro return;
3120e92d3f3fSGregory Neil Shapiro }
3121e92d3f3fSGregory Neil Shapiro
3122e92d3f3fSGregory Neil Shapiro /* add to e_msgsize */
3123e92d3f3fSGregory Neil Shapiro e->e_msgsize += strlen(response) + 2 + strlen(val);
3124e92d3f3fSGregory Neil Shapiro
3125e92d3f3fSGregory Neil Shapiro if (tTd(64, 10))
3126d0cef73dSGregory Neil Shapiro sm_dprintf("Insert (%d) %s: %s\n", idx, field, val);
3127e92d3f3fSGregory Neil Shapiro if (MilterLogLevel > 8)
3128e92d3f3fSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
31295b0945b5SGregory Neil Shapiro "Milter (%s) insert (%d): header: %s: %s",
31305b0945b5SGregory Neil Shapiro m->mf_name, idx, field, val);
3131d0cef73dSGregory Neil Shapiro mh_v_len = 0;
31322fb4f839SGregory Neil Shapiro mh_value = quote_internal_chars(val, NULL, &mh_v_len, NULL);
3133d0cef73dSGregory Neil Shapiro insheader(idx, newstr(field), mh_value, H_USER, e,
3134d0cef73dSGregory Neil Shapiro !bitset(SMFIP_HDR_LEADSPC, m->mf_pflags));
3135d0cef73dSGregory Neil Shapiro SM_FREE(mh_value);
3136e92d3f3fSGregory Neil Shapiro }
3137d0cef73dSGregory Neil Shapiro
3138e92d3f3fSGregory Neil Shapiro /*
313906f25ae9SGregory Neil Shapiro ** MILTER_CHANGEHEADER -- Change the supplied header in the message
314006f25ae9SGregory Neil Shapiro **
314106f25ae9SGregory Neil Shapiro ** Parameters:
3142d0cef73dSGregory Neil Shapiro ** m -- current filter.
314306f25ae9SGregory Neil Shapiro ** response -- encoded form of header/index/value.
314406f25ae9SGregory Neil Shapiro ** rlen -- length of response.
314506f25ae9SGregory Neil Shapiro ** e -- current envelope.
314606f25ae9SGregory Neil Shapiro **
314706f25ae9SGregory Neil Shapiro ** Returns:
314806f25ae9SGregory Neil Shapiro ** none
314906f25ae9SGregory Neil Shapiro */
315006f25ae9SGregory Neil Shapiro
315106f25ae9SGregory Neil Shapiro static void
milter_changeheader(m,response,rlen,e)3152d0cef73dSGregory Neil Shapiro milter_changeheader(m, response, rlen, e)
3153d0cef73dSGregory Neil Shapiro struct milter *m;
315406f25ae9SGregory Neil Shapiro char *response;
315506f25ae9SGregory Neil Shapiro ssize_t rlen;
315606f25ae9SGregory Neil Shapiro ENVELOPE *e;
315706f25ae9SGregory Neil Shapiro {
315806f25ae9SGregory Neil Shapiro mi_int32 i, index;
3159d0cef73dSGregory Neil Shapiro int mh_v_len;
3160d0cef73dSGregory Neil Shapiro char *field, *val, *mh_value;
3161193538b7SGregory Neil Shapiro HDR *h, *sysheader;
316206f25ae9SGregory Neil Shapiro
316306f25ae9SGregory Neil Shapiro if (tTd(64, 10))
316440266059SGregory Neil Shapiro sm_dprintf("milter_changeheader: ");
316506f25ae9SGregory Neil Shapiro
316606f25ae9SGregory Neil Shapiro /* sanity checks */
316706f25ae9SGregory Neil Shapiro if (response == NULL)
316806f25ae9SGregory Neil Shapiro {
316906f25ae9SGregory Neil Shapiro if (tTd(64, 10))
317040266059SGregory Neil Shapiro sm_dprintf("NULL response\n");
317106f25ae9SGregory Neil Shapiro return;
317206f25ae9SGregory Neil Shapiro }
317306f25ae9SGregory Neil Shapiro
317406f25ae9SGregory Neil Shapiro if (rlen < 2 || strlen(response) + 1 >= (size_t) rlen)
317506f25ae9SGregory Neil Shapiro {
317606f25ae9SGregory Neil Shapiro if (tTd(64, 10))
317740266059SGregory Neil Shapiro sm_dprintf("didn't follow protocol (total len)\n");
317806f25ae9SGregory Neil Shapiro return;
317906f25ae9SGregory Neil Shapiro }
318006f25ae9SGregory Neil Shapiro
318106f25ae9SGregory Neil Shapiro /* Find separating NUL */
318206f25ae9SGregory Neil Shapiro (void) memcpy((char *) &i, response, MILTER_LEN_BYTES);
318306f25ae9SGregory Neil Shapiro index = ntohl(i);
318406f25ae9SGregory Neil Shapiro field = response + MILTER_LEN_BYTES;
318506f25ae9SGregory Neil Shapiro val = field + strlen(field) + 1;
318606f25ae9SGregory Neil Shapiro
318706f25ae9SGregory Neil Shapiro /* another sanity check */
318806f25ae9SGregory Neil Shapiro if (MILTER_LEN_BYTES + strlen(field) + 1 +
318906f25ae9SGregory Neil Shapiro strlen(val) + 1 != (size_t) rlen)
319006f25ae9SGregory Neil Shapiro {
319106f25ae9SGregory Neil Shapiro if (tTd(64, 10))
319240266059SGregory Neil Shapiro sm_dprintf("didn't follow protocol (part len)\n");
319306f25ae9SGregory Neil Shapiro return;
319406f25ae9SGregory Neil Shapiro }
319506f25ae9SGregory Neil Shapiro
319606f25ae9SGregory Neil Shapiro if (*field == '\0')
319706f25ae9SGregory Neil Shapiro {
319806f25ae9SGregory Neil Shapiro if (tTd(64, 10))
319940266059SGregory Neil Shapiro sm_dprintf("empty field name\n");
320006f25ae9SGregory Neil Shapiro return;
320106f25ae9SGregory Neil Shapiro }
320206f25ae9SGregory Neil Shapiro
3203d0cef73dSGregory Neil Shapiro mh_v_len = 0;
32042fb4f839SGregory Neil Shapiro mh_value = quote_internal_chars(val, NULL, &mh_v_len, NULL);
3205d0cef73dSGregory Neil Shapiro
3206193538b7SGregory Neil Shapiro sysheader = NULL;
320706f25ae9SGregory Neil Shapiro for (h = e->e_header; h != NULL; h = h->h_link)
320806f25ae9SGregory Neil Shapiro {
32092fb4f839SGregory Neil Shapiro if (SM_STRCASEEQ(h->h_field, field))
3210193538b7SGregory Neil Shapiro {
3211d0cef73dSGregory Neil Shapiro if (bitset(H_USER, h->h_flags) && --index <= 0)
3212193538b7SGregory Neil Shapiro {
3213193538b7SGregory Neil Shapiro sysheader = NULL;
321406f25ae9SGregory Neil Shapiro break;
321506f25ae9SGregory Neil Shapiro }
3216193538b7SGregory Neil Shapiro else if (!bitset(H_USER, h->h_flags) &&
3217193538b7SGregory Neil Shapiro !bitset(H_TRACE, h->h_flags))
3218193538b7SGregory Neil Shapiro {
3219193538b7SGregory Neil Shapiro /*
32205b0945b5SGregory Neil Shapiro ** RFC 2822:
32215b0945b5SGregory Neil Shapiro ** 27. No multiple occurrences of fields
32225b0945b5SGregory Neil Shapiro ** (except resent and received).*
3223193538b7SGregory Neil Shapiro ** so make sure we replace any non-trace,
3224193538b7SGregory Neil Shapiro ** non-user field.
3225193538b7SGregory Neil Shapiro */
3226193538b7SGregory Neil Shapiro
3227193538b7SGregory Neil Shapiro sysheader = h;
3228193538b7SGregory Neil Shapiro }
3229193538b7SGregory Neil Shapiro }
3230193538b7SGregory Neil Shapiro }
3231193538b7SGregory Neil Shapiro
3232193538b7SGregory Neil Shapiro /* if not found as user-provided header at index, use sysheader */
3233193538b7SGregory Neil Shapiro if (h == NULL)
3234193538b7SGregory Neil Shapiro h = sysheader;
323506f25ae9SGregory Neil Shapiro
323606f25ae9SGregory Neil Shapiro if (h == NULL)
323706f25ae9SGregory Neil Shapiro {
323806f25ae9SGregory Neil Shapiro if (*val == '\0')
323906f25ae9SGregory Neil Shapiro {
324006f25ae9SGregory Neil Shapiro if (tTd(64, 10))
3241b6bacd31SGregory Neil Shapiro sm_dprintf("Delete (noop) %s\n", field);
3242b6bacd31SGregory Neil Shapiro if (MilterLogLevel > 8)
3243b6bacd31SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
32445b0945b5SGregory Neil Shapiro "Milter (%s) delete (noop): header: %s"
32455b0945b5SGregory Neil Shapiro , m->mf_name, field);
324606f25ae9SGregory Neil Shapiro }
324706f25ae9SGregory Neil Shapiro else
324806f25ae9SGregory Neil Shapiro {
324906f25ae9SGregory Neil Shapiro /* treat modify value with no existing header as add */
325006f25ae9SGregory Neil Shapiro if (tTd(64, 10))
3251d0cef73dSGregory Neil Shapiro sm_dprintf("Add %s: %s\n", field, mh_value);
3252b6bacd31SGregory Neil Shapiro if (MilterLogLevel > 8)
3253b6bacd31SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
32545b0945b5SGregory Neil Shapiro "Milter (%s) change (add): header: %s: %s"
32555b0945b5SGregory Neil Shapiro , m->mf_name, field, mh_value);
3256d0cef73dSGregory Neil Shapiro addheader(newstr(field), mh_value, H_USER, e,
3257d0cef73dSGregory Neil Shapiro !bitset(SMFIP_HDR_LEADSPC, m->mf_pflags));
325806f25ae9SGregory Neil Shapiro }
32595b0945b5SGregory Neil Shapiro SM_FREE(mh_value);
326006f25ae9SGregory Neil Shapiro return;
326106f25ae9SGregory Neil Shapiro }
326206f25ae9SGregory Neil Shapiro
326306f25ae9SGregory Neil Shapiro if (tTd(64, 10))
326406f25ae9SGregory Neil Shapiro {
326506f25ae9SGregory Neil Shapiro if (*val == '\0')
326606f25ae9SGregory Neil Shapiro {
326740266059SGregory Neil Shapiro sm_dprintf("Delete%s %s:%s\n",
3268193538b7SGregory Neil Shapiro h == sysheader ? " (default header)" : "",
3269193538b7SGregory Neil Shapiro field,
327006f25ae9SGregory Neil Shapiro h->h_value == NULL ? "<NULL>" : h->h_value);
327106f25ae9SGregory Neil Shapiro }
327206f25ae9SGregory Neil Shapiro else
327306f25ae9SGregory Neil Shapiro {
327440266059SGregory Neil Shapiro sm_dprintf("Change%s %s: from %s to %s\n",
327540266059SGregory Neil Shapiro h == sysheader ? " (default header)" : "",
327640266059SGregory Neil Shapiro field,
327740266059SGregory Neil Shapiro h->h_value == NULL ? "<NULL>" : h->h_value,
3278d0cef73dSGregory Neil Shapiro mh_value);
327940266059SGregory Neil Shapiro }
328040266059SGregory Neil Shapiro }
328140266059SGregory Neil Shapiro
328240266059SGregory Neil Shapiro if (MilterLogLevel > 8)
328340266059SGregory Neil Shapiro {
328440266059SGregory Neil Shapiro if (*val == '\0')
328540266059SGregory Neil Shapiro {
328640266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
32875b0945b5SGregory Neil Shapiro "Milter (%s) delete: header%s %s:%s",
32885b0945b5SGregory Neil Shapiro m->mf_name,
328940266059SGregory Neil Shapiro h == sysheader ? " (default header)" : "",
329040266059SGregory Neil Shapiro field,
329140266059SGregory Neil Shapiro h->h_value == NULL ? "<NULL>" : h->h_value);
329240266059SGregory Neil Shapiro }
329340266059SGregory Neil Shapiro else
329440266059SGregory Neil Shapiro {
329540266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
32965b0945b5SGregory Neil Shapiro "Milter (%s) change: header%s %s: from %s to %s",
32975b0945b5SGregory Neil Shapiro m->mf_name,
3298193538b7SGregory Neil Shapiro h == sysheader ? " (default header)" : "",
329906f25ae9SGregory Neil Shapiro field,
330006f25ae9SGregory Neil Shapiro h->h_value == NULL ? "<NULL>" : h->h_value,
3301d0cef73dSGregory Neil Shapiro mh_value);
330206f25ae9SGregory Neil Shapiro }
330306f25ae9SGregory Neil Shapiro }
330406f25ae9SGregory Neil Shapiro
3305193538b7SGregory Neil Shapiro if (h != sysheader && h->h_value != NULL)
330606f25ae9SGregory Neil Shapiro {
330740266059SGregory Neil Shapiro size_t l;
330840266059SGregory Neil Shapiro
330940266059SGregory Neil Shapiro l = strlen(h->h_value);
331040266059SGregory Neil Shapiro if (l > e->e_msgsize)
331140266059SGregory Neil Shapiro e->e_msgsize = 0;
331240266059SGregory Neil Shapiro else
331340266059SGregory Neil Shapiro e->e_msgsize -= l;
331440266059SGregory Neil Shapiro /* rpool, don't free: sm_free(h->h_value); XXX */
331506f25ae9SGregory Neil Shapiro }
331606f25ae9SGregory Neil Shapiro
331706f25ae9SGregory Neil Shapiro if (*val == '\0')
331806f25ae9SGregory Neil Shapiro {
331906f25ae9SGregory Neil Shapiro /* Remove "Field: " from message size */
3320193538b7SGregory Neil Shapiro if (h != sysheader)
332140266059SGregory Neil Shapiro {
332240266059SGregory Neil Shapiro size_t l;
332340266059SGregory Neil Shapiro
332440266059SGregory Neil Shapiro l = strlen(h->h_field) + 2;
332540266059SGregory Neil Shapiro if (l > e->e_msgsize)
332640266059SGregory Neil Shapiro e->e_msgsize = 0;
332740266059SGregory Neil Shapiro else
332840266059SGregory Neil Shapiro e->e_msgsize -= l;
332940266059SGregory Neil Shapiro }
333006f25ae9SGregory Neil Shapiro h->h_value = NULL;
3331d0cef73dSGregory Neil Shapiro SM_FREE(mh_value);
333206f25ae9SGregory Neil Shapiro }
333306f25ae9SGregory Neil Shapiro else
333406f25ae9SGregory Neil Shapiro {
3335d0cef73dSGregory Neil Shapiro if (bitset(SMFIP_HDR_LEADSPC, m->mf_pflags))
33362fb4f839SGregory Neil Shapiro h->h_value = mh_value; /* XXX must be allocated from rpool? */
3337d0cef73dSGregory Neil Shapiro else
3338d0cef73dSGregory Neil Shapiro {
3339d0cef73dSGregory Neil Shapiro h->h_value = addleadingspace(mh_value, e->e_rpool);
3340d0cef73dSGregory Neil Shapiro SM_FREE(mh_value);
3341d0cef73dSGregory Neil Shapiro }
3342193538b7SGregory Neil Shapiro h->h_flags |= H_USER;
334306f25ae9SGregory Neil Shapiro e->e_msgsize += strlen(h->h_value);
334406f25ae9SGregory Neil Shapiro }
334506f25ae9SGregory Neil Shapiro }
3346d0cef73dSGregory Neil Shapiro
3347d0cef73dSGregory Neil Shapiro /*
3348d0cef73dSGregory Neil Shapiro ** MILTER_SPLIT_RESPONSE -- Split response into fields.
3349d0cef73dSGregory Neil Shapiro **
3350d0cef73dSGregory Neil Shapiro ** Parameters:
3351*d39bd2c1SGregory Neil Shapiro ** response -- encoded response.
3352d0cef73dSGregory Neil Shapiro ** rlen -- length of response.
3353*d39bd2c1SGregory Neil Shapiro ** pargc -- number of arguments (output)
3354d0cef73dSGregory Neil Shapiro **
3355d0cef73dSGregory Neil Shapiro ** Returns:
3356d0cef73dSGregory Neil Shapiro ** array of pointers to the individual strings
3357d0cef73dSGregory Neil Shapiro */
3358d0cef73dSGregory Neil Shapiro
3359d0cef73dSGregory Neil Shapiro static char **milter_split_response __P((char *, ssize_t, int *));
3360d0cef73dSGregory Neil Shapiro
3361d0cef73dSGregory Neil Shapiro static char **
milter_split_response(response,rlen,pargc)3362d0cef73dSGregory Neil Shapiro milter_split_response(response, rlen, pargc)
3363d0cef73dSGregory Neil Shapiro char *response;
3364d0cef73dSGregory Neil Shapiro ssize_t rlen;
3365d0cef73dSGregory Neil Shapiro int *pargc;
3366d0cef73dSGregory Neil Shapiro {
3367d0cef73dSGregory Neil Shapiro char **s;
3368d0cef73dSGregory Neil Shapiro size_t i;
3369d0cef73dSGregory Neil Shapiro int elem, nelem;
3370d0cef73dSGregory Neil Shapiro
3371d0cef73dSGregory Neil Shapiro SM_ASSERT(response != NULL);
3372d0cef73dSGregory Neil Shapiro SM_ASSERT(pargc != NULL);
3373d0cef73dSGregory Neil Shapiro *pargc = 0;
3374d0cef73dSGregory Neil Shapiro if (rlen < 2 || strlen(response) >= (size_t) rlen)
3375d0cef73dSGregory Neil Shapiro {
3376d0cef73dSGregory Neil Shapiro if (tTd(64, 10))
3377d0cef73dSGregory Neil Shapiro sm_dprintf("didn't follow protocol (total len %d != rlen %d)\n",
3378d0cef73dSGregory Neil Shapiro (int) strlen(response), (int) (rlen - 1));
3379d0cef73dSGregory Neil Shapiro return NULL;
3380d0cef73dSGregory Neil Shapiro }
3381d0cef73dSGregory Neil Shapiro
3382d0cef73dSGregory Neil Shapiro nelem = 0;
3383d0cef73dSGregory Neil Shapiro for (i = 0; i < rlen; i++)
3384d0cef73dSGregory Neil Shapiro {
3385d0cef73dSGregory Neil Shapiro if (response[i] == '\0')
3386d0cef73dSGregory Neil Shapiro ++nelem;
3387d0cef73dSGregory Neil Shapiro }
3388d0cef73dSGregory Neil Shapiro if (nelem == 0)
3389d0cef73dSGregory Neil Shapiro return NULL;
3390d0cef73dSGregory Neil Shapiro
3391d0cef73dSGregory Neil Shapiro /* last entry is only for the name */
33929bd497b8SGregory Neil Shapiro s = (char **)malloc((nelem + 1) * (sizeof(*s)));
3393d0cef73dSGregory Neil Shapiro if (s == NULL)
3394d0cef73dSGregory Neil Shapiro return NULL;
3395d0cef73dSGregory Neil Shapiro s[0] = response;
3396d0cef73dSGregory Neil Shapiro for (i = 0, elem = 0; i < rlen && elem < nelem; i++)
3397d0cef73dSGregory Neil Shapiro {
3398d0cef73dSGregory Neil Shapiro if (response[i] == '\0')
3399d0cef73dSGregory Neil Shapiro {
3400d0cef73dSGregory Neil Shapiro ++elem;
3401d0cef73dSGregory Neil Shapiro if (i + 1 >= rlen)
3402d0cef73dSGregory Neil Shapiro s[elem] = NULL;
3403d0cef73dSGregory Neil Shapiro else
3404d0cef73dSGregory Neil Shapiro s[elem] = &(response[i + 1]);
3405d0cef73dSGregory Neil Shapiro }
3406d0cef73dSGregory Neil Shapiro }
3407d0cef73dSGregory Neil Shapiro *pargc = nelem;
3408d0cef73dSGregory Neil Shapiro
3409d0cef73dSGregory Neil Shapiro if (tTd(64, 10))
3410d0cef73dSGregory Neil Shapiro {
3411d0cef73dSGregory Neil Shapiro for (elem = 0; elem < nelem; elem++)
3412d0cef73dSGregory Neil Shapiro sm_dprintf("argv[%d]=\"%s\"\n", elem, s[elem]);
3413d0cef73dSGregory Neil Shapiro }
3414d0cef73dSGregory Neil Shapiro
3415d0cef73dSGregory Neil Shapiro /* overwrite last entry (already done above, just paranoia) */
3416d0cef73dSGregory Neil Shapiro s[elem] = NULL;
3417d0cef73dSGregory Neil Shapiro return s;
3418d0cef73dSGregory Neil Shapiro }
3419d0cef73dSGregory Neil Shapiro
3420d0cef73dSGregory Neil Shapiro /*
3421d0cef73dSGregory Neil Shapiro ** MILTER_CHGFROM -- Change the envelope sender address
3422d0cef73dSGregory Neil Shapiro **
3423d0cef73dSGregory Neil Shapiro ** Parameters:
3424d0cef73dSGregory Neil Shapiro ** response -- encoded form of recipient address.
3425d0cef73dSGregory Neil Shapiro ** rlen -- length of response.
3426d0cef73dSGregory Neil Shapiro ** e -- current envelope.
34275b0945b5SGregory Neil Shapiro ** mname -- name of milter.
3428d0cef73dSGregory Neil Shapiro **
3429d0cef73dSGregory Neil Shapiro ** Returns:
3430d0cef73dSGregory Neil Shapiro ** none
3431d0cef73dSGregory Neil Shapiro */
3432d0cef73dSGregory Neil Shapiro
3433d0cef73dSGregory Neil Shapiro static void
milter_chgfrom(response,rlen,e,mname)34345b0945b5SGregory Neil Shapiro milter_chgfrom(response, rlen, e, mname)
3435d0cef73dSGregory Neil Shapiro char *response;
3436d0cef73dSGregory Neil Shapiro ssize_t rlen;
3437d0cef73dSGregory Neil Shapiro ENVELOPE *e;
34385b0945b5SGregory Neil Shapiro const char *mname;
3439d0cef73dSGregory Neil Shapiro {
3440d0cef73dSGregory Neil Shapiro int olderrors, argc;
3441d0cef73dSGregory Neil Shapiro char **argv;
3442d0cef73dSGregory Neil Shapiro
3443d0cef73dSGregory Neil Shapiro if (tTd(64, 10))
3444d0cef73dSGregory Neil Shapiro sm_dprintf("milter_chgfrom: ");
3445d0cef73dSGregory Neil Shapiro
3446d0cef73dSGregory Neil Shapiro /* sanity checks */
3447d0cef73dSGregory Neil Shapiro if (response == NULL)
3448d0cef73dSGregory Neil Shapiro {
3449d0cef73dSGregory Neil Shapiro if (tTd(64, 10))
3450d0cef73dSGregory Neil Shapiro sm_dprintf("NULL response\n");
3451d0cef73dSGregory Neil Shapiro return;
3452d0cef73dSGregory Neil Shapiro }
3453d0cef73dSGregory Neil Shapiro
3454d0cef73dSGregory Neil Shapiro if (*response == '\0' ||
3455d0cef73dSGregory Neil Shapiro strlen(response) + 1 > (size_t) rlen)
3456d0cef73dSGregory Neil Shapiro {
3457d0cef73dSGregory Neil Shapiro if (tTd(64, 10))
3458d0cef73dSGregory Neil Shapiro sm_dprintf("didn't follow protocol (total len %d != rlen %d)\n",
3459d0cef73dSGregory Neil Shapiro (int) strlen(response), (int) (rlen - 1));
3460d0cef73dSGregory Neil Shapiro return;
3461d0cef73dSGregory Neil Shapiro }
3462d0cef73dSGregory Neil Shapiro
3463d0cef73dSGregory Neil Shapiro if (tTd(64, 10))
3464d0cef73dSGregory Neil Shapiro sm_dprintf("%s\n", response);
3465d0cef73dSGregory Neil Shapiro if (MilterLogLevel > 8)
34665b0945b5SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter (%s) chgfrom: %s",
34675b0945b5SGregory Neil Shapiro mname, response);
3468d0cef73dSGregory Neil Shapiro argv = milter_split_response(response, rlen, &argc);
3469d0cef73dSGregory Neil Shapiro if (argc < 1 || argc > 2)
3470d0cef73dSGregory Neil Shapiro {
3471d0cef73dSGregory Neil Shapiro if (tTd(64, 10))
3472d0cef73dSGregory Neil Shapiro sm_dprintf("didn't follow protocol argc=%d\n", argc);
34735b0945b5SGregory Neil Shapiro if (argv != NULL)
34745b0945b5SGregory Neil Shapiro free(argv);
3475d0cef73dSGregory Neil Shapiro return;
3476d0cef73dSGregory Neil Shapiro }
3477d0cef73dSGregory Neil Shapiro
3478d0cef73dSGregory Neil Shapiro olderrors = Errors;
3479d0cef73dSGregory Neil Shapiro setsender(argv[0], e, NULL, '\0', false);
3480d0cef73dSGregory Neil Shapiro if (argc == 2)
3481d0cef73dSGregory Neil Shapiro {
3482d0cef73dSGregory Neil Shapiro reset_mail_esmtp_args(e);
3483d0cef73dSGregory Neil Shapiro
3484d0cef73dSGregory Neil Shapiro /*
3485d0cef73dSGregory Neil Shapiro ** need "features" here: how to get those? via e?
3486d0cef73dSGregory Neil Shapiro ** "fake" it for now: allow everything.
3487d0cef73dSGregory Neil Shapiro */
3488d0cef73dSGregory Neil Shapiro
3489d0cef73dSGregory Neil Shapiro parse_esmtp_args(e, NULL, argv[0], argv[1], "MAIL", NULL,
3490d0cef73dSGregory Neil Shapiro mail_esmtp_args);
3491d0cef73dSGregory Neil Shapiro }
3492d0cef73dSGregory Neil Shapiro Errors = olderrors;
34935b0945b5SGregory Neil Shapiro free(argv);
3494d0cef73dSGregory Neil Shapiro return;
3495d0cef73dSGregory Neil Shapiro }
3496d0cef73dSGregory Neil Shapiro
3497d0cef73dSGregory Neil Shapiro /*
3498d0cef73dSGregory Neil Shapiro ** MILTER_ADDRCPT_PAR -- Add the supplied recipient to the message
3499d0cef73dSGregory Neil Shapiro **
3500d0cef73dSGregory Neil Shapiro ** Parameters:
3501d0cef73dSGregory Neil Shapiro ** response -- encoded form of recipient address.
3502d0cef73dSGregory Neil Shapiro ** rlen -- length of response.
3503d0cef73dSGregory Neil Shapiro ** e -- current envelope.
35045b0945b5SGregory Neil Shapiro ** mname -- name of milter.
3505d0cef73dSGregory Neil Shapiro **
3506d0cef73dSGregory Neil Shapiro ** Returns:
3507d0cef73dSGregory Neil Shapiro ** none
3508d0cef73dSGregory Neil Shapiro */
3509d0cef73dSGregory Neil Shapiro
3510d0cef73dSGregory Neil Shapiro static void
milter_addrcpt_par(response,rlen,e,mname)35115b0945b5SGregory Neil Shapiro milter_addrcpt_par(response, rlen, e, mname)
3512d0cef73dSGregory Neil Shapiro char *response;
3513d0cef73dSGregory Neil Shapiro ssize_t rlen;
3514d0cef73dSGregory Neil Shapiro ENVELOPE *e;
35155b0945b5SGregory Neil Shapiro const char *mname;
3516d0cef73dSGregory Neil Shapiro {
3517d0cef73dSGregory Neil Shapiro int olderrors, argc;
3518d0cef73dSGregory Neil Shapiro char *delimptr;
3519d0cef73dSGregory Neil Shapiro char **argv;
3520d0cef73dSGregory Neil Shapiro ADDRESS *a;
3521d0cef73dSGregory Neil Shapiro
3522d0cef73dSGregory Neil Shapiro if (tTd(64, 10))
3523d0cef73dSGregory Neil Shapiro sm_dprintf("milter_addrcpt_par: ");
3524d0cef73dSGregory Neil Shapiro
3525d0cef73dSGregory Neil Shapiro /* sanity checks */
3526d0cef73dSGregory Neil Shapiro if (response == NULL)
3527d0cef73dSGregory Neil Shapiro {
3528d0cef73dSGregory Neil Shapiro if (tTd(64, 10))
3529d0cef73dSGregory Neil Shapiro sm_dprintf("NULL response\n");
3530d0cef73dSGregory Neil Shapiro return;
3531d0cef73dSGregory Neil Shapiro }
3532d0cef73dSGregory Neil Shapiro
3533d0cef73dSGregory Neil Shapiro if (tTd(64, 10))
3534d0cef73dSGregory Neil Shapiro sm_dprintf("%s\n", response);
3535d0cef73dSGregory Neil Shapiro if (MilterLogLevel > 8)
35365b0945b5SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter (%s) add: rcpt: %s",
35375b0945b5SGregory Neil Shapiro mname, response);
3538d0cef73dSGregory Neil Shapiro
3539d0cef73dSGregory Neil Shapiro argv = milter_split_response(response, rlen, &argc);
3540d0cef73dSGregory Neil Shapiro if (argc < 1 || argc > 2)
3541d0cef73dSGregory Neil Shapiro {
3542d0cef73dSGregory Neil Shapiro if (tTd(64, 10))
3543d0cef73dSGregory Neil Shapiro sm_dprintf("didn't follow protocol argc=%d\n", argc);
35445b0945b5SGregory Neil Shapiro if (argv != NULL)
35455b0945b5SGregory Neil Shapiro free(argv);
3546d0cef73dSGregory Neil Shapiro return;
3547d0cef73dSGregory Neil Shapiro }
3548d0cef73dSGregory Neil Shapiro olderrors = Errors;
3549d0cef73dSGregory Neil Shapiro
3550d0cef73dSGregory Neil Shapiro /* how to set ESMTP arguments? */
35512fb4f839SGregory Neil Shapiro /* XXX argv[0] must be [i] */
3552d0cef73dSGregory Neil Shapiro a = parseaddr(argv[0], NULLADDR, RF_COPYALL, ' ', &delimptr, e, true);
3553d0cef73dSGregory Neil Shapiro
3554d0cef73dSGregory Neil Shapiro if (a != NULL && olderrors == Errors)
3555d0cef73dSGregory Neil Shapiro {
3556d0cef73dSGregory Neil Shapiro parse_esmtp_args(e, a, argv[0], argv[1], "RCPT", NULL,
3557d0cef73dSGregory Neil Shapiro rcpt_esmtp_args);
3558d0cef73dSGregory Neil Shapiro if (olderrors == Errors)
3559d0cef73dSGregory Neil Shapiro a = recipient(a, &e->e_sendqueue, 0, e);
3560d0cef73dSGregory Neil Shapiro else
3561d0cef73dSGregory Neil Shapiro sm_dprintf("olderrors=%d, Errors=%d\n",
3562d0cef73dSGregory Neil Shapiro olderrors, Errors);
3563d0cef73dSGregory Neil Shapiro }
3564d0cef73dSGregory Neil Shapiro else
3565d0cef73dSGregory Neil Shapiro {
3566d0cef73dSGregory Neil Shapiro sm_dprintf("a=%p, olderrors=%d, Errors=%d\n",
35675b0945b5SGregory Neil Shapiro (void *)a, olderrors, Errors);
3568d0cef73dSGregory Neil Shapiro }
3569d0cef73dSGregory Neil Shapiro
3570d0cef73dSGregory Neil Shapiro Errors = olderrors;
35715b0945b5SGregory Neil Shapiro free(argv);
3572d0cef73dSGregory Neil Shapiro return;
3573d0cef73dSGregory Neil Shapiro }
3574d0cef73dSGregory Neil Shapiro
357540266059SGregory Neil Shapiro /*
357606f25ae9SGregory Neil Shapiro ** MILTER_ADDRCPT -- Add the supplied recipient to the message
357706f25ae9SGregory Neil Shapiro **
357806f25ae9SGregory Neil Shapiro ** Parameters:
357906f25ae9SGregory Neil Shapiro ** response -- encoded form of recipient address.
358006f25ae9SGregory Neil Shapiro ** rlen -- length of response.
358106f25ae9SGregory Neil Shapiro ** e -- current envelope.
35825b0945b5SGregory Neil Shapiro ** mname -- name of milter.
358306f25ae9SGregory Neil Shapiro **
358406f25ae9SGregory Neil Shapiro ** Returns:
358506f25ae9SGregory Neil Shapiro ** none
358606f25ae9SGregory Neil Shapiro */
358706f25ae9SGregory Neil Shapiro
358806f25ae9SGregory Neil Shapiro static void
milter_addrcpt(response,rlen,e,mname)35895b0945b5SGregory Neil Shapiro milter_addrcpt(response, rlen, e, mname)
359006f25ae9SGregory Neil Shapiro char *response;
359106f25ae9SGregory Neil Shapiro ssize_t rlen;
359206f25ae9SGregory Neil Shapiro ENVELOPE *e;
35935b0945b5SGregory Neil Shapiro const char *mname;
359406f25ae9SGregory Neil Shapiro {
3595a7ec597cSGregory Neil Shapiro int olderrors;
3596a7ec597cSGregory Neil Shapiro
359706f25ae9SGregory Neil Shapiro if (tTd(64, 10))
359840266059SGregory Neil Shapiro sm_dprintf("milter_addrcpt: ");
359906f25ae9SGregory Neil Shapiro
360006f25ae9SGregory Neil Shapiro /* sanity checks */
360106f25ae9SGregory Neil Shapiro if (response == NULL)
360206f25ae9SGregory Neil Shapiro {
360306f25ae9SGregory Neil Shapiro if (tTd(64, 10))
360440266059SGregory Neil Shapiro sm_dprintf("NULL response\n");
360506f25ae9SGregory Neil Shapiro return;
360606f25ae9SGregory Neil Shapiro }
360706f25ae9SGregory Neil Shapiro
360806f25ae9SGregory Neil Shapiro if (*response == '\0' ||
360906f25ae9SGregory Neil Shapiro strlen(response) + 1 != (size_t) rlen)
361006f25ae9SGregory Neil Shapiro {
361106f25ae9SGregory Neil Shapiro if (tTd(64, 10))
361240266059SGregory Neil Shapiro sm_dprintf("didn't follow protocol (total len %d != rlen %d)\n",
361340266059SGregory Neil Shapiro (int) strlen(response), (int) (rlen - 1));
361406f25ae9SGregory Neil Shapiro return;
361506f25ae9SGregory Neil Shapiro }
361606f25ae9SGregory Neil Shapiro
361706f25ae9SGregory Neil Shapiro if (tTd(64, 10))
361840266059SGregory Neil Shapiro sm_dprintf("%s\n", response);
361940266059SGregory Neil Shapiro if (MilterLogLevel > 8)
36205b0945b5SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter (%s) add: rcpt: %s",
36215b0945b5SGregory Neil Shapiro mname, response);
3622a7ec597cSGregory Neil Shapiro olderrors = Errors;
362306f25ae9SGregory Neil Shapiro (void) sendtolist(response, NULLADDR, &e->e_sendqueue, 0, e);
3624a7ec597cSGregory Neil Shapiro Errors = olderrors;
362506f25ae9SGregory Neil Shapiro return;
362606f25ae9SGregory Neil Shapiro }
3627d0cef73dSGregory Neil Shapiro
362840266059SGregory Neil Shapiro /*
362906f25ae9SGregory Neil Shapiro ** MILTER_DELRCPT -- Delete the supplied recipient from the message
363006f25ae9SGregory Neil Shapiro **
363106f25ae9SGregory Neil Shapiro ** Parameters:
363206f25ae9SGregory Neil Shapiro ** response -- encoded form of recipient address.
363306f25ae9SGregory Neil Shapiro ** rlen -- length of response.
363406f25ae9SGregory Neil Shapiro ** e -- current envelope.
36355b0945b5SGregory Neil Shapiro ** mname -- name of milter.
363606f25ae9SGregory Neil Shapiro **
363706f25ae9SGregory Neil Shapiro ** Returns:
363806f25ae9SGregory Neil Shapiro ** none
363906f25ae9SGregory Neil Shapiro */
364006f25ae9SGregory Neil Shapiro
364106f25ae9SGregory Neil Shapiro static void
milter_delrcpt(response,rlen,e,mname)36425b0945b5SGregory Neil Shapiro milter_delrcpt(response, rlen, e, mname)
364306f25ae9SGregory Neil Shapiro char *response;
364406f25ae9SGregory Neil Shapiro ssize_t rlen;
364506f25ae9SGregory Neil Shapiro ENVELOPE *e;
36465b0945b5SGregory Neil Shapiro const char *mname;
364706f25ae9SGregory Neil Shapiro {
36485b0945b5SGregory Neil Shapiro int r;
36495b0945b5SGregory Neil Shapiro
365006f25ae9SGregory Neil Shapiro if (tTd(64, 10))
365140266059SGregory Neil Shapiro sm_dprintf("milter_delrcpt: ");
365206f25ae9SGregory Neil Shapiro
365306f25ae9SGregory Neil Shapiro /* sanity checks */
365406f25ae9SGregory Neil Shapiro if (response == NULL)
365506f25ae9SGregory Neil Shapiro {
365606f25ae9SGregory Neil Shapiro if (tTd(64, 10))
365740266059SGregory Neil Shapiro sm_dprintf("NULL response\n");
365806f25ae9SGregory Neil Shapiro return;
365906f25ae9SGregory Neil Shapiro }
366006f25ae9SGregory Neil Shapiro
366106f25ae9SGregory Neil Shapiro if (*response == '\0' ||
366206f25ae9SGregory Neil Shapiro strlen(response) + 1 != (size_t) rlen)
366306f25ae9SGregory Neil Shapiro {
366406f25ae9SGregory Neil Shapiro if (tTd(64, 10))
3665d0cef73dSGregory Neil Shapiro sm_dprintf("didn't follow protocol (total len %d != rlen %d)\n",
3666d0cef73dSGregory Neil Shapiro (int) strlen(response), (int) (rlen - 1));
366706f25ae9SGregory Neil Shapiro return;
366806f25ae9SGregory Neil Shapiro }
366906f25ae9SGregory Neil Shapiro
367006f25ae9SGregory Neil Shapiro if (tTd(64, 10))
367140266059SGregory Neil Shapiro sm_dprintf("%s\n", response);
36725b0945b5SGregory Neil Shapiro r = removefromlist(response, &e->e_sendqueue, e);
367340266059SGregory Neil Shapiro if (MilterLogLevel > 8)
36745b0945b5SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter (%s) delete: rcpt %s, naddrs=%d",
36755b0945b5SGregory Neil Shapiro mname, response, r);
367606f25ae9SGregory Neil Shapiro return;
367706f25ae9SGregory Neil Shapiro }
3678d0cef73dSGregory Neil Shapiro
367940266059SGregory Neil Shapiro /*
368040266059SGregory Neil Shapiro ** MILTER_REPLBODY -- Replace the current data file with new body
368106f25ae9SGregory Neil Shapiro **
368206f25ae9SGregory Neil Shapiro ** Parameters:
368306f25ae9SGregory Neil Shapiro ** response -- encoded form of new body.
368406f25ae9SGregory Neil Shapiro ** rlen -- length of response.
368506f25ae9SGregory Neil Shapiro ** newfilter -- if first time called by a new filter
368606f25ae9SGregory Neil Shapiro ** e -- current envelope.
36875b0945b5SGregory Neil Shapiro ** mname -- name of milter.
368806f25ae9SGregory Neil Shapiro **
368906f25ae9SGregory Neil Shapiro ** Returns:
369006f25ae9SGregory Neil Shapiro ** 0 upon success, -1 upon failure
369106f25ae9SGregory Neil Shapiro */
369206f25ae9SGregory Neil Shapiro
369306f25ae9SGregory Neil Shapiro static int
milter_replbody(response,rlen,newfilter,e,mname)36945b0945b5SGregory Neil Shapiro milter_replbody(response, rlen, newfilter, e, mname)
369506f25ae9SGregory Neil Shapiro char *response;
369606f25ae9SGregory Neil Shapiro ssize_t rlen;
369706f25ae9SGregory Neil Shapiro bool newfilter;
369806f25ae9SGregory Neil Shapiro ENVELOPE *e;
36995b0945b5SGregory Neil Shapiro const char *mname;
370006f25ae9SGregory Neil Shapiro {
370106f25ae9SGregory Neil Shapiro static char prevchar;
370206f25ae9SGregory Neil Shapiro int i;
370306f25ae9SGregory Neil Shapiro
370406f25ae9SGregory Neil Shapiro if (tTd(64, 10))
370540266059SGregory Neil Shapiro sm_dprintf("milter_replbody\n");
370606f25ae9SGregory Neil Shapiro
370740266059SGregory Neil Shapiro /* If a new filter, reset previous character and truncate data file */
370806f25ae9SGregory Neil Shapiro if (newfilter)
370906f25ae9SGregory Neil Shapiro {
3710605302a5SGregory Neil Shapiro off_t prevsize;
371106f25ae9SGregory Neil Shapiro char dfname[MAXPATHLEN];
371206f25ae9SGregory Neil Shapiro
371340266059SGregory Neil Shapiro (void) sm_strlcpy(dfname, queuename(e, DATAFL_LETTER),
3714d0cef73dSGregory Neil Shapiro sizeof(dfname));
371506f25ae9SGregory Neil Shapiro
371606f25ae9SGregory Neil Shapiro /* Reset prevchar */
371706f25ae9SGregory Neil Shapiro prevchar = '\0';
371806f25ae9SGregory Neil Shapiro
371940266059SGregory Neil Shapiro /* Get the current data file information */
3720605302a5SGregory Neil Shapiro prevsize = sm_io_getinfo(e->e_dfp, SM_IO_WHAT_SIZE, NULL);
3721605302a5SGregory Neil Shapiro if (prevsize < 0)
3722605302a5SGregory Neil Shapiro prevsize = 0;
372306f25ae9SGregory Neil Shapiro
372440266059SGregory Neil Shapiro /* truncate current data file */
372540266059SGregory Neil Shapiro if (sm_io_getinfo(e->e_dfp, SM_IO_WHAT_ISTYPE, BF_FILE_TYPE))
372606f25ae9SGregory Neil Shapiro {
372740266059SGregory Neil Shapiro if (sm_io_setinfo(e->e_dfp, SM_BF_TRUNCATE, NULL) < 0)
372840266059SGregory Neil Shapiro {
372940266059SGregory Neil Shapiro MILTER_DF_ERROR("milter_replbody: sm_io truncate %s: %s");
373006f25ae9SGregory Neil Shapiro return -1;
373106f25ae9SGregory Neil Shapiro }
373240266059SGregory Neil Shapiro }
373306f25ae9SGregory Neil Shapiro else
373406f25ae9SGregory Neil Shapiro {
373540266059SGregory Neil Shapiro int err;
373640266059SGregory Neil Shapiro
373740266059SGregory Neil Shapiro err = sm_io_error(e->e_dfp);
373840266059SGregory Neil Shapiro (void) sm_io_flush(e->e_dfp, SM_TIME_DEFAULT);
373940266059SGregory Neil Shapiro
374040266059SGregory Neil Shapiro /*
374140266059SGregory Neil Shapiro ** Clear error if tried to fflush()
374240266059SGregory Neil Shapiro ** a read-only file pointer and
374340266059SGregory Neil Shapiro ** there wasn't a previous error.
374440266059SGregory Neil Shapiro */
374540266059SGregory Neil Shapiro
374640266059SGregory Neil Shapiro if (err == 0)
374740266059SGregory Neil Shapiro sm_io_clearerr(e->e_dfp);
374840266059SGregory Neil Shapiro
374940266059SGregory Neil Shapiro /* errno is set implicitly by fseek() before return */
375040266059SGregory Neil Shapiro err = sm_io_seek(e->e_dfp, SM_TIME_DEFAULT,
375140266059SGregory Neil Shapiro 0, SEEK_SET);
37526a2f2ff3SGregory Neil Shapiro if (err < 0)
37536a2f2ff3SGregory Neil Shapiro {
37546a2f2ff3SGregory Neil Shapiro MILTER_DF_ERROR("milter_replbody: sm_io_seek %s: %s");
37556a2f2ff3SGregory Neil Shapiro return -1;
37566a2f2ff3SGregory Neil Shapiro }
37576a2f2ff3SGregory Neil Shapiro # if NOFTRUNCATE
37586a2f2ff3SGregory Neil Shapiro /* XXX: Not much we can do except rewind it */
37596a2f2ff3SGregory Neil Shapiro errno = EINVAL;
37606a2f2ff3SGregory Neil Shapiro MILTER_DF_ERROR("milter_replbody: ftruncate not available on this platform (%s:%s)");
37616a2f2ff3SGregory Neil Shapiro return -1;
376240266059SGregory Neil Shapiro # else /* NOFTRUNCATE */
376340266059SGregory Neil Shapiro err = ftruncate(sm_io_getinfo(e->e_dfp,
376440266059SGregory Neil Shapiro SM_IO_WHAT_FD, NULL),
376540266059SGregory Neil Shapiro 0);
376640266059SGregory Neil Shapiro if (err < 0)
376740266059SGregory Neil Shapiro {
376840266059SGregory Neil Shapiro MILTER_DF_ERROR("milter_replbody: sm_io ftruncate %s: %s");
376940266059SGregory Neil Shapiro return -1;
377040266059SGregory Neil Shapiro }
37716a2f2ff3SGregory Neil Shapiro # endif /* NOFTRUNCATE */
377240266059SGregory Neil Shapiro }
377340266059SGregory Neil Shapiro
377406f25ae9SGregory Neil Shapiro if (prevsize > e->e_msgsize)
377506f25ae9SGregory Neil Shapiro e->e_msgsize = 0;
377606f25ae9SGregory Neil Shapiro else
377706f25ae9SGregory Neil Shapiro e->e_msgsize -= prevsize;
377806f25ae9SGregory Neil Shapiro }
377940266059SGregory Neil Shapiro
378040266059SGregory Neil Shapiro if (newfilter && MilterLogLevel > 8)
37815b0945b5SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter (%s) message: body replaced",
37825b0945b5SGregory Neil Shapiro mname);
378306f25ae9SGregory Neil Shapiro
378406f25ae9SGregory Neil Shapiro if (response == NULL)
378506f25ae9SGregory Neil Shapiro {
378606f25ae9SGregory Neil Shapiro /* Flush the buffered '\r' */
378706f25ae9SGregory Neil Shapiro if (prevchar == '\r')
378806f25ae9SGregory Neil Shapiro {
378940266059SGregory Neil Shapiro (void) sm_io_putc(e->e_dfp, SM_TIME_DEFAULT, prevchar);
379006f25ae9SGregory Neil Shapiro e->e_msgsize++;
379106f25ae9SGregory Neil Shapiro }
379206f25ae9SGregory Neil Shapiro return 0;
379306f25ae9SGregory Neil Shapiro }
379406f25ae9SGregory Neil Shapiro
379506f25ae9SGregory Neil Shapiro for (i = 0; i < rlen; i++)
379606f25ae9SGregory Neil Shapiro {
379706f25ae9SGregory Neil Shapiro /* Buffered char from last chunk */
379806f25ae9SGregory Neil Shapiro if (i == 0 && prevchar == '\r')
379906f25ae9SGregory Neil Shapiro {
380006f25ae9SGregory Neil Shapiro /* Not CRLF, output prevchar */
380106f25ae9SGregory Neil Shapiro if (response[i] != '\n')
380206f25ae9SGregory Neil Shapiro {
380340266059SGregory Neil Shapiro (void) sm_io_putc(e->e_dfp, SM_TIME_DEFAULT,
380440266059SGregory Neil Shapiro prevchar);
380506f25ae9SGregory Neil Shapiro e->e_msgsize++;
380606f25ae9SGregory Neil Shapiro }
380706f25ae9SGregory Neil Shapiro prevchar = '\0';
380806f25ae9SGregory Neil Shapiro }
380906f25ae9SGregory Neil Shapiro
381006f25ae9SGregory Neil Shapiro /* Turn CRLF into LF */
381106f25ae9SGregory Neil Shapiro if (response[i] == '\r')
381206f25ae9SGregory Neil Shapiro {
381306f25ae9SGregory Neil Shapiro /* check if at end of chunk */
381406f25ae9SGregory Neil Shapiro if (i + 1 < rlen)
381506f25ae9SGregory Neil Shapiro {
381606f25ae9SGregory Neil Shapiro /* If LF, strip CR */
381706f25ae9SGregory Neil Shapiro if (response[i + 1] == '\n')
381806f25ae9SGregory Neil Shapiro i++;
381906f25ae9SGregory Neil Shapiro }
382006f25ae9SGregory Neil Shapiro else
382106f25ae9SGregory Neil Shapiro {
382206f25ae9SGregory Neil Shapiro /* check next chunk */
382306f25ae9SGregory Neil Shapiro prevchar = '\r';
382406f25ae9SGregory Neil Shapiro continue;
382506f25ae9SGregory Neil Shapiro }
382606f25ae9SGregory Neil Shapiro }
382740266059SGregory Neil Shapiro (void) sm_io_putc(e->e_dfp, SM_TIME_DEFAULT, response[i]);
382806f25ae9SGregory Neil Shapiro e->e_msgsize++;
382906f25ae9SGregory Neil Shapiro }
383006f25ae9SGregory Neil Shapiro return 0;
383106f25ae9SGregory Neil Shapiro }
383206f25ae9SGregory Neil Shapiro
383306f25ae9SGregory Neil Shapiro /*
383406f25ae9SGregory Neil Shapiro ** MTA callouts
383506f25ae9SGregory Neil Shapiro */
383606f25ae9SGregory Neil Shapiro
383740266059SGregory Neil Shapiro /*
383806f25ae9SGregory Neil Shapiro ** MILTER_INIT -- open and negotiate with all of the filters
383906f25ae9SGregory Neil Shapiro **
384006f25ae9SGregory Neil Shapiro ** Parameters:
384106f25ae9SGregory Neil Shapiro ** e -- current envelope.
384206f25ae9SGregory Neil Shapiro ** state -- return state from response.
3843ffb83623SGregory Neil Shapiro ** milters -- milters structure.
384406f25ae9SGregory Neil Shapiro **
384506f25ae9SGregory Neil Shapiro ** Returns:
384640266059SGregory Neil Shapiro ** true iff at least one filter is active
384706f25ae9SGregory Neil Shapiro */
384806f25ae9SGregory Neil Shapiro
384906f25ae9SGregory Neil Shapiro /* ARGSUSED */
385040266059SGregory Neil Shapiro bool
milter_init(e,state,milters)3851ffb83623SGregory Neil Shapiro milter_init(e, state, milters)
385206f25ae9SGregory Neil Shapiro ENVELOPE *e;
385306f25ae9SGregory Neil Shapiro char *state;
3854ffb83623SGregory Neil Shapiro milters_T *milters;
385506f25ae9SGregory Neil Shapiro {
385606f25ae9SGregory Neil Shapiro int i;
385706f25ae9SGregory Neil Shapiro
385806f25ae9SGregory Neil Shapiro if (tTd(64, 10))
385940266059SGregory Neil Shapiro sm_dprintf("milter_init\n");
386006f25ae9SGregory Neil Shapiro
3861ffb83623SGregory Neil Shapiro memset(milters, '\0', sizeof(*milters));
386206f25ae9SGregory Neil Shapiro *state = SMFIR_CONTINUE;
386340266059SGregory Neil Shapiro if (InputFilters[0] == NULL)
386440266059SGregory Neil Shapiro {
386540266059SGregory Neil Shapiro if (MilterLogLevel > 10)
386640266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
386740266059SGregory Neil Shapiro "Milter: no active filter");
386840266059SGregory Neil Shapiro return false;
386940266059SGregory Neil Shapiro }
387040266059SGregory Neil Shapiro
387106f25ae9SGregory Neil Shapiro for (i = 0; InputFilters[i] != NULL; i++)
387206f25ae9SGregory Neil Shapiro {
387306f25ae9SGregory Neil Shapiro struct milter *m = InputFilters[i];
387406f25ae9SGregory Neil Shapiro
387540266059SGregory Neil Shapiro m->mf_sock = milter_open(m, false, e);
387606f25ae9SGregory Neil Shapiro if (m->mf_state == SMFS_ERROR)
387706f25ae9SGregory Neil Shapiro {
38785ef517c0SGregory Neil Shapiro MILTER_CHECK_ERROR(true, continue);
387906f25ae9SGregory Neil Shapiro break;
388006f25ae9SGregory Neil Shapiro }
388106f25ae9SGregory Neil Shapiro
388206f25ae9SGregory Neil Shapiro if (m->mf_sock < 0 ||
3883ffb83623SGregory Neil Shapiro milter_negotiate(m, e, milters) < 0 ||
388406f25ae9SGregory Neil Shapiro m->mf_state == SMFS_ERROR)
388506f25ae9SGregory Neil Shapiro {
388606f25ae9SGregory Neil Shapiro if (tTd(64, 5))
388740266059SGregory Neil Shapiro sm_dprintf("milter_init(%s): failed to %s\n",
388806f25ae9SGregory Neil Shapiro m->mf_name,
388940266059SGregory Neil Shapiro m->mf_sock < 0 ? "open" :
389040266059SGregory Neil Shapiro "negotiate");
389140266059SGregory Neil Shapiro if (MilterLogLevel > 0)
389240266059SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
389340266059SGregory Neil Shapiro "Milter (%s): init failed to %s",
389440266059SGregory Neil Shapiro m->mf_name,
389540266059SGregory Neil Shapiro m->mf_sock < 0 ? "open" :
389640266059SGregory Neil Shapiro "negotiate");
389706f25ae9SGregory Neil Shapiro
38989bd497b8SGregory Neil Shapiro /* if negotiation failure, close socket */
389940266059SGregory Neil Shapiro milter_error(m, e);
39005ef517c0SGregory Neil Shapiro MILTER_CHECK_ERROR(true, continue);
3901e92d3f3fSGregory Neil Shapiro continue;
390206f25ae9SGregory Neil Shapiro }
390340266059SGregory Neil Shapiro if (MilterLogLevel > 9)
390440266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
390540266059SGregory Neil Shapiro "Milter (%s): init success to %s",
390640266059SGregory Neil Shapiro m->mf_name,
390740266059SGregory Neil Shapiro m->mf_sock < 0 ? "open" : "negotiate");
390806f25ae9SGregory Neil Shapiro }
390906f25ae9SGregory Neil Shapiro
391006f25ae9SGregory Neil Shapiro /*
391106f25ae9SGregory Neil Shapiro ** If something temp/perm failed with one of the filters,
391206f25ae9SGregory Neil Shapiro ** we won't be using any of them, so clear any existing
391306f25ae9SGregory Neil Shapiro ** connections.
391406f25ae9SGregory Neil Shapiro */
391506f25ae9SGregory Neil Shapiro
391606f25ae9SGregory Neil Shapiro if (*state != SMFIR_CONTINUE)
391706f25ae9SGregory Neil Shapiro milter_quit(e);
391840266059SGregory Neil Shapiro
391940266059SGregory Neil Shapiro return true;
392006f25ae9SGregory Neil Shapiro }
3921d0cef73dSGregory Neil Shapiro
392240266059SGregory Neil Shapiro /*
392306f25ae9SGregory Neil Shapiro ** MILTER_CONNECT -- send connection info to milter filters
392406f25ae9SGregory Neil Shapiro **
392506f25ae9SGregory Neil Shapiro ** Parameters:
392606f25ae9SGregory Neil Shapiro ** hostname -- hostname of remote machine.
392706f25ae9SGregory Neil Shapiro ** addr -- address of remote machine.
392806f25ae9SGregory Neil Shapiro ** e -- current envelope.
392906f25ae9SGregory Neil Shapiro ** state -- return state from response.
393006f25ae9SGregory Neil Shapiro **
393106f25ae9SGregory Neil Shapiro ** Returns:
393206f25ae9SGregory Neil Shapiro ** response string (may be NULL)
393306f25ae9SGregory Neil Shapiro */
393406f25ae9SGregory Neil Shapiro
393506f25ae9SGregory Neil Shapiro char *
milter_connect(hostname,addr,e,state)393606f25ae9SGregory Neil Shapiro milter_connect(hostname, addr, e, state)
393706f25ae9SGregory Neil Shapiro char *hostname;
393806f25ae9SGregory Neil Shapiro SOCKADDR addr;
393906f25ae9SGregory Neil Shapiro ENVELOPE *e;
394006f25ae9SGregory Neil Shapiro char *state;
394106f25ae9SGregory Neil Shapiro {
394206f25ae9SGregory Neil Shapiro char family;
394340266059SGregory Neil Shapiro unsigned short port;
394406f25ae9SGregory Neil Shapiro char *buf, *bp;
394506f25ae9SGregory Neil Shapiro char *response;
394606f25ae9SGregory Neil Shapiro char *sockinfo = NULL;
394706f25ae9SGregory Neil Shapiro ssize_t s;
394806f25ae9SGregory Neil Shapiro # if NETINET6
394906f25ae9SGregory Neil Shapiro char buf6[INET6_ADDRSTRLEN];
39505b0945b5SGregory Neil Shapiro # endif
395106f25ae9SGregory Neil Shapiro
395206f25ae9SGregory Neil Shapiro if (tTd(64, 10))
395340266059SGregory Neil Shapiro sm_dprintf("milter_connect(%s)\n", hostname);
395440266059SGregory Neil Shapiro if (MilterLogLevel > 9)
395540266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter: connect to filters");
395606f25ae9SGregory Neil Shapiro
395706f25ae9SGregory Neil Shapiro /* gather data */
395806f25ae9SGregory Neil Shapiro switch (addr.sa.sa_family)
395906f25ae9SGregory Neil Shapiro {
396006f25ae9SGregory Neil Shapiro # if NETUNIX
396106f25ae9SGregory Neil Shapiro case AF_UNIX:
396206f25ae9SGregory Neil Shapiro family = SMFIA_UNIX;
396306f25ae9SGregory Neil Shapiro port = htons(0);
396406f25ae9SGregory Neil Shapiro sockinfo = addr.sunix.sun_path;
396506f25ae9SGregory Neil Shapiro break;
396606f25ae9SGregory Neil Shapiro # endif /* NETUNIX */
396706f25ae9SGregory Neil Shapiro
396806f25ae9SGregory Neil Shapiro # if NETINET
396906f25ae9SGregory Neil Shapiro case AF_INET:
397006f25ae9SGregory Neil Shapiro family = SMFIA_INET;
3971605302a5SGregory Neil Shapiro port = addr.sin.sin_port;
397206f25ae9SGregory Neil Shapiro sockinfo = (char *) inet_ntoa(addr.sin.sin_addr);
397306f25ae9SGregory Neil Shapiro break;
397406f25ae9SGregory Neil Shapiro # endif /* NETINET */
397506f25ae9SGregory Neil Shapiro
397606f25ae9SGregory Neil Shapiro # if NETINET6
397706f25ae9SGregory Neil Shapiro case AF_INET6:
397813058a91SGregory Neil Shapiro if (IN6_IS_ADDR_V4MAPPED(&addr.sin6.sin6_addr))
397913058a91SGregory Neil Shapiro family = SMFIA_INET;
398013058a91SGregory Neil Shapiro else
398106f25ae9SGregory Neil Shapiro family = SMFIA_INET6;
3982605302a5SGregory Neil Shapiro port = addr.sin6.sin6_port;
398306f25ae9SGregory Neil Shapiro sockinfo = anynet_ntop(&addr.sin6.sin6_addr, buf6,
3984d0cef73dSGregory Neil Shapiro sizeof(buf6));
398506f25ae9SGregory Neil Shapiro if (sockinfo == NULL)
398606f25ae9SGregory Neil Shapiro sockinfo = "";
398706f25ae9SGregory Neil Shapiro break;
398806f25ae9SGregory Neil Shapiro # endif /* NETINET6 */
398906f25ae9SGregory Neil Shapiro
399006f25ae9SGregory Neil Shapiro default:
399106f25ae9SGregory Neil Shapiro family = SMFIA_UNKNOWN;
399206f25ae9SGregory Neil Shapiro break;
399306f25ae9SGregory Neil Shapiro }
399406f25ae9SGregory Neil Shapiro
399506f25ae9SGregory Neil Shapiro s = strlen(hostname) + 1 + sizeof(family);
399606f25ae9SGregory Neil Shapiro if (family != SMFIA_UNKNOWN)
399706f25ae9SGregory Neil Shapiro s += sizeof(port) + strlen(sockinfo) + 1;
399806f25ae9SGregory Neil Shapiro
399906f25ae9SGregory Neil Shapiro buf = (char *) xalloc(s);
400006f25ae9SGregory Neil Shapiro bp = buf;
400106f25ae9SGregory Neil Shapiro
400206f25ae9SGregory Neil Shapiro /* put together data */
400306f25ae9SGregory Neil Shapiro (void) memcpy(bp, hostname, strlen(hostname));
400406f25ae9SGregory Neil Shapiro bp += strlen(hostname);
400506f25ae9SGregory Neil Shapiro *bp++ = '\0';
4006d0cef73dSGregory Neil Shapiro (void) memcpy(bp, &family, sizeof(family));
4007d0cef73dSGregory Neil Shapiro bp += sizeof(family);
400806f25ae9SGregory Neil Shapiro if (family != SMFIA_UNKNOWN)
400906f25ae9SGregory Neil Shapiro {
4010d0cef73dSGregory Neil Shapiro (void) memcpy(bp, &port, sizeof(port));
4011d0cef73dSGregory Neil Shapiro bp += sizeof(port);
401206f25ae9SGregory Neil Shapiro
401306f25ae9SGregory Neil Shapiro /* include trailing '\0' */
401406f25ae9SGregory Neil Shapiro (void) memcpy(bp, sockinfo, strlen(sockinfo) + 1);
401506f25ae9SGregory Neil Shapiro }
401606f25ae9SGregory Neil Shapiro
4017ba00ec3dSGregory Neil Shapiro response = milter_command(SMFIC_CONNECT, buf, s, SMFIM_CONNECT,
4018d0cef73dSGregory Neil Shapiro e, state, "connect", false);
401940266059SGregory Neil Shapiro sm_free(buf); /* XXX */
402006f25ae9SGregory Neil Shapiro
402106f25ae9SGregory Neil Shapiro /*
402206f25ae9SGregory Neil Shapiro ** If this message connection is done for,
402306f25ae9SGregory Neil Shapiro ** close the filters.
402406f25ae9SGregory Neil Shapiro */
402506f25ae9SGregory Neil Shapiro
402606f25ae9SGregory Neil Shapiro if (*state != SMFIR_CONTINUE)
402740266059SGregory Neil Shapiro {
402840266059SGregory Neil Shapiro if (MilterLogLevel > 9)
402940266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter: connect, ending");
403006f25ae9SGregory Neil Shapiro milter_quit(e);
403140266059SGregory Neil Shapiro }
403206f25ae9SGregory Neil Shapiro else
403306f25ae9SGregory Neil Shapiro milter_per_connection_check(e);
403406f25ae9SGregory Neil Shapiro
4035da7d7b9cSGregory Neil Shapiro # if !_FFR_MILTER_CONNECT_REPLYCODE
403606f25ae9SGregory Neil Shapiro /*
403706f25ae9SGregory Neil Shapiro ** SMFIR_REPLYCODE can't work with connect due to
403806f25ae9SGregory Neil Shapiro ** the requirements of SMTP. Therefore, ignore the
403906f25ae9SGregory Neil Shapiro ** reply code text but keep the state it would reflect.
404006f25ae9SGregory Neil Shapiro */
404106f25ae9SGregory Neil Shapiro
404206f25ae9SGregory Neil Shapiro if (*state == SMFIR_REPLYCODE)
404306f25ae9SGregory Neil Shapiro {
404406f25ae9SGregory Neil Shapiro if (response != NULL &&
404506f25ae9SGregory Neil Shapiro *response == '4')
404613bd1963SGregory Neil Shapiro {
404713bd1963SGregory Neil Shapiro if (strncmp(response, "421 ", 4) == 0)
404813bd1963SGregory Neil Shapiro *state = SMFIR_SHUTDOWN;
404913bd1963SGregory Neil Shapiro else
405006f25ae9SGregory Neil Shapiro *state = SMFIR_TEMPFAIL;
405113bd1963SGregory Neil Shapiro }
405206f25ae9SGregory Neil Shapiro else
405306f25ae9SGregory Neil Shapiro *state = SMFIR_REJECT;
405406f25ae9SGregory Neil Shapiro if (response != NULL)
405506f25ae9SGregory Neil Shapiro {
405640266059SGregory Neil Shapiro sm_free(response); /* XXX */
405706f25ae9SGregory Neil Shapiro response = NULL;
405806f25ae9SGregory Neil Shapiro }
405906f25ae9SGregory Neil Shapiro }
4060da7d7b9cSGregory Neil Shapiro # endif /* !_FFR_MILTER_CONNECT_REPLYCODE */
406106f25ae9SGregory Neil Shapiro return response;
406206f25ae9SGregory Neil Shapiro }
4063d0cef73dSGregory Neil Shapiro
406440266059SGregory Neil Shapiro /*
406506f25ae9SGregory Neil Shapiro ** MILTER_HELO -- send SMTP HELO/EHLO command info to milter filters
406606f25ae9SGregory Neil Shapiro **
406706f25ae9SGregory Neil Shapiro ** Parameters:
406806f25ae9SGregory Neil Shapiro ** helo -- argument to SMTP HELO/EHLO command.
406906f25ae9SGregory Neil Shapiro ** e -- current envelope.
407006f25ae9SGregory Neil Shapiro ** state -- return state from response.
407106f25ae9SGregory Neil Shapiro **
407206f25ae9SGregory Neil Shapiro ** Returns:
407306f25ae9SGregory Neil Shapiro ** response string (may be NULL)
407406f25ae9SGregory Neil Shapiro */
407506f25ae9SGregory Neil Shapiro
407606f25ae9SGregory Neil Shapiro char *
milter_helo(helo,e,state)407706f25ae9SGregory Neil Shapiro milter_helo(helo, e, state)
407806f25ae9SGregory Neil Shapiro char *helo;
407906f25ae9SGregory Neil Shapiro ENVELOPE *e;
408006f25ae9SGregory Neil Shapiro char *state;
408106f25ae9SGregory Neil Shapiro {
4082602a2b1bSGregory Neil Shapiro int i;
408306f25ae9SGregory Neil Shapiro char *response;
408406f25ae9SGregory Neil Shapiro
408506f25ae9SGregory Neil Shapiro if (tTd(64, 10))
408640266059SGregory Neil Shapiro sm_dprintf("milter_helo(%s)\n", helo);
408706f25ae9SGregory Neil Shapiro
408840266059SGregory Neil Shapiro /* HELO/EHLO can come at any point */
4089602a2b1bSGregory Neil Shapiro for (i = 0; InputFilters[i] != NULL; i++)
4090602a2b1bSGregory Neil Shapiro {
4091602a2b1bSGregory Neil Shapiro struct milter *m = InputFilters[i];
4092602a2b1bSGregory Neil Shapiro
4093602a2b1bSGregory Neil Shapiro switch (m->mf_state)
4094602a2b1bSGregory Neil Shapiro {
4095602a2b1bSGregory Neil Shapiro case SMFS_INMSG:
4096602a2b1bSGregory Neil Shapiro /* abort in message filters */
4097602a2b1bSGregory Neil Shapiro milter_abort_filter(m, e);
4098602a2b1bSGregory Neil Shapiro /* FALLTHROUGH */
4099602a2b1bSGregory Neil Shapiro
4100602a2b1bSGregory Neil Shapiro case SMFS_DONE:
4101602a2b1bSGregory Neil Shapiro /* reset done filters */
4102602a2b1bSGregory Neil Shapiro m->mf_state = SMFS_OPEN;
4103602a2b1bSGregory Neil Shapiro break;
4104602a2b1bSGregory Neil Shapiro }
4105602a2b1bSGregory Neil Shapiro }
4106602a2b1bSGregory Neil Shapiro
410706f25ae9SGregory Neil Shapiro response = milter_command(SMFIC_HELO, helo, strlen(helo) + 1,
410869b95e36SGregory Neil Shapiro SMFIM_HELO, e, state, "helo", false);
410906f25ae9SGregory Neil Shapiro milter_per_connection_check(e);
411006f25ae9SGregory Neil Shapiro return response;
411106f25ae9SGregory Neil Shapiro }
4112d0cef73dSGregory Neil Shapiro
411340266059SGregory Neil Shapiro /*
411406f25ae9SGregory Neil Shapiro ** MILTER_ENVFROM -- send SMTP MAIL command info to milter filters
411506f25ae9SGregory Neil Shapiro **
411606f25ae9SGregory Neil Shapiro ** Parameters:
411706f25ae9SGregory Neil Shapiro ** args -- SMTP MAIL command args (args[0] == sender).
411806f25ae9SGregory Neil Shapiro ** e -- current envelope.
411906f25ae9SGregory Neil Shapiro ** state -- return state from response.
412006f25ae9SGregory Neil Shapiro **
412106f25ae9SGregory Neil Shapiro ** Returns:
412206f25ae9SGregory Neil Shapiro ** response string (may be NULL)
412306f25ae9SGregory Neil Shapiro */
412406f25ae9SGregory Neil Shapiro
412506f25ae9SGregory Neil Shapiro char *
milter_envfrom(args,e,state)412606f25ae9SGregory Neil Shapiro milter_envfrom(args, e, state)
412706f25ae9SGregory Neil Shapiro char **args;
412806f25ae9SGregory Neil Shapiro ENVELOPE *e;
412906f25ae9SGregory Neil Shapiro char *state;
413006f25ae9SGregory Neil Shapiro {
413106f25ae9SGregory Neil Shapiro int i;
413206f25ae9SGregory Neil Shapiro char *buf, *bp;
413306f25ae9SGregory Neil Shapiro char *response;
413406f25ae9SGregory Neil Shapiro ssize_t s;
413506f25ae9SGregory Neil Shapiro
413606f25ae9SGregory Neil Shapiro if (tTd(64, 10))
413706f25ae9SGregory Neil Shapiro {
413840266059SGregory Neil Shapiro sm_dprintf("milter_envfrom:");
413906f25ae9SGregory Neil Shapiro for (i = 0; args[i] != NULL; i++)
414040266059SGregory Neil Shapiro sm_dprintf(" %s", args[i]);
414140266059SGregory Neil Shapiro sm_dprintf("\n");
414206f25ae9SGregory Neil Shapiro }
414306f25ae9SGregory Neil Shapiro
414406f25ae9SGregory Neil Shapiro /* sanity check */
414506f25ae9SGregory Neil Shapiro if (args[0] == NULL)
414606f25ae9SGregory Neil Shapiro {
414706f25ae9SGregory Neil Shapiro *state = SMFIR_REJECT;
414840266059SGregory Neil Shapiro if (MilterLogLevel > 10)
414940266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
415040266059SGregory Neil Shapiro "Milter: reject, no sender");
415106f25ae9SGregory Neil Shapiro return NULL;
415206f25ae9SGregory Neil Shapiro }
415306f25ae9SGregory Neil Shapiro
415406f25ae9SGregory Neil Shapiro /* new message, so ... */
415506f25ae9SGregory Neil Shapiro for (i = 0; InputFilters[i] != NULL; i++)
415606f25ae9SGregory Neil Shapiro {
415706f25ae9SGregory Neil Shapiro struct milter *m = InputFilters[i];
415806f25ae9SGregory Neil Shapiro
415906f25ae9SGregory Neil Shapiro switch (m->mf_state)
416006f25ae9SGregory Neil Shapiro {
416106f25ae9SGregory Neil Shapiro case SMFS_INMSG:
416206f25ae9SGregory Neil Shapiro /* abort in message filters */
416306f25ae9SGregory Neil Shapiro milter_abort_filter(m, e);
416406f25ae9SGregory Neil Shapiro /* FALLTHROUGH */
416506f25ae9SGregory Neil Shapiro
416606f25ae9SGregory Neil Shapiro case SMFS_DONE:
416706f25ae9SGregory Neil Shapiro /* reset done filters */
416806f25ae9SGregory Neil Shapiro m->mf_state = SMFS_OPEN;
416906f25ae9SGregory Neil Shapiro break;
417006f25ae9SGregory Neil Shapiro }
417106f25ae9SGregory Neil Shapiro }
417206f25ae9SGregory Neil Shapiro
417306f25ae9SGregory Neil Shapiro /* put together data */
417406f25ae9SGregory Neil Shapiro s = 0;
417506f25ae9SGregory Neil Shapiro for (i = 0; args[i] != NULL; i++)
417606f25ae9SGregory Neil Shapiro s += strlen(args[i]) + 1;
417740266059SGregory Neil Shapiro
417840266059SGregory Neil Shapiro if (s < 0)
417940266059SGregory Neil Shapiro {
418040266059SGregory Neil Shapiro *state = SMFIR_TEMPFAIL;
418140266059SGregory Neil Shapiro return NULL;
418240266059SGregory Neil Shapiro }
418340266059SGregory Neil Shapiro
418406f25ae9SGregory Neil Shapiro buf = (char *) xalloc(s);
418506f25ae9SGregory Neil Shapiro bp = buf;
418606f25ae9SGregory Neil Shapiro for (i = 0; args[i] != NULL; i++)
418706f25ae9SGregory Neil Shapiro {
418840266059SGregory Neil Shapiro (void) sm_strlcpy(bp, args[i], s - (bp - buf));
418906f25ae9SGregory Neil Shapiro bp += strlen(bp) + 1;
419006f25ae9SGregory Neil Shapiro }
419106f25ae9SGregory Neil Shapiro
419240266059SGregory Neil Shapiro if (MilterLogLevel > 14)
4193d0cef73dSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter: sender: %s", buf);
419440266059SGregory Neil Shapiro
419506f25ae9SGregory Neil Shapiro /* send it over */
4196ba00ec3dSGregory Neil Shapiro response = milter_command(SMFIC_MAIL, buf, s, SMFIM_ENVFROM,
4197d0cef73dSGregory Neil Shapiro e, state, "mail", false);
419840266059SGregory Neil Shapiro sm_free(buf); /* XXX */
419906f25ae9SGregory Neil Shapiro
420006f25ae9SGregory Neil Shapiro /*
420106f25ae9SGregory Neil Shapiro ** If filter rejects/discards a per message command,
420206f25ae9SGregory Neil Shapiro ** abort the other filters since we are done with the
420306f25ae9SGregory Neil Shapiro ** current message.
420406f25ae9SGregory Neil Shapiro */
420506f25ae9SGregory Neil Shapiro
420606f25ae9SGregory Neil Shapiro MILTER_CHECK_DONE_MSG();
420740266059SGregory Neil Shapiro if (MilterLogLevel > 10 && *state == SMFIR_REJECT)
4208d0cef73dSGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter: reject, sender");
420906f25ae9SGregory Neil Shapiro return response;
421006f25ae9SGregory Neil Shapiro }
4211e92d3f3fSGregory Neil Shapiro
421240266059SGregory Neil Shapiro /*
421306f25ae9SGregory Neil Shapiro ** MILTER_ENVRCPT -- send SMTP RCPT command info to milter filters
421406f25ae9SGregory Neil Shapiro **
421506f25ae9SGregory Neil Shapiro ** Parameters:
42165b0945b5SGregory Neil Shapiro ** args -- SMTP RCPT command args (args[0] == recipient).
421706f25ae9SGregory Neil Shapiro ** e -- current envelope.
421806f25ae9SGregory Neil Shapiro ** state -- return state from response.
4219d0cef73dSGregory Neil Shapiro ** rcpt_error -- does RCPT have an error?
422006f25ae9SGregory Neil Shapiro **
422106f25ae9SGregory Neil Shapiro ** Returns:
422206f25ae9SGregory Neil Shapiro ** response string (may be NULL)
422306f25ae9SGregory Neil Shapiro */
422406f25ae9SGregory Neil Shapiro
422506f25ae9SGregory Neil Shapiro char *
milter_envrcpt(args,e,state,rcpt_error)4226d0cef73dSGregory Neil Shapiro milter_envrcpt(args, e, state, rcpt_error)
422706f25ae9SGregory Neil Shapiro char **args;
422806f25ae9SGregory Neil Shapiro ENVELOPE *e;
422906f25ae9SGregory Neil Shapiro char *state;
4230d0cef73dSGregory Neil Shapiro bool rcpt_error;
423106f25ae9SGregory Neil Shapiro {
423206f25ae9SGregory Neil Shapiro int i;
423306f25ae9SGregory Neil Shapiro char *buf, *bp;
423406f25ae9SGregory Neil Shapiro char *response;
423506f25ae9SGregory Neil Shapiro ssize_t s;
423606f25ae9SGregory Neil Shapiro
423706f25ae9SGregory Neil Shapiro if (tTd(64, 10))
423806f25ae9SGregory Neil Shapiro {
423940266059SGregory Neil Shapiro sm_dprintf("milter_envrcpt:");
424006f25ae9SGregory Neil Shapiro for (i = 0; args[i] != NULL; i++)
424140266059SGregory Neil Shapiro sm_dprintf(" %s", args[i]);
424240266059SGregory Neil Shapiro sm_dprintf("\n");
424306f25ae9SGregory Neil Shapiro }
424406f25ae9SGregory Neil Shapiro
424506f25ae9SGregory Neil Shapiro /* sanity check */
424606f25ae9SGregory Neil Shapiro if (args[0] == NULL)
424706f25ae9SGregory Neil Shapiro {
424806f25ae9SGregory Neil Shapiro *state = SMFIR_REJECT;
424940266059SGregory Neil Shapiro if (MilterLogLevel > 10)
425040266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter: reject, no rcpt");
425106f25ae9SGregory Neil Shapiro return NULL;
425206f25ae9SGregory Neil Shapiro }
425306f25ae9SGregory Neil Shapiro
425406f25ae9SGregory Neil Shapiro /* put together data */
425506f25ae9SGregory Neil Shapiro s = 0;
425606f25ae9SGregory Neil Shapiro for (i = 0; args[i] != NULL; i++)
425706f25ae9SGregory Neil Shapiro s += strlen(args[i]) + 1;
425840266059SGregory Neil Shapiro
425940266059SGregory Neil Shapiro if (s < 0)
426040266059SGregory Neil Shapiro {
426140266059SGregory Neil Shapiro *state = SMFIR_TEMPFAIL;
426240266059SGregory Neil Shapiro return NULL;
426340266059SGregory Neil Shapiro }
426440266059SGregory Neil Shapiro
426506f25ae9SGregory Neil Shapiro buf = (char *) xalloc(s);
426606f25ae9SGregory Neil Shapiro bp = buf;
426706f25ae9SGregory Neil Shapiro for (i = 0; args[i] != NULL; i++)
426806f25ae9SGregory Neil Shapiro {
426940266059SGregory Neil Shapiro (void) sm_strlcpy(bp, args[i], s - (bp - buf));
427006f25ae9SGregory Neil Shapiro bp += strlen(bp) + 1;
427106f25ae9SGregory Neil Shapiro }
427206f25ae9SGregory Neil Shapiro
427340266059SGregory Neil Shapiro if (MilterLogLevel > 14)
427440266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter: rcpts: %s", buf);
427540266059SGregory Neil Shapiro
427606f25ae9SGregory Neil Shapiro /* send it over */
4277ba00ec3dSGregory Neil Shapiro response = milter_command(SMFIC_RCPT, buf, s, SMFIM_ENVRCPT,
4278d0cef73dSGregory Neil Shapiro e, state, "rcpt", rcpt_error);
427940266059SGregory Neil Shapiro sm_free(buf); /* XXX */
428006f25ae9SGregory Neil Shapiro return response;
428106f25ae9SGregory Neil Shapiro }
4282e92d3f3fSGregory Neil Shapiro
4283e92d3f3fSGregory Neil Shapiro /*
4284e92d3f3fSGregory Neil Shapiro ** MILTER_DATA_CMD -- send SMTP DATA command info to milter filters
4285e92d3f3fSGregory Neil Shapiro **
4286e92d3f3fSGregory Neil Shapiro ** Parameters:
4287e92d3f3fSGregory Neil Shapiro ** e -- current envelope.
4288e92d3f3fSGregory Neil Shapiro ** state -- return state from response.
4289e92d3f3fSGregory Neil Shapiro **
4290e92d3f3fSGregory Neil Shapiro ** Returns:
4291e92d3f3fSGregory Neil Shapiro ** response string (may be NULL)
4292e92d3f3fSGregory Neil Shapiro */
4293e92d3f3fSGregory Neil Shapiro
4294e92d3f3fSGregory Neil Shapiro char *
milter_data_cmd(e,state)4295e92d3f3fSGregory Neil Shapiro milter_data_cmd(e, state)
4296e92d3f3fSGregory Neil Shapiro ENVELOPE *e;
4297e92d3f3fSGregory Neil Shapiro char *state;
4298e92d3f3fSGregory Neil Shapiro {
4299e92d3f3fSGregory Neil Shapiro if (tTd(64, 10))
4300e92d3f3fSGregory Neil Shapiro sm_dprintf("milter_data_cmd\n");
4301e92d3f3fSGregory Neil Shapiro
4302e92d3f3fSGregory Neil Shapiro /* send it over */
4303ba00ec3dSGregory Neil Shapiro return milter_command(SMFIC_DATA, NULL, 0, SMFIM_DATA,
4304ba00ec3dSGregory Neil Shapiro e, state, "data", false);
4305e92d3f3fSGregory Neil Shapiro }
4306e92d3f3fSGregory Neil Shapiro
430740266059SGregory Neil Shapiro /*
430806f25ae9SGregory Neil Shapiro ** MILTER_DATA -- send message headers/body and gather final message results
430906f25ae9SGregory Neil Shapiro **
431006f25ae9SGregory Neil Shapiro ** Parameters:
431106f25ae9SGregory Neil Shapiro ** e -- current envelope.
431206f25ae9SGregory Neil Shapiro ** state -- return state from response.
431306f25ae9SGregory Neil Shapiro **
431406f25ae9SGregory Neil Shapiro ** Returns:
431506f25ae9SGregory Neil Shapiro ** response string (may be NULL)
431606f25ae9SGregory Neil Shapiro **
431706f25ae9SGregory Neil Shapiro ** Side effects:
431806f25ae9SGregory Neil Shapiro ** - Uses e->e_dfp for access to the body
431906f25ae9SGregory Neil Shapiro ** - Can call the various milter action routines to
432006f25ae9SGregory Neil Shapiro ** modify the envelope or message.
432106f25ae9SGregory Neil Shapiro */
432206f25ae9SGregory Neil Shapiro
4323ba00ec3dSGregory Neil Shapiro /* flow through code using continue; don't wrap in do {} while */
432406f25ae9SGregory Neil Shapiro # define MILTER_CHECK_RESULTS() \
4325ba00ec3dSGregory Neil Shapiro if (m->mf_state == SMFS_ERROR && *state == SMFIR_CONTINUE) \
4326ba00ec3dSGregory Neil Shapiro { \
4327ba00ec3dSGregory Neil Shapiro MILTER_SET_STATE; \
4328ba00ec3dSGregory Neil Shapiro } \
432906f25ae9SGregory Neil Shapiro if (*state == SMFIR_ACCEPT || \
433006f25ae9SGregory Neil Shapiro m->mf_state == SMFS_DONE || \
433106f25ae9SGregory Neil Shapiro m->mf_state == SMFS_ERROR) \
433206f25ae9SGregory Neil Shapiro { \
433306f25ae9SGregory Neil Shapiro if (m->mf_state != SMFS_ERROR) \
433406f25ae9SGregory Neil Shapiro m->mf_state = SMFS_DONE; \
433506f25ae9SGregory Neil Shapiro continue; /* to next filter */ \
433606f25ae9SGregory Neil Shapiro } \
433706f25ae9SGregory Neil Shapiro if (*state != SMFIR_CONTINUE) \
433806f25ae9SGregory Neil Shapiro { \
433906f25ae9SGregory Neil Shapiro m->mf_state = SMFS_DONE; \
434006f25ae9SGregory Neil Shapiro goto finishup; \
434106f25ae9SGregory Neil Shapiro }
434206f25ae9SGregory Neil Shapiro
434306f25ae9SGregory Neil Shapiro char *
milter_data(e,state)434406f25ae9SGregory Neil Shapiro milter_data(e, state)
434506f25ae9SGregory Neil Shapiro ENVELOPE *e;
434606f25ae9SGregory Neil Shapiro char *state;
434706f25ae9SGregory Neil Shapiro {
434840266059SGregory Neil Shapiro bool replbody = false; /* milter_replbody() called? */
434940266059SGregory Neil Shapiro bool replfailed = false; /* milter_replbody() failed? */
435040266059SGregory Neil Shapiro bool rewind = false; /* rewind data file? */
435140266059SGregory Neil Shapiro bool dfopen = false; /* data file open for writing? */
435206f25ae9SGregory Neil Shapiro bool newfilter; /* reset on each new filter */
435306f25ae9SGregory Neil Shapiro char rcmd;
435406f25ae9SGregory Neil Shapiro int i;
435506f25ae9SGregory Neil Shapiro int save_errno;
435606f25ae9SGregory Neil Shapiro char *response = NULL;
435706f25ae9SGregory Neil Shapiro time_t eomsent;
435806f25ae9SGregory Neil Shapiro ssize_t rlen;
435906f25ae9SGregory Neil Shapiro
436006f25ae9SGregory Neil Shapiro if (tTd(64, 10))
436140266059SGregory Neil Shapiro sm_dprintf("milter_data\n");
436206f25ae9SGregory Neil Shapiro
436306f25ae9SGregory Neil Shapiro *state = SMFIR_CONTINUE;
436406f25ae9SGregory Neil Shapiro
436506f25ae9SGregory Neil Shapiro /*
436606f25ae9SGregory Neil Shapiro ** XXX: Should actually send body chunks to each filter
436706f25ae9SGregory Neil Shapiro ** a chunk at a time instead of sending the whole body to
436806f25ae9SGregory Neil Shapiro ** each filter in turn. However, only if the filters don't
436906f25ae9SGregory Neil Shapiro ** change the body.
437006f25ae9SGregory Neil Shapiro */
437106f25ae9SGregory Neil Shapiro
437206f25ae9SGregory Neil Shapiro for (i = 0; InputFilters[i] != NULL; i++)
437306f25ae9SGregory Neil Shapiro {
4374ba00ec3dSGregory Neil Shapiro int idx;
4375ba00ec3dSGregory Neil Shapiro char **macros;
437606f25ae9SGregory Neil Shapiro struct milter *m = InputFilters[i];
437706f25ae9SGregory Neil Shapiro
437806f25ae9SGregory Neil Shapiro if (*state != SMFIR_CONTINUE &&
437906f25ae9SGregory Neil Shapiro *state != SMFIR_ACCEPT)
438006f25ae9SGregory Neil Shapiro {
438106f25ae9SGregory Neil Shapiro /*
438206f25ae9SGregory Neil Shapiro ** A previous filter has dealt with the message,
438306f25ae9SGregory Neil Shapiro ** safe to stop processing the filters.
438406f25ae9SGregory Neil Shapiro */
438506f25ae9SGregory Neil Shapiro
438606f25ae9SGregory Neil Shapiro break;
438706f25ae9SGregory Neil Shapiro }
438806f25ae9SGregory Neil Shapiro
438906f25ae9SGregory Neil Shapiro /* Now reset state for later evaluation */
439006f25ae9SGregory Neil Shapiro *state = SMFIR_CONTINUE;
439140266059SGregory Neil Shapiro newfilter = true;
439206f25ae9SGregory Neil Shapiro
4393193538b7SGregory Neil Shapiro /* previous problem? */
4394193538b7SGregory Neil Shapiro if (m->mf_state == SMFS_ERROR)
4395193538b7SGregory Neil Shapiro {
43965ef517c0SGregory Neil Shapiro MILTER_CHECK_ERROR(false, continue);
4397193538b7SGregory Neil Shapiro break;
4398193538b7SGregory Neil Shapiro }
4399193538b7SGregory Neil Shapiro
440006f25ae9SGregory Neil Shapiro /* sanity checks */
440106f25ae9SGregory Neil Shapiro if (m->mf_sock < 0 ||
440206f25ae9SGregory Neil Shapiro (m->mf_state != SMFS_OPEN && m->mf_state != SMFS_INMSG))
440306f25ae9SGregory Neil Shapiro continue;
440406f25ae9SGregory Neil Shapiro
440506f25ae9SGregory Neil Shapiro m->mf_state = SMFS_INMSG;
440606f25ae9SGregory Neil Shapiro
440706f25ae9SGregory Neil Shapiro /* check if filter wants the headers */
440806f25ae9SGregory Neil Shapiro if (!bitset(SMFIP_NOHDRS, m->mf_pflags))
440906f25ae9SGregory Neil Shapiro {
441006f25ae9SGregory Neil Shapiro response = milter_headers(m, e, state);
441106f25ae9SGregory Neil Shapiro MILTER_CHECK_RESULTS();
441206f25ae9SGregory Neil Shapiro }
441306f25ae9SGregory Neil Shapiro
441406f25ae9SGregory Neil Shapiro /* check if filter wants EOH */
441506f25ae9SGregory Neil Shapiro if (!bitset(SMFIP_NOEOH, m->mf_pflags))
441606f25ae9SGregory Neil Shapiro {
441706f25ae9SGregory Neil Shapiro if (tTd(64, 10))
441840266059SGregory Neil Shapiro sm_dprintf("milter_data: eoh\n");
441906f25ae9SGregory Neil Shapiro
4420ba00ec3dSGregory Neil Shapiro if ((m->mf_lflags & MI_LFLAGS_SYM(SMFIM_EOH)) != 0)
4421ba00ec3dSGregory Neil Shapiro idx = m->mf_idx;
4422ba00ec3dSGregory Neil Shapiro else
4423ba00ec3dSGregory Neil Shapiro idx = 0;
4424ba00ec3dSGregory Neil Shapiro SM_ASSERT(idx >= 0 && idx <= MAXFILTERS);
4425ba00ec3dSGregory Neil Shapiro macros = MilterMacros[SMFIM_EOH][idx];
4426ba00ec3dSGregory Neil Shapiro
4427ba00ec3dSGregory Neil Shapiro if (macros != NULL)
4428d0cef73dSGregory Neil Shapiro {
4429ba00ec3dSGregory Neil Shapiro milter_send_macros(m, macros, SMFIC_EOH, e);
4430d0cef73dSGregory Neil Shapiro MILTER_CHECK_RESULTS();
4431d0cef73dSGregory Neil Shapiro }
4432d0cef73dSGregory Neil Shapiro
443306f25ae9SGregory Neil Shapiro /* send it over */
443406f25ae9SGregory Neil Shapiro response = milter_send_command(m, SMFIC_EOH, NULL, 0,
4435d0cef73dSGregory Neil Shapiro e, state, "eoh");
443606f25ae9SGregory Neil Shapiro MILTER_CHECK_RESULTS();
443706f25ae9SGregory Neil Shapiro }
443806f25ae9SGregory Neil Shapiro
443906f25ae9SGregory Neil Shapiro /* check if filter wants the body */
444006f25ae9SGregory Neil Shapiro if (!bitset(SMFIP_NOBODY, m->mf_pflags) &&
444106f25ae9SGregory Neil Shapiro e->e_dfp != NULL)
444206f25ae9SGregory Neil Shapiro {
444340266059SGregory Neil Shapiro rewind = true;
444406f25ae9SGregory Neil Shapiro response = milter_body(m, e, state);
444506f25ae9SGregory Neil Shapiro MILTER_CHECK_RESULTS();
444606f25ae9SGregory Neil Shapiro }
444706f25ae9SGregory Neil Shapiro
4448ba00ec3dSGregory Neil Shapiro if ((m->mf_lflags & MI_LFLAGS_SYM(SMFIM_EOH)) != 0)
4449ba00ec3dSGregory Neil Shapiro idx = m->mf_idx;
4450ba00ec3dSGregory Neil Shapiro else
4451ba00ec3dSGregory Neil Shapiro idx = 0;
4452ba00ec3dSGregory Neil Shapiro SM_ASSERT(idx >= 0 && idx <= MAXFILTERS);
4453ba00ec3dSGregory Neil Shapiro macros = MilterMacros[SMFIM_EOM][idx];
4454ba00ec3dSGregory Neil Shapiro if (macros != NULL)
445513d88268SGregory Neil Shapiro {
4456ba00ec3dSGregory Neil Shapiro milter_send_macros(m, macros, SMFIC_BODYEOB, e);
445713d88268SGregory Neil Shapiro MILTER_CHECK_RESULTS();
445813d88268SGregory Neil Shapiro }
4459323f6dcbSGregory Neil Shapiro
446006f25ae9SGregory Neil Shapiro /* send the final body chunk */
446106f25ae9SGregory Neil Shapiro (void) milter_write(m, SMFIC_BODYEOB, NULL, 0,
4462d0cef73dSGregory Neil Shapiro m->mf_timeout[SMFTO_WRITE], e, "eom");
446306f25ae9SGregory Neil Shapiro
446406f25ae9SGregory Neil Shapiro /* Get time EOM sent for timeout */
446506f25ae9SGregory Neil Shapiro eomsent = curtime();
446606f25ae9SGregory Neil Shapiro
446706f25ae9SGregory Neil Shapiro /* deal with the possibility of multiple responses */
446806f25ae9SGregory Neil Shapiro while (*state == SMFIR_CONTINUE)
446906f25ae9SGregory Neil Shapiro {
447006f25ae9SGregory Neil Shapiro /* Check total timeout from EOM to final ACK/NAK */
447106f25ae9SGregory Neil Shapiro if (m->mf_timeout[SMFTO_EOM] > 0 &&
447206f25ae9SGregory Neil Shapiro curtime() - eomsent >= m->mf_timeout[SMFTO_EOM])
447306f25ae9SGregory Neil Shapiro {
447406f25ae9SGregory Neil Shapiro if (tTd(64, 5))
447540266059SGregory Neil Shapiro sm_dprintf("milter_data(%s): EOM ACK/NAK timeout\n",
447606f25ae9SGregory Neil Shapiro m->mf_name);
447740266059SGregory Neil Shapiro if (MilterLogLevel > 0)
447806f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
447940266059SGregory Neil Shapiro "milter_data(%s): EOM ACK/NAK timeout",
448006f25ae9SGregory Neil Shapiro m->mf_name);
448140266059SGregory Neil Shapiro milter_error(m, e);
44825ef517c0SGregory Neil Shapiro MILTER_CHECK_ERROR(false, break);
448306f25ae9SGregory Neil Shapiro break;
448406f25ae9SGregory Neil Shapiro }
448506f25ae9SGregory Neil Shapiro
448606f25ae9SGregory Neil Shapiro response = milter_read(m, &rcmd, &rlen,
4487d0cef73dSGregory Neil Shapiro m->mf_timeout[SMFTO_READ], e,
44889bd497b8SGregory Neil Shapiro "eom");
448906f25ae9SGregory Neil Shapiro if (m->mf_state == SMFS_ERROR)
449006f25ae9SGregory Neil Shapiro break;
449106f25ae9SGregory Neil Shapiro
449206f25ae9SGregory Neil Shapiro if (tTd(64, 10))
449340266059SGregory Neil Shapiro sm_dprintf("milter_data(%s): state %c\n",
449406f25ae9SGregory Neil Shapiro m->mf_name, (char) rcmd);
449506f25ae9SGregory Neil Shapiro
449606f25ae9SGregory Neil Shapiro switch (rcmd)
449706f25ae9SGregory Neil Shapiro {
449806f25ae9SGregory Neil Shapiro case SMFIR_REPLYCODE:
449906f25ae9SGregory Neil Shapiro MILTER_CHECK_REPLYCODE("554 5.7.1 Command rejected");
450040266059SGregory Neil Shapiro if (MilterLogLevel > 12)
450140266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "milter=%s, reject=%s",
450240266059SGregory Neil Shapiro m->mf_name, response);
450306f25ae9SGregory Neil Shapiro *state = rcmd;
450406f25ae9SGregory Neil Shapiro m->mf_state = SMFS_DONE;
450506f25ae9SGregory Neil Shapiro break;
450606f25ae9SGregory Neil Shapiro
450740266059SGregory Neil Shapiro case SMFIR_REJECT: /* log msg at end of function */
450840266059SGregory Neil Shapiro if (MilterLogLevel > 12)
450940266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "milter=%s, reject",
451040266059SGregory Neil Shapiro m->mf_name);
451140266059SGregory Neil Shapiro *state = rcmd;
451240266059SGregory Neil Shapiro m->mf_state = SMFS_DONE;
451340266059SGregory Neil Shapiro break;
451440266059SGregory Neil Shapiro
451506f25ae9SGregory Neil Shapiro case SMFIR_DISCARD:
451640266059SGregory Neil Shapiro if (MilterLogLevel > 12)
451740266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "milter=%s, discard",
451840266059SGregory Neil Shapiro m->mf_name);
451940266059SGregory Neil Shapiro *state = rcmd;
452040266059SGregory Neil Shapiro m->mf_state = SMFS_DONE;
452140266059SGregory Neil Shapiro break;
452240266059SGregory Neil Shapiro
452306f25ae9SGregory Neil Shapiro case SMFIR_TEMPFAIL:
452440266059SGregory Neil Shapiro if (MilterLogLevel > 12)
452540266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "milter=%s, tempfail",
452640266059SGregory Neil Shapiro m->mf_name);
452706f25ae9SGregory Neil Shapiro *state = rcmd;
452806f25ae9SGregory Neil Shapiro m->mf_state = SMFS_DONE;
452906f25ae9SGregory Neil Shapiro break;
453006f25ae9SGregory Neil Shapiro
453106f25ae9SGregory Neil Shapiro case SMFIR_CONTINUE:
453206f25ae9SGregory Neil Shapiro case SMFIR_ACCEPT:
453306f25ae9SGregory Neil Shapiro /* this filter is done with message */
453406f25ae9SGregory Neil Shapiro if (replfailed)
453506f25ae9SGregory Neil Shapiro *state = SMFIR_TEMPFAIL;
453606f25ae9SGregory Neil Shapiro else
453706f25ae9SGregory Neil Shapiro *state = SMFIR_ACCEPT;
453806f25ae9SGregory Neil Shapiro m->mf_state = SMFS_DONE;
453906f25ae9SGregory Neil Shapiro break;
454006f25ae9SGregory Neil Shapiro
454106f25ae9SGregory Neil Shapiro case SMFIR_PROGRESS:
454206f25ae9SGregory Neil Shapiro break;
454306f25ae9SGregory Neil Shapiro
454440266059SGregory Neil Shapiro case SMFIR_QUARANTINE:
454540266059SGregory Neil Shapiro if (!bitset(SMFIF_QUARANTINE, m->mf_fflags))
454640266059SGregory Neil Shapiro {
454740266059SGregory Neil Shapiro if (MilterLogLevel > 9)
454840266059SGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id,
454940266059SGregory Neil Shapiro "milter_data(%s): lied about quarantining, honoring request anyway",
455040266059SGregory Neil Shapiro m->mf_name);
455140266059SGregory Neil Shapiro }
455240266059SGregory Neil Shapiro if (response == NULL)
455340266059SGregory Neil Shapiro response = newstr("");
455440266059SGregory Neil Shapiro if (MilterLogLevel > 3)
455540266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id,
455640266059SGregory Neil Shapiro "milter=%s, quarantine=%s",
455740266059SGregory Neil Shapiro m->mf_name, response);
455840266059SGregory Neil Shapiro e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool,
455940266059SGregory Neil Shapiro response);
456040266059SGregory Neil Shapiro macdefine(&e->e_macro, A_PERM,
456140266059SGregory Neil Shapiro macid("{quarantine}"), e->e_quarmsg);
456240266059SGregory Neil Shapiro break;
456340266059SGregory Neil Shapiro
456406f25ae9SGregory Neil Shapiro case SMFIR_ADDHEADER:
456506f25ae9SGregory Neil Shapiro if (!bitset(SMFIF_ADDHDRS, m->mf_fflags))
456606f25ae9SGregory Neil Shapiro {
456740266059SGregory Neil Shapiro if (MilterLogLevel > 9)
456806f25ae9SGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id,
456906f25ae9SGregory Neil Shapiro "milter_data(%s): lied about adding headers, honoring request anyway",
457006f25ae9SGregory Neil Shapiro m->mf_name);
457106f25ae9SGregory Neil Shapiro }
4572d0cef73dSGregory Neil Shapiro milter_addheader(m, response, rlen, e);
457306f25ae9SGregory Neil Shapiro break;
457406f25ae9SGregory Neil Shapiro
4575e92d3f3fSGregory Neil Shapiro case SMFIR_INSHEADER:
4576e92d3f3fSGregory Neil Shapiro if (!bitset(SMFIF_ADDHDRS, m->mf_fflags))
4577e92d3f3fSGregory Neil Shapiro {
4578e92d3f3fSGregory Neil Shapiro if (MilterLogLevel > 9)
4579e92d3f3fSGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id,
4580e92d3f3fSGregory Neil Shapiro "milter_data(%s): lied about adding headers, honoring request anyway",
4581e92d3f3fSGregory Neil Shapiro m->mf_name);
4582e92d3f3fSGregory Neil Shapiro }
4583d0cef73dSGregory Neil Shapiro milter_insheader(m, response, rlen, e);
4584e92d3f3fSGregory Neil Shapiro break;
4585e92d3f3fSGregory Neil Shapiro
458606f25ae9SGregory Neil Shapiro case SMFIR_CHGHEADER:
458706f25ae9SGregory Neil Shapiro if (!bitset(SMFIF_CHGHDRS, m->mf_fflags))
458806f25ae9SGregory Neil Shapiro {
458940266059SGregory Neil Shapiro if (MilterLogLevel > 9)
459006f25ae9SGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id,
459106f25ae9SGregory Neil Shapiro "milter_data(%s): lied about changing headers, honoring request anyway",
459206f25ae9SGregory Neil Shapiro m->mf_name);
459306f25ae9SGregory Neil Shapiro }
4594d0cef73dSGregory Neil Shapiro milter_changeheader(m, response, rlen, e);
4595d0cef73dSGregory Neil Shapiro break;
4596d0cef73dSGregory Neil Shapiro
4597d0cef73dSGregory Neil Shapiro case SMFIR_CHGFROM:
4598d0cef73dSGregory Neil Shapiro if (!bitset(SMFIF_CHGFROM, m->mf_fflags))
4599d0cef73dSGregory Neil Shapiro {
4600d0cef73dSGregory Neil Shapiro if (MilterLogLevel > 9)
4601d0cef73dSGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id,
4602d0cef73dSGregory Neil Shapiro "milter_data(%s) lied about changing sender, honoring request anyway",
4603d0cef73dSGregory Neil Shapiro m->mf_name);
4604d0cef73dSGregory Neil Shapiro }
46055b0945b5SGregory Neil Shapiro milter_chgfrom(response, rlen, e, m->mf_name);
460606f25ae9SGregory Neil Shapiro break;
460706f25ae9SGregory Neil Shapiro
460806f25ae9SGregory Neil Shapiro case SMFIR_ADDRCPT:
460906f25ae9SGregory Neil Shapiro if (!bitset(SMFIF_ADDRCPT, m->mf_fflags))
461006f25ae9SGregory Neil Shapiro {
461140266059SGregory Neil Shapiro if (MilterLogLevel > 9)
461206f25ae9SGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id,
461306f25ae9SGregory Neil Shapiro "milter_data(%s) lied about adding recipients, honoring request anyway",
461406f25ae9SGregory Neil Shapiro m->mf_name);
461506f25ae9SGregory Neil Shapiro }
46165b0945b5SGregory Neil Shapiro milter_addrcpt(response, rlen, e, m->mf_name);
461706f25ae9SGregory Neil Shapiro break;
461806f25ae9SGregory Neil Shapiro
4619d0cef73dSGregory Neil Shapiro case SMFIR_ADDRCPT_PAR:
4620d0cef73dSGregory Neil Shapiro if (!bitset(SMFIF_ADDRCPT_PAR, m->mf_fflags))
4621d0cef73dSGregory Neil Shapiro {
4622d0cef73dSGregory Neil Shapiro if (MilterLogLevel > 9)
4623d0cef73dSGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id,
4624d0cef73dSGregory Neil Shapiro "milter_data(%s) lied about adding recipients with parameters, honoring request anyway",
4625d0cef73dSGregory Neil Shapiro m->mf_name);
4626d0cef73dSGregory Neil Shapiro }
46275b0945b5SGregory Neil Shapiro milter_addrcpt_par(response, rlen, e, m->mf_name);
4628d0cef73dSGregory Neil Shapiro break;
4629d0cef73dSGregory Neil Shapiro
463006f25ae9SGregory Neil Shapiro case SMFIR_DELRCPT:
463106f25ae9SGregory Neil Shapiro if (!bitset(SMFIF_DELRCPT, m->mf_fflags))
463206f25ae9SGregory Neil Shapiro {
463340266059SGregory Neil Shapiro if (MilterLogLevel > 9)
463406f25ae9SGregory Neil Shapiro sm_syslog(LOG_WARNING, e->e_id,
463506f25ae9SGregory Neil Shapiro "milter_data(%s): lied about removing recipients, honoring request anyway",
463606f25ae9SGregory Neil Shapiro m->mf_name);
463706f25ae9SGregory Neil Shapiro }
46385b0945b5SGregory Neil Shapiro milter_delrcpt(response, rlen, e, m->mf_name);
463906f25ae9SGregory Neil Shapiro break;
464006f25ae9SGregory Neil Shapiro
464106f25ae9SGregory Neil Shapiro case SMFIR_REPLBODY:
464206f25ae9SGregory Neil Shapiro if (!bitset(SMFIF_MODBODY, m->mf_fflags))
464306f25ae9SGregory Neil Shapiro {
4644e92d3f3fSGregory Neil Shapiro if (MilterLogLevel > 0)
464506f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
464606f25ae9SGregory Neil Shapiro "milter_data(%s): lied about replacing body, rejecting request and tempfailing message",
464706f25ae9SGregory Neil Shapiro m->mf_name);
464840266059SGregory Neil Shapiro replfailed = true;
464906f25ae9SGregory Neil Shapiro break;
465006f25ae9SGregory Neil Shapiro }
465106f25ae9SGregory Neil Shapiro
465206f25ae9SGregory Neil Shapiro /* already failed in attempt */
465306f25ae9SGregory Neil Shapiro if (replfailed)
465406f25ae9SGregory Neil Shapiro break;
465506f25ae9SGregory Neil Shapiro
465606f25ae9SGregory Neil Shapiro if (!dfopen)
465706f25ae9SGregory Neil Shapiro {
465806f25ae9SGregory Neil Shapiro if (milter_reopen_df(e) < 0)
465906f25ae9SGregory Neil Shapiro {
466040266059SGregory Neil Shapiro replfailed = true;
466106f25ae9SGregory Neil Shapiro break;
466206f25ae9SGregory Neil Shapiro }
466340266059SGregory Neil Shapiro dfopen = true;
466440266059SGregory Neil Shapiro rewind = true;
466506f25ae9SGregory Neil Shapiro }
466606f25ae9SGregory Neil Shapiro
46675b0945b5SGregory Neil Shapiro if (milter_replbody(response, rlen, newfilter,
46685b0945b5SGregory Neil Shapiro e, m->mf_name) < 0)
466940266059SGregory Neil Shapiro replfailed = true;
467040266059SGregory Neil Shapiro newfilter = false;
467140266059SGregory Neil Shapiro replbody = true;
467206f25ae9SGregory Neil Shapiro break;
467306f25ae9SGregory Neil Shapiro
467406f25ae9SGregory Neil Shapiro default:
467506f25ae9SGregory Neil Shapiro /* Invalid response to command */
467640266059SGregory Neil Shapiro if (MilterLogLevel > 0)
467706f25ae9SGregory Neil Shapiro sm_syslog(LOG_ERR, e->e_id,
467806f25ae9SGregory Neil Shapiro "milter_data(%s): returned bogus response %c",
467906f25ae9SGregory Neil Shapiro m->mf_name, rcmd);
468040266059SGregory Neil Shapiro milter_error(m, e);
468106f25ae9SGregory Neil Shapiro break;
468206f25ae9SGregory Neil Shapiro }
468340266059SGregory Neil Shapiro if (rcmd != SMFIR_REPLYCODE && response != NULL)
468406f25ae9SGregory Neil Shapiro {
468540266059SGregory Neil Shapiro sm_free(response); /* XXX */
468606f25ae9SGregory Neil Shapiro response = NULL;
468706f25ae9SGregory Neil Shapiro }
468806f25ae9SGregory Neil Shapiro
468906f25ae9SGregory Neil Shapiro if (m->mf_state == SMFS_ERROR)
469006f25ae9SGregory Neil Shapiro break;
469106f25ae9SGregory Neil Shapiro }
469206f25ae9SGregory Neil Shapiro
469306f25ae9SGregory Neil Shapiro if (replbody && !replfailed)
469406f25ae9SGregory Neil Shapiro {
469506f25ae9SGregory Neil Shapiro /* flush possible buffered character */
46965b0945b5SGregory Neil Shapiro milter_replbody(NULL, 0, !replbody, e, m->mf_name);
469740266059SGregory Neil Shapiro replbody = false;
469806f25ae9SGregory Neil Shapiro }
469906f25ae9SGregory Neil Shapiro
470006f25ae9SGregory Neil Shapiro if (m->mf_state == SMFS_ERROR)
470106f25ae9SGregory Neil Shapiro {
47025ef517c0SGregory Neil Shapiro MILTER_CHECK_ERROR(false, continue);
470306f25ae9SGregory Neil Shapiro goto finishup;
470406f25ae9SGregory Neil Shapiro }
470506f25ae9SGregory Neil Shapiro }
470606f25ae9SGregory Neil Shapiro
470706f25ae9SGregory Neil Shapiro finishup:
470806f25ae9SGregory Neil Shapiro /* leave things in the expected state if we touched it */
470906f25ae9SGregory Neil Shapiro if (replfailed)
471006f25ae9SGregory Neil Shapiro {
471106f25ae9SGregory Neil Shapiro if (*state == SMFIR_CONTINUE ||
471206f25ae9SGregory Neil Shapiro *state == SMFIR_ACCEPT)
471306f25ae9SGregory Neil Shapiro {
471406f25ae9SGregory Neil Shapiro *state = SMFIR_TEMPFAIL;
47155b0945b5SGregory Neil Shapiro SM_FREE(response);
471606f25ae9SGregory Neil Shapiro }
471706f25ae9SGregory Neil Shapiro
471806f25ae9SGregory Neil Shapiro if (dfopen)
471906f25ae9SGregory Neil Shapiro {
47202fb4f839SGregory Neil Shapiro SM_CLOSE_FP(e->e_dfp);
472106f25ae9SGregory Neil Shapiro e->e_flags &= ~EF_HAS_DF;
472240266059SGregory Neil Shapiro dfopen = false;
472306f25ae9SGregory Neil Shapiro }
472440266059SGregory Neil Shapiro rewind = false;
472506f25ae9SGregory Neil Shapiro }
472606f25ae9SGregory Neil Shapiro
472706f25ae9SGregory Neil Shapiro if ((dfopen && milter_reset_df(e) < 0) ||
472806f25ae9SGregory Neil Shapiro (rewind && bfrewind(e->e_dfp) < 0))
472906f25ae9SGregory Neil Shapiro {
473006f25ae9SGregory Neil Shapiro save_errno = errno;
473106f25ae9SGregory Neil Shapiro ExitStat = EX_IOERR;
473206f25ae9SGregory Neil Shapiro
473306f25ae9SGregory Neil Shapiro /*
473406f25ae9SGregory Neil Shapiro ** If filter told us to keep message but we had
473506f25ae9SGregory Neil Shapiro ** an error, we can't really keep it, tempfail it.
473606f25ae9SGregory Neil Shapiro */
473706f25ae9SGregory Neil Shapiro
47385b0945b5SGregory Neil Shapiro if (*state == SMFIR_CONTINUE || *state == SMFIR_ACCEPT)
473906f25ae9SGregory Neil Shapiro {
474006f25ae9SGregory Neil Shapiro *state = SMFIR_TEMPFAIL;
47415b0945b5SGregory Neil Shapiro SM_FREE(response);
474206f25ae9SGregory Neil Shapiro }
474306f25ae9SGregory Neil Shapiro
474406f25ae9SGregory Neil Shapiro errno = save_errno;
474540266059SGregory Neil Shapiro syserr("milter_data: %s/%cf%s: read error",
474640266059SGregory Neil Shapiro qid_printqueue(e->e_qgrp, e->e_qdir),
474740266059SGregory Neil Shapiro DATAFL_LETTER, e->e_id);
474806f25ae9SGregory Neil Shapiro }
474940266059SGregory Neil Shapiro
475006f25ae9SGregory Neil Shapiro MILTER_CHECK_DONE_MSG();
475140266059SGregory Neil Shapiro if (MilterLogLevel > 10 && *state == SMFIR_REJECT)
475240266059SGregory Neil Shapiro sm_syslog(LOG_INFO, e->e_id, "Milter: reject, data");
475306f25ae9SGregory Neil Shapiro return response;
475406f25ae9SGregory Neil Shapiro }
4755e92d3f3fSGregory Neil Shapiro
4756e92d3f3fSGregory Neil Shapiro /*
4757e92d3f3fSGregory Neil Shapiro ** MILTER_UNKNOWN -- send any unrecognized or unimplemented command
4758e92d3f3fSGregory Neil Shapiro ** string to milter filters
4759e92d3f3fSGregory Neil Shapiro **
4760e92d3f3fSGregory Neil Shapiro ** Parameters:
4761d0cef73dSGregory Neil Shapiro ** smtpcmd -- the string itself.
4762e92d3f3fSGregory Neil Shapiro ** e -- current envelope.
4763e92d3f3fSGregory Neil Shapiro ** state -- return state from response.
4764e92d3f3fSGregory Neil Shapiro **
4765e92d3f3fSGregory Neil Shapiro **
4766e92d3f3fSGregory Neil Shapiro ** Returns:
4767e92d3f3fSGregory Neil Shapiro ** response string (may be NULL)
4768e92d3f3fSGregory Neil Shapiro */
4769e92d3f3fSGregory Neil Shapiro
4770e92d3f3fSGregory Neil Shapiro char *
milter_unknown(smtpcmd,e,state)4771d0cef73dSGregory Neil Shapiro milter_unknown(smtpcmd, e, state)
4772d0cef73dSGregory Neil Shapiro char *smtpcmd;
4773e92d3f3fSGregory Neil Shapiro ENVELOPE *e;
4774e92d3f3fSGregory Neil Shapiro char *state;
4775e92d3f3fSGregory Neil Shapiro {
4776e92d3f3fSGregory Neil Shapiro if (tTd(64, 10))
4777d0cef73dSGregory Neil Shapiro sm_dprintf("milter_unknown(%s)\n", smtpcmd);
4778e92d3f3fSGregory Neil Shapiro
4779d0cef73dSGregory Neil Shapiro return milter_command(SMFIC_UNKNOWN, smtpcmd, strlen(smtpcmd) + 1,
4780ba00ec3dSGregory Neil Shapiro SMFIM_NOMACROS, e, state, "unknown", false);
4781e92d3f3fSGregory Neil Shapiro }
4782e92d3f3fSGregory Neil Shapiro
478340266059SGregory Neil Shapiro /*
478406f25ae9SGregory Neil Shapiro ** MILTER_QUIT -- informs the filter(s) we are done and closes connection(s)
478506f25ae9SGregory Neil Shapiro **
478606f25ae9SGregory Neil Shapiro ** Parameters:
478706f25ae9SGregory Neil Shapiro ** e -- current envelope.
478806f25ae9SGregory Neil Shapiro **
478906f25ae9SGregory Neil Shapiro ** Returns:
479006f25ae9SGregory Neil Shapiro ** none
479106f25ae9SGregory Neil Shapiro */
479206f25ae9SGregory Neil Shapiro
479306f25ae9SGregory Neil Shapiro void
milter_quit(e)479406f25ae9SGregory Neil Shapiro milter_quit(e)
479506f25ae9SGregory Neil Shapiro ENVELOPE *e;
479606f25ae9SGregory Neil Shapiro {
479706f25ae9SGregory Neil Shapiro int i;
479806f25ae9SGregory Neil Shapiro
479906f25ae9SGregory Neil Shapiro if (tTd(64, 10))
480040266059SGregory Neil Shapiro sm_dprintf("milter_quit(%s)\n", e->e_id);
480106f25ae9SGregory Neil Shapiro
480206f25ae9SGregory Neil Shapiro for (i = 0; InputFilters[i] != NULL; i++)
480306f25ae9SGregory Neil Shapiro milter_quit_filter(InputFilters[i], e);
480406f25ae9SGregory Neil Shapiro }
4805d0cef73dSGregory Neil Shapiro
480640266059SGregory Neil Shapiro /*
480706f25ae9SGregory Neil Shapiro ** MILTER_ABORT -- informs the filter(s) that we are aborting current message
480806f25ae9SGregory Neil Shapiro **
480906f25ae9SGregory Neil Shapiro ** Parameters:
481006f25ae9SGregory Neil Shapiro ** e -- current envelope.
481106f25ae9SGregory Neil Shapiro **
481206f25ae9SGregory Neil Shapiro ** Returns:
481306f25ae9SGregory Neil Shapiro ** none
481406f25ae9SGregory Neil Shapiro */
481506f25ae9SGregory Neil Shapiro
481606f25ae9SGregory Neil Shapiro void
milter_abort(e)481706f25ae9SGregory Neil Shapiro milter_abort(e)
481806f25ae9SGregory Neil Shapiro ENVELOPE *e;
481906f25ae9SGregory Neil Shapiro {
482006f25ae9SGregory Neil Shapiro int i;
482106f25ae9SGregory Neil Shapiro
482206f25ae9SGregory Neil Shapiro if (tTd(64, 10))
482340266059SGregory Neil Shapiro sm_dprintf("milter_abort\n");
482406f25ae9SGregory Neil Shapiro
482506f25ae9SGregory Neil Shapiro for (i = 0; InputFilters[i] != NULL; i++)
482606f25ae9SGregory Neil Shapiro {
482706f25ae9SGregory Neil Shapiro struct milter *m = InputFilters[i];
482806f25ae9SGregory Neil Shapiro
482906f25ae9SGregory Neil Shapiro /* sanity checks */
483006f25ae9SGregory Neil Shapiro if (m->mf_sock < 0 || m->mf_state != SMFS_INMSG)
483106f25ae9SGregory Neil Shapiro continue;
483206f25ae9SGregory Neil Shapiro
483306f25ae9SGregory Neil Shapiro milter_abort_filter(m, e);
483406f25ae9SGregory Neil Shapiro }
483506f25ae9SGregory Neil Shapiro }
483640266059SGregory Neil Shapiro #endif /* MILTER */
4837