From: Wietse Venema Date: Sun, 13 Mar 2011 05:00:00 +0000 (-0500) Subject: postfix-2.9-20110313 X-Git-Tag: v2.9.0-RC1~50 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d582a9bb31a9db8b6c5a48d8414f7437ea1ab397;p=thirdparty%2Fpostfix.git postfix-2.9-20110313 --- diff --git a/postfix/HISTORY b/postfix/HISTORY index 315897483..0e388c942 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -16685,3 +16685,19 @@ Apologies for any names omitted. src/global/dict_ldap.c src/global/cfg_parser.h src/global/cfg_parser.c. +20110311 + + Feature: Base 32 encoder/decoder per RFC 4648. This code + was going to be used for long queue IDs, but plans were + changed. Files: src/util/base32_code.[hc]. + +20110313 + + Bugfix (introduced Postfix 2.8): number the postscreen DNSBL + requests, so that delayed results for an old session are + not added to the score when the same remote SMTP client has + reconnected in the mean time. Files: postscreen/postscreen_dnsbl.c, + dnsblog/dnsblog.c. + + Cleanup: protocol description in dnsblog(8) manpage. File: + dnsblog/dnsblog.c. diff --git a/postfix/RELEASE_NOTES b/postfix/RELEASE_NOTES index a09f1519b..01d988efb 100644 --- a/postfix/RELEASE_NOTES +++ b/postfix/RELEASE_NOTES @@ -14,6 +14,25 @@ specifies the release date of a stable release or snapshot release. If you upgrade from Postfix 2.7 or earlier, read RELEASE_NOTES-2.8 before proceeding. +Incompatible changes with snapshot 20110313 +=========================================== + +Use "postfix reload" after "make upgrade" on a running Postfix +system. This is needed because the protocol between postscreen(8) +and dnsblog(8) has changed. + +Major changes with snapshot 20110228 +==================================== + +postscreen(8) support to force remote SMTP clients to implement +proper MX lookup policy. By listening on both primary and backup +MX addresses, postscreen(8) can deny the temporary whitelist status +to clients that connect only to backup MX hosts, and prevent them +from talking to a Postfix SMTP server process. + +Example: when 1.2.3.4 is a local backup IP address, specify +"postscreen_whitelist_interfaces = !1.2.3.4 static:all". + Incompatible changes with snapshot 20110219 =========================================== diff --git a/postfix/WISHLIST b/postfix/WISHLIST index 1098f4190..fa63f559d 100644 --- a/postfix/WISHLIST +++ b/postfix/WISHLIST @@ -11,6 +11,15 @@ Wish list: Don't forget Apple's code donation for fetching mail from IMAP server. + Use queue ID (file name) based on inode number and enough + (time or random) bits to avoid repetition in 10+ years. + + Simplify postscreen logic: set the noforward flag if the + client made an unforgivable error. Individual "fail" flags + are needed only to avoid logging the same offense multiple + times. Individual "pass" flags are still needed as proof + that the client didn't skip tests by hanging up early. + postconf command-line option to show the compile-time settings (CCARGS, AUXLIBS) in case binary packages don't install the makedefs.out file. diff --git a/postfix/html/dnsblog.8.html b/postfix/html/dnsblog.8.html index 85de63982..84ff7371e 100644 --- a/postfix/html/dnsblog.8.html +++ b/postfix/html/dnsblog.8.html @@ -20,35 +20,36 @@ DNSBLOG(8) DNSBLOG(8) PROTOCOL With each connection, the dnsblog(8) server receives a DNS - white/blacklist domain name and an IP address. If the - address is listed under the DNS white/blacklist, the dns- - blog(8) server logs the match and replies with the query - arguments plus a non-zero status. Otherwise it replies - with the query arguments plus a zero status. Finally, The - dnsblog(8) server closes the connection. + white/blacklist domain name, IP address, and an ID. If + the address is listed under the DNS white/blacklist, the + dnsblog(8) server logs the match and replies with the + query arguments plus an address list with the resulting IP + addresses separated by whitespace. Otherwise it replies + with the query arguments plus an empty address list. + Finally, The dnsblog(8) server closes the connection. DIAGNOSTICS Problems and transactions are logged to syslogd(8). CONFIGURATION PARAMETERS - Changes to main.cf are picked up automatically, as dns- - blog(8) processes run for only a limited amount of time. + Changes to main.cf are picked up automatically, as dns- + blog(8) processes run for only a limited amount of time. Use the command "postfix reload" to speed up a change. - The text below provides only a parameter summary. See + The text below provides only a parameter summary. See postconf(5) for more details including examples. config_directory (see 'postconf -d' output) - The default location of the Postfix main.cf and + The default location of the Postfix main.cf and master.cf configuration files. daemon_timeout (18000s) - How much time a Postfix daemon process may take to - handle a request before it is terminated by a + How much time a Postfix daemon process may take to + handle a request before it is terminated by a built-in watchdog timer. postscreen_dnsbl_sites (empty) - Optional list of DNS white/blacklist domains, fil- + Optional list of DNS white/blacklist domains, fil- ters and weight factors. ipc_timeout (3600s) @@ -56,23 +57,23 @@ DNSBLOG(8) DNSBLOG(8) over an internal communication channel. process_id (read-only) - The process ID of a Postfix command or daemon + The process ID of a Postfix command or daemon process. process_name (read-only) - The process name of a Postfix command or daemon + The process name of a Postfix command or daemon process. queue_directory (see 'postconf -d' output) - The location of the Postfix top-level queue direc- + The location of the Postfix top-level queue direc- tory. syslog_facility (mail) The syslog facility of Postfix logging. syslog_name (see 'postconf -d' output) - The mail system name that is prepended to the - process name in syslog records, so that "smtpd" + The mail system name that is prepended to the + process name in syslog records, so that "smtpd" becomes, for example, "postfix/smtpd". SEE ALSO @@ -81,7 +82,7 @@ DNSBLOG(8) DNSBLOG(8) syslogd(5), system logging LICENSE - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. HISTORY diff --git a/postfix/makedefs b/postfix/makedefs index 7432cdbdf..282eabcd4 100644 --- a/postfix/makedefs +++ b/postfix/makedefs @@ -228,6 +228,12 @@ case "$SYSTEM.$RELEASE" in done ;; AIX.*) case "`uname -v`" in + 6) SYSTYPE=AIX6 + case "$CC" in + cc|*/cc|xlc|*/xlc) CCARGS="$CCARGS -w -blibpath:/usr/lib:/lib:/usr/local/lib";; + esac + CCARGS="$CCARGS -D_ALL_SOURCE -DHAS_POSIX_REGEXP" + ;; 5) SYSTYPE=AIX5 case "$CC" in cc|*/cc|xlc|*/xlc) CCARGS="$CCARGS -w -blibpath:/usr/lib:/lib:/usr/local/lib";; diff --git a/postfix/man/man8/dnsblog.8 b/postfix/man/man8/dnsblog.8 index ca6660d8e..5f485051b 100644 --- a/postfix/man/man8/dnsblog.8 +++ b/postfix/man/man8/dnsblog.8 @@ -22,12 +22,13 @@ replaced by an UDP client that is built directly into the .ad .fi With each connection, the \fBdnsblog\fR(8) server receives -a DNS white/blacklist domain name and an IP address. If the -address is listed under the DNS white/blacklist, the +a DNS white/blacklist domain name, IP address, and an ID. +If the address is listed under the DNS white/blacklist, the \fBdnsblog\fR(8) server logs the match and replies with the -query arguments plus a non-zero status. Otherwise it replies -with the query arguments plus a zero status. Finally, The -\fBdnsblog\fR(8) server closes the connection. +query arguments plus an address list with the resulting IP +addresses separated by whitespace. Otherwise it replies +with the query arguments plus an empty address list. Finally, +The \fBdnsblog\fR(8) server closes the connection. .SH DIAGNOSTICS .ad .fi diff --git a/postfix/src/dnsblog/dnsblog.c b/postfix/src/dnsblog/dnsblog.c index 89d1f0df7..977a68347 100644 --- a/postfix/src/dnsblog/dnsblog.c +++ b/postfix/src/dnsblog/dnsblog.c @@ -14,12 +14,13 @@ /* .ad /* .fi /* With each connection, the \fBdnsblog\fR(8) server receives -/* a DNS white/blacklist domain name and an IP address. If the -/* address is listed under the DNS white/blacklist, the +/* a DNS white/blacklist domain name, IP address, and an ID. +/* If the address is listed under the DNS white/blacklist, the /* \fBdnsblog\fR(8) server logs the match and replies with the -/* query arguments plus a non-zero status. Otherwise it replies -/* with the query arguments plus a zero status. Finally, The -/* \fBdnsblog\fR(8) server closes the connection. +/* query arguments plus an address list with the resulting IP +/* addresses separated by whitespace. Otherwise it replies +/* with the query arguments plus an empty address list. Finally, +/* The \fBdnsblog\fR(8) server closes the connection. /* DIAGNOSTICS /* Problems and transactions are logged to \fBsyslogd\fR(8). /* CONFIGURATION PARAMETERS @@ -215,6 +216,7 @@ static VSTRING *dnsblog_query(VSTRING *result, const char *dnsbl_domain, static void dnsblog_service(VSTREAM *client_stream, char *unused_service, char **argv) { + int request_id; /* * Sanity check. This service takes no command-line arguments. @@ -231,13 +233,15 @@ static void dnsblog_service(VSTREAM *client_stream, char *unused_service, ATTR_FLAG_MORE | ATTR_FLAG_STRICT, ATTR_TYPE_STR, MAIL_ATTR_RBL_DOMAIN, rbl_domain, ATTR_TYPE_STR, MAIL_ATTR_ACT_CLIENT_ADDR, addr, - ATTR_TYPE_END) == 2) { + ATTR_TYPE_INT, MAIL_ATTR_LABEL, &request_id, + ATTR_TYPE_END) == 3) { (void) dnsblog_query(result, STR(rbl_domain), STR(addr)); if (var_dnsblog_delay > 0) sleep(var_dnsblog_delay); attr_print(client_stream, ATTR_FLAG_NONE, ATTR_TYPE_STR, MAIL_ATTR_RBL_DOMAIN, STR(rbl_domain), ATTR_TYPE_STR, MAIL_ATTR_ACT_CLIENT_ADDR, STR(addr), + ATTR_TYPE_INT, MAIL_ATTR_LABEL, request_id, ATTR_TYPE_STR, MAIL_ATTR_RBL_ADDR, STR(result), ATTR_TYPE_END); vstream_fflush(client_stream); diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 782fff818..b6924097d 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -20,7 +20,7 @@ * Patches change both the patchlevel and the release date. Snapshots have no * patchlevel; they change the release date only. */ -#define MAIL_RELEASE_DATE "20110228" +#define MAIL_RELEASE_DATE "20110313" #define MAIL_VERSION_NUMBER "2.9" #ifdef SNAPSHOT diff --git a/postfix/src/postscreen/postscreen_dnsbl.c b/postfix/src/postscreen/postscreen_dnsbl.c index f21b04efd..a57f20ef4 100644 --- a/postfix/src/postscreen/postscreen_dnsbl.c +++ b/postfix/src/postscreen/postscreen_dnsbl.c @@ -143,6 +143,7 @@ typedef struct { int total; /* combined blocklist score */ int refcount; /* score reference count */ int pending_lookups; /* nr of DNS requests in flight */ + int request_id; /* duplicate suppression */ /* Call-back table support. */ int index; /* next table index */ int limit; /* last valid index */ @@ -344,6 +345,7 @@ static void psc_dnsbl_receive(int event, char *context) PSC_DNSBL_HEAD *head; PSC_DNSBL_SITE *site; ARGV *reply_argv; + int request_id; PSC_CLEAR_EVENT_REQUEST(vstream_fileno(stream), psc_dnsbl_receive, context); @@ -367,10 +369,12 @@ static void psc_dnsbl_receive(int event, char *context) ATTR_FLAG_STRICT, ATTR_TYPE_STR, MAIL_ATTR_RBL_DOMAIN, reply_dnsbl, ATTR_TYPE_STR, MAIL_ATTR_ACT_CLIENT_ADDR, reply_client, + ATTR_TYPE_INT, MAIL_ATTR_LABEL, &request_id, ATTR_TYPE_STR, MAIL_ATTR_RBL_ADDR, reply_addr, - ATTR_TYPE_END) == 3 + ATTR_TYPE_END) == 4 && (score = (PSC_DNSBL_SCORE *) - htable_find(dnsbl_score_cache, STR(reply_client))) != 0) { + htable_find(dnsbl_score_cache, STR(reply_client))) != 0 + && score->request_id == request_id) { /* * Run this response past all applicable DNSBL filters and update the @@ -429,6 +433,7 @@ int psc_dnsbl_request(const char *client_addr, HTABLE_INFO **ht; PSC_DNSBL_SCORE *score; HTABLE_INFO *hash_node; + static int request_count; /* * Some spambots make several connections at nearly the same time, @@ -468,6 +473,7 @@ int psc_dnsbl_request(const char *client_addr, if (msg_verbose > 1) msg_info("%s: create blocklist score for %s", myname, client_addr); score = (PSC_DNSBL_SCORE *) mymalloc(sizeof(*score)); + score->request_id = request_count++; score->dnsbl = 0; score->total = 0; score->refcount = 1; @@ -492,6 +498,7 @@ int psc_dnsbl_request(const char *client_addr, attr_print(stream, ATTR_FLAG_NONE, ATTR_TYPE_STR, MAIL_ATTR_RBL_DOMAIN, ht[0]->key, ATTR_TYPE_STR, MAIL_ATTR_ACT_CLIENT_ADDR, client_addr, + ATTR_TYPE_INT, MAIL_ATTR_LABEL, score->request_id, ATTR_TYPE_END); if (vstream_fflush(stream) != 0) { msg_warn("%s: error sending to %s service: %m", diff --git a/postfix/src/util/Makefile.in b/postfix/src/util/Makefile.in index 4455fbf20..d28d1aaac 100644 --- a/postfix/src/util/Makefile.in +++ b/postfix/src/util/Makefile.in @@ -33,7 +33,7 @@ SRCS = alldig.c allprint.c argv.c argv_split.c attr_clnt.c attr_print0.c \ allascii.c load_file.c killme_after.c vstream_tweak.c \ unix_pass_listen.c unix_pass_trigger.c edit_file.c inet_windowsize.c \ unix_pass_fd_fix.c dict_cache.c valid_utf_8.c dict_thash.c \ - ip_match.c nbbio.c stream_pass_connect.c + ip_match.c nbbio.c stream_pass_connect.c base32_code.c OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \ attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \ attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \ @@ -68,7 +68,7 @@ OBJS = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \ allascii.o load_file.o killme_after.o vstream_tweak.o \ unix_pass_listen.o unix_pass_trigger.o edit_file.o inet_windowsize.o \ unix_pass_fd_fix.o dict_cache.o valid_utf_8.o dict_thash.o \ - ip_match.o nbbio.o stream_pass_connect.o + ip_match.o nbbio.o stream_pass_connect.o base32_code.o HDRS = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \ chroot_uid.h cidr_match.h clean_env.h connect.h ctable.h dict.h \ dict_cdb.h dict_cidr.h dict_db.h dict_dbm.h dict_env.h dict_ht.h \ @@ -89,7 +89,7 @@ HDRS = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \ username.h valid_hostname.h vbuf.h vbuf_print.h vstream.h vstring.h \ vstring_vstream.h watchdog.h format_tv.h load_file.h killme_after.h \ edit_file.h dict_cache.h dict_thash.h \ - ip_match.h nbbio.h + ip_match.h nbbio.h base32_code.h TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \ stream_test.c dup2_pass_on_exec.c DEFS = -I. -D$(SYSTYPE) @@ -107,7 +107,7 @@ TESTPROG= dict_open dup2_pass_on_exec events exec_command fifo_open \ attr_scan0 host_port attr_scan_plain attr_print_plain htable \ unix_recv_fd unix_send_fd stream_recv_fd stream_send_fd hex_code \ myaddrinfo myaddrinfo4 inet_proto sane_basename format_tv \ - valid_utf_8 ip_match + valid_utf_8 ip_match base32_code LIB_DIR = ../../lib INC_DIR = ../../include @@ -427,11 +427,17 @@ ip_match: $(LIB) $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) mv junk $@.o +base32_code: $(LIB) + mv $@.o junk + $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS) + mv junk $@.o + tests: valid_hostname_test mac_expand_test dict_test unescape_test \ hex_quote_test ctable_test inet_addr_list_test base64_code_test \ attr_scan64_test attr_scan0_test dict_pcre_test host_port_test \ dict_cidr_test attr_scan_plain_test htable_test hex_code_test \ - myaddrinfo_test format_tv_test ip_match_test name_mask_tests + myaddrinfo_test format_tv_test ip_match_test name_mask_tests \ + base32_code_test root_tests: @@ -612,6 +618,9 @@ name_mask_test9: name_mask name_mask.in name_mask.ref9 diff name_mask.ref9 name_mask.tmp rm -f name_mask.tmp +base32_code_test: base32_code + ./base32_code + depend: $(MAKES) (sed '1,/^# do not edit/!d' Makefile.in; \ set -e; for i in [a-z][a-z0-9]*.c; do \ diff --git a/postfix/src/util/base32_code.c b/postfix/src/util/base32_code.c new file mode 100644 index 000000000..8de8391e5 --- /dev/null +++ b/postfix/src/util/base32_code.c @@ -0,0 +1,266 @@ +/*++ +/* NAME +/* base32_code 3 +/* SUMMARY +/* encode/decode data, base 32 style +/* SYNOPSIS +/* #include +/* +/* VSTRING *base32_encode(result, in, len) +/* VSTRING *result; +/* const char *in; +/* ssize_t len; +/* +/* VSTRING *base32_decode(result, in, len) +/* VSTRING *result; +/* const char *in; +/* ssize_t len; +/* DESCRIPTION +/* base32_encode() takes a block of len bytes and encodes it as one +/* null-terminated string. The result value is the result argument. +/* +/* base32_decode() performs the opposite transformation. The result +/* value is the result argument. The result is null terminated, whether +/* or not that makes sense. +/* DIAGNOSTICS +/* base32_decode() returns a null pointer when the input contains +/* characters not in the base 32 alphabet. +/* SEE ALSO +/* RFC 4648; padding is strictly enforced +/* 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 + +#ifndef UCHAR_MAX +#define UCHAR_MAX 0xff +#endif + +/* Utility library. */ + +#include +#include +#include +#include + +/* Application-specific. */ + +static unsigned char to_b32[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; + +#define UNSIG_CHAR_PTR(x) ((unsigned char *)(x)) + +/* base32_encode - raw data to encoded */ + +VSTRING *base32_encode(VSTRING *result, const char *in, ssize_t len) +{ + const unsigned char *cp; + ssize_t count; + static int pad_count[] = {0, 6, 4, 3, 1}; + + /* + * Encode 5 -> 8. + */ + VSTRING_RESET(result); + for (cp = UNSIG_CHAR_PTR(in), count = len; count > 0; count -= 5, cp += 5) { + VSTRING_ADDCH(result, to_b32[cp[0] >> 3]); + if (count < 2) { + VSTRING_ADDCH(result, to_b32[(cp[0] & 0x7) << 2]); + break; + } + VSTRING_ADDCH(result, to_b32[(cp[0] & 0x7) << 2 | cp[1] >> 6]); + VSTRING_ADDCH(result, to_b32[(cp[1] & 0x3f) >> 1]); + if (count < 3) { + VSTRING_ADDCH(result, to_b32[(cp[1] & 0x1) << 4]); + break; + } + VSTRING_ADDCH(result, to_b32[(cp[1] & 0x1) << 4 | cp[2] >> 4]); + if (count < 4) { + VSTRING_ADDCH(result, to_b32[(cp[2] & 0xf) << 1]); + break; + } + VSTRING_ADDCH(result, to_b32[(cp[2] & 0xf) << 1 | cp[3] >> 7]); + VSTRING_ADDCH(result, to_b32[(cp[3] & 0x7f) >> 2]); + if (count < 5) { + VSTRING_ADDCH(result, to_b32[(cp[3] & 0x3) << 3]); + break; + } + VSTRING_ADDCH(result, to_b32[(cp[3] & 0x3) << 3 | cp[4] >> 5]); + VSTRING_ADDCH(result, to_b32[cp[4] & 0x1f]); + } + if (count > 0) + vstring_strncat(result, "======", pad_count[count]); + VSTRING_TERMINATE(result); + return (result); +} + +/* base32_decode - encoded data to raw */ + +VSTRING *base32_decode(VSTRING *result, const char *in, ssize_t len) +{ + static unsigned char *un_b32 = 0; + const unsigned char *cp; + ssize_t count; + unsigned int ch0; + unsigned int ch1; + unsigned int ch2; + unsigned int ch3; + unsigned int ch4; + unsigned int ch5; + unsigned int ch6; + unsigned int ch7; + +#define CHARS_PER_BYTE (UCHAR_MAX + 1) +#define INVALID 0xff +#if 1 +#define ENFORCE_LENGTH(x) (x) +#define ENFORCE_PADDING(x) (x) +#define ENFORCE_NULL_BITS(x) (x) +#else +#define ENFORCE_LENGTH(x) (1) +#define ENFORCE_PADDING(x) (1) +#define ENFORCE_NULL_BITS(x) (1) +#endif + + /* + * Sanity check. + */ + if (ENFORCE_LENGTH(len % 8)) + return (0); + + /* + * Once: initialize the decoding lookup table on the fly. + */ + if (un_b32 == 0) { + un_b32 = (unsigned char *) mymalloc(CHARS_PER_BYTE); + memset(un_b32, INVALID, CHARS_PER_BYTE); + for (cp = to_b32; cp < to_b32 + sizeof(to_b32); cp++) + un_b32[*cp] = cp - to_b32; + } + + /* + * Decode 8 -> 5. + */ + VSTRING_RESET(result); + for (cp = UNSIG_CHAR_PTR(in), count = 0; count < len; count += 8) { + if ((ch0 = un_b32[*cp++]) == INVALID + || (ch1 = un_b32[*cp++]) == INVALID) + return (0); + VSTRING_ADDCH(result, ch0 << 3 | ch1 >> 2); + if ((ch2 = *cp++) == '=' + && ENFORCE_PADDING(strcmp((char *) cp, "=====") == 0) + && ENFORCE_NULL_BITS((ch1 & 0x3) == 0)) + break; + if ((ch2 = un_b32[ch2]) == INVALID) + return (0); + if ((ch3 = un_b32[*cp++]) == INVALID) + return (0); + VSTRING_ADDCH(result, ch1 << 6 | ch2 << 1 | ch3 >> 4); + if ((ch4 = *cp++) == '=' + && ENFORCE_PADDING(strcmp((char *) cp, "===") == 0) + && ENFORCE_NULL_BITS((ch3 & 0xf) == 0)) + break; + if ((ch4 = un_b32[ch4]) == INVALID) + return (0); + VSTRING_ADDCH(result, ch3 << 4 | ch4 >> 1); + if ((ch5 = *cp++) == '=' + && ENFORCE_PADDING(strcmp((char *) cp, "==") == 0) + && ENFORCE_NULL_BITS((ch4 & 0x1) == 0)) + break; + if ((ch5 = un_b32[ch5]) == INVALID) + return (0); + if ((ch6 = un_b32[*cp++]) == INVALID) + return (0); + VSTRING_ADDCH(result, ch4 << 7 | ch5 << 2 | ch6 >> 3); + if ((ch7 = *cp++) == '=' + && ENFORCE_NULL_BITS((ch6 & 0x7) == 0)) + break; + if ((ch7 = un_b32[ch7]) == INVALID) + return (0); + VSTRING_ADDCH(result, ch6 << 5 | ch7); + } + VSTRING_TERMINATE(result); + return (result); +} + +#ifdef TEST + + /* + * Proof-of-concept test program: convert to base 32 and back. + */ + +#define STR(x) vstring_str(x) +#define LEN(x) VSTRING_LEN(x) + +int main(int unused_argc, char **unused_argv) +{ + VSTRING *b1 = vstring_alloc(1); + VSTRING *b2 = vstring_alloc(1); + VSTRING *test = vstring_alloc(1); + int i, j; + + /* + * Test all byte values (except null) on all byte positions. + */ + for (j = 0; j < 256; j++) + for (i = 1; i < 256; i++) + VSTRING_ADDCH(test, i); + VSTRING_TERMINATE(test); + +#define DECODE(b,x,l) { \ + if (base32_decode((b),(x),(l)) == 0) \ + msg_panic("bad base32: %s", (x)); \ + } +#define VERIFY(b,t,l) { \ + if (memcmp((b), (t), (l)) != 0) \ + msg_panic("bad test: %s", (b)); \ + } + + /* + * Test all padding variants. + */ + for (i = 1; i <= 8; i++) { + base32_encode(b1, STR(test), LEN(test)); + DECODE(b2, STR(b1), LEN(b1)); + VERIFY(STR(b2), STR(test), LEN(test)); + + base32_encode(b1, STR(test), LEN(test)); + base32_encode(b2, STR(b1), LEN(b1)); + base32_encode(b1, STR(b2), LEN(b2)); + DECODE(b2, STR(b1), LEN(b1)); + DECODE(b1, STR(b2), LEN(b2)); + DECODE(b2, STR(b1), LEN(b1)); + VERIFY(STR(b2), STR(test), LEN(test)); + + base32_encode(b1, STR(test), LEN(test)); + base32_encode(b2, STR(b1), LEN(b1)); + base32_encode(b1, STR(b2), LEN(b2)); + base32_encode(b2, STR(b1), LEN(b1)); + base32_encode(b1, STR(b2), LEN(b2)); + DECODE(b2, STR(b1), LEN(b1)); + DECODE(b1, STR(b2), LEN(b2)); + DECODE(b2, STR(b1), LEN(b1)); + DECODE(b1, STR(b2), LEN(b2)); + DECODE(b2, STR(b1), LEN(b1)); + VERIFY(STR(b2), STR(test), LEN(test)); + vstring_truncate(test, LEN(test) - 1); + } + vstring_free(test); + vstring_free(b1); + vstring_free(b2); + return (0); +} + +#endif diff --git a/postfix/src/util/base32_code.h b/postfix/src/util/base32_code.h new file mode 100644 index 000000000..56906f44c --- /dev/null +++ b/postfix/src/util/base32_code.h @@ -0,0 +1,36 @@ +#ifndef _BASE32_CODE_H_INCLUDED_ +#define _BASE32_CODE_H_INCLUDED_ + +/*++ +/* NAME +/* base32_code 3h +/* SUMMARY +/* encode/decode data, base 32 style +/* SYNOPSIS +/* #include +/* DESCRIPTION +/* .nf + + /* + * Utility library. + */ +#include + + /* + * External interface. + */ +extern VSTRING *base32_encode(VSTRING *, const char *, ssize_t); +extern VSTRING *base32_decode(VSTRING *, const char *, ssize_t); + +/* 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/src/util/sys_defs.h b/postfix/src/util/sys_defs.h index 90eb075d6..4688f9be0 100644 --- a/postfix/src/util/sys_defs.h +++ b/postfix/src/util/sys_defs.h @@ -518,7 +518,7 @@ extern int opterr; * AIX: a SYSV-flavored hybrid. NB: fcntl() and flock() access the same * underlying locking primitives. */ -#ifdef AIX5 +#if defined(AIX5) || defined(AIX6) #define SUPPORTED #include #define UINT32_TYPE unsigned int