1/*++
2/* NAME
3/*	smtpd_milter 3
4/* SUMMARY
5/*	SMTP server milter glue
6/* SYNOPSIS
7/*	#include <smtpd.h>
8/*	#include <smtpd_milter.h>
9/*
10/*	const char *smtpd_milter_eval(name, context)
11/*	const char *name;
12/*	void	*context;
13/* DESCRIPTION
14/*	smtpd_milter_eval() is a milter(3) call-back routine to
15/*	expand Sendmail macros before they are sent to filters.
16/* DIAGNOSTICS
17/*	Panic: interface violations. Fatal errors: out of memory.
18/*	internal protocol errors.
19/* LICENSE
20/* .ad
21/* .fi
22/*	The Secure Mailer license must be distributed with this software.
23/* AUTHOR(S)
24/*	Wietse Venema
25/*	IBM T.J. Watson Research
26/*	P.O. Box 704
27/*	Yorktown Heights, NY 10598, USA
28/*--*/
29
30/* System library. */
31
32#include <sys_defs.h>
33
34/* Utility library. */
35
36#include <split_at.h>
37
38/* Global library. */
39
40#include <mail_params.h>
41#include <quote_821_local.h>
42
43/* Milter library. */
44
45#include <milter.h>
46
47/* Application-specific. */
48
49#include <smtpd.h>
50#include <smtpd_sasl_glue.h>
51#include <smtpd_resolve.h>
52#include <smtpd_milter.h>
53
54 /*
55  * SLMs.
56  */
57#define STR(x)	vstring_str(x)
58
59/* smtpd_milter_eval - evaluate milter macro */
60
61const char *smtpd_milter_eval(const char *name, void *ptr)
62{
63    SMTPD_STATE *state = (SMTPD_STATE *) ptr;
64    const RESOLVE_REPLY *reply;
65    char   *cp;
66
67    /*
68     * On-the-fly initialization.
69     */
70    if (state->expand_buf == 0)
71	state->expand_buf = vstring_alloc(10);
72
73    /*
74     * Canonicalize the name.
75     */
76    if (*name != '{') {				/* } */
77	vstring_sprintf(state->expand_buf, "{%s}", name);
78	name = STR(state->expand_buf);
79    }
80
81    /*
82     * System macros.
83     */
84    if (strcmp(name, S8_MAC_DAEMON_NAME) == 0)
85	return (var_milt_daemon_name);
86    if (strcmp(name, S8_MAC_V) == 0)
87	return (var_milt_v);
88
89    /*
90     * Connect macros.
91     */
92    if (strcmp(name, S8_MAC__) == 0) {
93	vstring_sprintf(state->expand_buf, "%s [%s]",
94			state->reverse_name, state->addr);
95	if (strcasecmp(state->name, state->reverse_name) != 0)
96	    vstring_strcat(state->expand_buf, " (may be forged)");
97	return (STR(state->expand_buf));
98    }
99    if (strcmp(name, S8_MAC_J) == 0)
100	return (var_myhostname);
101    if (strcmp(name, S8_MAC_CLIENT_ADDR) == 0)
102	return (state->rfc_addr);
103    if (strcmp(name, S8_MAC_CLIENT_PORT) == 0)
104	return (strcmp(state->port, CLIENT_PORT_UNKNOWN) ? state->port : "0");
105    if (strcmp(name, S8_MAC_CLIENT_CONN) == 0) {
106	vstring_sprintf(state->expand_buf, "%d", state->conn_count);
107	return (STR(state->expand_buf));
108    }
109    if (strcmp(name, S8_MAC_CLIENT_NAME) == 0)
110	return (state->name);
111    if (strcmp(name, S8_MAC_CLIENT_PTR) == 0)
112	return (state->reverse_name);
113    if (strcmp(name, S8_MAC_CLIENT_RES) == 0)
114	return (state->name_status == SMTPD_PEER_CODE_OK ? "OK" :
115		state->name_status == SMTPD_PEER_CODE_FORGED ? "FORGED" :
116	      state->name_status == SMTPD_PEER_CODE_TEMP ? "TEMP" : "FAIL");
117
118    /*
119     * HELO macros.
120     */
121#ifdef USE_TLS
122#define IF_ENCRYPTED(x) (state->tls_context ? (x) : 0)
123#define IF_TRUSTED(x) (TLS_CERT_IS_TRUSTED(state->tls_context) ? (x) : 0)
124
125    if (strcmp(name, S8_MAC_TLS_VERSION) == 0)
126	return (IF_ENCRYPTED(state->tls_context->protocol));
127    if (strcmp(name, S8_MAC_CIPHER) == 0)
128	return (IF_ENCRYPTED(state->tls_context->cipher_name));
129    if (strcmp(name, S8_MAC_CIPHER_BITS) == 0) {
130	if (state->tls_context == 0)
131	    return (0);
132	vstring_sprintf(state->expand_buf, "%d",
133			IF_ENCRYPTED(state->tls_context->cipher_usebits));
134	return (STR(state->expand_buf));
135    }
136    if (strcmp(name, S8_MAC_CERT_SUBJECT) == 0)
137	return (IF_TRUSTED(state->tls_context->peer_CN));
138    if (strcmp(name, S8_MAC_CERT_ISSUER) == 0)
139	return (IF_TRUSTED(state->tls_context->issuer_CN));
140#endif
141
142    /*
143     * MAIL FROM macros.
144     */
145#define IF_SASL_ENABLED(s) (smtpd_sasl_is_active(state) && (s) ? (s) : 0)
146
147    if (strcmp(name, S8_MAC_I) == 0)
148	return (state->queue_id);
149#ifdef USE_SASL_AUTH
150    if (strcmp(name, S8_MAC_AUTH_TYPE) == 0)
151	return (IF_SASL_ENABLED(state->sasl_method));
152    if (strcmp(name, S8_MAC_AUTH_AUTHEN) == 0)
153	return (IF_SASL_ENABLED(state->sasl_username));
154    if (strcmp(name, S8_MAC_AUTH_AUTHOR) == 0)
155	return (IF_SASL_ENABLED(state->sasl_sender));
156#endif
157    if (strcmp(name, S8_MAC_MAIL_ADDR) == 0) {
158	if (state->sender == 0)
159	    return (0);
160	if (state->sender[0] == 0)
161	    return ("");
162	reply = smtpd_resolve_addr(state->sender);
163	/* Sendmail 8.13 does not externalize the null string. */
164	if (STR(reply->recipient)[0])
165	    quote_821_local(state->expand_buf, STR(reply->recipient));
166	else
167	    vstring_strcpy(state->expand_buf, STR(reply->recipient));
168	return (STR(state->expand_buf));
169    }
170    if (strcmp(name, S8_MAC_MAIL_HOST) == 0) {
171	if (state->sender == 0)
172	    return (0);
173	reply = smtpd_resolve_addr(state->sender);
174	return (STR(reply->nexthop));
175    }
176    if (strcmp(name, S8_MAC_MAIL_MAILER) == 0) {
177	if (state->sender == 0)
178	    return (0);
179	reply = smtpd_resolve_addr(state->sender);
180	return (STR(reply->transport));
181    }
182
183    /*
184     * RCPT TO macros.
185     */
186    if (strcmp(name, S8_MAC_RCPT_ADDR) == 0) {
187	if (state->recipient == 0)
188	    return (0);
189	if (state->recipient[0] == 0)
190	    return ("");
191	if (state->milter_reject_text) {
192	    /* 554 5.7.1 <user@example.com>: Relay access denied */
193	    vstring_strcpy(state->expand_buf, state->milter_reject_text + 4);
194	    cp = split_at(STR(state->expand_buf), ' ');
195	    return (cp ? split_at(cp, ' ') : cp);
196	}
197	reply = smtpd_resolve_addr(state->recipient);
198	/* Sendmail 8.13 does not externalize the null string. */
199	if (STR(reply->recipient)[0])
200	    quote_821_local(state->expand_buf, STR(reply->recipient));
201	else
202	    vstring_strcpy(state->expand_buf, STR(reply->recipient));
203	return (STR(state->expand_buf));
204    }
205    if (strcmp(name, S8_MAC_RCPT_HOST) == 0) {
206	if (state->recipient == 0)
207	    return (0);
208	if (state->milter_reject_text) {
209	    /* 554 5.7.1 <user@example.com>: Relay access denied */
210	    vstring_strcpy(state->expand_buf, state->milter_reject_text + 4);
211	    (void) split_at(STR(state->expand_buf), ' ');
212	    return (STR(state->expand_buf));
213	}
214	reply = smtpd_resolve_addr(state->recipient);
215	return (STR(reply->nexthop));
216    }
217    if (strcmp(name, S8_MAC_RCPT_MAILER) == 0) {
218	if (state->recipient == 0)
219	    return (0);
220	if (state->milter_reject_text)
221	    return (S8_RCPT_MAILER_ERROR);
222	reply = smtpd_resolve_addr(state->recipient);
223	return (STR(reply->transport));
224    }
225    return (0);
226}
227