10Sstevel@tonic-gate /* 23544Sjbeck * Copyright (c) 1999-2006 Sendmail, Inc. and its suppliers. 30Sstevel@tonic-gate * All rights reserved. 40Sstevel@tonic-gate * 50Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set 60Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of 70Sstevel@tonic-gate * the sendmail distribution. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate */ 100Sstevel@tonic-gate 110Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 120Sstevel@tonic-gate 130Sstevel@tonic-gate #include <sendmail.h> 140Sstevel@tonic-gate 15*5402Sjbeck SM_RCSID("@(#)$Id: milter.c,v 8.269 2007/06/06 17:26:12 ca Exp $") 160Sstevel@tonic-gate 170Sstevel@tonic-gate #if MILTER 183544Sjbeck # include <sm/sendmail.h> 190Sstevel@tonic-gate # include <libmilter/mfapi.h> 200Sstevel@tonic-gate # include <libmilter/mfdef.h> 210Sstevel@tonic-gate 220Sstevel@tonic-gate # include <errno.h> 23616Sjbeck # include <sm/time.h> 240Sstevel@tonic-gate # include <sys/uio.h> 250Sstevel@tonic-gate 260Sstevel@tonic-gate # if NETINET || NETINET6 270Sstevel@tonic-gate # include <arpa/inet.h> 283544Sjbeck # if MILTER_NO_NAGLE 290Sstevel@tonic-gate # include <netinet/tcp.h> 303544Sjbeck # endif /* MILTER_NO_NAGLE */ 310Sstevel@tonic-gate # endif /* NETINET || NETINET6 */ 320Sstevel@tonic-gate 330Sstevel@tonic-gate # include <sm/fdset.h> 340Sstevel@tonic-gate 350Sstevel@tonic-gate static void milter_connect_timeout __P((int)); 360Sstevel@tonic-gate static void milter_error __P((struct milter *, ENVELOPE *)); 370Sstevel@tonic-gate static int milter_open __P((struct milter *, bool, ENVELOPE *)); 380Sstevel@tonic-gate static void milter_parse_timeouts __P((char *, struct milter *)); 393544Sjbeck static char *milter_sysread __P((struct milter *, char *, ssize_t, time_t, 403544Sjbeck ENVELOPE *, const char *)); 413544Sjbeck static char *milter_read __P((struct milter *, char *, ssize_t *, time_t, 423544Sjbeck ENVELOPE *, const char *)); 433544Sjbeck static char *milter_write __P((struct milter *, int, char *, ssize_t, 443544Sjbeck time_t, ENVELOPE *, const char *)); 453544Sjbeck static char *milter_send_command __P((struct milter *, int, void *, 463544Sjbeck ssize_t, ENVELOPE *, char *, const char *)); 473544Sjbeck static char *milter_command __P((int, void *, ssize_t, char **, 483544Sjbeck ENVELOPE *, char *, const char *, bool)); 493544Sjbeck static char *milter_body __P((struct milter *, ENVELOPE *, char *)); 503544Sjbeck static int milter_reopen_df __P((ENVELOPE *)); 513544Sjbeck static int milter_reset_df __P((ENVELOPE *)); 523544Sjbeck static void milter_quit_filter __P((struct milter *, ENVELOPE *)); 533544Sjbeck static void milter_abort_filter __P((struct milter *, ENVELOPE *)); 543544Sjbeck static void milter_send_macros __P((struct milter *, char **, int, 553544Sjbeck ENVELOPE *)); 56*5402Sjbeck static int milter_negotiate __P((struct milter *, ENVELOPE *, 57*5402Sjbeck milters_T *)); 583544Sjbeck static void milter_per_connection_check __P((ENVELOPE *)); 593544Sjbeck static char *milter_headers __P((struct milter *, ENVELOPE *, char *)); 603544Sjbeck static void milter_addheader __P((struct milter *, char *, ssize_t, 613544Sjbeck ENVELOPE *)); 623544Sjbeck static void milter_insheader __P((struct milter *, char *, ssize_t, 633544Sjbeck ENVELOPE *)); 643544Sjbeck static void milter_changeheader __P((struct milter *, char *, ssize_t, 653544Sjbeck ENVELOPE *)); 663544Sjbeck static void milter_chgfrom __P((char *, ssize_t, ENVELOPE *)); 673544Sjbeck static void milter_addrcpt __P((char *, ssize_t, ENVELOPE *)); 683544Sjbeck static void milter_addrcpt_par __P((char *, ssize_t, ENVELOPE *)); 693544Sjbeck static void milter_delrcpt __P((char *, ssize_t, ENVELOPE *)); 703544Sjbeck static int milter_replbody __P((char *, ssize_t, bool, ENVELOPE *)); 713544Sjbeck static int milter_set_macros __P((char *, char **, char *, int)); 723544Sjbeck 733544Sjbeck 743544Sjbeck /* milter states */ 753544Sjbeck # define SMFS_CLOSED 'C' /* closed for all further actions */ 763544Sjbeck # define SMFS_OPEN 'O' /* connected to remote milter filter */ 773544Sjbeck # define SMFS_INMSG 'M' /* currently servicing a message */ 783544Sjbeck # define SMFS_DONE 'D' /* done with current message */ 793544Sjbeck # define SMFS_CLOSABLE 'Q' /* done with current connection */ 803544Sjbeck # define SMFS_ERROR 'E' /* error state */ 813544Sjbeck # define SMFS_READY 'R' /* ready for action */ 823544Sjbeck # define SMFS_SKIP 'S' /* skip body */ 830Sstevel@tonic-gate 840Sstevel@tonic-gate static char *MilterConnectMacros[MAXFILTERMACROS + 1]; 850Sstevel@tonic-gate static char *MilterHeloMacros[MAXFILTERMACROS + 1]; 860Sstevel@tonic-gate static char *MilterEnvFromMacros[MAXFILTERMACROS + 1]; 870Sstevel@tonic-gate static char *MilterEnvRcptMacros[MAXFILTERMACROS + 1]; 880Sstevel@tonic-gate static char *MilterDataMacros[MAXFILTERMACROS + 1]; 890Sstevel@tonic-gate static char *MilterEOMMacros[MAXFILTERMACROS + 1]; 903544Sjbeck static char *MilterEOHMacros[MAXFILTERMACROS + 1]; 910Sstevel@tonic-gate static size_t MilterMaxDataSize = MILTER_MAX_DATA_SIZE; 920Sstevel@tonic-gate 930Sstevel@tonic-gate # define MILTER_CHECK_DONE_MSG() \ 940Sstevel@tonic-gate if (*state == SMFIR_REPLYCODE || \ 950Sstevel@tonic-gate *state == SMFIR_REJECT || \ 960Sstevel@tonic-gate *state == SMFIR_DISCARD || \ 970Sstevel@tonic-gate *state == SMFIR_TEMPFAIL) \ 980Sstevel@tonic-gate { \ 990Sstevel@tonic-gate /* Abort the filters to let them know we are done with msg */ \ 1000Sstevel@tonic-gate milter_abort(e); \ 1010Sstevel@tonic-gate } 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate # define MILTER_CHECK_ERROR(initial, action) \ 1040Sstevel@tonic-gate if (!initial && tTd(71, 100)) \ 1050Sstevel@tonic-gate { \ 1060Sstevel@tonic-gate if (e->e_quarmsg == NULL) \ 1070Sstevel@tonic-gate { \ 1080Sstevel@tonic-gate e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, \ 1090Sstevel@tonic-gate "filter failure"); \ 1100Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), \ 1110Sstevel@tonic-gate e->e_quarmsg); \ 1120Sstevel@tonic-gate } \ 1130Sstevel@tonic-gate } \ 1140Sstevel@tonic-gate else if (tTd(71, 101)) \ 1150Sstevel@tonic-gate { \ 1160Sstevel@tonic-gate if (e->e_quarmsg == NULL) \ 1170Sstevel@tonic-gate { \ 1180Sstevel@tonic-gate e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, \ 1190Sstevel@tonic-gate "filter failure"); \ 1200Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, macid("{quarantine}"), \ 1210Sstevel@tonic-gate e->e_quarmsg); \ 1220Sstevel@tonic-gate } \ 1230Sstevel@tonic-gate } \ 1240Sstevel@tonic-gate else if (bitnset(SMF_TEMPFAIL, m->mf_flags)) \ 1250Sstevel@tonic-gate *state = SMFIR_TEMPFAIL; \ 1260Sstevel@tonic-gate else if (bitnset(SMF_TEMPDROP, m->mf_flags)) \ 1270Sstevel@tonic-gate *state = SMFIR_SHUTDOWN; \ 1280Sstevel@tonic-gate else if (bitnset(SMF_REJECT, m->mf_flags)) \ 1290Sstevel@tonic-gate *state = SMFIR_REJECT; \ 1300Sstevel@tonic-gate else \ 1310Sstevel@tonic-gate action; 1320Sstevel@tonic-gate 1330Sstevel@tonic-gate # define MILTER_CHECK_REPLYCODE(default) \ 1340Sstevel@tonic-gate if (response == NULL || \ 1350Sstevel@tonic-gate strlen(response) + 1 != (size_t) rlen || \ 1360Sstevel@tonic-gate rlen < 3 || \ 1370Sstevel@tonic-gate (response[0] != '4' && response[0] != '5') || \ 1380Sstevel@tonic-gate !isascii(response[1]) || !isdigit(response[1]) || \ 1390Sstevel@tonic-gate !isascii(response[2]) || !isdigit(response[2])) \ 1400Sstevel@tonic-gate { \ 1410Sstevel@tonic-gate if (response != NULL) \ 1420Sstevel@tonic-gate sm_free(response); /* XXX */ \ 1430Sstevel@tonic-gate response = newstr(default); \ 1440Sstevel@tonic-gate } \ 1450Sstevel@tonic-gate else \ 1460Sstevel@tonic-gate { \ 1470Sstevel@tonic-gate char *ptr = response; \ 1480Sstevel@tonic-gate \ 1490Sstevel@tonic-gate /* Check for unprotected %'s in the string */ \ 1500Sstevel@tonic-gate while (*ptr != '\0') \ 1510Sstevel@tonic-gate { \ 1520Sstevel@tonic-gate if (*ptr == '%' && *++ptr != '%') \ 1530Sstevel@tonic-gate { \ 1540Sstevel@tonic-gate sm_free(response); /* XXX */ \ 1550Sstevel@tonic-gate response = newstr(default); \ 1560Sstevel@tonic-gate break; \ 1570Sstevel@tonic-gate } \ 1580Sstevel@tonic-gate ptr++; \ 1590Sstevel@tonic-gate } \ 1600Sstevel@tonic-gate } 1610Sstevel@tonic-gate 1620Sstevel@tonic-gate # define MILTER_DF_ERROR(msg) \ 1630Sstevel@tonic-gate { \ 1640Sstevel@tonic-gate int save_errno = errno; \ 1650Sstevel@tonic-gate \ 1660Sstevel@tonic-gate if (tTd(64, 5)) \ 1670Sstevel@tonic-gate { \ 1680Sstevel@tonic-gate sm_dprintf(msg, dfname, sm_errstring(save_errno)); \ 1690Sstevel@tonic-gate sm_dprintf("\n"); \ 1700Sstevel@tonic-gate } \ 1710Sstevel@tonic-gate if (MilterLogLevel > 0) \ 1720Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, msg, dfname, sm_errstring(save_errno)); \ 1730Sstevel@tonic-gate if (SuperSafe == SAFE_REALLY) \ 1740Sstevel@tonic-gate { \ 1750Sstevel@tonic-gate if (e->e_dfp != NULL) \ 1760Sstevel@tonic-gate { \ 1770Sstevel@tonic-gate (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT); \ 1780Sstevel@tonic-gate e->e_dfp = NULL; \ 1790Sstevel@tonic-gate } \ 1800Sstevel@tonic-gate e->e_flags &= ~EF_HAS_DF; \ 1810Sstevel@tonic-gate } \ 1820Sstevel@tonic-gate errno = save_errno; \ 1830Sstevel@tonic-gate } 1840Sstevel@tonic-gate 1850Sstevel@tonic-gate /* 1860Sstevel@tonic-gate ** MILTER_TIMEOUT -- make sure socket is ready in time 1870Sstevel@tonic-gate ** 1880Sstevel@tonic-gate ** Parameters: 1890Sstevel@tonic-gate ** routine -- routine name for debug/logging 1900Sstevel@tonic-gate ** secs -- number of seconds in timeout 1910Sstevel@tonic-gate ** write -- waiting to read or write? 1920Sstevel@tonic-gate ** started -- whether this is part of a previous sequence 1930Sstevel@tonic-gate ** 1940Sstevel@tonic-gate ** Assumes 'm' is a milter structure for the current socket. 1950Sstevel@tonic-gate */ 1960Sstevel@tonic-gate 1973544Sjbeck # define MILTER_TIMEOUT(routine, secs, write, started, function) \ 1980Sstevel@tonic-gate { \ 1990Sstevel@tonic-gate int ret; \ 2000Sstevel@tonic-gate int save_errno; \ 2010Sstevel@tonic-gate fd_set fds; \ 2020Sstevel@tonic-gate struct timeval tv; \ 2030Sstevel@tonic-gate \ 2040Sstevel@tonic-gate if (SM_FD_SETSIZE > 0 && m->mf_sock >= SM_FD_SETSIZE) \ 2050Sstevel@tonic-gate { \ 2060Sstevel@tonic-gate if (tTd(64, 5)) \ 2070Sstevel@tonic-gate sm_dprintf("milter_%s(%s): socket %d is larger than FD_SETSIZE %d\n", \ 2080Sstevel@tonic-gate (routine), m->mf_name, m->mf_sock, \ 2090Sstevel@tonic-gate SM_FD_SETSIZE); \ 2100Sstevel@tonic-gate if (MilterLogLevel > 0) \ 2110Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, \ 2120Sstevel@tonic-gate "Milter (%s): socket(%s) %d is larger than FD_SETSIZE %d", \ 2130Sstevel@tonic-gate m->mf_name, (routine), m->mf_sock, \ 2140Sstevel@tonic-gate SM_FD_SETSIZE); \ 2150Sstevel@tonic-gate milter_error(m, e); \ 2160Sstevel@tonic-gate return NULL; \ 2170Sstevel@tonic-gate } \ 2180Sstevel@tonic-gate \ 2190Sstevel@tonic-gate do \ 2200Sstevel@tonic-gate { \ 2210Sstevel@tonic-gate FD_ZERO(&fds); \ 2220Sstevel@tonic-gate SM_FD_SET(m->mf_sock, &fds); \ 2230Sstevel@tonic-gate tv.tv_sec = (secs); \ 2240Sstevel@tonic-gate tv.tv_usec = 0; \ 2250Sstevel@tonic-gate ret = select(m->mf_sock + 1, \ 2260Sstevel@tonic-gate (write) ? NULL : &fds, \ 2270Sstevel@tonic-gate (write) ? &fds : NULL, \ 2280Sstevel@tonic-gate NULL, &tv); \ 2290Sstevel@tonic-gate } while (ret < 0 && errno == EINTR); \ 2300Sstevel@tonic-gate \ 2310Sstevel@tonic-gate switch (ret) \ 2320Sstevel@tonic-gate { \ 2330Sstevel@tonic-gate case 0: \ 2340Sstevel@tonic-gate if (tTd(64, 5)) \ 2353544Sjbeck sm_dprintf("milter_%s(%s): timeout, where=%s\n", \ 2363544Sjbeck (routine), m->mf_name, (function)); \ 2370Sstevel@tonic-gate if (MilterLogLevel > 0) \ 2380Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, \ 2393544Sjbeck "Milter (%s): timeout %s data %s, where=%s", \ 2403544Sjbeck m->mf_name, \ 2410Sstevel@tonic-gate started ? "during" : "before", \ 2423544Sjbeck (routine), (function)); \ 2430Sstevel@tonic-gate milter_error(m, e); \ 2440Sstevel@tonic-gate return NULL; \ 2450Sstevel@tonic-gate \ 2460Sstevel@tonic-gate case -1: \ 2470Sstevel@tonic-gate save_errno = errno; \ 2480Sstevel@tonic-gate if (tTd(64, 5)) \ 2490Sstevel@tonic-gate sm_dprintf("milter_%s(%s): select: %s\n", (routine), \ 2500Sstevel@tonic-gate m->mf_name, sm_errstring(save_errno)); \ 2510Sstevel@tonic-gate if (MilterLogLevel > 0) \ 2520Sstevel@tonic-gate { \ 2530Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, \ 2540Sstevel@tonic-gate "Milter (%s): select(%s): %s", \ 2550Sstevel@tonic-gate m->mf_name, (routine), \ 2560Sstevel@tonic-gate sm_errstring(save_errno)); \ 2570Sstevel@tonic-gate } \ 2580Sstevel@tonic-gate milter_error(m, e); \ 2590Sstevel@tonic-gate return NULL; \ 2600Sstevel@tonic-gate \ 2610Sstevel@tonic-gate default: \ 2620Sstevel@tonic-gate if (SM_FD_ISSET(m->mf_sock, &fds)) \ 2630Sstevel@tonic-gate break; \ 2640Sstevel@tonic-gate if (tTd(64, 5)) \ 2650Sstevel@tonic-gate sm_dprintf("milter_%s(%s): socket not ready\n", \ 2660Sstevel@tonic-gate (routine), m->mf_name); \ 2670Sstevel@tonic-gate if (MilterLogLevel > 0) \ 2680Sstevel@tonic-gate { \ 2690Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, \ 2700Sstevel@tonic-gate "Milter (%s): socket(%s) not ready", \ 2710Sstevel@tonic-gate m->mf_name, (routine)); \ 2720Sstevel@tonic-gate } \ 2730Sstevel@tonic-gate milter_error(m, e); \ 2740Sstevel@tonic-gate return NULL; \ 2750Sstevel@tonic-gate } \ 2760Sstevel@tonic-gate } 2770Sstevel@tonic-gate 2780Sstevel@tonic-gate /* 2790Sstevel@tonic-gate ** Low level functions 2800Sstevel@tonic-gate */ 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate /* 2830Sstevel@tonic-gate ** MILTER_READ -- read from a remote milter filter 2840Sstevel@tonic-gate ** 2850Sstevel@tonic-gate ** Parameters: 2860Sstevel@tonic-gate ** m -- milter to read from. 2870Sstevel@tonic-gate ** cmd -- return param for command read. 2880Sstevel@tonic-gate ** rlen -- return length of response string. 2890Sstevel@tonic-gate ** to -- timeout in seconds. 2900Sstevel@tonic-gate ** e -- current envelope. 2910Sstevel@tonic-gate ** 2920Sstevel@tonic-gate ** Returns: 2930Sstevel@tonic-gate ** response string (may be NULL) 2940Sstevel@tonic-gate */ 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate static char * 2973544Sjbeck milter_sysread(m, buf, sz, to, e, where) 2980Sstevel@tonic-gate struct milter *m; 2990Sstevel@tonic-gate char *buf; 3000Sstevel@tonic-gate ssize_t sz; 3010Sstevel@tonic-gate time_t to; 3020Sstevel@tonic-gate ENVELOPE *e; 3033544Sjbeck const char *where; 3040Sstevel@tonic-gate { 3050Sstevel@tonic-gate time_t readstart = 0; 3060Sstevel@tonic-gate ssize_t len, curl; 3070Sstevel@tonic-gate bool started = false; 3080Sstevel@tonic-gate 3090Sstevel@tonic-gate curl = 0; 3100Sstevel@tonic-gate 3110Sstevel@tonic-gate if (to > 0) 3120Sstevel@tonic-gate readstart = curtime(); 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate for (;;) 3150Sstevel@tonic-gate { 3160Sstevel@tonic-gate if (to > 0) 3170Sstevel@tonic-gate { 3180Sstevel@tonic-gate time_t now; 3190Sstevel@tonic-gate 3200Sstevel@tonic-gate now = curtime(); 3210Sstevel@tonic-gate if (now - readstart >= to) 3220Sstevel@tonic-gate { 3230Sstevel@tonic-gate if (tTd(64, 5)) 3243544Sjbeck sm_dprintf("milter_sys_read (%s): timeout %s data read in %s", 3253544Sjbeck m->mf_name, 3260Sstevel@tonic-gate started ? "during" : "before", 3273544Sjbeck where); 3280Sstevel@tonic-gate if (MilterLogLevel > 0) 3290Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 3303544Sjbeck "Milter (%s): timeout %s data read in %s", 3313544Sjbeck m->mf_name, 3320Sstevel@tonic-gate started ? "during" : "before", 3333544Sjbeck where); 3340Sstevel@tonic-gate milter_error(m, e); 3350Sstevel@tonic-gate return NULL; 3360Sstevel@tonic-gate } 3370Sstevel@tonic-gate to -= now - readstart; 3380Sstevel@tonic-gate readstart = now; 3393544Sjbeck MILTER_TIMEOUT("read", to, false, started, where); 3400Sstevel@tonic-gate } 3410Sstevel@tonic-gate 3420Sstevel@tonic-gate len = read(m->mf_sock, buf + curl, sz - curl); 3430Sstevel@tonic-gate 3440Sstevel@tonic-gate if (len < 0) 3450Sstevel@tonic-gate { 3460Sstevel@tonic-gate int save_errno = errno; 3470Sstevel@tonic-gate 3480Sstevel@tonic-gate if (tTd(64, 5)) 3493544Sjbeck sm_dprintf("milter_sys_read(%s): read returned %ld: %s\n", 3500Sstevel@tonic-gate m->mf_name, (long) len, 3510Sstevel@tonic-gate sm_errstring(save_errno)); 3520Sstevel@tonic-gate if (MilterLogLevel > 0) 3530Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 3540Sstevel@tonic-gate "Milter (%s): read returned %ld: %s", 3550Sstevel@tonic-gate m->mf_name, (long) len, 3560Sstevel@tonic-gate sm_errstring(save_errno)); 3570Sstevel@tonic-gate milter_error(m, e); 3580Sstevel@tonic-gate return NULL; 3590Sstevel@tonic-gate } 3600Sstevel@tonic-gate 3610Sstevel@tonic-gate started = true; 3620Sstevel@tonic-gate curl += len; 3630Sstevel@tonic-gate if (len == 0 || curl >= sz) 3640Sstevel@tonic-gate break; 3650Sstevel@tonic-gate 3660Sstevel@tonic-gate } 3670Sstevel@tonic-gate 3680Sstevel@tonic-gate if (curl != sz) 3690Sstevel@tonic-gate { 3700Sstevel@tonic-gate if (tTd(64, 5)) 3713544Sjbeck sm_dprintf("milter_sys_read(%s): cmd read returned %ld, expecting %ld\n", 3720Sstevel@tonic-gate m->mf_name, (long) curl, (long) sz); 3730Sstevel@tonic-gate if (MilterLogLevel > 0) 3740Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 3753544Sjbeck "milter_sys_read(%s): cmd read returned %ld, expecting %ld", 3760Sstevel@tonic-gate m->mf_name, (long) curl, (long) sz); 3770Sstevel@tonic-gate milter_error(m, e); 3780Sstevel@tonic-gate return NULL; 3790Sstevel@tonic-gate } 3800Sstevel@tonic-gate return buf; 3810Sstevel@tonic-gate } 3820Sstevel@tonic-gate 3830Sstevel@tonic-gate static char * 3843544Sjbeck milter_read(m, cmd, rlen, to, e, where) 3850Sstevel@tonic-gate struct milter *m; 3860Sstevel@tonic-gate char *cmd; 3870Sstevel@tonic-gate ssize_t *rlen; 3880Sstevel@tonic-gate time_t to; 3890Sstevel@tonic-gate ENVELOPE *e; 3903544Sjbeck const char *where; 3910Sstevel@tonic-gate { 3920Sstevel@tonic-gate time_t readstart = 0; 3930Sstevel@tonic-gate ssize_t expl; 3940Sstevel@tonic-gate mi_int32 i; 3953544Sjbeck # if MILTER_NO_NAGLE && defined(TCP_CORK) 3960Sstevel@tonic-gate int cork = 0; 3973544Sjbeck # endif /* MILTER_NO_NAGLE && defined(TCP_CORK) */ 3980Sstevel@tonic-gate char *buf; 3990Sstevel@tonic-gate char data[MILTER_LEN_BYTES + 1]; 4000Sstevel@tonic-gate 4010Sstevel@tonic-gate if (m->mf_sock < 0) 4020Sstevel@tonic-gate { 4030Sstevel@tonic-gate if (MilterLogLevel > 0) 4040Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 4053544Sjbeck "milter_read(%s): socket closed, where=%s", 4063544Sjbeck m->mf_name, where); 4070Sstevel@tonic-gate milter_error(m, e); 4080Sstevel@tonic-gate return NULL; 4090Sstevel@tonic-gate } 4100Sstevel@tonic-gate 4110Sstevel@tonic-gate *rlen = 0; 4120Sstevel@tonic-gate *cmd = '\0'; 4130Sstevel@tonic-gate 4140Sstevel@tonic-gate if (to > 0) 4150Sstevel@tonic-gate readstart = curtime(); 4160Sstevel@tonic-gate 4173544Sjbeck # if MILTER_NO_NAGLE && defined(TCP_CORK) 4180Sstevel@tonic-gate setsockopt(m->mf_sock, IPPROTO_TCP, TCP_CORK, (char *)&cork, 4190Sstevel@tonic-gate sizeof(cork)); 4203544Sjbeck # endif /* MILTER_NO_NAGLE && defined(TCP_CORK) */ 4213544Sjbeck 4223544Sjbeck if (milter_sysread(m, data, sizeof(data), to, e, where) == NULL) 4230Sstevel@tonic-gate return NULL; 4240Sstevel@tonic-gate 4253544Sjbeck # if MILTER_NO_NAGLE && defined(TCP_CORK) 4260Sstevel@tonic-gate cork = 1; 4270Sstevel@tonic-gate setsockopt(m->mf_sock, IPPROTO_TCP, TCP_CORK, (char *)&cork, 4280Sstevel@tonic-gate sizeof(cork)); 4293544Sjbeck # endif /* MILTER_NO_NAGLE && defined(TCP_CORK) */ 4300Sstevel@tonic-gate 4310Sstevel@tonic-gate /* reset timeout */ 4320Sstevel@tonic-gate if (to > 0) 4330Sstevel@tonic-gate { 4340Sstevel@tonic-gate time_t now; 4350Sstevel@tonic-gate 4360Sstevel@tonic-gate now = curtime(); 4370Sstevel@tonic-gate if (now - readstart >= to) 4380Sstevel@tonic-gate { 4390Sstevel@tonic-gate if (tTd(64, 5)) 4403544Sjbeck sm_dprintf("milter_read(%s): timeout before data read, where=%s\n", 4413544Sjbeck m->mf_name, where); 4420Sstevel@tonic-gate if (MilterLogLevel > 0) 4430Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 4443544Sjbeck "Milter read(%s): timeout before data read, where=%s", 4453544Sjbeck m->mf_name, where); 4460Sstevel@tonic-gate milter_error(m, e); 4470Sstevel@tonic-gate return NULL; 4480Sstevel@tonic-gate } 4490Sstevel@tonic-gate to -= now - readstart; 4500Sstevel@tonic-gate } 4510Sstevel@tonic-gate 4520Sstevel@tonic-gate *cmd = data[MILTER_LEN_BYTES]; 4530Sstevel@tonic-gate data[MILTER_LEN_BYTES] = '\0'; 4540Sstevel@tonic-gate (void) memcpy(&i, data, MILTER_LEN_BYTES); 4550Sstevel@tonic-gate expl = ntohl(i) - 1; 4560Sstevel@tonic-gate 4570Sstevel@tonic-gate if (tTd(64, 25)) 4580Sstevel@tonic-gate sm_dprintf("milter_read(%s): expecting %ld bytes\n", 4590Sstevel@tonic-gate m->mf_name, (long) expl); 4600Sstevel@tonic-gate 4610Sstevel@tonic-gate if (expl < 0) 4620Sstevel@tonic-gate { 4630Sstevel@tonic-gate if (tTd(64, 5)) 4643544Sjbeck sm_dprintf("milter_read(%s): read size %ld out of range, where=%s\n", 4653544Sjbeck m->mf_name, (long) expl, where); 4660Sstevel@tonic-gate if (MilterLogLevel > 0) 4670Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 4683544Sjbeck "milter_read(%s): read size %ld out of range, where=%s", 4693544Sjbeck m->mf_name, (long) expl, where); 4700Sstevel@tonic-gate milter_error(m, e); 4710Sstevel@tonic-gate return NULL; 4720Sstevel@tonic-gate } 4730Sstevel@tonic-gate 4740Sstevel@tonic-gate if (expl == 0) 4750Sstevel@tonic-gate return NULL; 4760Sstevel@tonic-gate 4770Sstevel@tonic-gate buf = (char *) xalloc(expl); 4780Sstevel@tonic-gate 4793544Sjbeck if (milter_sysread(m, buf, expl, to, e, where) == NULL) 4800Sstevel@tonic-gate { 4810Sstevel@tonic-gate sm_free(buf); /* XXX */ 4820Sstevel@tonic-gate return NULL; 4830Sstevel@tonic-gate } 4840Sstevel@tonic-gate 4850Sstevel@tonic-gate if (tTd(64, 50)) 4860Sstevel@tonic-gate sm_dprintf("milter_read(%s): Returning %*s\n", 4870Sstevel@tonic-gate m->mf_name, (int) expl, buf); 4880Sstevel@tonic-gate *rlen = expl; 4890Sstevel@tonic-gate return buf; 4900Sstevel@tonic-gate } 4910Sstevel@tonic-gate 4920Sstevel@tonic-gate /* 4930Sstevel@tonic-gate ** MILTER_WRITE -- write to a remote milter filter 4940Sstevel@tonic-gate ** 4950Sstevel@tonic-gate ** Parameters: 4960Sstevel@tonic-gate ** m -- milter to read from. 4970Sstevel@tonic-gate ** cmd -- command to send. 4980Sstevel@tonic-gate ** buf -- optional command data. 4990Sstevel@tonic-gate ** len -- length of buf. 5000Sstevel@tonic-gate ** to -- timeout in seconds. 5010Sstevel@tonic-gate ** e -- current envelope. 5020Sstevel@tonic-gate ** 5030Sstevel@tonic-gate ** Returns: 5040Sstevel@tonic-gate ** buf if successful, NULL otherwise 5050Sstevel@tonic-gate ** Not actually used anywhere but function prototype 5060Sstevel@tonic-gate ** must match milter_read() 5070Sstevel@tonic-gate */ 5080Sstevel@tonic-gate 5090Sstevel@tonic-gate static char * 5103544Sjbeck milter_write(m, cmd, buf, len, to, e, where) 5110Sstevel@tonic-gate struct milter *m; 5123544Sjbeck int cmd; 5130Sstevel@tonic-gate char *buf; 5140Sstevel@tonic-gate ssize_t len; 5150Sstevel@tonic-gate time_t to; 5160Sstevel@tonic-gate ENVELOPE *e; 5173544Sjbeck const char *where; 5180Sstevel@tonic-gate { 5190Sstevel@tonic-gate time_t writestart = (time_t) 0; 5200Sstevel@tonic-gate ssize_t sl, i; 5210Sstevel@tonic-gate int num_vectors; 5220Sstevel@tonic-gate mi_int32 nl; 5233544Sjbeck char command = (char) cmd; 5240Sstevel@tonic-gate char data[MILTER_LEN_BYTES + 1]; 5250Sstevel@tonic-gate bool started = false; 5260Sstevel@tonic-gate struct iovec vector[2]; 5270Sstevel@tonic-gate 5280Sstevel@tonic-gate /* 5290Sstevel@tonic-gate ** At most two buffers will be written, though 5300Sstevel@tonic-gate ** only one may actually be used (see num_vectors). 5310Sstevel@tonic-gate ** The first is the size/command and the second is the command data. 5320Sstevel@tonic-gate */ 5330Sstevel@tonic-gate 5340Sstevel@tonic-gate if (len < 0 || len > MilterMaxDataSize) 5350Sstevel@tonic-gate { 5360Sstevel@tonic-gate if (tTd(64, 5)) 5370Sstevel@tonic-gate sm_dprintf("milter_write(%s): length %ld out of range\n", 5380Sstevel@tonic-gate m->mf_name, (long) len); 5390Sstevel@tonic-gate if (MilterLogLevel > 0) 5400Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 5410Sstevel@tonic-gate "milter_write(%s): length %ld out of range", 5420Sstevel@tonic-gate m->mf_name, (long) len); 5430Sstevel@tonic-gate milter_error(m, e); 5440Sstevel@tonic-gate return NULL; 5450Sstevel@tonic-gate } 5460Sstevel@tonic-gate if (m->mf_sock < 0) 5470Sstevel@tonic-gate { 5480Sstevel@tonic-gate if (MilterLogLevel > 0) 5490Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 5500Sstevel@tonic-gate "milter_write(%s): socket closed", 5510Sstevel@tonic-gate m->mf_name); 5520Sstevel@tonic-gate milter_error(m, e); 5530Sstevel@tonic-gate return NULL; 5540Sstevel@tonic-gate } 5550Sstevel@tonic-gate 5560Sstevel@tonic-gate if (tTd(64, 20)) 5570Sstevel@tonic-gate sm_dprintf("milter_write(%s): cmd %c, len %ld\n", 5583544Sjbeck m->mf_name, command, (long) len); 5593544Sjbeck 5603544Sjbeck nl = htonl(len + 1); /* add 1 for the command char */ 5610Sstevel@tonic-gate (void) memcpy(data, (char *) &nl, MILTER_LEN_BYTES); 5623544Sjbeck data[MILTER_LEN_BYTES] = command; 5630Sstevel@tonic-gate sl = MILTER_LEN_BYTES + 1; 5640Sstevel@tonic-gate 5650Sstevel@tonic-gate /* set up the vector for the size / command */ 5660Sstevel@tonic-gate vector[0].iov_base = (void *) data; 5670Sstevel@tonic-gate vector[0].iov_len = sl; 5680Sstevel@tonic-gate 5690Sstevel@tonic-gate /* 5700Sstevel@tonic-gate ** Determine if there is command data. If so, there will be two 5710Sstevel@tonic-gate ** vectors. If not, there will be only one. The vectors are set 5720Sstevel@tonic-gate ** up here and 'num_vectors' and 'sl' are set appropriately. 5730Sstevel@tonic-gate */ 5740Sstevel@tonic-gate 5750Sstevel@tonic-gate /* NOTE: len<0 has already been checked for. Pedantic */ 5760Sstevel@tonic-gate if (len <= 0 || buf == NULL) 5770Sstevel@tonic-gate { 5780Sstevel@tonic-gate /* There is no command data -- only a size / command data */ 5790Sstevel@tonic-gate num_vectors = 1; 5800Sstevel@tonic-gate } 5810Sstevel@tonic-gate else 5820Sstevel@tonic-gate { 5830Sstevel@tonic-gate /* 5840Sstevel@tonic-gate ** There is both size / command and command data. 5850Sstevel@tonic-gate ** Set up the vector for the command data. 5860Sstevel@tonic-gate */ 5870Sstevel@tonic-gate 5880Sstevel@tonic-gate num_vectors = 2; 5890Sstevel@tonic-gate sl += len; 5900Sstevel@tonic-gate vector[1].iov_base = (void *) buf; 5910Sstevel@tonic-gate vector[1].iov_len = len; 5920Sstevel@tonic-gate 5930Sstevel@tonic-gate if (tTd(64, 50)) 5940Sstevel@tonic-gate sm_dprintf("milter_write(%s): Sending %*s\n", 5950Sstevel@tonic-gate m->mf_name, (int) len, buf); 5960Sstevel@tonic-gate } 5970Sstevel@tonic-gate 5980Sstevel@tonic-gate if (to > 0) 5990Sstevel@tonic-gate { 6000Sstevel@tonic-gate writestart = curtime(); 6013544Sjbeck MILTER_TIMEOUT("write", to, true, started, where); 6020Sstevel@tonic-gate } 6030Sstevel@tonic-gate 6040Sstevel@tonic-gate /* write the vector(s) */ 6050Sstevel@tonic-gate i = writev(m->mf_sock, vector, num_vectors); 6060Sstevel@tonic-gate if (i != sl) 6070Sstevel@tonic-gate { 6080Sstevel@tonic-gate int save_errno = errno; 6090Sstevel@tonic-gate 6100Sstevel@tonic-gate if (tTd(64, 5)) 6110Sstevel@tonic-gate sm_dprintf("milter_write(%s): write(%c) returned %ld, expected %ld: %s\n", 6123544Sjbeck m->mf_name, command, (long) i, (long) sl, 6130Sstevel@tonic-gate sm_errstring(save_errno)); 6140Sstevel@tonic-gate if (MilterLogLevel > 0) 6150Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 6160Sstevel@tonic-gate "Milter (%s): write(%c) returned %ld, expected %ld: %s", 6173544Sjbeck m->mf_name, command, (long) i, (long) sl, 6180Sstevel@tonic-gate sm_errstring(save_errno)); 6190Sstevel@tonic-gate milter_error(m, e); 6200Sstevel@tonic-gate return NULL; 6210Sstevel@tonic-gate } 6220Sstevel@tonic-gate return buf; 6230Sstevel@tonic-gate } 6240Sstevel@tonic-gate 6250Sstevel@tonic-gate /* 6260Sstevel@tonic-gate ** Utility functions 6270Sstevel@tonic-gate */ 6280Sstevel@tonic-gate 6290Sstevel@tonic-gate /* 6300Sstevel@tonic-gate ** MILTER_OPEN -- connect to remote milter filter 6310Sstevel@tonic-gate ** 6320Sstevel@tonic-gate ** Parameters: 6330Sstevel@tonic-gate ** m -- milter to connect to. 6340Sstevel@tonic-gate ** parseonly -- parse but don't connect. 6350Sstevel@tonic-gate ** e -- current envelope. 6360Sstevel@tonic-gate ** 6370Sstevel@tonic-gate ** Returns: 6380Sstevel@tonic-gate ** connected socket if successful && !parseonly, 6390Sstevel@tonic-gate ** 0 upon parse success if parseonly, 6400Sstevel@tonic-gate ** -1 otherwise. 6410Sstevel@tonic-gate */ 6420Sstevel@tonic-gate 6430Sstevel@tonic-gate static jmp_buf MilterConnectTimeout; 6440Sstevel@tonic-gate 6450Sstevel@tonic-gate static int 6460Sstevel@tonic-gate milter_open(m, parseonly, e) 6470Sstevel@tonic-gate struct milter *m; 6480Sstevel@tonic-gate bool parseonly; 6490Sstevel@tonic-gate ENVELOPE *e; 6500Sstevel@tonic-gate { 6510Sstevel@tonic-gate int sock = 0; 6520Sstevel@tonic-gate SOCKADDR_LEN_T addrlen = 0; 6530Sstevel@tonic-gate int addrno = 0; 6540Sstevel@tonic-gate int save_errno; 6550Sstevel@tonic-gate char *p; 6560Sstevel@tonic-gate char *colon; 6570Sstevel@tonic-gate char *at; 6580Sstevel@tonic-gate struct hostent *hp = NULL; 6590Sstevel@tonic-gate SOCKADDR addr; 6600Sstevel@tonic-gate 6610Sstevel@tonic-gate if (m->mf_conn == NULL || m->mf_conn[0] == '\0') 6620Sstevel@tonic-gate { 6630Sstevel@tonic-gate if (tTd(64, 5)) 6640Sstevel@tonic-gate sm_dprintf("X%s: empty or missing socket information\n", 6650Sstevel@tonic-gate m->mf_name); 6660Sstevel@tonic-gate if (parseonly) 6670Sstevel@tonic-gate syserr("X%s: empty or missing socket information", 6680Sstevel@tonic-gate m->mf_name); 6690Sstevel@tonic-gate else if (MilterLogLevel > 0) 6700Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 6710Sstevel@tonic-gate "Milter (%s): empty or missing socket information", 6720Sstevel@tonic-gate m->mf_name); 6730Sstevel@tonic-gate milter_error(m, e); 6740Sstevel@tonic-gate return -1; 6750Sstevel@tonic-gate } 6760Sstevel@tonic-gate 6770Sstevel@tonic-gate /* protocol:filename or protocol:port@host */ 6783544Sjbeck memset(&addr, '\0', sizeof(addr)); 6790Sstevel@tonic-gate p = m->mf_conn; 6800Sstevel@tonic-gate colon = strchr(p, ':'); 6810Sstevel@tonic-gate if (colon != NULL) 6820Sstevel@tonic-gate { 6830Sstevel@tonic-gate *colon = '\0'; 6840Sstevel@tonic-gate 6850Sstevel@tonic-gate if (*p == '\0') 6860Sstevel@tonic-gate { 6870Sstevel@tonic-gate # if NETUNIX 6880Sstevel@tonic-gate /* default to AF_UNIX */ 6890Sstevel@tonic-gate addr.sa.sa_family = AF_UNIX; 6900Sstevel@tonic-gate # else /* NETUNIX */ 6910Sstevel@tonic-gate # if NETINET 6920Sstevel@tonic-gate /* default to AF_INET */ 6930Sstevel@tonic-gate addr.sa.sa_family = AF_INET; 6940Sstevel@tonic-gate # else /* NETINET */ 6950Sstevel@tonic-gate # if NETINET6 6960Sstevel@tonic-gate /* default to AF_INET6 */ 6970Sstevel@tonic-gate addr.sa.sa_family = AF_INET6; 6980Sstevel@tonic-gate # else /* NETINET6 */ 6990Sstevel@tonic-gate /* no protocols available */ 7000Sstevel@tonic-gate if (MilterLogLevel > 0) 7010Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 7020Sstevel@tonic-gate "Milter (%s): no valid socket protocols available", 7030Sstevel@tonic-gate m->mf_name); 7040Sstevel@tonic-gate milter_error(m, e); 7050Sstevel@tonic-gate return -1; 7060Sstevel@tonic-gate # endif /* NETINET6 */ 7070Sstevel@tonic-gate # endif /* NETINET */ 7080Sstevel@tonic-gate # endif /* NETUNIX */ 7090Sstevel@tonic-gate } 7100Sstevel@tonic-gate # if NETUNIX 7110Sstevel@tonic-gate else if (sm_strcasecmp(p, "unix") == 0 || 7120Sstevel@tonic-gate sm_strcasecmp(p, "local") == 0) 7130Sstevel@tonic-gate addr.sa.sa_family = AF_UNIX; 7140Sstevel@tonic-gate # endif /* NETUNIX */ 7150Sstevel@tonic-gate # if NETINET 7160Sstevel@tonic-gate else if (sm_strcasecmp(p, "inet") == 0) 7170Sstevel@tonic-gate addr.sa.sa_family = AF_INET; 7180Sstevel@tonic-gate # endif /* NETINET */ 7190Sstevel@tonic-gate # if NETINET6 7200Sstevel@tonic-gate else if (sm_strcasecmp(p, "inet6") == 0) 7210Sstevel@tonic-gate addr.sa.sa_family = AF_INET6; 7220Sstevel@tonic-gate # endif /* NETINET6 */ 7230Sstevel@tonic-gate else 7240Sstevel@tonic-gate { 7250Sstevel@tonic-gate # ifdef EPROTONOSUPPORT 7260Sstevel@tonic-gate errno = EPROTONOSUPPORT; 7270Sstevel@tonic-gate # else /* EPROTONOSUPPORT */ 7280Sstevel@tonic-gate errno = EINVAL; 7290Sstevel@tonic-gate # endif /* EPROTONOSUPPORT */ 7300Sstevel@tonic-gate if (tTd(64, 5)) 7310Sstevel@tonic-gate sm_dprintf("X%s: unknown socket type %s\n", 7320Sstevel@tonic-gate m->mf_name, p); 7330Sstevel@tonic-gate if (parseonly) 7340Sstevel@tonic-gate syserr("X%s: unknown socket type %s", 7350Sstevel@tonic-gate m->mf_name, p); 7360Sstevel@tonic-gate else if (MilterLogLevel > 0) 7370Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 7380Sstevel@tonic-gate "Milter (%s): unknown socket type %s", 7390Sstevel@tonic-gate m->mf_name, p); 7400Sstevel@tonic-gate milter_error(m, e); 7410Sstevel@tonic-gate return -1; 7420Sstevel@tonic-gate } 7430Sstevel@tonic-gate *colon++ = ':'; 7440Sstevel@tonic-gate } 7450Sstevel@tonic-gate else 7460Sstevel@tonic-gate { 7470Sstevel@tonic-gate /* default to AF_UNIX */ 7480Sstevel@tonic-gate addr.sa.sa_family = AF_UNIX; 7490Sstevel@tonic-gate colon = p; 7500Sstevel@tonic-gate } 7510Sstevel@tonic-gate 7520Sstevel@tonic-gate # if NETUNIX 7530Sstevel@tonic-gate if (addr.sa.sa_family == AF_UNIX) 7540Sstevel@tonic-gate { 7550Sstevel@tonic-gate long sff = SFF_SAFEDIRPATH|SFF_OPENASROOT|SFF_NOLINK|SFF_EXECOK; 7560Sstevel@tonic-gate 7570Sstevel@tonic-gate at = colon; 7583544Sjbeck if (strlen(colon) >= sizeof(addr.sunix.sun_path)) 7590Sstevel@tonic-gate { 7600Sstevel@tonic-gate if (tTd(64, 5)) 7610Sstevel@tonic-gate sm_dprintf("X%s: local socket name %s too long\n", 7620Sstevel@tonic-gate m->mf_name, colon); 7630Sstevel@tonic-gate errno = EINVAL; 7640Sstevel@tonic-gate if (parseonly) 7650Sstevel@tonic-gate syserr("X%s: local socket name %s too long", 7660Sstevel@tonic-gate m->mf_name, colon); 7670Sstevel@tonic-gate else if (MilterLogLevel > 0) 7680Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 7690Sstevel@tonic-gate "Milter (%s): local socket name %s too long", 7700Sstevel@tonic-gate m->mf_name, colon); 7710Sstevel@tonic-gate milter_error(m, e); 7720Sstevel@tonic-gate return -1; 7730Sstevel@tonic-gate } 7740Sstevel@tonic-gate errno = safefile(colon, RunAsUid, RunAsGid, RunAsUserName, sff, 7750Sstevel@tonic-gate S_IRUSR|S_IWUSR, NULL); 7760Sstevel@tonic-gate 7770Sstevel@tonic-gate /* if just parsing .cf file, socket doesn't need to exist */ 7780Sstevel@tonic-gate if (parseonly && errno == ENOENT) 7790Sstevel@tonic-gate { 7800Sstevel@tonic-gate if (OpMode == MD_DAEMON || 7810Sstevel@tonic-gate OpMode == MD_FGDAEMON) 7820Sstevel@tonic-gate (void) sm_io_fprintf(smioerr, SM_TIME_DEFAULT, 7830Sstevel@tonic-gate "WARNING: X%s: local socket name %s missing\n", 7840Sstevel@tonic-gate m->mf_name, colon); 7850Sstevel@tonic-gate } 7860Sstevel@tonic-gate else if (errno != 0) 7870Sstevel@tonic-gate { 7880Sstevel@tonic-gate /* if not safe, don't create */ 7890Sstevel@tonic-gate save_errno = errno; 7900Sstevel@tonic-gate if (tTd(64, 5)) 7910Sstevel@tonic-gate sm_dprintf("X%s: local socket name %s unsafe\n", 7920Sstevel@tonic-gate m->mf_name, colon); 7930Sstevel@tonic-gate errno = save_errno; 7940Sstevel@tonic-gate if (parseonly) 7950Sstevel@tonic-gate { 7960Sstevel@tonic-gate if (OpMode == MD_DAEMON || 7970Sstevel@tonic-gate OpMode == MD_FGDAEMON || 7980Sstevel@tonic-gate OpMode == MD_SMTP) 7990Sstevel@tonic-gate syserr("X%s: local socket name %s unsafe", 8000Sstevel@tonic-gate m->mf_name, colon); 8010Sstevel@tonic-gate } 8020Sstevel@tonic-gate else if (MilterLogLevel > 0) 8030Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 8040Sstevel@tonic-gate "Milter (%s): local socket name %s unsafe", 8050Sstevel@tonic-gate m->mf_name, colon); 8060Sstevel@tonic-gate milter_error(m, e); 8070Sstevel@tonic-gate return -1; 8080Sstevel@tonic-gate } 8090Sstevel@tonic-gate 8100Sstevel@tonic-gate (void) sm_strlcpy(addr.sunix.sun_path, colon, 8113544Sjbeck sizeof(addr.sunix.sun_path)); 8123544Sjbeck addrlen = sizeof(struct sockaddr_un); 8130Sstevel@tonic-gate } 8140Sstevel@tonic-gate else 8150Sstevel@tonic-gate # endif /* NETUNIX */ 8160Sstevel@tonic-gate # if NETINET || NETINET6 8170Sstevel@tonic-gate if (false 8180Sstevel@tonic-gate # if NETINET 8190Sstevel@tonic-gate || addr.sa.sa_family == AF_INET 8200Sstevel@tonic-gate # endif /* NETINET */ 8210Sstevel@tonic-gate # if NETINET6 8220Sstevel@tonic-gate || addr.sa.sa_family == AF_INET6 8230Sstevel@tonic-gate # endif /* NETINET6 */ 8240Sstevel@tonic-gate ) 8250Sstevel@tonic-gate { 8260Sstevel@tonic-gate unsigned short port; 8270Sstevel@tonic-gate 8280Sstevel@tonic-gate /* Parse port@host */ 8290Sstevel@tonic-gate at = strchr(colon, '@'); 8300Sstevel@tonic-gate if (at == NULL) 8310Sstevel@tonic-gate { 8320Sstevel@tonic-gate if (tTd(64, 5)) 8330Sstevel@tonic-gate sm_dprintf("X%s: bad address %s (expected port@host)\n", 8340Sstevel@tonic-gate m->mf_name, colon); 8350Sstevel@tonic-gate if (parseonly) 8360Sstevel@tonic-gate syserr("X%s: bad address %s (expected port@host)", 8370Sstevel@tonic-gate m->mf_name, colon); 8380Sstevel@tonic-gate else if (MilterLogLevel > 0) 8390Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 8400Sstevel@tonic-gate "Milter (%s): bad address %s (expected port@host)", 8410Sstevel@tonic-gate m->mf_name, colon); 8420Sstevel@tonic-gate milter_error(m, e); 8430Sstevel@tonic-gate return -1; 8440Sstevel@tonic-gate } 8450Sstevel@tonic-gate *at = '\0'; 8460Sstevel@tonic-gate if (isascii(*colon) && isdigit(*colon)) 8470Sstevel@tonic-gate port = htons((unsigned short) atoi(colon)); 8480Sstevel@tonic-gate else 8490Sstevel@tonic-gate { 8500Sstevel@tonic-gate # ifdef NO_GETSERVBYNAME 8510Sstevel@tonic-gate if (tTd(64, 5)) 8520Sstevel@tonic-gate sm_dprintf("X%s: invalid port number %s\n", 8530Sstevel@tonic-gate m->mf_name, colon); 8540Sstevel@tonic-gate if (parseonly) 8550Sstevel@tonic-gate syserr("X%s: invalid port number %s", 8560Sstevel@tonic-gate m->mf_name, colon); 8570Sstevel@tonic-gate else if (MilterLogLevel > 0) 8580Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 8590Sstevel@tonic-gate "Milter (%s): invalid port number %s", 8600Sstevel@tonic-gate m->mf_name, colon); 8610Sstevel@tonic-gate milter_error(m, e); 8620Sstevel@tonic-gate return -1; 8630Sstevel@tonic-gate # else /* NO_GETSERVBYNAME */ 8643544Sjbeck struct servent *sp; 8650Sstevel@tonic-gate 8660Sstevel@tonic-gate sp = getservbyname(colon, "tcp"); 8670Sstevel@tonic-gate if (sp == NULL) 8680Sstevel@tonic-gate { 8690Sstevel@tonic-gate save_errno = errno; 8700Sstevel@tonic-gate if (tTd(64, 5)) 8710Sstevel@tonic-gate sm_dprintf("X%s: unknown port name %s\n", 8720Sstevel@tonic-gate m->mf_name, colon); 8730Sstevel@tonic-gate errno = save_errno; 8740Sstevel@tonic-gate if (parseonly) 8750Sstevel@tonic-gate syserr("X%s: unknown port name %s", 8760Sstevel@tonic-gate m->mf_name, colon); 8770Sstevel@tonic-gate else if (MilterLogLevel > 0) 8780Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 8790Sstevel@tonic-gate "Milter (%s): unknown port name %s", 8800Sstevel@tonic-gate m->mf_name, colon); 8810Sstevel@tonic-gate milter_error(m, e); 8820Sstevel@tonic-gate return -1; 8830Sstevel@tonic-gate } 8840Sstevel@tonic-gate port = sp->s_port; 8850Sstevel@tonic-gate # endif /* NO_GETSERVBYNAME */ 8860Sstevel@tonic-gate } 8870Sstevel@tonic-gate *at++ = '@'; 8880Sstevel@tonic-gate if (*at == '[') 8890Sstevel@tonic-gate { 8900Sstevel@tonic-gate char *end; 8910Sstevel@tonic-gate 8920Sstevel@tonic-gate end = strchr(at, ']'); 8930Sstevel@tonic-gate if (end != NULL) 8940Sstevel@tonic-gate { 8950Sstevel@tonic-gate bool found = false; 8960Sstevel@tonic-gate # if NETINET 8970Sstevel@tonic-gate unsigned long hid = INADDR_NONE; 8980Sstevel@tonic-gate # endif /* NETINET */ 8990Sstevel@tonic-gate # if NETINET6 9000Sstevel@tonic-gate struct sockaddr_in6 hid6; 9010Sstevel@tonic-gate # endif /* NETINET6 */ 9020Sstevel@tonic-gate 9030Sstevel@tonic-gate *end = '\0'; 9040Sstevel@tonic-gate # if NETINET 9050Sstevel@tonic-gate if (addr.sa.sa_family == AF_INET && 9060Sstevel@tonic-gate (hid = inet_addr(&at[1])) != INADDR_NONE) 9070Sstevel@tonic-gate { 9080Sstevel@tonic-gate addr.sin.sin_addr.s_addr = hid; 9090Sstevel@tonic-gate addr.sin.sin_port = port; 9100Sstevel@tonic-gate found = true; 9110Sstevel@tonic-gate } 9120Sstevel@tonic-gate # endif /* NETINET */ 9130Sstevel@tonic-gate # if NETINET6 9143544Sjbeck (void) memset(&hid6, '\0', sizeof(hid6)); 9150Sstevel@tonic-gate if (addr.sa.sa_family == AF_INET6 && 9160Sstevel@tonic-gate anynet_pton(AF_INET6, &at[1], 9170Sstevel@tonic-gate &hid6.sin6_addr) == 1) 9180Sstevel@tonic-gate { 9190Sstevel@tonic-gate addr.sin6.sin6_addr = hid6.sin6_addr; 9200Sstevel@tonic-gate addr.sin6.sin6_port = port; 9210Sstevel@tonic-gate found = true; 9220Sstevel@tonic-gate } 9230Sstevel@tonic-gate # endif /* NETINET6 */ 9240Sstevel@tonic-gate *end = ']'; 9250Sstevel@tonic-gate if (!found) 9260Sstevel@tonic-gate { 9270Sstevel@tonic-gate if (tTd(64, 5)) 9280Sstevel@tonic-gate sm_dprintf("X%s: Invalid numeric domain spec \"%s\"\n", 9290Sstevel@tonic-gate m->mf_name, at); 9300Sstevel@tonic-gate if (parseonly) 9310Sstevel@tonic-gate syserr("X%s: Invalid numeric domain spec \"%s\"", 9320Sstevel@tonic-gate m->mf_name, at); 9330Sstevel@tonic-gate else if (MilterLogLevel > 0) 9340Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 9350Sstevel@tonic-gate "Milter (%s): Invalid numeric domain spec \"%s\"", 9360Sstevel@tonic-gate m->mf_name, at); 9370Sstevel@tonic-gate milter_error(m, e); 9380Sstevel@tonic-gate return -1; 9390Sstevel@tonic-gate } 9400Sstevel@tonic-gate } 9410Sstevel@tonic-gate else 9420Sstevel@tonic-gate { 9430Sstevel@tonic-gate if (tTd(64, 5)) 9440Sstevel@tonic-gate sm_dprintf("X%s: Invalid numeric domain spec \"%s\"\n", 9450Sstevel@tonic-gate m->mf_name, at); 9460Sstevel@tonic-gate if (parseonly) 9470Sstevel@tonic-gate syserr("X%s: Invalid numeric domain spec \"%s\"", 9480Sstevel@tonic-gate m->mf_name, at); 9490Sstevel@tonic-gate else if (MilterLogLevel > 0) 9500Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 9510Sstevel@tonic-gate "Milter (%s): Invalid numeric domain spec \"%s\"", 9520Sstevel@tonic-gate m->mf_name, at); 9530Sstevel@tonic-gate milter_error(m, e); 9540Sstevel@tonic-gate return -1; 9550Sstevel@tonic-gate } 9560Sstevel@tonic-gate } 9570Sstevel@tonic-gate else 9580Sstevel@tonic-gate { 9590Sstevel@tonic-gate hp = sm_gethostbyname(at, addr.sa.sa_family); 9600Sstevel@tonic-gate if (hp == NULL) 9610Sstevel@tonic-gate { 9620Sstevel@tonic-gate save_errno = errno; 9630Sstevel@tonic-gate if (tTd(64, 5)) 9640Sstevel@tonic-gate sm_dprintf("X%s: Unknown host name %s\n", 9650Sstevel@tonic-gate m->mf_name, at); 9660Sstevel@tonic-gate errno = save_errno; 9670Sstevel@tonic-gate if (parseonly) 9680Sstevel@tonic-gate syserr("X%s: Unknown host name %s", 9690Sstevel@tonic-gate m->mf_name, at); 9700Sstevel@tonic-gate else if (MilterLogLevel > 0) 9710Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 9720Sstevel@tonic-gate "Milter (%s): Unknown host name %s", 9730Sstevel@tonic-gate m->mf_name, at); 9740Sstevel@tonic-gate milter_error(m, e); 9750Sstevel@tonic-gate return -1; 9760Sstevel@tonic-gate } 9770Sstevel@tonic-gate addr.sa.sa_family = hp->h_addrtype; 9780Sstevel@tonic-gate switch (hp->h_addrtype) 9790Sstevel@tonic-gate { 9800Sstevel@tonic-gate # if NETINET 9810Sstevel@tonic-gate case AF_INET: 9820Sstevel@tonic-gate memmove(&addr.sin.sin_addr, 9830Sstevel@tonic-gate hp->h_addr, INADDRSZ); 9840Sstevel@tonic-gate addr.sin.sin_port = port; 9853544Sjbeck addrlen = sizeof(struct sockaddr_in); 9860Sstevel@tonic-gate addrno = 1; 9870Sstevel@tonic-gate break; 9880Sstevel@tonic-gate # endif /* NETINET */ 9890Sstevel@tonic-gate 9900Sstevel@tonic-gate # if NETINET6 9910Sstevel@tonic-gate case AF_INET6: 9920Sstevel@tonic-gate memmove(&addr.sin6.sin6_addr, 9930Sstevel@tonic-gate hp->h_addr, IN6ADDRSZ); 9940Sstevel@tonic-gate addr.sin6.sin6_port = port; 9953544Sjbeck addrlen = sizeof(struct sockaddr_in6); 9960Sstevel@tonic-gate addrno = 1; 9970Sstevel@tonic-gate break; 9980Sstevel@tonic-gate # endif /* NETINET6 */ 9990Sstevel@tonic-gate 10000Sstevel@tonic-gate default: 10010Sstevel@tonic-gate if (tTd(64, 5)) 10020Sstevel@tonic-gate sm_dprintf("X%s: Unknown protocol for %s (%d)\n", 10030Sstevel@tonic-gate m->mf_name, at, 10040Sstevel@tonic-gate hp->h_addrtype); 10050Sstevel@tonic-gate if (parseonly) 10060Sstevel@tonic-gate syserr("X%s: Unknown protocol for %s (%d)", 10070Sstevel@tonic-gate m->mf_name, at, hp->h_addrtype); 10080Sstevel@tonic-gate else if (MilterLogLevel > 0) 10090Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 10100Sstevel@tonic-gate "Milter (%s): Unknown protocol for %s (%d)", 10110Sstevel@tonic-gate m->mf_name, at, 10120Sstevel@tonic-gate hp->h_addrtype); 10130Sstevel@tonic-gate milter_error(m, e); 10140Sstevel@tonic-gate # if NETINET6 10150Sstevel@tonic-gate freehostent(hp); 10160Sstevel@tonic-gate # endif /* NETINET6 */ 10170Sstevel@tonic-gate return -1; 10180Sstevel@tonic-gate } 10190Sstevel@tonic-gate } 10200Sstevel@tonic-gate } 10210Sstevel@tonic-gate else 10220Sstevel@tonic-gate # endif /* NETINET || NETINET6 */ 10230Sstevel@tonic-gate { 10240Sstevel@tonic-gate if (tTd(64, 5)) 10250Sstevel@tonic-gate sm_dprintf("X%s: unknown socket protocol\n", 10260Sstevel@tonic-gate m->mf_name); 10270Sstevel@tonic-gate if (parseonly) 10280Sstevel@tonic-gate syserr("X%s: unknown socket protocol", m->mf_name); 10290Sstevel@tonic-gate else if (MilterLogLevel > 0) 10300Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 10310Sstevel@tonic-gate "Milter (%s): unknown socket protocol", 10320Sstevel@tonic-gate m->mf_name); 10330Sstevel@tonic-gate milter_error(m, e); 10340Sstevel@tonic-gate return -1; 10350Sstevel@tonic-gate } 10360Sstevel@tonic-gate 10370Sstevel@tonic-gate /* just parsing through? */ 10380Sstevel@tonic-gate if (parseonly) 10390Sstevel@tonic-gate { 10400Sstevel@tonic-gate m->mf_state = SMFS_READY; 10410Sstevel@tonic-gate # if NETINET6 10420Sstevel@tonic-gate if (hp != NULL) 10430Sstevel@tonic-gate freehostent(hp); 10440Sstevel@tonic-gate # endif /* NETINET6 */ 10450Sstevel@tonic-gate return 0; 10460Sstevel@tonic-gate } 10470Sstevel@tonic-gate 10480Sstevel@tonic-gate /* sanity check */ 10490Sstevel@tonic-gate if (m->mf_state != SMFS_READY && 10500Sstevel@tonic-gate m->mf_state != SMFS_CLOSED) 10510Sstevel@tonic-gate { 10520Sstevel@tonic-gate /* shouldn't happen */ 10530Sstevel@tonic-gate if (tTd(64, 1)) 10540Sstevel@tonic-gate sm_dprintf("Milter (%s): Trying to open filter in state %c\n", 10550Sstevel@tonic-gate m->mf_name, (char) m->mf_state); 10560Sstevel@tonic-gate milter_error(m, e); 10570Sstevel@tonic-gate # if NETINET6 10580Sstevel@tonic-gate if (hp != NULL) 10590Sstevel@tonic-gate freehostent(hp); 10600Sstevel@tonic-gate # endif /* NETINET6 */ 10610Sstevel@tonic-gate return -1; 10620Sstevel@tonic-gate } 10630Sstevel@tonic-gate 10640Sstevel@tonic-gate /* nope, actually connecting */ 10650Sstevel@tonic-gate for (;;) 10660Sstevel@tonic-gate { 10670Sstevel@tonic-gate sock = socket(addr.sa.sa_family, SOCK_STREAM, 0); 10680Sstevel@tonic-gate if (sock < 0) 10690Sstevel@tonic-gate { 10700Sstevel@tonic-gate save_errno = errno; 10710Sstevel@tonic-gate if (tTd(64, 5)) 10720Sstevel@tonic-gate sm_dprintf("Milter (%s): error creating socket: %s\n", 10730Sstevel@tonic-gate m->mf_name, 10740Sstevel@tonic-gate sm_errstring(save_errno)); 10750Sstevel@tonic-gate if (MilterLogLevel > 0) 10760Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 10770Sstevel@tonic-gate "Milter (%s): error creating socket: %s", 10780Sstevel@tonic-gate m->mf_name, sm_errstring(save_errno)); 10790Sstevel@tonic-gate milter_error(m, e); 10800Sstevel@tonic-gate # if NETINET6 10810Sstevel@tonic-gate if (hp != NULL) 10820Sstevel@tonic-gate freehostent(hp); 10830Sstevel@tonic-gate # endif /* NETINET6 */ 10840Sstevel@tonic-gate return -1; 10850Sstevel@tonic-gate } 10860Sstevel@tonic-gate 10870Sstevel@tonic-gate if (setjmp(MilterConnectTimeout) == 0) 10880Sstevel@tonic-gate { 10890Sstevel@tonic-gate SM_EVENT *ev = NULL; 10900Sstevel@tonic-gate int i; 10910Sstevel@tonic-gate 10920Sstevel@tonic-gate if (m->mf_timeout[SMFTO_CONNECT] > 0) 10930Sstevel@tonic-gate ev = sm_setevent(m->mf_timeout[SMFTO_CONNECT], 10940Sstevel@tonic-gate milter_connect_timeout, 0); 10950Sstevel@tonic-gate 10960Sstevel@tonic-gate i = connect(sock, (struct sockaddr *) &addr, addrlen); 10970Sstevel@tonic-gate save_errno = errno; 10980Sstevel@tonic-gate if (ev != NULL) 10990Sstevel@tonic-gate sm_clrevent(ev); 11000Sstevel@tonic-gate errno = save_errno; 11010Sstevel@tonic-gate if (i >= 0) 11020Sstevel@tonic-gate break; 11030Sstevel@tonic-gate } 11040Sstevel@tonic-gate 11050Sstevel@tonic-gate /* couldn't connect.... try next address */ 11060Sstevel@tonic-gate save_errno = errno; 11070Sstevel@tonic-gate p = CurHostName; 11080Sstevel@tonic-gate CurHostName = at; 11090Sstevel@tonic-gate if (tTd(64, 5)) 11100Sstevel@tonic-gate sm_dprintf("milter_open (%s): open %s failed: %s\n", 11110Sstevel@tonic-gate m->mf_name, at, sm_errstring(save_errno)); 11120Sstevel@tonic-gate if (MilterLogLevel > 13) 11130Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 11140Sstevel@tonic-gate "Milter (%s): open %s failed: %s", 11150Sstevel@tonic-gate m->mf_name, at, sm_errstring(save_errno)); 11160Sstevel@tonic-gate CurHostName = p; 11170Sstevel@tonic-gate (void) close(sock); 11180Sstevel@tonic-gate 11190Sstevel@tonic-gate /* try next address */ 11200Sstevel@tonic-gate if (hp != NULL && hp->h_addr_list[addrno] != NULL) 11210Sstevel@tonic-gate { 11220Sstevel@tonic-gate switch (addr.sa.sa_family) 11230Sstevel@tonic-gate { 11240Sstevel@tonic-gate # if NETINET 11250Sstevel@tonic-gate case AF_INET: 11260Sstevel@tonic-gate memmove(&addr.sin.sin_addr, 11270Sstevel@tonic-gate hp->h_addr_list[addrno++], 11280Sstevel@tonic-gate INADDRSZ); 11290Sstevel@tonic-gate break; 11300Sstevel@tonic-gate # endif /* NETINET */ 11310Sstevel@tonic-gate 11320Sstevel@tonic-gate # if NETINET6 11330Sstevel@tonic-gate case AF_INET6: 11340Sstevel@tonic-gate memmove(&addr.sin6.sin6_addr, 11350Sstevel@tonic-gate hp->h_addr_list[addrno++], 11360Sstevel@tonic-gate IN6ADDRSZ); 11370Sstevel@tonic-gate break; 11380Sstevel@tonic-gate # endif /* NETINET6 */ 11390Sstevel@tonic-gate 11400Sstevel@tonic-gate default: 11410Sstevel@tonic-gate if (tTd(64, 5)) 11420Sstevel@tonic-gate sm_dprintf("X%s: Unknown protocol for %s (%d)\n", 11430Sstevel@tonic-gate m->mf_name, at, 11440Sstevel@tonic-gate hp->h_addrtype); 11450Sstevel@tonic-gate if (MilterLogLevel > 0) 11460Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 11470Sstevel@tonic-gate "Milter (%s): Unknown protocol for %s (%d)", 11480Sstevel@tonic-gate m->mf_name, at, 11490Sstevel@tonic-gate hp->h_addrtype); 11500Sstevel@tonic-gate milter_error(m, e); 11510Sstevel@tonic-gate # if NETINET6 11520Sstevel@tonic-gate freehostent(hp); 11530Sstevel@tonic-gate # endif /* NETINET6 */ 11540Sstevel@tonic-gate return -1; 11550Sstevel@tonic-gate } 11560Sstevel@tonic-gate continue; 11570Sstevel@tonic-gate } 11580Sstevel@tonic-gate p = CurHostName; 11590Sstevel@tonic-gate CurHostName = at; 11600Sstevel@tonic-gate if (tTd(64, 5)) 11610Sstevel@tonic-gate sm_dprintf("X%s: error connecting to filter: %s\n", 11620Sstevel@tonic-gate m->mf_name, sm_errstring(save_errno)); 11630Sstevel@tonic-gate if (MilterLogLevel > 0) 11640Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 11650Sstevel@tonic-gate "Milter (%s): error connecting to filter: %s", 11660Sstevel@tonic-gate m->mf_name, sm_errstring(save_errno)); 11670Sstevel@tonic-gate CurHostName = p; 11680Sstevel@tonic-gate milter_error(m, e); 11690Sstevel@tonic-gate # if NETINET6 11700Sstevel@tonic-gate if (hp != NULL) 11710Sstevel@tonic-gate freehostent(hp); 11720Sstevel@tonic-gate # endif /* NETINET6 */ 11730Sstevel@tonic-gate return -1; 11740Sstevel@tonic-gate } 11750Sstevel@tonic-gate m->mf_state = SMFS_OPEN; 11760Sstevel@tonic-gate # if NETINET6 11770Sstevel@tonic-gate if (hp != NULL) 11780Sstevel@tonic-gate { 11790Sstevel@tonic-gate freehostent(hp); 11800Sstevel@tonic-gate hp = NULL; 11810Sstevel@tonic-gate } 11820Sstevel@tonic-gate # endif /* NETINET6 */ 11833544Sjbeck # if MILTER_NO_NAGLE && !defined(TCP_CORK) 11840Sstevel@tonic-gate { 11850Sstevel@tonic-gate int nodelay = 1; 11860Sstevel@tonic-gate 11870Sstevel@tonic-gate setsockopt(m->mf_sock, IPPROTO_TCP, TCP_NODELAY, 11880Sstevel@tonic-gate (char *)&nodelay, sizeof(nodelay)); 11890Sstevel@tonic-gate } 11903544Sjbeck # endif /* MILTER_NO_NAGLE && !defined(TCP_CORK) */ 11910Sstevel@tonic-gate return sock; 11920Sstevel@tonic-gate } 11930Sstevel@tonic-gate 11940Sstevel@tonic-gate static void 11950Sstevel@tonic-gate milter_connect_timeout(ignore) 11960Sstevel@tonic-gate int ignore; 11970Sstevel@tonic-gate { 11980Sstevel@tonic-gate /* 11990Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 12000Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 12010Sstevel@tonic-gate ** DOING. 12020Sstevel@tonic-gate */ 12030Sstevel@tonic-gate 12040Sstevel@tonic-gate errno = ETIMEDOUT; 12050Sstevel@tonic-gate longjmp(MilterConnectTimeout, 1); 12060Sstevel@tonic-gate } 12073544Sjbeck 12080Sstevel@tonic-gate /* 12090Sstevel@tonic-gate ** MILTER_SETUP -- setup structure for a mail filter 12100Sstevel@tonic-gate ** 12110Sstevel@tonic-gate ** Parameters: 12120Sstevel@tonic-gate ** line -- the options line. 12130Sstevel@tonic-gate ** 12140Sstevel@tonic-gate ** Returns: 12150Sstevel@tonic-gate ** none 12160Sstevel@tonic-gate */ 12170Sstevel@tonic-gate 12180Sstevel@tonic-gate void 12190Sstevel@tonic-gate milter_setup(line) 12200Sstevel@tonic-gate char *line; 12210Sstevel@tonic-gate { 12220Sstevel@tonic-gate char fcode; 12233544Sjbeck char *p; 12243544Sjbeck struct milter *m; 12250Sstevel@tonic-gate STAB *s; 12260Sstevel@tonic-gate 12270Sstevel@tonic-gate /* collect the filter name */ 12280Sstevel@tonic-gate for (p = line; 12290Sstevel@tonic-gate *p != '\0' && *p != ',' && !(isascii(*p) && isspace(*p)); 12300Sstevel@tonic-gate p++) 12310Sstevel@tonic-gate continue; 12320Sstevel@tonic-gate if (*p != '\0') 12330Sstevel@tonic-gate *p++ = '\0'; 12340Sstevel@tonic-gate if (line[0] == '\0') 12350Sstevel@tonic-gate { 12360Sstevel@tonic-gate syserr("name required for mail filter"); 12370Sstevel@tonic-gate return; 12380Sstevel@tonic-gate } 12393544Sjbeck m = (struct milter *) xalloc(sizeof(*m)); 12403544Sjbeck memset((char *) m, '\0', sizeof(*m)); 12410Sstevel@tonic-gate m->mf_name = newstr(line); 12420Sstevel@tonic-gate m->mf_state = SMFS_READY; 12430Sstevel@tonic-gate m->mf_sock = -1; 12440Sstevel@tonic-gate m->mf_timeout[SMFTO_CONNECT] = (time_t) 300; 12450Sstevel@tonic-gate m->mf_timeout[SMFTO_WRITE] = (time_t) 10; 12460Sstevel@tonic-gate m->mf_timeout[SMFTO_READ] = (time_t) 10; 12470Sstevel@tonic-gate m->mf_timeout[SMFTO_EOM] = (time_t) 300; 12483966Sjbeck #if _FFR_MILTER_CHECK 12493544Sjbeck m->mf_mta_prot_version = SMFI_PROT_VERSION; 12503544Sjbeck m->mf_mta_prot_flags = SMFI_CURR_PROT; 12513544Sjbeck m->mf_mta_actions = SMFI_CURR_ACTS; 12523966Sjbeck #endif /* _FFR_MILTER_CHECK */ 12530Sstevel@tonic-gate 12540Sstevel@tonic-gate /* now scan through and assign info from the fields */ 12550Sstevel@tonic-gate while (*p != '\0') 12560Sstevel@tonic-gate { 12570Sstevel@tonic-gate char *delimptr; 12580Sstevel@tonic-gate 12590Sstevel@tonic-gate while (*p != '\0' && 12600Sstevel@tonic-gate (*p == ',' || (isascii(*p) && isspace(*p)))) 12610Sstevel@tonic-gate p++; 12620Sstevel@tonic-gate 12630Sstevel@tonic-gate /* p now points to field code */ 12640Sstevel@tonic-gate fcode = *p; 12650Sstevel@tonic-gate while (*p != '\0' && *p != '=' && *p != ',') 12660Sstevel@tonic-gate p++; 12670Sstevel@tonic-gate if (*p++ != '=') 12680Sstevel@tonic-gate { 12690Sstevel@tonic-gate syserr("X%s: `=' expected", m->mf_name); 12700Sstevel@tonic-gate return; 12710Sstevel@tonic-gate } 12720Sstevel@tonic-gate while (isascii(*p) && isspace(*p)) 12730Sstevel@tonic-gate p++; 12740Sstevel@tonic-gate 12750Sstevel@tonic-gate /* p now points to the field body */ 12760Sstevel@tonic-gate p = munchstring(p, &delimptr, ','); 12770Sstevel@tonic-gate 12780Sstevel@tonic-gate /* install the field into the filter struct */ 12790Sstevel@tonic-gate switch (fcode) 12800Sstevel@tonic-gate { 12810Sstevel@tonic-gate case 'S': /* socket */ 12820Sstevel@tonic-gate if (p == NULL) 12830Sstevel@tonic-gate m->mf_conn = NULL; 12840Sstevel@tonic-gate else 12850Sstevel@tonic-gate m->mf_conn = newstr(p); 12860Sstevel@tonic-gate break; 12870Sstevel@tonic-gate 12880Sstevel@tonic-gate case 'F': /* Milter flags configured on MTA */ 12890Sstevel@tonic-gate for (; *p != '\0'; p++) 12900Sstevel@tonic-gate { 12910Sstevel@tonic-gate if (!(isascii(*p) && isspace(*p))) 12920Sstevel@tonic-gate setbitn(bitidx(*p), m->mf_flags); 12930Sstevel@tonic-gate } 12940Sstevel@tonic-gate break; 12950Sstevel@tonic-gate 12960Sstevel@tonic-gate case 'T': /* timeouts */ 12970Sstevel@tonic-gate milter_parse_timeouts(p, m); 12980Sstevel@tonic-gate break; 12990Sstevel@tonic-gate 13003966Sjbeck #if _FFR_MILTER_CHECK 13013544Sjbeck case 'a': 13023544Sjbeck m->mf_mta_actions = strtoul(p, NULL, 0); 13033544Sjbeck break; 13043544Sjbeck case 'f': 13053544Sjbeck m->mf_mta_prot_flags = strtoul(p, NULL, 0); 13063544Sjbeck break; 13073544Sjbeck case 'v': 13083544Sjbeck m->mf_mta_prot_version = strtoul(p, NULL, 0); 13093544Sjbeck break; 13103966Sjbeck #endif /* _FFR_MILTER_CHECK */ 13113544Sjbeck 13120Sstevel@tonic-gate default: 13130Sstevel@tonic-gate syserr("X%s: unknown filter equate %c=", 13140Sstevel@tonic-gate m->mf_name, fcode); 13150Sstevel@tonic-gate break; 13160Sstevel@tonic-gate } 13170Sstevel@tonic-gate p = delimptr; 13180Sstevel@tonic-gate } 13190Sstevel@tonic-gate 13200Sstevel@tonic-gate /* early check for errors */ 13210Sstevel@tonic-gate (void) milter_open(m, true, CurEnv); 13220Sstevel@tonic-gate 13230Sstevel@tonic-gate /* enter the filter into the symbol table */ 13240Sstevel@tonic-gate s = stab(m->mf_name, ST_MILTER, ST_ENTER); 13250Sstevel@tonic-gate if (s->s_milter != NULL) 13260Sstevel@tonic-gate syserr("X%s: duplicate filter definition", m->mf_name); 13270Sstevel@tonic-gate else 13280Sstevel@tonic-gate s->s_milter = m; 13290Sstevel@tonic-gate } 13303544Sjbeck 13310Sstevel@tonic-gate /* 13320Sstevel@tonic-gate ** MILTER_CONFIG -- parse option list into an array and check config 13330Sstevel@tonic-gate ** 13340Sstevel@tonic-gate ** Called when reading configuration file. 13350Sstevel@tonic-gate ** 13360Sstevel@tonic-gate ** Parameters: 13370Sstevel@tonic-gate ** spec -- the filter list. 13380Sstevel@tonic-gate ** list -- the array to fill in. 13390Sstevel@tonic-gate ** max -- the maximum number of entries in list. 13400Sstevel@tonic-gate ** 13410Sstevel@tonic-gate ** Returns: 13420Sstevel@tonic-gate ** none 13430Sstevel@tonic-gate */ 13440Sstevel@tonic-gate 13450Sstevel@tonic-gate void 13460Sstevel@tonic-gate milter_config(spec, list, max) 13470Sstevel@tonic-gate char *spec; 13480Sstevel@tonic-gate struct milter **list; 13490Sstevel@tonic-gate int max; 13500Sstevel@tonic-gate { 13510Sstevel@tonic-gate int numitems = 0; 13523544Sjbeck char *p; 13530Sstevel@tonic-gate 13540Sstevel@tonic-gate /* leave one for the NULL signifying the end of the list */ 13550Sstevel@tonic-gate max--; 13560Sstevel@tonic-gate 13570Sstevel@tonic-gate for (p = spec; p != NULL; ) 13580Sstevel@tonic-gate { 13590Sstevel@tonic-gate STAB *s; 13600Sstevel@tonic-gate 13610Sstevel@tonic-gate while (isascii(*p) && isspace(*p)) 13620Sstevel@tonic-gate p++; 13630Sstevel@tonic-gate if (*p == '\0') 13640Sstevel@tonic-gate break; 13650Sstevel@tonic-gate spec = p; 13660Sstevel@tonic-gate 13670Sstevel@tonic-gate if (numitems >= max) 13680Sstevel@tonic-gate { 13690Sstevel@tonic-gate syserr("Too many filters defined, %d max", max); 13700Sstevel@tonic-gate if (max > 0) 13710Sstevel@tonic-gate list[0] = NULL; 13720Sstevel@tonic-gate return; 13730Sstevel@tonic-gate } 13740Sstevel@tonic-gate p = strpbrk(p, ";,"); 13750Sstevel@tonic-gate if (p != NULL) 13760Sstevel@tonic-gate *p++ = '\0'; 13770Sstevel@tonic-gate 13780Sstevel@tonic-gate s = stab(spec, ST_MILTER, ST_FIND); 13790Sstevel@tonic-gate if (s == NULL) 13800Sstevel@tonic-gate { 13810Sstevel@tonic-gate syserr("InputFilter %s not defined", spec); 13820Sstevel@tonic-gate ExitStat = EX_CONFIG; 13830Sstevel@tonic-gate return; 13840Sstevel@tonic-gate } 13850Sstevel@tonic-gate list[numitems++] = s->s_milter; 13860Sstevel@tonic-gate } 13870Sstevel@tonic-gate list[numitems] = NULL; 13880Sstevel@tonic-gate 13890Sstevel@tonic-gate /* if not set, set to LogLevel */ 13900Sstevel@tonic-gate if (MilterLogLevel == -1) 13910Sstevel@tonic-gate MilterLogLevel = LogLevel; 13920Sstevel@tonic-gate } 13933544Sjbeck 13940Sstevel@tonic-gate /* 13950Sstevel@tonic-gate ** MILTER_PARSE_TIMEOUTS -- parse timeout list 13960Sstevel@tonic-gate ** 13970Sstevel@tonic-gate ** Called when reading configuration file. 13980Sstevel@tonic-gate ** 13990Sstevel@tonic-gate ** Parameters: 14000Sstevel@tonic-gate ** spec -- the timeout list. 14010Sstevel@tonic-gate ** m -- milter to set. 14020Sstevel@tonic-gate ** 14030Sstevel@tonic-gate ** Returns: 14040Sstevel@tonic-gate ** none 14050Sstevel@tonic-gate */ 14060Sstevel@tonic-gate 14070Sstevel@tonic-gate static void 14080Sstevel@tonic-gate milter_parse_timeouts(spec, m) 14090Sstevel@tonic-gate char *spec; 14100Sstevel@tonic-gate struct milter *m; 14110Sstevel@tonic-gate { 14120Sstevel@tonic-gate char fcode; 14130Sstevel@tonic-gate int tcode; 14143544Sjbeck char *p; 14150Sstevel@tonic-gate 14160Sstevel@tonic-gate p = spec; 14170Sstevel@tonic-gate 14180Sstevel@tonic-gate /* now scan through and assign info from the fields */ 14190Sstevel@tonic-gate while (*p != '\0') 14200Sstevel@tonic-gate { 14210Sstevel@tonic-gate char *delimptr; 14220Sstevel@tonic-gate 14230Sstevel@tonic-gate while (*p != '\0' && 14240Sstevel@tonic-gate (*p == ';' || (isascii(*p) && isspace(*p)))) 14250Sstevel@tonic-gate p++; 14260Sstevel@tonic-gate 14270Sstevel@tonic-gate /* p now points to field code */ 14280Sstevel@tonic-gate fcode = *p; 14290Sstevel@tonic-gate while (*p != '\0' && *p != ':') 14300Sstevel@tonic-gate p++; 14310Sstevel@tonic-gate if (*p++ != ':') 14320Sstevel@tonic-gate { 14330Sstevel@tonic-gate syserr("X%s, T=: `:' expected", m->mf_name); 14340Sstevel@tonic-gate return; 14350Sstevel@tonic-gate } 14360Sstevel@tonic-gate while (isascii(*p) && isspace(*p)) 14370Sstevel@tonic-gate p++; 14380Sstevel@tonic-gate 14390Sstevel@tonic-gate /* p now points to the field body */ 14400Sstevel@tonic-gate p = munchstring(p, &delimptr, ';'); 14410Sstevel@tonic-gate tcode = -1; 14420Sstevel@tonic-gate 14430Sstevel@tonic-gate /* install the field into the filter struct */ 14440Sstevel@tonic-gate switch (fcode) 14450Sstevel@tonic-gate { 14460Sstevel@tonic-gate case 'C': 14470Sstevel@tonic-gate tcode = SMFTO_CONNECT; 14480Sstevel@tonic-gate break; 14490Sstevel@tonic-gate 14500Sstevel@tonic-gate case 'S': 14510Sstevel@tonic-gate tcode = SMFTO_WRITE; 14520Sstevel@tonic-gate break; 14530Sstevel@tonic-gate 14540Sstevel@tonic-gate case 'R': 14550Sstevel@tonic-gate tcode = SMFTO_READ; 14560Sstevel@tonic-gate break; 14570Sstevel@tonic-gate 14580Sstevel@tonic-gate case 'E': 14590Sstevel@tonic-gate tcode = SMFTO_EOM; 14600Sstevel@tonic-gate break; 14610Sstevel@tonic-gate 14620Sstevel@tonic-gate default: 14630Sstevel@tonic-gate if (tTd(64, 5)) 14640Sstevel@tonic-gate sm_dprintf("X%s: %c unknown\n", 14650Sstevel@tonic-gate m->mf_name, fcode); 14660Sstevel@tonic-gate syserr("X%s: unknown filter timeout %c", 14670Sstevel@tonic-gate m->mf_name, fcode); 14680Sstevel@tonic-gate break; 14690Sstevel@tonic-gate } 14700Sstevel@tonic-gate if (tcode >= 0) 14710Sstevel@tonic-gate { 14720Sstevel@tonic-gate m->mf_timeout[tcode] = convtime(p, 's'); 14730Sstevel@tonic-gate if (tTd(64, 5)) 14740Sstevel@tonic-gate sm_dprintf("X%s: %c=%ld\n", 14750Sstevel@tonic-gate m->mf_name, fcode, 14760Sstevel@tonic-gate (u_long) m->mf_timeout[tcode]); 14770Sstevel@tonic-gate } 14780Sstevel@tonic-gate p = delimptr; 14790Sstevel@tonic-gate } 14800Sstevel@tonic-gate } 14813544Sjbeck 14823544Sjbeck /* 14833544Sjbeck ** MILTER_SET_MACROS -- set milter macros 14843544Sjbeck ** 14853544Sjbeck ** Parameters: 14863544Sjbeck ** name -- name of milter. 14873544Sjbeck ** macros -- where to store macros. 14883544Sjbeck ** val -- the value of the option. 14893544Sjbeck ** nummac -- current number of macros 14903544Sjbeck ** 14913544Sjbeck ** Returns: 14923544Sjbeck ** new number of macros 14933544Sjbeck */ 14943544Sjbeck 14953544Sjbeck static int 14963544Sjbeck milter_set_macros(name, macros, val, nummac) 14973544Sjbeck char *name; 14983544Sjbeck char **macros; 14993544Sjbeck char *val; 15003544Sjbeck int nummac; 15013544Sjbeck { 15023544Sjbeck char *p; 15033544Sjbeck 15043544Sjbeck p = newstr(val); 15053544Sjbeck while (*p != '\0') 15063544Sjbeck { 15073544Sjbeck char *macro; 15083544Sjbeck 15093544Sjbeck /* Skip leading commas, spaces */ 15103544Sjbeck while (*p != '\0' && 15113544Sjbeck (*p == ',' || (isascii(*p) && isspace(*p)))) 15123544Sjbeck p++; 15133544Sjbeck 15143544Sjbeck if (*p == '\0') 15153544Sjbeck break; 15163544Sjbeck 15173544Sjbeck /* Find end of macro */ 15183544Sjbeck macro = p; 15193544Sjbeck while (*p != '\0' && *p != ',' && 15203544Sjbeck isascii(*p) && !isspace(*p)) 15213544Sjbeck p++; 15223544Sjbeck if (*p != '\0') 15233544Sjbeck *p++ = '\0'; 15243544Sjbeck 15253544Sjbeck if (nummac >= MAXFILTERMACROS) 15263544Sjbeck { 15273544Sjbeck syserr("milter_set_option: too many macros in Milter.%s (max %d)", 15283544Sjbeck name, MAXFILTERMACROS); 15293544Sjbeck macros[nummac] = NULL; 15303544Sjbeck return -1; 15313544Sjbeck } 15323544Sjbeck macros[nummac++] = macro; 15333544Sjbeck } 15343544Sjbeck macros[nummac] = NULL; 15353544Sjbeck return nummac; 15363544Sjbeck } 15373544Sjbeck 15380Sstevel@tonic-gate /* 15390Sstevel@tonic-gate ** MILTER_SET_OPTION -- set an individual milter option 15400Sstevel@tonic-gate ** 15410Sstevel@tonic-gate ** Parameters: 15420Sstevel@tonic-gate ** name -- the name of the option. 15430Sstevel@tonic-gate ** val -- the value of the option. 15440Sstevel@tonic-gate ** sticky -- if set, don't let other setoptions override 15450Sstevel@tonic-gate ** this value. 15460Sstevel@tonic-gate ** 15470Sstevel@tonic-gate ** Returns: 15480Sstevel@tonic-gate ** none. 15490Sstevel@tonic-gate */ 15500Sstevel@tonic-gate 15510Sstevel@tonic-gate /* set if Milter sub-option is stuck */ 15520Sstevel@tonic-gate static BITMAP256 StickyMilterOpt; 15530Sstevel@tonic-gate 15540Sstevel@tonic-gate static struct milteropt 15550Sstevel@tonic-gate { 15560Sstevel@tonic-gate char *mo_name; /* long name of milter option */ 15570Sstevel@tonic-gate unsigned char mo_code; /* code for option */ 15580Sstevel@tonic-gate } MilterOptTab[] = 15590Sstevel@tonic-gate { 15603544Sjbeck # define MO_MACROS_CONNECT SMFIM_CONNECT 15610Sstevel@tonic-gate { "macros.connect", MO_MACROS_CONNECT }, 15623544Sjbeck # define MO_MACROS_HELO SMFIM_HELO 15630Sstevel@tonic-gate { "macros.helo", MO_MACROS_HELO }, 15643544Sjbeck # define MO_MACROS_ENVFROM SMFIM_ENVFROM 15650Sstevel@tonic-gate { "macros.envfrom", MO_MACROS_ENVFROM }, 15663544Sjbeck # define MO_MACROS_ENVRCPT SMFIM_ENVRCPT 15670Sstevel@tonic-gate { "macros.envrcpt", MO_MACROS_ENVRCPT }, 15683544Sjbeck # define MO_MACROS_DATA SMFIM_DATA 15690Sstevel@tonic-gate { "macros.data", MO_MACROS_DATA }, 15703544Sjbeck # define MO_MACROS_EOM SMFIM_EOM 15710Sstevel@tonic-gate { "macros.eom", MO_MACROS_EOM }, 15723544Sjbeck # define MO_MACROS_EOH SMFIM_EOH 15733544Sjbeck { "macros.eoh", MO_MACROS_EOH }, 15743544Sjbeck 15750Sstevel@tonic-gate # define MO_LOGLEVEL 0x07 15760Sstevel@tonic-gate { "loglevel", MO_LOGLEVEL }, 15770Sstevel@tonic-gate # if _FFR_MAXDATASIZE 15783544Sjbeck # define MO_MAXDATASIZE 0x08 15790Sstevel@tonic-gate { "maxdatasize", MO_MAXDATASIZE }, 15800Sstevel@tonic-gate # endif /* _FFR_MAXDATASIZE */ 15813544Sjbeck { NULL, (unsigned char)-1 }, 15820Sstevel@tonic-gate }; 15830Sstevel@tonic-gate 15840Sstevel@tonic-gate void 15850Sstevel@tonic-gate milter_set_option(name, val, sticky) 15860Sstevel@tonic-gate char *name; 15870Sstevel@tonic-gate char *val; 15880Sstevel@tonic-gate bool sticky; 15890Sstevel@tonic-gate { 15903544Sjbeck int nummac, r; 15913544Sjbeck struct milteropt *mo; 15920Sstevel@tonic-gate char **macros = NULL; 15930Sstevel@tonic-gate 15943544Sjbeck nummac = 0; 15950Sstevel@tonic-gate if (tTd(37, 2) || tTd(64, 5)) 15960Sstevel@tonic-gate sm_dprintf("milter_set_option(%s = %s)", name, val); 15970Sstevel@tonic-gate 15980Sstevel@tonic-gate if (name == NULL) 15990Sstevel@tonic-gate { 16000Sstevel@tonic-gate syserr("milter_set_option: invalid Milter option, must specify suboption"); 16010Sstevel@tonic-gate return; 16020Sstevel@tonic-gate } 16030Sstevel@tonic-gate 16040Sstevel@tonic-gate for (mo = MilterOptTab; mo->mo_name != NULL; mo++) 16050Sstevel@tonic-gate { 16060Sstevel@tonic-gate if (sm_strcasecmp(mo->mo_name, name) == 0) 16070Sstevel@tonic-gate break; 16080Sstevel@tonic-gate } 16090Sstevel@tonic-gate 16100Sstevel@tonic-gate if (mo->mo_name == NULL) 16110Sstevel@tonic-gate { 16120Sstevel@tonic-gate syserr("milter_set_option: invalid Milter option %s", name); 16130Sstevel@tonic-gate return; 16140Sstevel@tonic-gate } 16150Sstevel@tonic-gate 16160Sstevel@tonic-gate /* 16170Sstevel@tonic-gate ** See if this option is preset for us. 16180Sstevel@tonic-gate */ 16190Sstevel@tonic-gate 16200Sstevel@tonic-gate if (!sticky && bitnset(mo->mo_code, StickyMilterOpt)) 16210Sstevel@tonic-gate { 16220Sstevel@tonic-gate if (tTd(37, 2) || tTd(64,5)) 16230Sstevel@tonic-gate sm_dprintf(" (ignored)\n"); 16240Sstevel@tonic-gate return; 16250Sstevel@tonic-gate } 16260Sstevel@tonic-gate 16270Sstevel@tonic-gate if (tTd(37, 2) || tTd(64,5)) 16280Sstevel@tonic-gate sm_dprintf("\n"); 16290Sstevel@tonic-gate 16300Sstevel@tonic-gate switch (mo->mo_code) 16310Sstevel@tonic-gate { 16320Sstevel@tonic-gate case MO_LOGLEVEL: 16330Sstevel@tonic-gate MilterLogLevel = atoi(val); 16340Sstevel@tonic-gate break; 16350Sstevel@tonic-gate 16360Sstevel@tonic-gate #if _FFR_MAXDATASIZE 16370Sstevel@tonic-gate case MO_MAXDATASIZE: 16380Sstevel@tonic-gate MilterMaxDataSize = (size_t)atol(val); 16390Sstevel@tonic-gate break; 16400Sstevel@tonic-gate #endif /* _FFR_MAXDATASIZE */ 16410Sstevel@tonic-gate 16420Sstevel@tonic-gate case MO_MACROS_CONNECT: 16430Sstevel@tonic-gate if (macros == NULL) 16440Sstevel@tonic-gate macros = MilterConnectMacros; 16450Sstevel@tonic-gate /* FALLTHROUGH */ 16460Sstevel@tonic-gate 16470Sstevel@tonic-gate case MO_MACROS_HELO: 16480Sstevel@tonic-gate if (macros == NULL) 16490Sstevel@tonic-gate macros = MilterHeloMacros; 16500Sstevel@tonic-gate /* FALLTHROUGH */ 16510Sstevel@tonic-gate 16520Sstevel@tonic-gate case MO_MACROS_ENVFROM: 16530Sstevel@tonic-gate if (macros == NULL) 16540Sstevel@tonic-gate macros = MilterEnvFromMacros; 16550Sstevel@tonic-gate /* FALLTHROUGH */ 16560Sstevel@tonic-gate 16570Sstevel@tonic-gate case MO_MACROS_ENVRCPT: 16580Sstevel@tonic-gate if (macros == NULL) 16590Sstevel@tonic-gate macros = MilterEnvRcptMacros; 16600Sstevel@tonic-gate /* FALLTHROUGH */ 16610Sstevel@tonic-gate 16623544Sjbeck case MO_MACROS_EOH: 16633544Sjbeck if (macros == NULL) 16643544Sjbeck macros = MilterEOHMacros; 16653544Sjbeck /* FALLTHROUGH */ 16663544Sjbeck 16670Sstevel@tonic-gate case MO_MACROS_EOM: 16680Sstevel@tonic-gate if (macros == NULL) 16690Sstevel@tonic-gate macros = MilterEOMMacros; 16700Sstevel@tonic-gate /* FALLTHROUGH */ 16710Sstevel@tonic-gate 16720Sstevel@tonic-gate case MO_MACROS_DATA: 16730Sstevel@tonic-gate if (macros == NULL) 16740Sstevel@tonic-gate macros = MilterDataMacros; 16750Sstevel@tonic-gate 16763544Sjbeck r = milter_set_macros(name, macros, val, nummac); 16773544Sjbeck if (r >= 0) 16783544Sjbeck nummac = r; 16790Sstevel@tonic-gate break; 16800Sstevel@tonic-gate 16810Sstevel@tonic-gate default: 16820Sstevel@tonic-gate syserr("milter_set_option: invalid Milter option %s", name); 16830Sstevel@tonic-gate break; 16840Sstevel@tonic-gate } 16850Sstevel@tonic-gate if (sticky) 16860Sstevel@tonic-gate setbitn(mo->mo_code, StickyMilterOpt); 16870Sstevel@tonic-gate } 16883544Sjbeck 16890Sstevel@tonic-gate /* 16900Sstevel@tonic-gate ** MILTER_REOPEN_DF -- open & truncate the data file (for replbody) 16910Sstevel@tonic-gate ** 16920Sstevel@tonic-gate ** Parameters: 16930Sstevel@tonic-gate ** e -- current envelope. 16940Sstevel@tonic-gate ** 16950Sstevel@tonic-gate ** Returns: 16960Sstevel@tonic-gate ** 0 if succesful, -1 otherwise 16970Sstevel@tonic-gate */ 16980Sstevel@tonic-gate 16990Sstevel@tonic-gate static int 17000Sstevel@tonic-gate milter_reopen_df(e) 17010Sstevel@tonic-gate ENVELOPE *e; 17020Sstevel@tonic-gate { 17030Sstevel@tonic-gate char dfname[MAXPATHLEN]; 17040Sstevel@tonic-gate 17053544Sjbeck (void) sm_strlcpy(dfname, queuename(e, DATAFL_LETTER), sizeof(dfname)); 17060Sstevel@tonic-gate 17070Sstevel@tonic-gate /* 17080Sstevel@tonic-gate ** In SuperSafe == SAFE_REALLY mode, e->e_dfp is a read-only FP so 17090Sstevel@tonic-gate ** close and reopen writable (later close and reopen 17100Sstevel@tonic-gate ** read only again). 17110Sstevel@tonic-gate ** 17120Sstevel@tonic-gate ** In SuperSafe != SAFE_REALLY mode, e->e_dfp still points at the 17130Sstevel@tonic-gate ** buffered file I/O descriptor, still open for writing so there 17140Sstevel@tonic-gate ** isn't any work to do here (except checking for consistency). 17150Sstevel@tonic-gate */ 17160Sstevel@tonic-gate 17170Sstevel@tonic-gate if (SuperSafe == SAFE_REALLY) 17180Sstevel@tonic-gate { 17190Sstevel@tonic-gate /* close read-only data file */ 17200Sstevel@tonic-gate if (bitset(EF_HAS_DF, e->e_flags) && e->e_dfp != NULL) 17210Sstevel@tonic-gate { 17220Sstevel@tonic-gate (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT); 17230Sstevel@tonic-gate e->e_flags &= ~EF_HAS_DF; 17240Sstevel@tonic-gate } 17250Sstevel@tonic-gate 17260Sstevel@tonic-gate /* open writable */ 17270Sstevel@tonic-gate if ((e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname, 17280Sstevel@tonic-gate SM_IO_RDWR_B, NULL)) == NULL) 17290Sstevel@tonic-gate { 17300Sstevel@tonic-gate MILTER_DF_ERROR("milter_reopen_df: sm_io_open %s: %s"); 17310Sstevel@tonic-gate return -1; 17320Sstevel@tonic-gate } 17330Sstevel@tonic-gate } 17340Sstevel@tonic-gate else if (e->e_dfp == NULL) 17350Sstevel@tonic-gate { 17360Sstevel@tonic-gate /* shouldn't happen */ 17370Sstevel@tonic-gate errno = ENOENT; 17380Sstevel@tonic-gate MILTER_DF_ERROR("milter_reopen_df: NULL e_dfp (%s: %s)"); 17390Sstevel@tonic-gate return -1; 17400Sstevel@tonic-gate } 17410Sstevel@tonic-gate return 0; 17420Sstevel@tonic-gate } 17433544Sjbeck 17440Sstevel@tonic-gate /* 17450Sstevel@tonic-gate ** MILTER_RESET_DF -- re-open read-only the data file (for replbody) 17460Sstevel@tonic-gate ** 17470Sstevel@tonic-gate ** Parameters: 17480Sstevel@tonic-gate ** e -- current envelope. 17490Sstevel@tonic-gate ** 17500Sstevel@tonic-gate ** Returns: 17510Sstevel@tonic-gate ** 0 if succesful, -1 otherwise 17520Sstevel@tonic-gate */ 17530Sstevel@tonic-gate 17540Sstevel@tonic-gate static int 17550Sstevel@tonic-gate milter_reset_df(e) 17560Sstevel@tonic-gate ENVELOPE *e; 17570Sstevel@tonic-gate { 17580Sstevel@tonic-gate int afd; 17590Sstevel@tonic-gate char dfname[MAXPATHLEN]; 17600Sstevel@tonic-gate 17613544Sjbeck (void) sm_strlcpy(dfname, queuename(e, DATAFL_LETTER), sizeof(dfname)); 17620Sstevel@tonic-gate 17630Sstevel@tonic-gate if (sm_io_flush(e->e_dfp, SM_TIME_DEFAULT) != 0 || 17640Sstevel@tonic-gate sm_io_error(e->e_dfp)) 17650Sstevel@tonic-gate { 17660Sstevel@tonic-gate MILTER_DF_ERROR("milter_reset_df: error writing/flushing %s: %s"); 17670Sstevel@tonic-gate return -1; 17680Sstevel@tonic-gate } 17690Sstevel@tonic-gate else if (SuperSafe != SAFE_REALLY) 17700Sstevel@tonic-gate { 17710Sstevel@tonic-gate /* skip next few clauses */ 17720Sstevel@tonic-gate /* EMPTY */ 17730Sstevel@tonic-gate } 17740Sstevel@tonic-gate else if ((afd = sm_io_getinfo(e->e_dfp, SM_IO_WHAT_FD, NULL)) >= 0 17750Sstevel@tonic-gate && fsync(afd) < 0) 17760Sstevel@tonic-gate { 17770Sstevel@tonic-gate MILTER_DF_ERROR("milter_reset_df: error sync'ing %s: %s"); 17780Sstevel@tonic-gate return -1; 17790Sstevel@tonic-gate } 17800Sstevel@tonic-gate else if (sm_io_close(e->e_dfp, SM_TIME_DEFAULT) < 0) 17810Sstevel@tonic-gate { 17820Sstevel@tonic-gate MILTER_DF_ERROR("milter_reset_df: error closing %s: %s"); 17830Sstevel@tonic-gate return -1; 17840Sstevel@tonic-gate } 17850Sstevel@tonic-gate else if ((e->e_dfp = sm_io_open(SmFtStdio, SM_TIME_DEFAULT, dfname, 17860Sstevel@tonic-gate SM_IO_RDONLY_B, NULL)) == NULL) 17870Sstevel@tonic-gate { 17880Sstevel@tonic-gate MILTER_DF_ERROR("milter_reset_df: error reopening %s: %s"); 17890Sstevel@tonic-gate return -1; 17900Sstevel@tonic-gate } 17910Sstevel@tonic-gate else 17920Sstevel@tonic-gate e->e_flags |= EF_HAS_DF; 17930Sstevel@tonic-gate return 0; 17940Sstevel@tonic-gate } 17953544Sjbeck 17960Sstevel@tonic-gate /* 17970Sstevel@tonic-gate ** MILTER_QUIT_FILTER -- close down a single filter 17980Sstevel@tonic-gate ** 17990Sstevel@tonic-gate ** Parameters: 18000Sstevel@tonic-gate ** m -- milter structure of filter to close down. 18010Sstevel@tonic-gate ** e -- current envelope. 18020Sstevel@tonic-gate ** 18030Sstevel@tonic-gate ** Returns: 18040Sstevel@tonic-gate ** none 18050Sstevel@tonic-gate */ 18060Sstevel@tonic-gate 18070Sstevel@tonic-gate static void 18080Sstevel@tonic-gate milter_quit_filter(m, e) 18090Sstevel@tonic-gate struct milter *m; 18100Sstevel@tonic-gate ENVELOPE *e; 18110Sstevel@tonic-gate { 18120Sstevel@tonic-gate if (tTd(64, 10)) 18130Sstevel@tonic-gate sm_dprintf("milter_quit_filter(%s)\n", m->mf_name); 18140Sstevel@tonic-gate if (MilterLogLevel > 18) 18150Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter (%s): quit filter", 18160Sstevel@tonic-gate m->mf_name); 18170Sstevel@tonic-gate 18180Sstevel@tonic-gate /* Never replace error state */ 18190Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR) 18200Sstevel@tonic-gate return; 18210Sstevel@tonic-gate 18220Sstevel@tonic-gate if (m->mf_sock < 0 || 18230Sstevel@tonic-gate m->mf_state == SMFS_CLOSED || 18240Sstevel@tonic-gate m->mf_state == SMFS_READY) 18250Sstevel@tonic-gate { 18260Sstevel@tonic-gate m->mf_sock = -1; 18270Sstevel@tonic-gate m->mf_state = SMFS_CLOSED; 18280Sstevel@tonic-gate return; 18290Sstevel@tonic-gate } 18300Sstevel@tonic-gate 18310Sstevel@tonic-gate (void) milter_write(m, SMFIC_QUIT, (char *) NULL, 0, 18323544Sjbeck m->mf_timeout[SMFTO_WRITE], e, "quit_filter"); 18330Sstevel@tonic-gate if (m->mf_sock >= 0) 18340Sstevel@tonic-gate { 18350Sstevel@tonic-gate (void) close(m->mf_sock); 18360Sstevel@tonic-gate m->mf_sock = -1; 18370Sstevel@tonic-gate } 18380Sstevel@tonic-gate if (m->mf_state != SMFS_ERROR) 18390Sstevel@tonic-gate m->mf_state = SMFS_CLOSED; 18400Sstevel@tonic-gate } 18413544Sjbeck 18420Sstevel@tonic-gate /* 18430Sstevel@tonic-gate ** MILTER_ABORT_FILTER -- tell filter to abort current message 18440Sstevel@tonic-gate ** 18450Sstevel@tonic-gate ** Parameters: 18460Sstevel@tonic-gate ** m -- milter structure of filter to abort. 18470Sstevel@tonic-gate ** e -- current envelope. 18480Sstevel@tonic-gate ** 18490Sstevel@tonic-gate ** Returns: 18500Sstevel@tonic-gate ** none 18510Sstevel@tonic-gate */ 18520Sstevel@tonic-gate 18530Sstevel@tonic-gate static void 18540Sstevel@tonic-gate milter_abort_filter(m, e) 18550Sstevel@tonic-gate struct milter *m; 18560Sstevel@tonic-gate ENVELOPE *e; 18570Sstevel@tonic-gate { 18580Sstevel@tonic-gate if (tTd(64, 10)) 18590Sstevel@tonic-gate sm_dprintf("milter_abort_filter(%s)\n", m->mf_name); 18600Sstevel@tonic-gate if (MilterLogLevel > 10) 18610Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter (%s): abort filter", 18620Sstevel@tonic-gate m->mf_name); 18630Sstevel@tonic-gate 18640Sstevel@tonic-gate if (m->mf_sock < 0 || 18650Sstevel@tonic-gate m->mf_state != SMFS_INMSG) 18660Sstevel@tonic-gate return; 18670Sstevel@tonic-gate 18680Sstevel@tonic-gate (void) milter_write(m, SMFIC_ABORT, (char *) NULL, 0, 18693544Sjbeck m->mf_timeout[SMFTO_WRITE], e, "abort_filter"); 18700Sstevel@tonic-gate if (m->mf_state != SMFS_ERROR) 18710Sstevel@tonic-gate m->mf_state = SMFS_DONE; 18720Sstevel@tonic-gate } 18733544Sjbeck 18740Sstevel@tonic-gate /* 18750Sstevel@tonic-gate ** MILTER_SEND_MACROS -- provide macros to the filters 18760Sstevel@tonic-gate ** 18770Sstevel@tonic-gate ** Parameters: 18780Sstevel@tonic-gate ** m -- milter to send macros to. 18790Sstevel@tonic-gate ** macros -- macros to send for filter smfi_getsymval(). 18800Sstevel@tonic-gate ** cmd -- which command the macros are associated with. 18810Sstevel@tonic-gate ** e -- current envelope (for macro access). 18820Sstevel@tonic-gate ** 18830Sstevel@tonic-gate ** Returns: 18840Sstevel@tonic-gate ** none 18850Sstevel@tonic-gate */ 18860Sstevel@tonic-gate 18870Sstevel@tonic-gate static void 18880Sstevel@tonic-gate milter_send_macros(m, macros, cmd, e) 18890Sstevel@tonic-gate struct milter *m; 18900Sstevel@tonic-gate char **macros; 18913544Sjbeck int cmd; 18920Sstevel@tonic-gate ENVELOPE *e; 18930Sstevel@tonic-gate { 18940Sstevel@tonic-gate int i; 18950Sstevel@tonic-gate int mid; 18963544Sjbeck char command = (char) cmd; 18970Sstevel@tonic-gate char *v; 18980Sstevel@tonic-gate char *buf, *bp; 18990Sstevel@tonic-gate char exp[MAXLINE]; 19000Sstevel@tonic-gate ssize_t s; 19010Sstevel@tonic-gate 19020Sstevel@tonic-gate /* sanity check */ 19030Sstevel@tonic-gate if (macros == NULL || macros[0] == NULL) 19040Sstevel@tonic-gate return; 19050Sstevel@tonic-gate 19060Sstevel@tonic-gate /* put together data */ 19070Sstevel@tonic-gate s = 1; /* for the command character */ 19080Sstevel@tonic-gate for (i = 0; macros[i] != NULL; i++) 19090Sstevel@tonic-gate { 19100Sstevel@tonic-gate mid = macid(macros[i]); 19110Sstevel@tonic-gate if (mid == 0) 19120Sstevel@tonic-gate continue; 19130Sstevel@tonic-gate v = macvalue(mid, e); 19140Sstevel@tonic-gate if (v == NULL) 19150Sstevel@tonic-gate continue; 19160Sstevel@tonic-gate expand(v, exp, sizeof(exp), e); 19170Sstevel@tonic-gate s += strlen(macros[i]) + 1 + strlen(exp) + 1; 19180Sstevel@tonic-gate } 19190Sstevel@tonic-gate 19200Sstevel@tonic-gate if (s < 0) 19210Sstevel@tonic-gate return; 19220Sstevel@tonic-gate 19230Sstevel@tonic-gate buf = (char *) xalloc(s); 19240Sstevel@tonic-gate bp = buf; 19253544Sjbeck *bp++ = command; 19260Sstevel@tonic-gate for (i = 0; macros[i] != NULL; i++) 19270Sstevel@tonic-gate { 19280Sstevel@tonic-gate mid = macid(macros[i]); 19290Sstevel@tonic-gate if (mid == 0) 19300Sstevel@tonic-gate continue; 19310Sstevel@tonic-gate v = macvalue(mid, e); 19320Sstevel@tonic-gate if (v == NULL) 19330Sstevel@tonic-gate continue; 19340Sstevel@tonic-gate expand(v, exp, sizeof(exp), e); 19350Sstevel@tonic-gate 19360Sstevel@tonic-gate if (tTd(64, 10)) 19370Sstevel@tonic-gate sm_dprintf("milter_send_macros(%s, %c): %s=%s\n", 19383544Sjbeck m->mf_name, command, macros[i], exp); 19390Sstevel@tonic-gate 19400Sstevel@tonic-gate (void) sm_strlcpy(bp, macros[i], s - (bp - buf)); 19410Sstevel@tonic-gate bp += strlen(bp) + 1; 19420Sstevel@tonic-gate (void) sm_strlcpy(bp, exp, s - (bp - buf)); 19430Sstevel@tonic-gate bp += strlen(bp) + 1; 19440Sstevel@tonic-gate } 19450Sstevel@tonic-gate (void) milter_write(m, SMFIC_MACRO, buf, s, 19463544Sjbeck m->mf_timeout[SMFTO_WRITE], e, "send_macros"); 19470Sstevel@tonic-gate sm_free(buf); 19480Sstevel@tonic-gate } 19490Sstevel@tonic-gate 19500Sstevel@tonic-gate /* 19510Sstevel@tonic-gate ** MILTER_SEND_COMMAND -- send a command and return the response for a filter 19520Sstevel@tonic-gate ** 19530Sstevel@tonic-gate ** Parameters: 19540Sstevel@tonic-gate ** m -- current milter filter 19553544Sjbeck ** cmd -- command to send. 19560Sstevel@tonic-gate ** data -- optional command data. 19570Sstevel@tonic-gate ** sz -- length of buf. 19580Sstevel@tonic-gate ** e -- current envelope (for e->e_id). 19590Sstevel@tonic-gate ** state -- return state word. 19600Sstevel@tonic-gate ** 19610Sstevel@tonic-gate ** Returns: 19620Sstevel@tonic-gate ** response string (may be NULL) 19630Sstevel@tonic-gate */ 19640Sstevel@tonic-gate 19650Sstevel@tonic-gate static char * 19663544Sjbeck milter_send_command(m, cmd, data, sz, e, state, where) 19670Sstevel@tonic-gate struct milter *m; 19683544Sjbeck int cmd; 19690Sstevel@tonic-gate void *data; 19700Sstevel@tonic-gate ssize_t sz; 19710Sstevel@tonic-gate ENVELOPE *e; 19720Sstevel@tonic-gate char *state; 19733544Sjbeck const char *where; 19740Sstevel@tonic-gate { 19750Sstevel@tonic-gate char rcmd; 19760Sstevel@tonic-gate ssize_t rlen; 19770Sstevel@tonic-gate unsigned long skipflag; 19780Sstevel@tonic-gate unsigned long norespflag = 0; 19793544Sjbeck char command = (char) cmd; 19800Sstevel@tonic-gate char *action; 19810Sstevel@tonic-gate char *defresponse; 19820Sstevel@tonic-gate char *response; 19830Sstevel@tonic-gate 19840Sstevel@tonic-gate if (tTd(64, 10)) 19850Sstevel@tonic-gate sm_dprintf("milter_send_command(%s): cmd %c len %ld\n", 19860Sstevel@tonic-gate m->mf_name, (char) command, (long) sz); 19870Sstevel@tonic-gate 19880Sstevel@tonic-gate /* find skip flag and default failure */ 19890Sstevel@tonic-gate switch (command) 19900Sstevel@tonic-gate { 19910Sstevel@tonic-gate case SMFIC_CONNECT: 19920Sstevel@tonic-gate skipflag = SMFIP_NOCONNECT; 19933544Sjbeck norespflag = SMFIP_NR_CONN; 19940Sstevel@tonic-gate action = "connect"; 19950Sstevel@tonic-gate defresponse = "554 Command rejected"; 19960Sstevel@tonic-gate break; 19970Sstevel@tonic-gate 19980Sstevel@tonic-gate case SMFIC_HELO: 19990Sstevel@tonic-gate skipflag = SMFIP_NOHELO; 20003544Sjbeck norespflag = SMFIP_NR_HELO; 20010Sstevel@tonic-gate action = "helo"; 20020Sstevel@tonic-gate defresponse = "550 Command rejected"; 20030Sstevel@tonic-gate break; 20040Sstevel@tonic-gate 20050Sstevel@tonic-gate case SMFIC_MAIL: 20060Sstevel@tonic-gate skipflag = SMFIP_NOMAIL; 20073544Sjbeck norespflag = SMFIP_NR_MAIL; 20080Sstevel@tonic-gate action = "mail"; 20090Sstevel@tonic-gate defresponse = "550 5.7.1 Command rejected"; 20100Sstevel@tonic-gate break; 20110Sstevel@tonic-gate 20120Sstevel@tonic-gate case SMFIC_RCPT: 20130Sstevel@tonic-gate skipflag = SMFIP_NORCPT; 20143544Sjbeck norespflag = SMFIP_NR_RCPT; 20150Sstevel@tonic-gate action = "rcpt"; 20160Sstevel@tonic-gate defresponse = "550 5.7.1 Command rejected"; 20170Sstevel@tonic-gate break; 20180Sstevel@tonic-gate 20190Sstevel@tonic-gate case SMFIC_HEADER: 20200Sstevel@tonic-gate skipflag = SMFIP_NOHDRS; 20213544Sjbeck norespflag = SMFIP_NR_HDR; 20220Sstevel@tonic-gate action = "header"; 20230Sstevel@tonic-gate defresponse = "550 5.7.1 Command rejected"; 20240Sstevel@tonic-gate break; 20250Sstevel@tonic-gate 20260Sstevel@tonic-gate case SMFIC_BODY: 20270Sstevel@tonic-gate skipflag = SMFIP_NOBODY; 20283544Sjbeck norespflag = SMFIP_NR_BODY; 20290Sstevel@tonic-gate action = "body"; 20300Sstevel@tonic-gate defresponse = "554 5.7.1 Command rejected"; 20310Sstevel@tonic-gate break; 20320Sstevel@tonic-gate 20330Sstevel@tonic-gate case SMFIC_EOH: 20340Sstevel@tonic-gate skipflag = SMFIP_NOEOH; 20353544Sjbeck norespflag = SMFIP_NR_EOH; 20360Sstevel@tonic-gate action = "eoh"; 20370Sstevel@tonic-gate defresponse = "550 5.7.1 Command rejected"; 20380Sstevel@tonic-gate break; 20390Sstevel@tonic-gate 20400Sstevel@tonic-gate case SMFIC_UNKNOWN: 2041616Sjbeck skipflag = SMFIP_NOUNKNOWN; 20423544Sjbeck norespflag = SMFIP_NR_UNKN; 20430Sstevel@tonic-gate action = "unknown"; 20440Sstevel@tonic-gate defresponse = "550 5.7.1 Command rejected"; 20450Sstevel@tonic-gate break; 20463544Sjbeck 2047616Sjbeck case SMFIC_DATA: 2048616Sjbeck skipflag = SMFIP_NODATA; 20493544Sjbeck norespflag = SMFIP_NR_DATA; 2050616Sjbeck action = "data"; 2051616Sjbeck defresponse = "550 5.7.1 Command rejected"; 2052616Sjbeck break; 2053616Sjbeck 20540Sstevel@tonic-gate case SMFIC_BODYEOB: 20550Sstevel@tonic-gate case SMFIC_OPTNEG: 20560Sstevel@tonic-gate case SMFIC_MACRO: 20570Sstevel@tonic-gate case SMFIC_ABORT: 20580Sstevel@tonic-gate case SMFIC_QUIT: 20590Sstevel@tonic-gate /* NOTE: not handled by milter_send_command() */ 20600Sstevel@tonic-gate /* FALLTHROUGH */ 20610Sstevel@tonic-gate 20620Sstevel@tonic-gate default: 20630Sstevel@tonic-gate skipflag = 0; 20640Sstevel@tonic-gate action = "default"; 20650Sstevel@tonic-gate defresponse = "550 5.7.1 Command rejected"; 20660Sstevel@tonic-gate break; 20670Sstevel@tonic-gate } 20680Sstevel@tonic-gate 20693544Sjbeck if (tTd(64, 10)) 20703544Sjbeck sm_dprintf("milter_send_command(%s): skip=%lx, pflags=%x\n", 20713544Sjbeck m->mf_name, skipflag, m->mf_pflags); 20723544Sjbeck 20730Sstevel@tonic-gate /* check if filter wants this command */ 20743544Sjbeck if (skipflag != 0 && bitset(skipflag, m->mf_pflags)) 20750Sstevel@tonic-gate return NULL; 20760Sstevel@tonic-gate 20770Sstevel@tonic-gate /* send the command to the filter */ 20780Sstevel@tonic-gate (void) milter_write(m, command, data, sz, 20793544Sjbeck m->mf_timeout[SMFTO_WRITE], e, where); 20800Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR) 20810Sstevel@tonic-gate { 20820Sstevel@tonic-gate MILTER_CHECK_ERROR(false, return NULL); 20830Sstevel@tonic-gate return NULL; 20840Sstevel@tonic-gate } 20850Sstevel@tonic-gate 20860Sstevel@tonic-gate /* check if filter sends response to this command */ 20870Sstevel@tonic-gate if (norespflag != 0 && bitset(norespflag, m->mf_pflags)) 20880Sstevel@tonic-gate return NULL; 20890Sstevel@tonic-gate 20900Sstevel@tonic-gate /* get the response from the filter */ 20910Sstevel@tonic-gate response = milter_read(m, &rcmd, &rlen, 20923544Sjbeck m->mf_timeout[SMFTO_READ], e, where); 20930Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR) 20940Sstevel@tonic-gate { 20950Sstevel@tonic-gate MILTER_CHECK_ERROR(false, return NULL); 20960Sstevel@tonic-gate return NULL; 20970Sstevel@tonic-gate } 20980Sstevel@tonic-gate 20990Sstevel@tonic-gate if (tTd(64, 10)) 21000Sstevel@tonic-gate sm_dprintf("milter_send_command(%s): returned %c\n", 21010Sstevel@tonic-gate m->mf_name, (char) rcmd); 21020Sstevel@tonic-gate 21030Sstevel@tonic-gate switch (rcmd) 21040Sstevel@tonic-gate { 21050Sstevel@tonic-gate case SMFIR_REPLYCODE: 21060Sstevel@tonic-gate MILTER_CHECK_REPLYCODE(defresponse); 21070Sstevel@tonic-gate if (MilterLogLevel > 10) 21083544Sjbeck sm_syslog(LOG_INFO, e->e_id, 21093544Sjbeck "milter=%s, action=%s, reject=%s", 21100Sstevel@tonic-gate m->mf_name, action, response); 21110Sstevel@tonic-gate *state = rcmd; 21120Sstevel@tonic-gate break; 21130Sstevel@tonic-gate 21140Sstevel@tonic-gate case SMFIR_REJECT: 21150Sstevel@tonic-gate if (MilterLogLevel > 10) 21163544Sjbeck sm_syslog(LOG_INFO, e->e_id, 21173544Sjbeck "milter=%s, action=%s, reject", 21180Sstevel@tonic-gate m->mf_name, action); 21190Sstevel@tonic-gate *state = rcmd; 21200Sstevel@tonic-gate break; 21210Sstevel@tonic-gate 21220Sstevel@tonic-gate case SMFIR_DISCARD: 21230Sstevel@tonic-gate if (MilterLogLevel > 10) 21243544Sjbeck sm_syslog(LOG_INFO, e->e_id, 21253544Sjbeck "milter=%s, action=%s, discard", 21260Sstevel@tonic-gate m->mf_name, action); 21270Sstevel@tonic-gate *state = rcmd; 21280Sstevel@tonic-gate break; 21290Sstevel@tonic-gate 21300Sstevel@tonic-gate case SMFIR_TEMPFAIL: 21310Sstevel@tonic-gate if (MilterLogLevel > 10) 21323544Sjbeck sm_syslog(LOG_INFO, e->e_id, 21333544Sjbeck "milter=%s, action=%s, tempfail", 21340Sstevel@tonic-gate m->mf_name, action); 21350Sstevel@tonic-gate *state = rcmd; 21360Sstevel@tonic-gate break; 21370Sstevel@tonic-gate 21380Sstevel@tonic-gate case SMFIR_ACCEPT: 21390Sstevel@tonic-gate /* this filter is done with message/connection */ 21400Sstevel@tonic-gate if (command == SMFIC_HELO || 21410Sstevel@tonic-gate command == SMFIC_CONNECT) 21420Sstevel@tonic-gate m->mf_state = SMFS_CLOSABLE; 21430Sstevel@tonic-gate else 21440Sstevel@tonic-gate m->mf_state = SMFS_DONE; 21450Sstevel@tonic-gate if (MilterLogLevel > 10) 21463544Sjbeck sm_syslog(LOG_INFO, e->e_id, 21473544Sjbeck "milter=%s, action=%s, accepted", 21480Sstevel@tonic-gate m->mf_name, action); 21490Sstevel@tonic-gate break; 21500Sstevel@tonic-gate 21510Sstevel@tonic-gate case SMFIR_CONTINUE: 21520Sstevel@tonic-gate /* if MAIL command is ok, filter is in message state */ 21530Sstevel@tonic-gate if (command == SMFIC_MAIL) 21540Sstevel@tonic-gate m->mf_state = SMFS_INMSG; 21550Sstevel@tonic-gate if (MilterLogLevel > 12) 21563544Sjbeck sm_syslog(LOG_INFO, e->e_id, 21573544Sjbeck "milter=%s, action=%s, continue", 21580Sstevel@tonic-gate m->mf_name, action); 21590Sstevel@tonic-gate break; 21600Sstevel@tonic-gate 21613544Sjbeck case SMFIR_SKIP: 21623544Sjbeck if (MilterLogLevel > 12) 21633544Sjbeck sm_syslog(LOG_INFO, e->e_id, 21643544Sjbeck "milter=%s, action=%s, skip", 21653544Sjbeck m->mf_name, action); 21663544Sjbeck m->mf_state = SMFS_SKIP; 21673544Sjbeck break; 21683544Sjbeck 21690Sstevel@tonic-gate default: 21700Sstevel@tonic-gate /* Invalid response to command */ 21710Sstevel@tonic-gate if (MilterLogLevel > 0) 21720Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 21730Sstevel@tonic-gate "milter_send_command(%s): action=%s returned bogus response %c", 21740Sstevel@tonic-gate m->mf_name, action, rcmd); 21750Sstevel@tonic-gate milter_error(m, e); 21760Sstevel@tonic-gate break; 21770Sstevel@tonic-gate } 21780Sstevel@tonic-gate 21793544Sjbeck if (*state != SMFIR_REPLYCODE && response != NULL) 21800Sstevel@tonic-gate { 21810Sstevel@tonic-gate sm_free(response); /* XXX */ 21820Sstevel@tonic-gate response = NULL; 21830Sstevel@tonic-gate } 21840Sstevel@tonic-gate return response; 21850Sstevel@tonic-gate } 21860Sstevel@tonic-gate 21870Sstevel@tonic-gate /* 21880Sstevel@tonic-gate ** MILTER_COMMAND -- send a command and return the response for each filter 21890Sstevel@tonic-gate ** 21900Sstevel@tonic-gate ** Parameters: 21913544Sjbeck ** cmd -- command to send. 21920Sstevel@tonic-gate ** data -- optional command data. 21930Sstevel@tonic-gate ** sz -- length of buf. 21940Sstevel@tonic-gate ** macros -- macros to send for filter smfi_getsymval(). 21950Sstevel@tonic-gate ** e -- current envelope (for macro access). 21960Sstevel@tonic-gate ** state -- return state word. 21973544Sjbeck ** where -- description of calling function (logging). 21983544Sjbeck ** cmd_error -- did the SMTP command cause an error? 21990Sstevel@tonic-gate ** 22000Sstevel@tonic-gate ** Returns: 22010Sstevel@tonic-gate ** response string (may be NULL) 22020Sstevel@tonic-gate */ 22030Sstevel@tonic-gate 22040Sstevel@tonic-gate static char * 22053544Sjbeck milter_command(cmd, data, sz, macros, e, state, where, cmd_error) 22063544Sjbeck int cmd; 22070Sstevel@tonic-gate void *data; 22080Sstevel@tonic-gate ssize_t sz; 22090Sstevel@tonic-gate char **macros; 22100Sstevel@tonic-gate ENVELOPE *e; 22110Sstevel@tonic-gate char *state; 22123544Sjbeck const char *where; 22133544Sjbeck bool cmd_error; 22140Sstevel@tonic-gate { 22150Sstevel@tonic-gate int i; 22163544Sjbeck char command = (char) cmd; 22170Sstevel@tonic-gate char *response = NULL; 22180Sstevel@tonic-gate time_t tn = 0; 22190Sstevel@tonic-gate 22200Sstevel@tonic-gate if (tTd(64, 10)) 22210Sstevel@tonic-gate sm_dprintf("milter_command: cmd %c len %ld\n", 22223544Sjbeck command, (long) sz); 22230Sstevel@tonic-gate 22240Sstevel@tonic-gate *state = SMFIR_CONTINUE; 22250Sstevel@tonic-gate for (i = 0; InputFilters[i] != NULL; i++) 22260Sstevel@tonic-gate { 22270Sstevel@tonic-gate struct milter *m = InputFilters[i]; 22280Sstevel@tonic-gate 22290Sstevel@tonic-gate /* previous problem? */ 22300Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR) 22310Sstevel@tonic-gate { 22320Sstevel@tonic-gate MILTER_CHECK_ERROR(false, continue); 22330Sstevel@tonic-gate break; 22340Sstevel@tonic-gate } 22350Sstevel@tonic-gate 22360Sstevel@tonic-gate /* sanity check */ 22370Sstevel@tonic-gate if (m->mf_sock < 0 || 22380Sstevel@tonic-gate (m->mf_state != SMFS_OPEN && m->mf_state != SMFS_INMSG)) 22390Sstevel@tonic-gate continue; 22400Sstevel@tonic-gate 22410Sstevel@tonic-gate /* send macros (regardless of whether we send command) */ 22420Sstevel@tonic-gate if (macros != NULL && macros[0] != NULL) 22430Sstevel@tonic-gate { 22440Sstevel@tonic-gate milter_send_macros(m, macros, command, e); 22450Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR) 22460Sstevel@tonic-gate { 22470Sstevel@tonic-gate MILTER_CHECK_ERROR(false, continue); 22480Sstevel@tonic-gate break; 22490Sstevel@tonic-gate } 22500Sstevel@tonic-gate } 22510Sstevel@tonic-gate 22520Sstevel@tonic-gate if (MilterLogLevel > 21) 22530Sstevel@tonic-gate tn = curtime(); 22540Sstevel@tonic-gate 22553544Sjbeck /* 22563544Sjbeck ** send the command if 22573544Sjbeck ** there is no error 22583544Sjbeck ** or it's RCPT and the client asked for it: 22593544Sjbeck ** !cmd_error || 22603544Sjbeck ** where == "rcpt" && m->mf_pflags & SMFIP_RCPT_REJ != 0 22613544Sjbeck ** negate that condition and use continue 22623544Sjbeck */ 22633544Sjbeck 22643544Sjbeck if (cmd_error && 22653544Sjbeck (strcmp(where, "rcpt") != 0 || 22663544Sjbeck (m->mf_pflags & SMFIP_RCPT_REJ) == 0)) 22673544Sjbeck continue; 22683544Sjbeck 22693544Sjbeck response = milter_send_command(m, command, data, sz, e, state, 22703544Sjbeck where); 22710Sstevel@tonic-gate 22720Sstevel@tonic-gate if (MilterLogLevel > 21) 22730Sstevel@tonic-gate { 22740Sstevel@tonic-gate /* log the time it took for the command per filter */ 22750Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 22760Sstevel@tonic-gate "Milter (%s): time command (%c), %d", 22770Sstevel@tonic-gate m->mf_name, command, (int) (tn - curtime())); 22780Sstevel@tonic-gate } 22790Sstevel@tonic-gate 22800Sstevel@tonic-gate if (*state != SMFIR_CONTINUE) 22810Sstevel@tonic-gate break; 22820Sstevel@tonic-gate } 22830Sstevel@tonic-gate return response; 22840Sstevel@tonic-gate } 22853544Sjbeck 22863544Sjbeck static int milter_getsymlist __P((struct milter *, char *, int, int)); 22873544Sjbeck 22883544Sjbeck static int 22893544Sjbeck milter_getsymlist(m, buf, rlen, offset) 22903544Sjbeck struct milter *m; 22913544Sjbeck char *buf; 22923544Sjbeck int rlen; 22933544Sjbeck int offset; 22943544Sjbeck { 22953544Sjbeck int i, r, nummac; 22963544Sjbeck mi_int32 v; 22973544Sjbeck 22983544Sjbeck SM_ASSERT(m != NULL); 22993544Sjbeck SM_ASSERT(buf != NULL); 23003544Sjbeck 23013544Sjbeck while (offset + MILTER_LEN_BYTES < rlen) 23023544Sjbeck { 23033544Sjbeck size_t len; 23043544Sjbeck char **macros; 23053544Sjbeck 23063544Sjbeck nummac = 0; 23073544Sjbeck (void) memcpy((char *) &v, buf + offset, MILTER_LEN_BYTES); 23083544Sjbeck i = ntohl(v); 23093544Sjbeck if (i < SMFIM_FIRST || i > SMFIM_LAST) 23103544Sjbeck return -1; 23113544Sjbeck offset += MILTER_LEN_BYTES; 23123544Sjbeck macros = NULL; 23133544Sjbeck 23143544Sjbeck switch (i) 23153544Sjbeck { 23163544Sjbeck case MO_MACROS_CONNECT: 23173544Sjbeck if (macros == NULL) 23183544Sjbeck macros = MilterConnectMacros; 23193544Sjbeck /* FALLTHROUGH */ 23203544Sjbeck 23213544Sjbeck case MO_MACROS_HELO: 23223544Sjbeck if (macros == NULL) 23233544Sjbeck macros = MilterHeloMacros; 23243544Sjbeck /* FALLTHROUGH */ 23253544Sjbeck 23263544Sjbeck case MO_MACROS_ENVFROM: 23273544Sjbeck if (macros == NULL) 23283544Sjbeck macros = MilterEnvFromMacros; 23293544Sjbeck /* FALLTHROUGH */ 23303544Sjbeck 23313544Sjbeck case MO_MACROS_ENVRCPT: 23323544Sjbeck if (macros == NULL) 23333544Sjbeck macros = MilterEnvRcptMacros; 23343544Sjbeck /* FALLTHROUGH */ 23353544Sjbeck 23363544Sjbeck case MO_MACROS_EOM: 23373544Sjbeck if (macros == NULL) 23383544Sjbeck macros = MilterEOMMacros; 23393544Sjbeck /* FALLTHROUGH */ 23403544Sjbeck 23413544Sjbeck case MO_MACROS_EOH: 23423544Sjbeck if (macros == NULL) 23433544Sjbeck macros = MilterEOHMacros; 23443544Sjbeck /* FALLTHROUGH */ 23453544Sjbeck 23463544Sjbeck case MO_MACROS_DATA: 23473544Sjbeck if (macros == NULL) 23483544Sjbeck macros = MilterDataMacros; 23493544Sjbeck 23503544Sjbeck len = strlen(buf + offset); 23513544Sjbeck if (len > 0) 23523544Sjbeck { 23533544Sjbeck r = milter_set_macros(m->mf_name, macros, 23543544Sjbeck buf + offset, nummac); 23553544Sjbeck if (r >= 0) 23563544Sjbeck nummac = r; 23573544Sjbeck } 23583544Sjbeck break; 23593544Sjbeck 23603544Sjbeck default: 23613544Sjbeck return -1; 23623544Sjbeck } 23633544Sjbeck if (len == 0) 23643544Sjbeck return -1; 23653544Sjbeck offset += len + 1; 23663544Sjbeck } 23673544Sjbeck 23683544Sjbeck return 0; 23693544Sjbeck } 23703544Sjbeck 23710Sstevel@tonic-gate /* 23720Sstevel@tonic-gate ** MILTER_NEGOTIATE -- get version and flags from filter 23730Sstevel@tonic-gate ** 23740Sstevel@tonic-gate ** Parameters: 23750Sstevel@tonic-gate ** m -- milter filter structure. 23760Sstevel@tonic-gate ** e -- current envelope. 2377*5402Sjbeck ** milters -- milters structure. 23780Sstevel@tonic-gate ** 23790Sstevel@tonic-gate ** Returns: 23800Sstevel@tonic-gate ** 0 on success, -1 otherwise 23810Sstevel@tonic-gate */ 23820Sstevel@tonic-gate 23830Sstevel@tonic-gate static int 2384*5402Sjbeck milter_negotiate(m, e, milters) 23850Sstevel@tonic-gate struct milter *m; 23860Sstevel@tonic-gate ENVELOPE *e; 2387*5402Sjbeck milters_T *milters; 23880Sstevel@tonic-gate { 23890Sstevel@tonic-gate char rcmd; 23903544Sjbeck mi_int32 fvers, fflags, pflags; 23913544Sjbeck mi_int32 mta_prot_vers, mta_prot_flags, mta_actions; 2392616Sjbeck ssize_t rlen; 23930Sstevel@tonic-gate char *response; 23940Sstevel@tonic-gate char data[MILTER_OPTLEN]; 23950Sstevel@tonic-gate 23960Sstevel@tonic-gate /* sanity check */ 23970Sstevel@tonic-gate if (m->mf_sock < 0 || m->mf_state != SMFS_OPEN) 23980Sstevel@tonic-gate { 23990Sstevel@tonic-gate if (MilterLogLevel > 0) 24000Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 24010Sstevel@tonic-gate "Milter (%s): negotiate, impossible state", 24020Sstevel@tonic-gate m->mf_name); 24030Sstevel@tonic-gate milter_error(m, e); 24040Sstevel@tonic-gate return -1; 24050Sstevel@tonic-gate } 24060Sstevel@tonic-gate 24073966Sjbeck #if _FFR_MILTER_CHECK 24083544Sjbeck mta_prot_vers = m->mf_mta_prot_version; 24093544Sjbeck mta_prot_flags = m->mf_mta_prot_flags; 24103544Sjbeck mta_actions = m->mf_mta_actions; 24113966Sjbeck #else /* _FFR_MILTER_CHECK */ 24123544Sjbeck mta_prot_vers = SMFI_PROT_VERSION; 24133544Sjbeck mta_prot_flags = SMFI_CURR_PROT; 24143544Sjbeck mta_actions = SMFI_CURR_ACTS; 24153966Sjbeck #endif /* _FFR_MILTER_CHECK */ 24163544Sjbeck 24173544Sjbeck fvers = htonl(mta_prot_vers); 24183544Sjbeck pflags = htonl(mta_prot_flags); 24193544Sjbeck fflags = htonl(mta_actions); 24200Sstevel@tonic-gate (void) memcpy(data, (char *) &fvers, MILTER_LEN_BYTES); 24210Sstevel@tonic-gate (void) memcpy(data + MILTER_LEN_BYTES, 24220Sstevel@tonic-gate (char *) &fflags, MILTER_LEN_BYTES); 24230Sstevel@tonic-gate (void) memcpy(data + (MILTER_LEN_BYTES * 2), 24240Sstevel@tonic-gate (char *) &pflags, MILTER_LEN_BYTES); 24253544Sjbeck (void) milter_write(m, SMFIC_OPTNEG, data, sizeof(data), 24263544Sjbeck m->mf_timeout[SMFTO_WRITE], e, "negotiate"); 24270Sstevel@tonic-gate 24280Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR) 24290Sstevel@tonic-gate return -1; 24300Sstevel@tonic-gate 24313544Sjbeck if (tTd(64, 5)) 24323544Sjbeck sm_dprintf("milter_negotiate(%s): send: version %lu, fflags 0x%lx, pflags 0x%lx\n", 24333544Sjbeck m->mf_name, ntohl(fvers), ntohl(fflags), ntohl(pflags)); 24343544Sjbeck 24353544Sjbeck response = milter_read(m, &rcmd, &rlen, m->mf_timeout[SMFTO_READ], e, 24363544Sjbeck "negotiate"); 24370Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR) 24380Sstevel@tonic-gate return -1; 24390Sstevel@tonic-gate 24400Sstevel@tonic-gate if (rcmd != SMFIC_OPTNEG) 24410Sstevel@tonic-gate { 24420Sstevel@tonic-gate if (tTd(64, 5)) 24430Sstevel@tonic-gate sm_dprintf("milter_negotiate(%s): returned %c instead of %c\n", 24440Sstevel@tonic-gate m->mf_name, rcmd, SMFIC_OPTNEG); 24450Sstevel@tonic-gate if (MilterLogLevel > 0) 24460Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 24470Sstevel@tonic-gate "Milter (%s): negotiate: returned %c instead of %c", 24480Sstevel@tonic-gate m->mf_name, rcmd, SMFIC_OPTNEG); 24490Sstevel@tonic-gate if (response != NULL) 24500Sstevel@tonic-gate sm_free(response); /* XXX */ 24510Sstevel@tonic-gate milter_error(m, e); 24520Sstevel@tonic-gate return -1; 24530Sstevel@tonic-gate } 24540Sstevel@tonic-gate 24550Sstevel@tonic-gate /* Make sure we have enough bytes for the version */ 24560Sstevel@tonic-gate if (response == NULL || rlen < MILTER_LEN_BYTES) 24570Sstevel@tonic-gate { 24580Sstevel@tonic-gate if (tTd(64, 5)) 24590Sstevel@tonic-gate sm_dprintf("milter_negotiate(%s): did not return valid info\n", 24600Sstevel@tonic-gate m->mf_name); 24610Sstevel@tonic-gate if (MilterLogLevel > 0) 24620Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 24630Sstevel@tonic-gate "Milter (%s): negotiate: did not return valid info", 24640Sstevel@tonic-gate m->mf_name); 24650Sstevel@tonic-gate if (response != NULL) 24660Sstevel@tonic-gate sm_free(response); /* XXX */ 24670Sstevel@tonic-gate milter_error(m, e); 24680Sstevel@tonic-gate return -1; 24690Sstevel@tonic-gate } 24700Sstevel@tonic-gate 24710Sstevel@tonic-gate /* extract information */ 24720Sstevel@tonic-gate (void) memcpy((char *) &fvers, response, MILTER_LEN_BYTES); 24730Sstevel@tonic-gate 24740Sstevel@tonic-gate /* Now make sure we have enough for the feature bitmap */ 24753544Sjbeck if (rlen < MILTER_OPTLEN) 24760Sstevel@tonic-gate { 24770Sstevel@tonic-gate if (tTd(64, 5)) 24780Sstevel@tonic-gate sm_dprintf("milter_negotiate(%s): did not return enough info\n", 24790Sstevel@tonic-gate m->mf_name); 24800Sstevel@tonic-gate if (MilterLogLevel > 0) 24810Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 24820Sstevel@tonic-gate "Milter (%s): negotiate: did not return enough info", 24830Sstevel@tonic-gate m->mf_name); 24840Sstevel@tonic-gate if (response != NULL) 24850Sstevel@tonic-gate sm_free(response); /* XXX */ 24860Sstevel@tonic-gate milter_error(m, e); 24870Sstevel@tonic-gate return -1; 24880Sstevel@tonic-gate } 24890Sstevel@tonic-gate 24900Sstevel@tonic-gate (void) memcpy((char *) &fflags, response + MILTER_LEN_BYTES, 24910Sstevel@tonic-gate MILTER_LEN_BYTES); 24920Sstevel@tonic-gate (void) memcpy((char *) &pflags, response + (MILTER_LEN_BYTES * 2), 24930Sstevel@tonic-gate MILTER_LEN_BYTES); 24940Sstevel@tonic-gate 24950Sstevel@tonic-gate m->mf_fvers = ntohl(fvers); 24960Sstevel@tonic-gate m->mf_fflags = ntohl(fflags); 24970Sstevel@tonic-gate m->mf_pflags = ntohl(pflags); 24980Sstevel@tonic-gate 24990Sstevel@tonic-gate /* check for version compatibility */ 25000Sstevel@tonic-gate if (m->mf_fvers == 1 || 25010Sstevel@tonic-gate m->mf_fvers > SMFI_VERSION) 25020Sstevel@tonic-gate { 25030Sstevel@tonic-gate if (tTd(64, 5)) 25040Sstevel@tonic-gate sm_dprintf("milter_negotiate(%s): version %d != MTA milter version %d\n", 25050Sstevel@tonic-gate m->mf_name, m->mf_fvers, SMFI_VERSION); 25060Sstevel@tonic-gate if (MilterLogLevel > 0) 25070Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 25080Sstevel@tonic-gate "Milter (%s): negotiate: version %d != MTA milter version %d", 25090Sstevel@tonic-gate m->mf_name, m->mf_fvers, SMFI_VERSION); 25100Sstevel@tonic-gate milter_error(m, e); 25113544Sjbeck goto error; 25120Sstevel@tonic-gate } 25130Sstevel@tonic-gate 25140Sstevel@tonic-gate /* check for filter feature mismatch */ 25153544Sjbeck if ((m->mf_fflags & mta_actions) != m->mf_fflags) 25160Sstevel@tonic-gate { 25170Sstevel@tonic-gate if (tTd(64, 5)) 25180Sstevel@tonic-gate sm_dprintf("milter_negotiate(%s): filter abilities 0x%x != MTA milter abilities 0x%lx\n", 25190Sstevel@tonic-gate m->mf_name, m->mf_fflags, 25203544Sjbeck (unsigned long) mta_actions); 25210Sstevel@tonic-gate if (MilterLogLevel > 0) 25220Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 25230Sstevel@tonic-gate "Milter (%s): negotiate: filter abilities 0x%x != MTA milter abilities 0x%lx", 25240Sstevel@tonic-gate m->mf_name, m->mf_fflags, 25253544Sjbeck (unsigned long) mta_actions); 25260Sstevel@tonic-gate milter_error(m, e); 25273544Sjbeck goto error; 25280Sstevel@tonic-gate } 25290Sstevel@tonic-gate 25300Sstevel@tonic-gate /* check for protocol feature mismatch */ 25313544Sjbeck if ((m->mf_pflags & mta_prot_flags) != m->mf_pflags) 25320Sstevel@tonic-gate { 25330Sstevel@tonic-gate if (tTd(64, 5)) 25340Sstevel@tonic-gate sm_dprintf("milter_negotiate(%s): protocol abilities 0x%x != MTA milter abilities 0x%lx\n", 25350Sstevel@tonic-gate m->mf_name, m->mf_pflags, 25363544Sjbeck (unsigned long) mta_prot_flags); 25370Sstevel@tonic-gate if (MilterLogLevel > 0) 25380Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 25390Sstevel@tonic-gate "Milter (%s): negotiate: protocol abilities 0x%x != MTA milter abilities 0x%lx", 25400Sstevel@tonic-gate m->mf_name, m->mf_pflags, 25413544Sjbeck (unsigned long) mta_prot_flags); 25420Sstevel@tonic-gate milter_error(m, e); 25433544Sjbeck goto error; 25440Sstevel@tonic-gate } 25450Sstevel@tonic-gate 2546616Sjbeck if (m->mf_fvers <= 2) 2547616Sjbeck m->mf_pflags |= SMFIP_NOUNKNOWN; 2548616Sjbeck if (m->mf_fvers <= 3) 2549616Sjbeck m->mf_pflags |= SMFIP_NODATA; 2550616Sjbeck 25513544Sjbeck if (rlen > MILTER_OPTLEN) 25523544Sjbeck { 25533544Sjbeck milter_getsymlist(m, response, rlen, MILTER_OPTLEN); 25543544Sjbeck } 25553544Sjbeck 2556*5402Sjbeck if (bitset(SMFIF_DELRCPT, m->mf_fflags)) 2557*5402Sjbeck milters->mis_flags |= MIS_FL_DEL_RCPT; 2558*5402Sjbeck if (!bitset(SMFIP_NORCPT, m->mf_pflags) && 2559*5402Sjbeck !bitset(SMFIP_NR_RCPT, m->mf_pflags)) 2560*5402Sjbeck milters->mis_flags |= MIS_FL_REJ_RCPT; 2561*5402Sjbeck 25620Sstevel@tonic-gate if (tTd(64, 5)) 25633544Sjbeck sm_dprintf("milter_negotiate(%s): received: version %u, fflags 0x%x, pflags 0x%x\n", 25640Sstevel@tonic-gate m->mf_name, m->mf_fvers, m->mf_fflags, m->mf_pflags); 25650Sstevel@tonic-gate return 0; 25663544Sjbeck 25673544Sjbeck error: 25683544Sjbeck if (response != NULL) 25693544Sjbeck sm_free(response); /* XXX */ 25703544Sjbeck return -1; 25710Sstevel@tonic-gate } 25723544Sjbeck 25730Sstevel@tonic-gate /* 25740Sstevel@tonic-gate ** MILTER_PER_CONNECTION_CHECK -- checks on per-connection commands 25750Sstevel@tonic-gate ** 25760Sstevel@tonic-gate ** Reduce code duplication by putting these checks in one place 25770Sstevel@tonic-gate ** 25780Sstevel@tonic-gate ** Parameters: 25790Sstevel@tonic-gate ** e -- current envelope. 25800Sstevel@tonic-gate ** 25810Sstevel@tonic-gate ** Returns: 25820Sstevel@tonic-gate ** none 25830Sstevel@tonic-gate */ 25840Sstevel@tonic-gate 25850Sstevel@tonic-gate static void 25860Sstevel@tonic-gate milter_per_connection_check(e) 25870Sstevel@tonic-gate ENVELOPE *e; 25880Sstevel@tonic-gate { 25890Sstevel@tonic-gate int i; 25900Sstevel@tonic-gate 25910Sstevel@tonic-gate /* see if we are done with any of the filters */ 25920Sstevel@tonic-gate for (i = 0; InputFilters[i] != NULL; i++) 25930Sstevel@tonic-gate { 25940Sstevel@tonic-gate struct milter *m = InputFilters[i]; 25950Sstevel@tonic-gate 25960Sstevel@tonic-gate if (m->mf_state == SMFS_CLOSABLE) 25970Sstevel@tonic-gate milter_quit_filter(m, e); 25980Sstevel@tonic-gate } 25990Sstevel@tonic-gate } 26003544Sjbeck 26010Sstevel@tonic-gate /* 26020Sstevel@tonic-gate ** MILTER_ERROR -- Put a milter filter into error state 26030Sstevel@tonic-gate ** 26040Sstevel@tonic-gate ** Parameters: 26050Sstevel@tonic-gate ** m -- the broken filter. 26060Sstevel@tonic-gate ** e -- current envelope. 26070Sstevel@tonic-gate ** 26080Sstevel@tonic-gate ** Returns: 26090Sstevel@tonic-gate ** none 26100Sstevel@tonic-gate */ 26110Sstevel@tonic-gate 26120Sstevel@tonic-gate static void 26130Sstevel@tonic-gate milter_error(m, e) 26140Sstevel@tonic-gate struct milter *m; 26150Sstevel@tonic-gate ENVELOPE *e; 26160Sstevel@tonic-gate { 26170Sstevel@tonic-gate /* 26180Sstevel@tonic-gate ** We could send a quit here but we may have gotten here due to 26190Sstevel@tonic-gate ** an I/O error so we don't want to try to make things worse. 26200Sstevel@tonic-gate */ 26210Sstevel@tonic-gate 26220Sstevel@tonic-gate if (m->mf_sock >= 0) 26230Sstevel@tonic-gate { 26240Sstevel@tonic-gate (void) close(m->mf_sock); 26250Sstevel@tonic-gate m->mf_sock = -1; 26260Sstevel@tonic-gate } 26270Sstevel@tonic-gate m->mf_state = SMFS_ERROR; 26280Sstevel@tonic-gate 26290Sstevel@tonic-gate if (MilterLogLevel > 0) 26300Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter (%s): to error state", 26310Sstevel@tonic-gate m->mf_name); 26320Sstevel@tonic-gate } 26333544Sjbeck 26340Sstevel@tonic-gate /* 26350Sstevel@tonic-gate ** MILTER_HEADERS -- send headers to a single milter filter 26360Sstevel@tonic-gate ** 26370Sstevel@tonic-gate ** Parameters: 26380Sstevel@tonic-gate ** m -- current filter. 26390Sstevel@tonic-gate ** e -- current envelope. 26400Sstevel@tonic-gate ** state -- return state from response. 26410Sstevel@tonic-gate ** 26420Sstevel@tonic-gate ** Returns: 26430Sstevel@tonic-gate ** response string (may be NULL) 26440Sstevel@tonic-gate */ 26450Sstevel@tonic-gate 26460Sstevel@tonic-gate static char * 26470Sstevel@tonic-gate milter_headers(m, e, state) 26480Sstevel@tonic-gate struct milter *m; 26490Sstevel@tonic-gate ENVELOPE *e; 26500Sstevel@tonic-gate char *state; 26510Sstevel@tonic-gate { 26520Sstevel@tonic-gate char *response = NULL; 26530Sstevel@tonic-gate HDR *h; 26540Sstevel@tonic-gate 26550Sstevel@tonic-gate if (MilterLogLevel > 17) 26560Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter (%s): headers, send", 26570Sstevel@tonic-gate m->mf_name); 26580Sstevel@tonic-gate 26590Sstevel@tonic-gate for (h = e->e_header; h != NULL; h = h->h_link) 26600Sstevel@tonic-gate { 26613544Sjbeck int len_n, len_v, len_t, len_f; 26623544Sjbeck char *buf, *hv; 26630Sstevel@tonic-gate 26640Sstevel@tonic-gate /* don't send over deleted headers */ 26650Sstevel@tonic-gate if (h->h_value == NULL) 26660Sstevel@tonic-gate { 26670Sstevel@tonic-gate /* strip H_USER so not counted in milter_changeheader() */ 26680Sstevel@tonic-gate h->h_flags &= ~H_USER; 26690Sstevel@tonic-gate continue; 26700Sstevel@tonic-gate } 26710Sstevel@tonic-gate 26720Sstevel@tonic-gate /* skip auto-generated */ 26730Sstevel@tonic-gate if (!bitset(H_USER, h->h_flags)) 26740Sstevel@tonic-gate continue; 26750Sstevel@tonic-gate 26760Sstevel@tonic-gate if (tTd(64, 10)) 26773544Sjbeck sm_dprintf("milter_headers: %s:%s\n", 26780Sstevel@tonic-gate h->h_field, h->h_value); 26790Sstevel@tonic-gate if (MilterLogLevel > 21) 26800Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter (%s): header, %s", 26810Sstevel@tonic-gate m->mf_name, h->h_field); 26820Sstevel@tonic-gate 26833544Sjbeck if (bitset(SMFIP_HDR_LEADSPC, m->mf_pflags) 26843544Sjbeck || *(h->h_value) != ' ') 26853544Sjbeck hv = h->h_value; 26863544Sjbeck else 26873544Sjbeck hv = h->h_value + 1; 26883544Sjbeck len_f = strlen(h->h_field) + 1; 26893544Sjbeck len_t = len_f + strlen(hv) + 1; 26903544Sjbeck if (len_t < 0) 26910Sstevel@tonic-gate continue; 26923544Sjbeck buf = (char *) xalloc(len_t); 26933544Sjbeck 26943544Sjbeck /* 26953544Sjbeck ** Note: currently the call to dequote_internal_chars() 26963544Sjbeck ** is not required as h_field is supposed to be 7-bit US-ASCII. 26973544Sjbeck */ 26983544Sjbeck 26993544Sjbeck len_n = dequote_internal_chars(h->h_field, buf, len_f); 27003544Sjbeck SM_ASSERT(len_n < len_f); 27013544Sjbeck len_v = dequote_internal_chars(hv, buf + len_n + 1, 27023544Sjbeck len_t - len_n - 1); 27033544Sjbeck SM_ASSERT(len_t >= len_n + 1 + len_v + 1); 27043544Sjbeck len_t = len_n + 1 + len_v + 1; 27050Sstevel@tonic-gate 27060Sstevel@tonic-gate /* send it over */ 27070Sstevel@tonic-gate response = milter_send_command(m, SMFIC_HEADER, buf, 27083544Sjbeck len_t, e, state, "header"); 27093544Sjbeck sm_free(buf); 27100Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR || 27110Sstevel@tonic-gate m->mf_state == SMFS_DONE || 27120Sstevel@tonic-gate *state != SMFIR_CONTINUE) 27130Sstevel@tonic-gate break; 27140Sstevel@tonic-gate } 27150Sstevel@tonic-gate if (MilterLogLevel > 17) 27160Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter (%s): headers, sent", 27170Sstevel@tonic-gate m->mf_name); 27180Sstevel@tonic-gate return response; 27190Sstevel@tonic-gate } 27203544Sjbeck 27210Sstevel@tonic-gate /* 27220Sstevel@tonic-gate ** MILTER_BODY -- send the body to a filter 27230Sstevel@tonic-gate ** 27240Sstevel@tonic-gate ** Parameters: 27250Sstevel@tonic-gate ** m -- current filter. 27260Sstevel@tonic-gate ** e -- current envelope. 27270Sstevel@tonic-gate ** state -- return state from response. 27280Sstevel@tonic-gate ** 27290Sstevel@tonic-gate ** Returns: 27300Sstevel@tonic-gate ** response string (may be NULL) 27310Sstevel@tonic-gate */ 27320Sstevel@tonic-gate 27330Sstevel@tonic-gate static char * 27340Sstevel@tonic-gate milter_body(m, e, state) 27350Sstevel@tonic-gate struct milter *m; 27360Sstevel@tonic-gate ENVELOPE *e; 27370Sstevel@tonic-gate char *state; 27380Sstevel@tonic-gate { 27390Sstevel@tonic-gate char bufchar = '\0'; 27400Sstevel@tonic-gate char prevchar = '\0'; 27410Sstevel@tonic-gate int c; 27420Sstevel@tonic-gate char *response = NULL; 27430Sstevel@tonic-gate char *bp; 27440Sstevel@tonic-gate char buf[MILTER_CHUNK_SIZE]; 27450Sstevel@tonic-gate 27460Sstevel@tonic-gate if (tTd(64, 10)) 27470Sstevel@tonic-gate sm_dprintf("milter_body\n"); 27480Sstevel@tonic-gate 27490Sstevel@tonic-gate if (bfrewind(e->e_dfp) < 0) 27500Sstevel@tonic-gate { 27510Sstevel@tonic-gate ExitStat = EX_IOERR; 27520Sstevel@tonic-gate *state = SMFIR_TEMPFAIL; 27530Sstevel@tonic-gate syserr("milter_body: %s/%cf%s: rewind error", 27540Sstevel@tonic-gate qid_printqueue(e->e_qgrp, e->e_qdir), 27550Sstevel@tonic-gate DATAFL_LETTER, e->e_id); 27560Sstevel@tonic-gate return NULL; 27570Sstevel@tonic-gate } 27580Sstevel@tonic-gate 27590Sstevel@tonic-gate if (MilterLogLevel > 17) 27600Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter (%s): body, send", 27610Sstevel@tonic-gate m->mf_name); 27620Sstevel@tonic-gate bp = buf; 27630Sstevel@tonic-gate while ((c = sm_io_getc(e->e_dfp, SM_TIME_DEFAULT)) != SM_IO_EOF) 27640Sstevel@tonic-gate { 27650Sstevel@tonic-gate /* Change LF to CRLF */ 27660Sstevel@tonic-gate if (c == '\n') 27670Sstevel@tonic-gate { 27683544Sjbeck #if !_FFR_MILTER_CONVERT_ALL_LF_TO_CRLF 27690Sstevel@tonic-gate /* Not a CRLF already? */ 27700Sstevel@tonic-gate if (prevchar != '\r') 27713544Sjbeck #endif /* !_FFR_MILTER_CONVERT_ALL_LF_TO_CRLF */ 27720Sstevel@tonic-gate { 27730Sstevel@tonic-gate /* Room for CR now? */ 27743544Sjbeck if (bp + 2 > &buf[sizeof(buf)]) 27750Sstevel@tonic-gate { 27760Sstevel@tonic-gate /* No room, buffer LF */ 27770Sstevel@tonic-gate bufchar = c; 27780Sstevel@tonic-gate 27790Sstevel@tonic-gate /* and send CR now */ 27800Sstevel@tonic-gate c = '\r'; 27810Sstevel@tonic-gate } 27820Sstevel@tonic-gate else 27830Sstevel@tonic-gate { 27840Sstevel@tonic-gate /* Room to do it now */ 27850Sstevel@tonic-gate *bp++ = '\r'; 27860Sstevel@tonic-gate prevchar = '\r'; 27870Sstevel@tonic-gate } 27880Sstevel@tonic-gate } 27890Sstevel@tonic-gate } 27900Sstevel@tonic-gate *bp++ = (char) c; 27910Sstevel@tonic-gate prevchar = c; 27923544Sjbeck if (bp >= &buf[sizeof(buf)]) 27930Sstevel@tonic-gate { 27940Sstevel@tonic-gate /* send chunk */ 27950Sstevel@tonic-gate response = milter_send_command(m, SMFIC_BODY, buf, 27963544Sjbeck bp - buf, e, state, 27973544Sjbeck "body chunk"); 27980Sstevel@tonic-gate bp = buf; 27990Sstevel@tonic-gate if (bufchar != '\0') 28000Sstevel@tonic-gate { 28010Sstevel@tonic-gate *bp++ = bufchar; 28020Sstevel@tonic-gate bufchar = '\0'; 28030Sstevel@tonic-gate prevchar = bufchar; 28040Sstevel@tonic-gate } 28050Sstevel@tonic-gate } 28060Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR || 28070Sstevel@tonic-gate m->mf_state == SMFS_DONE || 28083544Sjbeck m->mf_state == SMFS_SKIP || 28090Sstevel@tonic-gate *state != SMFIR_CONTINUE) 28100Sstevel@tonic-gate break; 28110Sstevel@tonic-gate } 28120Sstevel@tonic-gate 28130Sstevel@tonic-gate /* check for read errors */ 28140Sstevel@tonic-gate if (sm_io_error(e->e_dfp)) 28150Sstevel@tonic-gate { 28160Sstevel@tonic-gate ExitStat = EX_IOERR; 28170Sstevel@tonic-gate if (*state == SMFIR_CONTINUE || 28183544Sjbeck *state == SMFIR_ACCEPT || 28193544Sjbeck m->mf_state == SMFS_SKIP) 28200Sstevel@tonic-gate { 28210Sstevel@tonic-gate *state = SMFIR_TEMPFAIL; 28220Sstevel@tonic-gate if (response != NULL) 28230Sstevel@tonic-gate { 28240Sstevel@tonic-gate sm_free(response); /* XXX */ 28250Sstevel@tonic-gate response = NULL; 28260Sstevel@tonic-gate } 28270Sstevel@tonic-gate } 28280Sstevel@tonic-gate syserr("milter_body: %s/%cf%s: read error", 28290Sstevel@tonic-gate qid_printqueue(e->e_qgrp, e->e_qdir), 28300Sstevel@tonic-gate DATAFL_LETTER, e->e_id); 28310Sstevel@tonic-gate return response; 28320Sstevel@tonic-gate } 28330Sstevel@tonic-gate 28340Sstevel@tonic-gate /* send last body chunk */ 28350Sstevel@tonic-gate if (bp > buf && 28360Sstevel@tonic-gate m->mf_state != SMFS_ERROR && 28370Sstevel@tonic-gate m->mf_state != SMFS_DONE && 28383544Sjbeck m->mf_state != SMFS_SKIP && 28390Sstevel@tonic-gate *state == SMFIR_CONTINUE) 28400Sstevel@tonic-gate { 28410Sstevel@tonic-gate /* send chunk */ 28420Sstevel@tonic-gate response = milter_send_command(m, SMFIC_BODY, buf, bp - buf, 28433544Sjbeck e, state, "last body chunk"); 28440Sstevel@tonic-gate bp = buf; 28450Sstevel@tonic-gate } 28460Sstevel@tonic-gate if (MilterLogLevel > 17) 28470Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter (%s): body, sent", 28480Sstevel@tonic-gate m->mf_name); 28493544Sjbeck if (m->mf_state == SMFS_SKIP) 28503544Sjbeck { 28513544Sjbeck *state = SMFIR_CONTINUE; 28523544Sjbeck m->mf_state = SMFS_READY; 28533544Sjbeck } 28543544Sjbeck 28550Sstevel@tonic-gate return response; 28560Sstevel@tonic-gate } 28570Sstevel@tonic-gate 28580Sstevel@tonic-gate /* 28590Sstevel@tonic-gate ** Actions 28600Sstevel@tonic-gate */ 28610Sstevel@tonic-gate 28620Sstevel@tonic-gate /* 28633544Sjbeck ** ADDLEADINGSPACE -- Add a leading space to a string 28643544Sjbeck ** 28653544Sjbeck ** Parameters: 28663544Sjbeck ** str -- string 28673544Sjbeck ** rp -- resource pool for allocations 28683544Sjbeck ** 28693544Sjbeck ** Returns: 28703544Sjbeck ** pointer to new string 28713544Sjbeck */ 28723544Sjbeck 28733544Sjbeck static char *addleadingspace __P((char *, SM_RPOOL_T *)); 28743544Sjbeck 28753544Sjbeck static char * 28763544Sjbeck addleadingspace(str, rp) 28773544Sjbeck char *str; 28783544Sjbeck SM_RPOOL_T *rp; 28793544Sjbeck { 28803544Sjbeck size_t l; 28813544Sjbeck char *new; 28823544Sjbeck 28833544Sjbeck SM_ASSERT(str != NULL); 28843544Sjbeck l = strlen(str); 28853544Sjbeck SM_ASSERT(l + 2 > l); 28863544Sjbeck new = sm_rpool_malloc_x(rp, l + 2); 28873544Sjbeck new[0] = ' '; 28883544Sjbeck new[1] = '\0'; 28893544Sjbeck sm_strlcpy(new + 1, str, l + 1); 28903544Sjbeck return new; 28913544Sjbeck } 28923544Sjbeck 28933544Sjbeck /* 28940Sstevel@tonic-gate ** MILTER_ADDHEADER -- Add the supplied header to the message 28950Sstevel@tonic-gate ** 28960Sstevel@tonic-gate ** Parameters: 28973544Sjbeck ** m -- current filter. 28980Sstevel@tonic-gate ** response -- encoded form of header/value. 28990Sstevel@tonic-gate ** rlen -- length of response. 29000Sstevel@tonic-gate ** e -- current envelope. 29010Sstevel@tonic-gate ** 29020Sstevel@tonic-gate ** Returns: 29030Sstevel@tonic-gate ** none 29040Sstevel@tonic-gate */ 29050Sstevel@tonic-gate 29060Sstevel@tonic-gate static void 29073544Sjbeck milter_addheader(m, response, rlen, e) 29083544Sjbeck struct milter *m; 29090Sstevel@tonic-gate char *response; 29100Sstevel@tonic-gate ssize_t rlen; 29110Sstevel@tonic-gate ENVELOPE *e; 29120Sstevel@tonic-gate { 29133544Sjbeck int mh_v_len; 29143544Sjbeck char *val, *mh_value; 29150Sstevel@tonic-gate HDR *h; 29160Sstevel@tonic-gate 29170Sstevel@tonic-gate if (tTd(64, 10)) 29180Sstevel@tonic-gate sm_dprintf("milter_addheader: "); 29190Sstevel@tonic-gate 29200Sstevel@tonic-gate /* sanity checks */ 29210Sstevel@tonic-gate if (response == NULL) 29220Sstevel@tonic-gate { 29230Sstevel@tonic-gate if (tTd(64, 10)) 29240Sstevel@tonic-gate sm_dprintf("NULL response\n"); 29250Sstevel@tonic-gate return; 29260Sstevel@tonic-gate } 29270Sstevel@tonic-gate 29280Sstevel@tonic-gate if (rlen < 2 || strlen(response) + 1 >= (size_t) rlen) 29290Sstevel@tonic-gate { 29300Sstevel@tonic-gate if (tTd(64, 10)) 29313544Sjbeck sm_dprintf("didn't follow protocol (total len %d != rlen %d)\n", 29323544Sjbeck (int) strlen(response), (int) (rlen - 1)); 29330Sstevel@tonic-gate return; 29340Sstevel@tonic-gate } 29350Sstevel@tonic-gate 29360Sstevel@tonic-gate /* Find separating NUL */ 29370Sstevel@tonic-gate val = response + strlen(response) + 1; 29380Sstevel@tonic-gate 29390Sstevel@tonic-gate /* another sanity check */ 29400Sstevel@tonic-gate if (strlen(response) + strlen(val) + 2 != (size_t) rlen) 29410Sstevel@tonic-gate { 29420Sstevel@tonic-gate if (tTd(64, 10)) 29430Sstevel@tonic-gate sm_dprintf("didn't follow protocol (part len)\n"); 29440Sstevel@tonic-gate return; 29450Sstevel@tonic-gate } 29460Sstevel@tonic-gate 29470Sstevel@tonic-gate if (*response == '\0') 29480Sstevel@tonic-gate { 29490Sstevel@tonic-gate if (tTd(64, 10)) 29500Sstevel@tonic-gate sm_dprintf("empty field name\n"); 29510Sstevel@tonic-gate return; 29520Sstevel@tonic-gate } 29530Sstevel@tonic-gate 29540Sstevel@tonic-gate for (h = e->e_header; h != NULL; h = h->h_link) 29550Sstevel@tonic-gate { 29560Sstevel@tonic-gate if (sm_strcasecmp(h->h_field, response) == 0 && 29570Sstevel@tonic-gate !bitset(H_USER, h->h_flags) && 29580Sstevel@tonic-gate !bitset(H_TRACE, h->h_flags)) 29590Sstevel@tonic-gate break; 29600Sstevel@tonic-gate } 29610Sstevel@tonic-gate 29623544Sjbeck mh_v_len = 0; 29633544Sjbeck mh_value = quote_internal_chars(val, NULL, &mh_v_len); 29643544Sjbeck 29650Sstevel@tonic-gate /* add to e_msgsize */ 29660Sstevel@tonic-gate e->e_msgsize += strlen(response) + 2 + strlen(val); 29670Sstevel@tonic-gate 29680Sstevel@tonic-gate if (h != NULL) 29690Sstevel@tonic-gate { 29700Sstevel@tonic-gate if (tTd(64, 10)) 29710Sstevel@tonic-gate sm_dprintf("Replace default header %s value with %s\n", 29723544Sjbeck h->h_field, mh_value); 29730Sstevel@tonic-gate if (MilterLogLevel > 8) 29740Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 29750Sstevel@tonic-gate "Milter change: default header %s value with %s", 29763544Sjbeck h->h_field, mh_value); 29773544Sjbeck if (bitset(SMFIP_HDR_LEADSPC, m->mf_pflags)) 29783544Sjbeck h->h_value = mh_value; 29793544Sjbeck else 29803544Sjbeck { 29813544Sjbeck h->h_value = addleadingspace (mh_value, e->e_rpool); 29823544Sjbeck SM_FREE(mh_value); 29833544Sjbeck } 29840Sstevel@tonic-gate h->h_flags |= H_USER; 29850Sstevel@tonic-gate } 29860Sstevel@tonic-gate else 29870Sstevel@tonic-gate { 29880Sstevel@tonic-gate if (tTd(64, 10)) 29893544Sjbeck sm_dprintf("Add %s: %s\n", response, mh_value); 29900Sstevel@tonic-gate if (MilterLogLevel > 8) 29913544Sjbeck sm_syslog(LOG_INFO, e->e_id, 29923544Sjbeck "Milter add: header: %s: %s", 29933544Sjbeck response, mh_value); 29943544Sjbeck addheader(newstr(response), mh_value, H_USER, e, 29953544Sjbeck !bitset(SMFIP_HDR_LEADSPC, m->mf_pflags)); 29963544Sjbeck SM_FREE(mh_value); 29970Sstevel@tonic-gate } 29980Sstevel@tonic-gate } 29993544Sjbeck 30000Sstevel@tonic-gate /* 30010Sstevel@tonic-gate ** MILTER_INSHEADER -- Insert the supplied header 30020Sstevel@tonic-gate ** 30030Sstevel@tonic-gate ** Parameters: 30043544Sjbeck ** m -- current filter. 30050Sstevel@tonic-gate ** response -- encoded form of header/value. 30060Sstevel@tonic-gate ** rlen -- length of response. 30070Sstevel@tonic-gate ** e -- current envelope. 30080Sstevel@tonic-gate ** 30090Sstevel@tonic-gate ** Returns: 30100Sstevel@tonic-gate ** none 30110Sstevel@tonic-gate ** 3012616Sjbeck ** Notes: 3013616Sjbeck ** Unlike milter_addheader(), this does not attempt to determine 3014616Sjbeck ** if the header already exists in the envelope, even a 3015616Sjbeck ** deleted version. It just blindly inserts. 30160Sstevel@tonic-gate */ 30170Sstevel@tonic-gate 30180Sstevel@tonic-gate static void 30193544Sjbeck milter_insheader(m, response, rlen, e) 30203544Sjbeck struct milter *m; 30210Sstevel@tonic-gate char *response; 30220Sstevel@tonic-gate ssize_t rlen; 30230Sstevel@tonic-gate ENVELOPE *e; 30240Sstevel@tonic-gate { 30250Sstevel@tonic-gate mi_int32 idx, i; 30263544Sjbeck int mh_v_len; 30273544Sjbeck char *field, *val, *mh_value; 30280Sstevel@tonic-gate 30290Sstevel@tonic-gate if (tTd(64, 10)) 30300Sstevel@tonic-gate sm_dprintf("milter_insheader: "); 30310Sstevel@tonic-gate 30320Sstevel@tonic-gate /* sanity checks */ 30330Sstevel@tonic-gate if (response == NULL) 30340Sstevel@tonic-gate { 30350Sstevel@tonic-gate if (tTd(64, 10)) 30360Sstevel@tonic-gate sm_dprintf("NULL response\n"); 30370Sstevel@tonic-gate return; 30380Sstevel@tonic-gate } 30390Sstevel@tonic-gate 30400Sstevel@tonic-gate if (rlen < 2 || strlen(response) + 1 >= (size_t) rlen) 30410Sstevel@tonic-gate { 30420Sstevel@tonic-gate if (tTd(64, 10)) 30430Sstevel@tonic-gate sm_dprintf("didn't follow protocol (total len)\n"); 30440Sstevel@tonic-gate return; 30450Sstevel@tonic-gate } 30460Sstevel@tonic-gate 30470Sstevel@tonic-gate /* decode */ 30480Sstevel@tonic-gate (void) memcpy((char *) &i, response, MILTER_LEN_BYTES); 30490Sstevel@tonic-gate idx = ntohl(i); 30500Sstevel@tonic-gate field = response + MILTER_LEN_BYTES; 30510Sstevel@tonic-gate val = field + strlen(field) + 1; 30520Sstevel@tonic-gate 30530Sstevel@tonic-gate /* another sanity check */ 30540Sstevel@tonic-gate if (MILTER_LEN_BYTES + strlen(field) + 1 + 30550Sstevel@tonic-gate strlen(val) + 1 != (size_t) rlen) 30560Sstevel@tonic-gate { 30570Sstevel@tonic-gate if (tTd(64, 10)) 30580Sstevel@tonic-gate sm_dprintf("didn't follow protocol (part len)\n"); 30590Sstevel@tonic-gate return; 30600Sstevel@tonic-gate } 30610Sstevel@tonic-gate 30620Sstevel@tonic-gate if (*field == '\0') 30630Sstevel@tonic-gate { 30640Sstevel@tonic-gate if (tTd(64, 10)) 30650Sstevel@tonic-gate sm_dprintf("empty field name\n"); 30660Sstevel@tonic-gate return; 30670Sstevel@tonic-gate } 30680Sstevel@tonic-gate 30690Sstevel@tonic-gate /* add to e_msgsize */ 30700Sstevel@tonic-gate e->e_msgsize += strlen(response) + 2 + strlen(val); 30710Sstevel@tonic-gate 30720Sstevel@tonic-gate if (tTd(64, 10)) 30733544Sjbeck sm_dprintf("Insert (%d) %s: %s\n", idx, field, val); 30740Sstevel@tonic-gate if (MilterLogLevel > 8) 30750Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 3076616Sjbeck "Milter insert (%d): header: %s: %s", 30770Sstevel@tonic-gate idx, field, val); 30783544Sjbeck mh_v_len = 0; 30793544Sjbeck mh_value = quote_internal_chars(val, NULL, &mh_v_len); 30803544Sjbeck insheader(idx, newstr(field), mh_value, H_USER, e, 30813544Sjbeck !bitset(SMFIP_HDR_LEADSPC, m->mf_pflags)); 30823544Sjbeck SM_FREE(mh_value); 30830Sstevel@tonic-gate } 30843544Sjbeck 30850Sstevel@tonic-gate /* 30860Sstevel@tonic-gate ** MILTER_CHANGEHEADER -- Change the supplied header in the message 30870Sstevel@tonic-gate ** 30880Sstevel@tonic-gate ** Parameters: 30893544Sjbeck ** m -- current filter. 30900Sstevel@tonic-gate ** response -- encoded form of header/index/value. 30910Sstevel@tonic-gate ** rlen -- length of response. 30920Sstevel@tonic-gate ** e -- current envelope. 30930Sstevel@tonic-gate ** 30940Sstevel@tonic-gate ** Returns: 30950Sstevel@tonic-gate ** none 30960Sstevel@tonic-gate */ 30970Sstevel@tonic-gate 30980Sstevel@tonic-gate static void 30993544Sjbeck milter_changeheader(m, response, rlen, e) 31003544Sjbeck struct milter *m; 31010Sstevel@tonic-gate char *response; 31020Sstevel@tonic-gate ssize_t rlen; 31030Sstevel@tonic-gate ENVELOPE *e; 31040Sstevel@tonic-gate { 31050Sstevel@tonic-gate mi_int32 i, index; 31063544Sjbeck int mh_v_len; 31073544Sjbeck char *field, *val, *mh_value; 31080Sstevel@tonic-gate HDR *h, *sysheader; 31090Sstevel@tonic-gate 31100Sstevel@tonic-gate if (tTd(64, 10)) 31110Sstevel@tonic-gate sm_dprintf("milter_changeheader: "); 31120Sstevel@tonic-gate 31130Sstevel@tonic-gate /* sanity checks */ 31140Sstevel@tonic-gate if (response == NULL) 31150Sstevel@tonic-gate { 31160Sstevel@tonic-gate if (tTd(64, 10)) 31170Sstevel@tonic-gate sm_dprintf("NULL response\n"); 31180Sstevel@tonic-gate return; 31190Sstevel@tonic-gate } 31200Sstevel@tonic-gate 31210Sstevel@tonic-gate if (rlen < 2 || strlen(response) + 1 >= (size_t) rlen) 31220Sstevel@tonic-gate { 31230Sstevel@tonic-gate if (tTd(64, 10)) 31240Sstevel@tonic-gate sm_dprintf("didn't follow protocol (total len)\n"); 31250Sstevel@tonic-gate return; 31260Sstevel@tonic-gate } 31270Sstevel@tonic-gate 31280Sstevel@tonic-gate /* Find separating NUL */ 31290Sstevel@tonic-gate (void) memcpy((char *) &i, response, MILTER_LEN_BYTES); 31300Sstevel@tonic-gate index = ntohl(i); 31310Sstevel@tonic-gate field = response + MILTER_LEN_BYTES; 31320Sstevel@tonic-gate val = field + strlen(field) + 1; 31330Sstevel@tonic-gate 31340Sstevel@tonic-gate /* another sanity check */ 31350Sstevel@tonic-gate if (MILTER_LEN_BYTES + strlen(field) + 1 + 31360Sstevel@tonic-gate strlen(val) + 1 != (size_t) rlen) 31370Sstevel@tonic-gate { 31380Sstevel@tonic-gate if (tTd(64, 10)) 31390Sstevel@tonic-gate sm_dprintf("didn't follow protocol (part len)\n"); 31400Sstevel@tonic-gate return; 31410Sstevel@tonic-gate } 31420Sstevel@tonic-gate 31430Sstevel@tonic-gate if (*field == '\0') 31440Sstevel@tonic-gate { 31450Sstevel@tonic-gate if (tTd(64, 10)) 31460Sstevel@tonic-gate sm_dprintf("empty field name\n"); 31470Sstevel@tonic-gate return; 31480Sstevel@tonic-gate } 31490Sstevel@tonic-gate 31503544Sjbeck mh_v_len = 0; 31513544Sjbeck mh_value = quote_internal_chars(val, NULL, &mh_v_len); 31523544Sjbeck 31530Sstevel@tonic-gate sysheader = NULL; 31540Sstevel@tonic-gate for (h = e->e_header; h != NULL; h = h->h_link) 31550Sstevel@tonic-gate { 31560Sstevel@tonic-gate if (sm_strcasecmp(h->h_field, field) == 0) 31570Sstevel@tonic-gate { 31583544Sjbeck if (bitset(H_USER, h->h_flags) && --index <= 0) 31590Sstevel@tonic-gate { 31600Sstevel@tonic-gate sysheader = NULL; 31610Sstevel@tonic-gate break; 31620Sstevel@tonic-gate } 31630Sstevel@tonic-gate else if (!bitset(H_USER, h->h_flags) && 31640Sstevel@tonic-gate !bitset(H_TRACE, h->h_flags)) 31650Sstevel@tonic-gate { 31660Sstevel@tonic-gate /* 31670Sstevel@tonic-gate ** DRUMS msg-fmt draft says can only have 31680Sstevel@tonic-gate ** multiple occurences of trace fields, 31690Sstevel@tonic-gate ** so make sure we replace any non-trace, 31700Sstevel@tonic-gate ** non-user field. 31710Sstevel@tonic-gate */ 31720Sstevel@tonic-gate 31730Sstevel@tonic-gate sysheader = h; 31740Sstevel@tonic-gate } 31750Sstevel@tonic-gate } 31760Sstevel@tonic-gate } 31770Sstevel@tonic-gate 31780Sstevel@tonic-gate /* if not found as user-provided header at index, use sysheader */ 31790Sstevel@tonic-gate if (h == NULL) 31800Sstevel@tonic-gate h = sysheader; 31810Sstevel@tonic-gate 31820Sstevel@tonic-gate if (h == NULL) 31830Sstevel@tonic-gate { 31840Sstevel@tonic-gate if (*val == '\0') 31850Sstevel@tonic-gate { 31860Sstevel@tonic-gate if (tTd(64, 10)) 31870Sstevel@tonic-gate sm_dprintf("Delete (noop) %s\n", field); 31880Sstevel@tonic-gate if (MilterLogLevel > 8) 31890Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 31900Sstevel@tonic-gate "Milter delete (noop): header: %s" 31910Sstevel@tonic-gate , field); 31920Sstevel@tonic-gate } 31930Sstevel@tonic-gate else 31940Sstevel@tonic-gate { 31950Sstevel@tonic-gate /* treat modify value with no existing header as add */ 31960Sstevel@tonic-gate if (tTd(64, 10)) 31973544Sjbeck sm_dprintf("Add %s: %s\n", field, mh_value); 31980Sstevel@tonic-gate if (MilterLogLevel > 8) 31990Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 32000Sstevel@tonic-gate "Milter change (add): header: %s: %s" 32013544Sjbeck , field, mh_value); 32023544Sjbeck addheader(newstr(field), mh_value, H_USER, e, 32033544Sjbeck !bitset(SMFIP_HDR_LEADSPC, m->mf_pflags)); 32040Sstevel@tonic-gate } 32050Sstevel@tonic-gate return; 32060Sstevel@tonic-gate } 32070Sstevel@tonic-gate 32080Sstevel@tonic-gate if (tTd(64, 10)) 32090Sstevel@tonic-gate { 32100Sstevel@tonic-gate if (*val == '\0') 32110Sstevel@tonic-gate { 32123544Sjbeck sm_dprintf("Delete%s %s:%s\n", 32130Sstevel@tonic-gate h == sysheader ? " (default header)" : "", 32140Sstevel@tonic-gate field, 32150Sstevel@tonic-gate h->h_value == NULL ? "<NULL>" : h->h_value); 32160Sstevel@tonic-gate } 32170Sstevel@tonic-gate else 32180Sstevel@tonic-gate { 32190Sstevel@tonic-gate sm_dprintf("Change%s %s: from %s to %s\n", 32200Sstevel@tonic-gate h == sysheader ? " (default header)" : "", 32210Sstevel@tonic-gate field, 32220Sstevel@tonic-gate h->h_value == NULL ? "<NULL>" : h->h_value, 32233544Sjbeck mh_value); 32240Sstevel@tonic-gate } 32250Sstevel@tonic-gate } 32260Sstevel@tonic-gate 32270Sstevel@tonic-gate if (MilterLogLevel > 8) 32280Sstevel@tonic-gate { 32290Sstevel@tonic-gate if (*val == '\0') 32300Sstevel@tonic-gate { 32310Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 32323544Sjbeck "Milter delete: header%s %s:%s", 32330Sstevel@tonic-gate h == sysheader ? " (default header)" : "", 32340Sstevel@tonic-gate field, 32350Sstevel@tonic-gate h->h_value == NULL ? "<NULL>" : h->h_value); 32360Sstevel@tonic-gate } 32370Sstevel@tonic-gate else 32380Sstevel@tonic-gate { 32390Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 32400Sstevel@tonic-gate "Milter change: header%s %s: from %s to %s", 32410Sstevel@tonic-gate h == sysheader ? " (default header)" : "", 32420Sstevel@tonic-gate field, 32430Sstevel@tonic-gate h->h_value == NULL ? "<NULL>" : h->h_value, 32443544Sjbeck mh_value); 32450Sstevel@tonic-gate } 32460Sstevel@tonic-gate } 32470Sstevel@tonic-gate 32480Sstevel@tonic-gate if (h != sysheader && h->h_value != NULL) 32490Sstevel@tonic-gate { 32500Sstevel@tonic-gate size_t l; 32510Sstevel@tonic-gate 32520Sstevel@tonic-gate l = strlen(h->h_value); 32530Sstevel@tonic-gate if (l > e->e_msgsize) 32540Sstevel@tonic-gate e->e_msgsize = 0; 32550Sstevel@tonic-gate else 32560Sstevel@tonic-gate e->e_msgsize -= l; 32570Sstevel@tonic-gate /* rpool, don't free: sm_free(h->h_value); XXX */ 32580Sstevel@tonic-gate } 32590Sstevel@tonic-gate 32600Sstevel@tonic-gate if (*val == '\0') 32610Sstevel@tonic-gate { 32620Sstevel@tonic-gate /* Remove "Field: " from message size */ 32630Sstevel@tonic-gate if (h != sysheader) 32640Sstevel@tonic-gate { 32650Sstevel@tonic-gate size_t l; 32660Sstevel@tonic-gate 32670Sstevel@tonic-gate l = strlen(h->h_field) + 2; 32680Sstevel@tonic-gate if (l > e->e_msgsize) 32690Sstevel@tonic-gate e->e_msgsize = 0; 32700Sstevel@tonic-gate else 32710Sstevel@tonic-gate e->e_msgsize -= l; 32720Sstevel@tonic-gate } 32730Sstevel@tonic-gate h->h_value = NULL; 32743544Sjbeck SM_FREE(mh_value); 32750Sstevel@tonic-gate } 32760Sstevel@tonic-gate else 32770Sstevel@tonic-gate { 32783544Sjbeck if (bitset(SMFIP_HDR_LEADSPC, m->mf_pflags)) 32793544Sjbeck h->h_value = mh_value; 32803544Sjbeck else 32813544Sjbeck { 32823544Sjbeck h->h_value = addleadingspace (mh_value, e->e_rpool); 32833544Sjbeck SM_FREE(mh_value); 32843544Sjbeck } 32850Sstevel@tonic-gate h->h_flags |= H_USER; 32860Sstevel@tonic-gate e->e_msgsize += strlen(h->h_value); 32870Sstevel@tonic-gate } 32880Sstevel@tonic-gate } 32893544Sjbeck 32903544Sjbeck /* 32913544Sjbeck ** MILTER_SPLIT_RESPONSE -- Split response into fields. 32923544Sjbeck ** 32933544Sjbeck ** Parameters: 32943544Sjbeck ** response -- encoded repsonse. 32953544Sjbeck ** rlen -- length of response. 32963544Sjbeck ** pargc -- number of arguments (ouput) 32973544Sjbeck ** 32983544Sjbeck ** Returns: 32993544Sjbeck ** array of pointers to the individual strings 33003544Sjbeck */ 33013544Sjbeck 33023544Sjbeck static char **milter_split_response __P((char *, ssize_t, int *)); 33033544Sjbeck 33043544Sjbeck static char ** 33053544Sjbeck milter_split_response(response, rlen, pargc) 33063544Sjbeck char *response; 33073544Sjbeck ssize_t rlen; 33083544Sjbeck int *pargc; 33093544Sjbeck { 33103544Sjbeck char **s; 33113544Sjbeck size_t i; 33123544Sjbeck int elem, nelem; 33133544Sjbeck 33143544Sjbeck SM_ASSERT(response != NULL); 33153544Sjbeck SM_ASSERT(pargc != NULL); 33163544Sjbeck *pargc = 0; 33173544Sjbeck if (rlen < 2 || strlen(response) >= (size_t) rlen) 33183544Sjbeck { 33193544Sjbeck if (tTd(64, 10)) 33203544Sjbeck sm_dprintf("didn't follow protocol (total len %d != rlen %d)\n", 33213544Sjbeck (int) strlen(response), (int) (rlen - 1)); 33223544Sjbeck return NULL; 33233544Sjbeck } 33243544Sjbeck 33253544Sjbeck nelem = 0; 33263544Sjbeck for (i = 0; i < rlen; i++) 33273544Sjbeck { 33283544Sjbeck if (response[i] == '\0') 33293544Sjbeck ++nelem; 33303544Sjbeck } 33313544Sjbeck if (nelem == 0) 33323544Sjbeck return NULL; 33333544Sjbeck 33343544Sjbeck /* last entry is only for the name */ 33353544Sjbeck s = (char **)malloc(nelem * (sizeof(*s))); 33363544Sjbeck if (s == NULL) 33373544Sjbeck return NULL; 33383544Sjbeck s[0] = response; 33393544Sjbeck for (i = 0, elem = 0; i < rlen && elem < nelem; i++) 33403544Sjbeck { 33413544Sjbeck if (response[i] == '\0') 33423544Sjbeck { 33433544Sjbeck ++elem; 33443544Sjbeck if (i + 1 >= rlen) 33453544Sjbeck s[elem] = NULL; 33463544Sjbeck else 33473544Sjbeck s[elem] = &(response[i + 1]); 33483544Sjbeck } 33493544Sjbeck } 33503544Sjbeck *pargc = nelem; 33513544Sjbeck 33523544Sjbeck if (tTd(64, 10)) 33533544Sjbeck { 33543544Sjbeck for (elem = 0; elem < nelem; elem++) 33553544Sjbeck sm_dprintf("argv[%d]=\"%s\"\n", elem, s[elem]); 33563544Sjbeck } 33573544Sjbeck 33583544Sjbeck /* overwrite last entry (already done above, just paranoia) */ 33593544Sjbeck s[elem] = NULL; 33603544Sjbeck return s; 33613544Sjbeck } 33623544Sjbeck 33633544Sjbeck /* 33643544Sjbeck ** MILTER_CHGFROM -- Change the envelope sender address 33653544Sjbeck ** 33663544Sjbeck ** Parameters: 33673544Sjbeck ** response -- encoded form of recipient address. 33683544Sjbeck ** rlen -- length of response. 33693544Sjbeck ** e -- current envelope. 33703544Sjbeck ** 33713544Sjbeck ** Returns: 33723544Sjbeck ** none 33733544Sjbeck */ 33743544Sjbeck 33753544Sjbeck static void 33763544Sjbeck milter_chgfrom(response, rlen, e) 33773544Sjbeck char *response; 33783544Sjbeck ssize_t rlen; 33793544Sjbeck ENVELOPE *e; 33803544Sjbeck { 33813544Sjbeck int olderrors, argc; 33823544Sjbeck char **argv; 33833544Sjbeck 33843544Sjbeck if (tTd(64, 10)) 33853544Sjbeck sm_dprintf("milter_chgfrom: "); 33863544Sjbeck 33873544Sjbeck /* sanity checks */ 33883544Sjbeck if (response == NULL) 33893544Sjbeck { 33903544Sjbeck if (tTd(64, 10)) 33913544Sjbeck sm_dprintf("NULL response\n"); 33923544Sjbeck return; 33933544Sjbeck } 33943544Sjbeck 33953544Sjbeck if (*response == '\0' || 33963544Sjbeck strlen(response) + 1 > (size_t) rlen) 33973544Sjbeck { 33983544Sjbeck if (tTd(64, 10)) 33993544Sjbeck sm_dprintf("didn't follow protocol (total len %d != rlen %d)\n", 34003544Sjbeck (int) strlen(response), (int) (rlen - 1)); 34013544Sjbeck return; 34023544Sjbeck } 34033544Sjbeck 34043544Sjbeck if (tTd(64, 10)) 34053544Sjbeck sm_dprintf("%s\n", response); 34063544Sjbeck if (MilterLogLevel > 8) 34073544Sjbeck sm_syslog(LOG_INFO, e->e_id, "Milter chgfrom: %s", response); 34083544Sjbeck argv = milter_split_response(response, rlen, &argc); 34093544Sjbeck if (argc < 1 || argc > 2) 34103544Sjbeck { 34113544Sjbeck if (tTd(64, 10)) 34123544Sjbeck sm_dprintf("didn't follow protocol argc=%d\n", argc); 34133544Sjbeck return; 34143544Sjbeck } 34153544Sjbeck 34163544Sjbeck olderrors = Errors; 34173544Sjbeck setsender(argv[0], e, NULL, '\0', false); 34183544Sjbeck if (argc == 2) 34193544Sjbeck { 34203544Sjbeck reset_mail_esmtp_args(e); 34213544Sjbeck 34223544Sjbeck /* 34233544Sjbeck ** need "features" here: how to get those? via e? 34243544Sjbeck ** "fake" it for now: allow everything. 34253544Sjbeck */ 34263544Sjbeck 34273544Sjbeck parse_esmtp_args(e, NULL, argv[0], argv[1], "MAIL", NULL, 34283544Sjbeck mail_esmtp_args); 34293544Sjbeck } 34303544Sjbeck Errors = olderrors; 34313544Sjbeck return; 34323544Sjbeck } 34333544Sjbeck 34343544Sjbeck /* 34353544Sjbeck ** MILTER_ADDRCPT_PAR -- Add the supplied recipient to the message 34363544Sjbeck ** 34373544Sjbeck ** Parameters: 34383544Sjbeck ** response -- encoded form of recipient address. 34393544Sjbeck ** rlen -- length of response. 34403544Sjbeck ** e -- current envelope. 34413544Sjbeck ** 34423544Sjbeck ** Returns: 34433544Sjbeck ** none 34443544Sjbeck */ 34453544Sjbeck 34463544Sjbeck static void 34473544Sjbeck milter_addrcpt_par(response, rlen, e) 34483544Sjbeck char *response; 34493544Sjbeck ssize_t rlen; 34503544Sjbeck ENVELOPE *e; 34513544Sjbeck { 34523544Sjbeck int olderrors, argc; 34533544Sjbeck char *delimptr; 34543544Sjbeck char **argv; 34553544Sjbeck ADDRESS *a; 34563544Sjbeck 34573544Sjbeck if (tTd(64, 10)) 34583544Sjbeck sm_dprintf("milter_addrcpt_par: "); 34593544Sjbeck 34603544Sjbeck /* sanity checks */ 34613544Sjbeck if (response == NULL) 34623544Sjbeck { 34633544Sjbeck if (tTd(64, 10)) 34643544Sjbeck sm_dprintf("NULL response\n"); 34653544Sjbeck return; 34663544Sjbeck } 34673544Sjbeck 34683544Sjbeck if (tTd(64, 10)) 34693544Sjbeck sm_dprintf("%s\n", response); 34703544Sjbeck if (MilterLogLevel > 8) 34713544Sjbeck sm_syslog(LOG_INFO, e->e_id, "Milter add: rcpt: %s", response); 34723544Sjbeck 34733544Sjbeck argv = milter_split_response(response, rlen, &argc); 34743544Sjbeck if (argc < 1 || argc > 2) 34753544Sjbeck { 34763544Sjbeck if (tTd(64, 10)) 34773544Sjbeck sm_dprintf("didn't follow protocol argc=%d\n", argc); 34783544Sjbeck return; 34793544Sjbeck } 34803544Sjbeck olderrors = Errors; 34813544Sjbeck 34823544Sjbeck /* how to set ESMTP arguments? */ 34833544Sjbeck a = parseaddr(argv[0], NULLADDR, RF_COPYALL, ' ', &delimptr, e, true); 34843544Sjbeck 34853544Sjbeck if (a != NULL && olderrors == Errors) 34863544Sjbeck { 34873544Sjbeck parse_esmtp_args(e, a, argv[0], argv[1], "RCPT", NULL, 34883544Sjbeck rcpt_esmtp_args); 34893544Sjbeck if (olderrors == Errors) 34903544Sjbeck a = recipient(a, &e->e_sendqueue, 0, e); 34913544Sjbeck else 34923544Sjbeck sm_dprintf("olderrors=%d, Errors=%d\n", 34933544Sjbeck olderrors, Errors); 34943544Sjbeck } 34953544Sjbeck else 34963544Sjbeck { 34973544Sjbeck sm_dprintf("a=%p, olderrors=%d, Errors=%d\n", 34983544Sjbeck a, olderrors, Errors); 34993544Sjbeck } 35003544Sjbeck 35013544Sjbeck Errors = olderrors; 35023544Sjbeck return; 35033544Sjbeck } 35043544Sjbeck 35050Sstevel@tonic-gate /* 35060Sstevel@tonic-gate ** MILTER_ADDRCPT -- Add the supplied recipient to the message 35070Sstevel@tonic-gate ** 35080Sstevel@tonic-gate ** Parameters: 35090Sstevel@tonic-gate ** response -- encoded form of recipient address. 35100Sstevel@tonic-gate ** rlen -- length of response. 35110Sstevel@tonic-gate ** e -- current envelope. 35120Sstevel@tonic-gate ** 35130Sstevel@tonic-gate ** Returns: 35140Sstevel@tonic-gate ** none 35150Sstevel@tonic-gate */ 35160Sstevel@tonic-gate 35170Sstevel@tonic-gate static void 35180Sstevel@tonic-gate milter_addrcpt(response, rlen, e) 35190Sstevel@tonic-gate char *response; 35200Sstevel@tonic-gate ssize_t rlen; 35210Sstevel@tonic-gate ENVELOPE *e; 35220Sstevel@tonic-gate { 35230Sstevel@tonic-gate int olderrors; 35240Sstevel@tonic-gate 35250Sstevel@tonic-gate if (tTd(64, 10)) 35260Sstevel@tonic-gate sm_dprintf("milter_addrcpt: "); 35270Sstevel@tonic-gate 35280Sstevel@tonic-gate /* sanity checks */ 35290Sstevel@tonic-gate if (response == NULL) 35300Sstevel@tonic-gate { 35310Sstevel@tonic-gate if (tTd(64, 10)) 35320Sstevel@tonic-gate sm_dprintf("NULL response\n"); 35330Sstevel@tonic-gate return; 35340Sstevel@tonic-gate } 35350Sstevel@tonic-gate 35360Sstevel@tonic-gate if (*response == '\0' || 35370Sstevel@tonic-gate strlen(response) + 1 != (size_t) rlen) 35380Sstevel@tonic-gate { 35390Sstevel@tonic-gate if (tTd(64, 10)) 35400Sstevel@tonic-gate sm_dprintf("didn't follow protocol (total len %d != rlen %d)\n", 35410Sstevel@tonic-gate (int) strlen(response), (int) (rlen - 1)); 35420Sstevel@tonic-gate return; 35430Sstevel@tonic-gate } 35440Sstevel@tonic-gate 35450Sstevel@tonic-gate if (tTd(64, 10)) 35460Sstevel@tonic-gate sm_dprintf("%s\n", response); 35470Sstevel@tonic-gate if (MilterLogLevel > 8) 35480Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter add: rcpt: %s", response); 35490Sstevel@tonic-gate olderrors = Errors; 35500Sstevel@tonic-gate (void) sendtolist(response, NULLADDR, &e->e_sendqueue, 0, e); 35510Sstevel@tonic-gate Errors = olderrors; 35520Sstevel@tonic-gate return; 35530Sstevel@tonic-gate } 35543544Sjbeck 35550Sstevel@tonic-gate /* 35560Sstevel@tonic-gate ** MILTER_DELRCPT -- Delete the supplied recipient from the message 35570Sstevel@tonic-gate ** 35580Sstevel@tonic-gate ** Parameters: 35590Sstevel@tonic-gate ** response -- encoded form of recipient address. 35600Sstevel@tonic-gate ** rlen -- length of response. 35610Sstevel@tonic-gate ** e -- current envelope. 35620Sstevel@tonic-gate ** 35630Sstevel@tonic-gate ** Returns: 35640Sstevel@tonic-gate ** none 35650Sstevel@tonic-gate */ 35660Sstevel@tonic-gate 35670Sstevel@tonic-gate static void 35680Sstevel@tonic-gate milter_delrcpt(response, rlen, e) 35690Sstevel@tonic-gate char *response; 35700Sstevel@tonic-gate ssize_t rlen; 35710Sstevel@tonic-gate ENVELOPE *e; 35720Sstevel@tonic-gate { 35730Sstevel@tonic-gate if (tTd(64, 10)) 35740Sstevel@tonic-gate sm_dprintf("milter_delrcpt: "); 35750Sstevel@tonic-gate 35760Sstevel@tonic-gate /* sanity checks */ 35770Sstevel@tonic-gate if (response == NULL) 35780Sstevel@tonic-gate { 35790Sstevel@tonic-gate if (tTd(64, 10)) 35800Sstevel@tonic-gate sm_dprintf("NULL response\n"); 35810Sstevel@tonic-gate return; 35820Sstevel@tonic-gate } 35830Sstevel@tonic-gate 35840Sstevel@tonic-gate if (*response == '\0' || 35850Sstevel@tonic-gate strlen(response) + 1 != (size_t) rlen) 35860Sstevel@tonic-gate { 35870Sstevel@tonic-gate if (tTd(64, 10)) 35883544Sjbeck sm_dprintf("didn't follow protocol (total len %d != rlen %d)\n", 35893544Sjbeck (int) strlen(response), (int) (rlen - 1)); 35900Sstevel@tonic-gate return; 35910Sstevel@tonic-gate } 35920Sstevel@tonic-gate 35930Sstevel@tonic-gate if (tTd(64, 10)) 35940Sstevel@tonic-gate sm_dprintf("%s\n", response); 35950Sstevel@tonic-gate if (MilterLogLevel > 8) 35960Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter delete: rcpt %s", 35970Sstevel@tonic-gate response); 35980Sstevel@tonic-gate (void) removefromlist(response, &e->e_sendqueue, e); 35990Sstevel@tonic-gate return; 36000Sstevel@tonic-gate } 36013544Sjbeck 36020Sstevel@tonic-gate /* 36030Sstevel@tonic-gate ** MILTER_REPLBODY -- Replace the current data file with new body 36040Sstevel@tonic-gate ** 36050Sstevel@tonic-gate ** Parameters: 36060Sstevel@tonic-gate ** response -- encoded form of new body. 36070Sstevel@tonic-gate ** rlen -- length of response. 36080Sstevel@tonic-gate ** newfilter -- if first time called by a new filter 36090Sstevel@tonic-gate ** e -- current envelope. 36100Sstevel@tonic-gate ** 36110Sstevel@tonic-gate ** Returns: 36120Sstevel@tonic-gate ** 0 upon success, -1 upon failure 36130Sstevel@tonic-gate */ 36140Sstevel@tonic-gate 36150Sstevel@tonic-gate static int 36160Sstevel@tonic-gate milter_replbody(response, rlen, newfilter, e) 36170Sstevel@tonic-gate char *response; 36180Sstevel@tonic-gate ssize_t rlen; 36190Sstevel@tonic-gate bool newfilter; 36200Sstevel@tonic-gate ENVELOPE *e; 36210Sstevel@tonic-gate { 36220Sstevel@tonic-gate static char prevchar; 36230Sstevel@tonic-gate int i; 36240Sstevel@tonic-gate 36250Sstevel@tonic-gate if (tTd(64, 10)) 36260Sstevel@tonic-gate sm_dprintf("milter_replbody\n"); 36270Sstevel@tonic-gate 36280Sstevel@tonic-gate /* If a new filter, reset previous character and truncate data file */ 36290Sstevel@tonic-gate if (newfilter) 36300Sstevel@tonic-gate { 36310Sstevel@tonic-gate off_t prevsize; 36320Sstevel@tonic-gate char dfname[MAXPATHLEN]; 36330Sstevel@tonic-gate 36340Sstevel@tonic-gate (void) sm_strlcpy(dfname, queuename(e, DATAFL_LETTER), 36353544Sjbeck sizeof(dfname)); 36360Sstevel@tonic-gate 36370Sstevel@tonic-gate /* Reset prevchar */ 36380Sstevel@tonic-gate prevchar = '\0'; 36390Sstevel@tonic-gate 36400Sstevel@tonic-gate /* Get the current data file information */ 36410Sstevel@tonic-gate prevsize = sm_io_getinfo(e->e_dfp, SM_IO_WHAT_SIZE, NULL); 36420Sstevel@tonic-gate if (prevsize < 0) 36430Sstevel@tonic-gate prevsize = 0; 36440Sstevel@tonic-gate 36450Sstevel@tonic-gate /* truncate current data file */ 36460Sstevel@tonic-gate if (sm_io_getinfo(e->e_dfp, SM_IO_WHAT_ISTYPE, BF_FILE_TYPE)) 36470Sstevel@tonic-gate { 36480Sstevel@tonic-gate if (sm_io_setinfo(e->e_dfp, SM_BF_TRUNCATE, NULL) < 0) 36490Sstevel@tonic-gate { 36500Sstevel@tonic-gate MILTER_DF_ERROR("milter_replbody: sm_io truncate %s: %s"); 36510Sstevel@tonic-gate return -1; 36520Sstevel@tonic-gate } 36530Sstevel@tonic-gate } 36540Sstevel@tonic-gate else 36550Sstevel@tonic-gate { 36560Sstevel@tonic-gate int err; 36570Sstevel@tonic-gate 36580Sstevel@tonic-gate err = sm_io_error(e->e_dfp); 36590Sstevel@tonic-gate (void) sm_io_flush(e->e_dfp, SM_TIME_DEFAULT); 36600Sstevel@tonic-gate 36610Sstevel@tonic-gate /* 36620Sstevel@tonic-gate ** Clear error if tried to fflush() 36630Sstevel@tonic-gate ** a read-only file pointer and 36640Sstevel@tonic-gate ** there wasn't a previous error. 36650Sstevel@tonic-gate */ 36660Sstevel@tonic-gate 36670Sstevel@tonic-gate if (err == 0) 36680Sstevel@tonic-gate sm_io_clearerr(e->e_dfp); 36690Sstevel@tonic-gate 36700Sstevel@tonic-gate /* errno is set implicitly by fseek() before return */ 36710Sstevel@tonic-gate err = sm_io_seek(e->e_dfp, SM_TIME_DEFAULT, 36720Sstevel@tonic-gate 0, SEEK_SET); 36730Sstevel@tonic-gate if (err < 0) 36740Sstevel@tonic-gate { 36750Sstevel@tonic-gate MILTER_DF_ERROR("milter_replbody: sm_io_seek %s: %s"); 36760Sstevel@tonic-gate return -1; 36770Sstevel@tonic-gate } 36780Sstevel@tonic-gate # if NOFTRUNCATE 36790Sstevel@tonic-gate /* XXX: Not much we can do except rewind it */ 36800Sstevel@tonic-gate errno = EINVAL; 36810Sstevel@tonic-gate MILTER_DF_ERROR("milter_replbody: ftruncate not available on this platform (%s:%s)"); 36820Sstevel@tonic-gate return -1; 36830Sstevel@tonic-gate # else /* NOFTRUNCATE */ 36840Sstevel@tonic-gate err = ftruncate(sm_io_getinfo(e->e_dfp, 36850Sstevel@tonic-gate SM_IO_WHAT_FD, NULL), 36860Sstevel@tonic-gate 0); 36870Sstevel@tonic-gate if (err < 0) 36880Sstevel@tonic-gate { 36890Sstevel@tonic-gate MILTER_DF_ERROR("milter_replbody: sm_io ftruncate %s: %s"); 36900Sstevel@tonic-gate return -1; 36910Sstevel@tonic-gate } 36920Sstevel@tonic-gate # endif /* NOFTRUNCATE */ 36930Sstevel@tonic-gate } 36940Sstevel@tonic-gate 36950Sstevel@tonic-gate if (prevsize > e->e_msgsize) 36960Sstevel@tonic-gate e->e_msgsize = 0; 36970Sstevel@tonic-gate else 36980Sstevel@tonic-gate e->e_msgsize -= prevsize; 36990Sstevel@tonic-gate } 37000Sstevel@tonic-gate 37010Sstevel@tonic-gate if (newfilter && MilterLogLevel > 8) 37020Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter message: body replaced"); 37030Sstevel@tonic-gate 37040Sstevel@tonic-gate if (response == NULL) 37050Sstevel@tonic-gate { 37060Sstevel@tonic-gate /* Flush the buffered '\r' */ 37070Sstevel@tonic-gate if (prevchar == '\r') 37080Sstevel@tonic-gate { 37090Sstevel@tonic-gate (void) sm_io_putc(e->e_dfp, SM_TIME_DEFAULT, prevchar); 37100Sstevel@tonic-gate e->e_msgsize++; 37110Sstevel@tonic-gate } 37120Sstevel@tonic-gate return 0; 37130Sstevel@tonic-gate } 37140Sstevel@tonic-gate 37150Sstevel@tonic-gate for (i = 0; i < rlen; i++) 37160Sstevel@tonic-gate { 37170Sstevel@tonic-gate /* Buffered char from last chunk */ 37180Sstevel@tonic-gate if (i == 0 && prevchar == '\r') 37190Sstevel@tonic-gate { 37200Sstevel@tonic-gate /* Not CRLF, output prevchar */ 37210Sstevel@tonic-gate if (response[i] != '\n') 37220Sstevel@tonic-gate { 37230Sstevel@tonic-gate (void) sm_io_putc(e->e_dfp, SM_TIME_DEFAULT, 37240Sstevel@tonic-gate prevchar); 37250Sstevel@tonic-gate e->e_msgsize++; 37260Sstevel@tonic-gate } 37270Sstevel@tonic-gate prevchar = '\0'; 37280Sstevel@tonic-gate } 37290Sstevel@tonic-gate 37300Sstevel@tonic-gate /* Turn CRLF into LF */ 37310Sstevel@tonic-gate if (response[i] == '\r') 37320Sstevel@tonic-gate { 37330Sstevel@tonic-gate /* check if at end of chunk */ 37340Sstevel@tonic-gate if (i + 1 < rlen) 37350Sstevel@tonic-gate { 37360Sstevel@tonic-gate /* If LF, strip CR */ 37370Sstevel@tonic-gate if (response[i + 1] == '\n') 37380Sstevel@tonic-gate i++; 37390Sstevel@tonic-gate } 37400Sstevel@tonic-gate else 37410Sstevel@tonic-gate { 37420Sstevel@tonic-gate /* check next chunk */ 37430Sstevel@tonic-gate prevchar = '\r'; 37440Sstevel@tonic-gate continue; 37450Sstevel@tonic-gate } 37460Sstevel@tonic-gate } 37470Sstevel@tonic-gate (void) sm_io_putc(e->e_dfp, SM_TIME_DEFAULT, response[i]); 37480Sstevel@tonic-gate e->e_msgsize++; 37490Sstevel@tonic-gate } 37500Sstevel@tonic-gate return 0; 37510Sstevel@tonic-gate } 37520Sstevel@tonic-gate 37530Sstevel@tonic-gate /* 37540Sstevel@tonic-gate ** MTA callouts 37550Sstevel@tonic-gate */ 37560Sstevel@tonic-gate 37570Sstevel@tonic-gate /* 37580Sstevel@tonic-gate ** MILTER_INIT -- open and negotiate with all of the filters 37590Sstevel@tonic-gate ** 37600Sstevel@tonic-gate ** Parameters: 37610Sstevel@tonic-gate ** e -- current envelope. 37620Sstevel@tonic-gate ** state -- return state from response. 3763*5402Sjbeck ** milters -- milters structure. 37640Sstevel@tonic-gate ** 37650Sstevel@tonic-gate ** Returns: 37660Sstevel@tonic-gate ** true iff at least one filter is active 37670Sstevel@tonic-gate */ 37680Sstevel@tonic-gate 37690Sstevel@tonic-gate /* ARGSUSED */ 37700Sstevel@tonic-gate bool 3771*5402Sjbeck milter_init(e, state, milters) 37720Sstevel@tonic-gate ENVELOPE *e; 37730Sstevel@tonic-gate char *state; 3774*5402Sjbeck milters_T *milters; 37750Sstevel@tonic-gate { 37760Sstevel@tonic-gate int i; 37770Sstevel@tonic-gate 37780Sstevel@tonic-gate if (tTd(64, 10)) 37790Sstevel@tonic-gate sm_dprintf("milter_init\n"); 37800Sstevel@tonic-gate 3781*5402Sjbeck memset(milters, '\0', sizeof(*milters)); 37820Sstevel@tonic-gate *state = SMFIR_CONTINUE; 37830Sstevel@tonic-gate if (InputFilters[0] == NULL) 37840Sstevel@tonic-gate { 37850Sstevel@tonic-gate if (MilterLogLevel > 10) 37860Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 37870Sstevel@tonic-gate "Milter: no active filter"); 37880Sstevel@tonic-gate return false; 37890Sstevel@tonic-gate } 37900Sstevel@tonic-gate 37910Sstevel@tonic-gate for (i = 0; InputFilters[i] != NULL; i++) 37920Sstevel@tonic-gate { 37930Sstevel@tonic-gate struct milter *m = InputFilters[i]; 37940Sstevel@tonic-gate 37950Sstevel@tonic-gate m->mf_sock = milter_open(m, false, e); 37960Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR) 37970Sstevel@tonic-gate { 37980Sstevel@tonic-gate MILTER_CHECK_ERROR(true, continue); 37990Sstevel@tonic-gate break; 38000Sstevel@tonic-gate } 38010Sstevel@tonic-gate 38020Sstevel@tonic-gate if (m->mf_sock < 0 || 3803*5402Sjbeck milter_negotiate(m, e, milters) < 0 || 38040Sstevel@tonic-gate m->mf_state == SMFS_ERROR) 38050Sstevel@tonic-gate { 38060Sstevel@tonic-gate if (tTd(64, 5)) 38070Sstevel@tonic-gate sm_dprintf("milter_init(%s): failed to %s\n", 38080Sstevel@tonic-gate m->mf_name, 38090Sstevel@tonic-gate m->mf_sock < 0 ? "open" : 38100Sstevel@tonic-gate "negotiate"); 38110Sstevel@tonic-gate if (MilterLogLevel > 0) 38120Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 38130Sstevel@tonic-gate "Milter (%s): init failed to %s", 38140Sstevel@tonic-gate m->mf_name, 38150Sstevel@tonic-gate m->mf_sock < 0 ? "open" : 38160Sstevel@tonic-gate "negotiate"); 38170Sstevel@tonic-gate 38180Sstevel@tonic-gate /* if negotation failure, close socket */ 38190Sstevel@tonic-gate milter_error(m, e); 38200Sstevel@tonic-gate MILTER_CHECK_ERROR(true, continue); 38210Sstevel@tonic-gate continue; 38220Sstevel@tonic-gate } 38230Sstevel@tonic-gate if (MilterLogLevel > 9) 38240Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 38250Sstevel@tonic-gate "Milter (%s): init success to %s", 38260Sstevel@tonic-gate m->mf_name, 38270Sstevel@tonic-gate m->mf_sock < 0 ? "open" : "negotiate"); 38280Sstevel@tonic-gate } 38290Sstevel@tonic-gate 38300Sstevel@tonic-gate /* 38310Sstevel@tonic-gate ** If something temp/perm failed with one of the filters, 38320Sstevel@tonic-gate ** we won't be using any of them, so clear any existing 38330Sstevel@tonic-gate ** connections. 38340Sstevel@tonic-gate */ 38350Sstevel@tonic-gate 38360Sstevel@tonic-gate if (*state != SMFIR_CONTINUE) 38370Sstevel@tonic-gate milter_quit(e); 38380Sstevel@tonic-gate 38390Sstevel@tonic-gate return true; 38400Sstevel@tonic-gate } 38413544Sjbeck 38420Sstevel@tonic-gate /* 38430Sstevel@tonic-gate ** MILTER_CONNECT -- send connection info to milter filters 38440Sstevel@tonic-gate ** 38450Sstevel@tonic-gate ** Parameters: 38460Sstevel@tonic-gate ** hostname -- hostname of remote machine. 38470Sstevel@tonic-gate ** addr -- address of remote machine. 38480Sstevel@tonic-gate ** e -- current envelope. 38490Sstevel@tonic-gate ** state -- return state from response. 38500Sstevel@tonic-gate ** 38510Sstevel@tonic-gate ** Returns: 38520Sstevel@tonic-gate ** response string (may be NULL) 38530Sstevel@tonic-gate */ 38540Sstevel@tonic-gate 38550Sstevel@tonic-gate char * 38560Sstevel@tonic-gate milter_connect(hostname, addr, e, state) 38570Sstevel@tonic-gate char *hostname; 38580Sstevel@tonic-gate SOCKADDR addr; 38590Sstevel@tonic-gate ENVELOPE *e; 38600Sstevel@tonic-gate char *state; 38610Sstevel@tonic-gate { 38620Sstevel@tonic-gate char family; 38630Sstevel@tonic-gate unsigned short port; 38640Sstevel@tonic-gate char *buf, *bp; 38650Sstevel@tonic-gate char *response; 38660Sstevel@tonic-gate char *sockinfo = NULL; 38670Sstevel@tonic-gate ssize_t s; 38680Sstevel@tonic-gate # if NETINET6 38690Sstevel@tonic-gate char buf6[INET6_ADDRSTRLEN]; 38700Sstevel@tonic-gate # endif /* NETINET6 */ 38710Sstevel@tonic-gate 38720Sstevel@tonic-gate if (tTd(64, 10)) 38730Sstevel@tonic-gate sm_dprintf("milter_connect(%s)\n", hostname); 38740Sstevel@tonic-gate if (MilterLogLevel > 9) 38750Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter: connect to filters"); 38760Sstevel@tonic-gate 38770Sstevel@tonic-gate /* gather data */ 38780Sstevel@tonic-gate switch (addr.sa.sa_family) 38790Sstevel@tonic-gate { 38800Sstevel@tonic-gate # if NETUNIX 38810Sstevel@tonic-gate case AF_UNIX: 38820Sstevel@tonic-gate family = SMFIA_UNIX; 38830Sstevel@tonic-gate port = htons(0); 38840Sstevel@tonic-gate sockinfo = addr.sunix.sun_path; 38850Sstevel@tonic-gate break; 38860Sstevel@tonic-gate # endif /* NETUNIX */ 38870Sstevel@tonic-gate 38880Sstevel@tonic-gate # if NETINET 38890Sstevel@tonic-gate case AF_INET: 38900Sstevel@tonic-gate family = SMFIA_INET; 38910Sstevel@tonic-gate port = addr.sin.sin_port; 38920Sstevel@tonic-gate sockinfo = (char *) inet_ntoa(addr.sin.sin_addr); 38930Sstevel@tonic-gate break; 38940Sstevel@tonic-gate # endif /* NETINET */ 38950Sstevel@tonic-gate 38960Sstevel@tonic-gate # if NETINET6 38970Sstevel@tonic-gate case AF_INET6: 38980Sstevel@tonic-gate if (IN6_IS_ADDR_V4MAPPED(&addr.sin6.sin6_addr)) 38990Sstevel@tonic-gate family = SMFIA_INET; 39000Sstevel@tonic-gate else 39010Sstevel@tonic-gate family = SMFIA_INET6; 39020Sstevel@tonic-gate port = addr.sin6.sin6_port; 39030Sstevel@tonic-gate sockinfo = anynet_ntop(&addr.sin6.sin6_addr, buf6, 39043544Sjbeck sizeof(buf6)); 39050Sstevel@tonic-gate if (sockinfo == NULL) 39060Sstevel@tonic-gate sockinfo = ""; 39070Sstevel@tonic-gate break; 39080Sstevel@tonic-gate # endif /* NETINET6 */ 39090Sstevel@tonic-gate 39100Sstevel@tonic-gate default: 39110Sstevel@tonic-gate family = SMFIA_UNKNOWN; 39120Sstevel@tonic-gate break; 39130Sstevel@tonic-gate } 39140Sstevel@tonic-gate 39150Sstevel@tonic-gate s = strlen(hostname) + 1 + sizeof(family); 39160Sstevel@tonic-gate if (family != SMFIA_UNKNOWN) 39170Sstevel@tonic-gate s += sizeof(port) + strlen(sockinfo) + 1; 39180Sstevel@tonic-gate 39190Sstevel@tonic-gate buf = (char *) xalloc(s); 39200Sstevel@tonic-gate bp = buf; 39210Sstevel@tonic-gate 39220Sstevel@tonic-gate /* put together data */ 39230Sstevel@tonic-gate (void) memcpy(bp, hostname, strlen(hostname)); 39240Sstevel@tonic-gate bp += strlen(hostname); 39250Sstevel@tonic-gate *bp++ = '\0'; 39263544Sjbeck (void) memcpy(bp, &family, sizeof(family)); 39273544Sjbeck bp += sizeof(family); 39280Sstevel@tonic-gate if (family != SMFIA_UNKNOWN) 39290Sstevel@tonic-gate { 39303544Sjbeck (void) memcpy(bp, &port, sizeof(port)); 39313544Sjbeck bp += sizeof(port); 39320Sstevel@tonic-gate 39330Sstevel@tonic-gate /* include trailing '\0' */ 39340Sstevel@tonic-gate (void) memcpy(bp, sockinfo, strlen(sockinfo) + 1); 39350Sstevel@tonic-gate } 39360Sstevel@tonic-gate 39373544Sjbeck response = milter_command(SMFIC_CONNECT, buf, s, MilterConnectMacros, 39383544Sjbeck e, state, "connect", false); 39390Sstevel@tonic-gate sm_free(buf); /* XXX */ 39400Sstevel@tonic-gate 39410Sstevel@tonic-gate /* 39420Sstevel@tonic-gate ** If this message connection is done for, 39430Sstevel@tonic-gate ** close the filters. 39440Sstevel@tonic-gate */ 39450Sstevel@tonic-gate 39460Sstevel@tonic-gate if (*state != SMFIR_CONTINUE) 39470Sstevel@tonic-gate { 39480Sstevel@tonic-gate if (MilterLogLevel > 9) 39490Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter: connect, ending"); 39500Sstevel@tonic-gate milter_quit(e); 39510Sstevel@tonic-gate } 39520Sstevel@tonic-gate else 39530Sstevel@tonic-gate milter_per_connection_check(e); 39540Sstevel@tonic-gate 39550Sstevel@tonic-gate /* 39560Sstevel@tonic-gate ** SMFIR_REPLYCODE can't work with connect due to 39570Sstevel@tonic-gate ** the requirements of SMTP. Therefore, ignore the 39580Sstevel@tonic-gate ** reply code text but keep the state it would reflect. 39590Sstevel@tonic-gate */ 39600Sstevel@tonic-gate 39610Sstevel@tonic-gate if (*state == SMFIR_REPLYCODE) 39620Sstevel@tonic-gate { 39630Sstevel@tonic-gate if (response != NULL && 39640Sstevel@tonic-gate *response == '4') 39650Sstevel@tonic-gate { 39660Sstevel@tonic-gate if (strncmp(response, "421 ", 4) == 0) 39670Sstevel@tonic-gate *state = SMFIR_SHUTDOWN; 39680Sstevel@tonic-gate else 39690Sstevel@tonic-gate *state = SMFIR_TEMPFAIL; 39700Sstevel@tonic-gate } 39710Sstevel@tonic-gate else 39720Sstevel@tonic-gate *state = SMFIR_REJECT; 39730Sstevel@tonic-gate if (response != NULL) 39740Sstevel@tonic-gate { 39750Sstevel@tonic-gate sm_free(response); /* XXX */ 39760Sstevel@tonic-gate response = NULL; 39770Sstevel@tonic-gate } 39780Sstevel@tonic-gate } 39790Sstevel@tonic-gate return response; 39800Sstevel@tonic-gate } 39813544Sjbeck 39820Sstevel@tonic-gate /* 39830Sstevel@tonic-gate ** MILTER_HELO -- send SMTP HELO/EHLO command info to milter filters 39840Sstevel@tonic-gate ** 39850Sstevel@tonic-gate ** Parameters: 39860Sstevel@tonic-gate ** helo -- argument to SMTP HELO/EHLO command. 39870Sstevel@tonic-gate ** e -- current envelope. 39880Sstevel@tonic-gate ** state -- return state from response. 39890Sstevel@tonic-gate ** 39900Sstevel@tonic-gate ** Returns: 39910Sstevel@tonic-gate ** response string (may be NULL) 39920Sstevel@tonic-gate */ 39930Sstevel@tonic-gate 39940Sstevel@tonic-gate char * 39950Sstevel@tonic-gate milter_helo(helo, e, state) 39960Sstevel@tonic-gate char *helo; 39970Sstevel@tonic-gate ENVELOPE *e; 39980Sstevel@tonic-gate char *state; 39990Sstevel@tonic-gate { 40000Sstevel@tonic-gate int i; 40010Sstevel@tonic-gate char *response; 40020Sstevel@tonic-gate 40030Sstevel@tonic-gate if (tTd(64, 10)) 40040Sstevel@tonic-gate sm_dprintf("milter_helo(%s)\n", helo); 40050Sstevel@tonic-gate 40060Sstevel@tonic-gate /* HELO/EHLO can come at any point */ 40070Sstevel@tonic-gate for (i = 0; InputFilters[i] != NULL; i++) 40080Sstevel@tonic-gate { 40090Sstevel@tonic-gate struct milter *m = InputFilters[i]; 40100Sstevel@tonic-gate 40110Sstevel@tonic-gate switch (m->mf_state) 40120Sstevel@tonic-gate { 40130Sstevel@tonic-gate case SMFS_INMSG: 40140Sstevel@tonic-gate /* abort in message filters */ 40150Sstevel@tonic-gate milter_abort_filter(m, e); 40160Sstevel@tonic-gate /* FALLTHROUGH */ 40170Sstevel@tonic-gate 40180Sstevel@tonic-gate case SMFS_DONE: 40190Sstevel@tonic-gate /* reset done filters */ 40200Sstevel@tonic-gate m->mf_state = SMFS_OPEN; 40210Sstevel@tonic-gate break; 40220Sstevel@tonic-gate } 40230Sstevel@tonic-gate } 40240Sstevel@tonic-gate 40250Sstevel@tonic-gate response = milter_command(SMFIC_HELO, helo, strlen(helo) + 1, 40263544Sjbeck MilterHeloMacros, e, state, "helo", false); 40270Sstevel@tonic-gate milter_per_connection_check(e); 40280Sstevel@tonic-gate return response; 40290Sstevel@tonic-gate } 40303544Sjbeck 40310Sstevel@tonic-gate /* 40320Sstevel@tonic-gate ** MILTER_ENVFROM -- send SMTP MAIL command info to milter filters 40330Sstevel@tonic-gate ** 40340Sstevel@tonic-gate ** Parameters: 40350Sstevel@tonic-gate ** args -- SMTP MAIL command args (args[0] == sender). 40360Sstevel@tonic-gate ** e -- current envelope. 40370Sstevel@tonic-gate ** state -- return state from response. 40380Sstevel@tonic-gate ** 40390Sstevel@tonic-gate ** Returns: 40400Sstevel@tonic-gate ** response string (may be NULL) 40410Sstevel@tonic-gate */ 40420Sstevel@tonic-gate 40430Sstevel@tonic-gate char * 40440Sstevel@tonic-gate milter_envfrom(args, e, state) 40450Sstevel@tonic-gate char **args; 40460Sstevel@tonic-gate ENVELOPE *e; 40470Sstevel@tonic-gate char *state; 40480Sstevel@tonic-gate { 40490Sstevel@tonic-gate int i; 40500Sstevel@tonic-gate char *buf, *bp; 40510Sstevel@tonic-gate char *response; 40520Sstevel@tonic-gate ssize_t s; 40530Sstevel@tonic-gate 40540Sstevel@tonic-gate if (tTd(64, 10)) 40550Sstevel@tonic-gate { 40560Sstevel@tonic-gate sm_dprintf("milter_envfrom:"); 40570Sstevel@tonic-gate for (i = 0; args[i] != NULL; i++) 40580Sstevel@tonic-gate sm_dprintf(" %s", args[i]); 40590Sstevel@tonic-gate sm_dprintf("\n"); 40600Sstevel@tonic-gate } 40610Sstevel@tonic-gate 40620Sstevel@tonic-gate /* sanity check */ 40630Sstevel@tonic-gate if (args[0] == NULL) 40640Sstevel@tonic-gate { 40650Sstevel@tonic-gate *state = SMFIR_REJECT; 40660Sstevel@tonic-gate if (MilterLogLevel > 10) 40670Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 40680Sstevel@tonic-gate "Milter: reject, no sender"); 40690Sstevel@tonic-gate return NULL; 40700Sstevel@tonic-gate } 40710Sstevel@tonic-gate 40720Sstevel@tonic-gate /* new message, so ... */ 40730Sstevel@tonic-gate for (i = 0; InputFilters[i] != NULL; i++) 40740Sstevel@tonic-gate { 40750Sstevel@tonic-gate struct milter *m = InputFilters[i]; 40760Sstevel@tonic-gate 40770Sstevel@tonic-gate switch (m->mf_state) 40780Sstevel@tonic-gate { 40790Sstevel@tonic-gate case SMFS_INMSG: 40800Sstevel@tonic-gate /* abort in message filters */ 40810Sstevel@tonic-gate milter_abort_filter(m, e); 40820Sstevel@tonic-gate /* FALLTHROUGH */ 40830Sstevel@tonic-gate 40840Sstevel@tonic-gate case SMFS_DONE: 40850Sstevel@tonic-gate /* reset done filters */ 40860Sstevel@tonic-gate m->mf_state = SMFS_OPEN; 40870Sstevel@tonic-gate break; 40880Sstevel@tonic-gate } 40890Sstevel@tonic-gate } 40900Sstevel@tonic-gate 40910Sstevel@tonic-gate /* put together data */ 40920Sstevel@tonic-gate s = 0; 40930Sstevel@tonic-gate for (i = 0; args[i] != NULL; i++) 40940Sstevel@tonic-gate s += strlen(args[i]) + 1; 40950Sstevel@tonic-gate 40960Sstevel@tonic-gate if (s < 0) 40970Sstevel@tonic-gate { 40980Sstevel@tonic-gate *state = SMFIR_TEMPFAIL; 40990Sstevel@tonic-gate return NULL; 41000Sstevel@tonic-gate } 41010Sstevel@tonic-gate 41020Sstevel@tonic-gate buf = (char *) xalloc(s); 41030Sstevel@tonic-gate bp = buf; 41040Sstevel@tonic-gate for (i = 0; args[i] != NULL; i++) 41050Sstevel@tonic-gate { 41060Sstevel@tonic-gate (void) sm_strlcpy(bp, args[i], s - (bp - buf)); 41070Sstevel@tonic-gate bp += strlen(bp) + 1; 41080Sstevel@tonic-gate } 41090Sstevel@tonic-gate 41100Sstevel@tonic-gate if (MilterLogLevel > 14) 41113544Sjbeck sm_syslog(LOG_INFO, e->e_id, "Milter: sender: %s", buf); 41120Sstevel@tonic-gate 41130Sstevel@tonic-gate /* send it over */ 41143544Sjbeck response = milter_command(SMFIC_MAIL, buf, s, MilterEnvFromMacros, 41153544Sjbeck e, state, "mail", false); 41160Sstevel@tonic-gate sm_free(buf); /* XXX */ 41170Sstevel@tonic-gate 41180Sstevel@tonic-gate /* 41190Sstevel@tonic-gate ** If filter rejects/discards a per message command, 41200Sstevel@tonic-gate ** abort the other filters since we are done with the 41210Sstevel@tonic-gate ** current message. 41220Sstevel@tonic-gate */ 41230Sstevel@tonic-gate 41240Sstevel@tonic-gate MILTER_CHECK_DONE_MSG(); 41250Sstevel@tonic-gate if (MilterLogLevel > 10 && *state == SMFIR_REJECT) 41263544Sjbeck sm_syslog(LOG_INFO, e->e_id, "Milter: reject, sender"); 41270Sstevel@tonic-gate return response; 41280Sstevel@tonic-gate } 41290Sstevel@tonic-gate 41300Sstevel@tonic-gate /* 41310Sstevel@tonic-gate ** MILTER_ENVRCPT -- send SMTP RCPT command info to milter filters 41320Sstevel@tonic-gate ** 41330Sstevel@tonic-gate ** Parameters: 41340Sstevel@tonic-gate ** args -- SMTP MAIL command args (args[0] == recipient). 41350Sstevel@tonic-gate ** e -- current envelope. 41360Sstevel@tonic-gate ** state -- return state from response. 41373544Sjbeck ** rcpt_error -- does RCPT have an error? 41380Sstevel@tonic-gate ** 41390Sstevel@tonic-gate ** Returns: 41400Sstevel@tonic-gate ** response string (may be NULL) 41410Sstevel@tonic-gate */ 41420Sstevel@tonic-gate 41430Sstevel@tonic-gate char * 41443544Sjbeck milter_envrcpt(args, e, state, rcpt_error) 41450Sstevel@tonic-gate char **args; 41460Sstevel@tonic-gate ENVELOPE *e; 41470Sstevel@tonic-gate char *state; 41483544Sjbeck bool rcpt_error; 41490Sstevel@tonic-gate { 41500Sstevel@tonic-gate int i; 41510Sstevel@tonic-gate char *buf, *bp; 41520Sstevel@tonic-gate char *response; 41530Sstevel@tonic-gate ssize_t s; 41540Sstevel@tonic-gate 41550Sstevel@tonic-gate if (tTd(64, 10)) 41560Sstevel@tonic-gate { 41570Sstevel@tonic-gate sm_dprintf("milter_envrcpt:"); 41580Sstevel@tonic-gate for (i = 0; args[i] != NULL; i++) 41590Sstevel@tonic-gate sm_dprintf(" %s", args[i]); 41600Sstevel@tonic-gate sm_dprintf("\n"); 41610Sstevel@tonic-gate } 41620Sstevel@tonic-gate 41630Sstevel@tonic-gate /* sanity check */ 41640Sstevel@tonic-gate if (args[0] == NULL) 41650Sstevel@tonic-gate { 41660Sstevel@tonic-gate *state = SMFIR_REJECT; 41670Sstevel@tonic-gate if (MilterLogLevel > 10) 41680Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter: reject, no rcpt"); 41690Sstevel@tonic-gate return NULL; 41700Sstevel@tonic-gate } 41710Sstevel@tonic-gate 41720Sstevel@tonic-gate /* put together data */ 41730Sstevel@tonic-gate s = 0; 41740Sstevel@tonic-gate for (i = 0; args[i] != NULL; i++) 41750Sstevel@tonic-gate s += strlen(args[i]) + 1; 41760Sstevel@tonic-gate 41770Sstevel@tonic-gate if (s < 0) 41780Sstevel@tonic-gate { 41790Sstevel@tonic-gate *state = SMFIR_TEMPFAIL; 41800Sstevel@tonic-gate return NULL; 41810Sstevel@tonic-gate } 41820Sstevel@tonic-gate 41830Sstevel@tonic-gate buf = (char *) xalloc(s); 41840Sstevel@tonic-gate bp = buf; 41850Sstevel@tonic-gate for (i = 0; args[i] != NULL; i++) 41860Sstevel@tonic-gate { 41870Sstevel@tonic-gate (void) sm_strlcpy(bp, args[i], s - (bp - buf)); 41880Sstevel@tonic-gate bp += strlen(bp) + 1; 41890Sstevel@tonic-gate } 41900Sstevel@tonic-gate 41910Sstevel@tonic-gate if (MilterLogLevel > 14) 41920Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter: rcpts: %s", buf); 41930Sstevel@tonic-gate 41940Sstevel@tonic-gate /* send it over */ 41953544Sjbeck response = milter_command(SMFIC_RCPT, buf, s, MilterEnvRcptMacros, 41963544Sjbeck e, state, "rcpt", rcpt_error); 41970Sstevel@tonic-gate sm_free(buf); /* XXX */ 41980Sstevel@tonic-gate return response; 41990Sstevel@tonic-gate } 42000Sstevel@tonic-gate 42010Sstevel@tonic-gate /* 42020Sstevel@tonic-gate ** MILTER_DATA_CMD -- send SMTP DATA command info to milter filters 42030Sstevel@tonic-gate ** 42040Sstevel@tonic-gate ** Parameters: 42050Sstevel@tonic-gate ** e -- current envelope. 42060Sstevel@tonic-gate ** state -- return state from response. 42070Sstevel@tonic-gate ** 42080Sstevel@tonic-gate ** Returns: 42090Sstevel@tonic-gate ** response string (may be NULL) 42100Sstevel@tonic-gate */ 42110Sstevel@tonic-gate 42120Sstevel@tonic-gate char * 42130Sstevel@tonic-gate milter_data_cmd(e, state) 42140Sstevel@tonic-gate ENVELOPE *e; 42150Sstevel@tonic-gate char *state; 42160Sstevel@tonic-gate { 42170Sstevel@tonic-gate if (tTd(64, 10)) 42180Sstevel@tonic-gate sm_dprintf("milter_data_cmd\n"); 42190Sstevel@tonic-gate 42200Sstevel@tonic-gate /* send it over */ 42213544Sjbeck return milter_command(SMFIC_DATA, NULL, 0, MilterDataMacros, e, state, 42223544Sjbeck "data", false); 42230Sstevel@tonic-gate } 42240Sstevel@tonic-gate 42250Sstevel@tonic-gate /* 42260Sstevel@tonic-gate ** MILTER_DATA -- send message headers/body and gather final message results 42270Sstevel@tonic-gate ** 42280Sstevel@tonic-gate ** Parameters: 42290Sstevel@tonic-gate ** e -- current envelope. 42300Sstevel@tonic-gate ** state -- return state from response. 42310Sstevel@tonic-gate ** 42320Sstevel@tonic-gate ** Returns: 42330Sstevel@tonic-gate ** response string (may be NULL) 42340Sstevel@tonic-gate ** 42350Sstevel@tonic-gate ** Side effects: 42360Sstevel@tonic-gate ** - Uses e->e_dfp for access to the body 42370Sstevel@tonic-gate ** - Can call the various milter action routines to 42380Sstevel@tonic-gate ** modify the envelope or message. 42390Sstevel@tonic-gate */ 42400Sstevel@tonic-gate 42410Sstevel@tonic-gate # define MILTER_CHECK_RESULTS() \ 42420Sstevel@tonic-gate if (*state == SMFIR_ACCEPT || \ 42430Sstevel@tonic-gate m->mf_state == SMFS_DONE || \ 42440Sstevel@tonic-gate m->mf_state == SMFS_ERROR) \ 42450Sstevel@tonic-gate { \ 42460Sstevel@tonic-gate if (m->mf_state != SMFS_ERROR) \ 42470Sstevel@tonic-gate m->mf_state = SMFS_DONE; \ 42480Sstevel@tonic-gate continue; /* to next filter */ \ 42490Sstevel@tonic-gate } \ 42500Sstevel@tonic-gate if (*state != SMFIR_CONTINUE) \ 42510Sstevel@tonic-gate { \ 42520Sstevel@tonic-gate m->mf_state = SMFS_DONE; \ 42530Sstevel@tonic-gate goto finishup; \ 42540Sstevel@tonic-gate } 42550Sstevel@tonic-gate 42560Sstevel@tonic-gate char * 42570Sstevel@tonic-gate milter_data(e, state) 42580Sstevel@tonic-gate ENVELOPE *e; 42590Sstevel@tonic-gate char *state; 42600Sstevel@tonic-gate { 42610Sstevel@tonic-gate bool replbody = false; /* milter_replbody() called? */ 42620Sstevel@tonic-gate bool replfailed = false; /* milter_replbody() failed? */ 42630Sstevel@tonic-gate bool rewind = false; /* rewind data file? */ 42640Sstevel@tonic-gate bool dfopen = false; /* data file open for writing? */ 42650Sstevel@tonic-gate bool newfilter; /* reset on each new filter */ 42660Sstevel@tonic-gate char rcmd; 42670Sstevel@tonic-gate int i; 42680Sstevel@tonic-gate int save_errno; 42690Sstevel@tonic-gate char *response = NULL; 42700Sstevel@tonic-gate time_t eomsent; 42710Sstevel@tonic-gate ssize_t rlen; 42720Sstevel@tonic-gate 42730Sstevel@tonic-gate if (tTd(64, 10)) 42740Sstevel@tonic-gate sm_dprintf("milter_data\n"); 42750Sstevel@tonic-gate 42760Sstevel@tonic-gate *state = SMFIR_CONTINUE; 42770Sstevel@tonic-gate 42780Sstevel@tonic-gate /* 42790Sstevel@tonic-gate ** XXX: Should actually send body chunks to each filter 42800Sstevel@tonic-gate ** a chunk at a time instead of sending the whole body to 42810Sstevel@tonic-gate ** each filter in turn. However, only if the filters don't 42820Sstevel@tonic-gate ** change the body. 42830Sstevel@tonic-gate */ 42840Sstevel@tonic-gate 42850Sstevel@tonic-gate for (i = 0; InputFilters[i] != NULL; i++) 42860Sstevel@tonic-gate { 42870Sstevel@tonic-gate struct milter *m = InputFilters[i]; 42880Sstevel@tonic-gate 42890Sstevel@tonic-gate if (*state != SMFIR_CONTINUE && 42900Sstevel@tonic-gate *state != SMFIR_ACCEPT) 42910Sstevel@tonic-gate { 42920Sstevel@tonic-gate /* 42930Sstevel@tonic-gate ** A previous filter has dealt with the message, 42940Sstevel@tonic-gate ** safe to stop processing the filters. 42950Sstevel@tonic-gate */ 42960Sstevel@tonic-gate 42970Sstevel@tonic-gate break; 42980Sstevel@tonic-gate } 42990Sstevel@tonic-gate 43000Sstevel@tonic-gate /* Now reset state for later evaluation */ 43010Sstevel@tonic-gate *state = SMFIR_CONTINUE; 43020Sstevel@tonic-gate newfilter = true; 43030Sstevel@tonic-gate 43040Sstevel@tonic-gate /* previous problem? */ 43050Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR) 43060Sstevel@tonic-gate { 43070Sstevel@tonic-gate MILTER_CHECK_ERROR(false, continue); 43080Sstevel@tonic-gate break; 43090Sstevel@tonic-gate } 43100Sstevel@tonic-gate 43110Sstevel@tonic-gate /* sanity checks */ 43120Sstevel@tonic-gate if (m->mf_sock < 0 || 43130Sstevel@tonic-gate (m->mf_state != SMFS_OPEN && m->mf_state != SMFS_INMSG)) 43140Sstevel@tonic-gate continue; 43150Sstevel@tonic-gate 43160Sstevel@tonic-gate m->mf_state = SMFS_INMSG; 43170Sstevel@tonic-gate 43180Sstevel@tonic-gate /* check if filter wants the headers */ 43190Sstevel@tonic-gate if (!bitset(SMFIP_NOHDRS, m->mf_pflags)) 43200Sstevel@tonic-gate { 43210Sstevel@tonic-gate response = milter_headers(m, e, state); 43220Sstevel@tonic-gate MILTER_CHECK_RESULTS(); 43230Sstevel@tonic-gate } 43240Sstevel@tonic-gate 43250Sstevel@tonic-gate /* check if filter wants EOH */ 43260Sstevel@tonic-gate if (!bitset(SMFIP_NOEOH, m->mf_pflags)) 43270Sstevel@tonic-gate { 43280Sstevel@tonic-gate if (tTd(64, 10)) 43290Sstevel@tonic-gate sm_dprintf("milter_data: eoh\n"); 43300Sstevel@tonic-gate 43313544Sjbeck if (MilterEOHMacros[0] != NULL) 43323544Sjbeck { 43333544Sjbeck milter_send_macros(m, MilterEOHMacros, 43343544Sjbeck SMFIC_EOH, e); 43353544Sjbeck MILTER_CHECK_RESULTS(); 43363544Sjbeck } 43373544Sjbeck 43380Sstevel@tonic-gate /* send it over */ 43390Sstevel@tonic-gate response = milter_send_command(m, SMFIC_EOH, NULL, 0, 43403544Sjbeck e, state, "eoh"); 43410Sstevel@tonic-gate MILTER_CHECK_RESULTS(); 43420Sstevel@tonic-gate } 43430Sstevel@tonic-gate 43440Sstevel@tonic-gate /* check if filter wants the body */ 43450Sstevel@tonic-gate if (!bitset(SMFIP_NOBODY, m->mf_pflags) && 43460Sstevel@tonic-gate e->e_dfp != NULL) 43470Sstevel@tonic-gate { 43480Sstevel@tonic-gate rewind = true; 43490Sstevel@tonic-gate response = milter_body(m, e, state); 43500Sstevel@tonic-gate MILTER_CHECK_RESULTS(); 43510Sstevel@tonic-gate } 43520Sstevel@tonic-gate 43530Sstevel@tonic-gate if (MilterEOMMacros[0] != NULL) 43540Sstevel@tonic-gate { 43550Sstevel@tonic-gate milter_send_macros(m, MilterEOMMacros, 43560Sstevel@tonic-gate SMFIC_BODYEOB, e); 43570Sstevel@tonic-gate MILTER_CHECK_RESULTS(); 43580Sstevel@tonic-gate } 43590Sstevel@tonic-gate 43600Sstevel@tonic-gate /* send the final body chunk */ 43610Sstevel@tonic-gate (void) milter_write(m, SMFIC_BODYEOB, NULL, 0, 43623544Sjbeck m->mf_timeout[SMFTO_WRITE], e, "eom"); 43630Sstevel@tonic-gate 43640Sstevel@tonic-gate /* Get time EOM sent for timeout */ 43650Sstevel@tonic-gate eomsent = curtime(); 43660Sstevel@tonic-gate 43670Sstevel@tonic-gate /* deal with the possibility of multiple responses */ 43680Sstevel@tonic-gate while (*state == SMFIR_CONTINUE) 43690Sstevel@tonic-gate { 43700Sstevel@tonic-gate /* Check total timeout from EOM to final ACK/NAK */ 43710Sstevel@tonic-gate if (m->mf_timeout[SMFTO_EOM] > 0 && 43720Sstevel@tonic-gate curtime() - eomsent >= m->mf_timeout[SMFTO_EOM]) 43730Sstevel@tonic-gate { 43740Sstevel@tonic-gate if (tTd(64, 5)) 43750Sstevel@tonic-gate sm_dprintf("milter_data(%s): EOM ACK/NAK timeout\n", 43760Sstevel@tonic-gate m->mf_name); 43770Sstevel@tonic-gate if (MilterLogLevel > 0) 43780Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 43790Sstevel@tonic-gate "milter_data(%s): EOM ACK/NAK timeout", 43800Sstevel@tonic-gate m->mf_name); 43810Sstevel@tonic-gate milter_error(m, e); 43820Sstevel@tonic-gate MILTER_CHECK_ERROR(false, break); 43830Sstevel@tonic-gate break; 43840Sstevel@tonic-gate } 43850Sstevel@tonic-gate 43860Sstevel@tonic-gate response = milter_read(m, &rcmd, &rlen, 43873544Sjbeck m->mf_timeout[SMFTO_READ], e, 43883544Sjbeck "body"); 43890Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR) 43900Sstevel@tonic-gate break; 43910Sstevel@tonic-gate 43920Sstevel@tonic-gate if (tTd(64, 10)) 43930Sstevel@tonic-gate sm_dprintf("milter_data(%s): state %c\n", 43940Sstevel@tonic-gate m->mf_name, (char) rcmd); 43950Sstevel@tonic-gate 43960Sstevel@tonic-gate switch (rcmd) 43970Sstevel@tonic-gate { 43980Sstevel@tonic-gate case SMFIR_REPLYCODE: 43990Sstevel@tonic-gate MILTER_CHECK_REPLYCODE("554 5.7.1 Command rejected"); 44000Sstevel@tonic-gate if (MilterLogLevel > 12) 44010Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "milter=%s, reject=%s", 44020Sstevel@tonic-gate m->mf_name, response); 44030Sstevel@tonic-gate *state = rcmd; 44040Sstevel@tonic-gate m->mf_state = SMFS_DONE; 44050Sstevel@tonic-gate break; 44060Sstevel@tonic-gate 44070Sstevel@tonic-gate case SMFIR_REJECT: /* log msg at end of function */ 44080Sstevel@tonic-gate if (MilterLogLevel > 12) 44090Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "milter=%s, reject", 44100Sstevel@tonic-gate m->mf_name); 44110Sstevel@tonic-gate *state = rcmd; 44120Sstevel@tonic-gate m->mf_state = SMFS_DONE; 44130Sstevel@tonic-gate break; 44140Sstevel@tonic-gate 44150Sstevel@tonic-gate case SMFIR_DISCARD: 44160Sstevel@tonic-gate if (MilterLogLevel > 12) 44170Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "milter=%s, discard", 44180Sstevel@tonic-gate m->mf_name); 44190Sstevel@tonic-gate *state = rcmd; 44200Sstevel@tonic-gate m->mf_state = SMFS_DONE; 44210Sstevel@tonic-gate break; 44220Sstevel@tonic-gate 44230Sstevel@tonic-gate case SMFIR_TEMPFAIL: 44240Sstevel@tonic-gate if (MilterLogLevel > 12) 44250Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "milter=%s, tempfail", 44260Sstevel@tonic-gate m->mf_name); 44270Sstevel@tonic-gate *state = rcmd; 44280Sstevel@tonic-gate m->mf_state = SMFS_DONE; 44290Sstevel@tonic-gate break; 44300Sstevel@tonic-gate 44310Sstevel@tonic-gate case SMFIR_CONTINUE: 44320Sstevel@tonic-gate case SMFIR_ACCEPT: 44330Sstevel@tonic-gate /* this filter is done with message */ 44340Sstevel@tonic-gate if (replfailed) 44350Sstevel@tonic-gate *state = SMFIR_TEMPFAIL; 44360Sstevel@tonic-gate else 44370Sstevel@tonic-gate *state = SMFIR_ACCEPT; 44380Sstevel@tonic-gate m->mf_state = SMFS_DONE; 44390Sstevel@tonic-gate break; 44400Sstevel@tonic-gate 44410Sstevel@tonic-gate case SMFIR_PROGRESS: 44420Sstevel@tonic-gate break; 44430Sstevel@tonic-gate 44440Sstevel@tonic-gate case SMFIR_QUARANTINE: 44450Sstevel@tonic-gate if (!bitset(SMFIF_QUARANTINE, m->mf_fflags)) 44460Sstevel@tonic-gate { 44470Sstevel@tonic-gate if (MilterLogLevel > 9) 44480Sstevel@tonic-gate sm_syslog(LOG_WARNING, e->e_id, 44490Sstevel@tonic-gate "milter_data(%s): lied about quarantining, honoring request anyway", 44500Sstevel@tonic-gate m->mf_name); 44510Sstevel@tonic-gate } 44520Sstevel@tonic-gate if (response == NULL) 44530Sstevel@tonic-gate response = newstr(""); 44540Sstevel@tonic-gate if (MilterLogLevel > 3) 44550Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, 44560Sstevel@tonic-gate "milter=%s, quarantine=%s", 44570Sstevel@tonic-gate m->mf_name, response); 44580Sstevel@tonic-gate e->e_quarmsg = sm_rpool_strdup_x(e->e_rpool, 44590Sstevel@tonic-gate response); 44600Sstevel@tonic-gate macdefine(&e->e_macro, A_PERM, 44610Sstevel@tonic-gate macid("{quarantine}"), e->e_quarmsg); 44620Sstevel@tonic-gate break; 44630Sstevel@tonic-gate 44640Sstevel@tonic-gate case SMFIR_ADDHEADER: 44650Sstevel@tonic-gate if (!bitset(SMFIF_ADDHDRS, m->mf_fflags)) 44660Sstevel@tonic-gate { 44670Sstevel@tonic-gate if (MilterLogLevel > 9) 44680Sstevel@tonic-gate sm_syslog(LOG_WARNING, e->e_id, 44690Sstevel@tonic-gate "milter_data(%s): lied about adding headers, honoring request anyway", 44700Sstevel@tonic-gate m->mf_name); 44710Sstevel@tonic-gate } 44723544Sjbeck milter_addheader(m, response, rlen, e); 44730Sstevel@tonic-gate break; 44740Sstevel@tonic-gate 44750Sstevel@tonic-gate case SMFIR_INSHEADER: 44760Sstevel@tonic-gate if (!bitset(SMFIF_ADDHDRS, m->mf_fflags)) 44770Sstevel@tonic-gate { 44780Sstevel@tonic-gate if (MilterLogLevel > 9) 44790Sstevel@tonic-gate sm_syslog(LOG_WARNING, e->e_id, 44800Sstevel@tonic-gate "milter_data(%s): lied about adding headers, honoring request anyway", 44810Sstevel@tonic-gate m->mf_name); 44820Sstevel@tonic-gate } 44833544Sjbeck milter_insheader(m, response, rlen, e); 44840Sstevel@tonic-gate break; 44850Sstevel@tonic-gate 44860Sstevel@tonic-gate case SMFIR_CHGHEADER: 44870Sstevel@tonic-gate if (!bitset(SMFIF_CHGHDRS, m->mf_fflags)) 44880Sstevel@tonic-gate { 44890Sstevel@tonic-gate if (MilterLogLevel > 9) 44900Sstevel@tonic-gate sm_syslog(LOG_WARNING, e->e_id, 44910Sstevel@tonic-gate "milter_data(%s): lied about changing headers, honoring request anyway", 44920Sstevel@tonic-gate m->mf_name); 44930Sstevel@tonic-gate } 44943544Sjbeck milter_changeheader(m, response, rlen, e); 44953544Sjbeck break; 44963544Sjbeck 44973544Sjbeck case SMFIR_CHGFROM: 44983544Sjbeck if (!bitset(SMFIF_CHGFROM, m->mf_fflags)) 44993544Sjbeck { 45003544Sjbeck if (MilterLogLevel > 9) 45013544Sjbeck sm_syslog(LOG_WARNING, e->e_id, 45023544Sjbeck "milter_data(%s) lied about changing sender, honoring request anyway", 45033544Sjbeck m->mf_name); 45043544Sjbeck } 45053544Sjbeck milter_chgfrom(response, rlen, e); 45060Sstevel@tonic-gate break; 45070Sstevel@tonic-gate 45080Sstevel@tonic-gate case SMFIR_ADDRCPT: 45090Sstevel@tonic-gate if (!bitset(SMFIF_ADDRCPT, m->mf_fflags)) 45100Sstevel@tonic-gate { 45110Sstevel@tonic-gate if (MilterLogLevel > 9) 45120Sstevel@tonic-gate sm_syslog(LOG_WARNING, e->e_id, 45130Sstevel@tonic-gate "milter_data(%s) lied about adding recipients, honoring request anyway", 45140Sstevel@tonic-gate m->mf_name); 45150Sstevel@tonic-gate } 45160Sstevel@tonic-gate milter_addrcpt(response, rlen, e); 45170Sstevel@tonic-gate break; 45180Sstevel@tonic-gate 45193544Sjbeck case SMFIR_ADDRCPT_PAR: 45203544Sjbeck if (!bitset(SMFIF_ADDRCPT_PAR, m->mf_fflags)) 45213544Sjbeck { 45223544Sjbeck if (MilterLogLevel > 9) 45233544Sjbeck sm_syslog(LOG_WARNING, e->e_id, 45243544Sjbeck "milter_data(%s) lied about adding recipients with parameters, honoring request anyway", 45253544Sjbeck m->mf_name); 45263544Sjbeck } 45273544Sjbeck milter_addrcpt_par(response, rlen, e); 45283544Sjbeck break; 45293544Sjbeck 45300Sstevel@tonic-gate case SMFIR_DELRCPT: 45310Sstevel@tonic-gate if (!bitset(SMFIF_DELRCPT, m->mf_fflags)) 45320Sstevel@tonic-gate { 45330Sstevel@tonic-gate if (MilterLogLevel > 9) 45340Sstevel@tonic-gate sm_syslog(LOG_WARNING, e->e_id, 45350Sstevel@tonic-gate "milter_data(%s): lied about removing recipients, honoring request anyway", 45360Sstevel@tonic-gate m->mf_name); 45370Sstevel@tonic-gate } 45380Sstevel@tonic-gate milter_delrcpt(response, rlen, e); 45390Sstevel@tonic-gate break; 45400Sstevel@tonic-gate 45410Sstevel@tonic-gate case SMFIR_REPLBODY: 45420Sstevel@tonic-gate if (!bitset(SMFIF_MODBODY, m->mf_fflags)) 45430Sstevel@tonic-gate { 45440Sstevel@tonic-gate if (MilterLogLevel > 0) 45450Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 45460Sstevel@tonic-gate "milter_data(%s): lied about replacing body, rejecting request and tempfailing message", 45470Sstevel@tonic-gate m->mf_name); 45480Sstevel@tonic-gate replfailed = true; 45490Sstevel@tonic-gate break; 45500Sstevel@tonic-gate } 45510Sstevel@tonic-gate 45520Sstevel@tonic-gate /* already failed in attempt */ 45530Sstevel@tonic-gate if (replfailed) 45540Sstevel@tonic-gate break; 45550Sstevel@tonic-gate 45560Sstevel@tonic-gate if (!dfopen) 45570Sstevel@tonic-gate { 45580Sstevel@tonic-gate if (milter_reopen_df(e) < 0) 45590Sstevel@tonic-gate { 45600Sstevel@tonic-gate replfailed = true; 45610Sstevel@tonic-gate break; 45620Sstevel@tonic-gate } 45630Sstevel@tonic-gate dfopen = true; 45640Sstevel@tonic-gate rewind = true; 45650Sstevel@tonic-gate } 45660Sstevel@tonic-gate 45670Sstevel@tonic-gate if (milter_replbody(response, rlen, 45680Sstevel@tonic-gate newfilter, e) < 0) 45690Sstevel@tonic-gate replfailed = true; 45700Sstevel@tonic-gate newfilter = false; 45710Sstevel@tonic-gate replbody = true; 45720Sstevel@tonic-gate break; 45730Sstevel@tonic-gate 45740Sstevel@tonic-gate default: 45750Sstevel@tonic-gate /* Invalid response to command */ 45760Sstevel@tonic-gate if (MilterLogLevel > 0) 45770Sstevel@tonic-gate sm_syslog(LOG_ERR, e->e_id, 45780Sstevel@tonic-gate "milter_data(%s): returned bogus response %c", 45790Sstevel@tonic-gate m->mf_name, rcmd); 45800Sstevel@tonic-gate milter_error(m, e); 45810Sstevel@tonic-gate break; 45820Sstevel@tonic-gate } 45830Sstevel@tonic-gate if (rcmd != SMFIR_REPLYCODE && response != NULL) 45840Sstevel@tonic-gate { 45850Sstevel@tonic-gate sm_free(response); /* XXX */ 45860Sstevel@tonic-gate response = NULL; 45870Sstevel@tonic-gate } 45880Sstevel@tonic-gate 45890Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR) 45900Sstevel@tonic-gate break; 45910Sstevel@tonic-gate } 45920Sstevel@tonic-gate 45930Sstevel@tonic-gate if (replbody && !replfailed) 45940Sstevel@tonic-gate { 45950Sstevel@tonic-gate /* flush possible buffered character */ 45960Sstevel@tonic-gate milter_replbody(NULL, 0, !replbody, e); 45970Sstevel@tonic-gate replbody = false; 45980Sstevel@tonic-gate } 45990Sstevel@tonic-gate 46000Sstevel@tonic-gate if (m->mf_state == SMFS_ERROR) 46010Sstevel@tonic-gate { 46020Sstevel@tonic-gate MILTER_CHECK_ERROR(false, continue); 46030Sstevel@tonic-gate goto finishup; 46040Sstevel@tonic-gate } 46050Sstevel@tonic-gate } 46060Sstevel@tonic-gate 46070Sstevel@tonic-gate finishup: 46080Sstevel@tonic-gate /* leave things in the expected state if we touched it */ 46090Sstevel@tonic-gate if (replfailed) 46100Sstevel@tonic-gate { 46110Sstevel@tonic-gate if (*state == SMFIR_CONTINUE || 46120Sstevel@tonic-gate *state == SMFIR_ACCEPT) 46130Sstevel@tonic-gate { 46140Sstevel@tonic-gate *state = SMFIR_TEMPFAIL; 46150Sstevel@tonic-gate SM_FREE_CLR(response); 46160Sstevel@tonic-gate } 46170Sstevel@tonic-gate 46180Sstevel@tonic-gate if (dfopen) 46190Sstevel@tonic-gate { 46200Sstevel@tonic-gate (void) sm_io_close(e->e_dfp, SM_TIME_DEFAULT); 46210Sstevel@tonic-gate e->e_dfp = NULL; 46220Sstevel@tonic-gate e->e_flags &= ~EF_HAS_DF; 46230Sstevel@tonic-gate dfopen = false; 46240Sstevel@tonic-gate } 46250Sstevel@tonic-gate rewind = false; 46260Sstevel@tonic-gate } 46270Sstevel@tonic-gate 46280Sstevel@tonic-gate if ((dfopen && milter_reset_df(e) < 0) || 46290Sstevel@tonic-gate (rewind && bfrewind(e->e_dfp) < 0)) 46300Sstevel@tonic-gate { 46310Sstevel@tonic-gate save_errno = errno; 46320Sstevel@tonic-gate ExitStat = EX_IOERR; 46330Sstevel@tonic-gate 46340Sstevel@tonic-gate /* 46350Sstevel@tonic-gate ** If filter told us to keep message but we had 46360Sstevel@tonic-gate ** an error, we can't really keep it, tempfail it. 46370Sstevel@tonic-gate */ 46380Sstevel@tonic-gate 46390Sstevel@tonic-gate if (*state == SMFIR_CONTINUE || 46400Sstevel@tonic-gate *state == SMFIR_ACCEPT) 46410Sstevel@tonic-gate { 46420Sstevel@tonic-gate *state = SMFIR_TEMPFAIL; 46430Sstevel@tonic-gate SM_FREE_CLR(response); 46440Sstevel@tonic-gate } 46450Sstevel@tonic-gate 46460Sstevel@tonic-gate errno = save_errno; 46470Sstevel@tonic-gate syserr("milter_data: %s/%cf%s: read error", 46480Sstevel@tonic-gate qid_printqueue(e->e_qgrp, e->e_qdir), 46490Sstevel@tonic-gate DATAFL_LETTER, e->e_id); 46500Sstevel@tonic-gate } 46510Sstevel@tonic-gate 46520Sstevel@tonic-gate MILTER_CHECK_DONE_MSG(); 46530Sstevel@tonic-gate if (MilterLogLevel > 10 && *state == SMFIR_REJECT) 46540Sstevel@tonic-gate sm_syslog(LOG_INFO, e->e_id, "Milter: reject, data"); 46550Sstevel@tonic-gate return response; 46560Sstevel@tonic-gate } 46570Sstevel@tonic-gate 46580Sstevel@tonic-gate /* 46590Sstevel@tonic-gate ** MILTER_UNKNOWN -- send any unrecognized or unimplemented command 46600Sstevel@tonic-gate ** string to milter filters 46610Sstevel@tonic-gate ** 46620Sstevel@tonic-gate ** Parameters: 46633544Sjbeck ** smtpcmd -- the string itself. 46640Sstevel@tonic-gate ** e -- current envelope. 46650Sstevel@tonic-gate ** state -- return state from response. 46660Sstevel@tonic-gate ** 46670Sstevel@tonic-gate ** 46680Sstevel@tonic-gate ** Returns: 46690Sstevel@tonic-gate ** response string (may be NULL) 46700Sstevel@tonic-gate */ 46710Sstevel@tonic-gate 46720Sstevel@tonic-gate char * 46733544Sjbeck milter_unknown(smtpcmd, e, state) 46743544Sjbeck char *smtpcmd; 46750Sstevel@tonic-gate ENVELOPE *e; 46760Sstevel@tonic-gate char *state; 46770Sstevel@tonic-gate { 46780Sstevel@tonic-gate if (tTd(64, 10)) 46793544Sjbeck sm_dprintf("milter_unknown(%s)\n", smtpcmd); 46803544Sjbeck 46813544Sjbeck return milter_command(SMFIC_UNKNOWN, smtpcmd, strlen(smtpcmd) + 1, 46823544Sjbeck NULL, e, state, "unknown", false); 46830Sstevel@tonic-gate } 46840Sstevel@tonic-gate 46850Sstevel@tonic-gate /* 46860Sstevel@tonic-gate ** MILTER_QUIT -- informs the filter(s) we are done and closes connection(s) 46870Sstevel@tonic-gate ** 46880Sstevel@tonic-gate ** Parameters: 46890Sstevel@tonic-gate ** e -- current envelope. 46900Sstevel@tonic-gate ** 46910Sstevel@tonic-gate ** Returns: 46920Sstevel@tonic-gate ** none 46930Sstevel@tonic-gate */ 46940Sstevel@tonic-gate 46950Sstevel@tonic-gate void 46960Sstevel@tonic-gate milter_quit(e) 46970Sstevel@tonic-gate ENVELOPE *e; 46980Sstevel@tonic-gate { 46990Sstevel@tonic-gate int i; 47000Sstevel@tonic-gate 47010Sstevel@tonic-gate if (tTd(64, 10)) 47020Sstevel@tonic-gate sm_dprintf("milter_quit(%s)\n", e->e_id); 47030Sstevel@tonic-gate 47040Sstevel@tonic-gate for (i = 0; InputFilters[i] != NULL; i++) 47050Sstevel@tonic-gate milter_quit_filter(InputFilters[i], e); 47060Sstevel@tonic-gate } 47073544Sjbeck 47080Sstevel@tonic-gate /* 47090Sstevel@tonic-gate ** MILTER_ABORT -- informs the filter(s) that we are aborting current message 47100Sstevel@tonic-gate ** 47110Sstevel@tonic-gate ** Parameters: 47120Sstevel@tonic-gate ** e -- current envelope. 47130Sstevel@tonic-gate ** 47140Sstevel@tonic-gate ** Returns: 47150Sstevel@tonic-gate ** none 47160Sstevel@tonic-gate */ 47170Sstevel@tonic-gate 47180Sstevel@tonic-gate void 47190Sstevel@tonic-gate milter_abort(e) 47200Sstevel@tonic-gate ENVELOPE *e; 47210Sstevel@tonic-gate { 47220Sstevel@tonic-gate int i; 47230Sstevel@tonic-gate 47240Sstevel@tonic-gate if (tTd(64, 10)) 47250Sstevel@tonic-gate sm_dprintf("milter_abort\n"); 47260Sstevel@tonic-gate 47270Sstevel@tonic-gate for (i = 0; InputFilters[i] != NULL; i++) 47280Sstevel@tonic-gate { 47290Sstevel@tonic-gate struct milter *m = InputFilters[i]; 47300Sstevel@tonic-gate 47310Sstevel@tonic-gate /* sanity checks */ 47320Sstevel@tonic-gate if (m->mf_sock < 0 || m->mf_state != SMFS_INMSG) 47330Sstevel@tonic-gate continue; 47340Sstevel@tonic-gate 47350Sstevel@tonic-gate milter_abort_filter(m, e); 47360Sstevel@tonic-gate } 47370Sstevel@tonic-gate } 47380Sstevel@tonic-gate #endif /* MILTER */ 4739