diff options
Diffstat (limited to 'src/smtp/smtp_key.c')
-rw-r--r-- | src/smtp/smtp_key.c | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/src/smtp/smtp_key.c b/src/smtp/smtp_key.c new file mode 100644 index 0000000..643f4db --- /dev/null +++ b/src/smtp/smtp_key.c @@ -0,0 +1,215 @@ +/*++ +/* NAME +/* smtp_key 3 +/* SUMMARY +/* cache/table lookup key management +/* SYNOPSIS +/* #include "smtp.h" +/* +/* char *smtp_key_prefix(buffer, delim_na, iterator, context_flags) +/* VSTRING *buffer; +/* const char *delim_na; +/* SMTP_ITERATOR *iterator; +/* int context_flags; +/* DESCRIPTION +/* The Postfix SMTP server accesses caches and lookup tables, +/* using lookup keys that contain information from various +/* contexts: per-server configuration, per-request envelope, +/* and results from DNS queries. +/* +/* These lookup keys sometimes share the same context information. +/* The primary purpose of this API is to ensure that this +/* shared context is used consistently, and that its use is +/* made explicit (both are needed to verify that there is no +/* false cache sharing). +/* +/* smtp_key_prefix() constructs a lookup key prefix from context +/* that may be shared with other lookup keys. The user is free +/* to append additional application-specific context. The result +/* value is a pointer to the result text. +/* +/* Arguments: +/* .IP buffer +/* Storage for the result. +/* .IP delim_na +/* The field delimiter character, and the optional place holder +/* character for a) information that is unavailable, b) +/* information that is inapplicable, or c) that would result +/* in an empty field. Key fields that contain "delim_na" +/* characters will be base64-encoded. +/* Do not specify "delim_na" characters that are part of the +/* base64 character set. +/* .IP iterator +/* Information that will be selected by the specified flags. +/* .IP context_flags +/* Bit-wise OR of one or more of the following. +/* .RS +/* .IP SMTP_KEY_FLAG_SERVICE +/* The global service name. This is a proxy for +/* destination-independent and request-independent context. +/* .IP SMTP_KEY_FLAG_SENDER +/* The envelope sender address. This is a proxy for sender-dependent +/* context, such as per-sender SASL authentication. +/* .IP SMTP_KEY_FLAG_REQ_NEXTHOP +/* The delivery request nexthop destination, including optional +/* [] and :port (the same form that users specify in a SASL +/* password or TLS policy lookup table). This is a proxy for +/* destination-dependent, but host-independent context. +/* .IP SMTP_KEY_FLAG_CUR_NEXTHOP +/* The current iterator's nexthop destination (delivery request +/* nexthop or fallback nexthop, including optional [] and +/* :port). +/* .IP SMTP_KEY_FLAG_HOSTNAME +/* The current iterator's remote hostname. +/* .IP SMTP_KEY_FLAG_ADDR +/* The current iterator's remote address. +/* .IP SMTP_KEY_FLAG_PORT +/* The current iterator's remote port. +/* .RE +/* DIAGNOSTICS +/* Panic: undefined flag or zero flags. Fatal: out of memory. +/* LICENSE +/* .ad +/* .fi +/* The Secure Mailer license must be distributed with this software. +/* AUTHOR(S) +/* Wietse Venema +/* IBM T.J. Watson Research +/* P.O. Box 704 +/* Yorktown Heights, NY 10598, USA +/* +/* Wietse Venema +/* Google, Inc. +/* 111 8th Avenue +/* New York, NY 10011, USA +/*--*/ + + /* + * System library. + */ +#include <sys_defs.h> +#include <netinet/in.h> /* ntohs() for Solaris or BSD */ +#include <arpa/inet.h> /* ntohs() for Linux or BSD */ +#include <string.h> + + /* + * Utility library. + */ +#include <msg.h> +#include <vstring.h> +#include <base64_code.h> + + /* + * Global library. + */ +#include <mail_params.h> + + /* + * Application-specific. + */ +#include <smtp.h> + + /* + * We use a configurable field terminator and optional place holder for data + * that is unavailable or inapplicable. We base64-encode content that + * contains these characters, and content that needs obfuscation. + */ + +/* smtp_key_append_na - append place-holder key field */ + +static void smtp_key_append_na(VSTRING *buffer, const char *delim_na) +{ + if (delim_na[1] != 0) + VSTRING_ADDCH(buffer, delim_na[1]); + VSTRING_ADDCH(buffer, delim_na[0]); +} + +/* smtp_key_append_str - append string-valued key field */ + +static void smtp_key_append_str(VSTRING *buffer, const char *str, + const char *delim_na) +{ + if (str == 0 || str[0] == 0) { + smtp_key_append_na(buffer, delim_na); + } else if (str[strcspn(str, delim_na)] != 0) { + base64_encode_opt(buffer, str, strlen(str), BASE64_FLAG_APPEND); + VSTRING_ADDCH(buffer, delim_na[0]); + } else { + vstring_sprintf_append(buffer, "%s%c", str, delim_na[0]); + } +} + +/* smtp_key_append_uint - append unsigned-valued key field */ + +static void smtp_key_append_uint(VSTRING *buffer, unsigned num, + const char *delim_na) +{ + vstring_sprintf_append(buffer, "%u%c", num, delim_na[0]); +} + +/* smtp_key_prefix - format common elements in lookup key */ + +char *smtp_key_prefix(VSTRING *buffer, const char *delim_na, + SMTP_ITERATOR *iter, int flags) +{ + static const char myname[] = "smtp_key_prefix"; + SMTP_STATE *state = iter->parent; /* private member */ + + /* + * Sanity checks. + */ + if (state == 0) + msg_panic("%s: no parent state", myname); + if (flags & ~SMTP_KEY_MASK_ALL) + msg_panic("%s: unknown key flags 0x%x", + myname, flags & ~SMTP_KEY_MASK_ALL); + if (flags == 0) + msg_panic("%s: zero flags", myname); + + /* + * Initialize. + */ + VSTRING_RESET(buffer); + + /* + * Per-service and per-request context. + */ + if (flags & SMTP_KEY_FLAG_SERVICE) + smtp_key_append_str(buffer, state->service, delim_na); + if (flags & SMTP_KEY_FLAG_SENDER) + smtp_key_append_str(buffer, state->request->sender, delim_na); + + /* + * Per-destination context, non-canonicalized form. + */ + if (flags & SMTP_KEY_FLAG_REQ_NEXTHOP) + smtp_key_append_str(buffer, STR(iter->request_nexthop), delim_na); + if (flags & SMTP_KEY_FLAG_CUR_NEXTHOP) + smtp_key_append_str(buffer, STR(iter->dest), delim_na); + + /* + * Per-host context, canonicalized form. + */ + if (flags & SMTP_KEY_FLAG_HOSTNAME) + smtp_key_append_str(buffer, STR(iter->host), delim_na); + if (flags & SMTP_KEY_FLAG_ADDR) + smtp_key_append_str(buffer, STR(iter->addr), delim_na); + if (flags & SMTP_KEY_FLAG_PORT) + smtp_key_append_uint(buffer, ntohs(iter->port), delim_na); + + /* + * Requested TLS level, if applicable. TODO(tlsproxy) should the lookup + * engine also try the requested TLS level and 'stronger', in case a + * server hosts multiple domains with different TLS requirements? + */ + if (flags & SMTP_KEY_FLAG_TLS_LEVEL) +#ifdef USE_TLS + smtp_key_append_uint(buffer, state->tls->level, delim_na); +#else + smtp_key_append_na(buffer, delim_na); +#endif + + VSTRING_TERMINATE(buffer); + + return STR(buffer); +} |