trivial-rewrite.c   [plain text]


/*++
/* NAME
/*	trivial-rewrite 8
/* SUMMARY
/*	Postfix address rewriting and resolving daemon
/* SYNOPSIS
/*	\fBtrivial-rewrite\fR [generic Postfix daemon options]
/* DESCRIPTION
/*	The \fBtrivial-rewrite\fR daemon processes two types of client
/*	service requests:
/* .IP \fBrewrite\fR
/*	Rewrite an address to standard form. The \fBtrivial-rewrite\fR
/*	daemon by default appends local domain information to unqualified
/*	addresses, swaps bang paths to domain form, and strips source
/*	routing information. This process is under control of several
/*	configuration parameters (see below).
/* .IP \fBresolve\fR
/*	Resolve an address to a (\fItransport\fR, \fInexthop\fR,
/*	\fIrecipient\fR) triple. The meaning of the results is as follows:
/* .RS
/* .IP \fItransport\fR
/*	The delivery agent to use. This is the first field of an entry
/*	in the \fBmaster.cf\fR file.
/* .IP \fInexthop\fR
/*	The host to send to and optional delivery method information.
/* .IP \fIrecipient\fR
/*	The envelope recipient address that is passed on to \fInexthop\fR.
/* .RE
/* DEFAULT DELIVERY METHODS
/* .ad
/* .fi
/*	By default, Postfix uses one of the following delivery methods.
/*	This may be overruled with the optional transport(5) table.
/*	The default delivery method is selected by matching the
/*	recipient address domain against one of the following:
/* .IP \fB$mydestination\fR
/* .IP \fB$inet_interfaces\fR
/*	The transport and optional nexthop
/*	are specified with \fB$local_transport\fR.
/*	The default nexthop is the recipient domain.
/* .IP \fB$virtual_alias_domains\fR
/*	The recipient address is undeliverable (user unknown).
/*	By definition, all known addresses in a virtual alias domain
/*	are aliased to other addresses.
/* .IP \fB$virtual_mailbox_domains\fR
/*	The transport and optional nexthop are specified with
/*	\fB$virtual_transport\fR.
/*	The default nexthop is the recipient domain.
/* .IP \fB$relay_domains\fR
/*	The transport and optional nexthop are specified with
/*	\fB$relay_transport\fR. This overrides the optional nexthop
/*	information that is specified with \fB$relayhost\fR.
/*	The default nexthop is the recipient domain.
/* .IP "none of the above"
/*	The transport and optional nexthop are specified with
/*	\fB$default_transport\fR.
/*	This overrides the optional nexthop information that is specified
/*	with \fB$relayhost\fR.
/*	The default nexthop is the recipient domain.
/* SERVER PROCESS MANAGEMENT
/* .ad
/* .fi
/*	The trivial-rewrite servers run under control by the Postfix master
/*	server.  Each server can handle multiple simultaneous connections.
/*	When all servers are busy while a client connects, the master
/*	creates a new server process, provided that the trivial-rewrite
/*	server process limit is not exceeded.
/*	Each trivial-rewrite server terminates after
/*	serving at least \fB$max_use\fR clients of after \fB$max_idle\fR
/*	seconds of idle time.
/* STANDARDS
/* .ad
/* .fi
/*	None. The command does not interact with the outside world.
/* SECURITY
/* .ad
/* .fi
/*	The \fBtrivial-rewrite\fR daemon is not security sensitive.
/*	By default, this daemon does not talk to remote or local users.
/*	It can run at a fixed low privilege in a chrooted environment.
/* DIAGNOSTICS
/*	Problems and transactions are logged to \fBsyslogd\fR(8).
/* BUGS
/* CONFIGURATION PARAMETERS
/* .ad
/* .fi
/*	The following \fBmain.cf\fR parameters are especially relevant to
/*	this program. See the Postfix \fBmain.cf\fR file for syntax details
/*	and for default values. Use the \fBpostfix reload\fR command after
/*	a configuration change.
/* .SH Miscellaneous
/* .ad
/* .fi
/* .IP \fBempty_address_recipient\fR
/*	The recipient that is substituted for the null address.
/* .IP \fBinet_interfaces\fR
/*	The network interfaces that this mail system receives mail on.
/*	This information is used to determine if
/*	\fIuser\fR@[\fInet.work.addr.ess\fR] is local or remote.
/*	Mail for local users is given to the \fB$local_transport\fR.
/* .IP \fBmydestination\fR
/*	List of domains that are given to the \fB$local_transport\fR.
/* .IP \fBvirtual_alias_domains\fR
/*	List of simulated virtual domains (domains with all recipients
/*	aliased to some other local or remote domain).
/* .IP \fBvirtual_mailbox_domains\fR
/*	List of domains that are given to the \fB$virtual_transport\fR.
/* .IP \fBrelay_domains\fR
/*	List of domains that are given to the \fB$relay_transport\fR.
/* .IP \fBresolve_unquoted_address\fR
/*	When resolving an address, do not quote the address localpart as
/*	per RFC 822, so that additional \fB@\fR, \fB%\fR or \fB!\fR
/*	characters remain visible. This is technically incorrect, but
/*	allows us to stop relay attacks when forwarding mail to a Sendmail
/*	primary MX host.
/* .IP \fBrelocated_maps\fR
/*      Tables with contact information for users, hosts or domains
/*      that no longer exist. See \fBrelocated\fR(5).
/* .SH Rewriting
/* .ad
/* .fi
/* .IP \fBmyorigin\fR
/*	The domain that locally-posted mail appears to come from.
/* .IP \fBallow_percent_hack\fR
/*	Rewrite \fIuser\fR%\fIdomain\fR to \fIuser\fR@\fIdomain\fR.
/* .IP \fBappend_at_myorigin\fR
/*	Rewrite \fIuser\fR to \fIuser\fR@\fB$myorigin\fR.
/* .IP \fBappend_dot_mydomain\fR
/*	Rewrite \fIuser\fR@\fIhost\fR to \fIuser\fR@\fIhost\fR.\fB$mydomain\fR.
/* .IP \fBswap_bangpath\fR
/*	Rewrite \fIsite\fR!\fIuser\fR to \fIuser\fR@\fIsite\fR.
/* .SH Routing
/* .ad
/* .fi
/* .IP \fBlocal_transport\fR
/*	Where to deliver mail for destinations that match \fB$mydestination\fR
/*	or \fB$inet_interfaces\fR.
/*	The default transport is \fBlocal:$myhostname\fR.
/* .sp
/*	Syntax is \fItransport\fR:\fInexthop\fR; see \fBtransport\fR(5)
/*	for details. The :\fInexthop\fR part is optional.
/* .IP \fBvirtual_transport\fR
/*	Where to deliver mail for non-local domains that match
/*	\fB$virtual_mailbox_domains\fR.
/*	The default transport is \fBvirtual\fR.
/* .sp
/*	Syntax is \fItransport\fR:\fInexthop\fR; see \fBtransport\fR(5)
/*	for details. The :\fInexthop\fR part is optional.
/* .IP \fBrelay_transport\fR
/*	Where to deliver mail for non-local domains that match
/*	\fB$relay_domains\fR.
/*	The default transport is \fBrelay\fR (which normally is a clone
/*	of the \fBsmtp\fR transport).
/* .sp
/*	Syntax is \fItransport\fR:\fInexthop\fR; see \fBtransport\fR(5)
/*	for details. The :\fInexthop\fR part is optional.
/* .IP \fBdefault_transport\fR
/*	Where to deliver all other non-local mail.
/*	The default transport is \fBsmtp\fR.
/* .sp
/*	Syntax is \fItransport\fR:\fInexthop\fR; see \fBtransport\fR(5)
/*	for details. The :\fInexthop\fR part is optional.
/* .IP \fBparent_domain_matches_subdomains\fR
/*	List of Postfix features that use \fIdomain.tld\fR patterns
/*	to match \fIsub.domain.tld\fR (as opposed to
/*	requiring \fI.domain.tld\fR patterns).
/* .IP \fBrelayhost\fR
/*	The default host to send non-local mail to when no host is
/*	specified with \fB$relay_transport\fR or \fB$default_transport\fR,
/*	and when the recipient address does not match the optional the
/*	\fBtransport\fR(5) table.
/* .IP \fBtransport_maps\fR
/*	List of tables with \fIrecipient\fR or \fIdomain\fR to
/*	(\fItransport, nexthop\fR) mappings.
/* SEE ALSO
/*	master(8) process manager
/*	syslogd(8) system logging
/*	transport(5) transport table format
/*	relocated(5) format of the "user has moved" table
/* 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 <unistd.h>
#include <stdlib.h>
#include <string.h>

/* Utility library. */

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

