Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  resolve.c

  Sprache: C
 

/*++
/* NAME
/* resolve 3
/* SUMMARY
/* mail address resolver
/* SYNOPSIS
/* #include "trivial-rewrite.h"
/*
/* void resolve_init(void)
/*
/* int resolve_class(domain)
/* const char *domain;
/*
/* void resolve_proto(context, stream)
/* RES_CONTEXT *context;
/* VSTREAM *stream;
/* DESCRIPTION
/* This module implements the trivial address resolving engine.
/* It distinguishes between local and remote mail, and optionally
/* consults one or more transport tables that map a destination
/* to a transport, nexthop pair.
/*
/* resolve_init() initializes data structures that are private
/* to this module. It should be called once before using the
/* actual resolver routines.
/*
/* resolve_class() returns the address class for the specified
/* domain, or -1 in case of error.
/*
/* resolve_proto() implements the client-server protocol:
/* read one address in FQDN form, reply with a (transport,
/* nexthop, internalized recipient) triple.
/* STANDARDS
/* DIAGNOSTICS
/* Problems and transactions are logged to \fBsyslogd\fR(8)
/* or \fBpostlogd\fR(8).
/* BUGS
/* SEE ALSO
/* LICENSE
/* .ad
/* .fi
/* The Secure Mailer license must be distributed with this software.
/* AUTHOR(S)
/* Wietse Venema
/* IBM T.J. Watson Research
/* P.O. Box 704
/* Yorktown Heights, NY 10598, USA
/*
/* Wietse Venema
/* Google, Inc.
/* 111 8th Avenue
/* New York, NY 10011, USA
/*--*/


/* System library. */

#include <sys_defs.h>
#include <stdlib.h>
#include <string.h>

#ifdef STRCASECMP_IN_STRINGS_H
#include <strings.h>
#endif

/* Utility library. */

#include <msg.h>
#include <vstring.h>
#include <vstream.h>
#include <vstring_vstream.h>
#include <split_at.h>
#include <valid_utf8_hostname.h>
#include <stringops.h>
#include <mymalloc.h>

/* Global library. */

#include <mail_params.h>
#include <mail_proto.h>
#include <resolve_local.h>
#include <mail_conf.h>
#include <quote_822_local.h>
#include <tok822.h>
#include <domain_list.h>
#include <string_list.h>
#include <match_parent_style.h>
#include <maps.h>
#include <mail_addr_find.h>
#include <valid_mailhost_addr.h>
#include <dsn_util.h>

/* Application-specific. */

#include "trivial-rewrite.h"
#include "transport.h"

 /*
  * The job of the address resolver is to map one recipient address to a
  * triple of (channel, nexthop, recipient). The channel is the name of the
  * delivery service specified in master.cf, the nexthop is (usually) a
  * description of the next host to deliver to, and recipient is the final
  * recipient address. The latter may differ from the input address as the
  * result of stripping multiple layers of sender-specified routing.
  * 
  * Addresses are resolved by their domain name. Known domain names are
  * categorized into classes: local, virtual alias, virtual mailbox, relay,
  * and everything else. Finding the address domain class is a matter of
  * table lookups.
  * 
  * Different address domain classes generally use different delivery channels,
  * and may use class dependent ways to arrive at the corresponding nexthop
  * information. With classes that do final delivery, the nexthop is
  * typically the local machine hostname.
  * 
  * The transport lookup table provides a means to override the domain class
  * channel and/or nexhop information for specific recipients or for entire
  * domain hierarchies.
  * 
  * This works well in the general case. The only bug in this approach is that
  * the structure of the nexthop information is transport dependent.
  * Typically, the nexthop specifies a hostname, hostname + TCP Port, or the
  * pathname of a UNIX-domain socket. However, with the error transport the
  * nexthop field contains free text with the reason for non-delivery.
  * 
  * Therefore, a transport map entry that overrides the channel but not the
  * nexthop information (or vice versa) may produce surprising results. In
  * particular, the free text nexthop information for the error transport is
  * likely to confuse regular delivery agents; and conversely, a hostname or
  * socket pathname is not an adequate text as reason for non-delivery.
  * 
  * In the code below, rcpt_domain specifies the domain name that we will use
  * when the transport table specifies a non-default channel but no nexthop
  * information (we use a generic text when that non-default channel is the
  * error transport).
  */


