Home | History | Annotate | Line # | Download | only in smtpd
      1 /*	$NetBSD: smtpd_expand.c,v 1.2 2017/02/14 01:16:48 christos Exp $	*/
      2 
      3 /*++
      4 /* NAME
      5 /*	smtpd_expand 3
      6 /* SUMMARY
      7 /*	SMTP server macro expansion
      8 /* SYNOPSIS
      9 /*	#include <smtpd.h>
     10 /*	#include <smtpd_expand.h>
     11 /*
     12 /*	void	smtpd_expand_init()
     13 /*
     14 /*	int	smtpd_expand(state, result, template, flags)
     15 /*	SMTPD_STATE *state;
     16 /*	VSTRING	*result;
     17 /*	const char *template;
     18 /*	int	flags;
     19 /* LOW_LEVEL INTERFACE
     20 /*	VSTRING *smtpd_expand_filter;
     21 /*
     22 /*	const char *smtpd_expand_lookup(name, unused_mode, context)
     23 /*	const char *name;
     24 /*	int	unused_mode;
     25 /*	void	*context;
     26 /*	const char *template;
     27 /* DESCRIPTION
     28 /*	This module expands session-related macros.
     29 /*
     30 /*	smtpd_expand_init() performs one-time initialization.
     31 /*
     32 /*	smtpd_expand() expands macros in the template, using session
     33 /*	attributes in the state argument, and writes the result to
     34 /*	the result argument. The flags and result value are as with
     35 /*	mac_expand().
     36 /*
     37 /*	smtpd_expand_filter and smtpd_expand_lookup() provide access
     38 /*	to lower-level interfaces that are used by smtpd_expand().
     39 /*	smtpd_expand_lookup() returns null when a string is not
     40 /*	found (or when it is a null pointer).
     41 /* DIAGNOSTICS
     42 /*	Panic: interface violations. Fatal errors: out of memory.
     43 /*	internal protocol errors. smtpd_expand() returns the binary
     44 /*	OR of MAC_PARSE_ERROR (syntax error) and MAC_PARSE_UNDEF
     45 /*	(undefined macro name).
     46 /* LICENSE
     47 /* .ad
     48 /* .fi
     49 /*	The Secure Mailer license must be distributed with this software.
     50 /* AUTHOR(S)
     51 /*	Wietse Venema
     52 /*	IBM T.J. Watson Research
     53 /*	P.O. Box 704
     54 /*	Yorktown Heights, NY 10598, USA
     55 /*--*/
     56 
     57 /* System library. */
     58 
     59 #include <sys_defs.h>
     60 #include <time.h>
     61 
     62 /* Utility library. */
     63 
     64 #include <msg.h>
     65 #include <vstring.h>
     66 #include <mac_expand.h>
     67 #include <stringops.h>
     68 
     69 /* Global library. */
     70 
     71 #include <mail_params.h>
     72 #include <mail_proto.h>
     73 
     74 /* Application-specific. */
     75 
     76 #include <smtpd.h>
     77 #include <smtpd_expand.h>
     78 
     79  /*
     80   * Pre-parsed expansion filter.
     81   */
     82 VSTRING *smtpd_expand_filter;
     83 
     84  /*
     85   * SLMs.
     86   */
     87 #define STR	vstring_str
     88 
     89 /* smtpd_expand_init - initialize once during process lifetime */
     90 
     91 void    smtpd_expand_init(void)
     92 {
     93 
     94     /*
     95      * Expand the expansion filter :-)
     96      */
     97     smtpd_expand_filter = vstring_alloc(10);
     98     unescape(smtpd_expand_filter, var_smtpd_exp_filter);
     99 }
    100 
    101 /* smtpd_expand_unknown - report unknown macro name */
    102 
    103 static void smtpd_expand_unknown(const char *name)
    104 {
    105     msg_warn("unknown macro name \"%s\" in expansion request", name);
    106 }
    107 
    108 /* smtpd_expand_addr - return address or substring thereof */
    109 
    110 static const char *smtpd_expand_addr(VSTRING *buf, const char *addr,
    111 				           const char *name, int prefix_len)
    112 {
    113     const char *p;
    114     const char *suffix;
    115 
    116     /*
    117      * Return NULL only for unknown names in expansion requests.
    118      */
    119     if (addr == 0)
    120 	return ("");
    121 
    122     suffix = name + prefix_len;
    123 
    124     /*
    125      * MAIL_ATTR_SENDER or MAIL_ATTR_RECIP.
    126      */
    127     if (*suffix == 0) {
    128 	if (*addr)
    129 	    return (addr);
    130 	else
    131 	    return ("<>");
    132     }
    133 
    134     /*
    135      * "sender_name" or "recipient_name".
    136      */
    137 #define STREQ(x,y) (*(x) == *(y) && strcmp((x), (y)) == 0)
    138 
    139     else if (STREQ(suffix, MAIL_ATTR_S_NAME)) {
    140 	if (*addr) {
    141 	    if ((p = strrchr(addr, '@')) != 0) {
    142 		vstring_strncpy(buf, addr, p - addr);
    143 		return (STR(buf));
    144 	    } else {
    145 		return (addr);
    146 	    }
    147 	} else
    148 	    return ("<>");
    149     }
    150 
    151     /*
    152      * "sender_domain" or "recipient_domain".
    153      */
    154     else if (STREQ(suffix, MAIL_ATTR_S_DOMAIN)) {
    155 	if (*addr) {
    156 	    if ((p = strrchr(addr, '@')) != 0) {
    157 		return (p + 1);
    158 	    } else {
    159 		return ("");
    160 	    }
    161 	} else
    162 	    return ("");
    163     }
    164 
    165     /*
    166      * Unknown. Return NULL to indicate an "unknown name" error.
    167      */
    168     else {
    169 	smtpd_expand_unknown(name);
    170 	return (0);
    171     }
    172 }
    173 
    174 /* smtpd_expand_lookup - generic SMTP attribute $name expansion */
    175 
    176 const char *smtpd_expand_lookup(const char *name, int unused_mode,
    177 				        void *context)
    178 {
    179     SMTPD_STATE *state = (SMTPD_STATE *) context;
    180     time_t  now;
    181     struct tm *lt;
    182 
    183     if (state->expand_buf == 0)
    184 	state->expand_buf = vstring_alloc(10);
    185 
    186     if (msg_verbose > 1)
    187 	msg_info("smtpd_expand_lookup: ${%s}", name);
    188 
    189 #define STREQN(x,y,n) (*(x) == *(y) && strncmp((x), (y), (n)) == 0)
    190 #define CONST_LEN(x)  (sizeof(x) - 1)
    191 
    192     /*
    193      * Don't query main.cf parameters, as the result of expansion could
    194      * reveal system-internal information in server replies.
    195      *
    196      * XXX: This said, multiple servers may be behind a single client-visible
    197      * name or IP address, and each may generate its own logs. Therefore, it
    198      * may be useful to expose the replying MTA id (myhostname) in the
    199      * contact footer, to identify the right logs. So while we don't expose
    200      * the raw configuration dictionary, we do expose "$myhostname" as
    201      * expanded in var_myhostname.
    202      *
    203      * Return NULL only for non-existent names.
    204      */
    205     if (STREQ(name, MAIL_ATTR_SERVER_NAME)) {
    206 	return (var_myhostname);
    207     } else if (STREQ(name, MAIL_ATTR_ACT_CLIENT)) {
    208 	return (state->namaddr);
    209     } else if (STREQ(name, MAIL_ATTR_ACT_CLIENT_PORT)) {
    210 	return (state->port);
    211     } else if (STREQ(name, MAIL_ATTR_ACT_CLIENT_ADDR)) {
    212 	return (state->addr);
    213     } else if (STREQ(name, MAIL_ATTR_ACT_CLIENT_NAME)) {
    214 	return (state->name);
    215     } else if (STREQ(name, MAIL_ATTR_ACT_REVERSE_CLIENT_NAME)) {
    216 	return (state->reverse_name);
    217     } else if (STREQ(name, MAIL_ATTR_ACT_HELO_NAME)) {
    218 	return (state->helo_name ? state->helo_name : "");
    219     } else if (STREQN(name, MAIL_ATTR_SENDER, CONST_LEN(MAIL_ATTR_SENDER))) {
    220 	return (smtpd_expand_addr(state->expand_buf, state->sender,
    221 				  name, CONST_LEN(MAIL_ATTR_SENDER)));
    222     } else if (STREQN(name, MAIL_ATTR_RECIP, CONST_LEN(MAIL_ATTR_RECIP))) {
    223 	return (smtpd_expand_addr(state->expand_buf, state->recipient,
    224 				  name, CONST_LEN(MAIL_ATTR_RECIP)));
    225     } if (STREQ(name, MAIL_ATTR_LOCALTIME)) {
    226 	if (time(&now) == (time_t) -1)
    227 	    msg_fatal("time lookup failed: %m");
    228 	lt = localtime(&now);
    229 	VSTRING_RESET(state->expand_buf);
    230 	do {
    231 	    VSTRING_SPACE(state->expand_buf, 100);
    232 	} while (strftime(STR(state->expand_buf),
    233 			  vstring_avail(state->expand_buf),
    234 			  "%b %d %H:%M:%S", lt) == 0);
    235 	return (STR(state->expand_buf));
    236     } else {
    237 	smtpd_expand_unknown(name);
    238 	return (0);
    239     }
    240 }
    241 
    242 /* smtpd_expand - expand session attributes in string */
    243 
    244 int     smtpd_expand(SMTPD_STATE *state, VSTRING *result,
    245 		             const char *template, int flags)
    246 {
    247     return (mac_expand(result, template, flags, STR(smtpd_expand_filter),
    248 		       smtpd_expand_lookup, (void *) state));
    249 }
    250