/* Global library. */

#include <mail_params.h>
#include <mail_proto.h>
#include <resolve_local.h>
#include <mail_conf.h>
#include <resolve_clnt.h>
#include <rewrite_clnt.h>
#include <tok822.h>
#include <mail_addr.h>

/* Multi server skeleton. */

#include <mail_server.h>

/* Application-specific. */

#include <trivial-rewrite.h>
#include <transport.h>

static VSTRING *command;

 /*
  * Tunable parameters.
  */
char   *var_transport_maps;
bool    var_swap_bangpath;
bool    var_append_dot_mydomain;
bool    var_append_at_myorigin;
bool    var_percent_hack;
char   *var_local_transport;
char   *var_virt_transport;
char   *var_relay_transport;
int     var_resolve_dequoted;
char   *var_virt_alias_maps;		/* XXX virtual_alias_domains */
char   *var_virt_mailbox_maps;		/* XXX virtual_mailbox_domains */
char   *var_virt_alias_doms;
char   *var_virt_mailbox_doms;
char   *var_relocated_maps;
char   *var_def_transport;
char   *var_empty_addr;
int     var_show_unk_rcpt_table;

/* rewrite_service - read request and send reply */

static void rewrite_service(VSTREAM *stream, char *unused_service, char **argv)
{
    int     status = -1;

    /*
     * Sanity check. This service takes no command-line arguments.
     */
    if (argv[0])
	msg_fatal("unexpected command-line argument: %s", argv[0]);

    /*
     * This routine runs whenever a client connects to the UNIX-domain socket
     * dedicated to address rewriting. All connection-management stuff is
     * handled by the common code in multi_server.c.
     */
    if (attr_scan(stream, ATTR_FLAG_STRICT | ATTR_FLAG_MORE,
		  ATTR_TYPE_STR, MAIL_ATTR_REQ, command,
		  ATTR_TYPE_END) == 1) {
	if (strcmp(vstring_str(command), REWRITE_ADDR) == 0) {
	    status = rewrite_proto(stream);
	} else if (strcmp(vstring_str(command), RESOLVE_ADDR) == 0) {
	    status = resolve_proto(stream);
	} else {
	    msg_warn("bad command %.30s", printable(vstring_str(command), '?'));
	}
    }
    if (status < 0)
	multi_server_disconnect(stream);
}

