Current File : //root/postfix-3.2.0/src/smtpd/smtpd_expand.c |
/*++
/* 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));
}