1 /* $NetBSD: smtpd_expand.c,v 1.1.1.1 2011/03/02 19:32:37 tron Exp $ */ 2 3 /*++ 4 /* NAME 5 /* smtpd_expand 3 6 /* SUMMARY 7 /* SMTP server macro expansion 8 /* SYNOPSIS 9 /* #include <smtpd.h> 10 /* #include <smtpd_expand.h> 11 /* 12 /* void smtpd_expand_init() 13 /* 14 /* int smtpd_expand(state, result, template, flags) 15 /* SMTPD_STATE *state; 16 /* VSTRING *result; 17 /* const char *template; 18 /* int flags; 19 /* LOW_LEVEL INTERFACE 20 /* VSTRING *smtpd_expand_filter; 21 /* 22 /* const char *smtpd_expand_lookup(name, unused_mode, context) 23 /* const char *name; 24 /* int unused_mode; 25 /* char *context; 26 /* const char *template; 27 /* DESCRIPTION 28 /* This module expands session-related macros. 29 /* 30 /* smtpd_expand_init() performs one-time initialization. 31 /* 32 /* smtpd_expand() expands macros in the template, using session 33 /* attributes in the state argument, and writes the result to 34 /* the result argument. The flags and result value are as with 35 /* mac_expand(). 36 /* 37 /* smtpd_expand_filter and smtpd_expand_lookup() provide access 38 /* to lower-level interfaces that are used by smtpd_expand(). 39 /* smtpd_expand_lookup() returns null when a string is not 40 /* found (or when it is a null pointer). 41 /* DIAGNOSTICS 42 /* Panic: interface violations. Fatal errors: out of memory. 43 /* internal protocol errors. smtpd_expand() returns the binary 44 /* OR of MAC_PARSE_ERROR (syntax error) and MAC_PARSE_UNDEF 45 /* (undefined macro name). 46 /* LICENSE 47 /* .ad 48 /* .fi 49 /* The Secure Mailer license must be distributed with this software. 50 /* AUTHOR(S) 51 /* Wietse Venema 52 /* IBM T.J. Watson Research 53 /* P.O. Box 704 54 /* Yorktown Heights, NY 10598, USA 55 /*--*/ 56 57 /* System library. */ 58 59 #include <sys_defs.h> 60 #include <time.h> 61 62 /* Utility library. */ 63 64 #include <msg.h> 65 #include <vstring.h> 66 #include <mac_expand.h> 67 #include <stringops.h> 68 69 /* Global library. */ 70 71 #include <mail_params.h> 72 #include <mail_proto.h> 73 74 /* Application-specific. */ 75 76 #include <smtpd.h> 77 #include <smtpd_expand.h> 78 79 /* 80 * Pre-parsed expansion filter. 81 */ 82 VSTRING *smtpd_expand_filter; 83 84 /* 85 * SLMs. 86 */ 87 #define STR vstring_str 88 89 /* smtpd_expand_init - initialize once during process lifetime */ 90 91 void smtpd_expand_init(void) 92 { 93 94 /* 95 * Expand the expansion filter :-) 96 */ 97 smtpd_expand_filter = vstring_alloc(10); 98 unescape(smtpd_expand_filter, var_smtpd_exp_filter); 99 } 100 101 /* smtpd_expand_unknown - report unknown macro name */ 102 103 static void smtpd_expand_unknown(const char *name) 104 { 105 msg_warn("unknown macro name \"%s\" in expansion request", name); 106 } 107 108 /* smtpd_expand_addr - return address or substring thereof */ 109 110 static const char *smtpd_expand_addr(VSTRING *buf, const char *addr, 111 const char *name, int prefix_len) 112 { 113 const char *p; 114 const char *suffix; 115 116 /* 117 * Return NULL only for unknown names in expansion requests. 118 */ 119 if (addr == 0) 120 return (""); 121 122 suffix = name + prefix_len; 123 124 /* 125 * MAIL_ATTR_SENDER or MAIL_ATTR_RECIP. 126 */ 127 if (*suffix == 0) { 128 if (*addr) 129 return (addr); 130 else 131 return ("<>"); 132 } 133 134 /* 135 * "sender_name" or "recipient_name". 136 */ 137 #define STREQ(x,y) (*(x) == *(y) && strcmp((x), (y)) == 0) 138 139 else if (STREQ(suffix, MAIL_ATTR_S_NAME)) { 140 if (*addr) { 141 if ((p = strrchr(addr, '@')) != 0) { 142 vstring_strncpy(buf, addr, p - addr); 143 return (STR(buf)); 144 } else { 145 return (addr); 146 } 147 } else 148 return ("<>"); 149 } 150 151 /* 152 * "sender_domain" or "recipient_domain". 153 */ 154 else if (STREQ(suffix, MAIL_ATTR_S_DOMAIN)) { 155 if (*addr) { 156 if ((p = strrchr(addr, '@')) != 0) { 157 return (p + 1); 158 } else { 159 return (""); 160 } 161 } else 162 return (""); 163 } 164 165 /* 166 * Unknown. Return NULL to indicate an "unknown name" error. 167 */ 168 else { 169 smtpd_expand_unknown(name); 170 return (0); 171 } 172 } 173 174 /* smtpd_expand_lookup - generic SMTP attribute $name expansion */ 175 176 const char *smtpd_expand_lookup(const char *name, int unused_mode, 177 char *context) 178 { 179 SMTPD_STATE *state = (SMTPD_STATE *) context; 180 time_t now; 181 struct tm *lt; 182 183 if (state->expand_buf == 0) 184 state->expand_buf = vstring_alloc(10); 185 186 if (msg_verbose > 1) 187 msg_info("smtpd_expand_lookup: ${%s}", name); 188 189 #define STREQN(x,y,n) (*(x) == *(y) && strncmp((x), (y), (n)) == 0) 190 #define CONST_LEN(x) (sizeof(x) - 1) 191 192 /* 193 * Don't query main.cf parameters, as the result of expansion could 194 * reveal system-internal information in server replies. 195 * 196 * XXX: This said, multiple servers may be behind a single client-visible 197 * name or IP address, and each may generate its own logs. Therefore, it 198 * may be useful to expose the replying MTA id (myhostname) in the 199 * contact footer, to identify the right logs. So while we don't expose 200 * the raw configuration dictionary, we do expose "$myhostname" as 201 * expanded in var_myhostname. 202 * 203 * Return NULL only for non-existent names. 204 */ 205 if (STREQ(name, MAIL_ATTR_SERVER_NAME)) { 206 return (var_myhostname); 207 } else if (STREQ(name, MAIL_ATTR_ACT_CLIENT)) { 208 return (state->namaddr); 209 } else if (STREQ(name, MAIL_ATTR_ACT_CLIENT_PORT)) { 210 return (state->port); 211 } else if (STREQ(name, MAIL_ATTR_ACT_CLIENT_ADDR)) { 212 return (state->addr); 213 } else if (STREQ(name, MAIL_ATTR_ACT_CLIENT_NAME)) { 214 return (state->name); 215 } else if (STREQ(name, MAIL_ATTR_ACT_REVERSE_CLIENT_NAME)) { 216 return (state->reverse_name); 217 } else if (STREQ(name, MAIL_ATTR_ACT_HELO_NAME)) { 218 return (state->helo_name ? state->helo_name : ""); 219 } else if (STREQN(name, MAIL_ATTR_SENDER, CONST_LEN(MAIL_ATTR_SENDER))) { 220 return (smtpd_expand_addr(state->expand_buf, state->sender, 221 name, CONST_LEN(MAIL_ATTR_SENDER))); 222 } else if (STREQN(name, MAIL_ATTR_RECIP, CONST_LEN(MAIL_ATTR_RECIP))) { 223 return (smtpd_expand_addr(state->expand_buf, state->recipient, 224 name, CONST_LEN(MAIL_ATTR_RECIP))); 225 } if (STREQ(name, MAIL_ATTR_LOCALTIME)) { 226 if (time(&now) == (time_t) - 1) 227 msg_fatal("time lookup failed: %m"); 228 lt = localtime(&now); 229 VSTRING_RESET(state->expand_buf); 230 do { 231 VSTRING_SPACE(state->expand_buf, 100); 232 } while (strftime(STR(state->expand_buf), 233 vstring_avail(state->expand_buf), 234 "%b %d %H:%M:%S", lt) == 0); 235 return (STR(state->expand_buf)); 236 } else { 237 smtpd_expand_unknown(name); 238 return (0); 239 } 240 } 241 242 /* smtpd_expand - expand session attributes in string */ 243 244 int smtpd_expand(SMTPD_STATE *state, VSTRING *result, 245 const char *template, int flags) 246 { 247 return (mac_expand(result, template, flags, STR(smtpd_expand_filter), 248 smtpd_expand_lookup, (char *) state)); 249 } 250