1/* $NetBSD$ */ 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 32/* System library. */ 33 34#include <sys_defs.h> 35 36/* Utility library. */ 37 38#include <split_at.h> 39 40/* Global library. */ 41 42#include <mail_params.h> 43#include <quote_821_local.h> 44 45/* Milter library. */ 46 47#include <milter.h> 48 49/* Application-specific. */ 50 51#include <smtpd.h> 52#include <smtpd_sasl_glue.h> 53#include <smtpd_resolve.h> 54#include <smtpd_milter.h> 55 56 /* 57 * SLMs. 58 */ 59#define STR(x) vstring_str(x) 60 61/* smtpd_milter_eval - evaluate milter macro */ 62 63const char *smtpd_milter_eval(const char *name, void *ptr) 64{ 65 SMTPD_STATE *state = (SMTPD_STATE *) ptr; 66 const RESOLVE_REPLY *reply; 67 char *cp; 68 69 /* 70 * On-the-fly initialization. 71 */ 72 if (state->expand_buf == 0) 73 state->expand_buf = vstring_alloc(10); 74 75 /* 76 * Canonicalize the name. 77 */ 78 if (*name != '{') { /* } */ 79 vstring_sprintf(state->expand_buf, "{%s}", name); 80 name = STR(state->expand_buf); 81 } 82 83 /* 84 * System macros. 85 */ 86 if (strcmp(name, S8_MAC_DAEMON_NAME) == 0) 87 return (var_milt_daemon_name); 88 if (strcmp(name, S8_MAC_V) == 0) 89 return (var_milt_v); 90 91 /* 92 * Connect macros. 93 */ 94 if (strcmp(name, S8_MAC__) == 0) { 95 vstring_sprintf(state->expand_buf, "%s [%s]", 96 state->reverse_name, state->addr); 97 if (strcasecmp(state->name, state->reverse_name) != 0) 98 vstring_strcat(state->expand_buf, " (may be forged)"); 99 return (STR(state->expand_buf)); 100 } 101 if (strcmp(name, S8_MAC_J) == 0) 102 return (var_myhostname); 103 if (strcmp(name, S8_MAC_CLIENT_ADDR) == 0) 104 return (state->rfc_addr); 105 if (strcmp(name, S8_MAC_CLIENT_PORT) == 0) 106 return (strcmp(state->port, CLIENT_PORT_UNKNOWN) ? state->port : "0"); 107 if (strcmp(name, S8_MAC_CLIENT_CONN) == 0) { 108 vstring_sprintf(state->expand_buf, "%d", state->conn_count); 109 return (STR(state->expand_buf)); 110 } 111 if (strcmp(name, S8_MAC_CLIENT_NAME) == 0) 112 return (state->name); 113 if (strcmp(name, S8_MAC_CLIENT_PTR) == 0) 114 return (state->reverse_name); 115 if (strcmp(name, S8_MAC_CLIENT_RES) == 0) 116 return (state->name_status == SMTPD_PEER_CODE_OK ? "OK" : 117 state->name_status == SMTPD_PEER_CODE_FORGED ? "FORGED" : 118 state->name_status == SMTPD_PEER_CODE_TEMP ? "TEMP" : "FAIL"); 119 120 /* 121 * HELO macros. 122 */ 123#ifdef USE_TLS 124#define IF_ENCRYPTED(x) (state->tls_context ? (x) : 0) 125#define IF_TRUSTED(x) (TLS_CERT_IS_TRUSTED(state->tls_context) ? (x) : 0) 126 127 if (strcmp(name, S8_MAC_TLS_VERSION) == 0) 128 return (IF_ENCRYPTED(state->tls_context->protocol)); 129 if (strcmp(name, S8_MAC_CIPHER) == 0) 130 return (IF_ENCRYPTED(state->tls_context->cipher_name)); 131 if (strcmp(name, S8_MAC_CIPHER_BITS) == 0) { 132 if (state->tls_context == 0) 133 return (0); 134 vstring_sprintf(state->expand_buf, "%d", 135 IF_ENCRYPTED(state->tls_context->cipher_usebits)); 136 return (STR(state->expand_buf)); 137 } 138 if (strcmp(name, S8_MAC_CERT_SUBJECT) == 0) 139 return (IF_TRUSTED(state->tls_context->peer_CN)); 140 if (strcmp(name, S8_MAC_CERT_ISSUER) == 0) 141 return (IF_TRUSTED(state->tls_context->issuer_CN)); 142#endif 143 144 /* 145 * MAIL FROM macros. 146 */ 147#define IF_SASL_ENABLED(s) (smtpd_sasl_is_active(state) && (s) ? (s) : 0) 148 149 if (strcmp(name, S8_MAC_I) == 0) 150 return (state->queue_id); 151#ifdef USE_SASL_AUTH 152 if (strcmp(name, S8_MAC_AUTH_TYPE) == 0) 153 return (IF_SASL_ENABLED(state->sasl_method)); 154 if (strcmp(name, S8_MAC_AUTH_AUTHEN) == 0) 155 return (IF_SASL_ENABLED(state->sasl_username)); 156 if (strcmp(name, S8_MAC_AUTH_AUTHOR) == 0) 157 return (IF_SASL_ENABLED(state->sasl_sender)); 158#endif 159 if (strcmp(name, S8_MAC_MAIL_ADDR) == 0) { 160 if (state->sender == 0) 161 return (0); 162 if (state->sender[0] == 0) 163 return (""); 164 reply = smtpd_resolve_addr(state->sender); 165 /* Sendmail 8.13 does not externalize the null string. */ 166 if (STR(reply->recipient)[0]) 167 quote_821_local(state->expand_buf, STR(reply->recipient)); 168 else 169 vstring_strcpy(state->expand_buf, STR(reply->recipient)); 170 return (STR(state->expand_buf)); 171 } 172 if (strcmp(name, S8_MAC_MAIL_HOST) == 0) { 173 if (state->sender == 0) 174 return (0); 175 reply = smtpd_resolve_addr(state->sender); 176 return (STR(reply->nexthop)); 177 } 178 if (strcmp(name, S8_MAC_MAIL_MAILER) == 0) { 179 if (state->sender == 0) 180 return (0); 181 reply = smtpd_resolve_addr(state->sender); 182 return (STR(reply->transport)); 183 } 184 185 /* 186 * RCPT TO macros. 187 */ 188 if (strcmp(name, S8_MAC_RCPT_ADDR) == 0) { 189 if (state->recipient == 0) 190 return (0); 191 if (state->recipient[0] == 0) 192 return (""); 193 if (state->milter_reject_text) { 194 /* 554 5.7.1 <user@example.com>: Relay access denied */ 195 vstring_strcpy(state->expand_buf, state->milter_reject_text + 4); 196 cp = split_at(STR(state->expand_buf), ' '); 197 return (cp ? split_at(cp, ' ') : cp); 198 } 199 reply = smtpd_resolve_addr(state->recipient); 200 /* Sendmail 8.13 does not externalize the null string. */ 201 if (STR(reply->recipient)[0]) 202 quote_821_local(state->expand_buf, STR(reply->recipient)); 203 else 204 vstring_strcpy(state->expand_buf, STR(reply->recipient)); 205 return (STR(state->expand_buf)); 206 } 207 if (strcmp(name, S8_MAC_RCPT_HOST) == 0) { 208 if (state->recipient == 0) 209 return (0); 210 if (state->milter_reject_text) { 211 /* 554 5.7.1 <user@example.com>: Relay access denied */ 212 vstring_strcpy(state->expand_buf, state->milter_reject_text + 4); 213 (void) split_at(STR(state->expand_buf), ' '); 214 return (STR(state->expand_buf)); 215 } 216 reply = smtpd_resolve_addr(state->recipient); 217 return (STR(reply->nexthop)); 218 } 219 if (strcmp(name, S8_MAC_RCPT_MAILER) == 0) { 220 if (state->recipient == 0) 221 return (0); 222 if (state->milter_reject_text) 223 return (S8_RCPT_MAILER_ERROR); 224 reply = smtpd_resolve_addr(state->recipient); 225 return (STR(reply->transport)); 226 } 227 return (0); 228} 229