1/*	$NetBSD: postscreen_expand.c,v 1.2 2017/02/14 01:16:47 christos Exp $	*/
2
3/*++
4/* NAME
5/*	postscreen_expand 3
6/* SUMMARY
7/*	SMTP server macro expansion
8/* SYNOPSIS
9/*	#include <postscreen.h>
10/*
11/*	void	psc_expand_init()
12/*
13/*	VSTRING *psc_expand_filter;
14/*
15/*	const char *psc_expand_lookup(name, unused_mode, context)
16/*	const char *name;
17/*	int	unused_mode;
18/*	char	*context;
19/* DESCRIPTION
20/*	This module expands session-related macros.
21/*
22/*	psc_expand_init() performs one-time initialization
23/*	of the psc_expand_filter buffer.
24/*
25/*	The psc_expand_filter buffer contains the characters
26/*	that are allowed in macro expansion, as specified with the
27/*	psc_expand_filter configuration parameter.
28/*
29/*	psc_expand_lookup() returns the value of the named
30/*	macro or a null pointer.
31/*
32/*	Arguments:
33/* .IP name
34/*	Macro name.
35/* .IP context
36/*	Call-back context (a PSC_STATE pointer).
37/* DIAGNOSTICS
38/*	Panic: interface violations. Fatal errors: out of memory.
39/*	internal protocol errors. postscreen_expand() returns the
40/*	binary OR of MAC_PARSE_ERROR (syntax error) and MAC_PARSE_UNDEF
41/*	(undefined macro name).
42/* LICENSE
43/* .ad
44/* .fi
45/*	The Secure Mailer license must be distributed with this software.
46/* AUTHOR(S)
47/*	Wietse Venema
48/*	IBM T.J. Watson Research
49/*	P.O. Box 704
50/*	Yorktown Heights, NY 10598, USA
51/*--*/
52
53/* System library. */
54
55#include <sys_defs.h>
56#include <time.h>
57
58/* Utility library. */
59
60#include <msg.h>
61#include <vstring.h>
62#include <stringops.h>
63
64/* Global library. */
65
66#include <mail_params.h>
67#include <mail_proto.h>
68
69/* Application-specific. */
70
71#include <postscreen.h>
72
73 /*
74  * Pre-parsed expansion filter.
75  */
76VSTRING *psc_expand_filter;
77
78/* psc_expand_init - initialize once during process lifetime */
79
80void    psc_expand_init(void)
81{
82
83    /*
84     * Expand the expansion filter :-)
85     */
86    psc_expand_filter = vstring_alloc(10);
87    unescape(psc_expand_filter, var_psc_exp_filter);
88}
89
90/* psc_expand_lookup - generic SMTP attribute $name expansion */
91
92const char *psc_expand_lookup(const char *name, int unused_mode,
93			              void *context)
94{
95    PSC_STATE *state = (PSC_STATE *) context;
96    time_t  now;
97    struct tm *lt;
98
99    if (state->expand_buf == 0)
100	state->expand_buf = vstring_alloc(10);
101
102    if (msg_verbose > 1)
103	msg_info("psc_expand_lookup: ${%s}", name);
104
105#define STREQ(x,y)    (*(x) == *(y) && strcmp((x), (y)) == 0)
106#define STREQN(x,y,n) (*(x) == *(y) && strncmp((x), (y), (n)) == 0)
107#define CONST_LEN(x)  (sizeof(x) - 1)
108
109    /*
110     * Don't query main.cf parameters, as the result of expansion could
111     * reveal system-internal information in server replies.
112     *
113     * XXX: This said, multiple servers may be behind a single client-visible
114     * name or IP address, and each may generate its own logs. Therefore, it
115     * may be useful to expose the replying MTA id (myhostname) in the
116     * contact footer, to identify the right logs. So while we don't expose
117     * the raw configuration dictionary, we do expose "$myhostname" as
118     * expanded in var_myhostname.
119     *
120     * Return NULL only for non-existent names.
121     */
122    if (STREQ(name, MAIL_ATTR_SERVER_NAME)) {
123	return (var_myhostname);
124    } else if (STREQ(name, MAIL_ATTR_ACT_CLIENT_ADDR)) {
125	return (state->smtp_client_addr);
126    } else if (STREQ(name, MAIL_ATTR_ACT_CLIENT_PORT)) {
127	return (state->smtp_client_port);
128    } if (STREQ(name, MAIL_ATTR_LOCALTIME)) {
129	if (time(&now) == (time_t) -1)
130	    msg_fatal("time lookup failed: %m");
131	lt = localtime(&now);
132	VSTRING_RESET(state->expand_buf);
133	do {
134	    VSTRING_SPACE(state->expand_buf, 100);
135	} while (strftime(STR(state->expand_buf),
136			  vstring_avail(state->expand_buf),
137			  "%b %d %H:%M:%S", lt) == 0);
138	return (STR(state->expand_buf));
139    } else {
140	msg_warn("unknown macro name \"%s\" in expansion request", name);
141	return (0);
142    }
143}
144