#define STR vstring_str
#define LEN VSTRING_LEN

 /*
  * Some of the lists that define the address domain classes.
  */

static DOMAIN_LIST *relay_domains;
static STRING_LIST *virt_alias_doms;
static STRING_LIST *virt_mailbox_doms;

static MAPS *relocated_maps;

/* resolve_class - determine domain address class */

int     resolve_class(const char *domain)
{
    int     ret;

    /*
     * Same order as in resolve_addr().
     */

    if ((ret = resolve_local(domain)) != 0)
 return (ret > 0 ? RESOLVE_CLASS_LOCAL : -1);
    if (virt_alias_doms) {
 if (string_list_match(virt_alias_doms, domain))
     return (RESOLVE_CLASS_ALIAS);
 if (virt_alias_doms->error)
     return (-1);
    }
    if (virt_mailbox_doms) {
 if (string_list_match(virt_mailbox_doms, domain))
     return (RESOLVE_CLASS_VIRTUAL);
 if (virt_mailbox_doms->error)
     return (-1);
    }
    if (relay_domains) {
 if (string_list_match(relay_domains, domain))
     return (RESOLVE_CLASS_RELAY);
 if (relay_domains->error)
     return (-1);
    }
    return (RESOLVE_CLASS_DEFAULT);
}

/* resolve_addr - resolve address according to rule set */

static void resolve_addr(RES_CONTEXT *rp, char *sender, char *addr,
            VSTRING *channel, VSTRING *nexthop,
            VSTRING *nextrcpt, int *flags)
{
    const char *myname = "resolve_addr";
    VSTRING *addr_buf = vstring_alloc(100);
    TOK822 *tree = 0;
    TOK822 *saved_domain = 0;
    TOK822 *domain = 0;
    char   *destination;
    const char *blame = 0;
    const char *rcpt_domain;
    ssize_t addr_len;
    ssize_t loop_count;
    ssize_t loop_max;
    char   *local;
    char   *oper;
    char   *junk;
    const char *relay;
    const char *xport;
    const char *sender_key;
    int     rc;

    *flags = 0;
    vstring_strcpy(channel, "CHANNEL NOT UPDATED");
    vstring_strcpy(nexthop, "NEXTHOP NOT UPDATED");
    vstring_strcpy(nextrcpt, "NEXTRCPT NOT UPDATED");

    /*
     * The address is in internalized (unquoted) form.
     * 
     * In an ideal world we would parse the externalized address form as given
     * to us by the sender.
     * 
     * However, in the real world we have to look for routing characters like
     * %@! in the address local-part, even when that information is quoted
     * due to the presence of special characters or whitespace. Although
     * technically incorrect, this is needed to stop user@domain@domain relay
     * attempts when forwarding mail to a Sendmail MX host.
     * 
     * This suggests that we parse the address in internalized (unquoted) form.
     * Unfortunately, if we do that, the unparser generates incorrect white
     * space between adjacent non-operator tokens. Example: ``first last''
     * needs white space, but ``stuff[stuff]'' does not. This is not a
     * problem when unparsing the result from parsing externalized forms,
     * because the parser/unparser were designed for valid externalized forms
     * where ``stuff[stuff]'' does not happen.
     * 
     * As a workaround we start with the quoted form and then dequote the
     * local-part only where needed. This will do the right thing in most
     * (but not all) cases.
     */

    addr_len = strlen(addr);
    quote_822_local(addr_buf, addr);
    tree = tok822_scan_addr(vstring_str(addr_buf));

    /*
     * The optimizer will eliminate tests that always fail, and will replace
     * multiple expansions of this macro by a GOTO to a single instance.
     */

#define FREE_MEMORY_AND_RETURN { \
 if (saved_domain) \
     tok822_free_tree(saved_domain); \
 if(tree) \
     tok822_free_tree(tree); \
 if (addr_buf) \
     vstring_free(addr_buf); \
 return; \
    }

    /*
     * Preliminary resolver: strip off all instances of the local domain.
     * Terminate when no destination domain is left over, or when the
     * destination domain is remote.
     * 
     * XXX To whom it may concern. If you change the resolver loop below, or
     * quote_822_local.c, or tok822_parse.c, be sure to re-run the tests
     * under "make resolve_clnt_test" in the global directory.
     */

