1 /* $NetBSD: smtpd_milter.c,v 1.3 2020/03/18 19:05:20 christos Exp $ */
2
3 /*++
4 /* NAME
5 /* smtpd_milter 3
6 /* SUMMARY
7 /* SMTP server milter glue
8 /* SYNOPSIS
9 /* #include <smtpd.h>
10 /* #include <smtpd_milter.h>
11 /*
12 /* const char *smtpd_milter_eval(name, context)
13 /* const char *name;
14 /* void *context;
15 /* DESCRIPTION
16 /* smtpd_milter_eval() is a milter(3) call-back routine to
17 /* expand Sendmail macros before they are sent to filters.
18 /* DIAGNOSTICS
19 /* Panic: interface violations. Fatal errors: out of memory.
20 /* internal protocol errors.
21 /* LICENSE
22 /* .ad
23 /* .fi
24 /* The Secure Mailer license must be distributed with this software.
25 /* AUTHOR(S)
26 /* Wietse Venema
27 /* IBM T.J. Watson Research
28 /* P.O. Box 704
29 /* Yorktown Heights, NY 10598, USA
30 /*
31 /* Wietse Venema
32 /* Google, Inc.
33 /* 111 8th Avenue
34 /* New York, NY 10011, USA
35 /*--*/
36
37 /* System library. */
38
39 #include <sys_defs.h>
40
41 /* Utility library. */
42
43 #include <split_at.h>
44 #include <stringops.h>
45
46 /* Global library. */
47
48 #include <mail_params.h>
49 #include <quote_821_local.h>
50
51 /* Milter library. */
52
53 #include <milter.h>
54
55 /* Application-specific. */
56
57 #include <smtpd.h>
58 #include <smtpd_sasl_glue.h>
59 #include <smtpd_resolve.h>
60 #include <smtpd_milter.h>
61
62 /*
63 * SLMs.
64 */
65 #define STR(x) vstring_str(x)
66
67 /* smtpd_milter_eval - evaluate milter macro */
68
smtpd_milter_eval(const char * name,void * ptr)69 const char *smtpd_milter_eval(const char *name, void *ptr)
70 {
71 SMTPD_STATE *state = (SMTPD_STATE *) ptr;
72 const RESOLVE_REPLY *reply;
73 char *cp;
74
75 /*
76 * On-the-fly initialization.
77 */
78 if (state->expand_buf == 0)
79 state->expand_buf = vstring_alloc(10);
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_utf8(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 if (strcmp(name, S8_MAC_DAEMON_ADDR) == 0)
119 return (state->dest_addr);
120 if (strcmp(name, S8_MAC_DAEMON_PORT) == 0)
121 return (state->dest_port);
122
123 /*
124 * HELO macros.
125 */
126 #ifdef USE_TLS
127 #define IF_ENCRYPTED(x) (state->tls_context ? (x) : 0)
128 #define IF_TRUSTED(x) (TLS_CERT_IS_TRUSTED(state->tls_context) ? (x) : 0)
129
130 if (strcmp(name, S8_MAC_TLS_VERSION) == 0)
131 return (IF_ENCRYPTED(state->tls_context->protocol));
132 if (strcmp(name, S8_MAC_CIPHER) == 0)
133 return (IF_ENCRYPTED(state->tls_context->cipher_name));
134 if (strcmp(name, S8_MAC_CIPHER_BITS) == 0) {
135 if (state->tls_context == 0)
136 return (0);
137 vstring_sprintf(state->expand_buf, "%d",
138 IF_ENCRYPTED(state->tls_context->cipher_usebits));
139 return (STR(state->expand_buf));
140 }
141 if (strcmp(name, S8_MAC_CERT_SUBJECT) == 0)
142 return (IF_TRUSTED(state->tls_context->peer_CN));
143 if (strcmp(name, S8_MAC_CERT_ISSUER) == 0)
144 return (IF_TRUSTED(state->tls_context->issuer_CN));
145 #endif
146
147 /*
148 * MAIL FROM macros.
149 */
150 #define IF_SASL_ENABLED(s) ((s) ? (s) : 0)
151
152 if (strcmp(name, S8_MAC_I) == 0)
153 return (state->queue_id);
154 #ifdef USE_SASL_AUTH
155 if (strcmp(name, S8_MAC_AUTH_TYPE) == 0)
156 return (IF_SASL_ENABLED(state->sasl_method));
157 if (strcmp(name, S8_MAC_AUTH_AUTHEN) == 0)
158 return (IF_SASL_ENABLED(state->sasl_username));
159 if (strcmp(name, S8_MAC_AUTH_AUTHOR) == 0)
160 return (IF_SASL_ENABLED(state->sasl_sender));
161 #endif
162 if (strcmp(name, S8_MAC_MAIL_ADDR) == 0) {
163 if (state->sender == 0)
164 return (0);
165 if (state->sender[0] == 0)
166 return ("");
167 reply = smtpd_resolve_addr(state->recipient, state->sender);
168 /* Sendmail 8.13 does not externalize the null string. */
169 if (STR(reply->recipient)[0])
170 quote_821_local(state->expand_buf, STR(reply->recipient));
171 else
172 vstring_strcpy(state->expand_buf, STR(reply->recipient));
173 return (STR(state->expand_buf));
174 }
175 if (strcmp(name, S8_MAC_MAIL_HOST) == 0) {
176 if (state->sender == 0)
177 return (0);
178 reply = smtpd_resolve_addr(state->recipient, state->sender);
179 return (STR(reply->nexthop));
180 }
181 if (strcmp(name, S8_MAC_MAIL_MAILER) == 0) {
182 if (state->sender == 0)
183 return (0);
184 reply = smtpd_resolve_addr(state->recipient, state->sender);
185 return (STR(reply->transport));
186 }
187
188 /*
189 * RCPT TO macros.
190 */
191 if (strcmp(name, S8_MAC_RCPT_ADDR) == 0) {
192 if (state->recipient == 0)
193 return (0);
194 if (state->recipient[0] == 0)
195 return ("");
196 if (state->milter_reject_text) {
197 /* 554 5.7.1 <user@example.com>: Relay access denied */
198 vstring_strcpy(state->expand_buf, state->milter_reject_text + 4);
199 cp = split_at(STR(state->expand_buf), ' ');
200 return (cp ? split_at(cp, ' ') : cp);
201 }
202 reply = smtpd_resolve_addr(state->sender, state->recipient);
203 /* Sendmail 8.13 does not externalize the null string. */
204 if (STR(reply->recipient)[0])
205 quote_821_local(state->expand_buf, STR(reply->recipient));
206 else
207 vstring_strcpy(state->expand_buf, STR(reply->recipient));
208 return (STR(state->expand_buf));
209 }
210 if (strcmp(name, S8_MAC_RCPT_HOST) == 0) {
211 if (state->recipient == 0)
212 return (0);
213 if (state->milter_reject_text) {
214 /* 554 5.7.1 <user@example.com>: Relay access denied */
215 vstring_strcpy(state->expand_buf, state->milter_reject_text + 4);
216 (void) split_at(STR(state->expand_buf), ' ');
217 return (STR(state->expand_buf));
218 }
219 reply = smtpd_resolve_addr(state->sender, state->recipient);
220 return (STR(reply->nexthop));
221 }
222 if (strcmp(name, S8_MAC_RCPT_MAILER) == 0) {
223 if (state->recipient == 0)
224 return (0);
225 if (state->milter_reject_text)
226 return (S8_RCPT_MAILER_ERROR);
227 reply = smtpd_resolve_addr(state->sender, state->recipient);
228 return (STR(reply->transport));
229 }
230 return (0);
231 }
232