From: Wietse Venema Date: Wed, 23 Aug 2000 00:00:00 +0000 (+0000) Subject: snapshot-20000823 X-Git-Tag: v20010228~45 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=77741d9964e5720819b2561bffb0ca979815d45a;p=thirdparty%2Fpostfix.git snapshot-20000823 --- diff --git a/postfix/HISTORY b/postfix/HISTORY index 6116015b3..106f87a42 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -4147,3 +4147,12 @@ Apologies for any names omitted. that cannot be represented with the off_t type that is used by standard functions such as lseek(2). Problem reported by Blaz Zupan @ amis.net. + +20000823 + + Feature: all this discussion about when to reject mail and + when not made me decide to implement a TCP-based map type + so that it becomes relatively simple to implement dynamic + access controls, for example, hold off mail from an unknown + client or sender until we have completed some investigation, + after which we will either reject or accept. diff --git a/postfix/global/mail_version.h b/postfix/global/mail_version.h index 79c466832..64a3274c3 100644 --- a/postfix/global/mail_version.h +++ b/postfix/global/mail_version.h @@ -15,7 +15,7 @@ * Version of this program. */ #define VAR_MAIL_VERSION "mail_version" -#define DEF_MAIL_VERSION "Snapshot-20000822" +#define DEF_MAIL_VERSION "Snapshot-20000823" extern char *var_mail_version; /* LICENSE diff --git a/postfix/util/.indent.pro b/postfix/util/.indent.pro index 5fbb816df..15931a7c1 100644 --- a/postfix/util/.indent.pro +++ b/postfix/util/.indent.pro @@ -32,6 +32,7 @@ -TDICT_PCRE -TDICT_REGEXP -TDICT_REGEXP_RULE +-TDICT_TCP -TDICT_UNIX -TDNS_FIXED -TDNS_REPLY diff --git a/postfix/util/Makefile.in b/postfix/util/Makefile.in index 89023fd45..9ce340a7e 100644 --- a/postfix/util/Makefile.in +++ b/postfix/util/Makefile.in @@ -21,7 +21,8 @@ SRCS = argv.c argv_split.c attr.c basename.c binhash.c chroot_uid.c \ write_buf.c write_wait.c dict_unix.c dict_pcre.c stream_listen.c \ stream_connect.c stream_trigger.c dict_regexp.c mac_expand.c \ clean_env.c watchdog.c spawn_command.c duplex_pipe.c sane_rename.c \ - sane_link.c unescape.c timed_read.c timed_write.c + sane_link.c unescape.c timed_read.c timed_write.c dict_tcp.c \ + hex_quote.c OBJS = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \ close_on_exec.o concatenate.o dict.o dict_db.o dict_dbm.o \ dict_env.o dict_ht.o dict_ldap.o dict_mysql.o dict_ni.o dict_nis.o \ @@ -44,7 +45,8 @@ OBJS = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \ write_buf.o write_wait.o dict_unix.o dict_pcre.o stream_listen.o \ stream_connect.o stream_trigger.o dict_regexp.o mac_expand.o \ clean_env.o watchdog.o spawn_command.o duplex_pipe.o sane_rename.o \ - sane_link.o unescape.o timed_read.o timed_write.o + sane_link.o unescape.o timed_read.o timed_write.o dict_tcp.o \ + hex_quote.o HDRS = argv.h attr.h binhash.h chroot_uid.h connect.h dict.h dict_db.h \ dict_dbm.h dict_env.h dict_ht.h dict_ldap.h dict_mysql.h \ dict_ni.h dict_nis.h dict_nisplus.h dir_forest.h events.h \ @@ -59,7 +61,7 @@ HDRS = argv.h attr.h binhash.h chroot_uid.h connect.h dict.h dict_db.h \ timed_connect.h timed_wait.h trigger.h username.h valid_hostname.h \ vbuf.h vbuf_print.h vstream.h vstring.h vstring_vstream.h \ dict_unix.h dict_pcre.h dict_regexp.h mac_expand.h clean_env.h \ - watchdog.h spawn_command.h sane_fsops.h + watchdog.h spawn_command.h sane_fsops.h dict_tcp.h hex_quote.h TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \ stream_test.c dup2_pass_on_exec.c WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ @@ -75,7 +77,7 @@ TESTPROG= dict_open dup2_pass_on_exec events exec_command fifo_open \ inet_addr_host inet_addr_local mac_parse make_dirs msg_syslog \ mystrtok sigdelay translit valid_hostname vstream_popen \ vstring vstring_vstream doze select_bug stream_test mac_expand \ - watchdog unescape + watchdog unescape hex_quote LIB_DIR = ../lib INC_DIR = ../include @@ -249,6 +251,11 @@ unescape: $(LIB) $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) mv junk $@.o +hex_quote: $(LIB) + mv $@.o junk + $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) + mv junk $@.o + depend: $(MAKES) (sed '1,/^# do not edit/!d' Makefile.in; \ set -e; for i in [a-z][a-z0-9]*.c; do \ @@ -260,7 +267,8 @@ depend: $(MAKES) stream_test: stream_test.c $(LIB) $(CC) $(CFLAGS) -o $@ $@.c $(LIB) $(SYSLIBS) -tests: valid_hostname_test mac_expand_test dict_test unescape_test +tests: valid_hostname_test mac_expand_test dict_test unescape_test \ + hex_quote_test valid_hostname_test: valid_hostname valid_hostname.in valid_hostname.ref ./valid_hostname valid_hostname.tmp @@ -277,6 +285,12 @@ unescape_test: unescape unescape.in unescape.ref diff -b unescape.ref unescape.tmp rm -f unescape.tmp +hex_quote_test: hex_quote + ./hex_quote hex_quote.tmp + od -cb hex_quote.ref + cmp hex_quote.ref hex_quote.tmp + rm -f hex_quote.ref hex_quote.tmp + DB_TYPE = `../postconf/postconf -h default_database_type` dict_test: dict_open testdb dict_test.in dict_test.ref @@ -416,6 +430,7 @@ dict_open.o: vstream.h dict_open.o: vbuf.h dict_open.o: dict_env.h dict_open.o: dict_unix.h +dict_open.o: dict_tcp.h dict_open.o: dict_dbm.h dict_open.o: dict_db.h dict_open.o: dict_nis.h @@ -445,6 +460,20 @@ dict_regexp.o: dict.h dict_regexp.o: argv.h dict_regexp.o: dict_regexp.h dict_regexp.o: mac_parse.h +dict_tcp.o: dict_tcp.c +dict_tcp.o: sys_defs.h +dict_tcp.o: msg.h +dict_tcp.o: mymalloc.h +dict_tcp.o: vstring.h +dict_tcp.o: vbuf.h +dict_tcp.o: vstream.h +dict_tcp.o: vstring_vstream.h +dict_tcp.o: connect.h +dict_tcp.o: iostuff.h +dict_tcp.o: hex_quote.h +dict_tcp.o: dict.h +dict_tcp.o: argv.h +dict_tcp.o: dict_tcp.h dict_unix.o: dict_unix.c dict_unix.o: sys_defs.h dict_unix.o: msg.h @@ -465,6 +494,7 @@ doze.o: doze.c doze.o: sys_defs.h doze.o: msg.h doze.o: iostuff.h +dup2_pass_on_exec.o: dup2_pass_on_exec.c duplex_pipe.o: duplex_pipe.c duplex_pipe.o: sys_defs.h duplex_pipe.o: iostuff.h @@ -526,6 +556,12 @@ get_hostname.o: mymalloc.h get_hostname.o: msg.h get_hostname.o: valid_hostname.h get_hostname.o: get_hostname.h +hex_quote.o: hex_quote.c +hex_quote.o: sys_defs.h +hex_quote.o: msg.h +hex_quote.o: vstring.h +hex_quote.o: vbuf.h +hex_quote.o: hex_quote.h htable.o: htable.c htable.o: sys_defs.h htable.o: mymalloc.h @@ -948,6 +984,7 @@ vstring_vstream.o: vstream.h vstring_vstream.o: vstring_vstream.h watchdog.o: watchdog.c watchdog.o: sys_defs.h +watchdog.o: posix_signals.h watchdog.o: msg.h watchdog.o: mymalloc.h watchdog.o: watchdog.h diff --git a/postfix/util/dict_open.c b/postfix/util/dict_open.c index 1eb2471ae..69a4071e8 100644 --- a/postfix/util/dict_open.c +++ b/postfix/util/dict_open.c @@ -156,6 +156,7 @@ #include #include #include +#include #include #include #include @@ -180,6 +181,7 @@ typedef struct { static DICT_OPEN_INFO dict_open_info[] = { "environ", dict_env_open, "unix", dict_unix_open, + "tcp", dict_tcp_open, #ifdef HAS_DBM "dbm", dict_dbm_open, #endif @@ -318,6 +320,7 @@ ARGV *dict_mapnames() #include #include #include +#include /* Utility library. */ @@ -343,6 +346,8 @@ main(int argc, char **argv) const char *value; int ch; + signal(SIGPIPE, SIG_IGN); + msg_vstream_init(argv[0], VSTREAM_ERR); while ((ch = GETOPT(argc, argv, "v")) > 0) { switch (ch) { @@ -380,7 +385,9 @@ main(int argc, char **argv) vstream_printf("%s: deleted\n", key); } else if (strcmp(cmd, "get") == 0 && key && !value) { if ((value = dict_get(dict, key)) == 0) { - vstream_printf("%s: not found\n", key); + vstream_printf("%s: %s\n", key, + dict_errno == DICT_ERR_RETRY ? + "soft error" : "not found"); } else { vstream_printf("%s=%s\n", key, value); } @@ -388,7 +395,7 @@ main(int argc, char **argv) dict_put(dict, key, value); vstream_printf("%s=%s\n", key, value); } else { - vstream_printf("usage: del key|get key|put key=value"); + vstream_printf("usage: del key|get key|put key=value\n"); } vstream_fflush(VSTREAM_OUT); } diff --git a/postfix/util/dict_tcp.c b/postfix/util/dict_tcp.c new file mode 100644 index 000000000..1cb4b1504 --- /dev/null +++ b/postfix/util/dict_tcp.c @@ -0,0 +1,191 @@ +/*++ +/* NAME +/* dict_tcp 3 +/* SUMMARY +/* dictionary manager interface to tcp-based lookup tables +/* SYNOPSIS +/* #include +/* +/* DICT *dict_tcp_open(map, dummy, dict_flags) +/* const char *map; +/* int dummy; +/* int dict_flags; +/* DESCRIPTION +/* dict_tcp_open() makes a TCP server accessible via the generic +/* dictionary operations described in dict_open(3). +/* The \fIdummy\fR argument is not used. Server access is read-only +/* (i.e., only lookups are implemented). +/* +/* Map names have the form host:port. +/* +/* The map implements a very simple protocol: the query is sent as +/* one line of text, and the reply is sent back in the same format. +/* Data is sent as a newline-terminated string. % and non-printable +/* characters are replaced by %xx, xx being the corresponding +/* hexadecimal value. +/* SEE ALSO +/* dict(3) generic dictionary manager +/* DIAGNOSTICS +/* Fatal errors: out of memory, unknown host or service name, +/* attempt to update map. +/* 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" +#include +#include +#include + +/* Utility library. */ + +#include "msg.h" +#include "mymalloc.h" +#include "vstring.h" +#include "vstream.h" +#include "vstring_vstream.h" +#include "connect.h" +#include "hex_quote.h" +#include "dict.h" +#include "dict_tcp.h" + +/* Application-specific. */ + +typedef struct { + DICT dict; /* generic members */ + char *map; /* server host:port */ + VSTRING *raw_buf; /* raw buffer */ + VSTRING *hex_buf; /* hexified buffer */ + VSTREAM *fp; /* I/O stream */ +} DICT_TCP; + +#define DICT_TCP_MAXTRY 10 +#define DICT_TCP_TMOUT 100 + +#define STR(x) vstring_str(x) + +/* dict_tcp_lookup - query TCP server */ + +static const char *dict_tcp_lookup(DICT *dict, const char *key) +{ + DICT_TCP *dict_tcp = (DICT_TCP *) dict; + int fd; + int i; + + dict_errno = 0; + + for (i = 0; /* see below */ ; i++) { + + /* + * Try to connect a few times before giving up. + */ + if (i >= DICT_TCP_MAXTRY) { + dict_errno = DICT_ERR_RETRY; + return (0); + } + + /* + * Sleep between connection attempts. + */ + if (i > 0) + sleep(1); + + /* + * Try to connect to the server. + */ + if (dict_tcp->fp == 0) { + if ((fd = inet_connect(dict_tcp->map, BLOCKING, 0)) < 0) { + msg_warn("connect to TCP map %s: %m", dict_tcp->map); + continue; + } + dict_tcp->fp = vstream_fdopen(fd, O_RDWR); + vstream_control(dict_tcp->fp, + VSTREAM_CTL_TIMEOUT, DICT_TCP_TMOUT, + VSTREAM_CTL_END); + } + + /* + * Allocate per-map buffers on the fly. + */ + if (dict_tcp->raw_buf == 0) { + dict_tcp->raw_buf = vstring_alloc(10); + dict_tcp->hex_buf = vstring_alloc(10); + } + + /* + * Send query and receive response. Both are %XX quoted and both are + * terminated by newline. + */ + hex_quote(dict_tcp->hex_buf, key); + vstream_fprintf(dict_tcp->fp, "%s\n", STR(dict_tcp->hex_buf)); + errno = 0; + if (vstring_get_nonl(dict_tcp->hex_buf, dict_tcp->fp) == VSTREAM_EOF) { + msg_warn("read TCP map reply from %s: %m", dict_tcp->map); + } else if (!hex_unquote(dict_tcp->raw_buf, STR(dict_tcp->hex_buf))) { + msg_warn("read TCP map reply from %s: malformed reply %.100s", + dict_tcp->map, STR(dict_tcp->hex_buf)); + } else { + return (STR(dict_tcp->raw_buf)); + } + + /* + * That did not work. Clean up and try again. + */ + (void) vstream_fclose(dict_tcp->fp); + dict_tcp->fp = 0; + } +} + +/* dict_tcp_update - add or update table entry */ + +static void dict_tcp_update(DICT *dict, const char *unused_name, const char *unused_value) +{ + DICT_TCP *dict_tcp = (DICT_TCP *) dict; + + msg_fatal("dict_tcp_update: attempt to update map %s", dict_tcp->map); +} + +/* dict_tcp_close - close TCP map */ + +static void dict_tcp_close(DICT *dict) +{ + DICT_TCP *dict_tcp = (DICT_TCP *) dict; + + if (dict_tcp->fp) + (void) vstream_fclose(dict_tcp->fp); + if (dict_tcp->raw_buf) + vstring_free(dict_tcp->raw_buf); + if (dict_tcp->hex_buf) + vstring_free(dict_tcp->hex_buf); + myfree(dict_tcp->map); + myfree((char *) dict_tcp); +} + +/* dict_tcp_open - open TCP map */ + +DICT *dict_tcp_open(const char *map, int unused_flags, int dict_flags) +{ + DICT_TCP *dict_tcp; + + dict_errno = 0; + + dict_tcp = (DICT_TCP *) mymalloc(sizeof(*dict_tcp)); + dict_tcp->fp = 0; + dict_tcp->raw_buf = dict_tcp->hex_buf = 0; + dict_tcp->dict.lookup = dict_tcp_lookup; + dict_tcp->dict.update = dict_tcp_update; + dict_tcp->dict.close = dict_tcp_close; + dict_tcp->dict.fd = -1; + dict_tcp->map = mystrdup(map); + dict_tcp->dict.flags = dict_flags | DICT_FLAG_FIXED; + return (&dict_tcp->dict); +} diff --git a/postfix/util/dict_tcp.h b/postfix/util/dict_tcp.h new file mode 100644 index 000000000..4b31edad6 --- /dev/null +++ b/postfix/util/dict_tcp.h @@ -0,0 +1,35 @@ +#ifndef _DICT_TCP_H_INCLUDED_ +#define _DICT_TCP_H_INCLUDED_ + +/*++ +/* NAME +/* dict_tcp 3h +/* SUMMARY +/* dictionary manager interface to tcp-based lookup tables +/* SYNOPSIS +/* #include +/* DESCRIPTION +/* .nf + + /* + * Utility library. + */ +#include + + /* + * External interface. + */ +extern DICT *dict_tcp_open(const char *, int, int); + +/* 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 +/*--*/ + +#endif diff --git a/postfix/util/hex_quote.c b/postfix/util/hex_quote.c new file mode 100644 index 000000000..4ed0e73e0 --- /dev/null +++ b/postfix/util/hex_quote.c @@ -0,0 +1,148 @@ +/*++ +/* NAME +/* hex_quote 3 +/* SUMMARY +/* quote/unquote text, HTTP style. +/* SYNOPSIS +/* #include +/* +/* VSTRING *hex_quote(hex, raw) +/* VSTRING *hex; +/* const char *raw; +/* +/* VSTRING *hex_unquote(raw, hex) +/* VSTRING *raw; +/* const char *hex; +/* DESCRIPTION +/* hex_quote() takes a null-terminated string and replaces non-printable +/* characters and % by %XX, XX being the two-digit hexadecimal equivalent. +/* The hexadecimal codes are produced as upper-case characters. The result +/* value is the hex argument. +/* +/* hex_unquote() performs the opposite transformation. This function +/* understands lowercase and uppercase %XX sequences. The result +/* value is the raw argument in case of success, a null pointer otherwise. +/* BUGS +/* Cannot process null characters. +/* 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" +#include + +/* Utility library. */ + +#include "msg.h" +#include "vstring.h" +#include "hex_quote.h" + +/* Application-specific. */ + +#define STR(x) vstring_str(x) +#define LEN(x) VSTRING_LEN(x) + +/* hex_quote - raw data to quoted */ + +VSTRING *hex_quote(VSTRING *hex, const char *raw) +{ + const char *cp; + int ch; + + VSTRING_RESET(hex); + for (cp = raw; (ch = *(unsigned const char *) cp) != 0; cp++) { + if (ch != '%' && ISPRINT(ch)) { + VSTRING_ADDCH(hex, ch); + } else { + vstring_sprintf_append(hex, "%%%02X", ch); + } + } + VSTRING_TERMINATE(hex); + return (hex); +} + +/* hex_unquote - quoted data to raw */ + +VSTRING *hex_unquote(VSTRING *raw, const char *hex) +{ + const char *cp; + int ch; + + VSTRING_RESET(raw); + for (cp = hex; (ch = *cp) != 0; cp++) { + if (ch == '%') { + if (ISDIGIT(cp[1])) + ch = (cp[1] - '0') << 4; + else if (cp[1] >= 'a' && cp[1] <= 'f') + ch = (cp[1] - 'a' + 10) << 4; + else if (cp[1] >= 'A' && cp[1] <= 'F') + ch = (cp[1] - 'A' + 10) << 4; + else + return (0); + if (ISDIGIT(cp[2])) + ch |= (cp[2] - '0'); + else if (cp[2] >= 'a' && cp[2] <= 'f') + ch |= (cp[2] - 'a' + 10); + else if (cp[2] >= 'A' && cp[2] <= 'F') + ch |= (cp[2] - 'A' + 10); + else + return (0); + cp += 2; + } + VSTRING_ADDCH(raw, ch); + } + VSTRING_TERMINATE(raw); + return (raw); +} + +#ifdef TEST + + /* + * Proof-of-concept test program: convert to hex and back. + */ +#include + +#define BUFLEN 1024 + +static int read_buf(VSTREAM *fp, VSTRING *buf) +{ + int len; + + VSTRING_RESET(buf); + len = vstream_fread(fp, STR(buf), vstring_avail(buf)); + VSTRING_AT_OFFSET(buf, len); /* XXX */ + VSTRING_TERMINATE(buf); + return (len); +} + +main(int unused_argc, char **unused_argv) +{ + VSTRING *raw = vstring_alloc(BUFLEN); + VSTRING *hex = vstring_alloc(100); + int len; + + while ((len = read_buf(VSTREAM_IN, raw)) > 0) { + hex_quote(hex, STR(raw)); + if (hex_unquote(raw, STR(hex)) == 0) + msg_fatal("bad input: %.100s", STR(hex)); + if (LEN(raw) != len) + msg_fatal("len %d != raw len %d", len, LEN(raw)); + if (vstream_fwrite(VSTREAM_OUT, STR(raw), LEN(raw)) != LEN(raw)) + msg_fatal("write error: %m"); + } + vstream_fflush(VSTREAM_OUT); + vstring_free(raw); + vstring_free(hex); + return (0); +} + +#endif diff --git a/postfix/util/hex_quote.h b/postfix/util/hex_quote.h new file mode 100644 index 000000000..d72ec5719 --- /dev/null +++ b/postfix/util/hex_quote.h @@ -0,0 +1,36 @@ +#ifndef _HEX_QUOTE_H_INCLUDED_ +#define _HEX_QUOTE_H_INCLUDED_ + +/*++ +/* NAME +/* hex_quote 3h +/* SUMMARY +/* quote/unquote text, HTTP style. +/* SYNOPSIS +/* #include +/* DESCRIPTION +/* .nf + + /* + * Utility library. + */ +#include + + /* + * External interface. + */ +extern VSTRING *hex_quote(VSTRING *, const char *); +extern VSTRING *hex_unquote(VSTRING *, const char *); + +/* 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 +/*--*/ + +#endif diff --git a/postfix/util/sys_defs.h b/postfix/util/sys_defs.h index 2a4f73aba..99e8762b3 100644 --- a/postfix/util/sys_defs.h +++ b/postfix/util/sys_defs.h @@ -825,7 +825,7 @@ typedef int pid_t; #if __GNUC__ == 2 && __GNUC_MINOR__ >= 7 #define PRINTFLIKE(x,y) __attribute__ ((format (printf, (x), (y)))) #else -#define PRINTFLIKE +#define PRINTFLIKE(x,y) #endif #endif