#define RESOLVE_LOCAL(domain) \
    resolve_local(STR(tok822_internalize(addr_buf, domain, TOK822_STR_DEFL)))

    for (loop_count = 0, loop_max = addr_len + 100/* void */ ; loop_count++) {

 /*
  * XXX Should never happen, but if this happens with some
  * pathological address, then that is not sufficient reason to
  * disrupt the operation of an MTA.
 */

 if (loop_count > loop_max) {
     msg_warn("resolve_addr: <%s>: giving up after %ld iterations",
       addr, (long) loop_count);
     *flags |= RESOLVE_FLAG_FAIL;
     FREE_MEMORY_AND_RETURN;
     break;
 }

 /*
  * Strip trailing dot at end of domain, but not dot-dot or at-dot.
  * This merely makes diagnostics more accurate by leaving bogus
  * addresses alone.
 */

 if (tree->tail
     && tree->tail->type == '.'
     && tok822_rfind_type(tree->tail, '@') != 0
     && tree->tail->prev->type != '.'
     && tree->tail->prev->type != '@')
     tok822_free_tree(tok822_sub_keep_before(tree, tree->tail));

 /*
  * Strip trailing @.
 */

 if (var_resolve_nulldom
     && tree->tail
     && tree->tail->type == '@')
     tok822_free_tree(tok822_sub_keep_before(tree, tree->tail));

 /*
  * Strip (and save) @domain if local.
  * 
  * Grr. resolve_local() table lookups may fail. It may be OK for local
  * file lookup code to abort upon failure, but with network-based
  * tables it is preferable to return an error indication to the
  * requestor.
 */

 if ((domain = tok822_rfind_type(tree->tail, '@')) != 0) {
     if (domain->next && (rc = RESOLVE_LOCAL(domain->next)) <= 0) {
  if (rc < 0) {
      *flags |= RESOLVE_FLAG_FAIL;
      FREE_MEMORY_AND_RETURN;
  }
  break;
     }
     tok822_sub_keep_before(tree, domain);
     if (saved_domain)
  tok822_free_tree(saved_domain);
     saved_domain = domain;
     domain = 0;    /* safety for future change */
 }

 /*
  * After stripping the local domain, if any, replace foo%bar by
  * foo@bar, site!user by user@site, rewrite to canonical form, and
  * retry.
 */

 if (tok822_rfind_type(tree->tail, '@')
     || (var_swap_bangpath && tok822_rfind_type(tree->tail, '!'))
     || (var_percent_hack && tok822_rfind_type(tree->tail, '%'))) {
     rewrite_tree(&local_context, tree);
     continue;
 }

 /*
  * If the local-part is a quoted string, crack it open when we're
  * permitted to do so and look for routing operators. This is
  * technically incorrect, but is needed to stop relaying problems.
  * 
  * XXX Do another feeble attempt to keep local-part info quoted.
 */

 if (var_resolve_dequoted
     && tree->head && tree->head == tree->tail
     && tree->head->type == TOK822_QSTRING
     && ((oper = strrchr(local = STR(tree->head->vstr), '@')) != 0
  || (var_percent_hack && (oper = strrchr(local, '%')) != 0)
      || (var_swap_bangpath && (oper = strrchr(local, '!')) != 0))) {
     if (*oper == '%')
  *oper = '@';
     tok822_internalize(addr_buf, tree->head, TOK822_STR_DEFL);
     if (*oper == '@') {
  junk = mystrdup(STR(addr_buf));
  quote_822_local(addr_buf, junk);
  myfree(junk);
     }
     tok822_free(tree->head);
     tree->head = tok822_scan(STR(addr_buf), &tree->tail);
     rewrite_tree(&local_context, tree);
     continue;
 }

 /*
  * An empty local-part or an empty quoted string local-part becomes
  * the local MAILER-DAEMON, for consistency with our own From:
  * message headers.
 */

 if (tree->head && tree->head == tree->tail
     && tree->head->type == TOK822_QSTRING
     && VSTRING_LEN(tree->head->vstr) == 0) {
     tok822_free(tree->head);
     tree->head = 0;
 }
 /* XXX Re-resolve the surrogate, in case already in user@domain form. */
 if (tree->head == 0) {
     tree->head = tok822_scan(var_empty_addr, &tree->tail);
     continue;
 }
 /* XXX Re-resolve with @$myhostname for backwards compatibility. */
 if (domain == 0 && saved_domain == 0) {
     tok822_sub_append(tree, tok822_alloc('@', (char *) 0));
     tok822_sub_append(tree, tok822_scan(var_myhostname, (TOK822 **) 0));
     continue;
 }

 /*
  * We're done. There are no domains left to strip off the address,
  * and all null local-part information is sanitized.
 */

 domain = 0;
 break;
    }

    vstring_free(addr_buf);
    addr_buf = 0;

    /*
     * Make sure the resolved envelope recipient has the user@domain form. If
     * no domain was specified in the address, assume the local machine. See
     * above for what happens with an empty address.
     */

    if (domain == 0) {
 if (saved_domain) {
     tok822_sub_append(tree, saved_domain);
     saved_domain = 0;
 } else {
     tok822_sub_append(tree, tok822_alloc('@', (char *) 0));
     tok822_sub_append(tree, tok822_scan(var_myhostname, (TOK822 **) 0));
 }
    }

    /*
     * Transform the recipient address back to internal form.
     * 
     * XXX This may produce incorrect results if we cracked open a quoted
     * local-part with routing operators; see discussion above at the top of
     * the big loop.
     * 
     * XXX We explicitly disallow domain names in bare network address form. A
     * network address destination should be formatted according to RFC 2821:
     * it should be enclosed in [], and an IPv6 address should have an IPv6:
     * prefix.
     */

    tok822_internalize(nextrcpt, tree, TOK822_STR_DEFL);
    rcpt_domain = strrchr(STR(nextrcpt), '@') + 1;
    if (rcpt_domain == (char *) 1)
 msg_panic("no @ in address: \"%s\"", STR(nextrcpt));
    if (*rcpt_domain == '[') {
 if (!valid_mailhost_literal(rcpt_domain, DONT_GRIPE))
     *flags |= RESOLVE_FLAG_ERROR;
    } else if (var_smtputf8_enable
        && valid_utf8_stringz(STR(nextrcpt)) == 0) {
 *flags |= RESOLVE_FLAG_ERROR;
    } else if (!valid_utf8_hostname(var_smtputf8_enable, rcpt_domain,
        DONT_GRIPE)) {
 if (var_resolve_num_dom && valid_hostaddr(rcpt_domain, DONT_GRIPE)) {
     vstring_insert(nextrcpt, rcpt_domain - STR(nextrcpt), "["1);
     vstring_strcat(nextrcpt, "]");
     rcpt_domain = strrchr(STR(nextrcpt), '@') + 1;
     if ((rc = resolve_local(rcpt_domain)) > 0/* XXX */
  domain = 0;
     else if (rc < 0) {
  *flags |= RESOLVE_FLAG_FAIL;
  FREE_MEMORY_AND_RETURN;
     }
 } else {
     *flags |= RESOLVE_FLAG_ERROR;
 }
    }
    tok822_free_tree(tree);
    tree = 0;

    /*
     * XXX Short-cut invalid address forms.
     */

    if (*flags & RESOLVE_FLAG_ERROR) {
 *flags |= RESOLVE_CLASS_DEFAULT;
 FREE_MEMORY_AND_RETURN;
    }

    /*
     * Recognize routing operators in the local-part, even when we do not
     * recognize ! or % as valid routing operators locally. This is needed to
     * prevent backup MX hosts from relaying third-party destinations through
     * primary MX hosts, otherwise the backup host could end up on black
     * lists. Ignore local swap_bangpath and percent_hack settings because we
     * can't know how the next MX host is set up.
     */

    if (strcmp(STR(nextrcpt) + strcspn(STR(nextrcpt), "@!%") + 1, rcpt_domain))
 *flags |= RESOLVE_FLAG_ROUTED;

    /*
     * With local, virtual, relay, or other non-local destinations, give the
     * highest precedence to transport associated nexthop information.
     * 
     * Otherwise, with relay or other non-local destinations, the relayhost
     * setting overrides the recipient domain name, and the sender-dependent
     * relayhost overrides both.
     * 
     * XXX Nag if the recipient domain is listed in multiple domain lists. The
     * result is implementation defined, and may break when internals change.
     * 
     * For now, we distinguish only a fixed number of address classes.
     * Eventually this may become extensible, so that new classes can be
     * configured with their own domain list, delivery transport, and
     * recipient table.
     */

#define STREQ(x,y) (strcmp((x), (y)) == 0)

    if (domain != 0) {

 /*
  * Virtual alias domain.
 */

 if (virt_alias_doms
     && string_list_match(virt_alias_doms, rcpt_domain)) {
     if (var_helpful_warnings) {
  if (virt_mailbox_doms
      && string_list_match(virt_mailbox_doms, rcpt_domain))
      msg_warn("do not list domain %s in BOTH %s and %s",
        rcpt_domain, VAR_VIRT_ALIAS_DOMS,
        VAR_VIRT_MAILBOX_DOMS);
  if (relay_domains
      && domain_list_match(relay_domains, rcpt_domain))
      msg_warn("do not list domain %s in BOTH %s and %s",
        rcpt_domain, VAR_VIRT_ALIAS_DOMS,
        VAR_RELAY_DOMAINS);
#if 0
  if (strcasecmp_utf8(rcpt_domain, var_myorigin) == 0)
      msg_warn("do not list $%s (%s) in %s",
      VAR_MYORIGIN, var_myorigin, VAR_VIRT_ALIAS_DOMS);
#endif
     }
     vstring_strcpy(channel, MAIL_SERVICE_ERROR);
     vstring_sprintf(nexthop, "5.1.1 User unknown%s",
       var_show_unk_rcpt_table ?
       " in virtual alias table" : "");
     *flags |= RESOLVE_CLASS_ALIAS;
 } else if (virt_alias_doms && virt_alias_doms->error != 0) {
     msg_warn("%s lookup failure", VAR_VIRT_ALIAS_DOMS);
     *flags |= RESOLVE_FLAG_FAIL;
     FREE_MEMORY_AND_RETURN;
 }

 /*
  * Virtual mailbox domain.
 */

 else if (virt_mailbox_doms
   && string_list_match(virt_mailbox_doms, rcpt_domain)) {
     if (var_helpful_warnings) {
  if (relay_domains
      && domain_list_match(relay_domains, rcpt_domain))
      msg_warn("do not list domain %s in BOTH %s and %s",
        rcpt_domain, VAR_VIRT_MAILBOX_DOMS,
        VAR_RELAY_DOMAINS);
     }
     vstring_strcpy(channel, RES_PARAM_VALUE(rp->virt_transport));
     vstring_strcpy(nexthop, rcpt_domain);
     blame = rp->virt_transport_name;
     *flags |= RESOLVE_CLASS_VIRTUAL;
 } else if (virt_mailbox_doms && virt_mailbox_doms->error != 0) {
     msg_warn("%s lookup failure", VAR_VIRT_MAILBOX_DOMS);
     *flags |= RESOLVE_FLAG_FAIL;
     FREE_MEMORY_AND_RETURN;
 } else {

     /*
      * Off-host relay destination.
     */

     if (relay_domains
  && domain_list_match(relay_domains, rcpt_domain)) {
  vstring_strcpy(channel, RES_PARAM_VALUE(rp->relay_transport));
  blame = rp->relay_transport_name;
  *flags |= RESOLVE_CLASS_RELAY;
     } else if (relay_domains && relay_domains->error != 0) {
  msg_warn("%s lookup failure", VAR_RELAY_DOMAINS);
  *flags |= RESOLVE_FLAG_FAIL;
  FREE_MEMORY_AND_RETURN;
     }

     /*
      * Other off-host destination.
     */

     else {
  if (rp->snd_def_xp_info
      && (xport = mail_addr_find(rp->snd_def_xp_info,
         sender_key = (*sender ? sender :
            var_null_def_xport_maps_key),
            (char **) 0)) != 0) {
      if (*xport == 0) {
   msg_warn("%s: ignoring null lookup result for %s",
     rp->snd_def_xp_maps_name, sender_key);
   xport = "DUNNO";
      }
      vstring_strcpy(channel, strcasecmp(xport, "DUNNO") == 0 ?
    RES_PARAM_VALUE(rp->def_transport) : xport);
      blame = rp->snd_def_xp_maps_name;
  } else if (rp->snd_def_xp_info
      && rp->snd_def_xp_info->error != 0) {
      msg_warn("%s lookup failure", rp->snd_def_xp_maps_name);
      *flags |= RESOLVE_FLAG_FAIL;
      FREE_MEMORY_AND_RETURN;
  } else {
      vstring_strcpy(channel, RES_PARAM_VALUE(rp->def_transport));
      blame = rp->def_transport_name;
  }
  *flags |= RESOLVE_CLASS_DEFAULT;
     }

     /*
      * With off-host delivery, sender-dependent or global relayhost
      * override the recipient domain.
     */

     if (rp->snd_relay_info
  && (relay = mail_addr_find(rp->snd_relay_info,
        sender_key = (*sender ? sender :
         var_null_relay_maps_key),
        (char **) 0)) != 0) {
  if (*relay == 0) {
      msg_warn("%s: ignoring null lookup result for %s",
        rp->snd_relay_maps_name, sender_key);
      relay = 0;
  } else if (strcasecmp_utf8(relay, "DUNNO") == 0)
      relay = 0;
     } else if (rp->snd_relay_info
         && rp->snd_relay_info->error != 0) {
  msg_warn("%s lookup failure", rp->snd_relay_maps_name);
  *flags |= RESOLVE_FLAG_FAIL;
  FREE_MEMORY_AND_RETURN;
     } else {
  relay = 0;
     }
     /* Enforce all the relayhost precedences in one place. */
     if (relay != 0) {
  vstring_strcpy(nexthop, relay);
     } else if (*RES_PARAM_VALUE(rp->relayhost))
  vstring_strcpy(nexthop, RES_PARAM_VALUE(rp->relayhost));
     else
  vstring_strcpy(nexthop, rcpt_domain);
 }
    }

    /*
     * Local delivery.
     * 
     * XXX Nag if the domain is listed in multiple domain lists. The effect is
     * implementation defined, and may break when internals change.
     */

    else {
 if (var_helpful_warnings) {
     if (virt_alias_doms
  && string_list_match(virt_alias_doms, rcpt_domain))
  msg_warn("do not list domain %s in BOTH %s and %s",
    rcpt_domain, VAR_MYDEST, VAR_VIRT_ALIAS_DOMS);
     if (virt_mailbox_doms
  && string_list_match(virt_mailbox_doms, rcpt_domain))
  msg_warn("do not list domain %s in BOTH %s and %s",
    rcpt_domain, VAR_MYDEST, VAR_VIRT_MAILBOX_DOMS);
 }
 vstring_strcpy(channel, RES_PARAM_VALUE(rp->local_transport));
 vstring_strcpy(nexthop, rcpt_domain);
 blame = rp->local_transport_name;
 *flags |= RESOLVE_CLASS_LOCAL;
    }

    /*
     * An explicit main.cf transport:nexthop setting overrides the nexthop.
     * 
     * XXX We depend on this mechanism to enforce per-recipient concurrencies
     * for local recipients. With "local_transport = local:$myhostname" we
     * force mail for any domain in $mydestination/${proxy,inet}_interfaces
     * to share the same queue.
     */

    if ((destination = split_at(STR(channel), ':')) != 0 && *destination)
 vstring_strcpy(nexthop, destination);

    /*
     * Sanity checks.
     */

    if (*STR(channel) == 0) {
 if (blame == 0)
     msg_panic("%s: null blame", myname);
 msg_warn("file %s/%s: parameter %s: null transport is not allowed",
   var_config_dir, MAIN_CONF_FILE, blame);
 *flags |= RESOLVE_FLAG_FAIL;
 FREE_MEMORY_AND_RETURN;
    }
    if (*STR(nexthop) == 0)
 msg_panic("%s: null nexthop", myname);

    /*
     * The transport map can selectively override any transport and/or
     * nexthop host info that is set up above. Unfortunately, the syntax for
     * nexthop information is transport specific. We therefore need sane and
     * intuitive semantics for transport map entries that specify a channel
     * but no nexthop.
     * 
     * With non-error transports, the initial nexthop information is the
     * recipient domain. However, specific main.cf transport definitions may
     * specify a transport-specific destination, such as a host + TCP socket,
     * or the pathname of a UNIX-domain socket. With less precedence than
     * main.cf transport definitions, a main.cf relayhost definition may also
     * override nexthop information for off-host deliveries.
     * 
     * With the error transport, the nexthop information is free text that
     * specifies the reason for non-delivery.
     * 
     * Because nexthop syntax is transport specific we reset the nexthop
     * information to the recipient domain when the transport table specifies
     * a transport without also specifying the nexthop information.
     * 
     * Subtle note: reset nexthop even when the transport table does not change
     * the transport. Otherwise it is hard to get rid of main.cf specified
     * nexthop information.
     * 
     * XXX Don't override the virtual alias class (error:User unknown) result.
     */

    if (rp->transport_info && !(*flags & RESOLVE_CLASS_ALIAS)) {
 if (transport_lookup(rp->transport_info, STR(nextrcpt),
        rcpt_domain, channel, nexthop) == 0
     && rp->transport_info->transport_path->error != 0) {
     msg_warn("%s lookup failure", rp->transport_maps_name);
     *flags |= RESOLVE_FLAG_FAIL;
     FREE_MEMORY_AND_RETURN;
 }
    }

    /*
     * Bounce recipients that have moved, regardless of domain address class.
     * We do this last, in anticipation of transport maps that can override
     * the recipient address.
     * 
     * The downside of not doing this in delivery agents is that this table has
     * no effect on local alias expansion results. Such mail will have to
     * make almost an entire iteration through the mail system.
     */

#define IGNORE_ADDR_EXTENSION   ((char **) 0)

    if (relocated_maps != 0) {
 const char *reply;
 DSN_SPLIT dp;

 if ((reply = mail_addr_find(relocated_maps, STR(nextrcpt),
        IGNORE_ADDR_EXTENSION)) != 0) {
     vstring_strcpy(channel, MAIL_SERVICE_ERROR);
     if (var_enb_relocated_pfx) {
  /* 5.1.6 is the closest match, but not perfect. */
  vstring_sprintf(nexthop, "5.1.6 User has moved to %s", reply);
     } else if (!dsn_valid(reply)
         || dsn_split(&dp, "5.2.0", reply)->text[0] == 0) {
  msg_warn("%s result must contain RFC 3463 status and text: '%.100s'",
    VAR_RELOCATED_MAPS, reply);
  vstring_sprintf(nexthop, "5.2.0 Mailbox is unavailable");
     } else {
  vstring_sprintf(nexthop, "%s %s", DSN_STATUS(dp.dsn), dp.text);
     }
 } else if (relocated_maps->error != 0) {
     msg_warn("%s lookup failure", VAR_RELOCATED_MAPS);
     *flags |= RESOLVE_FLAG_FAIL;
     FREE_MEMORY_AND_RETURN;
 }
    }

    /*
     * Bounce recipient addresses that start with `-'. External commands may
     * misinterpret such addresses as command-line options.
     * 
     * In theory I could say people should always carefully set up their
     * master.cf pipe mailer entries with `--' before the first non-option
     * argument, but mistakes will happen regardless.
     * 
     * Therefore the protection is put in place here, where it cannot be
     * bypassed.
     */

    if (var_allow_min_user == 0 && STR(nextrcpt)[0] == '-') {
 *flags |= RESOLVE_FLAG_ERROR;
 FREE_MEMORY_AND_RETURN;
    }

    /*
     * Clean up.
     */

    FREE_MEMORY_AND_RETURN;
}

