int bounce_workaround(LOCAL_STATE state) { const char *myname = "bounce_workaround"; VSTRING *canon_owner = 0; int rcpt_stat; /* * Look up the substitute sender address. */ if (var_ownreq_special) { char *stripped_recipient; char *owner_alias; const char *owner_expansion; #define FIND_OWNER(lhs, rhs, addr) { \ lhs = concatenate("owner-", addr, (char *) 0); \ (void) split_at_right(lhs, '@'); \ rhs = maps_find(alias_maps, lhs, DICT_FLAG_NONE); \ } FIND_OWNER(owner_alias, owner_expansion, state.msg_attr.rcpt.address); if (alias_maps->error == 0 && owner_expansion == 0 && (stripped_recipient = strip_addr(state.msg_attr.rcpt.address, (char **) 0, var_rcpt_delim)) != 0) { myfree(owner_alias); FIND_OWNER(owner_alias, owner_expansion, stripped_recipient); myfree(stripped_recipient); } if (alias_maps->error == 0 && owner_expansion != 0) { canon_owner = canon_addr_internal(vstring_alloc(10), var_exp_own_alias ? owner_expansion : owner_alias); SET_OWNER_ATTR(state.msg_attr, STR(canon_owner), state.level); } myfree(owner_alias); if (alias_maps->error != 0) /* At this point, canon_owner == 0. */ return (defer_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr))); } /* * Send a delivery status notification with a single recipient to the * substitute sender address, before completion of the delivery request. */ if (canon_owner) { rcpt_stat = bounce_one(BOUNCE_FLAGS(state.request), BOUNCE_ONE_ATTR(state.msg_attr)); vstring_free(canon_owner); } /* * Send a regular delivery status notification, after completion of the * delivery request. */ else { rcpt_stat = bounce_append(BOUNCE_FLAGS(state.request), BOUNCE_ATTR(state.msg_attr)); } return (rcpt_stat); }
const char *mail_addr_find(MAPS *path, const char *address, char **extp) { const char *myname = "mail_addr_find"; const char *result; char *ratsign = 0; char *full_key; char *bare_key; char *saved_ext; int rc = 0; /* * Initialize. */ full_key = mystrdup(address); if (*var_rcpt_delim == 0) { bare_key = saved_ext = 0; } else { bare_key = strip_addr(full_key, &saved_ext, *var_rcpt_delim); } /* * Try user+foo@domain and user@domain. * * Specify what keys are partial or full, to avoid matching partial * addresses with regular expressions. */ #define FULL 0 #define PARTIAL DICT_FLAG_FIXED if ((result = maps_find(path, full_key, FULL)) == 0 && path->error == 0 && bare_key != 0 && (result = maps_find(path, bare_key, PARTIAL)) != 0 && extp != 0) { *extp = saved_ext; saved_ext = 0; } /* * Try user+foo@$myorigin, user+foo@$mydestination or * user+foo@[${proxy,inet}_interfaces]. Then try with +foo stripped off. */ if (result == 0 && path->error == 0 && (ratsign = strrchr(full_key, '@')) != 0 && (strcasecmp(ratsign + 1, var_myorigin) == 0 || (rc = resolve_local(ratsign + 1)) > 0)) { *ratsign = 0; result = maps_find(path, full_key, PARTIAL); if (result == 0 && path->error == 0 && bare_key != 0) { if ((ratsign = strrchr(bare_key, '@')) == 0) msg_panic("%s: bare key botch", myname); *ratsign = 0; if ((result = maps_find(path, bare_key, PARTIAL)) != 0 && extp != 0) { *extp = saved_ext; saved_ext = 0; } } *ratsign = '@'; } else if (rc < 0) path->error = rc; /* * Try @domain. */ if (result == 0 && path->error == 0 && ratsign) result = maps_find(path, ratsign, PARTIAL); /* * Clean up. */ if (msg_verbose) msg_info("%s: %s -> %s", myname, address, result ? result : path->error ? "(try again)" : "(not found)"); myfree(full_key); if (bare_key) myfree(bare_key); if (saved_ext) myfree(saved_ext); return (result); }
int transport_lookup(TRANSPORT_INFO *tp, const char *addr, const char *rcpt_domain, VSTRING *channel, VSTRING *nexthop) { char *stripped_addr; char *ratsign = 0; const char *name; const char *next; int found; #define STREQ(x,y) (strcmp((x), (y)) == 0) #define DISCARD_EXTENSION ((char **) 0) /* * The null recipient is rewritten to the local mailer daemon address. */ if (*addr == 0) { msg_warn("transport_lookup: null address - skipping table lookup"); return (NOTFOUND); } /* * Look up the full address with the FULL flag to include regexp maps in * the query. */ if ((ratsign = strrchr(addr, '@')) == 0 || ratsign[1] == 0) msg_panic("transport_lookup: bad address: \"%s\"", addr); if (find_transport_entry(tp, addr, rcpt_domain, FULL, channel, nexthop)) return (FOUND); if (tp->transport_path->error != 0) return (NOTFOUND); /* * If the full address did not match, and there is an address extension, * look up the stripped address with the PARTIAL flag to avoid matching * partial lookup keys with regular expressions. */ if ((stripped_addr = strip_addr(addr, DISCARD_EXTENSION, var_rcpt_delim)) != 0) { found = find_transport_entry(tp, stripped_addr, rcpt_domain, PARTIAL, channel, nexthop); myfree(stripped_addr); if (found) return (FOUND); if (tp->transport_path->error != 0) return (NOTFOUND); } /* * If the full and stripped address lookup fails, try domain name lookup. * * Keep stripping domain components until nothing is left or until a * matching entry is found. * * After checking the full domain name, check for .upper.domain, to * distinguish between the parent domain and it's decendants, a la * sendmail and tcp wrappers. * * Before changing the DB lookup result, make a copy first, in order to * avoid DB cache corruption. * * Specify that the lookup key is partial, to avoid matching partial keys * with regular expressions. */ for (name = ratsign + 1; *name != 0; name = next) { if (find_transport_entry(tp, name, rcpt_domain, PARTIAL, channel, nexthop)) return (FOUND); if (tp->transport_path->error != 0) return (NOTFOUND); if ((next = strchr(name + 1, '.')) == 0) break; if (transport_match_parent_style == MATCH_FLAG_PARENT) next++; } /* * Fall back to the wild-card entry. */ if (tp->wildcard_errno || event_time() > tp->expire) transport_wildcard_init(tp); if (tp->wildcard_errno) { tp->transport_path->error = tp->wildcard_errno; return (NOTFOUND); } else if (tp->wildcard_channel) { update_entry(STR(tp->wildcard_channel), STR(tp->wildcard_nexthop), rcpt_domain, channel, nexthop); return (FOUND); } /* * We really did not find it. */ return (NOTFOUND); }