/* pre_accept - see if tables have changed */

static void pre_accept(char *unused_name, char **unused_argv)
{
    if (dict_changed()) {
	msg_info("table has changed -- exiting");
	exit(0);
    }
}

/* pre_jail_init - initialize before entering chroot jail */

static void pre_jail_init(char *unused_name, char **unused_argv)
{
    command = vstring_alloc(100);
    rewrite_init();
    resolve_init();
    transport_init();
}

static void post_jail_init(char *unused_name, char **unused_argv)
{
    transport_wildcard_init();
}

/* main - pass control to the multi-threaded skeleton code */

int     main(int argc, char **argv)
{
    static CONFIG_STR_TABLE str_table[] = {
	VAR_TRANSPORT_MAPS, DEF_TRANSPORT_MAPS, &var_transport_maps, 0, 0,
	VAR_LOCAL_TRANSPORT, DEF_LOCAL_TRANSPORT, &var_local_transport, 1, 0,
	VAR_VIRT_TRANSPORT, DEF_VIRT_TRANSPORT, &var_virt_transport, 1, 0,
	VAR_RELAY_TRANSPORT, DEF_RELAY_TRANSPORT, &var_relay_transport, 1, 0,
	VAR_VIRT_ALIAS_MAPS, DEF_VIRT_ALIAS_MAPS, &var_virt_alias_maps, 0, 0,
	VAR_VIRT_ALIAS_DOMS, DEF_VIRT_ALIAS_DOMS, &var_virt_alias_doms, 0, 0,
	VAR_VIRT_MAILBOX_MAPS, DEF_VIRT_MAILBOX_MAPS, &var_virt_mailbox_maps, 0, 0,
	VAR_VIRT_MAILBOX_DOMS, DEF_VIRT_MAILBOX_DOMS, &var_virt_mailbox_doms, 0, 0,
	VAR_DEF_TRANSPORT, DEF_DEF_TRANSPORT, &var_def_transport, 1, 0,
	VAR_VIRT_TRANSPORT, DEF_VIRT_TRANSPORT, &var_virt_transport, 1, 0,
	VAR_RELAY_TRANSPORT, DEF_RELAY_TRANSPORT, &var_relay_transport, 1, 0,
	VAR_RELOCATED_MAPS, DEF_RELOCATED_MAPS, &var_relocated_maps, 0, 0,
	VAR_EMPTY_ADDR, DEF_EMPTY_ADDR, &var_empty_addr, 1, 0,
	0,
    };
    static CONFIG_BOOL_TABLE bool_table[] = {
	VAR_SWAP_BANGPATH, DEF_SWAP_BANGPATH, &var_swap_bangpath,
	VAR_APP_DOT_MYDOMAIN, DEF_APP_DOT_MYDOMAIN, &var_append_dot_mydomain,
	VAR_APP_AT_MYORIGIN, DEF_APP_AT_MYORIGIN, &var_append_at_myorigin,
	VAR_PERCENT_HACK, DEF_PERCENT_HACK, &var_percent_hack,
	VAR_RESOLVE_DEQUOTED, DEF_RESOLVE_DEQUOTED, &var_resolve_dequoted,
	VAR_SHOW_UNK_RCPT_TABLE, DEF_SHOW_UNK_RCPT_TABLE, &var_show_unk_rcpt_table,
	0,
    };

    multi_server_main(argc, argv, rewrite_service,
		      MAIL_SERVER_STR_TABLE, str_table,
		      MAIL_SERVER_BOOL_TABLE, bool_table,
		      MAIL_SERVER_PRE_INIT, pre_jail_init,
		      MAIL_SERVER_POST_INIT, post_jail_init,
		      MAIL_SERVER_PRE_ACCEPT, pre_accept,
		      0);
}