/* Static, so they can be used by the network protocol interface only. */

static VSTRING *channel;
static VSTRING *nexthop;
static VSTRING *nextrcpt;
static VSTRING *query;
static VSTRING *sender;

/* resolve_proto - read request and send reply */

int     resolve_proto(RES_CONTEXT *context, VSTREAM *stream)
{
    int     flags;

    if (attr_scan(stream, ATTR_FLAG_STRICT,
    RECV_ATTR_STR(MAIL_ATTR_SENDER, sender),
    RECV_ATTR_STR(MAIL_ATTR_ADDR, query),
    ATTR_TYPE_END) != 2)
 return (-1);

    resolve_addr(context, STR(sender), STR(query),
   channel, nexthop, nextrcpt, &flags);

    if (msg_verbose)
 msg_info("`%s' -> `%s' -> (`%s' `%s' `%s' `%d')",
   STR(sender), STR(query), STR(channel),
   STR(nexthop), STR(nextrcpt), flags);

    attr_print(stream, ATTR_FLAG_NONE,
        SEND_ATTR_INT(MAIL_ATTR_FLAGS, server_flags),
        SEND_ATTR_STR(MAIL_ATTR_TRANSPORT, STR(channel)),
        SEND_ATTR_STR(MAIL_ATTR_NEXTHOP, STR(nexthop)),
        SEND_ATTR_STR(MAIL_ATTR_RECIP, STR(nextrcpt)),
        SEND_ATTR_INT(MAIL_ATTR_FLAGS, flags),
        ATTR_TYPE_END);

    if (vstream_fflush(stream) != 0) {
 msg_warn("write resolver reply: %m");
 return (-1);
    }
    return (0);
}

