17c478bd9Sstevel@tonic-gate /*
2*e9af4bc0SJohn Beck * Copyright (c) 1999-2009 Sendmail, Inc. and its suppliers.
37c478bd9Sstevel@tonic-gate * All rights reserved.
47c478bd9Sstevel@tonic-gate *
57c478bd9Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set
67c478bd9Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of
77c478bd9Sstevel@tonic-gate * the sendmail distribution.
87c478bd9Sstevel@tonic-gate *
97c478bd9Sstevel@tonic-gate */
107c478bd9Sstevel@tonic-gate
117c478bd9Sstevel@tonic-gate #include <sendmail.h>
127c478bd9Sstevel@tonic-gate
13*e9af4bc0SJohn Beck SM_RCSID("@(#)$Id: milter.c,v 8.277 2009/11/06 00:57:06 ca Exp $")
147c478bd9Sstevel@tonic-gate
157c478bd9Sstevel@tonic-gate #if MILTER
16058561cbSjbeck # include <sm/sendmail.h>
177c478bd9Sstevel@tonic-gate # include <libmilter/mfapi.h>
187c478bd9Sstevel@tonic-gate # include <libmilter/mfdef.h>
197c478bd9Sstevel@tonic-gate
207c478bd9Sstevel@tonic-gate # include <errno.h>
2149218d4fSjbeck # include <sm/time.h>
227c478bd9Sstevel@tonic-gate # include <sys/uio.h>
237c478bd9Sstevel@tonic-gate
247c478bd9Sstevel@tonic-gate # if NETINET || NETINET6
257c478bd9Sstevel@tonic-gate # include <arpa/inet.h>
26058561cbSjbeck # if MILTER_NO_NAGLE
277c478bd9Sstevel@tonic-gate # include <netinet/tcp.h>
28058561cbSjbeck # endif /* MILTER_NO_NAGLE */
297c478bd9Sstevel@tonic-gate # endif /* NETINET || NETINET6 */
307c478bd9Sstevel@tonic-gate
317c478bd9Sstevel@tonic-gate # include <sm/fdset.h>
327c478bd9Sstevel@tonic-gate
337c478bd9Sstevel@tonic-gate static void milter_connect_timeout __P((int));
347c478bd9Sstevel@tonic-gate static void milter_error __P((struct milter *, ENVELOPE *));
357c478bd9Sstevel@tonic-gate static int milter_open __P((struct milter *, bool, ENVELOPE *));
367c478bd9Sstevel@tonic-gate static void milter_parse_timeouts __P((char *, struct milter *));
37058561cbSjbeck static char *milter_sysread __P((struct milter *, char *, ssize_t, time_t,
38058561cbSjbeck ENVELOPE *, const char *));
39058561cbSjbeck static char *milter_read __P((struct milter *, char *, ssize_t *, time_t,
40058561cbSjbeck ENVELOPE *, const char *));
41058561cbSjbeck static char *milter_write __P((struct milter *, int, char *, ssize_t,
42058561cbSjbeck time_t, ENVELOPE *, const char *));
43058561cbSjbeck static char *milter_send_command __P((struct milter *, int, void *,
44058561cbSjbeck ssize_t, ENVELOPE *, char *, const char *));
45058561cbSjbeck static char *milter_command __P((int, void *, ssize_t, char **,
46058561cbSjbeck ENVELOPE *, char *, const char *, bool));
47058561cbSjbeck static char *milter_body __P((struct milter *, ENVELOPE *, char *));
48058561cbSjbeck static int milter_reopen_df __P((ENVELOPE *));
49058561cbSjbeck static int milter_reset_df __P((ENVELOPE *));
50058561cbSjbeck static void milter_quit_filter __P((struct milter *, ENVELOPE *));
51058561cbSjbeck static void milter_abort_filter __P((struct milter *, ENVELOPE *));
52058561cbSjbeck static void milter_send_macros __P((struct milter *, char **, int,
53058561cbSjbeck ENVELOPE *));
547800901eSjbeck static int milter_negotiate __P((struct milter *, ENVELOPE *,
557800901eSjbeck milters_T *));
56058561cbSjbeck static void milter_per_connection_check __P((ENVELOPE *));
57058561cbSjbeck static char *milter_headers __P((struct milter *, ENVELOPE *, char *));
58058561cbSjbeck static void milter_addheader __P((struct milter *, char *, ssize_t,
59058561cbSjbeck ENVELOPE *));
60058561cbSjbeck static void milter_insheader __P((struct milter *, char *, ssize_t,
61058561cbSjbeck ENVELOPE *));
62058561cbSjbeck static void milter_changeheader __P((struct milter *, char *, ssize_t,
63058561cbSjbeck ENVELOPE *));
64058561cbSjbeck static void milter_chgfrom __P((char *, ssize_t, ENVELOPE *));
65058561cbSjbeck static void milter_addrcpt __P((char *, ssize_t, ENVELOPE *));
66058561cbSjbeck static void milter_addrcpt_par __P((char *, ssize_t, ENVELOPE *));
67058561cbSjbeck static void milter_delrcpt __P((char *, ssize_t, ENVELOPE *));
68058561cbSjbeck static int milter_replbody __P((char *, ssize_t, bool, ENVELOPE *));
69058561cbSjbeck static int milter_set_macros __P((char *, char **, char *, int));
70058561cbSjbeck
71058561cbSjbeck
72058561cbSjbeck /* milter states */
73058561cbSjbeck # define SMFS_CLOSED 'C' /* closed for all further actions */
74058561cbSjbeck # define SMFS_OPEN 'O' /* connected to remote milter filter */
75058561cbSjbeck # define SMFS_INMSG 'M' /* currently servicing a message */
76058561cbSjbeck # define SMFS_DONE 'D' /* done with current message */
77058561cbSjbeck # define SMFS_CLOSABLE 'Q' /* done with current connection */
78058561cbSjbeck # define SMFS_ERROR 'E' /* error state */
79058561cbSjbeck # define SMFS_READY 'R' /* ready for action */
80058561cbSjbeck # define SMFS_SKIP 'S' /* skip body */
817c478bd9Sstevel@tonic-gate
827c478bd9Sstevel@tonic-gate static char *MilterConnectMacros[MAXFILTERMACROS + 1];
837c478bd9Sstevel@tonic-gate static char *MilterHeloMacros[MAXFILTERMACROS + 1];
847c478bd9Sstevel@tonic-gate static char *MilterEnvFromMacros[MAXFILTERMACROS + 1];
857c478bd9Sstevel@tonic-gate static char *MilterEnvRcptMacros[MAXFILTERMACROS + 1];
867c478bd9Sstevel@tonic-gate static char *MilterDataMacros[MAXFILTERMACROS + 1];
877c478bd9Sstevel@tonic-gate static char *MilterEOMMacros[MAXFILTERMACROS + 1];
88058561cbSjbeck static char *MilterEOHMacros[MAXFILTERMACROS + 1];
897c478bd9Sstevel@tonic-gate static size_t MilterMaxDataSize = MILTER_MAX_DATA_SIZE;
907c478bd9Sstevel@tonic-gate
917c478bd9Sstevel@tonic-gate # define MILTER_CHECK_DONE_MSG() \
927c478bd9Sstevel@tonic-gate if (*state == SMFIR_REPLYCODE || \
937c478bd9Sstevel@tonic-gate *state == SMFIR_REJECT || \
947c478bd9Sstevel@tonic-gate *state == SMFIR_DISCARD || \
957c478bd9Sstevel@tonic-gate *state == SMFIR_TEMPFAIL) \
967c478bd9Sstevel@tonic-gate { \
977c478bd9Sstevel@tonic-gate /* Abort the filters to let them know we are done with msg */ \
987c478bd9Sstevel@tonic-gate milter_abort(e); \
997c478bd9Sstevel@tonic-gate }
1007c478bd9Sstevel@tonic-gate
1017c478bd9Sstevel@tonic-gate # define MILTER_CHECK_ERROR(initial, action) \
1027c478bd9Sstevel@tonic-gate if (!initial && tTd(71, 100)) \
1037c478bd9Sstevel@tonic-gate { \
1047c478bd9Sstevel@tonic-gate if (e->e_quarmsg == NULL) \
1057c478bd9Sstevel@tonic-gate { \
1067c478bd9Sstevel@tonic-gate e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, \
1077c478bd9Sstevel@tonic-gate "filter failure"); \
1087c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), \
1097c478bd9Sstevel@tonic-gate e->e_quarmsg); \
1107c478bd9Sstevel@tonic-gate } \
1117c478bd9Sstevel@tonic-gate } \
1127c478bd9Sstevel@tonic-gate else if (tTd(71, 101)) \
1137c478bd9Sstevel@tonic-gate { \
1147c478bd9Sstevel@tonic-gate if (e->e_quarmsg == NULL) \
1157c478bd9Sstevel@tonic-gate { \
1167c478bd9Sstevel@tonic-gate e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, \
1177c478bd9Sstevel@tonic-gate "filter failure"); \
1187c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), \
1197c478bd9Sstevel@tonic-gate e->e_quarmsg); \
1207c478bd9Sstevel@tonic-gate } \
1217c478bd9Sstevel@tonic-gate } \
1227c478bd9Sstevel@tonic-gate else if (bitnset(SMF_TEMPFAIL, m->mf_flags)) \
1237c478bd9Sstevel@tonic-gate *state = SMFIR_TEMPFAIL; \
1247c478bd9Sstevel@tonic-gate else if (bitnset(SMF_TEMPDROP, m->mf_flags)) \
1257c478bd9Sstevel@tonic-gate *state = SMFIR_SHUTDOWN; \
1267c478bd9Sstevel@tonic-gate else if (bitnset(SMF_REJECT, m->mf_flags)) \
1277c478bd9Sstevel@tonic-gate *state = SMFIR_REJECT; \
1287c478bd9Sstevel@tonic-gate else \
1297c478bd9Sstevel@tonic-gate action;
1307c478bd9Sstevel@tonic-gate
1317c478bd9Sstevel@tonic-gate # define MILTER_CHECK_REPLYCODE(default) \
1327c478bd9Sstevel@tonic-gate if (response == NULL || \
1337c478bd9Sstevel@tonic-gate strlen(response) + 1 != (size_t) rlen || \
1347c478bd9Sstevel@tonic-gate rlen < 3 || \
1357c478bd9Sstevel@tonic-gate (response[0] != '4' && response[0] != '5') || \
1367c478bd9Sstevel@tonic-gate !isascii(response[1]) || !isdigit(response[1]) || \
1377c478bd9Sstevel@tonic-gate !isascii(response[2]) || !isdigit(response[2])) \
1387c478bd9Sstevel@tonic-gate { \
1397c478bd9Sstevel@tonic-gate if (response != NULL) \
1407c478bd9Sstevel@tonic-gate sm_free(response); /* XXX */ \
1417c478bd9Sstevel@tonic-gate response = newstr(default); \
1427c478bd9Sstevel@tonic-gate } \
1437c478bd9Sstevel@tonic-gate else \
1447c478bd9Sstevel@tonic-gate { \
1457c478bd9Sstevel@tonic-gate char *ptr = response; \
1467c478bd9Sstevel@tonic-gate \
1477c478bd9Sstevel@tonic-gate /* Check for unprotected %'s in the string */ \
1487c478bd9Sstevel@tonic-gate while (*ptr != '\0') \
1497c478bd9Sstevel@tonic-gate { \
1507c478bd9Sstevel@tonic-gate if (*ptr == '%' && *++ptr != '%') \
1517c478bd9Sstevel@tonic-gate { \
1527c478bd9Sstevel@tonic-gate sm_free(response); /* XXX */ \
1537c478bd9Sstevel@tonic-gate response = newstr(default); \
1547c478bd9Sstevel@tonic-gate break; \
1557c478bd9Sstevel@tonic-gate } \
1567c478bd9Sstevel@tonic-gate ptr++; \
1577c478bd9Sstevel@tonic-gate } \
1587c478bd9Sstevel@tonic-gate }
1597c478bd9Sstevel@tonic-gate
1607c478bd9Sstevel@tonic-gate # define MILTER_DF_ERROR(msg) \
1617c478bd9Sstevel@tonic-gate { \
1627c478bd9Sstevel@tonic-gate int save_errno = errno; \
1637c478bd9Sstevel@tonic-gate \
1647c478bd9Sstevel@tonic-gate if (tTd(64, 5)) \
1657c478bd9Sstevel@tonic-gate { \
1667c478bd9Sstevel@tonic-gate sm_dprintf(msg, dfname, sm_errstring(save_errno)); \
1677c478bd9Sstevel@tonic-gate sm_dprintf("\n"); \
1687c478bd9Sstevel@tonic-gate } \
1697c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) \
1707c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, msg, dfname, sm_errstring(save_errno)); \
1717c478bd9Sstevel@tonic-gate if (SuperSafe == SAFE_REALLY) \
1727c478bd9Sstevel@tonic-gate { \
1737c478bd9Sstevel@tonic-gate if (e->e_dfp != NULL) \
1747c478bd9Sstevel@tonic-gate { \
1757c478bd9Sstevel@tonic-gate (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT); \
1767c478bd9Sstevel@tonic-gate e->e_dfp = NULL; \
1777c478bd9Sstevel@tonic-gate } \
1787c478bd9Sstevel@tonic-gate e->e_flags &= ~EF_HAS_DF; \
1797c478bd9Sstevel@tonic-gate } \
1807c478bd9Sstevel@tonic-gate errno = save_errno; \
1817c478bd9Sstevel@tonic-gate }
1827c478bd9Sstevel@tonic-gate
1837c478bd9Sstevel@tonic-gate /*
1847c478bd9Sstevel@tonic-gate ** MILTER_TIMEOUT -- make sure socket is ready in time
1857c478bd9Sstevel@tonic-gate **
1867c478bd9Sstevel@tonic-gate ** Parameters:
1877c478bd9Sstevel@tonic-gate ** routine -- routine name for debug/logging
1887c478bd9Sstevel@tonic-gate ** secs -- number of seconds in timeout
1897c478bd9Sstevel@tonic-gate ** write -- waiting to read or write?
1907c478bd9Sstevel@tonic-gate ** started -- whether this is part of a previous sequence
1917c478bd9Sstevel@tonic-gate **
1927c478bd9Sstevel@tonic-gate ** Assumes 'm' is a milter structure for the current socket.
1937c478bd9Sstevel@tonic-gate */
1947c478bd9Sstevel@tonic-gate
195058561cbSjbeck # define MILTER_TIMEOUT(routine, secs, write, started, function) \
1967c478bd9Sstevel@tonic-gate { \
1977c478bd9Sstevel@tonic-gate int ret; \
1987c478bd9Sstevel@tonic-gate int save_errno; \
1997c478bd9Sstevel@tonic-gate fd_set fds; \
2007c478bd9Sstevel@tonic-gate struct timeval tv; \
2017c478bd9Sstevel@tonic-gate \
2027c478bd9Sstevel@tonic-gate if (SM_FD_SETSIZE > 0 && m->mf_sock >= SM_FD_SETSIZE) \
2037c478bd9Sstevel@tonic-gate { \
2047c478bd9Sstevel@tonic-gate if (tTd(64, 5)) \
2057c478bd9Sstevel@tonic-gate sm_dprintf("milter_%s(%s): socket %d is larger than FD_SETSIZE %d\n", \
2067c478bd9Sstevel@tonic-gate (routine), m->mf_name, m->mf_sock, \
2077c478bd9Sstevel@tonic-gate SM_FD_SETSIZE); \
2087c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) \
2097c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, \
2107c478bd9Sstevel@tonic-gate "Milter (%s): socket(%s) %d is larger than FD_SETSIZE %d", \
2117c478bd9Sstevel@tonic-gate m->mf_name, (routine), m->mf_sock, \
2127c478bd9Sstevel@tonic-gate SM_FD_SETSIZE); \
2137c478bd9Sstevel@tonic-gate milter_error(m, e); \
2147c478bd9Sstevel@tonic-gate return NULL; \
2157c478bd9Sstevel@tonic-gate } \
2167c478bd9Sstevel@tonic-gate \
2177c478bd9Sstevel@tonic-gate do \
2187c478bd9Sstevel@tonic-gate { \
2197c478bd9Sstevel@tonic-gate FD_ZERO(&fds); \
2207c478bd9Sstevel@tonic-gate SM_FD_SET(m->mf_sock, &fds); \
2217c478bd9Sstevel@tonic-gate tv.tv_sec = (secs); \
2227c478bd9Sstevel@tonic-gate tv.tv_usec = 0; \
2237c478bd9Sstevel@tonic-gate ret = select(m->mf_sock + 1, \
2247c478bd9Sstevel@tonic-gate (write) ? NULL : &fds, \
2257c478bd9Sstevel@tonic-gate (write) ? &fds : NULL, \
2267c478bd9Sstevel@tonic-gate NULL, &tv); \
2277c478bd9Sstevel@tonic-gate } while (ret < 0 && errno == EINTR); \
2287c478bd9Sstevel@tonic-gate \
2297c478bd9Sstevel@tonic-gate switch (ret) \
2307c478bd9Sstevel@tonic-gate { \
2317c478bd9Sstevel@tonic-gate case 0: \
2327c478bd9Sstevel@tonic-gate if (tTd(64, 5)) \
233058561cbSjbeck sm_dprintf("milter_%s(%s): timeout, where=%s\n", \
234058561cbSjbeck (routine), m->mf_name, (function)); \
2357c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) \
2367c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, \
237058561cbSjbeck "Milter (%s): timeout %s data %s, where=%s", \
238058561cbSjbeck m->mf_name, \
2397c478bd9Sstevel@tonic-gate started ? "during" : "before", \
240058561cbSjbeck (routine), (function)); \
2417c478bd9Sstevel@tonic-gate milter_error(m, e); \
2427c478bd9Sstevel@tonic-gate return NULL; \
2437c478bd9Sstevel@tonic-gate \
2447c478bd9Sstevel@tonic-gate case -1: \
2457c478bd9Sstevel@tonic-gate save_errno = errno; \
2467c478bd9Sstevel@tonic-gate if (tTd(64, 5)) \
2477c478bd9Sstevel@tonic-gate sm_dprintf("milter_%s(%s): select: %s\n", (routine), \
2487c478bd9Sstevel@tonic-gate m->mf_name, sm_errstring(save_errno)); \
2497c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) \
2507c478bd9Sstevel@tonic-gate { \
2517c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, \
2527c478bd9Sstevel@tonic-gate "Milter (%s): select(%s): %s", \
2537c478bd9Sstevel@tonic-gate m->mf_name, (routine), \
2547c478bd9Sstevel@tonic-gate sm_errstring(save_errno)); \
2557c478bd9Sstevel@tonic-gate } \
2567c478bd9Sstevel@tonic-gate milter_error(m, e); \
2577c478bd9Sstevel@tonic-gate return NULL; \
2587c478bd9Sstevel@tonic-gate \
2597c478bd9Sstevel@tonic-gate default: \
2607c478bd9Sstevel@tonic-gate if (SM_FD_ISSET(m->mf_sock, &fds)) \
2617c478bd9Sstevel@tonic-gate break; \
2627c478bd9Sstevel@tonic-gate if (tTd(64, 5)) \
2637c478bd9Sstevel@tonic-gate sm_dprintf("milter_%s(%s): socket not ready\n", \
2647c478bd9Sstevel@tonic-gate (routine), m->mf_name); \
2657c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0) \
2667c478bd9Sstevel@tonic-gate { \
2677c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, \
2687c478bd9Sstevel@tonic-gate "Milter (%s): socket(%s) not ready", \
2697c478bd9Sstevel@tonic-gate m->mf_name, (routine)); \
2707c478bd9Sstevel@tonic-gate } \
2717c478bd9Sstevel@tonic-gate milter_error(m, e); \
2727c478bd9Sstevel@tonic-gate return NULL; \
2737c478bd9Sstevel@tonic-gate } \
2747c478bd9Sstevel@tonic-gate }
2757c478bd9Sstevel@tonic-gate
2767c478bd9Sstevel@tonic-gate /*
2777c478bd9Sstevel@tonic-gate ** Low level functions
2787c478bd9Sstevel@tonic-gate */
2797c478bd9Sstevel@tonic-gate
2807c478bd9Sstevel@tonic-gate /*
2817c478bd9Sstevel@tonic-gate ** MILTER_READ -- read from a remote milter filter
2827c478bd9Sstevel@tonic-gate **
2837c478bd9Sstevel@tonic-gate ** Parameters:
2847c478bd9Sstevel@tonic-gate ** m -- milter to read from.
2857c478bd9Sstevel@tonic-gate ** cmd -- return param for command read.
2867c478bd9Sstevel@tonic-gate ** rlen -- return length of response string.
2877c478bd9Sstevel@tonic-gate ** to -- timeout in seconds.
2887c478bd9Sstevel@tonic-gate ** e -- current envelope.
2897c478bd9Sstevel@tonic-gate **
2907c478bd9Sstevel@tonic-gate ** Returns:
2917c478bd9Sstevel@tonic-gate ** response string (may be NULL)
2927c478bd9Sstevel@tonic-gate */
2937c478bd9Sstevel@tonic-gate
2947c478bd9Sstevel@tonic-gate static char *
milter_sysread(m,buf,sz,to,e,where)295058561cbSjbeck milter_sysread(m, buf, sz, to, e, where)
2967c478bd9Sstevel@tonic-gate struct milter *m;
2977c478bd9Sstevel@tonic-gate char *buf;
2987c478bd9Sstevel@tonic-gate ssize_t sz;
2997c478bd9Sstevel@tonic-gate time_t to;
3007c478bd9Sstevel@tonic-gate ENVELOPE *e;
301058561cbSjbeck const char *where;
3027c478bd9Sstevel@tonic-gate {
3037c478bd9Sstevel@tonic-gate time_t readstart = 0;
3047c478bd9Sstevel@tonic-gate ssize_t len, curl;
3057c478bd9Sstevel@tonic-gate bool started = false;
3067c478bd9Sstevel@tonic-gate
3077c478bd9Sstevel@tonic-gate curl = 0;
3087c478bd9Sstevel@tonic-gate
3097c478bd9Sstevel@tonic-gate if (to > 0)
3107c478bd9Sstevel@tonic-gate readstart = curtime();
3117c478bd9Sstevel@tonic-gate
3127c478bd9Sstevel@tonic-gate for (;;)
3137c478bd9Sstevel@tonic-gate {
3147c478bd9Sstevel@tonic-gate if (to > 0)
3157c478bd9Sstevel@tonic-gate {
3167c478bd9Sstevel@tonic-gate time_t now;
3177c478bd9Sstevel@tonic-gate
3187c478bd9Sstevel@tonic-gate now = curtime();
3197c478bd9Sstevel@tonic-gate if (now - readstart >= to)
3207c478bd9Sstevel@tonic-gate {
3217c478bd9Sstevel@tonic-gate if (tTd(64, 5))
322058561cbSjbeck sm_dprintf("milter_sys_read (%s): timeout %s data read in %s",
323058561cbSjbeck m->mf_name,
3247c478bd9Sstevel@tonic-gate started ? "during" : "before",
325058561cbSjbeck where);
3267c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0)
3277c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
328058561cbSjbeck "Milter (%s): timeout %s data read in %s",
329058561cbSjbeck m->mf_name,
3307c478bd9Sstevel@tonic-gate started ? "during" : "before",
331058561cbSjbeck where);
3327c478bd9Sstevel@tonic-gate milter_error(m, e);
3337c478bd9Sstevel@tonic-gate return NULL;
3347c478bd9Sstevel@tonic-gate }
3357c478bd9Sstevel@tonic-gate to -= now - readstart;
3367c478bd9Sstevel@tonic-gate readstart = now;
337058561cbSjbeck MILTER_TIMEOUT("read", to, false, started, where);
3387c478bd9Sstevel@tonic-gate }
3397c478bd9Sstevel@tonic-gate
3407c478bd9Sstevel@tonic-gate len = read(m->mf_sock, buf + curl, sz - curl);
3417c478bd9Sstevel@tonic-gate
3427c478bd9Sstevel@tonic-gate if (len < 0)
3437c478bd9Sstevel@tonic-gate {
3447c478bd9Sstevel@tonic-gate int save_errno = errno;
3457c478bd9Sstevel@tonic-gate
3467c478bd9Sstevel@tonic-gate if (tTd(64, 5))
347058561cbSjbeck sm_dprintf("milter_sys_read(%s): read returned %ld: %s\n",
3487c478bd9Sstevel@tonic-gate m->mf_name, (long) len,
3497c478bd9Sstevel@tonic-gate sm_errstring(save_errno));
3507c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0)
3517c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
3527c478bd9Sstevel@tonic-gate "Milter (%s): read returned %ld: %s",
3537c478bd9Sstevel@tonic-gate m->mf_name, (long) len,
3547c478bd9Sstevel@tonic-gate sm_errstring(save_errno));
3557c478bd9Sstevel@tonic-gate milter_error(m, e);
3567c478bd9Sstevel@tonic-gate return NULL;
3577c478bd9Sstevel@tonic-gate }
3587c478bd9Sstevel@tonic-gate
3597c478bd9Sstevel@tonic-gate started = true;
3607c478bd9Sstevel@tonic-gate curl += len;
3617c478bd9Sstevel@tonic-gate if (len == 0 || curl >= sz)
3627c478bd9Sstevel@tonic-gate break;
3637c478bd9Sstevel@tonic-gate
3647c478bd9Sstevel@tonic-gate }
3657c478bd9Sstevel@tonic-gate
3667c478bd9Sstevel@tonic-gate if (curl != sz)
3677c478bd9Sstevel@tonic-gate {
3687c478bd9Sstevel@tonic-gate if (tTd(64, 5))
369058561cbSjbeck sm_dprintf("milter_sys_read(%s): cmd read returned %ld, expecting %ld\n",
3707c478bd9Sstevel@tonic-gate m->mf_name, (long) curl, (long) sz);
3717c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0)
3727c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
373058561cbSjbeck "milter_sys_read(%s): cmd read returned %ld, expecting %ld",
3747c478bd9Sstevel@tonic-gate m->mf_name, (long) curl, (long) sz);
3757c478bd9Sstevel@tonic-gate milter_error(m, e);
3767c478bd9Sstevel@tonic-gate return NULL;
3777c478bd9Sstevel@tonic-gate }
3787c478bd9Sstevel@tonic-gate return buf;
3797c478bd9Sstevel@tonic-gate }
3807c478bd9Sstevel@tonic-gate
3817c478bd9Sstevel@tonic-gate static char *
milter_read(m,cmd,rlen,to,e,where)382058561cbSjbeck milter_read(m, cmd, rlen, to, e, where)
3837c478bd9Sstevel@tonic-gate struct milter *m;
3847c478bd9Sstevel@tonic-gate char *cmd;
3857c478bd9Sstevel@tonic-gate ssize_t *rlen;
3867c478bd9Sstevel@tonic-gate time_t to;
3877c478bd9Sstevel@tonic-gate ENVELOPE *e;
388058561cbSjbeck const char *where;
3897c478bd9Sstevel@tonic-gate {
3907c478bd9Sstevel@tonic-gate time_t readstart = 0;
3917c478bd9Sstevel@tonic-gate ssize_t expl;
3927c478bd9Sstevel@tonic-gate mi_int32 i;
393058561cbSjbeck # if MILTER_NO_NAGLE && defined(TCP_CORK)
3947c478bd9Sstevel@tonic-gate int cork = 0;
395058561cbSjbeck # endif /* MILTER_NO_NAGLE && defined(TCP_CORK) */
3967c478bd9Sstevel@tonic-gate char *buf;
3977c478bd9Sstevel@tonic-gate char data[MILTER_LEN_BYTES + 1];
3987c478bd9Sstevel@tonic-gate
3997c478bd9Sstevel@tonic-gate if (m->mf_sock < 0)
4007c478bd9Sstevel@tonic-gate {
4017c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0)
4027c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
403058561cbSjbeck "milter_read(%s): socket closed, where=%s",
404058561cbSjbeck m->mf_name, where);
4057c478bd9Sstevel@tonic-gate milter_error(m, e);
4067c478bd9Sstevel@tonic-gate return NULL;
4077c478bd9Sstevel@tonic-gate }
4087c478bd9Sstevel@tonic-gate
4097c478bd9Sstevel@tonic-gate *rlen = 0;
4107c478bd9Sstevel@tonic-gate *cmd = '\0';
4117c478bd9Sstevel@tonic-gate
4127c478bd9Sstevel@tonic-gate if (to > 0)
4137c478bd9Sstevel@tonic-gate readstart = curtime();
4147c478bd9Sstevel@tonic-gate
415058561cbSjbeck # if MILTER_NO_NAGLE && defined(TCP_CORK)
4167c478bd9Sstevel@tonic-gate setsockopt(m->mf_sock, IPPROTO_TCP, TCP_CORK, (char *)&cork,
4177c478bd9Sstevel@tonic-gate sizeof(cork));
418058561cbSjbeck # endif /* MILTER_NO_NAGLE && defined(TCP_CORK) */
4197c478bd9Sstevel@tonic-gate
420058561cbSjbeck if (milter_sysread(m, data, sizeof(data), to, e, where) == NULL)
4217c478bd9Sstevel@tonic-gate return NULL;
4227c478bd9Sstevel@tonic-gate
423058561cbSjbeck # if MILTER_NO_NAGLE && defined(TCP_CORK)
4247c478bd9Sstevel@tonic-gate cork = 1;
4257c478bd9Sstevel@tonic-gate setsockopt(m->mf_sock, IPPROTO_TCP, TCP_CORK, (char *)&cork,
4267c478bd9Sstevel@tonic-gate sizeof(cork));
427058561cbSjbeck # endif /* MILTER_NO_NAGLE && defined(TCP_CORK) */
4287c478bd9Sstevel@tonic-gate
4297c478bd9Sstevel@tonic-gate /* reset timeout */
4307c478bd9Sstevel@tonic-gate if (to > 0)
4317c478bd9Sstevel@tonic-gate {
4327c478bd9Sstevel@tonic-gate time_t now;
4337c478bd9Sstevel@tonic-gate
4347c478bd9Sstevel@tonic-gate now = curtime();
4357c478bd9Sstevel@tonic-gate if (now - readstart >= to)
4367c478bd9Sstevel@tonic-gate {
4377c478bd9Sstevel@tonic-gate if (tTd(64, 5))
438058561cbSjbeck sm_dprintf("milter_read(%s): timeout before data read, where=%s\n",
439058561cbSjbeck m->mf_name, where);
4407c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0)
4417c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
442058561cbSjbeck "Milter read(%s): timeout before data read, where=%s",
443058561cbSjbeck m->mf_name, where);
4447c478bd9Sstevel@tonic-gate milter_error(m, e);
4457c478bd9Sstevel@tonic-gate return NULL;
4467c478bd9Sstevel@tonic-gate }
4477c478bd9Sstevel@tonic-gate to -= now - readstart;
4487c478bd9Sstevel@tonic-gate }
4497c478bd9Sstevel@tonic-gate
4507c478bd9Sstevel@tonic-gate *cmd = data[MILTER_LEN_BYTES];
4517c478bd9Sstevel@tonic-gate data[MILTER_LEN_BYTES] = '\0';
4527c478bd9Sstevel@tonic-gate (void) memcpy(&i, data, MILTER_LEN_BYTES);
4537c478bd9Sstevel@tonic-gate expl = ntohl(i) - 1;
4547c478bd9Sstevel@tonic-gate
4557c478bd9Sstevel@tonic-gate if (tTd(64, 25))
4567c478bd9Sstevel@tonic-gate sm_dprintf("milter_read(%s): expecting %ld bytes\n",
4577c478bd9Sstevel@tonic-gate m->mf_name, (long) expl);
4587c478bd9Sstevel@tonic-gate
4597c478bd9Sstevel@tonic-gate if (expl < 0)
4607c478bd9Sstevel@tonic-gate {
4617c478bd9Sstevel@tonic-gate if (tTd(64, 5))
462058561cbSjbeck sm_dprintf("milter_read(%s): read size %ld out of range, where=%s\n",
463058561cbSjbeck m->mf_name, (long) expl, where);
4647c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0)
4657c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
466058561cbSjbeck "milter_read(%s): read size %ld out of range, where=%s",
467058561cbSjbeck m->mf_name, (long) expl, where);
4687c478bd9Sstevel@tonic-gate milter_error(m, e);
4697c478bd9Sstevel@tonic-gate return NULL;
4707c478bd9Sstevel@tonic-gate }
4717c478bd9Sstevel@tonic-gate
4727c478bd9Sstevel@tonic-gate if (expl == 0)
4737c478bd9Sstevel@tonic-gate return NULL;
4747c478bd9Sstevel@tonic-gate
4757c478bd9Sstevel@tonic-gate buf = (char *) xalloc(expl);
4767c478bd9Sstevel@tonic-gate
477058561cbSjbeck if (milter_sysread(m, buf, expl, to, e, where) == NULL)
4787c478bd9Sstevel@tonic-gate {
4797c478bd9Sstevel@tonic-gate sm_free(buf); /* XXX */
4807c478bd9Sstevel@tonic-gate return NULL;
4817c478bd9Sstevel@tonic-gate }
4827c478bd9Sstevel@tonic-gate
4837c478bd9Sstevel@tonic-gate if (tTd(64, 50))
4847c478bd9Sstevel@tonic-gate sm_dprintf("milter_read(%s): Returning %*s\n",
4857c478bd9Sstevel@tonic-gate m->mf_name, (int) expl, buf);
4867c478bd9Sstevel@tonic-gate *rlen = expl;
4877c478bd9Sstevel@tonic-gate return buf;
4887c478bd9Sstevel@tonic-gate }
4897c478bd9Sstevel@tonic-gate
4907c478bd9Sstevel@tonic-gate /*
4917c478bd9Sstevel@tonic-gate ** MILTER_WRITE -- write to a remote milter filter
4927c478bd9Sstevel@tonic-gate **
4937c478bd9Sstevel@tonic-gate ** Parameters:
4947c478bd9Sstevel@tonic-gate ** m -- milter to read from.
4957c478bd9Sstevel@tonic-gate ** cmd -- command to send.
4967c478bd9Sstevel@tonic-gate ** buf -- optional command data.
4977c478bd9Sstevel@tonic-gate ** len -- length of buf.
4987c478bd9Sstevel@tonic-gate ** to -- timeout in seconds.
4997c478bd9Sstevel@tonic-gate ** e -- current envelope.
5007c478bd9Sstevel@tonic-gate **
5017c478bd9Sstevel@tonic-gate ** Returns:
5027c478bd9Sstevel@tonic-gate ** buf if successful, NULL otherwise
5037c478bd9Sstevel@tonic-gate ** Not actually used anywhere but function prototype
5047c478bd9Sstevel@tonic-gate ** must match milter_read()
5057c478bd9Sstevel@tonic-gate */
5067c478bd9Sstevel@tonic-gate
5077c478bd9Sstevel@tonic-gate static char *
milter_write(m,cmd,buf,len,to,e,where)508058561cbSjbeck milter_write(m, cmd, buf, len, to, e, where)
5097c478bd9Sstevel@tonic-gate struct milter *m;
510058561cbSjbeck int cmd;
5117c478bd9Sstevel@tonic-gate char *buf;
5127c478bd9Sstevel@tonic-gate ssize_t len;
5137c478bd9Sstevel@tonic-gate time_t to;
5147c478bd9Sstevel@tonic-gate ENVELOPE *e;
515058561cbSjbeck const char *where;
5167c478bd9Sstevel@tonic-gate {
5177c478bd9Sstevel@tonic-gate ssize_t sl, i;
5187c478bd9Sstevel@tonic-gate int num_vectors;
5197c478bd9Sstevel@tonic-gate mi_int32 nl;
520058561cbSjbeck char command = (char) cmd;
5217c478bd9Sstevel@tonic-gate char data[MILTER_LEN_BYTES + 1];
5227c478bd9Sstevel@tonic-gate bool started = false;
5237c478bd9Sstevel@tonic-gate struct iovec vector[2];
5247c478bd9Sstevel@tonic-gate
5257c478bd9Sstevel@tonic-gate /*
5267c478bd9Sstevel@tonic-gate ** At most two buffers will be written, though
5277c478bd9Sstevel@tonic-gate ** only one may actually be used (see num_vectors).
5287c478bd9Sstevel@tonic-gate ** The first is the size/command and the second is the command data.
5297c478bd9Sstevel@tonic-gate */
5307c478bd9Sstevel@tonic-gate
5317c478bd9Sstevel@tonic-gate if (len < 0 || len > MilterMaxDataSize)
5327c478bd9Sstevel@tonic-gate {
5337c478bd9Sstevel@tonic-gate if (tTd(64, 5))
534*e9af4bc0SJohn Beck {
535*e9af4bc0SJohn Beck sm_dprintf("milter_write(%s): length %ld out of range, cmd=%c\n",
536*e9af4bc0SJohn Beck m->mf_name, (long) len, command);
537*e9af4bc0SJohn Beck sm_dprintf("milter_write(%s): buf=%s\n",
538*e9af4bc0SJohn Beck m->mf_name, str2prt(buf));
539*e9af4bc0SJohn Beck }
5407c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0)
5417c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
542*e9af4bc0SJohn Beck "milter_write(%s): length %ld out of range, cmd=%c",
543*e9af4bc0SJohn Beck m->mf_name, (long) len, command);
5447c478bd9Sstevel@tonic-gate milter_error(m, e);
5457c478bd9Sstevel@tonic-gate return NULL;
5467c478bd9Sstevel@tonic-gate }
5477c478bd9Sstevel@tonic-gate if (m->mf_sock < 0)
5487c478bd9Sstevel@tonic-gate {
5497c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0)
5507c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
5517c478bd9Sstevel@tonic-gate "milter_write(%s): socket closed",
5527c478bd9Sstevel@tonic-gate m->mf_name);
5537c478bd9Sstevel@tonic-gate milter_error(m, e);
5547c478bd9Sstevel@tonic-gate return NULL;
5557c478bd9Sstevel@tonic-gate }
5567c478bd9Sstevel@tonic-gate
5577c478bd9Sstevel@tonic-gate if (tTd(64, 20))
5587c478bd9Sstevel@tonic-gate sm_dprintf("milter_write(%s): cmd %c, len %ld\n",
559058561cbSjbeck m->mf_name, command, (long) len);
5607c478bd9Sstevel@tonic-gate
561058561cbSjbeck nl = htonl(len + 1); /* add 1 for the command char */
5627c478bd9Sstevel@tonic-gate (void) memcpy(data, (char *) &nl, MILTER_LEN_BYTES);
563058561cbSjbeck data[MILTER_LEN_BYTES] = command;
5647c478bd9Sstevel@tonic-gate sl = MILTER_LEN_BYTES + 1;
5657c478bd9Sstevel@tonic-gate
5667c478bd9Sstevel@tonic-gate /* set up the vector for the size / command */
5677c478bd9Sstevel@tonic-gate vector[0].iov_base = (void *) data;
5687c478bd9Sstevel@tonic-gate vector[0].iov_len = sl;
5697c478bd9Sstevel@tonic-gate
5707c478bd9Sstevel@tonic-gate /*
5717c478bd9Sstevel@tonic-gate ** Determine if there is command data. If so, there will be two
5727c478bd9Sstevel@tonic-gate ** vectors. If not, there will be only one. The vectors are set
5737c478bd9Sstevel@tonic-gate ** up here and 'num_vectors' and 'sl' are set appropriately.
5747c478bd9Sstevel@tonic-gate */
5757c478bd9Sstevel@tonic-gate
5767c478bd9Sstevel@tonic-gate /* NOTE: len<0 has already been checked for. Pedantic */
5777c478bd9Sstevel@tonic-gate if (len <= 0 || buf == NULL)
5787c478bd9Sstevel@tonic-gate {
5797c478bd9Sstevel@tonic-gate /* There is no command data -- only a size / command data */
5807c478bd9Sstevel@tonic-gate num_vectors = 1;
5817c478bd9Sstevel@tonic-gate }
5827c478bd9Sstevel@tonic-gate else
5837c478bd9Sstevel@tonic-gate {
5847c478bd9Sstevel@tonic-gate /*
5857c478bd9Sstevel@tonic-gate ** There is both size / command and command data.
5867c478bd9Sstevel@tonic-gate ** Set up the vector for the command data.
5877c478bd9Sstevel@tonic-gate */
5887c478bd9Sstevel@tonic-gate
5897c478bd9Sstevel@tonic-gate num_vectors = 2;
5907c478bd9Sstevel@tonic-gate sl += len;
5917c478bd9Sstevel@tonic-gate vector[1].iov_base = (void *) buf;
5927c478bd9Sstevel@tonic-gate vector[1].iov_len = len;
5937c478bd9Sstevel@tonic-gate
5947c478bd9Sstevel@tonic-gate if (tTd(64, 50))
5957c478bd9Sstevel@tonic-gate sm_dprintf("milter_write(%s): Sending %*s\n",
5967c478bd9Sstevel@tonic-gate m->mf_name, (int) len, buf);
5977c478bd9Sstevel@tonic-gate }
5987c478bd9Sstevel@tonic-gate
5997c478bd9Sstevel@tonic-gate if (to > 0)
600058561cbSjbeck MILTER_TIMEOUT("write", to, true, started, where);
6017c478bd9Sstevel@tonic-gate
6027c478bd9Sstevel@tonic-gate /* write the vector(s) */
6037c478bd9Sstevel@tonic-gate i = writev(m->mf_sock, vector, num_vectors);
6047c478bd9Sstevel@tonic-gate if (i != sl)
6057c478bd9Sstevel@tonic-gate {
6067c478bd9Sstevel@tonic-gate int save_errno = errno;
6077c478bd9Sstevel@tonic-gate
6087c478bd9Sstevel@tonic-gate if (tTd(64, 5))
6097c478bd9Sstevel@tonic-gate sm_dprintf("milter_write(%s): write(%c) returned %ld, expected %ld: %s\n",
610058561cbSjbeck m->mf_name, command, (long) i, (long) sl,
6117c478bd9Sstevel@tonic-gate sm_errstring(save_errno));
6127c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0)
6137c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
6147c478bd9Sstevel@tonic-gate "Milter (%s): write(%c) returned %ld, expected %ld: %s",
615058561cbSjbeck m->mf_name, command, (long) i, (long) sl,
6167c478bd9Sstevel@tonic-gate sm_errstring(save_errno));
6177c478bd9Sstevel@tonic-gate milter_error(m, e);
6187c478bd9Sstevel@tonic-gate return NULL;
6197c478bd9Sstevel@tonic-gate }
6207c478bd9Sstevel@tonic-gate return buf;
6217c478bd9Sstevel@tonic-gate }
6227c478bd9Sstevel@tonic-gate
6237c478bd9Sstevel@tonic-gate /*
6247c478bd9Sstevel@tonic-gate ** Utility functions
6257c478bd9Sstevel@tonic-gate */
6267c478bd9Sstevel@tonic-gate
6277c478bd9Sstevel@tonic-gate /*
6287c478bd9Sstevel@tonic-gate ** MILTER_OPEN -- connect to remote milter filter
6297c478bd9Sstevel@tonic-gate **
6307c478bd9Sstevel@tonic-gate ** Parameters:
6317c478bd9Sstevel@tonic-gate ** m -- milter to connect to.
6327c478bd9Sstevel@tonic-gate ** parseonly -- parse but don't connect.
6337c478bd9Sstevel@tonic-gate ** e -- current envelope.
6347c478bd9Sstevel@tonic-gate **
6357c478bd9Sstevel@tonic-gate ** Returns:
6367c478bd9Sstevel@tonic-gate ** connected socket if successful && !parseonly,
6377c478bd9Sstevel@tonic-gate ** 0 upon parse success if parseonly,
6387c478bd9Sstevel@tonic-gate ** -1 otherwise.
6397c478bd9Sstevel@tonic-gate */
6407c478bd9Sstevel@tonic-gate
6417c478bd9Sstevel@tonic-gate static jmp_buf MilterConnectTimeout;
6427c478bd9Sstevel@tonic-gate
6437c478bd9Sstevel@tonic-gate static int
milter_open(m,parseonly,e)6447c478bd9Sstevel@tonic-gate milter_open(m, parseonly, e)
6457c478bd9Sstevel@tonic-gate struct milter *m;
6467c478bd9Sstevel@tonic-gate bool parseonly;
6477c478bd9Sstevel@tonic-gate ENVELOPE *e;
6487c478bd9Sstevel@tonic-gate {
6497c478bd9Sstevel@tonic-gate int sock = 0;
6507c478bd9Sstevel@tonic-gate SOCKADDR_LEN_T addrlen = 0;
6517c478bd9Sstevel@tonic-gate int addrno = 0;
6527c478bd9Sstevel@tonic-gate int save_errno;
6537c478bd9Sstevel@tonic-gate char *p;
6547c478bd9Sstevel@tonic-gate char *colon;
6557c478bd9Sstevel@tonic-gate char *at;
6567c478bd9Sstevel@tonic-gate struct hostent *hp = NULL;
6577c478bd9Sstevel@tonic-gate SOCKADDR addr;
6587c478bd9Sstevel@tonic-gate
6597c478bd9Sstevel@tonic-gate if (m->mf_conn == NULL || m->mf_conn[0] == '\0')
6607c478bd9Sstevel@tonic-gate {
6617c478bd9Sstevel@tonic-gate if (tTd(64, 5))
6627c478bd9Sstevel@tonic-gate sm_dprintf("X%s: empty or missing socket information\n",
6637c478bd9Sstevel@tonic-gate m->mf_name);
6647c478bd9Sstevel@tonic-gate if (parseonly)
6657c478bd9Sstevel@tonic-gate syserr("X%s: empty or missing socket information",
6667c478bd9Sstevel@tonic-gate m->mf_name);
6677c478bd9Sstevel@tonic-gate else if (MilterLogLevel > 0)
6687c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
6697c478bd9Sstevel@tonic-gate "Milter (%s): empty or missing socket information",
6707c478bd9Sstevel@tonic-gate m->mf_name);
6717c478bd9Sstevel@tonic-gate milter_error(m, e);
6727c478bd9Sstevel@tonic-gate return -1;
6737c478bd9Sstevel@tonic-gate }
6747c478bd9Sstevel@tonic-gate
6757c478bd9Sstevel@tonic-gate /* protocol:filename or protocol:port@host */
676058561cbSjbeck memset(&addr, '\0', sizeof(addr));
6777c478bd9Sstevel@tonic-gate p = m->mf_conn;
6787c478bd9Sstevel@tonic-gate colon = strchr(p, ':');
6797c478bd9Sstevel@tonic-gate if (colon != NULL)
6807c478bd9Sstevel@tonic-gate {
6817c478bd9Sstevel@tonic-gate *colon = '\0';
6827c478bd9Sstevel@tonic-gate
6837c478bd9Sstevel@tonic-gate if (*p == '\0')
6847c478bd9Sstevel@tonic-gate {
6857c478bd9Sstevel@tonic-gate # if NETUNIX
6867c478bd9Sstevel@tonic-gate /* default to AF_UNIX */
6877c478bd9Sstevel@tonic-gate addr.sa.sa_family = AF_UNIX;
6887c478bd9Sstevel@tonic-gate # else /* NETUNIX */
6897c478bd9Sstevel@tonic-gate # if NETINET
6907c478bd9Sstevel@tonic-gate /* default to AF_INET */
6917c478bd9Sstevel@tonic-gate addr.sa.sa_family = AF_INET;
6927c478bd9Sstevel@tonic-gate # else /* NETINET */
6937c478bd9Sstevel@tonic-gate # if NETINET6
6947c478bd9Sstevel@tonic-gate /* default to AF_INET6 */
6957c478bd9Sstevel@tonic-gate addr.sa.sa_family = AF_INET6;
6967c478bd9Sstevel@tonic-gate # else /* NETINET6 */
6977c478bd9Sstevel@tonic-gate /* no protocols available */
6987c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0)
6997c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
7007c478bd9Sstevel@tonic-gate "Milter (%s): no valid socket protocols available",
7017c478bd9Sstevel@tonic-gate m->mf_name);
7027c478bd9Sstevel@tonic-gate milter_error(m, e);
7037c478bd9Sstevel@tonic-gate return -1;
7047c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
7057c478bd9Sstevel@tonic-gate # endif /* NETINET */
7067c478bd9Sstevel@tonic-gate # endif /* NETUNIX */
7077c478bd9Sstevel@tonic-gate }
7087c478bd9Sstevel@tonic-gate # if NETUNIX
7097c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(p, "unix") == 0 ||
7107c478bd9Sstevel@tonic-gate sm_strcasecmp(p, "local") == 0)
7117c478bd9Sstevel@tonic-gate addr.sa.sa_family = AF_UNIX;
7127c478bd9Sstevel@tonic-gate # endif /* NETUNIX */
7137c478bd9Sstevel@tonic-gate # if NETINET
7147c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(p, "inet") == 0)
7157c478bd9Sstevel@tonic-gate addr.sa.sa_family = AF_INET;
7167c478bd9Sstevel@tonic-gate # endif /* NETINET */
7177c478bd9Sstevel@tonic-gate # if NETINET6
7187c478bd9Sstevel@tonic-gate else if (sm_strcasecmp(p, "inet6") == 0)
7197c478bd9Sstevel@tonic-gate addr.sa.sa_family = AF_INET6;
7207c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
7217c478bd9Sstevel@tonic-gate else
7227c478bd9Sstevel@tonic-gate {
7237c478bd9Sstevel@tonic-gate # ifdef EPROTONOSUPPORT
7247c478bd9Sstevel@tonic-gate errno = EPROTONOSUPPORT;
7257c478bd9Sstevel@tonic-gate # else /* EPROTONOSUPPORT */
7267c478bd9Sstevel@tonic-gate errno = EINVAL;
7277c478bd9Sstevel@tonic-gate # endif /* EPROTONOSUPPORT */
7287c478bd9Sstevel@tonic-gate if (tTd(64, 5))
7297c478bd9Sstevel@tonic-gate sm_dprintf("X%s: unknown socket type %s\n",
7307c478bd9Sstevel@tonic-gate m->mf_name, p);
7317c478bd9Sstevel@tonic-gate if (parseonly)
7327c478bd9Sstevel@tonic-gate syserr("X%s: unknown socket type %s",
7337c478bd9Sstevel@tonic-gate m->mf_name, p);
7347c478bd9Sstevel@tonic-gate else if (MilterLogLevel > 0)
7357c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
7367c478bd9Sstevel@tonic-gate "Milter (%s): unknown socket type %s",
7377c478bd9Sstevel@tonic-gate m->mf_name, p);
7387c478bd9Sstevel@tonic-gate milter_error(m, e);
7397c478bd9Sstevel@tonic-gate return -1;
7407c478bd9Sstevel@tonic-gate }
7417c478bd9Sstevel@tonic-gate *colon++ = ':';
7427c478bd9Sstevel@tonic-gate }
7437c478bd9Sstevel@tonic-gate else
7447c478bd9Sstevel@tonic-gate {
7457c478bd9Sstevel@tonic-gate /* default to AF_UNIX */
7467c478bd9Sstevel@tonic-gate addr.sa.sa_family = AF_UNIX;
7477c478bd9Sstevel@tonic-gate colon = p;
7487c478bd9Sstevel@tonic-gate }
7497c478bd9Sstevel@tonic-gate
7507c478bd9Sstevel@tonic-gate # if NETUNIX
7517c478bd9Sstevel@tonic-gate if (addr.sa.sa_family == AF_UNIX)
7527c478bd9Sstevel@tonic-gate {
7537c478bd9Sstevel@tonic-gate long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_EXECOK;
7547c478bd9Sstevel@tonic-gate
7557c478bd9Sstevel@tonic-gate at = colon;
756058561cbSjbeck if (strlen(colon) >= sizeof(addr.sunix.sun_path))
7577c478bd9Sstevel@tonic-gate {
7587c478bd9Sstevel@tonic-gate if (tTd(64, 5))
7597c478bd9Sstevel@tonic-gate sm_dprintf("X%s: local socket name %s too long\n",
7607c478bd9Sstevel@tonic-gate m->mf_name, colon);
7617c478bd9Sstevel@tonic-gate errno = EINVAL;
7627c478bd9Sstevel@tonic-gate if (parseonly)
7637c478bd9Sstevel@tonic-gate syserr("X%s: local socket name %s too long",
7647c478bd9Sstevel@tonic-gate m->mf_name, colon);
7657c478bd9Sstevel@tonic-gate else if (MilterLogLevel > 0)
7667c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
7677c478bd9Sstevel@tonic-gate "Milter (%s): local socket name %s too long",
7687c478bd9Sstevel@tonic-gate m->mf_name, colon);
7697c478bd9Sstevel@tonic-gate milter_error(m, e);
7707c478bd9Sstevel@tonic-gate return -1;
7717c478bd9Sstevel@tonic-gate }
7727c478bd9Sstevel@tonic-gate errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff,
7737c478bd9Sstevel@tonic-gate S_IRUSR|S_IWUSR, NULL);
7747c478bd9Sstevel@tonic-gate
7757c478bd9Sstevel@tonic-gate /* if just parsing .cf file, socket doesn't need to exist */
7767c478bd9Sstevel@tonic-gate if (parseonly && errno == ENOENT)
7777c478bd9Sstevel@tonic-gate {
7787c478bd9Sstevel@tonic-gate if (OpMode == MD_DAEMON ||
7797c478bd9Sstevel@tonic-gate OpMode == MD_FGDAEMON)
7807c478bd9Sstevel@tonic-gate (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT,
7817c478bd9Sstevel@tonic-gate "WARNING: X%s: local socket name %s missing\n",
7827c478bd9Sstevel@tonic-gate m->mf_name, colon);
7837c478bd9Sstevel@tonic-gate }
7847c478bd9Sstevel@tonic-gate else if (errno != 0)
7857c478bd9Sstevel@tonic-gate {
7867c478bd9Sstevel@tonic-gate /* if not safe, don't create */
7877c478bd9Sstevel@tonic-gate save_errno = errno;
7887c478bd9Sstevel@tonic-gate if (tTd(64, 5))
7897c478bd9Sstevel@tonic-gate sm_dprintf("X%s: local socket name %s unsafe\n",
7907c478bd9Sstevel@tonic-gate m->mf_name, colon);
7917c478bd9Sstevel@tonic-gate errno = save_errno;
7927c478bd9Sstevel@tonic-gate if (parseonly)
7937c478bd9Sstevel@tonic-gate {
7947c478bd9Sstevel@tonic-gate if (OpMode == MD_DAEMON ||
7957c478bd9Sstevel@tonic-gate OpMode == MD_FGDAEMON ||
7967c478bd9Sstevel@tonic-gate OpMode == MD_SMTP)
7977c478bd9Sstevel@tonic-gate syserr("X%s: local socket name %s unsafe",
7987c478bd9Sstevel@tonic-gate m->mf_name, colon);
7997c478bd9Sstevel@tonic-gate }
8007c478bd9Sstevel@tonic-gate else if (MilterLogLevel > 0)
8017c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
8027c478bd9Sstevel@tonic-gate "Milter (%s): local socket name %s unsafe",
8037c478bd9Sstevel@tonic-gate m->mf_name, colon);
8047c478bd9Sstevel@tonic-gate milter_error(m, e);
8057c478bd9Sstevel@tonic-gate return -1;
8067c478bd9Sstevel@tonic-gate }
8077c478bd9Sstevel@tonic-gate
8087c478bd9Sstevel@tonic-gate (void) sm_strlcpy(addr.sunix.sun_path, colon,
809058561cbSjbeck sizeof(addr.sunix.sun_path));
810058561cbSjbeck addrlen = sizeof(struct sockaddr_un);
8117c478bd9Sstevel@tonic-gate }
8127c478bd9Sstevel@tonic-gate else
8137c478bd9Sstevel@tonic-gate # endif /* NETUNIX */
8147c478bd9Sstevel@tonic-gate # if NETINET || NETINET6
8157c478bd9Sstevel@tonic-gate if (false
8167c478bd9Sstevel@tonic-gate # if NETINET
8177c478bd9Sstevel@tonic-gate || addr.sa.sa_family == AF_INET
8187c478bd9Sstevel@tonic-gate # endif /* NETINET */
8197c478bd9Sstevel@tonic-gate # if NETINET6
8207c478bd9Sstevel@tonic-gate || addr.sa.sa_family == AF_INET6
8217c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
8227c478bd9Sstevel@tonic-gate )
8237c478bd9Sstevel@tonic-gate {
8247c478bd9Sstevel@tonic-gate unsigned short port;
8257c478bd9Sstevel@tonic-gate
8267c478bd9Sstevel@tonic-gate /* Parse port@host */
8277c478bd9Sstevel@tonic-gate at = strchr(colon, '@');
8287c478bd9Sstevel@tonic-gate if (at == NULL)
8297c478bd9Sstevel@tonic-gate {
8307c478bd9Sstevel@tonic-gate if (tTd(64, 5))
8317c478bd9Sstevel@tonic-gate sm_dprintf("X%s: bad address %s (expected port@host)\n",
8327c478bd9Sstevel@tonic-gate m->mf_name, colon);
8337c478bd9Sstevel@tonic-gate if (parseonly)
8347c478bd9Sstevel@tonic-gate syserr("X%s: bad address %s (expected port@host)",
8357c478bd9Sstevel@tonic-gate m->mf_name, colon);
8367c478bd9Sstevel@tonic-gate else if (MilterLogLevel > 0)
8377c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
8387c478bd9Sstevel@tonic-gate "Milter (%s): bad address %s (expected port@host)",
8397c478bd9Sstevel@tonic-gate m->mf_name, colon);
8407c478bd9Sstevel@tonic-gate milter_error(m, e);
8417c478bd9Sstevel@tonic-gate return -1;
8427c478bd9Sstevel@tonic-gate }
8437c478bd9Sstevel@tonic-gate *at = '\0';
8447c478bd9Sstevel@tonic-gate if (isascii(*colon) && isdigit(*colon))
8457c478bd9Sstevel@tonic-gate port = htons((unsigned short) atoi(colon));
8467c478bd9Sstevel@tonic-gate else
8477c478bd9Sstevel@tonic-gate {
8487c478bd9Sstevel@tonic-gate # ifdef NO_GETSERVBYNAME
8497c478bd9Sstevel@tonic-gate if (tTd(64, 5))
8507c478bd9Sstevel@tonic-gate sm_dprintf("X%s: invalid port number %s\n",
8517c478bd9Sstevel@tonic-gate m->mf_name, colon);
8527c478bd9Sstevel@tonic-gate if (parseonly)
8537c478bd9Sstevel@tonic-gate syserr("X%s: invalid port number %s",
8547c478bd9Sstevel@tonic-gate m->mf_name, colon);
8557c478bd9Sstevel@tonic-gate else if (MilterLogLevel > 0)
8567c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
8577c478bd9Sstevel@tonic-gate "Milter (%s): invalid port number %s",
8587c478bd9Sstevel@tonic-gate m->mf_name, colon);
8597c478bd9Sstevel@tonic-gate milter_error(m, e);
8607c478bd9Sstevel@tonic-gate return -1;
8617c478bd9Sstevel@tonic-gate # else /* NO_GETSERVBYNAME */
862058561cbSjbeck struct servent *sp;
8637c478bd9Sstevel@tonic-gate
8647c478bd9Sstevel@tonic-gate sp = getservbyname(colon, "tcp");
8657c478bd9Sstevel@tonic-gate if (sp == NULL)
8667c478bd9Sstevel@tonic-gate {
8677c478bd9Sstevel@tonic-gate save_errno = errno;
8687c478bd9Sstevel@tonic-gate if (tTd(64, 5))
8697c478bd9Sstevel@tonic-gate sm_dprintf("X%s: unknown port name %s\n",
8707c478bd9Sstevel@tonic-gate m->mf_name, colon);
8717c478bd9Sstevel@tonic-gate errno = save_errno;
8727c478bd9Sstevel@tonic-gate if (parseonly)
8737c478bd9Sstevel@tonic-gate syserr("X%s: unknown port name %s",
8747c478bd9Sstevel@tonic-gate m->mf_name, colon);
8757c478bd9Sstevel@tonic-gate else if (MilterLogLevel > 0)
8767c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
8777c478bd9Sstevel@tonic-gate "Milter (%s): unknown port name %s",
8787c478bd9Sstevel@tonic-gate m->mf_name, colon);
8797c478bd9Sstevel@tonic-gate milter_error(m, e);
8807c478bd9Sstevel@tonic-gate return -1;
8817c478bd9Sstevel@tonic-gate }
8827c478bd9Sstevel@tonic-gate port = sp->s_port;
8837c478bd9Sstevel@tonic-gate # endif /* NO_GETSERVBYNAME */
8847c478bd9Sstevel@tonic-gate }
8857c478bd9Sstevel@tonic-gate *at++ = '@';
8867c478bd9Sstevel@tonic-gate if (*at == '[')
8877c478bd9Sstevel@tonic-gate {
8887c478bd9Sstevel@tonic-gate char *end;
8897c478bd9Sstevel@tonic-gate
8907c478bd9Sstevel@tonic-gate end = strchr(at, ']');
8917c478bd9Sstevel@tonic-gate if (end != NULL)
8927c478bd9Sstevel@tonic-gate {
8937c478bd9Sstevel@tonic-gate bool found = false;
8947c478bd9Sstevel@tonic-gate # if NETINET
8957c478bd9Sstevel@tonic-gate unsigned long hid = INADDR_NONE;
8967c478bd9Sstevel@tonic-gate # endif /* NETINET */
8977c478bd9Sstevel@tonic-gate # if NETINET6
8987c478bd9Sstevel@tonic-gate struct sockaddr_in6 hid6;
8997c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
9007c478bd9Sstevel@tonic-gate
9017c478bd9Sstevel@tonic-gate *end = '\0';
9027c478bd9Sstevel@tonic-gate # if NETINET
9037c478bd9Sstevel@tonic-gate if (addr.sa.sa_family == AF_INET &&
9047c478bd9Sstevel@tonic-gate (hid = inet_addr(&at[1])) != INADDR_NONE)
9057c478bd9Sstevel@tonic-gate {
9067c478bd9Sstevel@tonic-gate addr.sin.sin_addr.s_addr = hid;
9077c478bd9Sstevel@tonic-gate addr.sin.sin_port = port;
9087c478bd9Sstevel@tonic-gate found = true;
9097c478bd9Sstevel@tonic-gate }
9107c478bd9Sstevel@tonic-gate # endif /* NETINET */
9117c478bd9Sstevel@tonic-gate # if NETINET6
912058561cbSjbeck (void) memset(&hid6, '\0', sizeof(hid6));
9137c478bd9Sstevel@tonic-gate if (addr.sa.sa_family == AF_INET6 &&
9147c478bd9Sstevel@tonic-gate anynet_pton(AF_INET6, &at[1],
9157c478bd9Sstevel@tonic-gate &hid6.sin6_addr) == 1)
9167c478bd9Sstevel@tonic-gate {
9177c478bd9Sstevel@tonic-gate addr.sin6.sin6_addr = hid6.sin6_addr;
9187c478bd9Sstevel@tonic-gate addr.sin6.sin6_port = port;
9197c478bd9Sstevel@tonic-gate found = true;
9207c478bd9Sstevel@tonic-gate }
9217c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
9227c478bd9Sstevel@tonic-gate *end = ']';
9237c478bd9Sstevel@tonic-gate if (!found)
9247c478bd9Sstevel@tonic-gate {
9257c478bd9Sstevel@tonic-gate if (tTd(64, 5))
9267c478bd9Sstevel@tonic-gate sm_dprintf("X%s: Invalid numeric domain spec \"%s\"\n",
9277c478bd9Sstevel@tonic-gate m->mf_name, at);
9287c478bd9Sstevel@tonic-gate if (parseonly)
9297c478bd9Sstevel@tonic-gate syserr("X%s: Invalid numeric domain spec \"%s\"",
9307c478bd9Sstevel@tonic-gate m->mf_name, at);
9317c478bd9Sstevel@tonic-gate else if (MilterLogLevel > 0)
9327c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
9337c478bd9Sstevel@tonic-gate "Milter (%s): Invalid numeric domain spec \"%s\"",
9347c478bd9Sstevel@tonic-gate m->mf_name, at);
9357c478bd9Sstevel@tonic-gate milter_error(m, e);
9367c478bd9Sstevel@tonic-gate return -1;
9377c478bd9Sstevel@tonic-gate }
9387c478bd9Sstevel@tonic-gate }
9397c478bd9Sstevel@tonic-gate else
9407c478bd9Sstevel@tonic-gate {
9417c478bd9Sstevel@tonic-gate if (tTd(64, 5))
9427c478bd9Sstevel@tonic-gate sm_dprintf("X%s: Invalid numeric domain spec \"%s\"\n",
9437c478bd9Sstevel@tonic-gate m->mf_name, at);
9447c478bd9Sstevel@tonic-gate if (parseonly)
9457c478bd9Sstevel@tonic-gate syserr("X%s: Invalid numeric domain spec \"%s\"",
9467c478bd9Sstevel@tonic-gate m->mf_name, at);
9477c478bd9Sstevel@tonic-gate else if (MilterLogLevel > 0)
9487c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
9497c478bd9Sstevel@tonic-gate "Milter (%s): Invalid numeric domain spec \"%s\"",
9507c478bd9Sstevel@tonic-gate m->mf_name, at);
9517c478bd9Sstevel@tonic-gate milter_error(m, e);
9527c478bd9Sstevel@tonic-gate return -1;
9537c478bd9Sstevel@tonic-gate }
9547c478bd9Sstevel@tonic-gate }
9557c478bd9Sstevel@tonic-gate else
9567c478bd9Sstevel@tonic-gate {
9577c478bd9Sstevel@tonic-gate hp = sm_gethostbyname(at, addr.sa.sa_family);
9587c478bd9Sstevel@tonic-gate if (hp == NULL)
9597c478bd9Sstevel@tonic-gate {
9607c478bd9Sstevel@tonic-gate save_errno = errno;
9617c478bd9Sstevel@tonic-gate if (tTd(64, 5))
9627c478bd9Sstevel@tonic-gate sm_dprintf("X%s: Unknown host name %s\n",
9637c478bd9Sstevel@tonic-gate m->mf_name, at);
9647c478bd9Sstevel@tonic-gate errno = save_errno;
9657c478bd9Sstevel@tonic-gate if (parseonly)
9667c478bd9Sstevel@tonic-gate syserr("X%s: Unknown host name %s",
9677c478bd9Sstevel@tonic-gate m->mf_name, at);
9687c478bd9Sstevel@tonic-gate else if (MilterLogLevel > 0)
9697c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
9707c478bd9Sstevel@tonic-gate "Milter (%s): Unknown host name %s",
9717c478bd9Sstevel@tonic-gate m->mf_name, at);
9727c478bd9Sstevel@tonic-gate milter_error(m, e);
9737c478bd9Sstevel@tonic-gate return -1;
9747c478bd9Sstevel@tonic-gate }
9757c478bd9Sstevel@tonic-gate addr.sa.sa_family = hp->h_addrtype;
9767c478bd9Sstevel@tonic-gate switch (hp->h_addrtype)
9777c478bd9Sstevel@tonic-gate {
9787c478bd9Sstevel@tonic-gate # if NETINET
9797c478bd9Sstevel@tonic-gate case AF_INET:
9807c478bd9Sstevel@tonic-gate memmove(&addr.sin.sin_addr,
9817c478bd9Sstevel@tonic-gate hp->h_addr, INADDRSZ);
9827c478bd9Sstevel@tonic-gate addr.sin.sin_port = port;
983058561cbSjbeck addrlen = sizeof(struct sockaddr_in);
9847c478bd9Sstevel@tonic-gate addrno = 1;
9857c478bd9Sstevel@tonic-gate break;
9867c478bd9Sstevel@tonic-gate # endif /* NETINET */
9877c478bd9Sstevel@tonic-gate
9887c478bd9Sstevel@tonic-gate # if NETINET6
9897c478bd9Sstevel@tonic-gate case AF_INET6:
9907c478bd9Sstevel@tonic-gate memmove(&addr.sin6.sin6_addr,
9917c478bd9Sstevel@tonic-gate hp->h_addr, IN6ADDRSZ);
9927c478bd9Sstevel@tonic-gate addr.sin6.sin6_port = port;
993058561cbSjbeck addrlen = sizeof(struct sockaddr_in6);
9947c478bd9Sstevel@tonic-gate addrno = 1;
9957c478bd9Sstevel@tonic-gate break;
9967c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
9977c478bd9Sstevel@tonic-gate
9987c478bd9Sstevel@tonic-gate default:
9997c478bd9Sstevel@tonic-gate if (tTd(64, 5))
10007c478bd9Sstevel@tonic-gate sm_dprintf("X%s: Unknown protocol for %s (%d)\n",
10017c478bd9Sstevel@tonic-gate m->mf_name, at,
10027c478bd9Sstevel@tonic-gate hp->h_addrtype);
10037c478bd9Sstevel@tonic-gate if (parseonly)
10047c478bd9Sstevel@tonic-gate syserr("X%s: Unknown protocol for %s (%d)",
10057c478bd9Sstevel@tonic-gate m->mf_name, at, hp->h_addrtype);
10067c478bd9Sstevel@tonic-gate else if (MilterLogLevel > 0)
10077c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
10087c478bd9Sstevel@tonic-gate "Milter (%s): Unknown protocol for %s (%d)",
10097c478bd9Sstevel@tonic-gate m->mf_name, at,
10107c478bd9Sstevel@tonic-gate hp->h_addrtype);
10117c478bd9Sstevel@tonic-gate milter_error(m, e);
10127c478bd9Sstevel@tonic-gate # if NETINET6
10137c478bd9Sstevel@tonic-gate freehostent(hp);
10147c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
10157c478bd9Sstevel@tonic-gate return -1;
10167c478bd9Sstevel@tonic-gate }
10177c478bd9Sstevel@tonic-gate }
10187c478bd9Sstevel@tonic-gate }
10197c478bd9Sstevel@tonic-gate else
10207c478bd9Sstevel@tonic-gate # endif /* NETINET || NETINET6 */
10217c478bd9Sstevel@tonic-gate {
10227c478bd9Sstevel@tonic-gate if (tTd(64, 5))
10237c478bd9Sstevel@tonic-gate sm_dprintf("X%s: unknown socket protocol\n",
10247c478bd9Sstevel@tonic-gate m->mf_name);
10257c478bd9Sstevel@tonic-gate if (parseonly)
10267c478bd9Sstevel@tonic-gate syserr("X%s: unknown socket protocol", m->mf_name);
10277c478bd9Sstevel@tonic-gate else if (MilterLogLevel > 0)
10287c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
10297c478bd9Sstevel@tonic-gate "Milter (%s): unknown socket protocol",
10307c478bd9Sstevel@tonic-gate m->mf_name);
10317c478bd9Sstevel@tonic-gate milter_error(m, e);
10327c478bd9Sstevel@tonic-gate return -1;
10337c478bd9Sstevel@tonic-gate }
10347c478bd9Sstevel@tonic-gate
10357c478bd9Sstevel@tonic-gate /* just parsing through? */
10367c478bd9Sstevel@tonic-gate if (parseonly)
10377c478bd9Sstevel@tonic-gate {
10387c478bd9Sstevel@tonic-gate m->mf_state = SMFS_READY;
10397c478bd9Sstevel@tonic-gate # if NETINET6
10407c478bd9Sstevel@tonic-gate if (hp != NULL)
10417c478bd9Sstevel@tonic-gate freehostent(hp);
10427c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
10437c478bd9Sstevel@tonic-gate return 0;
10447c478bd9Sstevel@tonic-gate }
10457c478bd9Sstevel@tonic-gate
10467c478bd9Sstevel@tonic-gate /* sanity check */
10477c478bd9Sstevel@tonic-gate if (m->mf_state != SMFS_READY &&
10487c478bd9Sstevel@tonic-gate m->mf_state != SMFS_CLOSED)
10497c478bd9Sstevel@tonic-gate {
10507c478bd9Sstevel@tonic-gate /* shouldn't happen */
10517c478bd9Sstevel@tonic-gate if (tTd(64, 1))
10527c478bd9Sstevel@tonic-gate sm_dprintf("Milter (%s): Trying to open filter in state %c\n",
10537c478bd9Sstevel@tonic-gate m->mf_name, (char) m->mf_state);
10547c478bd9Sstevel@tonic-gate milter_error(m, e);
10557c478bd9Sstevel@tonic-gate # if NETINET6
10567c478bd9Sstevel@tonic-gate if (hp != NULL)
10577c478bd9Sstevel@tonic-gate freehostent(hp);
10587c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
10597c478bd9Sstevel@tonic-gate return -1;
10607c478bd9Sstevel@tonic-gate }
10617c478bd9Sstevel@tonic-gate
10627c478bd9Sstevel@tonic-gate /* nope, actually connecting */
10637c478bd9Sstevel@tonic-gate for (;;)
10647c478bd9Sstevel@tonic-gate {
10657c478bd9Sstevel@tonic-gate sock = socket(addr.sa.sa_family, SOCK_STREAM, 0);
10667c478bd9Sstevel@tonic-gate if (sock < 0)
10677c478bd9Sstevel@tonic-gate {
10687c478bd9Sstevel@tonic-gate save_errno = errno;
10697c478bd9Sstevel@tonic-gate if (tTd(64, 5))
10707c478bd9Sstevel@tonic-gate sm_dprintf("Milter (%s): error creating socket: %s\n",
10717c478bd9Sstevel@tonic-gate m->mf_name,
10727c478bd9Sstevel@tonic-gate sm_errstring(save_errno));
10737c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0)
10747c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
10757c478bd9Sstevel@tonic-gate "Milter (%s): error creating socket: %s",
10767c478bd9Sstevel@tonic-gate m->mf_name, sm_errstring(save_errno));
10777c478bd9Sstevel@tonic-gate milter_error(m, e);
10787c478bd9Sstevel@tonic-gate # if NETINET6
10797c478bd9Sstevel@tonic-gate if (hp != NULL)
10807c478bd9Sstevel@tonic-gate freehostent(hp);
10817c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
10827c478bd9Sstevel@tonic-gate return -1;
10837c478bd9Sstevel@tonic-gate }
10847c478bd9Sstevel@tonic-gate
10857c478bd9Sstevel@tonic-gate if (setjmp(MilterConnectTimeout) == 0)
10867c478bd9Sstevel@tonic-gate {
10877c478bd9Sstevel@tonic-gate SM_EVENT *ev = NULL;
10887c478bd9Sstevel@tonic-gate int i;
10897c478bd9Sstevel@tonic-gate
10907c478bd9Sstevel@tonic-gate if (m->mf_timeout[SMFTO_CONNECT] > 0)
10917c478bd9Sstevel@tonic-gate ev = sm_setevent(m->mf_timeout[SMFTO_CONNECT],
10927c478bd9Sstevel@tonic-gate milter_connect_timeout, 0);
10937c478bd9Sstevel@tonic-gate
10947c478bd9Sstevel@tonic-gate i = connect(sock, (struct sockaddr *) &addr, addrlen);
10957c478bd9Sstevel@tonic-gate save_errno = errno;
10967c478bd9Sstevel@tonic-gate if (ev != NULL)
10977c478bd9Sstevel@tonic-gate sm_clrevent(ev);
10987c478bd9Sstevel@tonic-gate errno = save_errno;
10997c478bd9Sstevel@tonic-gate if (i >= 0)
11007c478bd9Sstevel@tonic-gate break;
11017c478bd9Sstevel@tonic-gate }
11027c478bd9Sstevel@tonic-gate
11037c478bd9Sstevel@tonic-gate /* couldn't connect.... try next address */
11047c478bd9Sstevel@tonic-gate save_errno = errno;
11057c478bd9Sstevel@tonic-gate p = CurHostName;
11067c478bd9Sstevel@tonic-gate CurHostName = at;
11077c478bd9Sstevel@tonic-gate if (tTd(64, 5))
11087c478bd9Sstevel@tonic-gate sm_dprintf("milter_open (%s): open %s failed: %s\n",
11097c478bd9Sstevel@tonic-gate m->mf_name, at, sm_errstring(save_errno));
11107c478bd9Sstevel@tonic-gate if (MilterLogLevel > 13)
11117c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id,
11127c478bd9Sstevel@tonic-gate "Milter (%s): open %s failed: %s",
11137c478bd9Sstevel@tonic-gate m->mf_name, at, sm_errstring(save_errno));
11147c478bd9Sstevel@tonic-gate CurHostName = p;
11157c478bd9Sstevel@tonic-gate (void) close(sock);
11167c478bd9Sstevel@tonic-gate
11177c478bd9Sstevel@tonic-gate /* try next address */
11187c478bd9Sstevel@tonic-gate if (hp != NULL && hp->h_addr_list[addrno] != NULL)
11197c478bd9Sstevel@tonic-gate {
11207c478bd9Sstevel@tonic-gate switch (addr.sa.sa_family)
11217c478bd9Sstevel@tonic-gate {
11227c478bd9Sstevel@tonic-gate # if NETINET
11237c478bd9Sstevel@tonic-gate case AF_INET:
11247c478bd9Sstevel@tonic-gate memmove(&addr.sin.sin_addr,
11257c478bd9Sstevel@tonic-gate hp->h_addr_list[addrno++],
11267c478bd9Sstevel@tonic-gate INADDRSZ);
11277c478bd9Sstevel@tonic-gate break;
11287c478bd9Sstevel@tonic-gate # endif /* NETINET */
11297c478bd9Sstevel@tonic-gate
11307c478bd9Sstevel@tonic-gate # if NETINET6
11317c478bd9Sstevel@tonic-gate case AF_INET6:
11327c478bd9Sstevel@tonic-gate memmove(&addr.sin6.sin6_addr,
11337c478bd9Sstevel@tonic-gate hp->h_addr_list[addrno++],
11347c478bd9Sstevel@tonic-gate IN6ADDRSZ);
11357c478bd9Sstevel@tonic-gate break;
11367c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
11377c478bd9Sstevel@tonic-gate
11387c478bd9Sstevel@tonic-gate default:
11397c478bd9Sstevel@tonic-gate if (tTd(64, 5))
11407c478bd9Sstevel@tonic-gate sm_dprintf("X%s: Unknown protocol for %s (%d)\n",
11417c478bd9Sstevel@tonic-gate m->mf_name, at,
11427c478bd9Sstevel@tonic-gate hp->h_addrtype);
11437c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0)
11447c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
11457c478bd9Sstevel@tonic-gate "Milter (%s): Unknown protocol for %s (%d)",
11467c478bd9Sstevel@tonic-gate m->mf_name, at,
11477c478bd9Sstevel@tonic-gate hp->h_addrtype);
11487c478bd9Sstevel@tonic-gate milter_error(m, e);
11497c478bd9Sstevel@tonic-gate # if NETINET6
11507c478bd9Sstevel@tonic-gate freehostent(hp);
11517c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
11527c478bd9Sstevel@tonic-gate return -1;
11537c478bd9Sstevel@tonic-gate }
11547c478bd9Sstevel@tonic-gate continue;
11557c478bd9Sstevel@tonic-gate }
11567c478bd9Sstevel@tonic-gate p = CurHostName;
11577c478bd9Sstevel@tonic-gate CurHostName = at;
11587c478bd9Sstevel@tonic-gate if (tTd(64, 5))
11597c478bd9Sstevel@tonic-gate sm_dprintf("X%s: error connecting to filter: %s\n",
11607c478bd9Sstevel@tonic-gate m->mf_name, sm_errstring(save_errno));
11617c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0)
11627c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
11637c478bd9Sstevel@tonic-gate "Milter (%s): error connecting to filter: %s",
11647c478bd9Sstevel@tonic-gate m->mf_name, sm_errstring(save_errno));
11657c478bd9Sstevel@tonic-gate CurHostName = p;
11667c478bd9Sstevel@tonic-gate milter_error(m, e);
11677c478bd9Sstevel@tonic-gate # if NETINET6
11687c478bd9Sstevel@tonic-gate if (hp != NULL)
11697c478bd9Sstevel@tonic-gate freehostent(hp);
11707c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
11717c478bd9Sstevel@tonic-gate return -1;
11727c478bd9Sstevel@tonic-gate }
11737c478bd9Sstevel@tonic-gate m->mf_state = SMFS_OPEN;
11747c478bd9Sstevel@tonic-gate # if NETINET6
11757c478bd9Sstevel@tonic-gate if (hp != NULL)
11767c478bd9Sstevel@tonic-gate {
11777c478bd9Sstevel@tonic-gate freehostent(hp);
11787c478bd9Sstevel@tonic-gate hp = NULL;
11797c478bd9Sstevel@tonic-gate }
11807c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
1181058561cbSjbeck # if MILTER_NO_NAGLE && !defined(TCP_CORK)
11827c478bd9Sstevel@tonic-gate {
11837c478bd9Sstevel@tonic-gate int nodelay = 1;
11847c478bd9Sstevel@tonic-gate
11857c478bd9Sstevel@tonic-gate setsockopt(m->mf_sock, IPPROTO_TCP, TCP_NODELAY,
11867c478bd9Sstevel@tonic-gate (char *)&nodelay, sizeof(nodelay));
11877c478bd9Sstevel@tonic-gate }
1188058561cbSjbeck # endif /* MILTER_NO_NAGLE && !defined(TCP_CORK) */
11897c478bd9Sstevel@tonic-gate return sock;
11907c478bd9Sstevel@tonic-gate }
11917c478bd9Sstevel@tonic-gate
11927c478bd9Sstevel@tonic-gate static void
milter_connect_timeout(ignore)11937c478bd9Sstevel@tonic-gate milter_connect_timeout(ignore)
11947c478bd9Sstevel@tonic-gate int ignore;
11957c478bd9Sstevel@tonic-gate {
11967c478bd9Sstevel@tonic-gate /*
11977c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD
11987c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE
11997c478bd9Sstevel@tonic-gate ** DOING.
12007c478bd9Sstevel@tonic-gate */
12017c478bd9Sstevel@tonic-gate
12027c478bd9Sstevel@tonic-gate errno = ETIMEDOUT;
12037c478bd9Sstevel@tonic-gate longjmp(MilterConnectTimeout, 1);
12047c478bd9Sstevel@tonic-gate }
1205058561cbSjbeck
12067c478bd9Sstevel@tonic-gate /*
12077c478bd9Sstevel@tonic-gate ** MILTER_SETUP -- setup structure for a mail filter
12087c478bd9Sstevel@tonic-gate **
12097c478bd9Sstevel@tonic-gate ** Parameters:
12107c478bd9Sstevel@tonic-gate ** line -- the options line.
12117c478bd9Sstevel@tonic-gate **
12127c478bd9Sstevel@tonic-gate ** Returns:
12137c478bd9Sstevel@tonic-gate ** none
12147c478bd9Sstevel@tonic-gate */
12157c478bd9Sstevel@tonic-gate
12167c478bd9Sstevel@tonic-gate void
milter_setup(line)12177c478bd9Sstevel@tonic-gate milter_setup(line)
12187c478bd9Sstevel@tonic-gate char *line;
12197c478bd9Sstevel@tonic-gate {
12207c478bd9Sstevel@tonic-gate char fcode;
1221058561cbSjbeck char *p;
1222058561cbSjbeck struct milter *m;
12237c478bd9Sstevel@tonic-gate STAB *s;
12247c478bd9Sstevel@tonic-gate
12257c478bd9Sstevel@tonic-gate /* collect the filter name */
12267c478bd9Sstevel@tonic-gate for (p = line;
12277c478bd9Sstevel@tonic-gate *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p));
12287c478bd9Sstevel@tonic-gate p++)
12297c478bd9Sstevel@tonic-gate continue;
12307c478bd9Sstevel@tonic-gate if (*p != '\0')
12317c478bd9Sstevel@tonic-gate *p++ = '\0';
12327c478bd9Sstevel@tonic-gate if (line[0] == '\0')
12337c478bd9Sstevel@tonic-gate {
12347c478bd9Sstevel@tonic-gate syserr("name required for mail filter");
12357c478bd9Sstevel@tonic-gate return;
12367c478bd9Sstevel@tonic-gate }
1237058561cbSjbeck m = (struct milter *) xalloc(sizeof(*m));
1238058561cbSjbeck memset((char *) m, '\0', sizeof(*m));
12397c478bd9Sstevel@tonic-gate m->mf_name = newstr(line);
12407c478bd9Sstevel@tonic-gate m->mf_state = SMFS_READY;
12417c478bd9Sstevel@tonic-gate m->mf_sock = -1;
12427c478bd9Sstevel@tonic-gate m->mf_timeout[SMFTO_CONNECT] = (time_t) 300;
12437c478bd9Sstevel@tonic-gate m->mf_timeout[SMFTO_WRITE] = (time_t) 10;
12447c478bd9Sstevel@tonic-gate m->mf_timeout[SMFTO_READ] = (time_t) 10;
12457c478bd9Sstevel@tonic-gate m->mf_timeout[SMFTO_EOM] = (time_t) 300;
12464aac33d3Sjbeck #if _FFR_MILTER_CHECK
1247058561cbSjbeck m->mf_mta_prot_version = SMFI_PROT_VERSION;
1248058561cbSjbeck m->mf_mta_prot_flags = SMFI_CURR_PROT;
1249058561cbSjbeck m->mf_mta_actions = SMFI_CURR_ACTS;
12504aac33d3Sjbeck #endif /* _FFR_MILTER_CHECK */
12517c478bd9Sstevel@tonic-gate
12527c478bd9Sstevel@tonic-gate /* now scan through and assign info from the fields */
12537c478bd9Sstevel@tonic-gate while (*p != '\0')
12547c478bd9Sstevel@tonic-gate {
12557c478bd9Sstevel@tonic-gate char *delimptr;
12567c478bd9Sstevel@tonic-gate
12577c478bd9Sstevel@tonic-gate while (*p != '\0' &&
12587c478bd9Sstevel@tonic-gate (*p == ',' || (isascii(*p) && isspace(*p))))
12597c478bd9Sstevel@tonic-gate p++;
12607c478bd9Sstevel@tonic-gate
12617c478bd9Sstevel@tonic-gate /* p now points to field code */
12627c478bd9Sstevel@tonic-gate fcode = *p;
12637c478bd9Sstevel@tonic-gate while (*p != '\0' && *p != '=' && *p != ',')
12647c478bd9Sstevel@tonic-gate p++;
12657c478bd9Sstevel@tonic-gate if (*p++ != '=')
12667c478bd9Sstevel@tonic-gate {
12677c478bd9Sstevel@tonic-gate syserr("X%s: `=' expected", m->mf_name);
12687c478bd9Sstevel@tonic-gate return;
12697c478bd9Sstevel@tonic-gate }
12707c478bd9Sstevel@tonic-gate while (isascii(*p) && isspace(*p))
12717c478bd9Sstevel@tonic-gate p++;
12727c478bd9Sstevel@tonic-gate
12737c478bd9Sstevel@tonic-gate /* p now points to the field body */
12747c478bd9Sstevel@tonic-gate p = munchstring(p, &delimptr, ',');
12757c478bd9Sstevel@tonic-gate
12767c478bd9Sstevel@tonic-gate /* install the field into the filter struct */
12777c478bd9Sstevel@tonic-gate switch (fcode)
12787c478bd9Sstevel@tonic-gate {
12797c478bd9Sstevel@tonic-gate case 'S': /* socket */
12807c478bd9Sstevel@tonic-gate if (p == NULL)
12817c478bd9Sstevel@tonic-gate m->mf_conn = NULL;
12827c478bd9Sstevel@tonic-gate else
12837c478bd9Sstevel@tonic-gate m->mf_conn = newstr(p);
12847c478bd9Sstevel@tonic-gate break;
12857c478bd9Sstevel@tonic-gate
12867c478bd9Sstevel@tonic-gate case 'F': /* Milter flags configured on MTA */
12877c478bd9Sstevel@tonic-gate for (; *p != '\0'; p++)
12887c478bd9Sstevel@tonic-gate {
12897c478bd9Sstevel@tonic-gate if (!(isascii(*p) && isspace(*p)))
12907c478bd9Sstevel@tonic-gate setbitn(bitidx(*p), m->mf_flags);
12917c478bd9Sstevel@tonic-gate }
12927c478bd9Sstevel@tonic-gate break;
12937c478bd9Sstevel@tonic-gate
12947c478bd9Sstevel@tonic-gate case 'T': /* timeouts */
12957c478bd9Sstevel@tonic-gate milter_parse_timeouts(p, m);
12967c478bd9Sstevel@tonic-gate break;
12977c478bd9Sstevel@tonic-gate
12984aac33d3Sjbeck #if _FFR_MILTER_CHECK
1299058561cbSjbeck case 'a':
1300058561cbSjbeck m->mf_mta_actions = strtoul(p, NULL, 0);
1301058561cbSjbeck break;
1302058561cbSjbeck case 'f':
1303058561cbSjbeck m->mf_mta_prot_flags = strtoul(p, NULL, 0);
1304058561cbSjbeck break;
1305058561cbSjbeck case 'v':
1306058561cbSjbeck m->mf_mta_prot_version = strtoul(p, NULL, 0);
1307058561cbSjbeck break;
13084aac33d3Sjbeck #endif /* _FFR_MILTER_CHECK */
1309058561cbSjbeck
13107c478bd9Sstevel@tonic-gate default:
13117c478bd9Sstevel@tonic-gate syserr("X%s: unknown filter equate %c=",
13127c478bd9Sstevel@tonic-gate m->mf_name, fcode);
13137c478bd9Sstevel@tonic-gate break;
13147c478bd9Sstevel@tonic-gate }
13157c478bd9Sstevel@tonic-gate p = delimptr;
13167c478bd9Sstevel@tonic-gate }
13177c478bd9Sstevel@tonic-gate
13187c478bd9Sstevel@tonic-gate /* early check for errors */
13197c478bd9Sstevel@tonic-gate (void) milter_open(m, true, CurEnv);
13207c478bd9Sstevel@tonic-gate
13217c478bd9Sstevel@tonic-gate /* enter the filter into the symbol table */
13227c478bd9Sstevel@tonic-gate s = stab(m->mf_name, ST_MILTER, ST_ENTER);
13237c478bd9Sstevel@tonic-gate if (s->s_milter != NULL)
13247c478bd9Sstevel@tonic-gate syserr("X%s: duplicate filter definition", m->mf_name);
13257c478bd9Sstevel@tonic-gate else
13267c478bd9Sstevel@tonic-gate s->s_milter = m;
13277c478bd9Sstevel@tonic-gate }
1328058561cbSjbeck
13297c478bd9Sstevel@tonic-gate /*
13307c478bd9Sstevel@tonic-gate ** MILTER_CONFIG -- parse option list into an array and check config
13317c478bd9Sstevel@tonic-gate **
13327c478bd9Sstevel@tonic-gate ** Called when reading configuration file.
13337c478bd9Sstevel@tonic-gate **
13347c478bd9Sstevel@tonic-gate ** Parameters:
13357c478bd9Sstevel@tonic-gate ** spec -- the filter list.
13367c478bd9Sstevel@tonic-gate ** list -- the array to fill in.
13377c478bd9Sstevel@tonic-gate ** max -- the maximum number of entries in list.
13387c478bd9Sstevel@tonic-gate **
13397c478bd9Sstevel@tonic-gate ** Returns:
13407c478bd9Sstevel@tonic-gate ** none
13417c478bd9Sstevel@tonic-gate */
13427c478bd9Sstevel@tonic-gate
13437c478bd9Sstevel@tonic-gate void
milter_config(spec,list,max)13447c478bd9Sstevel@tonic-gate milter_config(spec, list, max)
13457c478bd9Sstevel@tonic-gate char *spec;
13467c478bd9Sstevel@tonic-gate struct milter **list;
13477c478bd9Sstevel@tonic-gate int max;
13487c478bd9Sstevel@tonic-gate {
13497c478bd9Sstevel@tonic-gate int numitems = 0;
1350058561cbSjbeck char *p;
13517c478bd9Sstevel@tonic-gate
13527c478bd9Sstevel@tonic-gate /* leave one for the NULL signifying the end of the list */
13537c478bd9Sstevel@tonic-gate max--;
13547c478bd9Sstevel@tonic-gate
13557c478bd9Sstevel@tonic-gate for (p = spec; p != NULL; )
13567c478bd9Sstevel@tonic-gate {
13577c478bd9Sstevel@tonic-gate STAB *s;
13587c478bd9Sstevel@tonic-gate
13597c478bd9Sstevel@tonic-gate while (isascii(*p) && isspace(*p))
13607c478bd9Sstevel@tonic-gate p++;
13617c478bd9Sstevel@tonic-gate if (*p == '\0')
13627c478bd9Sstevel@tonic-gate break;
13637c478bd9Sstevel@tonic-gate spec = p;
13647c478bd9Sstevel@tonic-gate
13657c478bd9Sstevel@tonic-gate if (numitems >= max)
13667c478bd9Sstevel@tonic-gate {
13677c478bd9Sstevel@tonic-gate syserr("Too many filters defined, %d max", max);
13687c478bd9Sstevel@tonic-gate if (max > 0)
13697c478bd9Sstevel@tonic-gate list[0] = NULL;
13707c478bd9Sstevel@tonic-gate return;
13717c478bd9Sstevel@tonic-gate }
13727c478bd9Sstevel@tonic-gate p = strpbrk(p, ";,");
13737c478bd9Sstevel@tonic-gate if (p != NULL)
13747c478bd9Sstevel@tonic-gate *p++ = '\0';
13757c478bd9Sstevel@tonic-gate
13767c478bd9Sstevel@tonic-gate s = stab(spec, ST_MILTER, ST_FIND);
13777c478bd9Sstevel@tonic-gate if (s == NULL)
13787c478bd9Sstevel@tonic-gate {
13797c478bd9Sstevel@tonic-gate syserr("InputFilter %s not defined", spec);
13807c478bd9Sstevel@tonic-gate ExitStat = EX_CONFIG;
13817c478bd9Sstevel@tonic-gate return;
13827c478bd9Sstevel@tonic-gate }
13837c478bd9Sstevel@tonic-gate list[numitems++] = s->s_milter;
13847c478bd9Sstevel@tonic-gate }
13857c478bd9Sstevel@tonic-gate list[numitems] = NULL;
13867c478bd9Sstevel@tonic-gate
13877c478bd9Sstevel@tonic-gate /* if not set, set to LogLevel */
13887c478bd9Sstevel@tonic-gate if (MilterLogLevel == -1)
13897c478bd9Sstevel@tonic-gate MilterLogLevel = LogLevel;
13907c478bd9Sstevel@tonic-gate }
1391058561cbSjbeck
13927c478bd9Sstevel@tonic-gate /*
13937c478bd9Sstevel@tonic-gate ** MILTER_PARSE_TIMEOUTS -- parse timeout list
13947c478bd9Sstevel@tonic-gate **
13957c478bd9Sstevel@tonic-gate ** Called when reading configuration file.
13967c478bd9Sstevel@tonic-gate **
13977c478bd9Sstevel@tonic-gate ** Parameters:
13987c478bd9Sstevel@tonic-gate ** spec -- the timeout list.
13997c478bd9Sstevel@tonic-gate ** m -- milter to set.
14007c478bd9Sstevel@tonic-gate **
14017c478bd9Sstevel@tonic-gate ** Returns:
14027c478bd9Sstevel@tonic-gate ** none
14037c478bd9Sstevel@tonic-gate */
14047c478bd9Sstevel@tonic-gate
14057c478bd9Sstevel@tonic-gate static void
milter_parse_timeouts(spec,m)14067c478bd9Sstevel@tonic-gate milter_parse_timeouts(spec, m)
14077c478bd9Sstevel@tonic-gate char *spec;
14087c478bd9Sstevel@tonic-gate struct milter *m;
14097c478bd9Sstevel@tonic-gate {
14107c478bd9Sstevel@tonic-gate char fcode;
14117c478bd9Sstevel@tonic-gate int tcode;
1412058561cbSjbeck char *p;
14137c478bd9Sstevel@tonic-gate
14147c478bd9Sstevel@tonic-gate p = spec;
14157c478bd9Sstevel@tonic-gate
14167c478bd9Sstevel@tonic-gate /* now scan through and assign info from the fields */
14177c478bd9Sstevel@tonic-gate while (*p != '\0')
14187c478bd9Sstevel@tonic-gate {
14197c478bd9Sstevel@tonic-gate char *delimptr;
14207c478bd9Sstevel@tonic-gate
14217c478bd9Sstevel@tonic-gate while (*p != '\0' &&
14227c478bd9Sstevel@tonic-gate (*p == ';' || (isascii(*p) && isspace(*p))))
14237c478bd9Sstevel@tonic-gate p++;
14247c478bd9Sstevel@tonic-gate
14257c478bd9Sstevel@tonic-gate /* p now points to field code */
14267c478bd9Sstevel@tonic-gate fcode = *p;
14277c478bd9Sstevel@tonic-gate while (*p != '\0' && *p != ':')
14287c478bd9Sstevel@tonic-gate p++;
14297c478bd9Sstevel@tonic-gate if (*p++ != ':')
14307c478bd9Sstevel@tonic-gate {
14317c478bd9Sstevel@tonic-gate syserr("X%s, T=: `:' expected", m->mf_name);
14327c478bd9Sstevel@tonic-gate return;
14337c478bd9Sstevel@tonic-gate }
14347c478bd9Sstevel@tonic-gate while (isascii(*p) && isspace(*p))
14357c478bd9Sstevel@tonic-gate p++;
14367c478bd9Sstevel@tonic-gate
14377c478bd9Sstevel@tonic-gate /* p now points to the field body */
14387c478bd9Sstevel@tonic-gate p = munchstring(p, &delimptr, ';');
14397c478bd9Sstevel@tonic-gate tcode = -1;
14407c478bd9Sstevel@tonic-gate
14417c478bd9Sstevel@tonic-gate /* install the field into the filter struct */
14427c478bd9Sstevel@tonic-gate switch (fcode)
14437c478bd9Sstevel@tonic-gate {
14447c478bd9Sstevel@tonic-gate case 'C':
14457c478bd9Sstevel@tonic-gate tcode = SMFTO_CONNECT;
14467c478bd9Sstevel@tonic-gate break;
14477c478bd9Sstevel@tonic-gate
14487c478bd9Sstevel@tonic-gate case 'S':
14497c478bd9Sstevel@tonic-gate tcode = SMFTO_WRITE;
14507c478bd9Sstevel@tonic-gate break;
14517c478bd9Sstevel@tonic-gate
14527c478bd9Sstevel@tonic-gate case 'R':
14537c478bd9Sstevel@tonic-gate tcode = SMFTO_READ;
14547c478bd9Sstevel@tonic-gate break;
14557c478bd9Sstevel@tonic-gate
14567c478bd9Sstevel@tonic-gate case 'E':
14577c478bd9Sstevel@tonic-gate tcode = SMFTO_EOM;
14587c478bd9Sstevel@tonic-gate break;
14597c478bd9Sstevel@tonic-gate
14607c478bd9Sstevel@tonic-gate default:
14617c478bd9Sstevel@tonic-gate if (tTd(64, 5))
14627c478bd9Sstevel@tonic-gate sm_dprintf("X%s: %c unknown\n",
14637c478bd9Sstevel@tonic-gate m->mf_name, fcode);
14647c478bd9Sstevel@tonic-gate syserr("X%s: unknown filter timeout %c",
14657c478bd9Sstevel@tonic-gate m->mf_name, fcode);
14667c478bd9Sstevel@tonic-gate break;
14677c478bd9Sstevel@tonic-gate }
14687c478bd9Sstevel@tonic-gate if (tcode >= 0)
14697c478bd9Sstevel@tonic-gate {
14707c478bd9Sstevel@tonic-gate m->mf_timeout[tcode] = convtime(p, 's');
14717c478bd9Sstevel@tonic-gate if (tTd(64, 5))
14727c478bd9Sstevel@tonic-gate sm_dprintf("X%s: %c=%ld\n",
14737c478bd9Sstevel@tonic-gate m->mf_name, fcode,
14747c478bd9Sstevel@tonic-gate (u_long) m->mf_timeout[tcode]);
14757c478bd9Sstevel@tonic-gate }
14767c478bd9Sstevel@tonic-gate p = delimptr;
14777c478bd9Sstevel@tonic-gate }
14787c478bd9Sstevel@tonic-gate }
1479058561cbSjbeck
1480058561cbSjbeck /*
1481058561cbSjbeck ** MILTER_SET_MACROS -- set milter macros
1482058561cbSjbeck **
1483058561cbSjbeck ** Parameters:
1484058561cbSjbeck ** name -- name of milter.
1485058561cbSjbeck ** macros -- where to store macros.
1486058561cbSjbeck ** val -- the value of the option.
1487058561cbSjbeck ** nummac -- current number of macros
1488058561cbSjbeck **
1489058561cbSjbeck ** Returns:
1490058561cbSjbeck ** new number of macros
1491058561cbSjbeck */
1492058561cbSjbeck
1493058561cbSjbeck static int
milter_set_macros(name,macros,val,nummac)1494058561cbSjbeck milter_set_macros(name, macros, val, nummac)
1495058561cbSjbeck char *name;
1496058561cbSjbeck char **macros;
1497058561cbSjbeck char *val;
1498058561cbSjbeck int nummac;
1499058561cbSjbeck {
1500058561cbSjbeck char *p;
1501058561cbSjbeck
1502058561cbSjbeck p = newstr(val);
1503058561cbSjbeck while (*p != '\0')
1504058561cbSjbeck {
1505058561cbSjbeck char *macro;
1506058561cbSjbeck
1507058561cbSjbeck /* Skip leading commas, spaces */
1508058561cbSjbeck while (*p != '\0' &&
1509058561cbSjbeck (*p == ',' || (isascii(*p) && isspace(*p))))
1510058561cbSjbeck p++;
1511058561cbSjbeck
1512058561cbSjbeck if (*p == '\0')
1513058561cbSjbeck break;
1514058561cbSjbeck
1515058561cbSjbeck /* Find end of macro */
1516058561cbSjbeck macro = p;
1517058561cbSjbeck while (*p != '\0' && *p != ',' &&
1518058561cbSjbeck isascii(*p) && !isspace(*p))
1519058561cbSjbeck p++;
1520058561cbSjbeck if (*p != '\0')
1521058561cbSjbeck *p++ = '\0';
1522058561cbSjbeck
1523058561cbSjbeck if (nummac >= MAXFILTERMACROS)
1524058561cbSjbeck {
1525058561cbSjbeck syserr("milter_set_option: too many macros in Milter.%s (max %d)",
1526058561cbSjbeck name, MAXFILTERMACROS);
1527058561cbSjbeck macros[nummac] = NULL;
1528058561cbSjbeck return -1;
1529058561cbSjbeck }
1530058561cbSjbeck macros[nummac++] = macro;
1531058561cbSjbeck }
1532058561cbSjbeck macros[nummac] = NULL;
1533058561cbSjbeck return nummac;
1534058561cbSjbeck }
1535058561cbSjbeck
15367c478bd9Sstevel@tonic-gate /*
15377c478bd9Sstevel@tonic-gate ** MILTER_SET_OPTION -- set an individual milter option
15387c478bd9Sstevel@tonic-gate **
15397c478bd9Sstevel@tonic-gate ** Parameters:
15407c478bd9Sstevel@tonic-gate ** name -- the name of the option.
15417c478bd9Sstevel@tonic-gate ** val -- the value of the option.
15427c478bd9Sstevel@tonic-gate ** sticky -- if set, don't let other setoptions override
15437c478bd9Sstevel@tonic-gate ** this value.
15447c478bd9Sstevel@tonic-gate **
15457c478bd9Sstevel@tonic-gate ** Returns:
15467c478bd9Sstevel@tonic-gate ** none.
15477c478bd9Sstevel@tonic-gate */
15487c478bd9Sstevel@tonic-gate
15497c478bd9Sstevel@tonic-gate /* set if Milter sub-option is stuck */
15507c478bd9Sstevel@tonic-gate static BITMAP256 StickyMilterOpt;
15517c478bd9Sstevel@tonic-gate
15527c478bd9Sstevel@tonic-gate static struct milteropt
15537c478bd9Sstevel@tonic-gate {
15547c478bd9Sstevel@tonic-gate char *mo_name; /* long name of milter option */
15557c478bd9Sstevel@tonic-gate unsigned char mo_code; /* code for option */
15567c478bd9Sstevel@tonic-gate } MilterOptTab[] =
15577c478bd9Sstevel@tonic-gate {
1558058561cbSjbeck # define MO_MACROS_CONNECT SMFIM_CONNECT
15597c478bd9Sstevel@tonic-gate { "macros.connect", MO_MACROS_CONNECT },
1560058561cbSjbeck # define MO_MACROS_HELO SMFIM_HELO
15617c478bd9Sstevel@tonic-gate { "macros.helo", MO_MACROS_HELO },
1562058561cbSjbeck # define MO_MACROS_ENVFROM SMFIM_ENVFROM
15637c478bd9Sstevel@tonic-gate { "macros.envfrom", MO_MACROS_ENVFROM },
1564058561cbSjbeck # define MO_MACROS_ENVRCPT SMFIM_ENVRCPT
15657c478bd9Sstevel@tonic-gate { "macros.envrcpt", MO_MACROS_ENVRCPT },
1566058561cbSjbeck # define MO_MACROS_DATA SMFIM_DATA
15677c478bd9Sstevel@tonic-gate { "macros.data", MO_MACROS_DATA },
1568058561cbSjbeck # define MO_MACROS_EOM SMFIM_EOM
15697c478bd9Sstevel@tonic-gate { "macros.eom", MO_MACROS_EOM },
1570058561cbSjbeck # define MO_MACROS_EOH SMFIM_EOH
1571058561cbSjbeck { "macros.eoh", MO_MACROS_EOH },
1572058561cbSjbeck
15737c478bd9Sstevel@tonic-gate # define MO_LOGLEVEL 0x07
15747c478bd9Sstevel@tonic-gate { "loglevel", MO_LOGLEVEL },
1575*e9af4bc0SJohn Beck # if _FFR_MAXDATASIZE || _FFR_MDS_NEGOTIATE
1576058561cbSjbeck # define MO_MAXDATASIZE 0x08
15777c478bd9Sstevel@tonic-gate { "maxdatasize", MO_MAXDATASIZE },
1578*e9af4bc0SJohn Beck # endif /* _FFR_MAXDATASIZE || _FFR_MDS_NEGOTIATE */
1579058561cbSjbeck { NULL, (unsigned char)-1 },
15807c478bd9Sstevel@tonic-gate };
15817c478bd9Sstevel@tonic-gate
15827c478bd9Sstevel@tonic-gate void
milter_set_option(name,val,sticky)15837c478bd9Sstevel@tonic-gate milter_set_option(name, val, sticky)
15847c478bd9Sstevel@tonic-gate char *name;
15857c478bd9Sstevel@tonic-gate char *val;
15867c478bd9Sstevel@tonic-gate bool sticky;
15877c478bd9Sstevel@tonic-gate {
1588058561cbSjbeck int nummac, r;
1589058561cbSjbeck struct milteropt *mo;
15907c478bd9Sstevel@tonic-gate char **macros = NULL;
15917c478bd9Sstevel@tonic-gate
1592058561cbSjbeck nummac = 0;
15937c478bd9Sstevel@tonic-gate if (tTd(37, 2) || tTd(64, 5))
15947c478bd9Sstevel@tonic-gate sm_dprintf("milter_set_option(%s = %s)", name, val);
15957c478bd9Sstevel@tonic-gate
15967c478bd9Sstevel@tonic-gate if (name == NULL)
15977c478bd9Sstevel@tonic-gate {
15987c478bd9Sstevel@tonic-gate syserr("milter_set_option: invalid Milter option, must specify suboption");
15997c478bd9Sstevel@tonic-gate return;
16007c478bd9Sstevel@tonic-gate }
16017c478bd9Sstevel@tonic-gate
16027c478bd9Sstevel@tonic-gate for (mo = MilterOptTab; mo->mo_name != NULL; mo++)
16037c478bd9Sstevel@tonic-gate {
16047c478bd9Sstevel@tonic-gate if (sm_strcasecmp(mo->mo_name, name) == 0)
16057c478bd9Sstevel@tonic-gate break;
16067c478bd9Sstevel@tonic-gate }
16077c478bd9Sstevel@tonic-gate
16087c478bd9Sstevel@tonic-gate if (mo->mo_name == NULL)
16097c478bd9Sstevel@tonic-gate {
16107c478bd9Sstevel@tonic-gate syserr("milter_set_option: invalid Milter option %s", name);
16117c478bd9Sstevel@tonic-gate return;
16127c478bd9Sstevel@tonic-gate }
16137c478bd9Sstevel@tonic-gate
16147c478bd9Sstevel@tonic-gate /*
16157c478bd9Sstevel@tonic-gate ** See if this option is preset for us.
16167c478bd9Sstevel@tonic-gate */
16177c478bd9Sstevel@tonic-gate
16187c478bd9Sstevel@tonic-gate if (!sticky && bitnset(mo->mo_code, StickyMilterOpt))
16197c478bd9Sstevel@tonic-gate {
16207c478bd9Sstevel@tonic-gate if (tTd(37, 2) || tTd(64,5))
16217c478bd9Sstevel@tonic-gate sm_dprintf(" (ignored)\n");
16227c478bd9Sstevel@tonic-gate return;
16237c478bd9Sstevel@tonic-gate }
16247c478bd9Sstevel@tonic-gate
16257c478bd9Sstevel@tonic-gate if (tTd(37, 2) || tTd(64,5))
16267c478bd9Sstevel@tonic-gate sm_dprintf("\n");
16277c478bd9Sstevel@tonic-gate
16287c478bd9Sstevel@tonic-gate switch (mo->mo_code)
16297c478bd9Sstevel@tonic-gate {
16307c478bd9Sstevel@tonic-gate case MO_LOGLEVEL:
16317c478bd9Sstevel@tonic-gate MilterLogLevel = atoi(val);
16327c478bd9Sstevel@tonic-gate break;
16337c478bd9Sstevel@tonic-gate
1634*e9af4bc0SJohn Beck # if _FFR_MAXDATASIZE || _FFR_MDS_NEGOTIATE
16357c478bd9Sstevel@tonic-gate case MO_MAXDATASIZE:
1636*e9af4bc0SJohn Beck # if _FFR_MDS_NEGOTIATE
16377c478bd9Sstevel@tonic-gate MilterMaxDataSize = (size_t)atol(val);
1638*e9af4bc0SJohn Beck if (MilterMaxDataSize != MILTER_MDS_64K &&
1639*e9af4bc0SJohn Beck MilterMaxDataSize != MILTER_MDS_256K &&
1640*e9af4bc0SJohn Beck MilterMaxDataSize != MILTER_MDS_1M)
1641*e9af4bc0SJohn Beck {
1642*e9af4bc0SJohn Beck sm_syslog(LOG_WARNING, NOQID,
1643*e9af4bc0SJohn Beck "WARNING: Milter.%s=%d, allowed are only %d, %d, and %d",
1644*e9af4bc0SJohn Beck name, MilterMaxDataSize,
1645*e9af4bc0SJohn Beck MILTER_MDS_64K, MILTER_MDS_256K,
1646*e9af4bc0SJohn Beck MILTER_MDS_1M);
1647*e9af4bc0SJohn Beck if (MilterMaxDataSize < MILTER_MDS_64K)
1648*e9af4bc0SJohn Beck MilterMaxDataSize = MILTER_MDS_64K;
1649*e9af4bc0SJohn Beck else if (MilterMaxDataSize < MILTER_MDS_256K)
1650*e9af4bc0SJohn Beck MilterMaxDataSize = MILTER_MDS_256K;
1651*e9af4bc0SJohn Beck else
1652*e9af4bc0SJohn Beck MilterMaxDataSize = MILTER_MDS_1M;
1653*e9af4bc0SJohn Beck }
1654*e9af4bc0SJohn Beck # endif /* _FFR_MDS_NEGOTIATE */
16557c478bd9Sstevel@tonic-gate break;
1656*e9af4bc0SJohn Beck # endif /* _FFR_MAXDATASIZE || _FFR_MDS_NEGOTIATE */
16577c478bd9Sstevel@tonic-gate
16587c478bd9Sstevel@tonic-gate case MO_MACROS_CONNECT:
16597c478bd9Sstevel@tonic-gate if (macros == NULL)
16607c478bd9Sstevel@tonic-gate macros = MilterConnectMacros;
16617c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
16627c478bd9Sstevel@tonic-gate
16637c478bd9Sstevel@tonic-gate case MO_MACROS_HELO:
16647c478bd9Sstevel@tonic-gate if (macros == NULL)
16657c478bd9Sstevel@tonic-gate macros = MilterHeloMacros;
16667c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
16677c478bd9Sstevel@tonic-gate
16687c478bd9Sstevel@tonic-gate case MO_MACROS_ENVFROM:
16697c478bd9Sstevel@tonic-gate if (macros == NULL)
16707c478bd9Sstevel@tonic-gate macros = MilterEnvFromMacros;
16717c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
16727c478bd9Sstevel@tonic-gate
16737c478bd9Sstevel@tonic-gate case MO_MACROS_ENVRCPT:
16747c478bd9Sstevel@tonic-gate if (macros == NULL)
16757c478bd9Sstevel@tonic-gate macros = MilterEnvRcptMacros;
16767c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
16777c478bd9Sstevel@tonic-gate
1678058561cbSjbeck case MO_MACROS_EOH:
1679058561cbSjbeck if (macros == NULL)
1680058561cbSjbeck macros = MilterEOHMacros;
1681058561cbSjbeck /* FALLTHROUGH */
1682058561cbSjbeck
16837c478bd9Sstevel@tonic-gate case MO_MACROS_EOM:
16847c478bd9Sstevel@tonic-gate if (macros == NULL)
16857c478bd9Sstevel@tonic-gate macros = MilterEOMMacros;
16867c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
16877c478bd9Sstevel@tonic-gate
16887c478bd9Sstevel@tonic-gate case MO_MACROS_DATA:
16897c478bd9Sstevel@tonic-gate if (macros == NULL)
16907c478bd9Sstevel@tonic-gate macros = MilterDataMacros;
16917c478bd9Sstevel@tonic-gate
1692058561cbSjbeck r = milter_set_macros(name, macros, val, nummac);
1693058561cbSjbeck if (r >= 0)
1694058561cbSjbeck nummac = r;
16957c478bd9Sstevel@tonic-gate break;
16967c478bd9Sstevel@tonic-gate
16977c478bd9Sstevel@tonic-gate default:
16987c478bd9Sstevel@tonic-gate syserr("milter_set_option: invalid Milter option %s", name);
16997c478bd9Sstevel@tonic-gate break;
17007c478bd9Sstevel@tonic-gate }
17017c478bd9Sstevel@tonic-gate if (sticky)
17027c478bd9Sstevel@tonic-gate setbitn(mo->mo_code, StickyMilterOpt);
17037c478bd9Sstevel@tonic-gate }
1704058561cbSjbeck
17057c478bd9Sstevel@tonic-gate /*
17067c478bd9Sstevel@tonic-gate ** MILTER_REOPEN_DF -- open & truncate the data file (for replbody)
17077c478bd9Sstevel@tonic-gate **
17087c478bd9Sstevel@tonic-gate ** Parameters:
17097c478bd9Sstevel@tonic-gate ** e -- current envelope.
17107c478bd9Sstevel@tonic-gate **
17117c478bd9Sstevel@tonic-gate ** Returns:
17127c478bd9Sstevel@tonic-gate ** 0 if succesful, -1 otherwise
17137c478bd9Sstevel@tonic-gate */
17147c478bd9Sstevel@tonic-gate
17157c478bd9Sstevel@tonic-gate static int
milter_reopen_df(e)17167c478bd9Sstevel@tonic-gate milter_reopen_df(e)
17177c478bd9Sstevel@tonic-gate ENVELOPE *e;
17187c478bd9Sstevel@tonic-gate {
17197c478bd9Sstevel@tonic-gate char dfname[MAXPATHLEN];
17207c478bd9Sstevel@tonic-gate
1721058561cbSjbeck (void) sm_strlcpy(dfname, queuename(e, DATAFL_LETTER), sizeof(dfname));
17227c478bd9Sstevel@tonic-gate
17237c478bd9Sstevel@tonic-gate /*
17247c478bd9Sstevel@tonic-gate ** In SuperSafe == SAFE_REALLY mode, e->e_dfp is a read-only FP so
17257c478bd9Sstevel@tonic-gate ** close and reopen writable (later close and reopen
17267c478bd9Sstevel@tonic-gate ** read only again).
17277c478bd9Sstevel@tonic-gate **
17287c478bd9Sstevel@tonic-gate ** In SuperSafe != SAFE_REALLY mode, e->e_dfp still points at the
17297c478bd9Sstevel@tonic-gate ** buffered file I/O descriptor, still open for writing so there
17307c478bd9Sstevel@tonic-gate ** isn't any work to do here (except checking for consistency).
17317c478bd9Sstevel@tonic-gate */
17327c478bd9Sstevel@tonic-gate
17337c478bd9Sstevel@tonic-gate if (SuperSafe == SAFE_REALLY)
17347c478bd9Sstevel@tonic-gate {
17357c478bd9Sstevel@tonic-gate /* close read-only data file */
17367c478bd9Sstevel@tonic-gate if (bitset(EF_HAS_DF, e->e_flags) && e->e_dfp != NULL)
17377c478bd9Sstevel@tonic-gate {
17387c478bd9Sstevel@tonic-gate (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT);
17397c478bd9Sstevel@tonic-gate e->e_flags &= ~EF_HAS_DF;
17407c478bd9Sstevel@tonic-gate }
17417c478bd9Sstevel@tonic-gate
17427c478bd9Sstevel@tonic-gate /* open writable */
17437c478bd9Sstevel@tonic-gate if ((e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname,
17447c478bd9Sstevel@tonic-gate SM_IO_RDWR_B, NULL)) == NULL)
17457c478bd9Sstevel@tonic-gate {
17467c478bd9Sstevel@tonic-gate MILTER_DF_ERROR("milter_reopen_df: sm_io_open %s: %s");
17477c478bd9Sstevel@tonic-gate return -1;
17487c478bd9Sstevel@tonic-gate }
17497c478bd9Sstevel@tonic-gate }
17507c478bd9Sstevel@tonic-gate else if (e->e_dfp == NULL)
17517c478bd9Sstevel@tonic-gate {
17527c478bd9Sstevel@tonic-gate /* shouldn't happen */
17537c478bd9Sstevel@tonic-gate errno = ENOENT;
17547c478bd9Sstevel@tonic-gate MILTER_DF_ERROR("milter_reopen_df: NULL e_dfp (%s: %s)");
17557c478bd9Sstevel@tonic-gate return -1;
17567c478bd9Sstevel@tonic-gate }
17577c478bd9Sstevel@tonic-gate return 0;
17587c478bd9Sstevel@tonic-gate }
1759058561cbSjbeck
17607c478bd9Sstevel@tonic-gate /*
17617c478bd9Sstevel@tonic-gate ** MILTER_RESET_DF -- re-open read-only the data file (for replbody)
17627c478bd9Sstevel@tonic-gate **
17637c478bd9Sstevel@tonic-gate ** Parameters:
17647c478bd9Sstevel@tonic-gate ** e -- current envelope.
17657c478bd9Sstevel@tonic-gate **
17667c478bd9Sstevel@tonic-gate ** Returns:
17677c478bd9Sstevel@tonic-gate ** 0 if succesful, -1 otherwise
17687c478bd9Sstevel@tonic-gate */
17697c478bd9Sstevel@tonic-gate
17707c478bd9Sstevel@tonic-gate static int
milter_reset_df(e)17717c478bd9Sstevel@tonic-gate milter_reset_df(e)
17727c478bd9Sstevel@tonic-gate ENVELOPE *e;
17737c478bd9Sstevel@tonic-gate {
17747c478bd9Sstevel@tonic-gate int afd;
17757c478bd9Sstevel@tonic-gate char dfname[MAXPATHLEN];
17767c478bd9Sstevel@tonic-gate
1777058561cbSjbeck (void) sm_strlcpy(dfname, queuename(e, DATAFL_LETTER), sizeof(dfname));
17787c478bd9Sstevel@tonic-gate
17797c478bd9Sstevel@tonic-gate if (sm_io_flush(e->e_dfp, SM_TIME_DEFAULT) != 0 ||
17807c478bd9Sstevel@tonic-gate sm_io_error(e->e_dfp))
17817c478bd9Sstevel@tonic-gate {
17827c478bd9Sstevel@tonic-gate MILTER_DF_ERROR("milter_reset_df: error writing/flushing %s: %s");
17837c478bd9Sstevel@tonic-gate return -1;
17847c478bd9Sstevel@tonic-gate }
17857c478bd9Sstevel@tonic-gate else if (SuperSafe != SAFE_REALLY)
17867c478bd9Sstevel@tonic-gate {
17877c478bd9Sstevel@tonic-gate /* skip next few clauses */
17887c478bd9Sstevel@tonic-gate /* EMPTY */
17897c478bd9Sstevel@tonic-gate }
17907c478bd9Sstevel@tonic-gate else if ((afd = sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, NULL)) >= 0
17917c478bd9Sstevel@tonic-gate && fsync(afd) < 0)
17927c478bd9Sstevel@tonic-gate {
17937c478bd9Sstevel@tonic-gate MILTER_DF_ERROR("milter_reset_df: error sync'ing %s: %s");
17947c478bd9Sstevel@tonic-gate return -1;
17957c478bd9Sstevel@tonic-gate }
17967c478bd9Sstevel@tonic-gate else if (sm_io_close(e->e_dfp, SM_TIME_DEFAULT) < 0)
17977c478bd9Sstevel@tonic-gate {
17987c478bd9Sstevel@tonic-gate MILTER_DF_ERROR("milter_reset_df: error closing %s: %s");
17997c478bd9Sstevel@tonic-gate return -1;
18007c478bd9Sstevel@tonic-gate }
18017c478bd9Sstevel@tonic-gate else if ((e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname,
18027c478bd9Sstevel@tonic-gate SM_IO_RDONLY_B, NULL)) == NULL)
18037c478bd9Sstevel@tonic-gate {
18047c478bd9Sstevel@tonic-gate MILTER_DF_ERROR("milter_reset_df: error reopening %s: %s");
18057c478bd9Sstevel@tonic-gate return -1;
18067c478bd9Sstevel@tonic-gate }
18077c478bd9Sstevel@tonic-gate else
18087c478bd9Sstevel@tonic-gate e->e_flags |= EF_HAS_DF;
18097c478bd9Sstevel@tonic-gate return 0;
18107c478bd9Sstevel@tonic-gate }
1811058561cbSjbeck
18127c478bd9Sstevel@tonic-gate /*
18137c478bd9Sstevel@tonic-gate ** MILTER_QUIT_FILTER -- close down a single filter
18147c478bd9Sstevel@tonic-gate **
18157c478bd9Sstevel@tonic-gate ** Parameters:
18167c478bd9Sstevel@tonic-gate ** m -- milter structure of filter to close down.
18177c478bd9Sstevel@tonic-gate ** e -- current envelope.
18187c478bd9Sstevel@tonic-gate **
18197c478bd9Sstevel@tonic-gate ** Returns:
18207c478bd9Sstevel@tonic-gate ** none
18217c478bd9Sstevel@tonic-gate */
18227c478bd9Sstevel@tonic-gate
18237c478bd9Sstevel@tonic-gate static void
milter_quit_filter(m,e)18247c478bd9Sstevel@tonic-gate milter_quit_filter(m, e)
18257c478bd9Sstevel@tonic-gate struct milter *m;
18267c478bd9Sstevel@tonic-gate ENVELOPE *e;
18277c478bd9Sstevel@tonic-gate {
18287c478bd9Sstevel@tonic-gate if (tTd(64, 10))
18297c478bd9Sstevel@tonic-gate sm_dprintf("milter_quit_filter(%s)\n", m->mf_name);
18307c478bd9Sstevel@tonic-gate if (MilterLogLevel > 18)
18317c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter (%s): quit filter",
18327c478bd9Sstevel@tonic-gate m->mf_name);
18337c478bd9Sstevel@tonic-gate
18347c478bd9Sstevel@tonic-gate /* Never replace error state */
18357c478bd9Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR)
18367c478bd9Sstevel@tonic-gate return;
18377c478bd9Sstevel@tonic-gate
18387c478bd9Sstevel@tonic-gate if (m->mf_sock < 0 ||
18397c478bd9Sstevel@tonic-gate m->mf_state == SMFS_CLOSED ||
18407c478bd9Sstevel@tonic-gate m->mf_state == SMFS_READY)
18417c478bd9Sstevel@tonic-gate {
18427c478bd9Sstevel@tonic-gate m->mf_sock = -1;
18437c478bd9Sstevel@tonic-gate m->mf_state = SMFS_CLOSED;
18447c478bd9Sstevel@tonic-gate return;
18457c478bd9Sstevel@tonic-gate }
18467c478bd9Sstevel@tonic-gate
18477c478bd9Sstevel@tonic-gate (void) milter_write(m, SMFIC_QUIT, (char *) NULL, 0,
1848058561cbSjbeck m->mf_timeout[SMFTO_WRITE], e, "quit_filter");
18497c478bd9Sstevel@tonic-gate if (m->mf_sock >= 0)
18507c478bd9Sstevel@tonic-gate {
18517c478bd9Sstevel@tonic-gate (void) close(m->mf_sock);
18527c478bd9Sstevel@tonic-gate m->mf_sock = -1;
18537c478bd9Sstevel@tonic-gate }
18547c478bd9Sstevel@tonic-gate if (m->mf_state != SMFS_ERROR)
18557c478bd9Sstevel@tonic-gate m->mf_state = SMFS_CLOSED;
18567c478bd9Sstevel@tonic-gate }
1857058561cbSjbeck
18587c478bd9Sstevel@tonic-gate /*
18597c478bd9Sstevel@tonic-gate ** MILTER_ABORT_FILTER -- tell filter to abort current message
18607c478bd9Sstevel@tonic-gate **
18617c478bd9Sstevel@tonic-gate ** Parameters:
18627c478bd9Sstevel@tonic-gate ** m -- milter structure of filter to abort.
18637c478bd9Sstevel@tonic-gate ** e -- current envelope.
18647c478bd9Sstevel@tonic-gate **
18657c478bd9Sstevel@tonic-gate ** Returns:
18667c478bd9Sstevel@tonic-gate ** none
18677c478bd9Sstevel@tonic-gate */
18687c478bd9Sstevel@tonic-gate
18697c478bd9Sstevel@tonic-gate static void
milter_abort_filter(m,e)18707c478bd9Sstevel@tonic-gate milter_abort_filter(m, e)
18717c478bd9Sstevel@tonic-gate struct milter *m;
18727c478bd9Sstevel@tonic-gate ENVELOPE *e;
18737c478bd9Sstevel@tonic-gate {
18747c478bd9Sstevel@tonic-gate if (tTd(64, 10))
18757c478bd9Sstevel@tonic-gate sm_dprintf("milter_abort_filter(%s)\n", m->mf_name);
18767c478bd9Sstevel@tonic-gate if (MilterLogLevel > 10)
18777c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter (%s): abort filter",
18787c478bd9Sstevel@tonic-gate m->mf_name);
18797c478bd9Sstevel@tonic-gate
18807c478bd9Sstevel@tonic-gate if (m->mf_sock < 0 ||
18817c478bd9Sstevel@tonic-gate m->mf_state != SMFS_INMSG)
18827c478bd9Sstevel@tonic-gate return;
18837c478bd9Sstevel@tonic-gate
18847c478bd9Sstevel@tonic-gate (void) milter_write(m, SMFIC_ABORT, (char *) NULL, 0,
1885058561cbSjbeck m->mf_timeout[SMFTO_WRITE], e, "abort_filter");
18867c478bd9Sstevel@tonic-gate if (m->mf_state != SMFS_ERROR)
18877c478bd9Sstevel@tonic-gate m->mf_state = SMFS_DONE;
18887c478bd9Sstevel@tonic-gate }
1889058561cbSjbeck
18907c478bd9Sstevel@tonic-gate /*
18917c478bd9Sstevel@tonic-gate ** MILTER_SEND_MACROS -- provide macros to the filters
18927c478bd9Sstevel@tonic-gate **
18937c478bd9Sstevel@tonic-gate ** Parameters:
18947c478bd9Sstevel@tonic-gate ** m -- milter to send macros to.
18957c478bd9Sstevel@tonic-gate ** macros -- macros to send for filter smfi_getsymval().
18967c478bd9Sstevel@tonic-gate ** cmd -- which command the macros are associated with.
18977c478bd9Sstevel@tonic-gate ** e -- current envelope (for macro access).
18987c478bd9Sstevel@tonic-gate **
18997c478bd9Sstevel@tonic-gate ** Returns:
19007c478bd9Sstevel@tonic-gate ** none
19017c478bd9Sstevel@tonic-gate */
19027c478bd9Sstevel@tonic-gate
19037c478bd9Sstevel@tonic-gate static void
milter_send_macros(m,macros,cmd,e)19047c478bd9Sstevel@tonic-gate milter_send_macros(m, macros, cmd, e)
19057c478bd9Sstevel@tonic-gate struct milter *m;
19067c478bd9Sstevel@tonic-gate char **macros;
1907058561cbSjbeck int cmd;
19087c478bd9Sstevel@tonic-gate ENVELOPE *e;
19097c478bd9Sstevel@tonic-gate {
19107c478bd9Sstevel@tonic-gate int i;
19117c478bd9Sstevel@tonic-gate int mid;
1912058561cbSjbeck char command = (char) cmd;
19137c478bd9Sstevel@tonic-gate char *v;
19147c478bd9Sstevel@tonic-gate char *buf, *bp;
19157c478bd9Sstevel@tonic-gate char exp[MAXLINE];
19167c478bd9Sstevel@tonic-gate ssize_t s;
19177c478bd9Sstevel@tonic-gate
19187c478bd9Sstevel@tonic-gate /* sanity check */
19197c478bd9Sstevel@tonic-gate if (macros == NULL || macros[0] == NULL)
19207c478bd9Sstevel@tonic-gate return;
19217c478bd9Sstevel@tonic-gate
19227c478bd9Sstevel@tonic-gate /* put together data */
19237c478bd9Sstevel@tonic-gate s = 1; /* for the command character */
19247c478bd9Sstevel@tonic-gate for (i = 0; macros[i] != NULL; i++)
19257c478bd9Sstevel@tonic-gate {
19267c478bd9Sstevel@tonic-gate mid = macid(macros[i]);
19277c478bd9Sstevel@tonic-gate if (mid == 0)
19287c478bd9Sstevel@tonic-gate continue;
19297c478bd9Sstevel@tonic-gate v = macvalue(mid, e);
19307c478bd9Sstevel@tonic-gate if (v == NULL)
19317c478bd9Sstevel@tonic-gate continue;
19327c478bd9Sstevel@tonic-gate expand(v, exp, sizeof(exp), e);
19337c478bd9Sstevel@tonic-gate s += strlen(macros[i]) + 1 + strlen(exp) + 1;
19347c478bd9Sstevel@tonic-gate }
19357c478bd9Sstevel@tonic-gate
19367c478bd9Sstevel@tonic-gate if (s < 0)
19377c478bd9Sstevel@tonic-gate return;
19387c478bd9Sstevel@tonic-gate
19397c478bd9Sstevel@tonic-gate buf = (char *) xalloc(s);
19407c478bd9Sstevel@tonic-gate bp = buf;
1941058561cbSjbeck *bp++ = command;
19427c478bd9Sstevel@tonic-gate for (i = 0; macros[i] != NULL; i++)
19437c478bd9Sstevel@tonic-gate {
19447c478bd9Sstevel@tonic-gate mid = macid(macros[i]);
19457c478bd9Sstevel@tonic-gate if (mid == 0)
19467c478bd9Sstevel@tonic-gate continue;
19477c478bd9Sstevel@tonic-gate v = macvalue(mid, e);
19487c478bd9Sstevel@tonic-gate if (v == NULL)
19497c478bd9Sstevel@tonic-gate continue;
19507c478bd9Sstevel@tonic-gate expand(v, exp, sizeof(exp), e);
19517c478bd9Sstevel@tonic-gate
19527c478bd9Sstevel@tonic-gate if (tTd(64, 10))
19537c478bd9Sstevel@tonic-gate sm_dprintf("milter_send_macros(%s, %c): %s=%s\n",
1954058561cbSjbeck m->mf_name, command, macros[i], exp);
19557c478bd9Sstevel@tonic-gate
19567c478bd9Sstevel@tonic-gate (void) sm_strlcpy(bp, macros[i], s - (bp - buf));
19577c478bd9Sstevel@tonic-gate bp += strlen(bp) + 1;
19587c478bd9Sstevel@tonic-gate (void) sm_strlcpy(bp, exp, s - (bp - buf));
19597c478bd9Sstevel@tonic-gate bp += strlen(bp) + 1;
19607c478bd9Sstevel@tonic-gate }
19617c478bd9Sstevel@tonic-gate (void) milter_write(m, SMFIC_MACRO, buf, s,
1962058561cbSjbeck m->mf_timeout[SMFTO_WRITE], e, "send_macros");
19637c478bd9Sstevel@tonic-gate sm_free(buf);
19647c478bd9Sstevel@tonic-gate }
19657c478bd9Sstevel@tonic-gate
19667c478bd9Sstevel@tonic-gate /*
19677c478bd9Sstevel@tonic-gate ** MILTER_SEND_COMMAND -- send a command and return the response for a filter
19687c478bd9Sstevel@tonic-gate **
19697c478bd9Sstevel@tonic-gate ** Parameters:
19707c478bd9Sstevel@tonic-gate ** m -- current milter filter
1971058561cbSjbeck ** cmd -- command to send.
19727c478bd9Sstevel@tonic-gate ** data -- optional command data.
19737c478bd9Sstevel@tonic-gate ** sz -- length of buf.
19747c478bd9Sstevel@tonic-gate ** e -- current envelope (for e->e_id).
19757c478bd9Sstevel@tonic-gate ** state -- return state word.
19767c478bd9Sstevel@tonic-gate **
19777c478bd9Sstevel@tonic-gate ** Returns:
19787c478bd9Sstevel@tonic-gate ** response string (may be NULL)
19797c478bd9Sstevel@tonic-gate */
19807c478bd9Sstevel@tonic-gate
19817c478bd9Sstevel@tonic-gate static char *
milter_send_command(m,cmd,data,sz,e,state,where)1982058561cbSjbeck milter_send_command(m, cmd, data, sz, e, state, where)
19837c478bd9Sstevel@tonic-gate struct milter *m;
1984058561cbSjbeck int cmd;
19857c478bd9Sstevel@tonic-gate void *data;
19867c478bd9Sstevel@tonic-gate ssize_t sz;
19877c478bd9Sstevel@tonic-gate ENVELOPE *e;
19887c478bd9Sstevel@tonic-gate char *state;
1989058561cbSjbeck const char *where;
19907c478bd9Sstevel@tonic-gate {
19917c478bd9Sstevel@tonic-gate char rcmd;
19927c478bd9Sstevel@tonic-gate ssize_t rlen;
19937c478bd9Sstevel@tonic-gate unsigned long skipflag;
19947c478bd9Sstevel@tonic-gate unsigned long norespflag = 0;
1995058561cbSjbeck char command = (char) cmd;
19967c478bd9Sstevel@tonic-gate char *action;
19977c478bd9Sstevel@tonic-gate char *defresponse;
19987c478bd9Sstevel@tonic-gate char *response;
19997c478bd9Sstevel@tonic-gate
20007c478bd9Sstevel@tonic-gate if (tTd(64, 10))
20017c478bd9Sstevel@tonic-gate sm_dprintf("milter_send_command(%s): cmd %c len %ld\n",
20027c478bd9Sstevel@tonic-gate m->mf_name, (char) command, (long) sz);
20037c478bd9Sstevel@tonic-gate
20047c478bd9Sstevel@tonic-gate /* find skip flag and default failure */
20057c478bd9Sstevel@tonic-gate switch (command)
20067c478bd9Sstevel@tonic-gate {
20077c478bd9Sstevel@tonic-gate case SMFIC_CONNECT:
20087c478bd9Sstevel@tonic-gate skipflag = SMFIP_NOCONNECT;
2009058561cbSjbeck norespflag = SMFIP_NR_CONN;
20107c478bd9Sstevel@tonic-gate action = "connect";
20117c478bd9Sstevel@tonic-gate defresponse = "554 Command rejected";
20127c478bd9Sstevel@tonic-gate break;
20137c478bd9Sstevel@tonic-gate
20147c478bd9Sstevel@tonic-gate case SMFIC_HELO:
20157c478bd9Sstevel@tonic-gate skipflag = SMFIP_NOHELO;
2016058561cbSjbeck norespflag = SMFIP_NR_HELO;
20177c478bd9Sstevel@tonic-gate action = "helo";
20187c478bd9Sstevel@tonic-gate defresponse = "550 Command rejected";
20197c478bd9Sstevel@tonic-gate break;
20207c478bd9Sstevel@tonic-gate
20217c478bd9Sstevel@tonic-gate case SMFIC_MAIL:
20227c478bd9Sstevel@tonic-gate skipflag = SMFIP_NOMAIL;
2023058561cbSjbeck norespflag = SMFIP_NR_MAIL;
20247c478bd9Sstevel@tonic-gate action = "mail";
20257c478bd9Sstevel@tonic-gate defresponse = "550 5.7.1 Command rejected";
20267c478bd9Sstevel@tonic-gate break;
20277c478bd9Sstevel@tonic-gate
20287c478bd9Sstevel@tonic-gate case SMFIC_RCPT:
20297c478bd9Sstevel@tonic-gate skipflag = SMFIP_NORCPT;
2030058561cbSjbeck norespflag = SMFIP_NR_RCPT;
20317c478bd9Sstevel@tonic-gate action = "rcpt";
20327c478bd9Sstevel@tonic-gate defresponse = "550 5.7.1 Command rejected";
20337c478bd9Sstevel@tonic-gate break;
20347c478bd9Sstevel@tonic-gate
20357c478bd9Sstevel@tonic-gate case SMFIC_HEADER:
20367c478bd9Sstevel@tonic-gate skipflag = SMFIP_NOHDRS;
2037058561cbSjbeck norespflag = SMFIP_NR_HDR;
20387c478bd9Sstevel@tonic-gate action = "header";
20397c478bd9Sstevel@tonic-gate defresponse = "550 5.7.1 Command rejected";
20407c478bd9Sstevel@tonic-gate break;
20417c478bd9Sstevel@tonic-gate
20427c478bd9Sstevel@tonic-gate case SMFIC_BODY:
20437c478bd9Sstevel@tonic-gate skipflag = SMFIP_NOBODY;
2044058561cbSjbeck norespflag = SMFIP_NR_BODY;
20457c478bd9Sstevel@tonic-gate action = "body";
20467c478bd9Sstevel@tonic-gate defresponse = "554 5.7.1 Command rejected";
20477c478bd9Sstevel@tonic-gate break;
20487c478bd9Sstevel@tonic-gate
20497c478bd9Sstevel@tonic-gate case SMFIC_EOH:
20507c478bd9Sstevel@tonic-gate skipflag = SMFIP_NOEOH;
2051058561cbSjbeck norespflag = SMFIP_NR_EOH;
20527c478bd9Sstevel@tonic-gate action = "eoh";
20537c478bd9Sstevel@tonic-gate defresponse = "550 5.7.1 Command rejected";
20547c478bd9Sstevel@tonic-gate break;
20557c478bd9Sstevel@tonic-gate
20567c478bd9Sstevel@tonic-gate case SMFIC_UNKNOWN:
205749218d4fSjbeck skipflag = SMFIP_NOUNKNOWN;
2058058561cbSjbeck norespflag = SMFIP_NR_UNKN;
20597c478bd9Sstevel@tonic-gate action = "unknown";
20607c478bd9Sstevel@tonic-gate defresponse = "550 5.7.1 Command rejected";
20617c478bd9Sstevel@tonic-gate break;
20627c478bd9Sstevel@tonic-gate
206349218d4fSjbeck case SMFIC_DATA:
206449218d4fSjbeck skipflag = SMFIP_NODATA;
2065058561cbSjbeck norespflag = SMFIP_NR_DATA;
206649218d4fSjbeck action = "data";
206749218d4fSjbeck defresponse = "550 5.7.1 Command rejected";
206849218d4fSjbeck break;
206949218d4fSjbeck
20707c478bd9Sstevel@tonic-gate case SMFIC_BODYEOB:
20717c478bd9Sstevel@tonic-gate case SMFIC_OPTNEG:
20727c478bd9Sstevel@tonic-gate case SMFIC_MACRO:
20737c478bd9Sstevel@tonic-gate case SMFIC_ABORT:
20747c478bd9Sstevel@tonic-gate case SMFIC_QUIT:
20757c478bd9Sstevel@tonic-gate /* NOTE: not handled by milter_send_command() */
20767c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
20777c478bd9Sstevel@tonic-gate
20787c478bd9Sstevel@tonic-gate default:
20797c478bd9Sstevel@tonic-gate skipflag = 0;
20807c478bd9Sstevel@tonic-gate action = "default";
20817c478bd9Sstevel@tonic-gate defresponse = "550 5.7.1 Command rejected";
20827c478bd9Sstevel@tonic-gate break;
20837c478bd9Sstevel@tonic-gate }
20847c478bd9Sstevel@tonic-gate
2085058561cbSjbeck if (tTd(64, 10))
2086058561cbSjbeck sm_dprintf("milter_send_command(%s): skip=%lx, pflags=%x\n",
2087058561cbSjbeck m->mf_name, skipflag, m->mf_pflags);
2088058561cbSjbeck
20897c478bd9Sstevel@tonic-gate /* check if filter wants this command */
2090058561cbSjbeck if (skipflag != 0 && bitset(skipflag, m->mf_pflags))
20917c478bd9Sstevel@tonic-gate return NULL;
20927c478bd9Sstevel@tonic-gate
20937c478bd9Sstevel@tonic-gate /* send the command to the filter */
20947c478bd9Sstevel@tonic-gate (void) milter_write(m, command, data, sz,
2095058561cbSjbeck m->mf_timeout[SMFTO_WRITE], e, where);
20967c478bd9Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR)
20977c478bd9Sstevel@tonic-gate {
20987c478bd9Sstevel@tonic-gate MILTER_CHECK_ERROR(false, return NULL);
20997c478bd9Sstevel@tonic-gate return NULL;
21007c478bd9Sstevel@tonic-gate }
21017c478bd9Sstevel@tonic-gate
21027c478bd9Sstevel@tonic-gate /* check if filter sends response to this command */
21037c478bd9Sstevel@tonic-gate if (norespflag != 0 && bitset(norespflag, m->mf_pflags))
21047c478bd9Sstevel@tonic-gate return NULL;
21057c478bd9Sstevel@tonic-gate
21067c478bd9Sstevel@tonic-gate /* get the response from the filter */
21077c478bd9Sstevel@tonic-gate response = milter_read(m, &rcmd, &rlen,
2108058561cbSjbeck m->mf_timeout[SMFTO_READ], e, where);
21097c478bd9Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR)
21107c478bd9Sstevel@tonic-gate {
21117c478bd9Sstevel@tonic-gate MILTER_CHECK_ERROR(false, return NULL);
21127c478bd9Sstevel@tonic-gate return NULL;
21137c478bd9Sstevel@tonic-gate }
21147c478bd9Sstevel@tonic-gate
21157c478bd9Sstevel@tonic-gate if (tTd(64, 10))
21167c478bd9Sstevel@tonic-gate sm_dprintf("milter_send_command(%s): returned %c\n",
21177c478bd9Sstevel@tonic-gate m->mf_name, (char) rcmd);
21187c478bd9Sstevel@tonic-gate
21197c478bd9Sstevel@tonic-gate switch (rcmd)
21207c478bd9Sstevel@tonic-gate {
21217c478bd9Sstevel@tonic-gate case SMFIR_REPLYCODE:
21227c478bd9Sstevel@tonic-gate MILTER_CHECK_REPLYCODE(defresponse);
21237c478bd9Sstevel@tonic-gate if (MilterLogLevel > 10)
2124058561cbSjbeck sm_syslog(LOG_INFO, e->e_id,
2125058561cbSjbeck "milter=%s, action=%s, reject=%s",
21267c478bd9Sstevel@tonic-gate m->mf_name, action, response);
21277c478bd9Sstevel@tonic-gate *state = rcmd;
21287c478bd9Sstevel@tonic-gate break;
21297c478bd9Sstevel@tonic-gate
21307c478bd9Sstevel@tonic-gate case SMFIR_REJECT:
21317c478bd9Sstevel@tonic-gate if (MilterLogLevel > 10)
2132058561cbSjbeck sm_syslog(LOG_INFO, e->e_id,
2133058561cbSjbeck "milter=%s, action=%s, reject",
21347c478bd9Sstevel@tonic-gate m->mf_name, action);
21357c478bd9Sstevel@tonic-gate *state = rcmd;
21367c478bd9Sstevel@tonic-gate break;
21377c478bd9Sstevel@tonic-gate
21387c478bd9Sstevel@tonic-gate case SMFIR_DISCARD:
21397c478bd9Sstevel@tonic-gate if (MilterLogLevel > 10)
2140058561cbSjbeck sm_syslog(LOG_INFO, e->e_id,
2141058561cbSjbeck "milter=%s, action=%s, discard",
21427c478bd9Sstevel@tonic-gate m->mf_name, action);
21437c478bd9Sstevel@tonic-gate *state = rcmd;
21447c478bd9Sstevel@tonic-gate break;
21457c478bd9Sstevel@tonic-gate
21467c478bd9Sstevel@tonic-gate case SMFIR_TEMPFAIL:
21477c478bd9Sstevel@tonic-gate if (MilterLogLevel > 10)
2148058561cbSjbeck sm_syslog(LOG_INFO, e->e_id,
2149058561cbSjbeck "milter=%s, action=%s, tempfail",
21507c478bd9Sstevel@tonic-gate m->mf_name, action);
21517c478bd9Sstevel@tonic-gate *state = rcmd;
21527c478bd9Sstevel@tonic-gate break;
21537c478bd9Sstevel@tonic-gate
21547c478bd9Sstevel@tonic-gate case SMFIR_ACCEPT:
21557c478bd9Sstevel@tonic-gate /* this filter is done with message/connection */
21567c478bd9Sstevel@tonic-gate if (command == SMFIC_HELO ||
21577c478bd9Sstevel@tonic-gate command == SMFIC_CONNECT)
21587c478bd9Sstevel@tonic-gate m->mf_state = SMFS_CLOSABLE;
21597c478bd9Sstevel@tonic-gate else
21607c478bd9Sstevel@tonic-gate m->mf_state = SMFS_DONE;
21617c478bd9Sstevel@tonic-gate if (MilterLogLevel > 10)
2162058561cbSjbeck sm_syslog(LOG_INFO, e->e_id,
2163058561cbSjbeck "milter=%s, action=%s, accepted",
21647c478bd9Sstevel@tonic-gate m->mf_name, action);
21657c478bd9Sstevel@tonic-gate break;
21667c478bd9Sstevel@tonic-gate
21677c478bd9Sstevel@tonic-gate case SMFIR_CONTINUE:
21687c478bd9Sstevel@tonic-gate /* if MAIL command is ok, filter is in message state */
21697c478bd9Sstevel@tonic-gate if (command == SMFIC_MAIL)
21707c478bd9Sstevel@tonic-gate m->mf_state = SMFS_INMSG;
21717c478bd9Sstevel@tonic-gate if (MilterLogLevel > 12)
2172058561cbSjbeck sm_syslog(LOG_INFO, e->e_id,
2173058561cbSjbeck "milter=%s, action=%s, continue",
2174058561cbSjbeck m->mf_name, action);
2175058561cbSjbeck break;
2176058561cbSjbeck
2177058561cbSjbeck case SMFIR_SKIP:
2178058561cbSjbeck if (MilterLogLevel > 12)
2179058561cbSjbeck sm_syslog(LOG_INFO, e->e_id,
2180058561cbSjbeck "milter=%s, action=%s, skip",
21817c478bd9Sstevel@tonic-gate m->mf_name, action);
2182058561cbSjbeck m->mf_state = SMFS_SKIP;
21837c478bd9Sstevel@tonic-gate break;
21847c478bd9Sstevel@tonic-gate
21857c478bd9Sstevel@tonic-gate default:
21867c478bd9Sstevel@tonic-gate /* Invalid response to command */
21877c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0)
21887c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
21897c478bd9Sstevel@tonic-gate "milter_send_command(%s): action=%s returned bogus response %c",
21907c478bd9Sstevel@tonic-gate m->mf_name, action, rcmd);
21917c478bd9Sstevel@tonic-gate milter_error(m, e);
21927c478bd9Sstevel@tonic-gate break;
21937c478bd9Sstevel@tonic-gate }
21947c478bd9Sstevel@tonic-gate
2195058561cbSjbeck if (*state != SMFIR_REPLYCODE && response != NULL)
21967c478bd9Sstevel@tonic-gate {
21977c478bd9Sstevel@tonic-gate sm_free(response); /* XXX */
21987c478bd9Sstevel@tonic-gate response = NULL;
21997c478bd9Sstevel@tonic-gate }
22007c478bd9Sstevel@tonic-gate return response;
22017c478bd9Sstevel@tonic-gate }
22027c478bd9Sstevel@tonic-gate
22037c478bd9Sstevel@tonic-gate /*
22047c478bd9Sstevel@tonic-gate ** MILTER_COMMAND -- send a command and return the response for each filter
22057c478bd9Sstevel@tonic-gate **
22067c478bd9Sstevel@tonic-gate ** Parameters:
2207058561cbSjbeck ** cmd -- command to send.
22087c478bd9Sstevel@tonic-gate ** data -- optional command data.
22097c478bd9Sstevel@tonic-gate ** sz -- length of buf.
22107c478bd9Sstevel@tonic-gate ** macros -- macros to send for filter smfi_getsymval().
22117c478bd9Sstevel@tonic-gate ** e -- current envelope (for macro access).
22127c478bd9Sstevel@tonic-gate ** state -- return state word.
2213058561cbSjbeck ** where -- description of calling function (logging).
2214058561cbSjbeck ** cmd_error -- did the SMTP command cause an error?
22157c478bd9Sstevel@tonic-gate **
22167c478bd9Sstevel@tonic-gate ** Returns:
22177c478bd9Sstevel@tonic-gate ** response string (may be NULL)
22187c478bd9Sstevel@tonic-gate */
22197c478bd9Sstevel@tonic-gate
22207c478bd9Sstevel@tonic-gate static char *
milter_command(cmd,data,sz,macros,e,state,where,cmd_error)2221058561cbSjbeck milter_command(cmd, data, sz, macros, e, state, where, cmd_error)
2222058561cbSjbeck int cmd;
22237c478bd9Sstevel@tonic-gate void *data;
22247c478bd9Sstevel@tonic-gate ssize_t sz;
22257c478bd9Sstevel@tonic-gate char **macros;
22267c478bd9Sstevel@tonic-gate ENVELOPE *e;
22277c478bd9Sstevel@tonic-gate char *state;
2228058561cbSjbeck const char *where;
2229058561cbSjbeck bool cmd_error;
22307c478bd9Sstevel@tonic-gate {
22317c478bd9Sstevel@tonic-gate int i;
2232058561cbSjbeck char command = (char) cmd;
22337c478bd9Sstevel@tonic-gate char *response = NULL;
22347c478bd9Sstevel@tonic-gate time_t tn = 0;
22357c478bd9Sstevel@tonic-gate
22367c478bd9Sstevel@tonic-gate if (tTd(64, 10))
22377c478bd9Sstevel@tonic-gate sm_dprintf("milter_command: cmd %c len %ld\n",
2238058561cbSjbeck command, (long) sz);
22397c478bd9Sstevel@tonic-gate
22407c478bd9Sstevel@tonic-gate *state = SMFIR_CONTINUE;
22417c478bd9Sstevel@tonic-gate for (i = 0; InputFilters[i] != NULL; i++)
22427c478bd9Sstevel@tonic-gate {
22437c478bd9Sstevel@tonic-gate struct milter *m = InputFilters[i];
22447c478bd9Sstevel@tonic-gate
22457c478bd9Sstevel@tonic-gate /* previous problem? */
22467c478bd9Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR)
22477c478bd9Sstevel@tonic-gate {
22487c478bd9Sstevel@tonic-gate MILTER_CHECK_ERROR(false, continue);
22497c478bd9Sstevel@tonic-gate break;
22507c478bd9Sstevel@tonic-gate }
22517c478bd9Sstevel@tonic-gate
22527c478bd9Sstevel@tonic-gate /* sanity check */
22537c478bd9Sstevel@tonic-gate if (m->mf_sock < 0 ||
22547c478bd9Sstevel@tonic-gate (m->mf_state != SMFS_OPEN && m->mf_state != SMFS_INMSG))
22557c478bd9Sstevel@tonic-gate continue;
22567c478bd9Sstevel@tonic-gate
22577c478bd9Sstevel@tonic-gate /* send macros (regardless of whether we send command) */
22587c478bd9Sstevel@tonic-gate if (macros != NULL && macros[0] != NULL)
22597c478bd9Sstevel@tonic-gate {
22607c478bd9Sstevel@tonic-gate milter_send_macros(m, macros, command, e);
22617c478bd9Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR)
22627c478bd9Sstevel@tonic-gate {
22637c478bd9Sstevel@tonic-gate MILTER_CHECK_ERROR(false, continue);
22647c478bd9Sstevel@tonic-gate break;
22657c478bd9Sstevel@tonic-gate }
22667c478bd9Sstevel@tonic-gate }
22677c478bd9Sstevel@tonic-gate
22687c478bd9Sstevel@tonic-gate if (MilterLogLevel > 21)
22697c478bd9Sstevel@tonic-gate tn = curtime();
22707c478bd9Sstevel@tonic-gate
2271058561cbSjbeck /*
2272058561cbSjbeck ** send the command if
2273058561cbSjbeck ** there is no error
2274058561cbSjbeck ** or it's RCPT and the client asked for it:
2275058561cbSjbeck ** !cmd_error ||
2276058561cbSjbeck ** where == "rcpt" && m->mf_pflags & SMFIP_RCPT_REJ != 0
2277058561cbSjbeck ** negate that condition and use continue
2278058561cbSjbeck */
2279058561cbSjbeck
2280058561cbSjbeck if (cmd_error &&
2281058561cbSjbeck (strcmp(where, "rcpt") != 0 ||
2282058561cbSjbeck (m->mf_pflags & SMFIP_RCPT_REJ) == 0))
2283058561cbSjbeck continue;
2284058561cbSjbeck
2285058561cbSjbeck response = milter_send_command(m, command, data, sz, e, state,
2286058561cbSjbeck where);
22877c478bd9Sstevel@tonic-gate
22887c478bd9Sstevel@tonic-gate if (MilterLogLevel > 21)
22897c478bd9Sstevel@tonic-gate {
22907c478bd9Sstevel@tonic-gate /* log the time it took for the command per filter */
22917c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id,
22927c478bd9Sstevel@tonic-gate "Milter (%s): time command (%c), %d",
22937c478bd9Sstevel@tonic-gate m->mf_name, command, (int) (tn - curtime()));
22947c478bd9Sstevel@tonic-gate }
22957c478bd9Sstevel@tonic-gate
22967c478bd9Sstevel@tonic-gate if (*state != SMFIR_CONTINUE)
22977c478bd9Sstevel@tonic-gate break;
22987c478bd9Sstevel@tonic-gate }
22997c478bd9Sstevel@tonic-gate return response;
23007c478bd9Sstevel@tonic-gate }
2301058561cbSjbeck
2302058561cbSjbeck static int milter_getsymlist __P((struct milter *, char *, int, int));
2303058561cbSjbeck
2304058561cbSjbeck static int
milter_getsymlist(m,buf,rlen,offset)2305058561cbSjbeck milter_getsymlist(m, buf, rlen, offset)
2306058561cbSjbeck struct milter *m;
2307058561cbSjbeck char *buf;
2308058561cbSjbeck int rlen;
2309058561cbSjbeck int offset;
2310058561cbSjbeck {
2311058561cbSjbeck int i, r, nummac;
2312058561cbSjbeck mi_int32 v;
2313058561cbSjbeck
2314058561cbSjbeck SM_ASSERT(m != NULL);
2315058561cbSjbeck SM_ASSERT(buf != NULL);
2316058561cbSjbeck
2317058561cbSjbeck while (offset + MILTER_LEN_BYTES < rlen)
2318058561cbSjbeck {
2319058561cbSjbeck size_t len;
2320058561cbSjbeck char **macros;
2321058561cbSjbeck
2322058561cbSjbeck nummac = 0;
2323058561cbSjbeck (void) memcpy((char *) &v, buf + offset, MILTER_LEN_BYTES);
2324058561cbSjbeck i = ntohl(v);
2325058561cbSjbeck if (i < SMFIM_FIRST || i > SMFIM_LAST)
2326058561cbSjbeck return -1;
2327058561cbSjbeck offset += MILTER_LEN_BYTES;
2328058561cbSjbeck macros = NULL;
2329058561cbSjbeck
2330058561cbSjbeck switch (i)
2331058561cbSjbeck {
2332058561cbSjbeck case MO_MACROS_CONNECT:
2333058561cbSjbeck if (macros == NULL)
2334058561cbSjbeck macros = MilterConnectMacros;
2335058561cbSjbeck /* FALLTHROUGH */
2336058561cbSjbeck
2337058561cbSjbeck case MO_MACROS_HELO:
2338058561cbSjbeck if (macros == NULL)
2339058561cbSjbeck macros = MilterHeloMacros;
2340058561cbSjbeck /* FALLTHROUGH */
2341058561cbSjbeck
2342058561cbSjbeck case MO_MACROS_ENVFROM:
2343058561cbSjbeck if (macros == NULL)
2344058561cbSjbeck macros = MilterEnvFromMacros;
2345058561cbSjbeck /* FALLTHROUGH */
2346058561cbSjbeck
2347058561cbSjbeck case MO_MACROS_ENVRCPT:
2348058561cbSjbeck if (macros == NULL)
2349058561cbSjbeck macros = MilterEnvRcptMacros;
2350058561cbSjbeck /* FALLTHROUGH */
2351058561cbSjbeck
2352058561cbSjbeck case MO_MACROS_EOM:
2353058561cbSjbeck if (macros == NULL)
2354058561cbSjbeck macros = MilterEOMMacros;
2355058561cbSjbeck /* FALLTHROUGH */
2356058561cbSjbeck
2357058561cbSjbeck case MO_MACROS_EOH:
2358058561cbSjbeck if (macros == NULL)
2359058561cbSjbeck macros = MilterEOHMacros;
2360058561cbSjbeck /* FALLTHROUGH */
2361058561cbSjbeck
2362058561cbSjbeck case MO_MACROS_DATA:
2363058561cbSjbeck if (macros == NULL)
2364058561cbSjbeck macros = MilterDataMacros;
2365058561cbSjbeck
2366058561cbSjbeck len = strlen(buf + offset);
2367058561cbSjbeck if (len > 0)
2368058561cbSjbeck {
2369058561cbSjbeck r = milter_set_macros(m->mf_name, macros,
2370058561cbSjbeck buf + offset, nummac);
2371058561cbSjbeck if (r >= 0)
2372058561cbSjbeck nummac = r;
2373058561cbSjbeck }
2374058561cbSjbeck break;
2375058561cbSjbeck
2376058561cbSjbeck default:
2377058561cbSjbeck return -1;
2378058561cbSjbeck }
2379058561cbSjbeck if (len == 0)
2380058561cbSjbeck return -1;
2381058561cbSjbeck offset += len + 1;
2382058561cbSjbeck }
2383058561cbSjbeck
2384058561cbSjbeck return 0;
2385058561cbSjbeck }
2386058561cbSjbeck
23877c478bd9Sstevel@tonic-gate /*
23887c478bd9Sstevel@tonic-gate ** MILTER_NEGOTIATE -- get version and flags from filter
23897c478bd9Sstevel@tonic-gate **
23907c478bd9Sstevel@tonic-gate ** Parameters:
23917c478bd9Sstevel@tonic-gate ** m -- milter filter structure.
23927c478bd9Sstevel@tonic-gate ** e -- current envelope.
23937800901eSjbeck ** milters -- milters structure.
23947c478bd9Sstevel@tonic-gate **
23957c478bd9Sstevel@tonic-gate ** Returns:
23967c478bd9Sstevel@tonic-gate ** 0 on success, -1 otherwise
23977c478bd9Sstevel@tonic-gate */
23987c478bd9Sstevel@tonic-gate
23997c478bd9Sstevel@tonic-gate static int
milter_negotiate(m,e,milters)24007800901eSjbeck milter_negotiate(m, e, milters)
24017c478bd9Sstevel@tonic-gate struct milter *m;
24027c478bd9Sstevel@tonic-gate ENVELOPE *e;
24037800901eSjbeck milters_T *milters;
24047c478bd9Sstevel@tonic-gate {
24057c478bd9Sstevel@tonic-gate char rcmd;
2406058561cbSjbeck mi_int32 fvers, fflags, pflags;
2407058561cbSjbeck mi_int32 mta_prot_vers, mta_prot_flags, mta_actions;
24087c478bd9Sstevel@tonic-gate ssize_t rlen;
240949218d4fSjbeck char *response;
24107c478bd9Sstevel@tonic-gate char data[MILTER_OPTLEN];
24117c478bd9Sstevel@tonic-gate
24127c478bd9Sstevel@tonic-gate /* sanity check */
24137c478bd9Sstevel@tonic-gate if (m->mf_sock < 0 || m->mf_state != SMFS_OPEN)
24147c478bd9Sstevel@tonic-gate {
24157c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0)
24167c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
24177c478bd9Sstevel@tonic-gate "Milter (%s): negotiate, impossible state",
24187c478bd9Sstevel@tonic-gate m->mf_name);
24197c478bd9Sstevel@tonic-gate milter_error(m, e);
24207c478bd9Sstevel@tonic-gate return -1;
24217c478bd9Sstevel@tonic-gate }
24227c478bd9Sstevel@tonic-gate
24234aac33d3Sjbeck #if _FFR_MILTER_CHECK
2424058561cbSjbeck mta_prot_vers = m->mf_mta_prot_version;
2425058561cbSjbeck mta_prot_flags = m->mf_mta_prot_flags;
2426058561cbSjbeck mta_actions = m->mf_mta_actions;
24274aac33d3Sjbeck #else /* _FFR_MILTER_CHECK */
2428058561cbSjbeck mta_prot_vers = SMFI_PROT_VERSION;
2429058561cbSjbeck mta_prot_flags = SMFI_CURR_PROT;
2430058561cbSjbeck mta_actions = SMFI_CURR_ACTS;
24314aac33d3Sjbeck #endif /* _FFR_MILTER_CHECK */
2432*e9af4bc0SJohn Beck #if _FFR_MDS_NEGOTIATE
2433*e9af4bc0SJohn Beck if (MilterMaxDataSize == MILTER_MDS_256K)
2434*e9af4bc0SJohn Beck mta_prot_flags |= SMFIP_MDS_256K;
2435*e9af4bc0SJohn Beck else if (MilterMaxDataSize == MILTER_MDS_1M)
2436*e9af4bc0SJohn Beck mta_prot_flags |= SMFIP_MDS_1M;
2437*e9af4bc0SJohn Beck #endif /* _FFR_MDS_NEGOTIATE */
2438058561cbSjbeck
2439058561cbSjbeck fvers = htonl(mta_prot_vers);
2440058561cbSjbeck pflags = htonl(mta_prot_flags);
2441058561cbSjbeck fflags = htonl(mta_actions);
24427c478bd9Sstevel@tonic-gate (void) memcpy(data, (char *) &fvers, MILTER_LEN_BYTES);
24437c478bd9Sstevel@tonic-gate (void) memcpy(data + MILTER_LEN_BYTES,
24447c478bd9Sstevel@tonic-gate (char *) &fflags, MILTER_LEN_BYTES);
24457c478bd9Sstevel@tonic-gate (void) memcpy(data + (MILTER_LEN_BYTES * 2),
24467c478bd9Sstevel@tonic-gate (char *) &pflags, MILTER_LEN_BYTES);
2447058561cbSjbeck (void) milter_write(m, SMFIC_OPTNEG, data, sizeof(data),
2448058561cbSjbeck m->mf_timeout[SMFTO_WRITE], e, "negotiate");
24497c478bd9Sstevel@tonic-gate
24507c478bd9Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR)
24517c478bd9Sstevel@tonic-gate return -1;
24527c478bd9Sstevel@tonic-gate
2453058561cbSjbeck if (tTd(64, 5))
2454058561cbSjbeck sm_dprintf("milter_negotiate(%s): send: version %lu, fflags 0x%lx, pflags 0x%lx\n",
2455058561cbSjbeck m->mf_name, ntohl(fvers), ntohl(fflags), ntohl(pflags));
2456058561cbSjbeck
2457058561cbSjbeck response = milter_read(m, &rcmd, &rlen, m->mf_timeout[SMFTO_READ], e,
2458058561cbSjbeck "negotiate");
24597c478bd9Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR)
24607c478bd9Sstevel@tonic-gate return -1;
24617c478bd9Sstevel@tonic-gate
24627c478bd9Sstevel@tonic-gate if (rcmd != SMFIC_OPTNEG)
24637c478bd9Sstevel@tonic-gate {
24647c478bd9Sstevel@tonic-gate if (tTd(64, 5))
24657c478bd9Sstevel@tonic-gate sm_dprintf("milter_negotiate(%s): returned %c instead of %c\n",
24667c478bd9Sstevel@tonic-gate m->mf_name, rcmd, SMFIC_OPTNEG);
24677c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0)
24687c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
24697c478bd9Sstevel@tonic-gate "Milter (%s): negotiate: returned %c instead of %c",
24707c478bd9Sstevel@tonic-gate m->mf_name, rcmd, SMFIC_OPTNEG);
24717c478bd9Sstevel@tonic-gate if (response != NULL)
24727c478bd9Sstevel@tonic-gate sm_free(response); /* XXX */
24737c478bd9Sstevel@tonic-gate milter_error(m, e);
24747c478bd9Sstevel@tonic-gate return -1;
24757c478bd9Sstevel@tonic-gate }
24767c478bd9Sstevel@tonic-gate
24777c478bd9Sstevel@tonic-gate /* Make sure we have enough bytes for the version */
24787c478bd9Sstevel@tonic-gate if (response == NULL || rlen < MILTER_LEN_BYTES)
24797c478bd9Sstevel@tonic-gate {
24807c478bd9Sstevel@tonic-gate if (tTd(64, 5))
24817c478bd9Sstevel@tonic-gate sm_dprintf("milter_negotiate(%s): did not return valid info\n",
24827c478bd9Sstevel@tonic-gate m->mf_name);
24837c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0)
24847c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
24857c478bd9Sstevel@tonic-gate "Milter (%s): negotiate: did not return valid info",
24867c478bd9Sstevel@tonic-gate m->mf_name);
24877c478bd9Sstevel@tonic-gate if (response != NULL)
24887c478bd9Sstevel@tonic-gate sm_free(response); /* XXX */
24897c478bd9Sstevel@tonic-gate milter_error(m, e);
24907c478bd9Sstevel@tonic-gate return -1;
24917c478bd9Sstevel@tonic-gate }
24927c478bd9Sstevel@tonic-gate
24937c478bd9Sstevel@tonic-gate /* extract information */
24947c478bd9Sstevel@tonic-gate (void) memcpy((char *) &fvers, response, MILTER_LEN_BYTES);
24957c478bd9Sstevel@tonic-gate
24967c478bd9Sstevel@tonic-gate /* Now make sure we have enough for the feature bitmap */
2497058561cbSjbeck if (rlen < MILTER_OPTLEN)
24987c478bd9Sstevel@tonic-gate {
24997c478bd9Sstevel@tonic-gate if (tTd(64, 5))
25007c478bd9Sstevel@tonic-gate sm_dprintf("milter_negotiate(%s): did not return enough info\n",
25017c478bd9Sstevel@tonic-gate m->mf_name);
25027c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0)
25037c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
25047c478bd9Sstevel@tonic-gate "Milter (%s): negotiate: did not return enough info",
25057c478bd9Sstevel@tonic-gate m->mf_name);
25067c478bd9Sstevel@tonic-gate if (response != NULL)
25077c478bd9Sstevel@tonic-gate sm_free(response); /* XXX */
25087c478bd9Sstevel@tonic-gate milter_error(m, e);
25097c478bd9Sstevel@tonic-gate return -1;
25107c478bd9Sstevel@tonic-gate }
25117c478bd9Sstevel@tonic-gate
25127c478bd9Sstevel@tonic-gate (void) memcpy((char *) &fflags, response + MILTER_LEN_BYTES,
25137c478bd9Sstevel@tonic-gate MILTER_LEN_BYTES);
25147c478bd9Sstevel@tonic-gate (void) memcpy((char *) &pflags, response + (MILTER_LEN_BYTES * 2),
25157c478bd9Sstevel@tonic-gate MILTER_LEN_BYTES);
25167c478bd9Sstevel@tonic-gate
25177c478bd9Sstevel@tonic-gate m->mf_fvers = ntohl(fvers);
25187c478bd9Sstevel@tonic-gate m->mf_fflags = ntohl(fflags);
25197c478bd9Sstevel@tonic-gate m->mf_pflags = ntohl(pflags);
25207c478bd9Sstevel@tonic-gate
25217c478bd9Sstevel@tonic-gate /* check for version compatibility */
25227c478bd9Sstevel@tonic-gate if (m->mf_fvers == 1 ||
25237c478bd9Sstevel@tonic-gate m->mf_fvers > SMFI_VERSION)
25247c478bd9Sstevel@tonic-gate {
25257c478bd9Sstevel@tonic-gate if (tTd(64, 5))
25267c478bd9Sstevel@tonic-gate sm_dprintf("milter_negotiate(%s): version %d != MTA milter version %d\n",
25277c478bd9Sstevel@tonic-gate m->mf_name, m->mf_fvers, SMFI_VERSION);
25287c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0)
25297c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
25307c478bd9Sstevel@tonic-gate "Milter (%s): negotiate: version %d != MTA milter version %d",
25317c478bd9Sstevel@tonic-gate m->mf_name, m->mf_fvers, SMFI_VERSION);
25327c478bd9Sstevel@tonic-gate milter_error(m, e);
2533058561cbSjbeck goto error;
25347c478bd9Sstevel@tonic-gate }
25357c478bd9Sstevel@tonic-gate
25367c478bd9Sstevel@tonic-gate /* check for filter feature mismatch */
2537058561cbSjbeck if ((m->mf_fflags & mta_actions) != m->mf_fflags)
25387c478bd9Sstevel@tonic-gate {
25397c478bd9Sstevel@tonic-gate if (tTd(64, 5))
25407c478bd9Sstevel@tonic-gate sm_dprintf("milter_negotiate(%s): filter abilities 0x%x != MTA milter abilities 0x%lx\n",
25417c478bd9Sstevel@tonic-gate m->mf_name, m->mf_fflags,
2542058561cbSjbeck (unsigned long) mta_actions);
25437c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0)
25447c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
25457c478bd9Sstevel@tonic-gate "Milter (%s): negotiate: filter abilities 0x%x != MTA milter abilities 0x%lx",
25467c478bd9Sstevel@tonic-gate m->mf_name, m->mf_fflags,
2547058561cbSjbeck (unsigned long) mta_actions);
25487c478bd9Sstevel@tonic-gate milter_error(m, e);
2549058561cbSjbeck goto error;
25507c478bd9Sstevel@tonic-gate }
25517c478bd9Sstevel@tonic-gate
2552*e9af4bc0SJohn Beck #if _FFR_MDS_NEGOTIATE
2553*e9af4bc0SJohn Beck /* use a table instead of sequence? */
2554*e9af4bc0SJohn Beck if (bitset(SMFIP_MDS_1M, m->mf_pflags))
2555*e9af4bc0SJohn Beck {
2556*e9af4bc0SJohn Beck if (MilterMaxDataSize != MILTER_MDS_1M)
2557*e9af4bc0SJohn Beck {
2558*e9af4bc0SJohn Beck /* this should not happen... */
2559*e9af4bc0SJohn Beck sm_syslog(LOG_WARNING, NOQID,
2560*e9af4bc0SJohn Beck "WARNING: Milter.maxdatasize: configured=%d, set by libmilter=%d",
2561*e9af4bc0SJohn Beck MilterMaxDataSize, MILTER_MDS_1M);
2562*e9af4bc0SJohn Beck MilterMaxDataSize = MILTER_MDS_1M;
2563*e9af4bc0SJohn Beck }
2564*e9af4bc0SJohn Beck }
2565*e9af4bc0SJohn Beck else if (bitset(SMFIP_MDS_256K, m->mf_pflags))
2566*e9af4bc0SJohn Beck {
2567*e9af4bc0SJohn Beck if (MilterMaxDataSize != MILTER_MDS_256K)
2568*e9af4bc0SJohn Beck {
2569*e9af4bc0SJohn Beck sm_syslog(LOG_WARNING, NOQID,
2570*e9af4bc0SJohn Beck "WARNING: Milter.maxdatasize: configured=%d, set by libmilter=%d",
2571*e9af4bc0SJohn Beck MilterMaxDataSize, MILTER_MDS_256K);
2572*e9af4bc0SJohn Beck MilterMaxDataSize = MILTER_MDS_256K;
2573*e9af4bc0SJohn Beck }
2574*e9af4bc0SJohn Beck }
2575*e9af4bc0SJohn Beck else if (MilterMaxDataSize != MILTER_MDS_64K)
2576*e9af4bc0SJohn Beck {
2577*e9af4bc0SJohn Beck sm_syslog(LOG_WARNING, NOQID,
2578*e9af4bc0SJohn Beck "WARNING: Milter.maxdatasize: configured=%d, set by libmilter=%d",
2579*e9af4bc0SJohn Beck MilterMaxDataSize, MILTER_MDS_64K);
2580*e9af4bc0SJohn Beck MilterMaxDataSize = MILTER_MDS_64K;
2581*e9af4bc0SJohn Beck }
2582*e9af4bc0SJohn Beck m->mf_pflags &= ~SMFI_INTERNAL;
2583*e9af4bc0SJohn Beck #endif /* _FFR_MDS_NEGOTIATE */
2584*e9af4bc0SJohn Beck
25857c478bd9Sstevel@tonic-gate /* check for protocol feature mismatch */
2586058561cbSjbeck if ((m->mf_pflags & mta_prot_flags) != m->mf_pflags)
25877c478bd9Sstevel@tonic-gate {
25887c478bd9Sstevel@tonic-gate if (tTd(64, 5))
25897c478bd9Sstevel@tonic-gate sm_dprintf("milter_negotiate(%s): protocol abilities 0x%x != MTA milter abilities 0x%lx\n",
25907c478bd9Sstevel@tonic-gate m->mf_name, m->mf_pflags,
2591058561cbSjbeck (unsigned long) mta_prot_flags);
25927c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0)
25937c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
25947c478bd9Sstevel@tonic-gate "Milter (%s): negotiate: protocol abilities 0x%x != MTA milter abilities 0x%lx",
25957c478bd9Sstevel@tonic-gate m->mf_name, m->mf_pflags,
2596058561cbSjbeck (unsigned long) mta_prot_flags);
25977c478bd9Sstevel@tonic-gate milter_error(m, e);
2598058561cbSjbeck goto error;
25997c478bd9Sstevel@tonic-gate }
26007c478bd9Sstevel@tonic-gate
260149218d4fSjbeck if (m->mf_fvers <= 2)
260249218d4fSjbeck m->mf_pflags |= SMFIP_NOUNKNOWN;
260349218d4fSjbeck if (m->mf_fvers <= 3)
260449218d4fSjbeck m->mf_pflags |= SMFIP_NODATA;
260549218d4fSjbeck
2606058561cbSjbeck if (rlen > MILTER_OPTLEN)
2607058561cbSjbeck {
2608058561cbSjbeck milter_getsymlist(m, response, rlen, MILTER_OPTLEN);
2609058561cbSjbeck }
2610058561cbSjbeck
26117800901eSjbeck if (bitset(SMFIF_DELRCPT, m->mf_fflags))
26127800901eSjbeck milters->mis_flags |= MIS_FL_DEL_RCPT;
26137800901eSjbeck if (!bitset(SMFIP_NORCPT, m->mf_pflags) &&
26147800901eSjbeck !bitset(SMFIP_NR_RCPT, m->mf_pflags))
26157800901eSjbeck milters->mis_flags |= MIS_FL_REJ_RCPT;
26167800901eSjbeck
26177c478bd9Sstevel@tonic-gate if (tTd(64, 5))
2618058561cbSjbeck sm_dprintf("milter_negotiate(%s): received: version %u, fflags 0x%x, pflags 0x%x\n",
26197c478bd9Sstevel@tonic-gate m->mf_name, m->mf_fvers, m->mf_fflags, m->mf_pflags);
26207c478bd9Sstevel@tonic-gate return 0;
2621058561cbSjbeck
2622058561cbSjbeck error:
2623058561cbSjbeck if (response != NULL)
2624058561cbSjbeck sm_free(response); /* XXX */
2625058561cbSjbeck return -1;
26267c478bd9Sstevel@tonic-gate }
2627058561cbSjbeck
26287c478bd9Sstevel@tonic-gate /*
26297c478bd9Sstevel@tonic-gate ** MILTER_PER_CONNECTION_CHECK -- checks on per-connection commands
26307c478bd9Sstevel@tonic-gate **
26317c478bd9Sstevel@tonic-gate ** Reduce code duplication by putting these checks in one place
26327c478bd9Sstevel@tonic-gate **
26337c478bd9Sstevel@tonic-gate ** Parameters:
26347c478bd9Sstevel@tonic-gate ** e -- current envelope.
26357c478bd9Sstevel@tonic-gate **
26367c478bd9Sstevel@tonic-gate ** Returns:
26377c478bd9Sstevel@tonic-gate ** none
26387c478bd9Sstevel@tonic-gate */
26397c478bd9Sstevel@tonic-gate
26407c478bd9Sstevel@tonic-gate static void
milter_per_connection_check(e)26417c478bd9Sstevel@tonic-gate milter_per_connection_check(e)
26427c478bd9Sstevel@tonic-gate ENVELOPE *e;
26437c478bd9Sstevel@tonic-gate {
26447c478bd9Sstevel@tonic-gate int i;
26457c478bd9Sstevel@tonic-gate
26467c478bd9Sstevel@tonic-gate /* see if we are done with any of the filters */
26477c478bd9Sstevel@tonic-gate for (i = 0; InputFilters[i] != NULL; i++)
26487c478bd9Sstevel@tonic-gate {
26497c478bd9Sstevel@tonic-gate struct milter *m = InputFilters[i];
26507c478bd9Sstevel@tonic-gate
26517c478bd9Sstevel@tonic-gate if (m->mf_state == SMFS_CLOSABLE)
26527c478bd9Sstevel@tonic-gate milter_quit_filter(m, e);
26537c478bd9Sstevel@tonic-gate }
26547c478bd9Sstevel@tonic-gate }
2655058561cbSjbeck
26567c478bd9Sstevel@tonic-gate /*
26577c478bd9Sstevel@tonic-gate ** MILTER_ERROR -- Put a milter filter into error state
26587c478bd9Sstevel@tonic-gate **
26597c478bd9Sstevel@tonic-gate ** Parameters:
26607c478bd9Sstevel@tonic-gate ** m -- the broken filter.
26617c478bd9Sstevel@tonic-gate ** e -- current envelope.
26627c478bd9Sstevel@tonic-gate **
26637c478bd9Sstevel@tonic-gate ** Returns:
26647c478bd9Sstevel@tonic-gate ** none
26657c478bd9Sstevel@tonic-gate */
26667c478bd9Sstevel@tonic-gate
26677c478bd9Sstevel@tonic-gate static void
milter_error(m,e)26687c478bd9Sstevel@tonic-gate milter_error(m, e)
26697c478bd9Sstevel@tonic-gate struct milter *m;
26707c478bd9Sstevel@tonic-gate ENVELOPE *e;
26717c478bd9Sstevel@tonic-gate {
26727c478bd9Sstevel@tonic-gate /*
26737c478bd9Sstevel@tonic-gate ** We could send a quit here but we may have gotten here due to
26747c478bd9Sstevel@tonic-gate ** an I/O error so we don't want to try to make things worse.
26757c478bd9Sstevel@tonic-gate */
26767c478bd9Sstevel@tonic-gate
26777c478bd9Sstevel@tonic-gate if (m->mf_sock >= 0)
26787c478bd9Sstevel@tonic-gate {
26797c478bd9Sstevel@tonic-gate (void) close(m->mf_sock);
26807c478bd9Sstevel@tonic-gate m->mf_sock = -1;
26817c478bd9Sstevel@tonic-gate }
26827c478bd9Sstevel@tonic-gate m->mf_state = SMFS_ERROR;
26837c478bd9Sstevel@tonic-gate
26847c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0)
26857c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter (%s): to error state",
26867c478bd9Sstevel@tonic-gate m->mf_name);
26877c478bd9Sstevel@tonic-gate }
2688058561cbSjbeck
26897c478bd9Sstevel@tonic-gate /*
26907c478bd9Sstevel@tonic-gate ** MILTER_HEADERS -- send headers to a single milter filter
26917c478bd9Sstevel@tonic-gate **
26927c478bd9Sstevel@tonic-gate ** Parameters:
26937c478bd9Sstevel@tonic-gate ** m -- current filter.
26947c478bd9Sstevel@tonic-gate ** e -- current envelope.
26957c478bd9Sstevel@tonic-gate ** state -- return state from response.
26967c478bd9Sstevel@tonic-gate **
26977c478bd9Sstevel@tonic-gate ** Returns:
26987c478bd9Sstevel@tonic-gate ** response string (may be NULL)
26997c478bd9Sstevel@tonic-gate */
27007c478bd9Sstevel@tonic-gate
27017c478bd9Sstevel@tonic-gate static char *
milter_headers(m,e,state)27027c478bd9Sstevel@tonic-gate milter_headers(m, e, state)
27037c478bd9Sstevel@tonic-gate struct milter *m;
27047c478bd9Sstevel@tonic-gate ENVELOPE *e;
27057c478bd9Sstevel@tonic-gate char *state;
27067c478bd9Sstevel@tonic-gate {
27077c478bd9Sstevel@tonic-gate char *response = NULL;
27087c478bd9Sstevel@tonic-gate HDR *h;
27097c478bd9Sstevel@tonic-gate
27107c478bd9Sstevel@tonic-gate if (MilterLogLevel > 17)
27117c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter (%s): headers, send",
27127c478bd9Sstevel@tonic-gate m->mf_name);
27137c478bd9Sstevel@tonic-gate
27147c478bd9Sstevel@tonic-gate for (h = e->e_header; h != NULL; h = h->h_link)
27157c478bd9Sstevel@tonic-gate {
2716058561cbSjbeck int len_n, len_v, len_t, len_f;
2717058561cbSjbeck char *buf, *hv;
27187c478bd9Sstevel@tonic-gate
27197c478bd9Sstevel@tonic-gate /* don't send over deleted headers */
27207c478bd9Sstevel@tonic-gate if (h->h_value == NULL)
27217c478bd9Sstevel@tonic-gate {
27227c478bd9Sstevel@tonic-gate /* strip H_USER so not counted in milter_changeheader() */
27237c478bd9Sstevel@tonic-gate h->h_flags &= ~H_USER;
27247c478bd9Sstevel@tonic-gate continue;
27257c478bd9Sstevel@tonic-gate }
27267c478bd9Sstevel@tonic-gate
27277c478bd9Sstevel@tonic-gate /* skip auto-generated */
27287c478bd9Sstevel@tonic-gate if (!bitset(H_USER, h->h_flags))
27297c478bd9Sstevel@tonic-gate continue;
27307c478bd9Sstevel@tonic-gate
27317c478bd9Sstevel@tonic-gate if (tTd(64, 10))
2732058561cbSjbeck sm_dprintf("milter_headers: %s:%s\n",
27337c478bd9Sstevel@tonic-gate h->h_field, h->h_value);
27347c478bd9Sstevel@tonic-gate if (MilterLogLevel > 21)
27357c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter (%s): header, %s",
27367c478bd9Sstevel@tonic-gate m->mf_name, h->h_field);
27377c478bd9Sstevel@tonic-gate
2738058561cbSjbeck if (bitset(SMFIP_HDR_LEADSPC, m->mf_pflags)
2739058561cbSjbeck || *(h->h_value) != ' ')
2740058561cbSjbeck hv = h->h_value;
2741058561cbSjbeck else
2742058561cbSjbeck hv = h->h_value + 1;
2743058561cbSjbeck len_f = strlen(h->h_field) + 1;
2744058561cbSjbeck len_t = len_f + strlen(hv) + 1;
2745058561cbSjbeck if (len_t < 0)
27467c478bd9Sstevel@tonic-gate continue;
2747058561cbSjbeck buf = (char *) xalloc(len_t);
2748058561cbSjbeck
2749058561cbSjbeck /*
2750058561cbSjbeck ** Note: currently the call to dequote_internal_chars()
2751058561cbSjbeck ** is not required as h_field is supposed to be 7-bit US-ASCII.
2752058561cbSjbeck */
2753058561cbSjbeck
2754058561cbSjbeck len_n = dequote_internal_chars(h->h_field, buf, len_f);
2755058561cbSjbeck SM_ASSERT(len_n < len_f);
2756058561cbSjbeck len_v = dequote_internal_chars(hv, buf + len_n + 1,
2757058561cbSjbeck len_t - len_n - 1);
2758058561cbSjbeck SM_ASSERT(len_t >= len_n + 1 + len_v + 1);
2759058561cbSjbeck len_t = len_n + 1 + len_v + 1;
27607c478bd9Sstevel@tonic-gate
27617c478bd9Sstevel@tonic-gate /* send it over */
27627c478bd9Sstevel@tonic-gate response = milter_send_command(m, SMFIC_HEADER, buf,
2763058561cbSjbeck len_t, e, state, "header");
2764058561cbSjbeck sm_free(buf);
27657c478bd9Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR ||
27667c478bd9Sstevel@tonic-gate m->mf_state == SMFS_DONE ||
27677c478bd9Sstevel@tonic-gate *state != SMFIR_CONTINUE)
27687c478bd9Sstevel@tonic-gate break;
27697c478bd9Sstevel@tonic-gate }
27707c478bd9Sstevel@tonic-gate if (MilterLogLevel > 17)
27717c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter (%s): headers, sent",
27727c478bd9Sstevel@tonic-gate m->mf_name);
27737c478bd9Sstevel@tonic-gate return response;
27747c478bd9Sstevel@tonic-gate }
2775058561cbSjbeck
27767c478bd9Sstevel@tonic-gate /*
27777c478bd9Sstevel@tonic-gate ** MILTER_BODY -- send the body to a filter
27787c478bd9Sstevel@tonic-gate **
27797c478bd9Sstevel@tonic-gate ** Parameters:
27807c478bd9Sstevel@tonic-gate ** m -- current filter.
27817c478bd9Sstevel@tonic-gate ** e -- current envelope.
27827c478bd9Sstevel@tonic-gate ** state -- return state from response.
27837c478bd9Sstevel@tonic-gate **
27847c478bd9Sstevel@tonic-gate ** Returns:
27857c478bd9Sstevel@tonic-gate ** response string (may be NULL)
27867c478bd9Sstevel@tonic-gate */
27877c478bd9Sstevel@tonic-gate
27887c478bd9Sstevel@tonic-gate static char *
milter_body(m,e,state)27897c478bd9Sstevel@tonic-gate milter_body(m, e, state)
27907c478bd9Sstevel@tonic-gate struct milter *m;
27917c478bd9Sstevel@tonic-gate ENVELOPE *e;
27927c478bd9Sstevel@tonic-gate char *state;
27937c478bd9Sstevel@tonic-gate {
27947c478bd9Sstevel@tonic-gate char bufchar = '\0';
27957c478bd9Sstevel@tonic-gate char prevchar = '\0';
27967c478bd9Sstevel@tonic-gate int c;
27977c478bd9Sstevel@tonic-gate char *response = NULL;
27987c478bd9Sstevel@tonic-gate char *bp;
27997c478bd9Sstevel@tonic-gate char buf[MILTER_CHUNK_SIZE];
28007c478bd9Sstevel@tonic-gate
28017c478bd9Sstevel@tonic-gate if (tTd(64, 10))
28027c478bd9Sstevel@tonic-gate sm_dprintf("milter_body\n");
28037c478bd9Sstevel@tonic-gate
28047c478bd9Sstevel@tonic-gate if (bfrewind(e->e_dfp) < 0)
28057c478bd9Sstevel@tonic-gate {
28067c478bd9Sstevel@tonic-gate ExitStat = EX_IOERR;
28077c478bd9Sstevel@tonic-gate *state = SMFIR_TEMPFAIL;
28087c478bd9Sstevel@tonic-gate syserr("milter_body: %s/%cf%s: rewind error",
28097c478bd9Sstevel@tonic-gate qid_printqueue(e->e_qgrp, e->e_qdir),
28107c478bd9Sstevel@tonic-gate DATAFL_LETTER, e->e_id);
28117c478bd9Sstevel@tonic-gate return NULL;
28127c478bd9Sstevel@tonic-gate }
28137c478bd9Sstevel@tonic-gate
28147c478bd9Sstevel@tonic-gate if (MilterLogLevel > 17)
28157c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter (%s): body, send",
28167c478bd9Sstevel@tonic-gate m->mf_name);
28177c478bd9Sstevel@tonic-gate bp = buf;
28187c478bd9Sstevel@tonic-gate while ((c = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT)) != SM_IO_EOF)
28197c478bd9Sstevel@tonic-gate {
28207c478bd9Sstevel@tonic-gate /* Change LF to CRLF */
28217c478bd9Sstevel@tonic-gate if (c == '\n')
28227c478bd9Sstevel@tonic-gate {
2823058561cbSjbeck #if !_FFR_MILTER_CONVERT_ALL_LF_TO_CRLF
28247c478bd9Sstevel@tonic-gate /* Not a CRLF already? */
28257c478bd9Sstevel@tonic-gate if (prevchar != '\r')
2826058561cbSjbeck #endif /* !_FFR_MILTER_CONVERT_ALL_LF_TO_CRLF */
28277c478bd9Sstevel@tonic-gate {
28287c478bd9Sstevel@tonic-gate /* Room for CR now? */
2829058561cbSjbeck if (bp + 2 > &buf[sizeof(buf)])
28307c478bd9Sstevel@tonic-gate {
28317c478bd9Sstevel@tonic-gate /* No room, buffer LF */
28327c478bd9Sstevel@tonic-gate bufchar = c;
28337c478bd9Sstevel@tonic-gate
28347c478bd9Sstevel@tonic-gate /* and send CR now */
28357c478bd9Sstevel@tonic-gate c = '\r';
28367c478bd9Sstevel@tonic-gate }
28377c478bd9Sstevel@tonic-gate else
28387c478bd9Sstevel@tonic-gate {
28397c478bd9Sstevel@tonic-gate /* Room to do it now */
28407c478bd9Sstevel@tonic-gate *bp++ = '\r';
28417c478bd9Sstevel@tonic-gate prevchar = '\r';
28427c478bd9Sstevel@tonic-gate }
28437c478bd9Sstevel@tonic-gate }
28447c478bd9Sstevel@tonic-gate }
28457c478bd9Sstevel@tonic-gate *bp++ = (char) c;
28467c478bd9Sstevel@tonic-gate prevchar = c;
2847058561cbSjbeck if (bp >= &buf[sizeof(buf)])
28487c478bd9Sstevel@tonic-gate {
28497c478bd9Sstevel@tonic-gate /* send chunk */
28507c478bd9Sstevel@tonic-gate response = milter_send_command(m, SMFIC_BODY, buf,
2851058561cbSjbeck bp - buf, e, state,
2852058561cbSjbeck "body chunk");
28537c478bd9Sstevel@tonic-gate bp = buf;
28547c478bd9Sstevel@tonic-gate if (bufchar != '\0')
28557c478bd9Sstevel@tonic-gate {
28567c478bd9Sstevel@tonic-gate *bp++ = bufchar;
28577c478bd9Sstevel@tonic-gate bufchar = '\0';
28587c478bd9Sstevel@tonic-gate prevchar = bufchar;
28597c478bd9Sstevel@tonic-gate }
28607c478bd9Sstevel@tonic-gate }
28617c478bd9Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR ||
28627c478bd9Sstevel@tonic-gate m->mf_state == SMFS_DONE ||
2863058561cbSjbeck m->mf_state == SMFS_SKIP ||
28647c478bd9Sstevel@tonic-gate *state != SMFIR_CONTINUE)
28657c478bd9Sstevel@tonic-gate break;
28667c478bd9Sstevel@tonic-gate }
28677c478bd9Sstevel@tonic-gate
28687c478bd9Sstevel@tonic-gate /* check for read errors */
28697c478bd9Sstevel@tonic-gate if (sm_io_error(e->e_dfp))
28707c478bd9Sstevel@tonic-gate {
28717c478bd9Sstevel@tonic-gate ExitStat = EX_IOERR;
28727c478bd9Sstevel@tonic-gate if (*state == SMFIR_CONTINUE ||
2873058561cbSjbeck *state == SMFIR_ACCEPT ||
2874058561cbSjbeck m->mf_state == SMFS_SKIP)
28757c478bd9Sstevel@tonic-gate {
28767c478bd9Sstevel@tonic-gate *state = SMFIR_TEMPFAIL;
28777c478bd9Sstevel@tonic-gate if (response != NULL)
28787c478bd9Sstevel@tonic-gate {
28797c478bd9Sstevel@tonic-gate sm_free(response); /* XXX */
28807c478bd9Sstevel@tonic-gate response = NULL;
28817c478bd9Sstevel@tonic-gate }
28827c478bd9Sstevel@tonic-gate }
28837c478bd9Sstevel@tonic-gate syserr("milter_body: %s/%cf%s: read error",
28847c478bd9Sstevel@tonic-gate qid_printqueue(e->e_qgrp, e->e_qdir),
28857c478bd9Sstevel@tonic-gate DATAFL_LETTER, e->e_id);
28867c478bd9Sstevel@tonic-gate return response;
28877c478bd9Sstevel@tonic-gate }
28887c478bd9Sstevel@tonic-gate
28897c478bd9Sstevel@tonic-gate /* send last body chunk */
28907c478bd9Sstevel@tonic-gate if (bp > buf &&
28917c478bd9Sstevel@tonic-gate m->mf_state != SMFS_ERROR &&
28927c478bd9Sstevel@tonic-gate m->mf_state != SMFS_DONE &&
2893058561cbSjbeck m->mf_state != SMFS_SKIP &&
28947c478bd9Sstevel@tonic-gate *state == SMFIR_CONTINUE)
28957c478bd9Sstevel@tonic-gate {
28967c478bd9Sstevel@tonic-gate /* send chunk */
28977c478bd9Sstevel@tonic-gate response = milter_send_command(m, SMFIC_BODY, buf, bp - buf,
2898058561cbSjbeck e, state, "last body chunk");
28997c478bd9Sstevel@tonic-gate bp = buf;
29007c478bd9Sstevel@tonic-gate }
29017c478bd9Sstevel@tonic-gate if (MilterLogLevel > 17)
29027c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter (%s): body, sent",
29037c478bd9Sstevel@tonic-gate m->mf_name);
2904058561cbSjbeck if (m->mf_state == SMFS_SKIP)
2905058561cbSjbeck {
2906058561cbSjbeck *state = SMFIR_CONTINUE;
2907058561cbSjbeck m->mf_state = SMFS_READY;
2908058561cbSjbeck }
2909058561cbSjbeck
29107c478bd9Sstevel@tonic-gate return response;
29117c478bd9Sstevel@tonic-gate }
29127c478bd9Sstevel@tonic-gate
29137c478bd9Sstevel@tonic-gate /*
29147c478bd9Sstevel@tonic-gate ** Actions
29157c478bd9Sstevel@tonic-gate */
29167c478bd9Sstevel@tonic-gate
2917058561cbSjbeck /*
2918058561cbSjbeck ** ADDLEADINGSPACE -- Add a leading space to a string
2919058561cbSjbeck **
2920058561cbSjbeck ** Parameters:
2921058561cbSjbeck ** str -- string
2922058561cbSjbeck ** rp -- resource pool for allocations
2923058561cbSjbeck **
2924058561cbSjbeck ** Returns:
2925058561cbSjbeck ** pointer to new string
2926058561cbSjbeck */
2927058561cbSjbeck
2928058561cbSjbeck static char *addleadingspace __P((char *, SM_RPOOL_T *));
2929058561cbSjbeck
2930058561cbSjbeck static char *
addleadingspace(str,rp)2931058561cbSjbeck addleadingspace(str, rp)
2932058561cbSjbeck char *str;
2933058561cbSjbeck SM_RPOOL_T *rp;
2934058561cbSjbeck {
2935058561cbSjbeck size_t l;
2936058561cbSjbeck char *new;
2937058561cbSjbeck
2938058561cbSjbeck SM_ASSERT(str != NULL);
2939058561cbSjbeck l = strlen(str);
2940058561cbSjbeck SM_ASSERT(l + 2 > l);
2941058561cbSjbeck new = sm_rpool_malloc_x(rp, l + 2);
2942058561cbSjbeck new[0] = ' ';
2943058561cbSjbeck new[1] = '\0';
2944058561cbSjbeck sm_strlcpy(new + 1, str, l + 1);
2945058561cbSjbeck return new;
2946058561cbSjbeck }
2947058561cbSjbeck
29487c478bd9Sstevel@tonic-gate /*
29497c478bd9Sstevel@tonic-gate ** MILTER_ADDHEADER -- Add the supplied header to the message
29507c478bd9Sstevel@tonic-gate **
29517c478bd9Sstevel@tonic-gate ** Parameters:
2952058561cbSjbeck ** m -- current filter.
29537c478bd9Sstevel@tonic-gate ** response -- encoded form of header/value.
29547c478bd9Sstevel@tonic-gate ** rlen -- length of response.
29557c478bd9Sstevel@tonic-gate ** e -- current envelope.
29567c478bd9Sstevel@tonic-gate **
29577c478bd9Sstevel@tonic-gate ** Returns:
29587c478bd9Sstevel@tonic-gate ** none
29597c478bd9Sstevel@tonic-gate */
29607c478bd9Sstevel@tonic-gate
29617c478bd9Sstevel@tonic-gate static void
milter_addheader(m,response,rlen,e)2962058561cbSjbeck milter_addheader(m, response, rlen, e)
2963058561cbSjbeck struct milter *m;
29647c478bd9Sstevel@tonic-gate char *response;
29657c478bd9Sstevel@tonic-gate ssize_t rlen;
29667c478bd9Sstevel@tonic-gate ENVELOPE *e;
29677c478bd9Sstevel@tonic-gate {
2968058561cbSjbeck int mh_v_len;
2969058561cbSjbeck char *val, *mh_value;
29707c478bd9Sstevel@tonic-gate HDR *h;
29717c478bd9Sstevel@tonic-gate
29727c478bd9Sstevel@tonic-gate if (tTd(64, 10))
29737c478bd9Sstevel@tonic-gate sm_dprintf("milter_addheader: ");
29747c478bd9Sstevel@tonic-gate
29757c478bd9Sstevel@tonic-gate /* sanity checks */
29767c478bd9Sstevel@tonic-gate if (response == NULL)
29777c478bd9Sstevel@tonic-gate {
29787c478bd9Sstevel@tonic-gate if (tTd(64, 10))
29797c478bd9Sstevel@tonic-gate sm_dprintf("NULL response\n");
29807c478bd9Sstevel@tonic-gate return;
29817c478bd9Sstevel@tonic-gate }
29827c478bd9Sstevel@tonic-gate
29837c478bd9Sstevel@tonic-gate if (rlen < 2 || strlen(response) + 1 >= (size_t) rlen)
29847c478bd9Sstevel@tonic-gate {
29857c478bd9Sstevel@tonic-gate if (tTd(64, 10))
2986058561cbSjbeck sm_dprintf("didn't follow protocol (total len %d != rlen %d)\n",
2987058561cbSjbeck (int) strlen(response), (int) (rlen - 1));
29887c478bd9Sstevel@tonic-gate return;
29897c478bd9Sstevel@tonic-gate }
29907c478bd9Sstevel@tonic-gate
29917c478bd9Sstevel@tonic-gate /* Find separating NUL */
29927c478bd9Sstevel@tonic-gate val = response + strlen(response) + 1;
29937c478bd9Sstevel@tonic-gate
29947c478bd9Sstevel@tonic-gate /* another sanity check */
29957c478bd9Sstevel@tonic-gate if (strlen(response) + strlen(val) + 2 != (size_t) rlen)
29967c478bd9Sstevel@tonic-gate {
29977c478bd9Sstevel@tonic-gate if (tTd(64, 10))
29987c478bd9Sstevel@tonic-gate sm_dprintf("didn't follow protocol (part len)\n");
29997c478bd9Sstevel@tonic-gate return;
30007c478bd9Sstevel@tonic-gate }
30017c478bd9Sstevel@tonic-gate
30027c478bd9Sstevel@tonic-gate if (*response == '\0')
30037c478bd9Sstevel@tonic-gate {
30047c478bd9Sstevel@tonic-gate if (tTd(64, 10))
30057c478bd9Sstevel@tonic-gate sm_dprintf("empty field name\n");
30067c478bd9Sstevel@tonic-gate return;
30077c478bd9Sstevel@tonic-gate }
30087c478bd9Sstevel@tonic-gate
30097c478bd9Sstevel@tonic-gate for (h = e->e_header; h != NULL; h = h->h_link)
30107c478bd9Sstevel@tonic-gate {
30117c478bd9Sstevel@tonic-gate if (sm_strcasecmp(h->h_field, response) == 0 &&
30127c478bd9Sstevel@tonic-gate !bitset(H_USER, h->h_flags) &&
30137c478bd9Sstevel@tonic-gate !bitset(H_TRACE, h->h_flags))
30147c478bd9Sstevel@tonic-gate break;
30157c478bd9Sstevel@tonic-gate }
30167c478bd9Sstevel@tonic-gate
3017058561cbSjbeck mh_v_len = 0;
3018058561cbSjbeck mh_value = quote_internal_chars(val, NULL, &mh_v_len);
3019058561cbSjbeck
30207c478bd9Sstevel@tonic-gate /* add to e_msgsize */
30217c478bd9Sstevel@tonic-gate e->e_msgsize += strlen(response) + 2 + strlen(val);
30227c478bd9Sstevel@tonic-gate
30237c478bd9Sstevel@tonic-gate if (h != NULL)
30247c478bd9Sstevel@tonic-gate {
30257c478bd9Sstevel@tonic-gate if (tTd(64, 10))
30267c478bd9Sstevel@tonic-gate sm_dprintf("Replace default header %s value with %s\n",
3027058561cbSjbeck h->h_field, mh_value);
30287c478bd9Sstevel@tonic-gate if (MilterLogLevel > 8)
30297c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id,
30307c478bd9Sstevel@tonic-gate "Milter change: default header %s value with %s",
3031058561cbSjbeck h->h_field, mh_value);
3032058561cbSjbeck if (bitset(SMFIP_HDR_LEADSPC, m->mf_pflags))
3033058561cbSjbeck h->h_value = mh_value;
3034058561cbSjbeck else
3035058561cbSjbeck {
3036*e9af4bc0SJohn Beck h->h_value = addleadingspace(mh_value, e->e_rpool);
3037058561cbSjbeck SM_FREE(mh_value);
3038058561cbSjbeck }
30397c478bd9Sstevel@tonic-gate h->h_flags |= H_USER;
30407c478bd9Sstevel@tonic-gate }
30417c478bd9Sstevel@tonic-gate else
30427c478bd9Sstevel@tonic-gate {
30437c478bd9Sstevel@tonic-gate if (tTd(64, 10))
3044058561cbSjbeck sm_dprintf("Add %s: %s\n", response, mh_value);
30457c478bd9Sstevel@tonic-gate if (MilterLogLevel > 8)
3046058561cbSjbeck sm_syslog(LOG_INFO, e->e_id,
3047058561cbSjbeck "Milter add: header: %s: %s",
3048058561cbSjbeck response, mh_value);
3049058561cbSjbeck addheader(newstr(response), mh_value, H_USER, e,
3050058561cbSjbeck !bitset(SMFIP_HDR_LEADSPC, m->mf_pflags));
3051058561cbSjbeck SM_FREE(mh_value);
30527c478bd9Sstevel@tonic-gate }
30537c478bd9Sstevel@tonic-gate }
3054058561cbSjbeck
30557c478bd9Sstevel@tonic-gate /*
30567c478bd9Sstevel@tonic-gate ** MILTER_INSHEADER -- Insert the supplied header
30577c478bd9Sstevel@tonic-gate **
30587c478bd9Sstevel@tonic-gate ** Parameters:
3059058561cbSjbeck ** m -- current filter.
30607c478bd9Sstevel@tonic-gate ** response -- encoded form of header/value.
30617c478bd9Sstevel@tonic-gate ** rlen -- length of response.
30627c478bd9Sstevel@tonic-gate ** e -- current envelope.
30637c478bd9Sstevel@tonic-gate **
30647c478bd9Sstevel@tonic-gate ** Returns:
30657c478bd9Sstevel@tonic-gate ** none
30667c478bd9Sstevel@tonic-gate **
306749218d4fSjbeck ** Notes:
306849218d4fSjbeck ** Unlike milter_addheader(), this does not attempt to determine
306949218d4fSjbeck ** if the header already exists in the envelope, even a
307049218d4fSjbeck ** deleted version. It just blindly inserts.
30717c478bd9Sstevel@tonic-gate */
30727c478bd9Sstevel@tonic-gate
30737c478bd9Sstevel@tonic-gate static void
milter_insheader(m,response,rlen,e)3074058561cbSjbeck milter_insheader(m, response, rlen, e)
3075058561cbSjbeck struct milter *m;
30767c478bd9Sstevel@tonic-gate char *response;
30777c478bd9Sstevel@tonic-gate ssize_t rlen;
30787c478bd9Sstevel@tonic-gate ENVELOPE *e;
30797c478bd9Sstevel@tonic-gate {
30807c478bd9Sstevel@tonic-gate mi_int32 idx, i;
3081058561cbSjbeck int mh_v_len;
3082058561cbSjbeck char *field, *val, *mh_value;
30837c478bd9Sstevel@tonic-gate
30847c478bd9Sstevel@tonic-gate if (tTd(64, 10))
30857c478bd9Sstevel@tonic-gate sm_dprintf("milter_insheader: ");
30867c478bd9Sstevel@tonic-gate
30877c478bd9Sstevel@tonic-gate /* sanity checks */
30887c478bd9Sstevel@tonic-gate if (response == NULL)
30897c478bd9Sstevel@tonic-gate {
30907c478bd9Sstevel@tonic-gate if (tTd(64, 10))
30917c478bd9Sstevel@tonic-gate sm_dprintf("NULL response\n");
30927c478bd9Sstevel@tonic-gate return;
30937c478bd9Sstevel@tonic-gate }
30947c478bd9Sstevel@tonic-gate
30957c478bd9Sstevel@tonic-gate if (rlen < 2 || strlen(response) + 1 >= (size_t) rlen)
30967c478bd9Sstevel@tonic-gate {
30977c478bd9Sstevel@tonic-gate if (tTd(64, 10))
30987c478bd9Sstevel@tonic-gate sm_dprintf("didn't follow protocol (total len)\n");
30997c478bd9Sstevel@tonic-gate return;
31007c478bd9Sstevel@tonic-gate }
31017c478bd9Sstevel@tonic-gate
31027c478bd9Sstevel@tonic-gate /* decode */
31037c478bd9Sstevel@tonic-gate (void) memcpy((char *) &i, response, MILTER_LEN_BYTES);
31047c478bd9Sstevel@tonic-gate idx = ntohl(i);
31057c478bd9Sstevel@tonic-gate field = response + MILTER_LEN_BYTES;
31067c478bd9Sstevel@tonic-gate val = field + strlen(field) + 1;
31077c478bd9Sstevel@tonic-gate
31087c478bd9Sstevel@tonic-gate /* another sanity check */
31097c478bd9Sstevel@tonic-gate if (MILTER_LEN_BYTES + strlen(field) + 1 +
31107c478bd9Sstevel@tonic-gate strlen(val) + 1 != (size_t) rlen)
31117c478bd9Sstevel@tonic-gate {
31127c478bd9Sstevel@tonic-gate if (tTd(64, 10))
31137c478bd9Sstevel@tonic-gate sm_dprintf("didn't follow protocol (part len)\n");
31147c478bd9Sstevel@tonic-gate return;
31157c478bd9Sstevel@tonic-gate }
31167c478bd9Sstevel@tonic-gate
31177c478bd9Sstevel@tonic-gate if (*field == '\0')
31187c478bd9Sstevel@tonic-gate {
31197c478bd9Sstevel@tonic-gate if (tTd(64, 10))
31207c478bd9Sstevel@tonic-gate sm_dprintf("empty field name\n");
31217c478bd9Sstevel@tonic-gate return;
31227c478bd9Sstevel@tonic-gate }
31237c478bd9Sstevel@tonic-gate
31247c478bd9Sstevel@tonic-gate /* add to e_msgsize */
31257c478bd9Sstevel@tonic-gate e->e_msgsize += strlen(response) + 2 + strlen(val);
31267c478bd9Sstevel@tonic-gate
31277c478bd9Sstevel@tonic-gate if (tTd(64, 10))
3128058561cbSjbeck sm_dprintf("Insert (%d) %s: %s\n", idx, field, val);
31297c478bd9Sstevel@tonic-gate if (MilterLogLevel > 8)
31307c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id,
313149218d4fSjbeck "Milter insert (%d): header: %s: %s",
31327c478bd9Sstevel@tonic-gate idx, field, val);
3133058561cbSjbeck mh_v_len = 0;
3134058561cbSjbeck mh_value = quote_internal_chars(val, NULL, &mh_v_len);
3135058561cbSjbeck insheader(idx, newstr(field), mh_value, H_USER, e,
3136058561cbSjbeck !bitset(SMFIP_HDR_LEADSPC, m->mf_pflags));
3137058561cbSjbeck SM_FREE(mh_value);
31387c478bd9Sstevel@tonic-gate }
3139058561cbSjbeck
31407c478bd9Sstevel@tonic-gate /*
31417c478bd9Sstevel@tonic-gate ** MILTER_CHANGEHEADER -- Change the supplied header in the message
31427c478bd9Sstevel@tonic-gate **
31437c478bd9Sstevel@tonic-gate ** Parameters:
3144058561cbSjbeck ** m -- current filter.
31457c478bd9Sstevel@tonic-gate ** response -- encoded form of header/index/value.
31467c478bd9Sstevel@tonic-gate ** rlen -- length of response.
31477c478bd9Sstevel@tonic-gate ** e -- current envelope.
31487c478bd9Sstevel@tonic-gate **
31497c478bd9Sstevel@tonic-gate ** Returns:
31507c478bd9Sstevel@tonic-gate ** none
31517c478bd9Sstevel@tonic-gate */
31527c478bd9Sstevel@tonic-gate
31537c478bd9Sstevel@tonic-gate static void
milter_changeheader(m,response,rlen,e)3154058561cbSjbeck milter_changeheader(m, response, rlen, e)
3155058561cbSjbeck struct milter *m;
31567c478bd9Sstevel@tonic-gate char *response;
31577c478bd9Sstevel@tonic-gate ssize_t rlen;
31587c478bd9Sstevel@tonic-gate ENVELOPE *e;
31597c478bd9Sstevel@tonic-gate {
31607c478bd9Sstevel@tonic-gate mi_int32 i, index;
3161058561cbSjbeck int mh_v_len;
3162058561cbSjbeck char *field, *val, *mh_value;
31637c478bd9Sstevel@tonic-gate HDR *h, *sysheader;
31647c478bd9Sstevel@tonic-gate
31657c478bd9Sstevel@tonic-gate if (tTd(64, 10))
31667c478bd9Sstevel@tonic-gate sm_dprintf("milter_changeheader: ");
31677c478bd9Sstevel@tonic-gate
31687c478bd9Sstevel@tonic-gate /* sanity checks */
31697c478bd9Sstevel@tonic-gate if (response == NULL)
31707c478bd9Sstevel@tonic-gate {
31717c478bd9Sstevel@tonic-gate if (tTd(64, 10))
31727c478bd9Sstevel@tonic-gate sm_dprintf("NULL response\n");
31737c478bd9Sstevel@tonic-gate return;
31747c478bd9Sstevel@tonic-gate }
31757c478bd9Sstevel@tonic-gate
31767c478bd9Sstevel@tonic-gate if (rlen < 2 || strlen(response) + 1 >= (size_t) rlen)
31777c478bd9Sstevel@tonic-gate {
31787c478bd9Sstevel@tonic-gate if (tTd(64, 10))
31797c478bd9Sstevel@tonic-gate sm_dprintf("didn't follow protocol (total len)\n");
31807c478bd9Sstevel@tonic-gate return;
31817c478bd9Sstevel@tonic-gate }
31827c478bd9Sstevel@tonic-gate
31837c478bd9Sstevel@tonic-gate /* Find separating NUL */
31847c478bd9Sstevel@tonic-gate (void) memcpy((char *) &i, response, MILTER_LEN_BYTES);
31857c478bd9Sstevel@tonic-gate index = ntohl(i);
31867c478bd9Sstevel@tonic-gate field = response + MILTER_LEN_BYTES;
31877c478bd9Sstevel@tonic-gate val = field + strlen(field) + 1;
31887c478bd9Sstevel@tonic-gate
31897c478bd9Sstevel@tonic-gate /* another sanity check */
31907c478bd9Sstevel@tonic-gate if (MILTER_LEN_BYTES + strlen(field) + 1 +
31917c478bd9Sstevel@tonic-gate strlen(val) + 1 != (size_t) rlen)
31927c478bd9Sstevel@tonic-gate {
31937c478bd9Sstevel@tonic-gate if (tTd(64, 10))
31947c478bd9Sstevel@tonic-gate sm_dprintf("didn't follow protocol (part len)\n");
31957c478bd9Sstevel@tonic-gate return;
31967c478bd9Sstevel@tonic-gate }
31977c478bd9Sstevel@tonic-gate
31987c478bd9Sstevel@tonic-gate if (*field == '\0')
31997c478bd9Sstevel@tonic-gate {
32007c478bd9Sstevel@tonic-gate if (tTd(64, 10))
32017c478bd9Sstevel@tonic-gate sm_dprintf("empty field name\n");
32027c478bd9Sstevel@tonic-gate return;
32037c478bd9Sstevel@tonic-gate }
32047c478bd9Sstevel@tonic-gate
3205058561cbSjbeck mh_v_len = 0;
3206058561cbSjbeck mh_value = quote_internal_chars(val, NULL, &mh_v_len);
3207058561cbSjbeck
32087c478bd9Sstevel@tonic-gate sysheader = NULL;
32097c478bd9Sstevel@tonic-gate for (h = e->e_header; h != NULL; h = h->h_link)
32107c478bd9Sstevel@tonic-gate {
32117c478bd9Sstevel@tonic-gate if (sm_strcasecmp(h->h_field, field) == 0)
32127c478bd9Sstevel@tonic-gate {
3213058561cbSjbeck if (bitset(H_USER, h->h_flags) && --index <= 0)
32147c478bd9Sstevel@tonic-gate {
32157c478bd9Sstevel@tonic-gate sysheader = NULL;
32167c478bd9Sstevel@tonic-gate break;
32177c478bd9Sstevel@tonic-gate }
32187c478bd9Sstevel@tonic-gate else if (!bitset(H_USER, h->h_flags) &&
32197c478bd9Sstevel@tonic-gate !bitset(H_TRACE, h->h_flags))
32207c478bd9Sstevel@tonic-gate {
32217c478bd9Sstevel@tonic-gate /*
32227c478bd9Sstevel@tonic-gate ** DRUMS msg-fmt draft says can only have
32237c478bd9Sstevel@tonic-gate ** multiple occurences of trace fields,
32247c478bd9Sstevel@tonic-gate ** so make sure we replace any non-trace,
32257c478bd9Sstevel@tonic-gate ** non-user field.
32267c478bd9Sstevel@tonic-gate */
32277c478bd9Sstevel@tonic-gate
32287c478bd9Sstevel@tonic-gate sysheader = h;
32297c478bd9Sstevel@tonic-gate }
32307c478bd9Sstevel@tonic-gate }
32317c478bd9Sstevel@tonic-gate }
32327c478bd9Sstevel@tonic-gate
32337c478bd9Sstevel@tonic-gate /* if not found as user-provided header at index, use sysheader */
32347c478bd9Sstevel@tonic-gate if (h == NULL)
32357c478bd9Sstevel@tonic-gate h = sysheader;
32367c478bd9Sstevel@tonic-gate
32377c478bd9Sstevel@tonic-gate if (h == NULL)
32387c478bd9Sstevel@tonic-gate {
32397c478bd9Sstevel@tonic-gate if (*val == '\0')
32407c478bd9Sstevel@tonic-gate {
32417c478bd9Sstevel@tonic-gate if (tTd(64, 10))
32427c478bd9Sstevel@tonic-gate sm_dprintf("Delete (noop) %s\n", field);
32437c478bd9Sstevel@tonic-gate if (MilterLogLevel > 8)
32447c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id,
32457c478bd9Sstevel@tonic-gate "Milter delete (noop): header: %s"
32467c478bd9Sstevel@tonic-gate , field);
32477c478bd9Sstevel@tonic-gate }
32487c478bd9Sstevel@tonic-gate else
32497c478bd9Sstevel@tonic-gate {
32507c478bd9Sstevel@tonic-gate /* treat modify value with no existing header as add */
32517c478bd9Sstevel@tonic-gate if (tTd(64, 10))
3252058561cbSjbeck sm_dprintf("Add %s: %s\n", field, mh_value);
32537c478bd9Sstevel@tonic-gate if (MilterLogLevel > 8)
32547c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id,
32557c478bd9Sstevel@tonic-gate "Milter change (add): header: %s: %s"
3256058561cbSjbeck , field, mh_value);
3257058561cbSjbeck addheader(newstr(field), mh_value, H_USER, e,
3258058561cbSjbeck !bitset(SMFIP_HDR_LEADSPC, m->mf_pflags));
32597c478bd9Sstevel@tonic-gate }
32607c478bd9Sstevel@tonic-gate return;
32617c478bd9Sstevel@tonic-gate }
32627c478bd9Sstevel@tonic-gate
32637c478bd9Sstevel@tonic-gate if (tTd(64, 10))
32647c478bd9Sstevel@tonic-gate {
32657c478bd9Sstevel@tonic-gate if (*val == '\0')
32667c478bd9Sstevel@tonic-gate {
3267058561cbSjbeck sm_dprintf("Delete%s %s:%s\n",
32687c478bd9Sstevel@tonic-gate h == sysheader ? " (default header)" : "",
32697c478bd9Sstevel@tonic-gate field,
32707c478bd9Sstevel@tonic-gate h->h_value == NULL ? "<NULL>" : h->h_value);
32717c478bd9Sstevel@tonic-gate }
32727c478bd9Sstevel@tonic-gate else
32737c478bd9Sstevel@tonic-gate {
32747c478bd9Sstevel@tonic-gate sm_dprintf("Change%s %s: from %s to %s\n",
32757c478bd9Sstevel@tonic-gate h == sysheader ? " (default header)" : "",
32767c478bd9Sstevel@tonic-gate field,
32777c478bd9Sstevel@tonic-gate h->h_value == NULL ? "<NULL>" : h->h_value,
3278058561cbSjbeck mh_value);
32797c478bd9Sstevel@tonic-gate }
32807c478bd9Sstevel@tonic-gate }
32817c478bd9Sstevel@tonic-gate
32827c478bd9Sstevel@tonic-gate if (MilterLogLevel > 8)
32837c478bd9Sstevel@tonic-gate {
32847c478bd9Sstevel@tonic-gate if (*val == '\0')
32857c478bd9Sstevel@tonic-gate {
32867c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id,
3287058561cbSjbeck "Milter delete: header%s %s:%s",
32887c478bd9Sstevel@tonic-gate h == sysheader ? " (default header)" : "",
32897c478bd9Sstevel@tonic-gate field,
32907c478bd9Sstevel@tonic-gate h->h_value == NULL ? "<NULL>" : h->h_value);
32917c478bd9Sstevel@tonic-gate }
32927c478bd9Sstevel@tonic-gate else
32937c478bd9Sstevel@tonic-gate {
32947c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id,
32957c478bd9Sstevel@tonic-gate "Milter change: header%s %s: from %s to %s",
32967c478bd9Sstevel@tonic-gate h == sysheader ? " (default header)" : "",
32977c478bd9Sstevel@tonic-gate field,
32987c478bd9Sstevel@tonic-gate h->h_value == NULL ? "<NULL>" : h->h_value,
3299058561cbSjbeck mh_value);
33007c478bd9Sstevel@tonic-gate }
33017c478bd9Sstevel@tonic-gate }
33027c478bd9Sstevel@tonic-gate
33037c478bd9Sstevel@tonic-gate if (h != sysheader && h->h_value != NULL)
33047c478bd9Sstevel@tonic-gate {
33057c478bd9Sstevel@tonic-gate size_t l;
33067c478bd9Sstevel@tonic-gate
33077c478bd9Sstevel@tonic-gate l = strlen(h->h_value);
33087c478bd9Sstevel@tonic-gate if (l > e->e_msgsize)
33097c478bd9Sstevel@tonic-gate e->e_msgsize = 0;
33107c478bd9Sstevel@tonic-gate else
33117c478bd9Sstevel@tonic-gate e->e_msgsize -= l;
33127c478bd9Sstevel@tonic-gate /* rpool, don't free: sm_free(h->h_value); XXX */
33137c478bd9Sstevel@tonic-gate }
33147c478bd9Sstevel@tonic-gate
33157c478bd9Sstevel@tonic-gate if (*val == '\0')
33167c478bd9Sstevel@tonic-gate {
33177c478bd9Sstevel@tonic-gate /* Remove "Field: " from message size */
33187c478bd9Sstevel@tonic-gate if (h != sysheader)
33197c478bd9Sstevel@tonic-gate {
33207c478bd9Sstevel@tonic-gate size_t l;
33217c478bd9Sstevel@tonic-gate
33227c478bd9Sstevel@tonic-gate l = strlen(h->h_field) + 2;
33237c478bd9Sstevel@tonic-gate if (l > e->e_msgsize)
33247c478bd9Sstevel@tonic-gate e->e_msgsize = 0;
33257c478bd9Sstevel@tonic-gate else
33267c478bd9Sstevel@tonic-gate e->e_msgsize -= l;
33277c478bd9Sstevel@tonic-gate }
33287c478bd9Sstevel@tonic-gate h->h_value = NULL;
3329058561cbSjbeck SM_FREE(mh_value);
33307c478bd9Sstevel@tonic-gate }
33317c478bd9Sstevel@tonic-gate else
33327c478bd9Sstevel@tonic-gate {
3333058561cbSjbeck if (bitset(SMFIP_HDR_LEADSPC, m->mf_pflags))
3334058561cbSjbeck h->h_value = mh_value;
3335058561cbSjbeck else
3336058561cbSjbeck {
3337*e9af4bc0SJohn Beck h->h_value = addleadingspace(mh_value, e->e_rpool);
3338058561cbSjbeck SM_FREE(mh_value);
3339058561cbSjbeck }
33407c478bd9Sstevel@tonic-gate h->h_flags |= H_USER;
33417c478bd9Sstevel@tonic-gate e->e_msgsize += strlen(h->h_value);
33427c478bd9Sstevel@tonic-gate }
33437c478bd9Sstevel@tonic-gate }
3344058561cbSjbeck
3345058561cbSjbeck /*
3346058561cbSjbeck ** MILTER_SPLIT_RESPONSE -- Split response into fields.
3347058561cbSjbeck **
3348058561cbSjbeck ** Parameters:
3349058561cbSjbeck ** response -- encoded repsonse.
3350058561cbSjbeck ** rlen -- length of response.
3351058561cbSjbeck ** pargc -- number of arguments (ouput)
3352058561cbSjbeck **
3353058561cbSjbeck ** Returns:
3354058561cbSjbeck ** array of pointers to the individual strings
3355058561cbSjbeck */
3356058561cbSjbeck
3357058561cbSjbeck static char **milter_split_response __P((char *, ssize_t, int *));
3358058561cbSjbeck
3359058561cbSjbeck static char **
milter_split_response(response,rlen,pargc)3360058561cbSjbeck milter_split_response(response, rlen, pargc)
3361058561cbSjbeck char *response;
3362058561cbSjbeck ssize_t rlen;
3363058561cbSjbeck int *pargc;
3364058561cbSjbeck {
3365058561cbSjbeck char **s;
3366058561cbSjbeck size_t i;
3367058561cbSjbeck int elem, nelem;
3368058561cbSjbeck
3369058561cbSjbeck SM_ASSERT(response != NULL);
3370058561cbSjbeck SM_ASSERT(pargc != NULL);
3371058561cbSjbeck *pargc = 0;
3372058561cbSjbeck if (rlen < 2 || strlen(response) >= (size_t) rlen)
3373058561cbSjbeck {
3374058561cbSjbeck if (tTd(64, 10))
3375058561cbSjbeck sm_dprintf("didn't follow protocol (total len %d != rlen %d)\n",
3376058561cbSjbeck (int) strlen(response), (int) (rlen - 1));
3377058561cbSjbeck return NULL;
3378058561cbSjbeck }
3379058561cbSjbeck
3380058561cbSjbeck nelem = 0;
3381058561cbSjbeck for (i = 0; i < rlen; i++)
3382058561cbSjbeck {
3383058561cbSjbeck if (response[i] == '\0')
3384058561cbSjbeck ++nelem;
3385058561cbSjbeck }
3386058561cbSjbeck if (nelem == 0)
3387058561cbSjbeck return NULL;
3388058561cbSjbeck
3389058561cbSjbeck /* last entry is only for the name */
3390*e9af4bc0SJohn Beck s = (char **)malloc((nelem + 1) * (sizeof(*s)));
3391058561cbSjbeck if (s == NULL)
3392058561cbSjbeck return NULL;
3393058561cbSjbeck s[0] = response;
3394058561cbSjbeck for (i = 0, elem = 0; i < rlen && elem < nelem; i++)
3395058561cbSjbeck {
3396058561cbSjbeck if (response[i] == '\0')
3397058561cbSjbeck {
3398058561cbSjbeck ++elem;
3399058561cbSjbeck if (i + 1 >= rlen)
3400058561cbSjbeck s[elem] = NULL;
3401058561cbSjbeck else
3402058561cbSjbeck s[elem] = &(response[i + 1]);
3403058561cbSjbeck }
3404058561cbSjbeck }
3405058561cbSjbeck *pargc = nelem;
3406058561cbSjbeck
3407058561cbSjbeck if (tTd(64, 10))
3408058561cbSjbeck {
3409058561cbSjbeck for (elem = 0; elem < nelem; elem++)
3410058561cbSjbeck sm_dprintf("argv[%d]=\"%s\"\n", elem, s[elem]);
3411058561cbSjbeck }
3412058561cbSjbeck
3413058561cbSjbeck /* overwrite last entry (already done above, just paranoia) */
3414058561cbSjbeck s[elem] = NULL;
3415058561cbSjbeck return s;
3416058561cbSjbeck }
3417058561cbSjbeck
3418058561cbSjbeck /*
3419058561cbSjbeck ** MILTER_CHGFROM -- Change the envelope sender address
3420058561cbSjbeck **
3421058561cbSjbeck ** Parameters:
3422058561cbSjbeck ** response -- encoded form of recipient address.
3423058561cbSjbeck ** rlen -- length of response.
3424058561cbSjbeck ** e -- current envelope.
3425058561cbSjbeck **
3426058561cbSjbeck ** Returns:
3427058561cbSjbeck ** none
3428058561cbSjbeck */
3429058561cbSjbeck
3430058561cbSjbeck static void
milter_chgfrom(response,rlen,e)3431058561cbSjbeck milter_chgfrom(response, rlen, e)
3432058561cbSjbeck char *response;
3433058561cbSjbeck ssize_t rlen;
3434058561cbSjbeck ENVELOPE *e;
3435058561cbSjbeck {
3436058561cbSjbeck int olderrors, argc;
3437058561cbSjbeck char **argv;
3438058561cbSjbeck
3439058561cbSjbeck if (tTd(64, 10))
3440058561cbSjbeck sm_dprintf("milter_chgfrom: ");
3441058561cbSjbeck
3442058561cbSjbeck /* sanity checks */
3443058561cbSjbeck if (response == NULL)
3444058561cbSjbeck {
3445058561cbSjbeck if (tTd(64, 10))
3446058561cbSjbeck sm_dprintf("NULL response\n");
3447058561cbSjbeck return;
3448058561cbSjbeck }
3449058561cbSjbeck
3450058561cbSjbeck if (*response == '\0' ||
3451058561cbSjbeck strlen(response) + 1 > (size_t) rlen)
3452058561cbSjbeck {
3453058561cbSjbeck if (tTd(64, 10))
3454058561cbSjbeck sm_dprintf("didn't follow protocol (total len %d != rlen %d)\n",
3455058561cbSjbeck (int) strlen(response), (int) (rlen - 1));
3456058561cbSjbeck return;
3457058561cbSjbeck }
3458058561cbSjbeck
3459058561cbSjbeck if (tTd(64, 10))
3460058561cbSjbeck sm_dprintf("%s\n", response);
3461058561cbSjbeck if (MilterLogLevel > 8)
3462058561cbSjbeck sm_syslog(LOG_INFO, e->e_id, "Milter chgfrom: %s", response);
3463058561cbSjbeck argv = milter_split_response(response, rlen, &argc);
3464058561cbSjbeck if (argc < 1 || argc > 2)
3465058561cbSjbeck {
3466058561cbSjbeck if (tTd(64, 10))
3467058561cbSjbeck sm_dprintf("didn't follow protocol argc=%d\n", argc);
3468058561cbSjbeck return;
3469058561cbSjbeck }
3470058561cbSjbeck
3471058561cbSjbeck olderrors = Errors;
3472058561cbSjbeck setsender(argv[0], e, NULL, '\0', false);
3473058561cbSjbeck if (argc == 2)
3474058561cbSjbeck {
3475058561cbSjbeck reset_mail_esmtp_args(e);
3476058561cbSjbeck
3477058561cbSjbeck /*
3478058561cbSjbeck ** need "features" here: how to get those? via e?
3479058561cbSjbeck ** "fake" it for now: allow everything.
3480058561cbSjbeck */
3481058561cbSjbeck
3482058561cbSjbeck parse_esmtp_args(e, NULL, argv[0], argv[1], "MAIL", NULL,
3483058561cbSjbeck mail_esmtp_args);
3484058561cbSjbeck }
3485058561cbSjbeck Errors = olderrors;
3486058561cbSjbeck return;
3487058561cbSjbeck }
3488058561cbSjbeck
3489058561cbSjbeck /*
3490058561cbSjbeck ** MILTER_ADDRCPT_PAR -- Add the supplied recipient to the message
3491058561cbSjbeck **
3492058561cbSjbeck ** Parameters:
3493058561cbSjbeck ** response -- encoded form of recipient address.
3494058561cbSjbeck ** rlen -- length of response.
3495058561cbSjbeck ** e -- current envelope.
3496058561cbSjbeck **
3497058561cbSjbeck ** Returns:
3498058561cbSjbeck ** none
3499058561cbSjbeck */
3500058561cbSjbeck
3501058561cbSjbeck static void
milter_addrcpt_par(response,rlen,e)3502058561cbSjbeck milter_addrcpt_par(response, rlen, e)
3503058561cbSjbeck char *response;
3504058561cbSjbeck ssize_t rlen;
3505058561cbSjbeck ENVELOPE *e;
3506058561cbSjbeck {
3507058561cbSjbeck int olderrors, argc;
3508058561cbSjbeck char *delimptr;
3509058561cbSjbeck char **argv;
3510058561cbSjbeck ADDRESS *a;
3511058561cbSjbeck
3512058561cbSjbeck if (tTd(64, 10))
3513058561cbSjbeck sm_dprintf("milter_addrcpt_par: ");
3514058561cbSjbeck
3515058561cbSjbeck /* sanity checks */
3516058561cbSjbeck if (response == NULL)
3517058561cbSjbeck {
3518058561cbSjbeck if (tTd(64, 10))
3519058561cbSjbeck sm_dprintf("NULL response\n");
3520058561cbSjbeck return;
3521058561cbSjbeck }
3522058561cbSjbeck
3523058561cbSjbeck if (tTd(64, 10))
3524058561cbSjbeck sm_dprintf("%s\n", response);
3525058561cbSjbeck if (MilterLogLevel > 8)
3526058561cbSjbeck sm_syslog(LOG_INFO, e->e_id, "Milter add: rcpt: %s", response);
3527058561cbSjbeck
3528058561cbSjbeck argv = milter_split_response(response, rlen, &argc);
3529058561cbSjbeck if (argc < 1 || argc > 2)
3530058561cbSjbeck {
3531058561cbSjbeck if (tTd(64, 10))
3532058561cbSjbeck sm_dprintf("didn't follow protocol argc=%d\n", argc);
3533058561cbSjbeck return;
3534058561cbSjbeck }
3535058561cbSjbeck olderrors = Errors;
3536058561cbSjbeck
3537058561cbSjbeck /* how to set ESMTP arguments? */
3538058561cbSjbeck a = parseaddr(argv[0], NULLADDR, RF_COPYALL, ' ', &delimptr, e, true);
3539058561cbSjbeck
3540058561cbSjbeck if (a != NULL && olderrors == Errors)
3541058561cbSjbeck {
3542058561cbSjbeck parse_esmtp_args(e, a, argv[0], argv[1], "RCPT", NULL,
3543058561cbSjbeck rcpt_esmtp_args);
3544058561cbSjbeck if (olderrors == Errors)
3545058561cbSjbeck a = recipient(a, &e->e_sendqueue, 0, e);
3546058561cbSjbeck else
3547058561cbSjbeck sm_dprintf("olderrors=%d, Errors=%d\n",
3548058561cbSjbeck olderrors, Errors);
3549058561cbSjbeck }
3550058561cbSjbeck else
3551058561cbSjbeck {
3552058561cbSjbeck sm_dprintf("a=%p, olderrors=%d, Errors=%d\n",
3553058561cbSjbeck a, olderrors, Errors);
3554058561cbSjbeck }
3555058561cbSjbeck
3556058561cbSjbeck Errors = olderrors;
3557058561cbSjbeck return;
3558058561cbSjbeck }
3559058561cbSjbeck
35607c478bd9Sstevel@tonic-gate /*
35617c478bd9Sstevel@tonic-gate ** MILTER_ADDRCPT -- Add the supplied recipient to the message
35627c478bd9Sstevel@tonic-gate **
35637c478bd9Sstevel@tonic-gate ** Parameters:
35647c478bd9Sstevel@tonic-gate ** response -- encoded form of recipient address.
35657c478bd9Sstevel@tonic-gate ** rlen -- length of response.
35667c478bd9Sstevel@tonic-gate ** e -- current envelope.
35677c478bd9Sstevel@tonic-gate **
35687c478bd9Sstevel@tonic-gate ** Returns:
35697c478bd9Sstevel@tonic-gate ** none
35707c478bd9Sstevel@tonic-gate */
35717c478bd9Sstevel@tonic-gate
35727c478bd9Sstevel@tonic-gate static void
milter_addrcpt(response,rlen,e)35737c478bd9Sstevel@tonic-gate milter_addrcpt(response, rlen, e)
35747c478bd9Sstevel@tonic-gate char *response;
35757c478bd9Sstevel@tonic-gate ssize_t rlen;
35767c478bd9Sstevel@tonic-gate ENVELOPE *e;
35777c478bd9Sstevel@tonic-gate {
35787c478bd9Sstevel@tonic-gate int olderrors;
35797c478bd9Sstevel@tonic-gate
35807c478bd9Sstevel@tonic-gate if (tTd(64, 10))
35817c478bd9Sstevel@tonic-gate sm_dprintf("milter_addrcpt: ");
35827c478bd9Sstevel@tonic-gate
35837c478bd9Sstevel@tonic-gate /* sanity checks */
35847c478bd9Sstevel@tonic-gate if (response == NULL)
35857c478bd9Sstevel@tonic-gate {
35867c478bd9Sstevel@tonic-gate if (tTd(64, 10))
35877c478bd9Sstevel@tonic-gate sm_dprintf("NULL response\n");
35887c478bd9Sstevel@tonic-gate return;
35897c478bd9Sstevel@tonic-gate }
35907c478bd9Sstevel@tonic-gate
35917c478bd9Sstevel@tonic-gate if (*response == '\0' ||
35927c478bd9Sstevel@tonic-gate strlen(response) + 1 != (size_t) rlen)
35937c478bd9Sstevel@tonic-gate {
35947c478bd9Sstevel@tonic-gate if (tTd(64, 10))
35957c478bd9Sstevel@tonic-gate sm_dprintf("didn't follow protocol (total len %d != rlen %d)\n",
35967c478bd9Sstevel@tonic-gate (int) strlen(response), (int) (rlen - 1));
35977c478bd9Sstevel@tonic-gate return;
35987c478bd9Sstevel@tonic-gate }
35997c478bd9Sstevel@tonic-gate
36007c478bd9Sstevel@tonic-gate if (tTd(64, 10))
36017c478bd9Sstevel@tonic-gate sm_dprintf("%s\n", response);
36027c478bd9Sstevel@tonic-gate if (MilterLogLevel > 8)
36037c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter add: rcpt: %s", response);
36047c478bd9Sstevel@tonic-gate olderrors = Errors;
36057c478bd9Sstevel@tonic-gate (void) sendtolist(response, NULLADDR, &e->e_sendqueue, 0, e);
36067c478bd9Sstevel@tonic-gate Errors = olderrors;
36077c478bd9Sstevel@tonic-gate return;
36087c478bd9Sstevel@tonic-gate }
3609058561cbSjbeck
36107c478bd9Sstevel@tonic-gate /*
36117c478bd9Sstevel@tonic-gate ** MILTER_DELRCPT -- Delete the supplied recipient from the message
36127c478bd9Sstevel@tonic-gate **
36137c478bd9Sstevel@tonic-gate ** Parameters:
36147c478bd9Sstevel@tonic-gate ** response -- encoded form of recipient address.
36157c478bd9Sstevel@tonic-gate ** rlen -- length of response.
36167c478bd9Sstevel@tonic-gate ** e -- current envelope.
36177c478bd9Sstevel@tonic-gate **
36187c478bd9Sstevel@tonic-gate ** Returns:
36197c478bd9Sstevel@tonic-gate ** none
36207c478bd9Sstevel@tonic-gate */
36217c478bd9Sstevel@tonic-gate
36227c478bd9Sstevel@tonic-gate static void
milter_delrcpt(response,rlen,e)36237c478bd9Sstevel@tonic-gate milter_delrcpt(response, rlen, e)
36247c478bd9Sstevel@tonic-gate char *response;
36257c478bd9Sstevel@tonic-gate ssize_t rlen;
36267c478bd9Sstevel@tonic-gate ENVELOPE *e;
36277c478bd9Sstevel@tonic-gate {
36287c478bd9Sstevel@tonic-gate if (tTd(64, 10))
36297c478bd9Sstevel@tonic-gate sm_dprintf("milter_delrcpt: ");
36307c478bd9Sstevel@tonic-gate
36317c478bd9Sstevel@tonic-gate /* sanity checks */
36327c478bd9Sstevel@tonic-gate if (response == NULL)
36337c478bd9Sstevel@tonic-gate {
36347c478bd9Sstevel@tonic-gate if (tTd(64, 10))
36357c478bd9Sstevel@tonic-gate sm_dprintf("NULL response\n");
36367c478bd9Sstevel@tonic-gate return;
36377c478bd9Sstevel@tonic-gate }
36387c478bd9Sstevel@tonic-gate
36397c478bd9Sstevel@tonic-gate if (*response == '\0' ||
36407c478bd9Sstevel@tonic-gate strlen(response) + 1 != (size_t) rlen)
36417c478bd9Sstevel@tonic-gate {
36427c478bd9Sstevel@tonic-gate if (tTd(64, 10))
3643058561cbSjbeck sm_dprintf("didn't follow protocol (total len %d != rlen %d)\n",
3644058561cbSjbeck (int) strlen(response), (int) (rlen - 1));
36457c478bd9Sstevel@tonic-gate return;
36467c478bd9Sstevel@tonic-gate }
36477c478bd9Sstevel@tonic-gate
36487c478bd9Sstevel@tonic-gate if (tTd(64, 10))
36497c478bd9Sstevel@tonic-gate sm_dprintf("%s\n", response);
36507c478bd9Sstevel@tonic-gate if (MilterLogLevel > 8)
36517c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter delete: rcpt %s",
36527c478bd9Sstevel@tonic-gate response);
36537c478bd9Sstevel@tonic-gate (void) removefromlist(response, &e->e_sendqueue, e);
36547c478bd9Sstevel@tonic-gate return;
36557c478bd9Sstevel@tonic-gate }
3656058561cbSjbeck
36577c478bd9Sstevel@tonic-gate /*
36587c478bd9Sstevel@tonic-gate ** MILTER_REPLBODY -- Replace the current data file with new body
36597c478bd9Sstevel@tonic-gate **
36607c478bd9Sstevel@tonic-gate ** Parameters:
36617c478bd9Sstevel@tonic-gate ** response -- encoded form of new body.
36627c478bd9Sstevel@tonic-gate ** rlen -- length of response.
36637c478bd9Sstevel@tonic-gate ** newfilter -- if first time called by a new filter
36647c478bd9Sstevel@tonic-gate ** e -- current envelope.
36657c478bd9Sstevel@tonic-gate **
36667c478bd9Sstevel@tonic-gate ** Returns:
36677c478bd9Sstevel@tonic-gate ** 0 upon success, -1 upon failure
36687c478bd9Sstevel@tonic-gate */
36697c478bd9Sstevel@tonic-gate
36707c478bd9Sstevel@tonic-gate static int
milter_replbody(response,rlen,newfilter,e)36717c478bd9Sstevel@tonic-gate milter_replbody(response, rlen, newfilter, e)
36727c478bd9Sstevel@tonic-gate char *response;
36737c478bd9Sstevel@tonic-gate ssize_t rlen;
36747c478bd9Sstevel@tonic-gate bool newfilter;
36757c478bd9Sstevel@tonic-gate ENVELOPE *e;
36767c478bd9Sstevel@tonic-gate {
36777c478bd9Sstevel@tonic-gate static char prevchar;
36787c478bd9Sstevel@tonic-gate int i;
36797c478bd9Sstevel@tonic-gate
36807c478bd9Sstevel@tonic-gate if (tTd(64, 10))
36817c478bd9Sstevel@tonic-gate sm_dprintf("milter_replbody\n");
36827c478bd9Sstevel@tonic-gate
36837c478bd9Sstevel@tonic-gate /* If a new filter, reset previous character and truncate data file */
36847c478bd9Sstevel@tonic-gate if (newfilter)
36857c478bd9Sstevel@tonic-gate {
36867c478bd9Sstevel@tonic-gate off_t prevsize;
36877c478bd9Sstevel@tonic-gate char dfname[MAXPATHLEN];
36887c478bd9Sstevel@tonic-gate
36897c478bd9Sstevel@tonic-gate (void) sm_strlcpy(dfname, queuename(e, DATAFL_LETTER),
3690058561cbSjbeck sizeof(dfname));
36917c478bd9Sstevel@tonic-gate
36927c478bd9Sstevel@tonic-gate /* Reset prevchar */
36937c478bd9Sstevel@tonic-gate prevchar = '\0';
36947c478bd9Sstevel@tonic-gate
36957c478bd9Sstevel@tonic-gate /* Get the current data file information */
36967c478bd9Sstevel@tonic-gate prevsize = sm_io_getinfo(e->e_dfp, SM_IO_WHAT_SIZE, NULL);
36977c478bd9Sstevel@tonic-gate if (prevsize < 0)
36987c478bd9Sstevel@tonic-gate prevsize = 0;
36997c478bd9Sstevel@tonic-gate
37007c478bd9Sstevel@tonic-gate /* truncate current data file */
37017c478bd9Sstevel@tonic-gate if (sm_io_getinfo(e->e_dfp, SM_IO_WHAT_ISTYPE, BF_FILE_TYPE))
37027c478bd9Sstevel@tonic-gate {
37037c478bd9Sstevel@tonic-gate if (sm_io_setinfo(e->e_dfp, SM_BF_TRUNCATE, NULL) < 0)
37047c478bd9Sstevel@tonic-gate {
37057c478bd9Sstevel@tonic-gate MILTER_DF_ERROR("milter_replbody: sm_io truncate %s: %s");
37067c478bd9Sstevel@tonic-gate return -1;
37077c478bd9Sstevel@tonic-gate }
37087c478bd9Sstevel@tonic-gate }
37097c478bd9Sstevel@tonic-gate else
37107c478bd9Sstevel@tonic-gate {
37117c478bd9Sstevel@tonic-gate int err;
37127c478bd9Sstevel@tonic-gate
37137c478bd9Sstevel@tonic-gate err = sm_io_error(e->e_dfp);
37147c478bd9Sstevel@tonic-gate (void) sm_io_flush(e->e_dfp, SM_TIME_DEFAULT);
37157c478bd9Sstevel@tonic-gate
37167c478bd9Sstevel@tonic-gate /*
37177c478bd9Sstevel@tonic-gate ** Clear error if tried to fflush()
37187c478bd9Sstevel@tonic-gate ** a read-only file pointer and
37197c478bd9Sstevel@tonic-gate ** there wasn't a previous error.
37207c478bd9Sstevel@tonic-gate */
37217c478bd9Sstevel@tonic-gate
37227c478bd9Sstevel@tonic-gate if (err == 0)
37237c478bd9Sstevel@tonic-gate sm_io_clearerr(e->e_dfp);
37247c478bd9Sstevel@tonic-gate
37257c478bd9Sstevel@tonic-gate /* errno is set implicitly by fseek() before return */
37267c478bd9Sstevel@tonic-gate err = sm_io_seek(e->e_dfp, SM_TIME_DEFAULT,
37277c478bd9Sstevel@tonic-gate 0, SEEK_SET);
37287c478bd9Sstevel@tonic-gate if (err < 0)
37297c478bd9Sstevel@tonic-gate {
37307c478bd9Sstevel@tonic-gate MILTER_DF_ERROR("milter_replbody: sm_io_seek %s: %s");
37317c478bd9Sstevel@tonic-gate return -1;
37327c478bd9Sstevel@tonic-gate }
37337c478bd9Sstevel@tonic-gate # if NOFTRUNCATE
37347c478bd9Sstevel@tonic-gate /* XXX: Not much we can do except rewind it */
37357c478bd9Sstevel@tonic-gate errno = EINVAL;
37367c478bd9Sstevel@tonic-gate MILTER_DF_ERROR("milter_replbody: ftruncate not available on this platform (%s:%s)");
37377c478bd9Sstevel@tonic-gate return -1;
37387c478bd9Sstevel@tonic-gate # else /* NOFTRUNCATE */
37397c478bd9Sstevel@tonic-gate err = ftruncate(sm_io_getinfo(e->e_dfp,
37407c478bd9Sstevel@tonic-gate SM_IO_WHAT_FD, NULL),
37417c478bd9Sstevel@tonic-gate 0);
37427c478bd9Sstevel@tonic-gate if (err < 0)
37437c478bd9Sstevel@tonic-gate {
37447c478bd9Sstevel@tonic-gate MILTER_DF_ERROR("milter_replbody: sm_io ftruncate %s: %s");
37457c478bd9Sstevel@tonic-gate return -1;
37467c478bd9Sstevel@tonic-gate }
37477c478bd9Sstevel@tonic-gate # endif /* NOFTRUNCATE */
37487c478bd9Sstevel@tonic-gate }
37497c478bd9Sstevel@tonic-gate
37507c478bd9Sstevel@tonic-gate if (prevsize > e->e_msgsize)
37517c478bd9Sstevel@tonic-gate e->e_msgsize = 0;
37527c478bd9Sstevel@tonic-gate else
37537c478bd9Sstevel@tonic-gate e->e_msgsize -= prevsize;
37547c478bd9Sstevel@tonic-gate }
37557c478bd9Sstevel@tonic-gate
37567c478bd9Sstevel@tonic-gate if (newfilter && MilterLogLevel > 8)
37577c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter message: body replaced");
37587c478bd9Sstevel@tonic-gate
37597c478bd9Sstevel@tonic-gate if (response == NULL)
37607c478bd9Sstevel@tonic-gate {
37617c478bd9Sstevel@tonic-gate /* Flush the buffered '\r' */
37627c478bd9Sstevel@tonic-gate if (prevchar == '\r')
37637c478bd9Sstevel@tonic-gate {
37647c478bd9Sstevel@tonic-gate (void) sm_io_putc(e->e_dfp, SM_TIME_DEFAULT, prevchar);
37657c478bd9Sstevel@tonic-gate e->e_msgsize++;
37667c478bd9Sstevel@tonic-gate }
37677c478bd9Sstevel@tonic-gate return 0;
37687c478bd9Sstevel@tonic-gate }
37697c478bd9Sstevel@tonic-gate
37707c478bd9Sstevel@tonic-gate for (i = 0; i < rlen; i++)
37717c478bd9Sstevel@tonic-gate {
37727c478bd9Sstevel@tonic-gate /* Buffered char from last chunk */
37737c478bd9Sstevel@tonic-gate if (i == 0 && prevchar == '\r')
37747c478bd9Sstevel@tonic-gate {
37757c478bd9Sstevel@tonic-gate /* Not CRLF, output prevchar */
37767c478bd9Sstevel@tonic-gate if (response[i] != '\n')
37777c478bd9Sstevel@tonic-gate {
37787c478bd9Sstevel@tonic-gate (void) sm_io_putc(e->e_dfp, SM_TIME_DEFAULT,
37797c478bd9Sstevel@tonic-gate prevchar);
37807c478bd9Sstevel@tonic-gate e->e_msgsize++;
37817c478bd9Sstevel@tonic-gate }
37827c478bd9Sstevel@tonic-gate prevchar = '\0';
37837c478bd9Sstevel@tonic-gate }
37847c478bd9Sstevel@tonic-gate
37857c478bd9Sstevel@tonic-gate /* Turn CRLF into LF */
37867c478bd9Sstevel@tonic-gate if (response[i] == '\r')
37877c478bd9Sstevel@tonic-gate {
37887c478bd9Sstevel@tonic-gate /* check if at end of chunk */
37897c478bd9Sstevel@tonic-gate if (i + 1 < rlen)
37907c478bd9Sstevel@tonic-gate {
37917c478bd9Sstevel@tonic-gate /* If LF, strip CR */
37927c478bd9Sstevel@tonic-gate if (response[i + 1] == '\n')
37937c478bd9Sstevel@tonic-gate i++;
37947c478bd9Sstevel@tonic-gate }
37957c478bd9Sstevel@tonic-gate else
37967c478bd9Sstevel@tonic-gate {
37977c478bd9Sstevel@tonic-gate /* check next chunk */
37987c478bd9Sstevel@tonic-gate prevchar = '\r';
37997c478bd9Sstevel@tonic-gate continue;
38007c478bd9Sstevel@tonic-gate }
38017c478bd9Sstevel@tonic-gate }
38027c478bd9Sstevel@tonic-gate (void) sm_io_putc(e->e_dfp, SM_TIME_DEFAULT, response[i]);
38037c478bd9Sstevel@tonic-gate e->e_msgsize++;
38047c478bd9Sstevel@tonic-gate }
38057c478bd9Sstevel@tonic-gate return 0;
38067c478bd9Sstevel@tonic-gate }
38077c478bd9Sstevel@tonic-gate
38087c478bd9Sstevel@tonic-gate /*
38097c478bd9Sstevel@tonic-gate ** MTA callouts
38107c478bd9Sstevel@tonic-gate */
38117c478bd9Sstevel@tonic-gate
38127c478bd9Sstevel@tonic-gate /*
38137c478bd9Sstevel@tonic-gate ** MILTER_INIT -- open and negotiate with all of the filters
38147c478bd9Sstevel@tonic-gate **
38157c478bd9Sstevel@tonic-gate ** Parameters:
38167c478bd9Sstevel@tonic-gate ** e -- current envelope.
38177c478bd9Sstevel@tonic-gate ** state -- return state from response.
38187800901eSjbeck ** milters -- milters structure.
38197c478bd9Sstevel@tonic-gate **
38207c478bd9Sstevel@tonic-gate ** Returns:
38217c478bd9Sstevel@tonic-gate ** true iff at least one filter is active
38227c478bd9Sstevel@tonic-gate */
38237c478bd9Sstevel@tonic-gate
38247c478bd9Sstevel@tonic-gate /* ARGSUSED */
38257c478bd9Sstevel@tonic-gate bool
milter_init(e,state,milters)38267800901eSjbeck milter_init(e, state, milters)
38277c478bd9Sstevel@tonic-gate ENVELOPE *e;
38287c478bd9Sstevel@tonic-gate char *state;
38297800901eSjbeck milters_T *milters;
38307c478bd9Sstevel@tonic-gate {
38317c478bd9Sstevel@tonic-gate int i;
38327c478bd9Sstevel@tonic-gate
38337c478bd9Sstevel@tonic-gate if (tTd(64, 10))
38347c478bd9Sstevel@tonic-gate sm_dprintf("milter_init\n");
38357c478bd9Sstevel@tonic-gate
38367800901eSjbeck memset(milters, '\0', sizeof(*milters));
38377c478bd9Sstevel@tonic-gate *state = SMFIR_CONTINUE;
38387c478bd9Sstevel@tonic-gate if (InputFilters[0] == NULL)
38397c478bd9Sstevel@tonic-gate {
38407c478bd9Sstevel@tonic-gate if (MilterLogLevel > 10)
38417c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id,
38427c478bd9Sstevel@tonic-gate "Milter: no active filter");
38437c478bd9Sstevel@tonic-gate return false;
38447c478bd9Sstevel@tonic-gate }
38457c478bd9Sstevel@tonic-gate
38467c478bd9Sstevel@tonic-gate for (i = 0; InputFilters[i] != NULL; i++)
38477c478bd9Sstevel@tonic-gate {
38487c478bd9Sstevel@tonic-gate struct milter *m = InputFilters[i];
38497c478bd9Sstevel@tonic-gate
38507c478bd9Sstevel@tonic-gate m->mf_sock = milter_open(m, false, e);
38517c478bd9Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR)
38527c478bd9Sstevel@tonic-gate {
38537c478bd9Sstevel@tonic-gate MILTER_CHECK_ERROR(true, continue);
38547c478bd9Sstevel@tonic-gate break;
38557c478bd9Sstevel@tonic-gate }
38567c478bd9Sstevel@tonic-gate
38577c478bd9Sstevel@tonic-gate if (m->mf_sock < 0 ||
38587800901eSjbeck milter_negotiate(m, e, milters) < 0 ||
38597c478bd9Sstevel@tonic-gate m->mf_state == SMFS_ERROR)
38607c478bd9Sstevel@tonic-gate {
38617c478bd9Sstevel@tonic-gate if (tTd(64, 5))
38627c478bd9Sstevel@tonic-gate sm_dprintf("milter_init(%s): failed to %s\n",
38637c478bd9Sstevel@tonic-gate m->mf_name,
38647c478bd9Sstevel@tonic-gate m->mf_sock < 0 ? "open" :
38657c478bd9Sstevel@tonic-gate "negotiate");
38667c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0)
38677c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
38687c478bd9Sstevel@tonic-gate "Milter (%s): init failed to %s",
38697c478bd9Sstevel@tonic-gate m->mf_name,
38707c478bd9Sstevel@tonic-gate m->mf_sock < 0 ? "open" :
38717c478bd9Sstevel@tonic-gate "negotiate");
38727c478bd9Sstevel@tonic-gate
3873*e9af4bc0SJohn Beck /* if negotiation failure, close socket */
38747c478bd9Sstevel@tonic-gate milter_error(m, e);
38757c478bd9Sstevel@tonic-gate MILTER_CHECK_ERROR(true, continue);
38767c478bd9Sstevel@tonic-gate continue;
38777c478bd9Sstevel@tonic-gate }
38787c478bd9Sstevel@tonic-gate if (MilterLogLevel > 9)
38797c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id,
38807c478bd9Sstevel@tonic-gate "Milter (%s): init success to %s",
38817c478bd9Sstevel@tonic-gate m->mf_name,
38827c478bd9Sstevel@tonic-gate m->mf_sock < 0 ? "open" : "negotiate");
38837c478bd9Sstevel@tonic-gate }
38847c478bd9Sstevel@tonic-gate
38857c478bd9Sstevel@tonic-gate /*
38867c478bd9Sstevel@tonic-gate ** If something temp/perm failed with one of the filters,
38877c478bd9Sstevel@tonic-gate ** we won't be using any of them, so clear any existing
38887c478bd9Sstevel@tonic-gate ** connections.
38897c478bd9Sstevel@tonic-gate */
38907c478bd9Sstevel@tonic-gate
38917c478bd9Sstevel@tonic-gate if (*state != SMFIR_CONTINUE)
38927c478bd9Sstevel@tonic-gate milter_quit(e);
38937c478bd9Sstevel@tonic-gate
38947c478bd9Sstevel@tonic-gate return true;
38957c478bd9Sstevel@tonic-gate }
3896058561cbSjbeck
38977c478bd9Sstevel@tonic-gate /*
38987c478bd9Sstevel@tonic-gate ** MILTER_CONNECT -- send connection info to milter filters
38997c478bd9Sstevel@tonic-gate **
39007c478bd9Sstevel@tonic-gate ** Parameters:
39017c478bd9Sstevel@tonic-gate ** hostname -- hostname of remote machine.
39027c478bd9Sstevel@tonic-gate ** addr -- address of remote machine.
39037c478bd9Sstevel@tonic-gate ** e -- current envelope.
39047c478bd9Sstevel@tonic-gate ** state -- return state from response.
39057c478bd9Sstevel@tonic-gate **
39067c478bd9Sstevel@tonic-gate ** Returns:
39077c478bd9Sstevel@tonic-gate ** response string (may be NULL)
39087c478bd9Sstevel@tonic-gate */
39097c478bd9Sstevel@tonic-gate
39107c478bd9Sstevel@tonic-gate char *
milter_connect(hostname,addr,e,state)39117c478bd9Sstevel@tonic-gate milter_connect(hostname, addr, e, state)
39127c478bd9Sstevel@tonic-gate char *hostname;
39137c478bd9Sstevel@tonic-gate SOCKADDR addr;
39147c478bd9Sstevel@tonic-gate ENVELOPE *e;
39157c478bd9Sstevel@tonic-gate char *state;
39167c478bd9Sstevel@tonic-gate {
39177c478bd9Sstevel@tonic-gate char family;
39187c478bd9Sstevel@tonic-gate unsigned short port;
39197c478bd9Sstevel@tonic-gate char *buf, *bp;
39207c478bd9Sstevel@tonic-gate char *response;
39217c478bd9Sstevel@tonic-gate char *sockinfo = NULL;
39227c478bd9Sstevel@tonic-gate ssize_t s;
39237c478bd9Sstevel@tonic-gate # if NETINET6
39247c478bd9Sstevel@tonic-gate char buf6[INET6_ADDRSTRLEN];
39257c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
39267c478bd9Sstevel@tonic-gate
39277c478bd9Sstevel@tonic-gate if (tTd(64, 10))
39287c478bd9Sstevel@tonic-gate sm_dprintf("milter_connect(%s)\n", hostname);
39297c478bd9Sstevel@tonic-gate if (MilterLogLevel > 9)
39307c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter: connect to filters");
39317c478bd9Sstevel@tonic-gate
39327c478bd9Sstevel@tonic-gate /* gather data */
39337c478bd9Sstevel@tonic-gate switch (addr.sa.sa_family)
39347c478bd9Sstevel@tonic-gate {
39357c478bd9Sstevel@tonic-gate # if NETUNIX
39367c478bd9Sstevel@tonic-gate case AF_UNIX:
39377c478bd9Sstevel@tonic-gate family = SMFIA_UNIX;
39387c478bd9Sstevel@tonic-gate port = htons(0);
39397c478bd9Sstevel@tonic-gate sockinfo = addr.sunix.sun_path;
39407c478bd9Sstevel@tonic-gate break;
39417c478bd9Sstevel@tonic-gate # endif /* NETUNIX */
39427c478bd9Sstevel@tonic-gate
39437c478bd9Sstevel@tonic-gate # if NETINET
39447c478bd9Sstevel@tonic-gate case AF_INET:
39457c478bd9Sstevel@tonic-gate family = SMFIA_INET;
39467c478bd9Sstevel@tonic-gate port = addr.sin.sin_port;
39477c478bd9Sstevel@tonic-gate sockinfo = (char *) inet_ntoa(addr.sin.sin_addr);
39487c478bd9Sstevel@tonic-gate break;
39497c478bd9Sstevel@tonic-gate # endif /* NETINET */
39507c478bd9Sstevel@tonic-gate
39517c478bd9Sstevel@tonic-gate # if NETINET6
39527c478bd9Sstevel@tonic-gate case AF_INET6:
39537c478bd9Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(&addr.sin6.sin6_addr))
39547c478bd9Sstevel@tonic-gate family = SMFIA_INET;
39557c478bd9Sstevel@tonic-gate else
39567c478bd9Sstevel@tonic-gate family = SMFIA_INET6;
39577c478bd9Sstevel@tonic-gate port = addr.sin6.sin6_port;
39587c478bd9Sstevel@tonic-gate sockinfo = anynet_ntop(&addr.sin6.sin6_addr, buf6,
3959058561cbSjbeck sizeof(buf6));
39607c478bd9Sstevel@tonic-gate if (sockinfo == NULL)
39617c478bd9Sstevel@tonic-gate sockinfo = "";
39627c478bd9Sstevel@tonic-gate break;
39637c478bd9Sstevel@tonic-gate # endif /* NETINET6 */
39647c478bd9Sstevel@tonic-gate
39657c478bd9Sstevel@tonic-gate default:
39667c478bd9Sstevel@tonic-gate family = SMFIA_UNKNOWN;
39677c478bd9Sstevel@tonic-gate break;
39687c478bd9Sstevel@tonic-gate }
39697c478bd9Sstevel@tonic-gate
39707c478bd9Sstevel@tonic-gate s = strlen(hostname) + 1 + sizeof(family);
39717c478bd9Sstevel@tonic-gate if (family != SMFIA_UNKNOWN)
39727c478bd9Sstevel@tonic-gate s += sizeof(port) + strlen(sockinfo) + 1;
39737c478bd9Sstevel@tonic-gate
39747c478bd9Sstevel@tonic-gate buf = (char *) xalloc(s);
39757c478bd9Sstevel@tonic-gate bp = buf;
39767c478bd9Sstevel@tonic-gate
39777c478bd9Sstevel@tonic-gate /* put together data */
39787c478bd9Sstevel@tonic-gate (void) memcpy(bp, hostname, strlen(hostname));
39797c478bd9Sstevel@tonic-gate bp += strlen(hostname);
39807c478bd9Sstevel@tonic-gate *bp++ = '\0';
3981058561cbSjbeck (void) memcpy(bp, &family, sizeof(family));
3982058561cbSjbeck bp += sizeof(family);
39837c478bd9Sstevel@tonic-gate if (family != SMFIA_UNKNOWN)
39847c478bd9Sstevel@tonic-gate {
3985058561cbSjbeck (void) memcpy(bp, &port, sizeof(port));
3986058561cbSjbeck bp += sizeof(port);
39877c478bd9Sstevel@tonic-gate
39887c478bd9Sstevel@tonic-gate /* include trailing '\0' */
39897c478bd9Sstevel@tonic-gate (void) memcpy(bp, sockinfo, strlen(sockinfo) + 1);
39907c478bd9Sstevel@tonic-gate }
39917c478bd9Sstevel@tonic-gate
3992058561cbSjbeck response = milter_command(SMFIC_CONNECT, buf, s, MilterConnectMacros,
3993058561cbSjbeck e, state, "connect", false);
39947c478bd9Sstevel@tonic-gate sm_free(buf); /* XXX */
39957c478bd9Sstevel@tonic-gate
39967c478bd9Sstevel@tonic-gate /*
39977c478bd9Sstevel@tonic-gate ** If this message connection is done for,
39987c478bd9Sstevel@tonic-gate ** close the filters.
39997c478bd9Sstevel@tonic-gate */
40007c478bd9Sstevel@tonic-gate
40017c478bd9Sstevel@tonic-gate if (*state != SMFIR_CONTINUE)
40027c478bd9Sstevel@tonic-gate {
40037c478bd9Sstevel@tonic-gate if (MilterLogLevel > 9)
40047c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter: connect, ending");
40057c478bd9Sstevel@tonic-gate milter_quit(e);
40067c478bd9Sstevel@tonic-gate }
40077c478bd9Sstevel@tonic-gate else
40087c478bd9Sstevel@tonic-gate milter_per_connection_check(e);
40097c478bd9Sstevel@tonic-gate
40107c478bd9Sstevel@tonic-gate /*
40117c478bd9Sstevel@tonic-gate ** SMFIR_REPLYCODE can't work with connect due to
40127c478bd9Sstevel@tonic-gate ** the requirements of SMTP. Therefore, ignore the
40137c478bd9Sstevel@tonic-gate ** reply code text but keep the state it would reflect.
40147c478bd9Sstevel@tonic-gate */
40157c478bd9Sstevel@tonic-gate
40167c478bd9Sstevel@tonic-gate if (*state == SMFIR_REPLYCODE)
40177c478bd9Sstevel@tonic-gate {
40187c478bd9Sstevel@tonic-gate if (response != NULL &&
40197c478bd9Sstevel@tonic-gate *response == '4')
40207c478bd9Sstevel@tonic-gate {
40217c478bd9Sstevel@tonic-gate if (strncmp(response, "421 ", 4) == 0)
40227c478bd9Sstevel@tonic-gate *state = SMFIR_SHUTDOWN;
40237c478bd9Sstevel@tonic-gate else
40247c478bd9Sstevel@tonic-gate *state = SMFIR_TEMPFAIL;
40257c478bd9Sstevel@tonic-gate }
40267c478bd9Sstevel@tonic-gate else
40277c478bd9Sstevel@tonic-gate *state = SMFIR_REJECT;
40287c478bd9Sstevel@tonic-gate if (response != NULL)
40297c478bd9Sstevel@tonic-gate {
40307c478bd9Sstevel@tonic-gate sm_free(response); /* XXX */
40317c478bd9Sstevel@tonic-gate response = NULL;
40327c478bd9Sstevel@tonic-gate }
40337c478bd9Sstevel@tonic-gate }
40347c478bd9Sstevel@tonic-gate return response;
40357c478bd9Sstevel@tonic-gate }
4036058561cbSjbeck
40377c478bd9Sstevel@tonic-gate /*
40387c478bd9Sstevel@tonic-gate ** MILTER_HELO -- send SMTP HELO/EHLO command info to milter filters
40397c478bd9Sstevel@tonic-gate **
40407c478bd9Sstevel@tonic-gate ** Parameters:
40417c478bd9Sstevel@tonic-gate ** helo -- argument to SMTP HELO/EHLO command.
40427c478bd9Sstevel@tonic-gate ** e -- current envelope.
40437c478bd9Sstevel@tonic-gate ** state -- return state from response.
40447c478bd9Sstevel@tonic-gate **
40457c478bd9Sstevel@tonic-gate ** Returns:
40467c478bd9Sstevel@tonic-gate ** response string (may be NULL)
40477c478bd9Sstevel@tonic-gate */
40487c478bd9Sstevel@tonic-gate
40497c478bd9Sstevel@tonic-gate char *
milter_helo(helo,e,state)40507c478bd9Sstevel@tonic-gate milter_helo(helo, e, state)
40517c478bd9Sstevel@tonic-gate char *helo;
40527c478bd9Sstevel@tonic-gate ENVELOPE *e;
40537c478bd9Sstevel@tonic-gate char *state;
40547c478bd9Sstevel@tonic-gate {
40557c478bd9Sstevel@tonic-gate int i;
40567c478bd9Sstevel@tonic-gate char *response;
40577c478bd9Sstevel@tonic-gate
40587c478bd9Sstevel@tonic-gate if (tTd(64, 10))
40597c478bd9Sstevel@tonic-gate sm_dprintf("milter_helo(%s)\n", helo);
40607c478bd9Sstevel@tonic-gate
40617c478bd9Sstevel@tonic-gate /* HELO/EHLO can come at any point */
40627c478bd9Sstevel@tonic-gate for (i = 0; InputFilters[i] != NULL; i++)
40637c478bd9Sstevel@tonic-gate {
40647c478bd9Sstevel@tonic-gate struct milter *m = InputFilters[i];
40657c478bd9Sstevel@tonic-gate
40667c478bd9Sstevel@tonic-gate switch (m->mf_state)
40677c478bd9Sstevel@tonic-gate {
40687c478bd9Sstevel@tonic-gate case SMFS_INMSG:
40697c478bd9Sstevel@tonic-gate /* abort in message filters */
40707c478bd9Sstevel@tonic-gate milter_abort_filter(m, e);
40717c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
40727c478bd9Sstevel@tonic-gate
40737c478bd9Sstevel@tonic-gate case SMFS_DONE:
40747c478bd9Sstevel@tonic-gate /* reset done filters */
40757c478bd9Sstevel@tonic-gate m->mf_state = SMFS_OPEN;
40767c478bd9Sstevel@tonic-gate break;
40777c478bd9Sstevel@tonic-gate }
40787c478bd9Sstevel@tonic-gate }
40797c478bd9Sstevel@tonic-gate
40807c478bd9Sstevel@tonic-gate response = milter_command(SMFIC_HELO, helo, strlen(helo) + 1,
4081058561cbSjbeck MilterHeloMacros, e, state, "helo", false);
40827c478bd9Sstevel@tonic-gate milter_per_connection_check(e);
40837c478bd9Sstevel@tonic-gate return response;
40847c478bd9Sstevel@tonic-gate }
4085058561cbSjbeck
40867c478bd9Sstevel@tonic-gate /*
40877c478bd9Sstevel@tonic-gate ** MILTER_ENVFROM -- send SMTP MAIL command info to milter filters
40887c478bd9Sstevel@tonic-gate **
40897c478bd9Sstevel@tonic-gate ** Parameters:
40907c478bd9Sstevel@tonic-gate ** args -- SMTP MAIL command args (args[0] == sender).
40917c478bd9Sstevel@tonic-gate ** e -- current envelope.
40927c478bd9Sstevel@tonic-gate ** state -- return state from response.
40937c478bd9Sstevel@tonic-gate **
40947c478bd9Sstevel@tonic-gate ** Returns:
40957c478bd9Sstevel@tonic-gate ** response string (may be NULL)
40967c478bd9Sstevel@tonic-gate */
40977c478bd9Sstevel@tonic-gate
40987c478bd9Sstevel@tonic-gate char *
milter_envfrom(args,e,state)40997c478bd9Sstevel@tonic-gate milter_envfrom(args, e, state)
41007c478bd9Sstevel@tonic-gate char **args;
41017c478bd9Sstevel@tonic-gate ENVELOPE *e;
41027c478bd9Sstevel@tonic-gate char *state;
41037c478bd9Sstevel@tonic-gate {
41047c478bd9Sstevel@tonic-gate int i;
41057c478bd9Sstevel@tonic-gate char *buf, *bp;
41067c478bd9Sstevel@tonic-gate char *response;
41077c478bd9Sstevel@tonic-gate ssize_t s;
41087c478bd9Sstevel@tonic-gate
41097c478bd9Sstevel@tonic-gate if (tTd(64, 10))
41107c478bd9Sstevel@tonic-gate {
41117c478bd9Sstevel@tonic-gate sm_dprintf("milter_envfrom:");
41127c478bd9Sstevel@tonic-gate for (i = 0; args[i] != NULL; i++)
41137c478bd9Sstevel@tonic-gate sm_dprintf(" %s", args[i]);
41147c478bd9Sstevel@tonic-gate sm_dprintf("\n");
41157c478bd9Sstevel@tonic-gate }
41167c478bd9Sstevel@tonic-gate
41177c478bd9Sstevel@tonic-gate /* sanity check */
41187c478bd9Sstevel@tonic-gate if (args[0] == NULL)
41197c478bd9Sstevel@tonic-gate {
41207c478bd9Sstevel@tonic-gate *state = SMFIR_REJECT;
41217c478bd9Sstevel@tonic-gate if (MilterLogLevel > 10)
41227c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id,
41237c478bd9Sstevel@tonic-gate "Milter: reject, no sender");
41247c478bd9Sstevel@tonic-gate return NULL;
41257c478bd9Sstevel@tonic-gate }
41267c478bd9Sstevel@tonic-gate
41277c478bd9Sstevel@tonic-gate /* new message, so ... */
41287c478bd9Sstevel@tonic-gate for (i = 0; InputFilters[i] != NULL; i++)
41297c478bd9Sstevel@tonic-gate {
41307c478bd9Sstevel@tonic-gate struct milter *m = InputFilters[i];
41317c478bd9Sstevel@tonic-gate
41327c478bd9Sstevel@tonic-gate switch (m->mf_state)
41337c478bd9Sstevel@tonic-gate {
41347c478bd9Sstevel@tonic-gate case SMFS_INMSG:
41357c478bd9Sstevel@tonic-gate /* abort in message filters */
41367c478bd9Sstevel@tonic-gate milter_abort_filter(m, e);
41377c478bd9Sstevel@tonic-gate /* FALLTHROUGH */
41387c478bd9Sstevel@tonic-gate
41397c478bd9Sstevel@tonic-gate case SMFS_DONE:
41407c478bd9Sstevel@tonic-gate /* reset done filters */
41417c478bd9Sstevel@tonic-gate m->mf_state = SMFS_OPEN;
41427c478bd9Sstevel@tonic-gate break;
41437c478bd9Sstevel@tonic-gate }
41447c478bd9Sstevel@tonic-gate }
41457c478bd9Sstevel@tonic-gate
41467c478bd9Sstevel@tonic-gate /* put together data */
41477c478bd9Sstevel@tonic-gate s = 0;
41487c478bd9Sstevel@tonic-gate for (i = 0; args[i] != NULL; i++)
41497c478bd9Sstevel@tonic-gate s += strlen(args[i]) + 1;
41507c478bd9Sstevel@tonic-gate
41517c478bd9Sstevel@tonic-gate if (s < 0)
41527c478bd9Sstevel@tonic-gate {
41537c478bd9Sstevel@tonic-gate *state = SMFIR_TEMPFAIL;
41547c478bd9Sstevel@tonic-gate return NULL;
41557c478bd9Sstevel@tonic-gate }
41567c478bd9Sstevel@tonic-gate
41577c478bd9Sstevel@tonic-gate buf = (char *) xalloc(s);
41587c478bd9Sstevel@tonic-gate bp = buf;
41597c478bd9Sstevel@tonic-gate for (i = 0; args[i] != NULL; i++)
41607c478bd9Sstevel@tonic-gate {
41617c478bd9Sstevel@tonic-gate (void) sm_strlcpy(bp, args[i], s - (bp - buf));
41627c478bd9Sstevel@tonic-gate bp += strlen(bp) + 1;
41637c478bd9Sstevel@tonic-gate }
41647c478bd9Sstevel@tonic-gate
41657c478bd9Sstevel@tonic-gate if (MilterLogLevel > 14)
4166058561cbSjbeck sm_syslog(LOG_INFO, e->e_id, "Milter: sender: %s", buf);
41677c478bd9Sstevel@tonic-gate
41687c478bd9Sstevel@tonic-gate /* send it over */
4169058561cbSjbeck response = milter_command(SMFIC_MAIL, buf, s, MilterEnvFromMacros,
4170058561cbSjbeck e, state, "mail", false);
41717c478bd9Sstevel@tonic-gate sm_free(buf); /* XXX */
41727c478bd9Sstevel@tonic-gate
41737c478bd9Sstevel@tonic-gate /*
41747c478bd9Sstevel@tonic-gate ** If filter rejects/discards a per message command,
41757c478bd9Sstevel@tonic-gate ** abort the other filters since we are done with the
41767c478bd9Sstevel@tonic-gate ** current message.
41777c478bd9Sstevel@tonic-gate */
41787c478bd9Sstevel@tonic-gate
41797c478bd9Sstevel@tonic-gate MILTER_CHECK_DONE_MSG();
41807c478bd9Sstevel@tonic-gate if (MilterLogLevel > 10 && *state == SMFIR_REJECT)
4181058561cbSjbeck sm_syslog(LOG_INFO, e->e_id, "Milter: reject, sender");
41827c478bd9Sstevel@tonic-gate return response;
41837c478bd9Sstevel@tonic-gate }
41847c478bd9Sstevel@tonic-gate
41857c478bd9Sstevel@tonic-gate /*
41867c478bd9Sstevel@tonic-gate ** MILTER_ENVRCPT -- send SMTP RCPT command info to milter filters
41877c478bd9Sstevel@tonic-gate **
41887c478bd9Sstevel@tonic-gate ** Parameters:
41897c478bd9Sstevel@tonic-gate ** args -- SMTP MAIL command args (args[0] == recipient).
41907c478bd9Sstevel@tonic-gate ** e -- current envelope.
41917c478bd9Sstevel@tonic-gate ** state -- return state from response.
4192058561cbSjbeck ** rcpt_error -- does RCPT have an error?
41937c478bd9Sstevel@tonic-gate **
41947c478bd9Sstevel@tonic-gate ** Returns:
41957c478bd9Sstevel@tonic-gate ** response string (may be NULL)
41967c478bd9Sstevel@tonic-gate */
41977c478bd9Sstevel@tonic-gate
41987c478bd9Sstevel@tonic-gate char *
milter_envrcpt(args,e,state,rcpt_error)4199058561cbSjbeck milter_envrcpt(args, e, state, rcpt_error)
42007c478bd9Sstevel@tonic-gate char **args;
42017c478bd9Sstevel@tonic-gate ENVELOPE *e;
42027c478bd9Sstevel@tonic-gate char *state;
4203058561cbSjbeck bool rcpt_error;
42047c478bd9Sstevel@tonic-gate {
42057c478bd9Sstevel@tonic-gate int i;
42067c478bd9Sstevel@tonic-gate char *buf, *bp;
42077c478bd9Sstevel@tonic-gate char *response;
42087c478bd9Sstevel@tonic-gate ssize_t s;
42097c478bd9Sstevel@tonic-gate
42107c478bd9Sstevel@tonic-gate if (tTd(64, 10))
42117c478bd9Sstevel@tonic-gate {
42127c478bd9Sstevel@tonic-gate sm_dprintf("milter_envrcpt:");
42137c478bd9Sstevel@tonic-gate for (i = 0; args[i] != NULL; i++)
42147c478bd9Sstevel@tonic-gate sm_dprintf(" %s", args[i]);
42157c478bd9Sstevel@tonic-gate sm_dprintf("\n");
42167c478bd9Sstevel@tonic-gate }
42177c478bd9Sstevel@tonic-gate
42187c478bd9Sstevel@tonic-gate /* sanity check */
42197c478bd9Sstevel@tonic-gate if (args[0] == NULL)
42207c478bd9Sstevel@tonic-gate {
42217c478bd9Sstevel@tonic-gate *state = SMFIR_REJECT;
42227c478bd9Sstevel@tonic-gate if (MilterLogLevel > 10)
42237c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter: reject, no rcpt");
42247c478bd9Sstevel@tonic-gate return NULL;
42257c478bd9Sstevel@tonic-gate }
42267c478bd9Sstevel@tonic-gate
42277c478bd9Sstevel@tonic-gate /* put together data */
42287c478bd9Sstevel@tonic-gate s = 0;
42297c478bd9Sstevel@tonic-gate for (i = 0; args[i] != NULL; i++)
42307c478bd9Sstevel@tonic-gate s += strlen(args[i]) + 1;
42317c478bd9Sstevel@tonic-gate
42327c478bd9Sstevel@tonic-gate if (s < 0)
42337c478bd9Sstevel@tonic-gate {
42347c478bd9Sstevel@tonic-gate *state = SMFIR_TEMPFAIL;
42357c478bd9Sstevel@tonic-gate return NULL;
42367c478bd9Sstevel@tonic-gate }
42377c478bd9Sstevel@tonic-gate
42387c478bd9Sstevel@tonic-gate buf = (char *) xalloc(s);
42397c478bd9Sstevel@tonic-gate bp = buf;
42407c478bd9Sstevel@tonic-gate for (i = 0; args[i] != NULL; i++)
42417c478bd9Sstevel@tonic-gate {
42427c478bd9Sstevel@tonic-gate (void) sm_strlcpy(bp, args[i], s - (bp - buf));
42437c478bd9Sstevel@tonic-gate bp += strlen(bp) + 1;
42447c478bd9Sstevel@tonic-gate }
42457c478bd9Sstevel@tonic-gate
42467c478bd9Sstevel@tonic-gate if (MilterLogLevel > 14)
42477c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter: rcpts: %s", buf);
42487c478bd9Sstevel@tonic-gate
42497c478bd9Sstevel@tonic-gate /* send it over */
4250058561cbSjbeck response = milter_command(SMFIC_RCPT, buf, s, MilterEnvRcptMacros,
4251058561cbSjbeck e, state, "rcpt", rcpt_error);
42527c478bd9Sstevel@tonic-gate sm_free(buf); /* XXX */
42537c478bd9Sstevel@tonic-gate return response;
42547c478bd9Sstevel@tonic-gate }
42557c478bd9Sstevel@tonic-gate
42567c478bd9Sstevel@tonic-gate /*
42577c478bd9Sstevel@tonic-gate ** MILTER_DATA_CMD -- send SMTP DATA command info to milter filters
42587c478bd9Sstevel@tonic-gate **
42597c478bd9Sstevel@tonic-gate ** Parameters:
42607c478bd9Sstevel@tonic-gate ** e -- current envelope.
42617c478bd9Sstevel@tonic-gate ** state -- return state from response.
42627c478bd9Sstevel@tonic-gate **
42637c478bd9Sstevel@tonic-gate ** Returns:
42647c478bd9Sstevel@tonic-gate ** response string (may be NULL)
42657c478bd9Sstevel@tonic-gate */
42667c478bd9Sstevel@tonic-gate
42677c478bd9Sstevel@tonic-gate char *
milter_data_cmd(e,state)42687c478bd9Sstevel@tonic-gate milter_data_cmd(e, state)
42697c478bd9Sstevel@tonic-gate ENVELOPE *e;
42707c478bd9Sstevel@tonic-gate char *state;
42717c478bd9Sstevel@tonic-gate {
42727c478bd9Sstevel@tonic-gate if (tTd(64, 10))
42737c478bd9Sstevel@tonic-gate sm_dprintf("milter_data_cmd\n");
42747c478bd9Sstevel@tonic-gate
42757c478bd9Sstevel@tonic-gate /* send it over */
4276058561cbSjbeck return milter_command(SMFIC_DATA, NULL, 0, MilterDataMacros, e, state,
4277058561cbSjbeck "data", false);
42787c478bd9Sstevel@tonic-gate }
42797c478bd9Sstevel@tonic-gate
42807c478bd9Sstevel@tonic-gate /*
42817c478bd9Sstevel@tonic-gate ** MILTER_DATA -- send message headers/body and gather final message results
42827c478bd9Sstevel@tonic-gate **
42837c478bd9Sstevel@tonic-gate ** Parameters:
42847c478bd9Sstevel@tonic-gate ** e -- current envelope.
42857c478bd9Sstevel@tonic-gate ** state -- return state from response.
42867c478bd9Sstevel@tonic-gate **
42877c478bd9Sstevel@tonic-gate ** Returns:
42887c478bd9Sstevel@tonic-gate ** response string (may be NULL)
42897c478bd9Sstevel@tonic-gate **
42907c478bd9Sstevel@tonic-gate ** Side effects:
42917c478bd9Sstevel@tonic-gate ** - Uses e->e_dfp for access to the body
42927c478bd9Sstevel@tonic-gate ** - Can call the various milter action routines to
42937c478bd9Sstevel@tonic-gate ** modify the envelope or message.
42947c478bd9Sstevel@tonic-gate */
42957c478bd9Sstevel@tonic-gate
42967c478bd9Sstevel@tonic-gate # define MILTER_CHECK_RESULTS() \
42977c478bd9Sstevel@tonic-gate if (*state == SMFIR_ACCEPT || \
42987c478bd9Sstevel@tonic-gate m->mf_state == SMFS_DONE || \
42997c478bd9Sstevel@tonic-gate m->mf_state == SMFS_ERROR) \
43007c478bd9Sstevel@tonic-gate { \
43017c478bd9Sstevel@tonic-gate if (m->mf_state != SMFS_ERROR) \
43027c478bd9Sstevel@tonic-gate m->mf_state = SMFS_DONE; \
43037c478bd9Sstevel@tonic-gate continue; /* to next filter */ \
43047c478bd9Sstevel@tonic-gate } \
43057c478bd9Sstevel@tonic-gate if (*state != SMFIR_CONTINUE) \
43067c478bd9Sstevel@tonic-gate { \
43077c478bd9Sstevel@tonic-gate m->mf_state = SMFS_DONE; \
43087c478bd9Sstevel@tonic-gate goto finishup; \
43097c478bd9Sstevel@tonic-gate }
43107c478bd9Sstevel@tonic-gate
43117c478bd9Sstevel@tonic-gate char *
milter_data(e,state)43127c478bd9Sstevel@tonic-gate milter_data(e, state)
43137c478bd9Sstevel@tonic-gate ENVELOPE *e;
43147c478bd9Sstevel@tonic-gate char *state;
43157c478bd9Sstevel@tonic-gate {
43167c478bd9Sstevel@tonic-gate bool replbody = false; /* milter_replbody() called? */
43177c478bd9Sstevel@tonic-gate bool replfailed = false; /* milter_replbody() failed? */
43187c478bd9Sstevel@tonic-gate bool rewind = false; /* rewind data file? */
43197c478bd9Sstevel@tonic-gate bool dfopen = false; /* data file open for writing? */
43207c478bd9Sstevel@tonic-gate bool newfilter; /* reset on each new filter */
43217c478bd9Sstevel@tonic-gate char rcmd;
43227c478bd9Sstevel@tonic-gate int i;
43237c478bd9Sstevel@tonic-gate int save_errno;
43247c478bd9Sstevel@tonic-gate char *response = NULL;
43257c478bd9Sstevel@tonic-gate time_t eomsent;
43267c478bd9Sstevel@tonic-gate ssize_t rlen;
43277c478bd9Sstevel@tonic-gate
43287c478bd9Sstevel@tonic-gate if (tTd(64, 10))
43297c478bd9Sstevel@tonic-gate sm_dprintf("milter_data\n");
43307c478bd9Sstevel@tonic-gate
43317c478bd9Sstevel@tonic-gate *state = SMFIR_CONTINUE;
43327c478bd9Sstevel@tonic-gate
43337c478bd9Sstevel@tonic-gate /*
43347c478bd9Sstevel@tonic-gate ** XXX: Should actually send body chunks to each filter
43357c478bd9Sstevel@tonic-gate ** a chunk at a time instead of sending the whole body to
43367c478bd9Sstevel@tonic-gate ** each filter in turn. However, only if the filters don't
43377c478bd9Sstevel@tonic-gate ** change the body.
43387c478bd9Sstevel@tonic-gate */
43397c478bd9Sstevel@tonic-gate
43407c478bd9Sstevel@tonic-gate for (i = 0; InputFilters[i] != NULL; i++)
43417c478bd9Sstevel@tonic-gate {
43427c478bd9Sstevel@tonic-gate struct milter *m = InputFilters[i];
43437c478bd9Sstevel@tonic-gate
43447c478bd9Sstevel@tonic-gate if (*state != SMFIR_CONTINUE &&
43457c478bd9Sstevel@tonic-gate *state != SMFIR_ACCEPT)
43467c478bd9Sstevel@tonic-gate {
43477c478bd9Sstevel@tonic-gate /*
43487c478bd9Sstevel@tonic-gate ** A previous filter has dealt with the message,
43497c478bd9Sstevel@tonic-gate ** safe to stop processing the filters.
43507c478bd9Sstevel@tonic-gate */
43517c478bd9Sstevel@tonic-gate
43527c478bd9Sstevel@tonic-gate break;
43537c478bd9Sstevel@tonic-gate }
43547c478bd9Sstevel@tonic-gate
43557c478bd9Sstevel@tonic-gate /* Now reset state for later evaluation */
43567c478bd9Sstevel@tonic-gate *state = SMFIR_CONTINUE;
43577c478bd9Sstevel@tonic-gate newfilter = true;
43587c478bd9Sstevel@tonic-gate
43597c478bd9Sstevel@tonic-gate /* previous problem? */
43607c478bd9Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR)
43617c478bd9Sstevel@tonic-gate {
43627c478bd9Sstevel@tonic-gate MILTER_CHECK_ERROR(false, continue);
43637c478bd9Sstevel@tonic-gate break;
43647c478bd9Sstevel@tonic-gate }
43657c478bd9Sstevel@tonic-gate
43667c478bd9Sstevel@tonic-gate /* sanity checks */
43677c478bd9Sstevel@tonic-gate if (m->mf_sock < 0 ||
43687c478bd9Sstevel@tonic-gate (m->mf_state != SMFS_OPEN && m->mf_state != SMFS_INMSG))
43697c478bd9Sstevel@tonic-gate continue;
43707c478bd9Sstevel@tonic-gate
43717c478bd9Sstevel@tonic-gate m->mf_state = SMFS_INMSG;
43727c478bd9Sstevel@tonic-gate
43737c478bd9Sstevel@tonic-gate /* check if filter wants the headers */
43747c478bd9Sstevel@tonic-gate if (!bitset(SMFIP_NOHDRS, m->mf_pflags))
43757c478bd9Sstevel@tonic-gate {
43767c478bd9Sstevel@tonic-gate response = milter_headers(m, e, state);
43777c478bd9Sstevel@tonic-gate MILTER_CHECK_RESULTS();
43787c478bd9Sstevel@tonic-gate }
43797c478bd9Sstevel@tonic-gate
43807c478bd9Sstevel@tonic-gate /* check if filter wants EOH */
43817c478bd9Sstevel@tonic-gate if (!bitset(SMFIP_NOEOH, m->mf_pflags))
43827c478bd9Sstevel@tonic-gate {
43837c478bd9Sstevel@tonic-gate if (tTd(64, 10))
43847c478bd9Sstevel@tonic-gate sm_dprintf("milter_data: eoh\n");
43857c478bd9Sstevel@tonic-gate
4386058561cbSjbeck if (MilterEOHMacros[0] != NULL)
4387058561cbSjbeck {
4388058561cbSjbeck milter_send_macros(m, MilterEOHMacros,
4389058561cbSjbeck SMFIC_EOH, e);
4390058561cbSjbeck MILTER_CHECK_RESULTS();
4391058561cbSjbeck }
4392058561cbSjbeck
43937c478bd9Sstevel@tonic-gate /* send it over */
43947c478bd9Sstevel@tonic-gate response = milter_send_command(m, SMFIC_EOH, NULL, 0,
4395058561cbSjbeck e, state, "eoh");
43967c478bd9Sstevel@tonic-gate MILTER_CHECK_RESULTS();
43977c478bd9Sstevel@tonic-gate }
43987c478bd9Sstevel@tonic-gate
43997c478bd9Sstevel@tonic-gate /* check if filter wants the body */
44007c478bd9Sstevel@tonic-gate if (!bitset(SMFIP_NOBODY, m->mf_pflags) &&
44017c478bd9Sstevel@tonic-gate e->e_dfp != NULL)
44027c478bd9Sstevel@tonic-gate {
44037c478bd9Sstevel@tonic-gate rewind = true;
44047c478bd9Sstevel@tonic-gate response = milter_body(m, e, state);
44057c478bd9Sstevel@tonic-gate MILTER_CHECK_RESULTS();
44067c478bd9Sstevel@tonic-gate }
44077c478bd9Sstevel@tonic-gate
44087c478bd9Sstevel@tonic-gate if (MilterEOMMacros[0] != NULL)
44097c478bd9Sstevel@tonic-gate {
44107c478bd9Sstevel@tonic-gate milter_send_macros(m, MilterEOMMacros,
44117c478bd9Sstevel@tonic-gate SMFIC_BODYEOB, e);
44127c478bd9Sstevel@tonic-gate MILTER_CHECK_RESULTS();
44137c478bd9Sstevel@tonic-gate }
44147c478bd9Sstevel@tonic-gate
44157c478bd9Sstevel@tonic-gate /* send the final body chunk */
44167c478bd9Sstevel@tonic-gate (void) milter_write(m, SMFIC_BODYEOB, NULL, 0,
4417058561cbSjbeck m->mf_timeout[SMFTO_WRITE], e, "eom");
44187c478bd9Sstevel@tonic-gate
44197c478bd9Sstevel@tonic-gate /* Get time EOM sent for timeout */
44207c478bd9Sstevel@tonic-gate eomsent = curtime();
44217c478bd9Sstevel@tonic-gate
44227c478bd9Sstevel@tonic-gate /* deal with the possibility of multiple responses */
44237c478bd9Sstevel@tonic-gate while (*state == SMFIR_CONTINUE)
44247c478bd9Sstevel@tonic-gate {
44257c478bd9Sstevel@tonic-gate /* Check total timeout from EOM to final ACK/NAK */
44267c478bd9Sstevel@tonic-gate if (m->mf_timeout[SMFTO_EOM] > 0 &&
44277c478bd9Sstevel@tonic-gate curtime() - eomsent >= m->mf_timeout[SMFTO_EOM])
44287c478bd9Sstevel@tonic-gate {
44297c478bd9Sstevel@tonic-gate if (tTd(64, 5))
44307c478bd9Sstevel@tonic-gate sm_dprintf("milter_data(%s): EOM ACK/NAK timeout\n",
44317c478bd9Sstevel@tonic-gate m->mf_name);
44327c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0)
44337c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
44347c478bd9Sstevel@tonic-gate "milter_data(%s): EOM ACK/NAK timeout",
44357c478bd9Sstevel@tonic-gate m->mf_name);
44367c478bd9Sstevel@tonic-gate milter_error(m, e);
44377c478bd9Sstevel@tonic-gate MILTER_CHECK_ERROR(false, break);
44387c478bd9Sstevel@tonic-gate break;
44397c478bd9Sstevel@tonic-gate }
44407c478bd9Sstevel@tonic-gate
44417c478bd9Sstevel@tonic-gate response = milter_read(m, &rcmd, &rlen,
4442058561cbSjbeck m->mf_timeout[SMFTO_READ], e,
4443*e9af4bc0SJohn Beck "eom");
44447c478bd9Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR)
44457c478bd9Sstevel@tonic-gate break;
44467c478bd9Sstevel@tonic-gate
44477c478bd9Sstevel@tonic-gate if (tTd(64, 10))
44487c478bd9Sstevel@tonic-gate sm_dprintf("milter_data(%s): state %c\n",
44497c478bd9Sstevel@tonic-gate m->mf_name, (char) rcmd);
44507c478bd9Sstevel@tonic-gate
44517c478bd9Sstevel@tonic-gate switch (rcmd)
44527c478bd9Sstevel@tonic-gate {
44537c478bd9Sstevel@tonic-gate case SMFIR_REPLYCODE:
44547c478bd9Sstevel@tonic-gate MILTER_CHECK_REPLYCODE("554 5.7.1 Command rejected");
44557c478bd9Sstevel@tonic-gate if (MilterLogLevel > 12)
44567c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "milter=%s, reject=%s",
44577c478bd9Sstevel@tonic-gate m->mf_name, response);
44587c478bd9Sstevel@tonic-gate *state = rcmd;
44597c478bd9Sstevel@tonic-gate m->mf_state = SMFS_DONE;
44607c478bd9Sstevel@tonic-gate break;
44617c478bd9Sstevel@tonic-gate
44627c478bd9Sstevel@tonic-gate case SMFIR_REJECT: /* log msg at end of function */
44637c478bd9Sstevel@tonic-gate if (MilterLogLevel > 12)
44647c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "milter=%s, reject",
44657c478bd9Sstevel@tonic-gate m->mf_name);
44667c478bd9Sstevel@tonic-gate *state = rcmd;
44677c478bd9Sstevel@tonic-gate m->mf_state = SMFS_DONE;
44687c478bd9Sstevel@tonic-gate break;
44697c478bd9Sstevel@tonic-gate
44707c478bd9Sstevel@tonic-gate case SMFIR_DISCARD:
44717c478bd9Sstevel@tonic-gate if (MilterLogLevel > 12)
44727c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "milter=%s, discard",
44737c478bd9Sstevel@tonic-gate m->mf_name);
44747c478bd9Sstevel@tonic-gate *state = rcmd;
44757c478bd9Sstevel@tonic-gate m->mf_state = SMFS_DONE;
44767c478bd9Sstevel@tonic-gate break;
44777c478bd9Sstevel@tonic-gate
44787c478bd9Sstevel@tonic-gate case SMFIR_TEMPFAIL:
44797c478bd9Sstevel@tonic-gate if (MilterLogLevel > 12)
44807c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "milter=%s, tempfail",
44817c478bd9Sstevel@tonic-gate m->mf_name);
44827c478bd9Sstevel@tonic-gate *state = rcmd;
44837c478bd9Sstevel@tonic-gate m->mf_state = SMFS_DONE;
44847c478bd9Sstevel@tonic-gate break;
44857c478bd9Sstevel@tonic-gate
44867c478bd9Sstevel@tonic-gate case SMFIR_CONTINUE:
44877c478bd9Sstevel@tonic-gate case SMFIR_ACCEPT:
44887c478bd9Sstevel@tonic-gate /* this filter is done with message */
44897c478bd9Sstevel@tonic-gate if (replfailed)
44907c478bd9Sstevel@tonic-gate *state = SMFIR_TEMPFAIL;
44917c478bd9Sstevel@tonic-gate else
44927c478bd9Sstevel@tonic-gate *state = SMFIR_ACCEPT;
44937c478bd9Sstevel@tonic-gate m->mf_state = SMFS_DONE;
44947c478bd9Sstevel@tonic-gate break;
44957c478bd9Sstevel@tonic-gate
44967c478bd9Sstevel@tonic-gate case SMFIR_PROGRESS:
44977c478bd9Sstevel@tonic-gate break;
44987c478bd9Sstevel@tonic-gate
44997c478bd9Sstevel@tonic-gate case SMFIR_QUARANTINE:
45007c478bd9Sstevel@tonic-gate if (!bitset(SMFIF_QUARANTINE, m->mf_fflags))
45017c478bd9Sstevel@tonic-gate {
45027c478bd9Sstevel@tonic-gate if (MilterLogLevel > 9)
45037c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, e->e_id,
45047c478bd9Sstevel@tonic-gate "milter_data(%s): lied about quarantining, honoring request anyway",
45057c478bd9Sstevel@tonic-gate m->mf_name);
45067c478bd9Sstevel@tonic-gate }
45077c478bd9Sstevel@tonic-gate if (response == NULL)
45087c478bd9Sstevel@tonic-gate response = newstr("");
45097c478bd9Sstevel@tonic-gate if (MilterLogLevel > 3)
45107c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id,
45117c478bd9Sstevel@tonic-gate "milter=%s, quarantine=%s",
45127c478bd9Sstevel@tonic-gate m->mf_name, response);
45137c478bd9Sstevel@tonic-gate e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool,
45147c478bd9Sstevel@tonic-gate response);
45157c478bd9Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM,
45167c478bd9Sstevel@tonic-gate macid("{quarantine}"), e->e_quarmsg);
45177c478bd9Sstevel@tonic-gate break;
45187c478bd9Sstevel@tonic-gate
45197c478bd9Sstevel@tonic-gate case SMFIR_ADDHEADER:
45207c478bd9Sstevel@tonic-gate if (!bitset(SMFIF_ADDHDRS, m->mf_fflags))
45217c478bd9Sstevel@tonic-gate {
45227c478bd9Sstevel@tonic-gate if (MilterLogLevel > 9)
45237c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, e->e_id,
45247c478bd9Sstevel@tonic-gate "milter_data(%s): lied about adding headers, honoring request anyway",
45257c478bd9Sstevel@tonic-gate m->mf_name);
45267c478bd9Sstevel@tonic-gate }
4527058561cbSjbeck milter_addheader(m, response, rlen, e);
45287c478bd9Sstevel@tonic-gate break;
45297c478bd9Sstevel@tonic-gate
45307c478bd9Sstevel@tonic-gate case SMFIR_INSHEADER:
45317c478bd9Sstevel@tonic-gate if (!bitset(SMFIF_ADDHDRS, m->mf_fflags))
45327c478bd9Sstevel@tonic-gate {
45337c478bd9Sstevel@tonic-gate if (MilterLogLevel > 9)
45347c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, e->e_id,
45357c478bd9Sstevel@tonic-gate "milter_data(%s): lied about adding headers, honoring request anyway",
45367c478bd9Sstevel@tonic-gate m->mf_name);
45377c478bd9Sstevel@tonic-gate }
4538058561cbSjbeck milter_insheader(m, response, rlen, e);
45397c478bd9Sstevel@tonic-gate break;
45407c478bd9Sstevel@tonic-gate
45417c478bd9Sstevel@tonic-gate case SMFIR_CHGHEADER:
45427c478bd9Sstevel@tonic-gate if (!bitset(SMFIF_CHGHDRS, m->mf_fflags))
45437c478bd9Sstevel@tonic-gate {
45447c478bd9Sstevel@tonic-gate if (MilterLogLevel > 9)
45457c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, e->e_id,
45467c478bd9Sstevel@tonic-gate "milter_data(%s): lied about changing headers, honoring request anyway",
45477c478bd9Sstevel@tonic-gate m->mf_name);
45487c478bd9Sstevel@tonic-gate }
4549058561cbSjbeck milter_changeheader(m, response, rlen, e);
4550058561cbSjbeck break;
4551058561cbSjbeck
4552058561cbSjbeck case SMFIR_CHGFROM:
4553058561cbSjbeck if (!bitset(SMFIF_CHGFROM, m->mf_fflags))
4554058561cbSjbeck {
4555058561cbSjbeck if (MilterLogLevel > 9)
4556058561cbSjbeck sm_syslog(LOG_WARNING, e->e_id,
4557058561cbSjbeck "milter_data(%s) lied about changing sender, honoring request anyway",
4558058561cbSjbeck m->mf_name);
4559058561cbSjbeck }
4560058561cbSjbeck milter_chgfrom(response, rlen, e);
45617c478bd9Sstevel@tonic-gate break;
45627c478bd9Sstevel@tonic-gate
45637c478bd9Sstevel@tonic-gate case SMFIR_ADDRCPT:
45647c478bd9Sstevel@tonic-gate if (!bitset(SMFIF_ADDRCPT, m->mf_fflags))
45657c478bd9Sstevel@tonic-gate {
45667c478bd9Sstevel@tonic-gate if (MilterLogLevel > 9)
45677c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, e->e_id,
45687c478bd9Sstevel@tonic-gate "milter_data(%s) lied about adding recipients, honoring request anyway",
45697c478bd9Sstevel@tonic-gate m->mf_name);
45707c478bd9Sstevel@tonic-gate }
45717c478bd9Sstevel@tonic-gate milter_addrcpt(response, rlen, e);
45727c478bd9Sstevel@tonic-gate break;
45737c478bd9Sstevel@tonic-gate
4574058561cbSjbeck case SMFIR_ADDRCPT_PAR:
4575058561cbSjbeck if (!bitset(SMFIF_ADDRCPT_PAR, m->mf_fflags))
4576058561cbSjbeck {
4577058561cbSjbeck if (MilterLogLevel > 9)
4578058561cbSjbeck sm_syslog(LOG_WARNING, e->e_id,
4579058561cbSjbeck "milter_data(%s) lied about adding recipients with parameters, honoring request anyway",
4580058561cbSjbeck m->mf_name);
4581058561cbSjbeck }
4582058561cbSjbeck milter_addrcpt_par(response, rlen, e);
4583058561cbSjbeck break;
4584058561cbSjbeck
45857c478bd9Sstevel@tonic-gate case SMFIR_DELRCPT:
45867c478bd9Sstevel@tonic-gate if (!bitset(SMFIF_DELRCPT, m->mf_fflags))
45877c478bd9Sstevel@tonic-gate {
45887c478bd9Sstevel@tonic-gate if (MilterLogLevel > 9)
45897c478bd9Sstevel@tonic-gate sm_syslog(LOG_WARNING, e->e_id,
45907c478bd9Sstevel@tonic-gate "milter_data(%s): lied about removing recipients, honoring request anyway",
45917c478bd9Sstevel@tonic-gate m->mf_name);
45927c478bd9Sstevel@tonic-gate }
45937c478bd9Sstevel@tonic-gate milter_delrcpt(response, rlen, e);
45947c478bd9Sstevel@tonic-gate break;
45957c478bd9Sstevel@tonic-gate
45967c478bd9Sstevel@tonic-gate case SMFIR_REPLBODY:
45977c478bd9Sstevel@tonic-gate if (!bitset(SMFIF_MODBODY, m->mf_fflags))
45987c478bd9Sstevel@tonic-gate {
45997c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0)
46007c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
46017c478bd9Sstevel@tonic-gate "milter_data(%s): lied about replacing body, rejecting request and tempfailing message",
46027c478bd9Sstevel@tonic-gate m->mf_name);
46037c478bd9Sstevel@tonic-gate replfailed = true;
46047c478bd9Sstevel@tonic-gate break;
46057c478bd9Sstevel@tonic-gate }
46067c478bd9Sstevel@tonic-gate
46077c478bd9Sstevel@tonic-gate /* already failed in attempt */
46087c478bd9Sstevel@tonic-gate if (replfailed)
46097c478bd9Sstevel@tonic-gate break;
46107c478bd9Sstevel@tonic-gate
46117c478bd9Sstevel@tonic-gate if (!dfopen)
46127c478bd9Sstevel@tonic-gate {
46137c478bd9Sstevel@tonic-gate if (milter_reopen_df(e) < 0)
46147c478bd9Sstevel@tonic-gate {
46157c478bd9Sstevel@tonic-gate replfailed = true;
46167c478bd9Sstevel@tonic-gate break;
46177c478bd9Sstevel@tonic-gate }
46187c478bd9Sstevel@tonic-gate dfopen = true;
46197c478bd9Sstevel@tonic-gate rewind = true;
46207c478bd9Sstevel@tonic-gate }
46217c478bd9Sstevel@tonic-gate
46227c478bd9Sstevel@tonic-gate if (milter_replbody(response, rlen,
46237c478bd9Sstevel@tonic-gate newfilter, e) < 0)
46247c478bd9Sstevel@tonic-gate replfailed = true;
46257c478bd9Sstevel@tonic-gate newfilter = false;
46267c478bd9Sstevel@tonic-gate replbody = true;
46277c478bd9Sstevel@tonic-gate break;
46287c478bd9Sstevel@tonic-gate
46297c478bd9Sstevel@tonic-gate default:
46307c478bd9Sstevel@tonic-gate /* Invalid response to command */
46317c478bd9Sstevel@tonic-gate if (MilterLogLevel > 0)
46327c478bd9Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id,
46337c478bd9Sstevel@tonic-gate "milter_data(%s): returned bogus response %c",
46347c478bd9Sstevel@tonic-gate m->mf_name, rcmd);
46357c478bd9Sstevel@tonic-gate milter_error(m, e);
46367c478bd9Sstevel@tonic-gate break;
46377c478bd9Sstevel@tonic-gate }
46387c478bd9Sstevel@tonic-gate if (rcmd != SMFIR_REPLYCODE && response != NULL)
46397c478bd9Sstevel@tonic-gate {
46407c478bd9Sstevel@tonic-gate sm_free(response); /* XXX */
46417c478bd9Sstevel@tonic-gate response = NULL;
46427c478bd9Sstevel@tonic-gate }
46437c478bd9Sstevel@tonic-gate
46447c478bd9Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR)
46457c478bd9Sstevel@tonic-gate break;
46467c478bd9Sstevel@tonic-gate }
46477c478bd9Sstevel@tonic-gate
46487c478bd9Sstevel@tonic-gate if (replbody && !replfailed)
46497c478bd9Sstevel@tonic-gate {
46507c478bd9Sstevel@tonic-gate /* flush possible buffered character */
46517c478bd9Sstevel@tonic-gate milter_replbody(NULL, 0, !replbody, e);
46527c478bd9Sstevel@tonic-gate replbody = false;
46537c478bd9Sstevel@tonic-gate }
46547c478bd9Sstevel@tonic-gate
46557c478bd9Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR)
46567c478bd9Sstevel@tonic-gate {
46577c478bd9Sstevel@tonic-gate MILTER_CHECK_ERROR(false, continue);
46587c478bd9Sstevel@tonic-gate goto finishup;
46597c478bd9Sstevel@tonic-gate }
46607c478bd9Sstevel@tonic-gate }
46617c478bd9Sstevel@tonic-gate
46627c478bd9Sstevel@tonic-gate finishup:
46637c478bd9Sstevel@tonic-gate /* leave things in the expected state if we touched it */
46647c478bd9Sstevel@tonic-gate if (replfailed)
46657c478bd9Sstevel@tonic-gate {
46667c478bd9Sstevel@tonic-gate if (*state == SMFIR_CONTINUE ||
46677c478bd9Sstevel@tonic-gate *state == SMFIR_ACCEPT)
46687c478bd9Sstevel@tonic-gate {
46697c478bd9Sstevel@tonic-gate *state = SMFIR_TEMPFAIL;
46707c478bd9Sstevel@tonic-gate SM_FREE_CLR(response);
46717c478bd9Sstevel@tonic-gate }
46727c478bd9Sstevel@tonic-gate
46737c478bd9Sstevel@tonic-gate if (dfopen)
46747c478bd9Sstevel@tonic-gate {
46757c478bd9Sstevel@tonic-gate (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT);
46767c478bd9Sstevel@tonic-gate e->e_dfp = NULL;
46777c478bd9Sstevel@tonic-gate e->e_flags &= ~EF_HAS_DF;
46787c478bd9Sstevel@tonic-gate dfopen = false;
46797c478bd9Sstevel@tonic-gate }
46807c478bd9Sstevel@tonic-gate rewind = false;
46817c478bd9Sstevel@tonic-gate }
46827c478bd9Sstevel@tonic-gate
46837c478bd9Sstevel@tonic-gate if ((dfopen && milter_reset_df(e) < 0) ||
46847c478bd9Sstevel@tonic-gate (rewind && bfrewind(e->e_dfp) < 0))
46857c478bd9Sstevel@tonic-gate {
46867c478bd9Sstevel@tonic-gate save_errno = errno;
46877c478bd9Sstevel@tonic-gate ExitStat = EX_IOERR;
46887c478bd9Sstevel@tonic-gate
46897c478bd9Sstevel@tonic-gate /*
46907c478bd9Sstevel@tonic-gate ** If filter told us to keep message but we had
46917c478bd9Sstevel@tonic-gate ** an error, we can't really keep it, tempfail it.
46927c478bd9Sstevel@tonic-gate */
46937c478bd9Sstevel@tonic-gate
46947c478bd9Sstevel@tonic-gate if (*state == SMFIR_CONTINUE ||
46957c478bd9Sstevel@tonic-gate *state == SMFIR_ACCEPT)
46967c478bd9Sstevel@tonic-gate {
46977c478bd9Sstevel@tonic-gate *state = SMFIR_TEMPFAIL;
46987c478bd9Sstevel@tonic-gate SM_FREE_CLR(response);
46997c478bd9Sstevel@tonic-gate }
47007c478bd9Sstevel@tonic-gate
47017c478bd9Sstevel@tonic-gate errno = save_errno;
47027c478bd9Sstevel@tonic-gate syserr("milter_data: %s/%cf%s: read error",
47037c478bd9Sstevel@tonic-gate qid_printqueue(e->e_qgrp, e->e_qdir),
47047c478bd9Sstevel@tonic-gate DATAFL_LETTER, e->e_id);
47057c478bd9Sstevel@tonic-gate }
47067c478bd9Sstevel@tonic-gate
47077c478bd9Sstevel@tonic-gate MILTER_CHECK_DONE_MSG();
47087c478bd9Sstevel@tonic-gate if (MilterLogLevel > 10 && *state == SMFIR_REJECT)
47097c478bd9Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter: reject, data");
47107c478bd9Sstevel@tonic-gate return response;
47117c478bd9Sstevel@tonic-gate }
47127c478bd9Sstevel@tonic-gate
47137c478bd9Sstevel@tonic-gate /*
47147c478bd9Sstevel@tonic-gate ** MILTER_UNKNOWN -- send any unrecognized or unimplemented command
47157c478bd9Sstevel@tonic-gate ** string to milter filters
47167c478bd9Sstevel@tonic-gate **
47177c478bd9Sstevel@tonic-gate ** Parameters:
4718058561cbSjbeck ** smtpcmd -- the string itself.
47197c478bd9Sstevel@tonic-gate ** e -- current envelope.
47207c478bd9Sstevel@tonic-gate ** state -- return state from response.
47217c478bd9Sstevel@tonic-gate **
47227c478bd9Sstevel@tonic-gate **
47237c478bd9Sstevel@tonic-gate ** Returns:
47247c478bd9Sstevel@tonic-gate ** response string (may be NULL)
47257c478bd9Sstevel@tonic-gate */
47267c478bd9Sstevel@tonic-gate
47277c478bd9Sstevel@tonic-gate char *
milter_unknown(smtpcmd,e,state)4728058561cbSjbeck milter_unknown(smtpcmd, e, state)
4729058561cbSjbeck char *smtpcmd;
47307c478bd9Sstevel@tonic-gate ENVELOPE *e;
47317c478bd9Sstevel@tonic-gate char *state;
47327c478bd9Sstevel@tonic-gate {
47337c478bd9Sstevel@tonic-gate if (tTd(64, 10))
4734058561cbSjbeck sm_dprintf("milter_unknown(%s)\n", smtpcmd);
47357c478bd9Sstevel@tonic-gate
4736058561cbSjbeck return milter_command(SMFIC_UNKNOWN, smtpcmd, strlen(smtpcmd) + 1,
4737058561cbSjbeck NULL, e, state, "unknown", false);
47387c478bd9Sstevel@tonic-gate }
47397c478bd9Sstevel@tonic-gate
47407c478bd9Sstevel@tonic-gate /*
47417c478bd9Sstevel@tonic-gate ** MILTER_QUIT -- informs the filter(s) we are done and closes connection(s)
47427c478bd9Sstevel@tonic-gate **
47437c478bd9Sstevel@tonic-gate ** Parameters:
47447c478bd9Sstevel@tonic-gate ** e -- current envelope.
47457c478bd9Sstevel@tonic-gate **
47467c478bd9Sstevel@tonic-gate ** Returns:
47477c478bd9Sstevel@tonic-gate ** none
47487c478bd9Sstevel@tonic-gate */
47497c478bd9Sstevel@tonic-gate
47507c478bd9Sstevel@tonic-gate void
milter_quit(e)47517c478bd9Sstevel@tonic-gate milter_quit(e)
47527c478bd9Sstevel@tonic-gate ENVELOPE *e;
47537c478bd9Sstevel@tonic-gate {
47547c478bd9Sstevel@tonic-gate int i;
47557c478bd9Sstevel@tonic-gate
47567c478bd9Sstevel@tonic-gate if (tTd(64, 10))
47577c478bd9Sstevel@tonic-gate sm_dprintf("milter_quit(%s)\n", e->e_id);
47587c478bd9Sstevel@tonic-gate
47597c478bd9Sstevel@tonic-gate for (i = 0; InputFilters[i] != NULL; i++)
47607c478bd9Sstevel@tonic-gate milter_quit_filter(InputFilters[i], e);
47617c478bd9Sstevel@tonic-gate }
4762058561cbSjbeck
47637c478bd9Sstevel@tonic-gate /*
47647c478bd9Sstevel@tonic-gate ** MILTER_ABORT -- informs the filter(s) that we are aborting current message
47657c478bd9Sstevel@tonic-gate **
47667c478bd9Sstevel@tonic-gate ** Parameters:
47677c478bd9Sstevel@tonic-gate ** e -- current envelope.
47687c478bd9Sstevel@tonic-gate **
47697c478bd9Sstevel@tonic-gate ** Returns:
47707c478bd9Sstevel@tonic-gate ** none
47717c478bd9Sstevel@tonic-gate */
47727c478bd9Sstevel@tonic-gate
47737c478bd9Sstevel@tonic-gate void
milter_abort(e)47747c478bd9Sstevel@tonic-gate milter_abort(e)
47757c478bd9Sstevel@tonic-gate ENVELOPE *e;
47767c478bd9Sstevel@tonic-gate {
47777c478bd9Sstevel@tonic-gate int i;
47787c478bd9Sstevel@tonic-gate
47797c478bd9Sstevel@tonic-gate if (tTd(64, 10))
47807c478bd9Sstevel@tonic-gate sm_dprintf("milter_abort\n");
47817c478bd9Sstevel@tonic-gate
47827c478bd9Sstevel@tonic-gate for (i = 0; InputFilters[i] != NULL; i++)
47837c478bd9Sstevel@tonic-gate {
47847c478bd9Sstevel@tonic-gate struct milter *m = InputFilters[i];
47857c478bd9Sstevel@tonic-gate
47867c478bd9Sstevel@tonic-gate /* sanity checks */
47877c478bd9Sstevel@tonic-gate if (m->mf_sock < 0 || m->mf_state != SMFS_INMSG)
47887c478bd9Sstevel@tonic-gate continue;
47897c478bd9Sstevel@tonic-gate
47907c478bd9Sstevel@tonic-gate milter_abort_filter(m, e);
47917c478bd9Sstevel@tonic-gate }
47927c478bd9Sstevel@tonic-gate }
47937c478bd9Sstevel@tonic-gate #endif /* MILTER */
4794