ARGV *cleanup_map1n_internal(CLEANUP_STATE *state, const char *addr, MAPS *maps, int propagate) { ARGV *argv; ARGV *lookup; int count; int i; int arg; BH_TABLE *been_here; char *saved_lhs; /* * Initialize. */ argv = argv_alloc(1); argv_add(argv, addr, ARGV_END); argv_terminate(argv); been_here = been_here_init(0, BH_FLAG_FOLD); /* * Rewrite the address vector in place. With each map lookup result, * split it into separate addresses, then rewrite and flatten each * address, and repeat the process. Beware: argv is being changed, so we * must index the array explicitly, instead of running along it with a * pointer. */ #define UPDATE(ptr,new) do { \ if (ptr) myfree(ptr); ptr = mystrdup(new); \ } while (0) #define STR vstring_str #define RETURN(x) do { \ been_here_free(been_here); return (x); \ } while (0) #define UNEXPAND(argv, addr) do { \ argv_truncate((argv), 0); argv_add((argv), (addr), (char *) 0); \ } while (0) for (arg = 0; arg < argv->argc; arg++) { if (argv->argc > var_virt_expan_limit) { msg_warn("%s: unreasonable %s map expansion size for %s -- " "message not accepted, try again later", state->queue_id, maps->title, addr); state->errs |= CLEANUP_STAT_DEFER; UPDATE(state->reason, "4.6.0 Alias expansion error"); UNEXPAND(argv, addr); RETURN(argv); } for (count = 0; /* void */ ; count++) { /* * Don't expand an address that already expanded into itself. */ if (been_here_check_fixed(been_here, argv->argv[arg]) != 0) break; if (count >= var_virt_recur_limit) { msg_warn("%s: unreasonable %s map nesting for %s -- " "message not accepted, try again later", state->queue_id, maps->title, addr); state->errs |= CLEANUP_STAT_DEFER; UPDATE(state->reason, "4.6.0 Alias expansion error"); UNEXPAND(argv, addr); RETURN(argv); } quote_822_local(state->temp1, argv->argv[arg]); if ((lookup = mail_addr_map(maps, STR(state->temp1), propagate)) != 0) { saved_lhs = mystrdup(argv->argv[arg]); for (i = 0; i < lookup->argc; i++) { unquote_822_local(state->temp1, lookup->argv[i]); if (i == 0) { UPDATE(argv->argv[arg], STR(state->temp1)); } else { argv_add(argv, STR(state->temp1), ARGV_END); argv_terminate(argv); } /* * Allow an address to expand into itself once. */ if (strcasecmp(saved_lhs, STR(state->temp1)) == 0) been_here_fixed(been_here, saved_lhs); } myfree(saved_lhs); argv_free(lookup); } else if (maps->error != 0) { msg_warn("%s: %s map lookup problem for %s -- " "message not accepted, try again later", state->queue_id, maps->title, addr); state->errs |= CLEANUP_STAT_WRITE; UPDATE(state->reason, "4.6.0 Alias expansion error"); UNEXPAND(argv, addr); RETURN(argv); } else { break; } } } RETURN(argv); }
static int local_deliver(DELIVER_REQUEST *rqst, char *service) { const char *myname = "local_deliver"; RECIPIENT *rcpt_end = rqst->rcpt_list.info + rqst->rcpt_list.len; RECIPIENT *rcpt; int rcpt_stat; int msg_stat; LOCAL_STATE state; USER_ATTR usr_attr; if (msg_verbose) msg_info("local_deliver: %s from %s", rqst->queue_id, rqst->sender); /* * Initialize the delivery attributes that are not recipient specific. * While messages are being delivered and while aliases or forward files * are being expanded, this attribute list is being changed constantly. * For this reason, the list is passed on by value (except when it is * being initialized :-), so that there is no need to undo attribute * changes made by lower-level routines. The alias/include/forward * expansion attribute list is part of a tree with self and parent * references (see the EXPAND_ATTR definitions). The user-specific * attributes are security sensitive, and are therefore kept separate. * All this results in a noticeable level of clumsiness, but passing * things around by value gives good protection against accidental change * by subroutines. */ state.level = 0; deliver_attr_init(&state.msg_attr); state.msg_attr.queue_name = rqst->queue_name; state.msg_attr.queue_id = rqst->queue_id; state.msg_attr.fp = rqst->fp; state.msg_attr.offset = rqst->data_offset; state.msg_attr.encoding = rqst->encoding; state.msg_attr.sender = rqst->sender; state.msg_attr.dsn_envid = rqst->dsn_envid; state.msg_attr.dsn_ret = rqst->dsn_ret; state.msg_attr.relay = service; state.msg_attr.msg_stats = rqst->msg_stats; state.msg_attr.request = rqst; RESET_OWNER_ATTR(state.msg_attr, state.level); RESET_USER_ATTR(usr_attr, state.level); state.loop_info = delivered_hdr_init(rqst->fp, rqst->data_offset, FOLD_ADDR_ALL); state.request = rqst; /* * Iterate over each recipient named in the delivery request. When the * mail delivery status for a given recipient is definite (i.e. bounced * or delivered), update the message queue file and cross off the * recipient. Update the per-message delivery status. */ for (msg_stat = 0, rcpt = rqst->rcpt_list.info; rcpt < rcpt_end; rcpt++) { state.dup_filter = been_here_init(var_dup_filter_limit, BH_FLAG_FOLD); forward_init(); state.msg_attr.rcpt = *rcpt; rcpt_stat = deliver_recipient(state, usr_attr); rcpt_stat |= forward_finish(rqst, state.msg_attr, rcpt_stat); if (rcpt_stat == 0 && (rqst->flags & DEL_REQ_FLAG_SUCCESS)) deliver_completed(state.msg_attr.fp, rcpt->offset); been_here_free(state.dup_filter); msg_stat |= rcpt_stat; } /* * Clean up. */ delivered_hdr_free(state.loop_info); deliver_attr_free(&state.msg_attr); return (msg_stat); }
CLEANUP_STATE *cleanup_state_alloc(VSTREAM *src) { CLEANUP_STATE *state = (CLEANUP_STATE *) mymalloc(sizeof(*state)); state->attr_buf = vstring_alloc(10); state->temp1 = vstring_alloc(10); state->temp2 = vstring_alloc(10); if (cleanup_strip_chars) state->stripped_buf = vstring_alloc(10); state->src = src; state->dst = 0; state->handle = 0; state->queue_name = 0; state->queue_id = 0; state->arrival_time.tv_sec = state->arrival_time.tv_usec = 0; state->fullname = 0; state->sender = 0; state->recip = 0; state->orig_rcpt = 0; state->return_receipt = 0; state->errors_to = 0; state->auto_hdrs = argv_alloc(1); state->hbc_rcpt = 0; state->flags = 0; state->qmgr_opts = 0; state->errs = 0; state->err_mask = 0; state->headers_seen = 0; state->hop_count = 0; state->resent = ""; state->dups = been_here_init(var_dup_filter_limit, BH_FLAG_FOLD); state->action = cleanup_envelope; state->data_offset = -1; state->body_offset = -1; state->xtra_offset = -1; state->cont_length = 0; state->sender_pt_offset = -1; state->sender_pt_target = -1; state->append_rcpt_pt_offset = -1; state->append_rcpt_pt_target = -1; state->append_hdr_pt_offset = -1; state->append_hdr_pt_target = -1; state->append_meta_pt_offset = -1; state->append_meta_pt_target = -1; state->milter_hbc_checks = 0; state->milter_hbc_reply = 0; state->rcpt_count = 0; state->reason = 0; state->smtp_reply = 0; state->attr = nvtable_create(10); nvtable_update(state->attr, MAIL_ATTR_LOG_ORIGIN, MAIL_ATTR_ORG_LOCAL); state->mime_state = 0; state->mime_errs = 0; state->hdr_rewrite_context = MAIL_ATTR_RWR_LOCAL; state->filter = 0; state->redirect = 0; state->dsn_envid = 0; state->dsn_ret = 0; state->dsn_notify = 0; state->dsn_orcpt = 0; state->verp_delims = 0; state->milters = 0; state->client_name = 0; state->reverse_name = 0; state->client_addr = 0; state->client_af = 0; state->client_port = 0; state->milter_ext_from = 0; state->milter_ext_rcpt = 0; state->milter_err_text = 0; state->free_regions = state->body_regions = state->curr_body_region = 0; state->smtputf8 = 0; return (state); }