Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Postfix/src/local/   (Postfix Mailserver Version 3.11©)  Datei vom 11.9.2024 mit Größe 12 kB image not shown  

Quelle  alias.c

  Sprache: C
 

/*++
/* NAME
/* alias 3
/* SUMMARY
/* alias data base lookups
/* SYNOPSIS
/* #include "local.h"
/*
/* int deliver_alias(state, usr_attr, name, statusp)
/* LOCAL_STATE state;
/* USER_ATTR usr_attr;
/* char *name;
/* int *statusp;
/* DESCRIPTION
/* deliver_alias() looks up the expansion of the recipient in
/* the global alias database and delivers the message to the
/* listed destinations. The result is zero when no alias was found
/* or when the message should be delivered to the user instead.
/*
/* deliver_alias() has wired-in knowledge about a few reserved
/* recipient names.
/* .IP \(bu
/* When no alias is found for the local \fIpostmaster\fR or
/* \fImailer-daemon\fR a warning is issued and the message
/* is discarded.
/* .IP \(bu
/* When an alias exists for recipient \fIname\fR, and an alias
/* exists for \fIowner-name\fR, the sender address is changed
/* to \fIowner-name\fR, and the owner delivery attribute is
/* set accordingly. This feature is disabled with
/* "owner_request_special = no".
/* .PP
/* Arguments:
/* .IP state
/* Attributes that specify the message, recipient and more.
/* Expansion type (alias, include, .forward).
/* A table with the results from expanding aliases or lists.
/* A table with delivered-to: addresses taken from the message.
/* .IP usr_attr
/* User attributes (rights, environment).
/* .IP name
/* The alias to be looked up.
/* .IP statusp
/* Delivery status. See below.
/* DIAGNOSTICS
/* Fatal errors: out of memory. The delivery status is non-zero
/* when delivery should be tried again.
/* 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
/*--*/


/* System library. */

#include <sys_defs.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>

/* Utility library. */

#include <msg.h>
#include <htable.h>
#include <dict.h>
#include <argv.h>
#include <stringops.h>
#include <mymalloc.h>
#include <vstring.h>
#include <vstream.h>

/* Global library. */

#include <mail_params.h>
#include <defer.h>
#include <maps.h>
#include <bounce.h>
#include <mypwd.h>
#include <canon_addr.h>
#include <sent.h>
#include <trace.h>
#include <dsn_mask.h>

/* Application-specific. */

#include "local.h"

/* Application-specific. */

#define NO 0
#define YES 1

/* deliver_alias - expand alias file entry */

