summaryrefslogtreecommitdiffstats
path: root/src/global/resolve_local.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/global/resolve_local.c')
-rw-r--r--src/global/resolve_local.c192
1 files changed, 192 insertions, 0 deletions
diff --git a/src/global/resolve_local.c b/src/global/resolve_local.c
new file mode 100644
index 0000000..c6ef848
--- /dev/null
+++ b/src/global/resolve_local.c
@@ -0,0 +1,192 @@
+/*++
+/* NAME
+/* resolve_local 3
+/* SUMMARY
+/* determine if domain resolves to local mail system
+/* SYNOPSIS
+/* #include <resolve_local.h>
+/*
+/* void resolve_local_init()
+/*
+/* int resolve_local(domain)
+/* const char *domain;
+/* DESCRIPTION
+/* resolve_local() determines if the named domain resolves to the
+/* local mail system, either by case-insensitive exact match
+/* against the domains, files or tables listed in $mydestination,
+/* or by a match of an [address-literal] against of the network
+/* addresses listed in $inet_interfaces or in $proxy_interfaces.
+/* The result is > 0 if the domain matches the list of local
+/* domains and IP addresses, 0 when it does not match, and < 0
+/* in case of error.
+/*
+/* resolve_local_init() performs initialization. If this routine is
+/* not called explicitly ahead of time, it will be called on the fly.
+/* BUGS
+/* Calling resolve_local_init() on the fly is an incomplete solution.
+/* It is bound to fail with applications that enter a chroot jail.
+/* SEE ALSO
+/* own_inet_addr(3), find out my own network interfaces
+/* match_list(3), generic pattern matching engine
+/* match_ops(3), generic pattern matching operators
+/* 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
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <mymalloc.h>
+#include <string_list.h>
+#include <myaddrinfo.h>
+#include <valid_mailhost_addr.h>
+
+/* Global library. */
+
+#include <mail_params.h>
+#include <own_inet_addr.h>
+#include <resolve_local.h>
+
+/* Application-specific */
+
+static STRING_LIST *resolve_local_list;
+
+/* resolve_local_init - initialize lookup table */
+
+void resolve_local_init(void)
+{
+ /* Allow on-the-fly update to make testing easier. */
+ if (resolve_local_list)
+ string_list_free(resolve_local_list);
+ resolve_local_list = string_list_init(VAR_MYDEST, MATCH_FLAG_RETURN,
+ var_mydest);
+}
+
+/* resolve_local - match domain against list of local destinations */
+
+int resolve_local(const char *addr)
+{
+ char *saved_addr = mystrdup(addr);
+ char *dest;
+ const char *bare_dest;
+ struct addrinfo *res0 = 0;
+ ssize_t len;
+
+ /*
+ * The optimizer will eliminate tests that always fail.
+ */
+#define RETURN(x) \
+ do { \
+ myfree(saved_addr); \
+ if (res0) \
+ freeaddrinfo(res0); \
+ return(x); \
+ } while (0)
+
+ if (resolve_local_list == 0)
+ resolve_local_init();
+
+ /*
+ * Strip one trailing dot but not dot-dot.
+ *
+ * XXX This should not be distributed all over the code. Problem is,
+ * addresses can enter the system via multiple paths: networks, local
+ * forward/alias/include files, even as the result of address rewriting.
+ */
+ len = strlen(saved_addr);
+ if (len == 0)
+ RETURN(0);
+ if (saved_addr[len - 1] == '.')
+ saved_addr[--len] = 0;
+ if (len == 0 || saved_addr[len - 1] == '.')
+ RETURN(0);
+
+ /*
+ * Compare the destination against the list of destinations that we
+ * consider local.
+ */
+ if (string_list_match(resolve_local_list, saved_addr))
+ RETURN(1);
+ if (resolve_local_list->error != 0)
+ RETURN(resolve_local_list->error);
+
+ /*
+ * Compare the destination against the list of interface addresses that
+ * we are supposed to listen on.
+ *
+ * The destination may be an IPv6 address literal that was buried somewhere
+ * inside a deeply recursively nested address. This information comes
+ * from an untrusted source, and Wietse is not confident that everyone's
+ * getaddrinfo() etc. implementation is sufficiently robust. The syntax
+ * is complex enough with null field compression and with IPv4-in-IPv6
+ * addresses that errors are likely.
+ *
+ * The solution below is ad-hoc. We neutralize the string as soon as we
+ * realize that its contents could be harmful. We neutralize the string
+ * here, instead of neutralizing it in every resolve_local() caller.
+ * That's because resolve_local knows how the address is going to be
+ * parsed and converted into binary form.
+ *
+ * There are several more structural solutions to this.
+ *
+ * - One solution is to disallow address literals. This is not as bad as it
+ * seems: I have never seen actual legitimate use of address literals.
+ *
+ * - Another solution is to label each string with a trustworthiness label
+ * and to expect that all Postfix infrastructure will exercise additional
+ * caution when given a string with untrusted content. This is not likely
+ * to happen.
+ *
+ * FIX 200501 IPv6 patch did not require "IPv6:" prefix in numerical
+ * addresses.
+ */
+ dest = saved_addr;
+ if (*dest == '[' && dest[len - 1] == ']') {
+ dest++;
+ dest[len -= 2] = 0;
+ if ((bare_dest = valid_mailhost_addr(dest, DO_GRIPE)) != 0
+ && hostaddr_to_sockaddr(bare_dest, (char *) 0, 0, &res0) == 0) {
+ if (own_inet_addr(res0->ai_addr) || proxy_inet_addr(res0->ai_addr))
+ RETURN(1);
+ }
+ }
+
+ /*
+ * Must be remote, or a syntax error.
+ */
+ RETURN(0);
+}
+
+#ifdef TEST
+
+#include <vstream.h>
+#include <mail_conf.h>
+
+int main(int argc, char **argv)
+{
+ int rc;
+
+ if (argc != 3)
+ msg_fatal("usage: %s mydestination domain", argv[0]);
+ mail_conf_read();
+ myfree(var_mydest);
+ var_mydest = mystrdup(argv[1]);
+ vstream_printf("mydestination=%s destination=%s %s\n", argv[1], argv[2],
+ (rc = resolve_local(argv[2])) > 0 ? "YES" :
+ rc == 0 ? "NO" : "ERROR");
+ vstream_fflush(VSTREAM_OUT);
+ return (0);
+}
+
+#endif