/* resolve_init - module initializations */

void    resolve_init(void)
{
    sender = vstring_alloc(100);
    query = vstring_alloc(100);
    channel = vstring_alloc(100);
    nexthop = vstring_alloc(100);
    nextrcpt = vstring_alloc(100);

    if (*var_virt_alias_doms)
 virt_alias_doms =
     string_list_init(VAR_VIRT_ALIAS_DOMS, MATCH_FLAG_RETURN,
        var_virt_alias_doms);

    if (*var_virt_mailbox_doms)
 virt_mailbox_doms =
     string_list_init(VAR_VIRT_MAILBOX_DOMS, MATCH_FLAG_RETURN,
        var_virt_mailbox_doms);

    if (*var_relay_domains)
 relay_domains =
     domain_list_init(VAR_RELAY_DOMAINS, MATCH_FLAG_RETURN
        | match_parent_style(VAR_RELAY_DOMAINS),
        var_relay_domains);

    if (*var_relocated_maps)
 relocated_maps =
     maps_create(VAR_RELOCATED_MAPS, var_relocated_maps,
   DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX
   | DICT_FLAG_UTF8_REQUEST);
}

Messung V0.5 in Prozent
C=74 H=95 G=84

¤ Dauer der Verarbeitung: 0.38 Sekunden  (vorverarbeitet am  2026-08-08) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=141584
#Domains=752002