int     deliver_alias(LOCAL_STATE state, USER_ATTR usr_attr,
                char *name, int *statusp)
{
    const char *myname = "deliver_alias";
    const char *alias_result;
    char   *saved_alias_result;
    char   *owner;
    char  **cpp;
    struct mypasswd *alias_pwd;
    VSTRING *canon_owner;
    DICT   *dict;
    const char *owner_rhs;  /* owner alias, RHS */
    int     alias_count;
    int     dsn_notify;
    char   *dsn_envid;
    int     dsn_ret;
    const char *dsn_orcpt;

    /*
     * Make verbose logging easier to understand.
     */

    state.level++;
    if (msg_verbose)
 MSG_LOG_STATE(myname, state);

    /*
     * DUPLICATE/LOOP ELIMINATION
     * 
     * We cannot do duplicate elimination here. Sendmail compatibility requires
     * that we allow multiple deliveries to the same alias, even recursively!
     * For example, we must deliver to mailbox any messages that are
     * addressed to the alias of a user that lists that same alias in her own
     * .forward file. Yuck! This is just an example of some really perverse
     * semantics that people will expect Postfix to implement just like
     * sendmail.
     * 
     * We can recognize one special case: when an alias includes its own name,
     * deliver to the user instead, just like sendmail. Otherwise, we just
     * bail out when nesting reaches some unreasonable depth, and blame it on
     * a possible alias loop.
     */

    if (state.msg_attr.exp_from != 0
 && strcasecmp_utf8(state.msg_attr.exp_from, name) == 0)
 return (NO);
    if (state.level > 100) {
 msg_warn("alias database loop for %s", name);
 dsb_simple(state.msg_attr.why, "5.4.6",
     "alias database loop for %s", name);
 *statusp = bounce_append(BOUNCE_FLAGS(state.request),
     BOUNCE_ATTR(state.msg_attr));
 return (YES);
    }
    state.msg_attr.exp_from = name;

    /*
     * There are a bunch of roles that we're trying to keep track of.
     * 
     * First, there's the issue of whose rights should be used when delivering
     * to "|command" or to /file/name. With alias databases, the rights are
     * those of who owns the alias, i.e. the database owner. With aliases
     * owned by root, a default user is used instead. When an alias with
     * default rights references an include file owned by an ordinary user,
     * we must use the rights of the include file owner, otherwise the
     * include file owner could take control of the default account.
     * 
     * Secondly, there's the question of who to notify of delivery problems.
     * With aliases that have an owner- alias, the latter is used to set the
     * sender and owner attributes. Otherwise, the owner attribute is reset
     * (the alias is globally visible and could be sent to by anyone).
     */

    for (cpp = alias_maps->argv->argv; *cpp; cpp++) {
 if ((dict = dict_handle(*cpp)) == 0)
     msg_panic("%s: dictionary not found: %s", myname, *cpp);
 if ((alias_result = dict_get(dict, name)) != 0) {
     if (msg_verbose)
  msg_info("%s: %s: %s = %s", myname, *cpp, name, alias_result);

     /*
      * Don't expand a verify-only request.
     */

     if (state.request->flags & DEL_REQ_FLAG_MTA_VRFY) {
  dsb_simple(state.msg_attr.why, "2.0.0",
      "aliased to %s", alias_result);
  *statusp = sent(BOUNCE_FLAGS(state.request),
    SENT_ATTR(state.msg_attr));
  return (YES);
     }

     /*
      * DELIVERY POLICY
      * 
      * Update the expansion type attribute, so we can decide if
      * deliveries to |command and /file/name are allowed at all.
     */

     state.msg_attr.exp_type = EXPAND_TYPE_ALIAS;

     /*
      * DELIVERY RIGHTS
      * 
      * What rights to use for |command and /file/name deliveries? The
      * command and file code will use default rights when the alias
      * database is owned by root, otherwise it will use the rights of
      * the alias database owner.
     */

     if (dict->owner.status == DICT_OWNER_TRUSTED) {
  alias_pwd = 0;
  RESET_USER_ATTR(usr_attr, state.level);
     } else {
  if (dict->owner.status == DICT_OWNER_UNKNOWN) {
      msg_warn("%s: no owner UID for alias database %s",
        myname, *cpp);
      dsb_simple(state.msg_attr.why, "4.3.0",
          "mail system configuration error");
      *statusp = defer_append(BOUNCE_FLAGS(state.request),
         BOUNCE_ATTR(state.msg_attr));
      return (YES);
  }
  if ((errno = mypwuid_err(dict->owner.uid, &alias_pwd)) != 0
      || alias_pwd == 0) {
      msg_warn(errno ?
        "cannot find alias database owner for %s: %m" :
      "cannot find alias database owner for %s", *cpp);
      dsb_simple(state.msg_attr.why, "4.3.0",
          "cannot find alias database owner");
      *statusp = defer_append(BOUNCE_FLAGS(state.request),
         BOUNCE_ATTR(state.msg_attr));
      return (YES);
  }
  SET_USER_ATTR(usr_attr, alias_pwd, state.level);
     }

     /*
      * WHERE TO REPORT DELIVERY PROBLEMS.
      * 
      * Use the owner- alias if one is specified, otherwise reset the
      * owner attribute and use the include file ownership if we can.
      * Save the dict_lookup() result before something clobbers it.
      * 
      * Don't match aliases that are based on regexps.
     */

#define OWNER_ASSIGN(own) \
     (own = (var_ownreq_special == 0 ? 0 : \
     concatenate("owner-", name, (char *) 0)))

     saved_alias_result = mystrdup(alias_result);
     if (OWNER_ASSIGN(owner) != 0
  && (owner_rhs = maps_find(alias_maps, owner, DICT_FLAG_NONE)) != 0) {
  canon_owner = canon_addr_internal(vstring_alloc(10),
         var_exp_own_alias ? owner_rhs : owner);
  /* Set envelope sender and owner attribute. */
  SET_OWNER_ATTR(state.msg_attr, STR(canon_owner), state.level);
     } else {
  canon_owner = 0;
  /* Note: this does not reset the envelope sender. */
  if (var_reset_owner_attr)
      RESET_OWNER_ATTR(state.msg_attr, state.level);
     }

     /*
      * EXTERNAL LOOP CONTROL
      * 
      * Set the delivered message attribute to the recipient, so that
      * this message will list the correct forwarding address.
     */

     if (var_frozen_delivered == 0)
  state.msg_attr.delivered = state.msg_attr.rcpt.address;

     /*
      * Deliver.
     */

     alias_count = 0;
     if (owner != 0 && alias_maps->error != 0) {
  dsb_simple(state.msg_attr.why, "4.3.0",
      "alias database unavailable");
  *statusp = defer_append(BOUNCE_FLAGS(state.request),
     BOUNCE_ATTR(state.msg_attr));
     } else {

  /*
   * XXX DSN
   * 
   * When delivering to a mailing list (i.e. the envelope sender
   * is replaced) the ENVID, NOTIFY, RET, and ORCPT parameters
   * which accompany the redistributed message MUST NOT be
   * derived from those of the original message.
   * 
   * When delivering to an alias (i.e. the envelope sender is not
   * replaced) any ENVID, RET, or ORCPT parameters are
   * propagated to all forwarding addresses associated with
   * that alias.  The NOTIFY parameter is propagated to the
   * forwarding addresses, except that any SUCCESS keyword is
   * removed.
 */

#define DSN_SAVE_UPDATE(saved, old, newdo { \
 saved = old; \
 old = new; \
    } while (0)

  DSN_SAVE_UPDATE(dsn_notify, state.msg_attr.rcpt.dsn_notify,
    dsn_notify == DSN_NOTIFY_SUCCESS ?
    DSN_NOTIFY_NEVER :
    dsn_notify & ~DSN_NOTIFY_SUCCESS);
  if (canon_owner != 0) {
      DSN_SAVE_UPDATE(dsn_envid, state.msg_attr.dsn_envid, "");
      DSN_SAVE_UPDATE(dsn_ret, state.msg_attr.dsn_ret, 0);
      DSN_SAVE_UPDATE(dsn_orcpt, state.msg_attr.rcpt.dsn_orcpt, "");
      state.msg_attr.rcpt.orig_addr = "";
  }
  *statusp =
      deliver_token_string(state, usr_attr, saved_alias_result,
      &alias_count);
#if 0
  if (var_ownreq_special
      && strncmp("owner-", state.msg_attr.sender, 6) != 0
      && alias_count > 10)
      msg_warn("mailing list \"%s\" needs an \"owner-%s\" alias",
        name, name);
#endif
  if (alias_count < 1) {
      msg_warn("no recipient in alias lookup result for %s", name);
      dsb_simple(state.msg_attr.why, "4.3.0",
          "alias database unavailable");
      *statusp = defer_append(BOUNCE_FLAGS(state.request),
         BOUNCE_ATTR(state.msg_attr));
  } else {

      /*
       * XXX DSN
       * 
       * When delivering to a mailing list (i.e. the envelope
       * sender address is replaced) and NOTIFY=SUCCESS was
       * specified, report a DSN of "delivered".
       * 
       * When delivering to an alias (i.e. the envelope sender
       * address is not replaced) and NOTIFY=SUCCESS was
       * specified, report a DSN of "expanded".
     */

      if (dsn_notify & DSN_NOTIFY_SUCCESS) {
   state.msg_attr.rcpt.dsn_notify = dsn_notify;
   if (canon_owner != 0) {
       state.msg_attr.dsn_envid = dsn_envid;
       state.msg_attr.dsn_ret = dsn_ret;
       state.msg_attr.rcpt.dsn_orcpt = dsn_orcpt;
   }
   dsb_update(state.msg_attr.why, "2.0.0", canon_owner ?
       "delivered" : "expanded",
       DSB_SKIP_RMTA, DSB_SKIP_REPLY,
       "alias expanded");
   (void) trace_append(BOUNCE_FLAG_NONE,
         SENT_ATTR(state.msg_attr));
      }
  }
     }
     myfree(saved_alias_result);
     if (owner)
  myfree(owner);
     if (canon_owner)
  vstring_free(canon_owner);
     if (alias_pwd)
  mypwfree(alias_pwd);
     return (YES);
 }

 /*
  * If the alias database was inaccessible for some reason, defer
  * further delivery for the current top-level recipient.
 */

 if (alias_result == 0 && dict->error != 0) {
     msg_warn("%s:%s: lookup of '%s' failed",
       dict->type, dict->name, name);
     dsb_simple(state.msg_attr.why, "4.3.0",
         "alias database unavailable");
     *statusp = defer_append(BOUNCE_FLAGS(state.request),
        BOUNCE_ATTR(state.msg_attr));
     return (YES);
 } else {
     if (msg_verbose)
  msg_info("%s: %s: %s not found", myname, *cpp, name);
 }
    }

    /*
     * Try delivery to a local user instead.
     */

    return (NO);
}

Messung V0.5 in Prozent
C=71 H=95 G=83

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

*© 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.