diff options
Diffstat (limited to 'src/smtpd/smtpd_expand.c')
-rw-r--r-- | src/smtpd/smtpd_expand.c | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/src/smtpd/smtpd_expand.c b/src/smtpd/smtpd_expand.c new file mode 100644 index 0000000..8362bd7 --- /dev/null +++ b/src/smtpd/smtpd_expand.c @@ -0,0 +1,247 @@ +/*++ +/* NAME +/* smtpd_expand 3 +/* SUMMARY +/* SMTP server macro expansion +/* SYNOPSIS +/* #include <smtpd.h> +/* #include <smtpd_expand.h> +/* +/* void smtpd_expand_init() +/* +/* int smtpd_expand(state, result, template, flags) +/* SMTPD_STATE *state; +/* VSTRING *result; +/* const char *template; +/* int flags; +/* LOW_LEVEL INTERFACE +/* VSTRING *smtpd_expand_filter; +/* +/* const char *smtpd_expand_lookup(name, unused_mode, context) +/* const char *name; +/* int unused_mode; +/* void *context; +/* const char *template; +/* DESCRIPTION +/* This module expands session-related macros. +/* +/* smtpd_expand_init() performs one-time initialization. +/* +/* smtpd_expand() expands macros in the template, using session +/* attributes in the state argument, and writes the result to +/* the result argument. The flags and result value are as with +/* mac_expand(). +/* +/* smtpd_expand_filter and smtpd_expand_lookup() provide access +/* to lower-level interfaces that are used by smtpd_expand(). +/* smtpd_expand_lookup() returns null when a string is not +/* found (or when it is a null pointer). +/* DIAGNOSTICS +/* Panic: interface violations. Fatal errors: out of memory. +/* internal protocol errors. smtpd_expand() returns the binary +/* OR of MAC_PARSE_ERROR (syntax error) and MAC_PARSE_UNDEF +/* (undefined macro name). +/* 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 <time.h> + +/* Utility library. */ + +#include <msg.h> +#include <vstring.h> +#include <mac_expand.h> +#include <stringops.h> + +/* Global library. */ + +#include <mail_params.h> +#include <mail_proto.h> + +/* Application-specific. */ + +#include <smtpd.h> +#include <smtpd_expand.h> + + /* + * Pre-parsed expansion filter. + */ +VSTRING *smtpd_expand_filter; + + /* + * SLMs. + */ +#define STR vstring_str + +/* smtpd_expand_init - initialize once during process lifetime */ + +void smtpd_expand_init(void) +{ + + /* + * Expand the expansion filter :-) + */ + smtpd_expand_filter = vstring_alloc(10); + unescape(smtpd_expand_filter, var_smtpd_exp_filter); +} + +/* smtpd_expand_unknown - report unknown macro name */ + +static void smtpd_expand_unknown(const char *name) +{ + msg_warn("unknown macro name \"%s\" in expansion request", name); +} + +/* smtpd_expand_addr - return address or substring thereof */ + +static const char *smtpd_expand_addr(VSTRING *buf, const char *addr, + const char *name, int prefix_len) +{ + const char *p; + const char *suffix; + + /* + * Return NULL only for unknown names in expansion requests. + */ + if (addr == 0) + return (""); + + suffix = name + prefix_len; + + /* + * MAIL_ATTR_SENDER or MAIL_ATTR_RECIP. + */ + if (*suffix == 0) { + if (*addr) + return (addr); + else + return ("<>"); + } + + /* + * "sender_name" or "recipient_name". + */ +#define STREQ(x,y) (*(x) == *(y) && strcmp((x), (y)) == 0) + + else if (STREQ(suffix, MAIL_ATTR_S_NAME)) { + if (*addr) { + if ((p = strrchr(addr, '@')) != 0) { + vstring_strncpy(buf, addr, p - addr); + return (STR(buf)); + } else { + return (addr); + } + } else + return ("<>"); + } + + /* + * "sender_domain" or "recipient_domain". + */ + else if (STREQ(suffix, MAIL_ATTR_S_DOMAIN)) { + if (*addr) { + if ((p = strrchr(addr, '@')) != 0) { + return (p + 1); + } else { + return (""); + } + } else + return (""); + } + + /* + * Unknown. Return NULL to indicate an "unknown name" error. + */ + else { + smtpd_expand_unknown(name); + return (0); + } +} + +/* smtpd_expand_lookup - generic SMTP attribute $name expansion */ + +const char *smtpd_expand_lookup(const char *name, int unused_mode, + void *context) +{ + SMTPD_STATE *state = (SMTPD_STATE *) context; + time_t now; + struct tm *lt; + + if (state->expand_buf == 0) + state->expand_buf = vstring_alloc(10); + + if (msg_verbose > 1) + msg_info("smtpd_expand_lookup: ${%s}", name); + +#define STREQN(x,y,n) (*(x) == *(y) && strncmp((x), (y), (n)) == 0) +#define CONST_LEN(x) (sizeof(x) - 1) + + /* + * Don't query main.cf parameters, as the result of expansion could + * reveal system-internal information in server replies. + * + * XXX: This said, multiple servers may be behind a single client-visible + * name or IP address, and each may generate its own logs. Therefore, it + * may be useful to expose the replying MTA id (myhostname) in the + * contact footer, to identify the right logs. So while we don't expose + * the raw configuration dictionary, we do expose "$myhostname" as + * expanded in var_myhostname. + * + * Return NULL only for non-existent names. + */ + if (STREQ(name, MAIL_ATTR_SERVER_NAME)) { + return (var_myhostname); + } else if (STREQ(name, MAIL_ATTR_ACT_CLIENT)) { + return (state->namaddr); + } else if (STREQ(name, MAIL_ATTR_ACT_CLIENT_PORT)) { + return (state->port); + } else if (STREQ(name, MAIL_ATTR_ACT_CLIENT_ADDR)) { + return (state->addr); + } else if (STREQ(name, MAIL_ATTR_ACT_CLIENT_NAME)) { + return (state->name); + } else if (STREQ(name, MAIL_ATTR_ACT_REVERSE_CLIENT_NAME)) { + return (state->reverse_name); + } else if (STREQ(name, MAIL_ATTR_ACT_HELO_NAME)) { + return (state->helo_name ? state->helo_name : ""); + } else if (STREQN(name, MAIL_ATTR_SENDER, CONST_LEN(MAIL_ATTR_SENDER))) { + return (smtpd_expand_addr(state->expand_buf, state->sender, + name, CONST_LEN(MAIL_ATTR_SENDER))); + } else if (STREQN(name, MAIL_ATTR_RECIP, CONST_LEN(MAIL_ATTR_RECIP))) { + return (smtpd_expand_addr(state->expand_buf, state->recipient, + name, CONST_LEN(MAIL_ATTR_RECIP))); + } if (STREQ(name, MAIL_ATTR_LOCALTIME)) { + if (time(&now) == (time_t) -1) + msg_fatal("time lookup failed: %m"); + lt = localtime(&now); + VSTRING_RESET(state->expand_buf); + do { + VSTRING_SPACE(state->expand_buf, 100); + } while (strftime(STR(state->expand_buf), + vstring_avail(state->expand_buf), + "%b %d %H:%M:%S", lt) == 0); + return (STR(state->expand_buf)); + } else { + smtpd_expand_unknown(name); + return (0); + } +} + +/* smtpd_expand - expand session attributes in string */ + +int smtpd_expand(SMTPD_STATE *state, VSTRING *result, + const char *template, int flags) +{ + return (mac_expand(result, template, flags, STR(smtpd_expand_filter), + smtpd_expand_lookup, (void *) state)); +} |