85 #include <sys/socket.h>
89 #ifdef STRCASECMP_IN_STRINGS_H
225 static const char *cleanup_add_rcpt_par(
void *,
const char *,
const char *);
227 #define STR(x) vstring_str(x)
228 #define LEN(x) VSTRING_LEN(x)
232 static void cleanup_milter_hbc_log(
void *context,
const char *action,
233 const char *where,
const char *line,
234 const char *optional_text)
240 state->
queue_id, where, action, where, line,
257 static void cleanup_milter_header_prepend(
void *context,
int rec_type,
258 const char *buf, ssize_t len, off_t offset)
261 msg_warn(
"the milter_header/body_checks prepend action is not implemented");
266 static char *cleanup_milter_hbc_extend(
void *context,
const char *command,
267 ssize_t cmd_len,
const char *optional_text,
268 const char *where,
const char *buf,
269 ssize_t buf_len, off_t offset)
274 #define STREQUAL(x,y,l) (strncasecmp((x), (y), (l)) == 0 && (y)[l] == 0)
283 #define CLEANUP_MILTER_REJECTING_OR_DISCARDING_MESSAGE(state) \
284 ((state->flags & CLEANUP_FLAG_DISCARD) || (state->errs & CLEANUP_STAT_CONT))
309 return ((
char *) buf);
311 if (
STREQUAL(command,
"BCC", cmd_len)) {
312 if (strchr(optional_text,
'@') == 0) {
313 msg_warn(
"bad BCC address \"%s\" in %s map -- "
317 cleanup_milter_hbc_log(context,
"bcc", where, buf, optional_text);
319 (void) cleanup_add_rcpt_par(state, optional_text,
"");
321 return ((
char *) buf);
323 if (
STREQUAL(command,
"REJECT", cmd_len)) {
329 if (*optional_text) {
332 msg_warn(
"bad DSN action in %s -- need 4.x.x or 5.x.x",
339 if (*state->
reason ==
'4')
344 cleanup_milter_hbc_log(context,
"reject", where, buf, state->
reason);
348 return ((
char *) buf);
350 if (
STREQUAL(command,
"FILTER", cmd_len)) {
351 if (*optional_text == 0) {
352 msg_warn(
"missing FILTER command argument in %s map", map_class);
353 }
else if (strchr(optional_text,
':') == 0) {
354 msg_warn(
"bad FILTER command %s in %s -- "
355 "need transport:destination",
356 optional_text, map_class);
361 cleanup_milter_hbc_log(context,
"filter", where, buf,
364 return ((
char *) buf);
366 if (
STREQUAL(command,
"DISCARD", cmd_len)) {
367 cleanup_milter_hbc_log(context,
"discard", where, buf, optional_text);
371 return ((
char *) buf);
373 if (
STREQUAL(command,
"HOLD", cmd_len)) {
375 cleanup_milter_hbc_log(context,
"hold", where, buf, optional_text);
378 return ((
char *) buf);
380 if (
STREQUAL(command,
"REDIRECT", cmd_len)) {
381 if (strchr(optional_text,
'@') == 0) {
382 msg_warn(
"bad REDIRECT target \"%s\" in %s map -- "
384 optional_text, map_class);
389 cleanup_milter_hbc_log(context,
"redirect", where, buf,
393 return ((
char *) buf);
415 msg_warn(
"%s: %s map lookup problem -- "
416 "message not accepted, try again later",
421 if (ret !=
STR(buf)) {
431 static void cleanup_milter_hbc_add_meta_records(
CLEANUP_STATE *state)
433 const char *myname =
"cleanup_milter_hbc_add_meta_records";
434 off_t reverse_ptr_offset;
435 off_t new_meta_offset;
447 msg_panic(
"%s: no meta append pointer location", myname);
449 msg_panic(
"%s: no meta append pointer target", myname);
461 if ((new_meta_offset =
vstream_fseek(state->
dst, (off_t) 0, SEEK_END)) < 0) {
462 cleanup_milter_set_error(state, errno);
482 cleanup_milter_set_error(state, errno);
486 (
long) new_meta_offset);
504 static void cleanup_milter_header_checks_init(
CLEANUP_STATE *state)
506 #define NO_NESTED_HDR_NAME ""
507 #define NO_NESTED_HDR_VALUE ""
508 #define NO_MIME_HDR_NAME ""
509 #define NO_MIME_HDR_VALUE ""
512 cleanup_milter_hbc_log,
513 cleanup_milter_header_prepend,
514 cleanup_milter_hbc_extend,
544 cleanup_milter_hbc_add_meta_records(state);
550 #define CLEANUP_MILTER_SET_REASON(__state, __reason) do { \
551 if ((__state)->reason) \
552 myfree((__state)->reason); \
553 (__state)->reason = mystrdup(__reason); \
554 if ((__state)->smtp_reply) { \
555 myfree((__state)->smtp_reply); \
556 (__state)->smtp_reply = 0; \
560 #define CLEANUP_MILTER_SET_SMTP_REPLY(__state, __smtp_reply) do { \
561 if ((__state)->reason) \
562 myfree((__state)->reason); \
563 (__state)->reason = mystrdup(__smtp_reply + 4); \
564 printable((__state)->reason, '_'); \
565 if ((__state)->smtp_reply) \
566 myfree((__state)->smtp_reply); \
567 (__state)->smtp_reply = mystrdup(__smtp_reply); \
572 static void cleanup_milter_set_error(
CLEANUP_STATE *state,
int err)
585 static const char *cleanup_milter_error(
CLEANUP_STATE *state,
int err)
587 const char *myname =
"cleanup_milter_error";
603 cleanup_milter_set_error(state, err);
605 msg_panic(
"%s: missing errno to error flag mapping", myname);
615 static const char *cleanup_add_header(
void *context,
const char *name,
619 const char *myname =
"cleanup_add_header";
622 off_t reverse_ptr_offset;
623 off_t new_hdr_offset;
632 msg_panic(
"%s: no header append pointer location", myname);
634 msg_panic(
"%s: no header append pointer target", myname);
645 if (cleanup_milter_header_checks(state, buf) == 0
652 return (cleanup_milter_error(state, 0));
662 if ((new_hdr_offset =
vstream_fseek(state->
dst, (off_t) 0, SEEK_END)) < 0) {
665 return (cleanup_milter_error(state, errno));
672 return (cleanup_milter_error(state, errno));
689 return (cleanup_milter_error(state, errno));
692 (
long) new_hdr_offset);
706 return (
CLEANUP_OUT_OK(state) == 0 ? cleanup_milter_error(state, 0) :
717 static off_t cleanup_find_header_start(
CLEANUP_STATE *state, ssize_t index,
718 const char *header_label,
721 int allow_ptr_backup,
724 const char *myname =
"cleanup_find_header_start";
734 msg_info(
"%s: index %ld name \"%s\"",
735 myname, (
long) index, header_label ? header_label :
"(none)");
741 msg_panic(
"%s: bad header index %ld", myname, (
long) index);
804 #define CLEANUP_FIND_HEADER_NOTFOUND (-1)
805 #define CLEANUP_FIND_HEADER_IOERROR (-2)
807 #define CLEANUP_FIND_HEADER_RETURN(offs) do { \
809 vstring_free(ptr_buf); \
813 #define GET_NEXT_TEXT_OR_PTR_RECORD(rec_type, state, buf, curr_offset, quit) \
814 if ((rec_type = rec_get_raw(state->dst, buf, 0, REC_FLAG_NONE)) < 0) { \
815 msg_warn("%s: read file %s: %m", myname, cleanup_path); \
816 cleanup_milter_set_error(state, errno); \
817 do { quit; } while (0); \
819 if (msg_verbose > 1) \
820 msg_info("%s: read: %ld: %.*s", myname, (long) curr_offset, \
821 LEN(buf) > 30 ? 30 : (int) LEN(buf), STR(buf)); \
822 if (rec_type == REC_TYPE_DTXT) \
824 if (rec_type != REC_TYPE_NORM && rec_type != REC_TYPE_CONT \
825 && rec_type != REC_TYPE_PTR) \
831 cleanup_milter_set_error(state, errno);
834 for (ptr_offset = 0, last_type = 0; ; ) {
837 cleanup_milter_set_error(state, errno);
851 cleanup_milter_set_error(state, errno);
855 if (allow_ptr_backup) {
856 ptr_offset = curr_offset;
873 else if (hdr_count++ < skip_headers)
875 else if ((header_label == 0
877 && (strlen(header_label) == len)))
883 last_type = rec_type;
900 VSTRING *rbuf = (ptr_offset ? buf :
906 cleanup_milter_set_error(state, errno);
910 msg_panic(
"%s: short header without padding", myname);
919 if (ptr_offset != 0) {
921 curr_offset = ptr_offset;
924 *prec_type = rec_type;
927 msg_info(
"%s: index %ld name %s type %d offset %ld",
928 myname, (
long) index, header_label ?
929 header_label :
"(none)", rec_type, (
long) curr_offset);
940 const char *myname =
"cleanup_find_header_end";
954 cleanup_milter_error(state, errno);
968 cleanup_milter_error(state, errno);
977 last_type = rec_type;
979 return (read_offset);
984 static const char *cleanup_patch_header(
CLEANUP_STATE *state,
985 const char *new_hdr_name,
986 const char *hdr_space,
987 const char *new_hdr_value,
988 off_t old_rec_offset,
993 const char *myname =
"cleanup_patch_header";
995 off_t new_hdr_offset;
997 #define CLEANUP_PATCH_HEADER_RETURN(ret) do { \
1003 msg_info(
"%s: \"%s\" \"%s\" at %ld",
1004 myname, new_hdr_name, new_hdr_value, (
long) old_rec_offset);
1031 vstring_sprintf(buf,
"%s:%s%s", new_hdr_name, hdr_space, new_hdr_value);
1033 && cleanup_milter_header_checks(state, buf) == 0)
1040 if ((new_hdr_offset =
vstream_fseek(state->
dst, (off_t) 0, SEEK_END)) < 0) {
1047 msg_info(
"%s: %ld: write %.*s", myname, (
long) new_hdr_offset,
1048 LEN(buf) > 30 ? 30 : (
int)
LEN(buf),
STR(buf));
1055 if (old_rec_type > 0) {
1061 msg_info(
"%s: write %.*s", myname,
LEN(old_rec_buf) > 30 ?
1062 30 : (
int)
LEN(old_rec_buf),
STR(old_rec_buf));
1071 if (next_offset < 0)
1072 msg_panic(
"%s: bad reverse pointer %ld",
1073 myname, (
long) next_offset);
1075 (
long) next_offset);
1077 msg_info(
"%s: write PTR %ld", myname, (
long) next_offset);
1091 (
long) new_hdr_offset);
1093 msg_info(
"%s: %ld: write PTR %ld", myname, (
long) old_rec_offset,
1094 (
long) new_hdr_offset);
1111 static const char *cleanup_ins_header(
void *context, ssize_t index,
1112 const char *new_hdr_name,
1113 const char *hdr_space,
1114 const char *new_hdr_value)
1116 const char *myname =
"cleanup_ins_header";
1119 off_t old_rec_offset;
1124 #define CLEANUP_INS_HEADER_RETURN(ret) do { \
1125 vstring_free(old_rec_buf); \
1131 myname, (
long) index, new_hdr_name, new_hdr_value);
1141 #define NO_HEADER_NAME ((char *) 0)
1142 #define ALLOW_PTR_BACKUP 1
1143 #define SKIP_ONE_HEADER 1
1144 #define DONT_SKIP_HEADERS 0
1148 old_rec_offset = cleanup_find_header_start(state, index,
NO_HEADER_NAME,
1149 old_rec_buf, &old_rec_type,
1160 if (old_rec_offset < 0)
1162 hdr_space, new_hdr_value));
1178 ret = cleanup_patch_header(state, new_hdr_name, hdr_space, new_hdr_value,
1179 old_rec_offset, old_rec_type,
1180 old_rec_buf, next_offset);
1186 static const char *cleanup_upd_header(
void *context, ssize_t index,
1187 const char *new_hdr_name,
1188 const char *hdr_space,
1189 const char *new_hdr_value)
1191 const char *myname =
"cleanup_upd_header";
1194 off_t old_rec_offset;
1201 myname, (
long) index, new_hdr_name, new_hdr_value);
1206 if (*new_hdr_name == 0)
1207 msg_panic(
"%s: null header name", myname);
1220 #define DONT_SAVE_RECORD 0
1221 #define NO_PTR_BACKUP 0
1223 #define CLEANUP_UPD_HEADER_RETURN(ret) do { \
1224 vstring_free(rec_buf); \
1229 old_rec_offset = cleanup_find_header_start(state, index, new_hdr_name,
1230 rec_buf, &last_type,
1241 if (old_rec_offset < 0)
1243 hdr_space, new_hdr_value));
1250 if ((next_offset = cleanup_find_header_end(state, rec_buf, last_type)) < 0)
1253 ret = cleanup_patch_header(state, new_hdr_name, hdr_space, new_hdr_value,
1261 static const char *cleanup_del_header(
void *context, ssize_t index,
1262 const char *hdr_name)
1264 const char *myname =
"cleanup_del_header";
1267 off_t header_offset;
1272 msg_info(
"%s: %ld \"%s\"", myname, (
long) index, hdr_name);
1278 msg_panic(
"%s: null header name", myname);
1287 #define CLEANUP_DEL_HEADER_RETURN(ret) do { \
1288 vstring_free(rec_buf); \
1293 header_offset = cleanup_find_header_start(state, index, hdr_name, rec_buf,
1306 if (header_offset > 0) {
1307 if ((next_offset = cleanup_find_header_end(state, rec_buf, last_type)) < 0)
1316 (
long) next_offset);
1323 return (
CLEANUP_OUT_OK(state) ? 0 : cleanup_milter_error(state, 0));
1328 static const char *cleanup_chg_from(
void *context,
const char *ext_from,
1329 const char *esmtp_args)
1331 const char *myname =
"cleanup_chg_from";
1334 off_t new_sender_offset;
1335 off_t after_sender_offs;
1344 msg_info(
"%s: \"%s\" \"%s\"", myname, ext_from, esmtp_args);
1350 if (esmtp_args[0]) {
1356 for (i = 0; i < esmtp_argv->
argc; ++i) {
1357 arg = esmtp_argv->
argv[i];
1360 msg_warn(
"Ignoring bad ESMTP parameter \"%s\" in "
1361 "SMFI_CHGFROM request", arg);
1371 msg_warn(
"Ignoring bad ESMTP parameter \"%s\" in "
1372 "SMFI_CHGFROM request", arg);
1379 msg_warn(
"Ignoring bad ESMTP parameter \"%s\" in "
1380 "SMFI_CHGFROM request", arg);
1394 msg_panic(
"%s: no original sender record offset", myname);
1396 msg_panic(
"%s: no post-sender record offset", myname);
1411 return (cleanup_milter_error(state, errno));
1423 if (dsn_envid == 0 && dsn_ret == 0) {
1424 new_sender_offset = new_offset;
1427 return (cleanup_milter_error(state, errno));
1438 for (addr_count = 0, tp = tree; tp != 0; tp = tp->
next) {
1440 if (addr_count == 0) {
1444 msg_warn(
"%s: Milter request to add multi-sender: \"%s\"",
1463 return (cleanup_milter_error(state, errno));
1476 return (
CLEANUP_OUT_OK(state) ? 0 : cleanup_milter_error(state, 0));
1481 static const char *cleanup_add_rcpt_par(
void *context,
const char *ext_rcpt,
1482 const char *esmtp_args)
1484 const char *myname =
"cleanup_add_rcpt_par";
1486 off_t new_rcpt_offset;
1487 off_t reverse_ptr_offset;
1495 const char *dsn_orcpt_info = 0;
1499 const char *arg_val;
1502 msg_info(
"%s: \"%s\" \"%s\"", myname, ext_rcpt, esmtp_args);
1511 msg_panic(
"%s: no recipient append pointer location", myname);
1513 msg_panic(
"%s: no recipient append pointer target", myname);
1526 if ((new_rcpt_offset =
vstream_fseek(state->
dst, (off_t) 0, SEEK_END)) < 0) {
1528 return (cleanup_milter_error(state, errno));
1534 if (esmtp_args[0]) {
1536 for (i = 0; i < esmtp_argv->
argc; ++i) {
1537 arg = esmtp_argv->
argv[i];
1540 msg_warn(
"%s: Bad NOTIFY parameter from Milter or "
1541 "header/body_checks: \"%.100s\"",
1547 || (type_len = strcspn(arg_val = arg + 6,
";")) == 0
1548 || (arg_val)[type_len] !=
';'
1550 "%.*s;", (
int) type_len,
1552 arg_val + type_len + 1) == 0) {
1553 msg_warn(
"%s: Bad ORCPT parameter from Milter or "
1554 "header/body_checks: \"%.100s\"",
1557 dsn_orcpt_info =
STR(orcpt_buf);
1560 msg_warn(
"%s: ignoring ESMTP argument from Milter or "
1561 "header/body_checks: \"%.100s\"",
1576 for (addr_count = 0, tp = tree; tp != 0; tp = tp->
next) {
1578 if (addr_count == 0) {
1582 msg_warn(
"%s: Milter or header/body_checks request to "
1583 "add multi-recipient: \"%s\"",
1590 if (addr_count != 0)
1594 msg_warn(
"%s: ignoring attempt from Milter to add null recipient",
1605 return (
CLEANUP_OUT_OK(state) ? 0 : cleanup_milter_error(state, 0));
1613 return (cleanup_milter_error(state, errno));
1624 return (cleanup_milter_error(state, errno));
1627 (
long) new_rcpt_offset);
1641 return (
CLEANUP_OUT_OK(state) ? 0 : cleanup_milter_error(state, 0));
1646 static const char *cleanup_add_rcpt(
void *context,
const char *ext_rcpt)
1648 return (cleanup_add_rcpt_par(context, ext_rcpt,
""));
1653 static const char *cleanup_del_rcpt(
void *context,
const char *ext_rcpt)
1655 const char *myname =
"cleanup_del_rcpt";
1661 char *dsn_orcpt = 0;
1663 char *orig_rcpt = 0;
1674 msg_info(
"%s: \"%s\"", myname, ext_rcpt);
1698 return (cleanup_milter_error(state, errno));
1700 #define CLEANUP_DEL_RCPT_RETURN(ret) do { \
1701 if (orig_rcpt != 0) \
1702 myfree(orig_rcpt); \
1703 if (dsn_orcpt != 0) \
1704 myfree(dsn_orcpt); \
1705 vstring_free(buf); \
1706 vstring_free(int_rcpt_buf); \
1718 for (addr_count = 0, tp = tree; tp != 0; tp = tp->
next) {
1720 if (addr_count == 0) {
1724 msg_warn(
"%s: Milter request to drop multi-recipient: \"%s\"",
1766 || *attr_value == 0)
1780 if (
alldig(start) && (junk = atoi(start)) > 0
1792 if (strcmp(orig_rcpt ? orig_rcpt : start,
STR(int_rcpt_buf)) == 0) {
1806 if (orig_rcpt != 0) {
1810 if (dsn_orcpt != 0) {
1820 msg_info(
"%s: deleted %d records for recipient \"%s\"",
1821 myname, count, ext_rcpt);
1828 static const char *cleanup_repl_body(
void *context,
int cmd,
VSTRING *buf)
1830 const char *myname =
"cleanup_repl_body";
1841 return (cleanup_milter_error(state, errno));
1847 return (cleanup_milter_error(state, errno));
1851 return (cleanup_milter_error(state, errno));
1854 msg_panic(
"%s: bad command: %d", myname, cmd);
1856 return (
CLEANUP_OUT_OK(state) ? 0 : cleanup_milter_error(state, errno));
1861 static const char *cleanup_milter_eval(
const char *name,
void *ptr)
1881 #ifndef CLIENT_ATTR_UNKNOWN
1882 #define CLIENT_ATTR_UNKNOWN "unknown"
1883 #define SERVER_ATTR_UNKNOWN "unknown"
1918 #ifdef USE_SASL_AUTH
1945 msg_fatal(
"cleanup_milter_receive: milter receive failed");
1950 cleanup_add_header, cleanup_upd_header,
1951 cleanup_ins_header, cleanup_del_header,
1952 cleanup_chg_from, cleanup_add_rcpt,
1953 cleanup_add_rcpt_par, cleanup_del_rcpt,
1954 cleanup_repl_body, (
void *) state);
1959 static const char *cleanup_milter_apply(
CLEANUP_STATE *state,
const char *event,
1962 const char *myname =
"cleanup_milter_apply";
1966 const char *ret = 0;
1989 msg_info(
"%s: ignoring redundant or conflicting milter reply: %s",
1998 msg_panic(
"%s: missing client info initialization", myname);
2012 action =
"milter-hold";
2013 text =
"milter triggers HOLD action";
2017 action =
"milter-discard";
2018 text =
"milter triggers DISCARD action";
2023 action =
"milter-reject";
2042 action =
"milter-reject";
2049 action =
"milter-reject";
2053 msg_panic(
"%s: unexpected mail filter reply: %s", myname, resp);
2073 static void cleanup_milter_client_init(
CLEANUP_STATE *state)
2076 const char *proto_attr;
2082 #define NO_CLIENT_PORT "0"
2094 || !
alldig(proto_attr)) {
2097 if (proto_info == 0)
2124 const char *myname =
"cleanup_milter";
2134 cleanup_milter_client_init(state);
2140 cleanup_milter_header_checks_init(state);
2148 cleanup_milter_apply(state,
"END-OF-MESSAGE", resp);
2154 cleanup_milter_hbc_finish(state);
2168 const char *argv[2];
2175 cleanup_add_header, cleanup_upd_header,
2176 cleanup_ins_header, cleanup_del_header,
2177 cleanup_chg_from, cleanup_add_rcpt,
2178 cleanup_add_rcpt_par, cleanup_del_rcpt,
2179 cleanup_repl_body, (
void *) state);
2181 cleanup_milter_client_init(state);
2188 cleanup_milter_apply(state,
"CONNECT", resp);
2191 #define PRETEND_ESMTP 1
2197 cleanup_milter_apply(state,
"EHLO", resp);
2212 cleanup_milter_apply(state,
"MAIL", resp);
2224 const char *myname =
"cleanup_milter_emul_rcpt";
2226 const char *argv[2];
2232 msg_panic(
"%s: missing client info initialization", myname);
2249 && cleanup_milter_apply(state,
"RCPT", resp) != 0) {
2250 msg_warn(
"%s: milter configuration error: can't reject recipient "
2251 "in non-smtpd(8) submission", state->
queue_id);
2262 const char *myname =
"cleanup_milter_emul_data";
2269 msg_panic(
"%s: missing client info initialization", myname);
2272 cleanup_milter_apply(state,
"DATA", resp);
2315 msg_panic(
"cleanup_masquerade_internal dummy");
2326 MAPS *maps,
int propagate)
2328 msg_panic(
"cleanup_map11_internal dummy");
2332 MAPS *maps,
int propagate)
2334 msg_panic(
"cleanup_map1n_internal dummy");
2343 static void usage(
void)
2349 msg_warn(
" add_header index name [value]");
2350 msg_warn(
" ins_header index name [value]");
2351 msg_warn(
" upd_header index name [value]");
2352 msg_warn(
" del_header index name");
2353 msg_warn(
" chg_from addr parameters");
2355 msg_warn(
" add_rcpt_par addr parameters");
2358 msg_warn(
" header_checks type:name");
2363 static void flatten_args(
VSTRING *buf,
char **argv)
2368 for (cpp = argv; *cpp; cpp++) {
2378 static void open_queue_file(
CLEANUP_STATE *state,
const char *path)
2388 if (state->
dst != 0) {
2389 msg_warn(
"closing %s", cleanup_path);
2401 msg_fatal(
"file %s: vstream_ftell: %m", cleanup_path);
2403 msg_fatal(
"file %s: missing SIZE or PTR record", cleanup_path);
2405 if (sscanf(
STR(buf),
"%ld %ld %ld %ld",
2406 &msg_seg_len, &data_offset,
2407 &rcpt_count, &qmgr_opts) != 4)
2408 msg_fatal(
"file %s: bad SIZE record: %s",
2409 cleanup_path,
STR(buf));
2416 msg_fatal(
"file %s: missing PTR record after short sender",
2419 msg_fatal(
"file %s: missing END record", cleanup_path);
2422 msg_fatal(
"file %s: missing SIZE record", cleanup_path);
2423 if (curr_offset < state->data_offset
2427 if (atol(
STR(buf)) != 0)
2428 msg_fatal(
"file %s: bad dummy recipient PTR record: %s",
2429 cleanup_path,
STR(buf));
2432 msg_fatal(
"file %s: vstream_ftell: %m", cleanup_path);
2436 if (atol(
STR(buf)) != 0)
2437 msg_fatal(
"file %s: bad dummy meta PTR record: %s",
2438 cleanup_path,
STR(buf));
2441 msg_fatal(
"file %s: vstream_ftell: %m", cleanup_path);
2446 if (atol(
STR(buf)) != 0)
2447 msg_fatal(
"file %s: bad dummy header PTR record: %s",
2448 cleanup_path,
STR(buf));
2451 msg_fatal(
"file %s: vstream_ftell: %m", cleanup_path);
2462 msg_info(
"append_rcpt_pt_offset %ld append_rcpt_pt_target %ld",
2465 msg_info(
"append_hdr_pt_offset %ld append_hdr_pt_target %ld",
2481 int main(
int unused_argc,
char **argv)
2488 const char *parens =
"{}";
2505 const char *resp = 0;
2519 if (*bufp ==
'#' || *bufp == 0 ||
allspace(bufp))
2522 if (argv->
argc == 0) {
2524 }
else if (strcmp(argv->
argv[0],
"?") == 0) {
2526 }
else if (strcmp(argv->
argv[0],
"verbose") == 0) {
2527 if (argv->
argc != 2) {
2528 msg_warn(
"bad verbose argument count: %ld", (
long) argv->
argc);
2529 }
else if (strcmp(argv->
argv[1],
"on") == 0) {
2531 }
else if (strcmp(argv->
argv[1],
"off") == 0) {
2536 }
else if (strcmp(argv->
argv[0],
"open") == 0) {
2537 if (state->
dst != 0) {
2539 close_queue_file(state);
2541 if (argv->
argc != 2) {
2542 msg_warn(
"bad open argument count: %ld", (
long) argv->
argc);
2544 open_queue_file(state, argv->
argv[1]);
2546 }
else if (state->
dst == 0) {
2548 }
else if (strcmp(argv->
argv[0],
"close") == 0) {
2549 if (*var_milt_head_checks) {
2550 cleanup_milter_hbc_finish(state);
2551 myfree(var_milt_head_checks);
2552 var_milt_head_checks =
"";
2554 close_queue_file(state);
2558 argv->
argc > 1 ? argv->
argv[1] :
"",
2559 argv->
argc > 2 ? argv->
argv[2] :
"");
2560 }
else if (strcmp(argv->
argv[0],
"add_header") == 0) {
2561 if (argv->
argc < 2) {
2562 msg_warn(
"bad add_header argument count: %ld",
2565 flatten_args(arg_buf, argv->
argv + 2);
2566 resp = cleanup_add_header(state, argv->
argv[1],
" ",
STR(arg_buf));
2568 }
else if (strcmp(argv->
argv[0],
"ins_header") == 0) {
2569 if (argv->
argc < 3) {
2570 msg_warn(
"bad ins_header argument count: %ld",
2572 }
else if ((index = atoi(argv->
argv[1])) < 1) {
2573 msg_warn(
"bad ins_header index value");
2575 flatten_args(arg_buf, argv->
argv + 3);
2576 resp = cleanup_ins_header(state, index, argv->
argv[2],
" ",
STR(arg_buf));
2578 }
else if (strcmp(argv->
argv[0],
"upd_header") == 0) {
2579 if (argv->
argc < 3) {
2580 msg_warn(
"bad upd_header argument count: %ld",
2582 }
else if ((index = atoi(argv->
argv[1])) < 1) {
2583 msg_warn(
"bad upd_header index value");
2585 flatten_args(arg_buf, argv->
argv + 3);
2586 resp = cleanup_upd_header(state, index, argv->
argv[2],
" ",
STR(arg_buf));
2588 }
else if (strcmp(argv->
argv[0],
"del_header") == 0) {
2589 if (argv->
argc != 3) {
2590 msg_warn(
"bad del_header argument count: %ld",
2592 }
else if ((index = atoi(argv->
argv[1])) < 1) {
2593 msg_warn(
"bad del_header index value");
2595 cleanup_del_header(state, index, argv->
argv[2]);
2597 }
else if (strcmp(argv->
argv[0],
"chg_from") == 0) {
2598 if (argv->
argc != 3) {
2599 msg_warn(
"bad chg_from argument count: %ld", (
long) argv->
argc);
2601 char *arg = argv->
argv[2];
2604 if (*arg == parens[0]
2606 msg_warn(
"%s in \"%s\"", err, arg);
2608 cleanup_chg_from(state, argv->
argv[1], arg);
2611 }
else if (strcmp(argv->
argv[0],
"add_rcpt") == 0) {
2612 if (argv->
argc != 2) {
2613 msg_warn(
"bad add_rcpt argument count: %ld", (
long) argv->
argc);
2615 cleanup_add_rcpt(state, argv->
argv[1]);
2617 }
else if (strcmp(argv->
argv[0],
"add_rcpt_par") == 0) {
2618 if (argv->
argc != 3) {
2619 msg_warn(
"bad add_rcpt_par argument count: %ld",
2622 cleanup_add_rcpt_par(state, argv->
argv[1], argv->
argv[2]);
2624 }
else if (strcmp(argv->
argv[0],
"del_rcpt") == 0) {
2625 if (argv->
argc != 2) {
2626 msg_warn(
"bad del_rcpt argument count: %ld", (
long) argv->
argc);
2628 cleanup_del_rcpt(state, argv->
argv[1]);
2630 }
else if (strcmp(argv->
argv[0],
"replbody") == 0) {
2631 if (argv->
argc != 2) {
2632 msg_warn(
"bad replbody argument count: %ld", (
long) argv->
argc);
2649 }
else if (strcmp(argv->
argv[0],
"header_checks") == 0) {
2650 if (argv->
argc != 2) {
2651 msg_warn(
"bad header_checks argument count: %ld",
2653 }
else if (*var_milt_head_checks) {
2654 msg_warn(
"can't change header checks");
2657 cleanup_milter_header_checks_init(state);
2659 }
else if (strcmp(argv->
argv[0],
"sender_bcc_maps") == 0) {
2660 if (argv->
argc != 2) {
2661 msg_warn(
"bad sender_bcc_maps argument count: %ld",
2664 if (cleanup_send_bcc_maps)
2666 cleanup_send_bcc_maps =
2678 cleanup_milter_apply(state,
"END-OF-MESSAGE", resp);
2689 if (*var_milt_head_checks)
2690 myfree(var_milt_head_checks);
VSTRING * milter_ext_rcpt
MAPS * cleanup_send_bcc_maps
#define MAIL_ATTR_ACT_CLIENT_AF
#define vstring_fgets_nonl(s, p)
#define S8_MAC_DAEMON_ADDR
#define MAIL_ATTR_ACT_HELO_NAME
const CLEANUP_STAT_DETAIL * cleanup_stat_detail(unsigned status)
#define NO_NESTED_HDR_VALUE
#define HBC_CHECKS_STAT_UNKNOWN
void cleanup_out_format(CLEANUP_STATE *state, int type, const char *fmt,...)
MAPS * cleanup_rcpt_bcc_maps
char * mystrdup(const char *str)
void cleanup_envelope(CLEANUP_STATE *, int, const char *, ssize_t)
#define CLEANUP_UPD_HEADER_RETURN(ret)
int cleanup_map11_internal(CLEANUP_STATE *, VSTRING *, MAPS *, int)
char * extpar(char **bp, const char *parens, int flags)
char * var_milt_head_checks
VSTRING * cleanup_trace_path
int vstring_get_nonl(VSTRING *vp, VSTREAM *fp)
MAPS * cleanup_virt_alias_maps
ARGV * argv_free(ARGV *argvp)
#define CLEANUP_STAT_SIZE
ARGV * cleanup_map1n_internal(CLEANUP_STATE *, const char *, MAPS *, int)
void cleanup_milter_emul_data(CLEANUP_STATE *state, MILTERS *milters)
NORETURN msg_panic(const char *fmt,...)
off_t vstream_ftell(VSTREAM *stream)
off_t cleanup_addr_sender(CLEANUP_STATE *, const char *)
#define S8_MAC_CLIENT_ADDR
#define CLEANUP_INS_HEADER_RETURN(ret)
#define CLEANUP_FIND_HEADER_IOERROR
#define NO_MIME_HDR_VALUE
VSTRING * milter_err_text
#define inet_proto_info()
void cleanup_state_free(CLEANUP_STATE *)
MAPS * cleanup_rcpt_canon_maps
#define DONT_SKIP_HEADERS
int main(int argc, char **argv)
#define CLEANUP_MILTER_SET_SMTP_REPLY(__state, __smtp_reply)
off_t append_rcpt_pt_target
HBC_CHECKS * milter_hbc_checks
int rec_goto(VSTREAM *stream, const char *buf)
#define REC_TYPE_PTR_PAYL_SIZE
#define CLEANUP_OUT_BUF(s, t, b)
#define S8_MAC_AUTH_AUTHOR
int cleanup_comm_canon_flags
#define CLEANUP_FLAG_DISCARD
#define MAIL_ATTR_ACT_CLIENT_ADDR
#define MAIL_ATTR_ACT_SERVER_ADDR
#define CLEANUP_PATCH_HEADER_RETURN(ret)
#define DICT_FLAG_UTF8_REQUEST
#define MAIL_ATTR_SASL_METHOD
#define CLEANUP_MILTER_OK(s)
int alldig(const char *string)
ARGV * cleanup_masq_domains
const char * milter_message(MILTERS *milters, VSTREAM *fp, off_t data_offset, ARGV *auto_hdrs)
#define MAIL_ATTR_LOG_HELO_NAME
int cleanup_body_edit_write(CLEANUP_STATE *, int, VSTRING *)
const char * split_nameval(char *buf, char **name, char **value)
#define REC_TYPE_DSN_NOTIFY
#define CLEANUP_FLAG_HOLD
#define DICT_FLAG_FOLD_FIX
#define MAIL_ATTR_LOG_PROTO_NAME
int strncasecmp(const char *s1, const char *s2, size_t n)
const char * milter_helo_event(MILTERS *milters, const char *helo_name, int esmtp_flag)
int allspace(const char *string)
#define S8_MAC_DAEMON_NAME
#define NO_NESTED_HDR_NAME
MILTERS * milter_receive(VSTREAM *stream, int count)
VSTRING * vstring_strcpy(VSTRING *vp, const char *src)
TOK822 * tok822_free_tree(TOK822 *)
VSTREAM * vstream_fopen(const char *path, int flags, mode_t mode)
int cleanup_ext_prop_mask
int cleanup_body_edit_start(CLEANUP_STATE *)
#define VSTRING_TERMINATE(vp)
char * dsn_prepend(const char *def_dsn, const char *text)
#define CLEANUP_DEL_RCPT_RETURN(ret)
#define CLEANUP_FIND_HEADER_RETURN(offs)
off_t append_meta_pt_offset
int cleanup_rcpt_canon_flags
#define REC_PUT_BUF(v, t, b)
int rec_get_raw(VSTREAM *stream, VSTRING *buf, ssize_t maxsize, int flags)
#define CLEANUP_MILTER_REJECTING_OR_DISCARDING_MESSAGE(state)
#define VSTRING_ADDCH(vp, ch)
VSTRING * vstring_sprintf_append(VSTRING *vp, const char *format,...)
#define CLIENT_ATTR_UNKNOWN
#define MAIL_ATTR_ACT_CLIENT_PORT
const char * milter_mail_event(MILTERS *milters, const char **argv)
ARGV * argv_splitq(const char *, const char *, const char *)
#define REC_TYPE_DSN_ORCPT
#define REC_TYPE_PTR_FORMAT
VSTRING * milter_hbc_reply
off_t append_rcpt_pt_offset
#define S8_MAC_CLIENT_PTR
int dsn_notify_mask(const char *str)
MAPS * maps_create(const char *title, const char *map_names, int dict_flags)
int vstream_fclose(VSTREAM *stream)
#define CLEANUP_FIND_HEADER_NOTFOUND
int rec_pad(VSTREAM *stream, int type, ssize_t len)
const char * reverse_name
VSTREAM * vstream_printf(const char *fmt,...)
void cleanup_milter_receive(CLEANUP_STATE *state, int count)
off_t append_hdr_pt_offset
#define VSTRING_RESET(vp)
VSTRING * milter_ext_from
#define MAIL_ATTR_SASL_SENDER
int cleanup_body_edit_finish(CLEANUP_STATE *)
void msg_warn(const char *fmt,...)
char * hbc_header_checks(void *context, HBC_CHECKS *hbc, int header_class, const HEADER_OPTS *hdr_opts, VSTRING *header, off_t offset)
#define MAIL_ATTR_ACT_CLIENT_NAME
VSTRING * vstring_alloc(ssize_t len)
#define MAIL_ATTR_DSN_RET
#define STREQUAL(x, y, l)
unsigned char * sa_family_list
#define MAIL_ATTR_ACT_REVERSE_CLIENT_NAME
const char * milter_rcpt_event(MILTERS *milters, int flags, const char **argv)
int cleanup_send_canon_flags
VSTRING * vstring_sprintf(VSTRING *vp, const char *format,...)
#define MAIL_ATTR_DSN_ENVID
CLEANUP_STATE * cleanup_state_alloc(VSTREAM *)
char * var_milt_daemon_name
VSTRING * tok822_internalize(VSTRING *, TOK822 *, int)
void cleanup_milter_emul_rcpt(CLEANUP_STATE *state, MILTERS *milters, const char *addr)
int rec_attr_map(const char *attr_name)
void milter_free(MILTERS *milters)
#define MAIL_ATTR_ACT_SERVER_PORT
MAPS * cleanup_comm_canon_maps
#define CLEANUP_DEL_HEADER_RETURN(ret)
NORETURN msg_fatal(const char *fmt,...)
#define MILTER_BODY_START
#define CLEANUP_FLAG_FILTER_ALL
MAPS * maps_free(MAPS *maps)
off_t vstream_fseek(VSTREAM *stream, off_t offset, int whence)
void cleanup_milter_emul_mail(CLEANUP_STATE *state, MILTERS *milters, const char *addr)
const char * milter_data_event(MILTERS *milters)
#define VAR_MILT_HEAD_CHECKS
int vstream_fflush(VSTREAM *stream)
VSTRING * xtext_unquote(VSTRING *unquoted, const char *quoted)
#define CLEANUP_STAT_CONT
#define quote_821_local(dst, src)
off_t append_meta_pt_target
#define S8_MAC_DAEMON_PORT
ARGV * argv_split(const char *, const char *)
#define CLEANUP_OUT_OK(s)
#define GET_NEXT_TEXT_OR_PTR_RECORD(rec_type, state, buf, curr_offset, quit)
int dsn_ret_code(const char *str)
int cleanup_masquerade_internal(CLEANUP_STATE *, VSTRING *, ARGV *)
void milter_edit_callback(MILTERS *milters, MILTER_ADD_HEADER_FN add_header, MILTER_EDIT_HEADER_FN upd_header, MILTER_EDIT_HEADER_FN ins_header, MILTER_DEL_HEADER_FN del_header, MILTER_EDIT_FROM_FN chg_from, MILTER_EDIT_RCPT_FN add_rcpt, MILTER_EDIT_RCPT_PAR_FN add_rcpt_par, MILTER_EDIT_RCPT_FN del_rcpt, MILTER_EDIT_BODY_FN repl_body, void *chg_context)
#define MAIL_ATTR_SASL_USERNAME
HBC_CHECKS * hbc_header_checks_create(const char *header_checks_name, const char *header_checks_value, const char *mime_header_checks_name, const char *mime_header_checks_value, const char *nested_header_checks_name, const char *nested_header_checks_value, HBC_CALL_BACKS *call_backs)
int strcasecmp(const char *s1, const char *s2)
void const char void cleanup_out_header(CLEANUP_STATE *, VSTRING *)
#define CLEANUP_MILTER_SET_REASON(__state, __reason)
#define HBC_CHECKS_STAT_ERROR
VSTRING * vstring_free(VSTRING *vp)
#define S8_MAC_AUTH_AUTHEN
MAPS * cleanup_send_canon_maps
int allprint(const char *string)
#define vstream_fileno(vp)
void cleanup_addr_bcc_dsn(CLEANUP_STATE *, const char *, const char *, int)
const char * milter_conn_event(MILTERS *milters, const char *client_name, const char *client_addr, const char *client_port, unsigned addr_family)
void msg_vstream_init(const char *name, VSTREAM *vp)
#define S8_MAC_CLIENT_PORT
#define CLEANUP_STAT_WRITE
#define nvtable_find(table, key)
const char * cleanup_strerror(unsigned status)
off_t append_hdr_pt_target
#define S8_MAC_CLIENT_NAME
const char * cleanup_strflags(unsigned flags)
#define hbc_header_checks_free(hbc)
void cleanup_out_string(CLEANUP_STATE *, int, const char *)
#define CLEANUP_STAT_DEFER
MILTERS * cleanup_milters
void cleanup_milter_inspect(CLEANUP_STATE *state, MILTERS *milters)
#define CLEANUP_FLAG_BCC_OK
void milter_macro_callback(MILTERS *milters, const char *(*mac_lookup)(const char *, void *), void *mac_context)
int rec_fprintf(VSTREAM *stream, int type, const char *format,...)
#define DEF_DUP_FILTER_LIMIT
VSTRING * vstring_strcat(VSTRING *vp, const char *src)
#define SERVER_ATTR_UNKNOWN
VSTRING * cleanup_strip_chars
int cleanup_rewrite_internal(const char *, VSTRING *, const char *)
void msg_info(const char *fmt,...)
VSTRING * xtext_unquote_append(VSTRING *unquoted, const char *quoted)