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