]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.9-20110313
authorWietse Venema <wietse@porcupine.org>
Sun, 13 Mar 2011 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:37:15 +0000 (06:37 +0000)
13 files changed:
postfix/HISTORY
postfix/RELEASE_NOTES
postfix/WISHLIST
postfix/html/dnsblog.8.html
postfix/makedefs
postfix/man/man8/dnsblog.8
postfix/src/dnsblog/dnsblog.c
postfix/src/global/mail_version.h
postfix/src/postscreen/postscreen_dnsbl.c
postfix/src/util/Makefile.in
postfix/src/util/base32_code.c [new file with mode: 0644]
postfix/src/util/base32_code.h [new file with mode: 0644]
postfix/src/util/sys_defs.h

index 31589748368335bc1f56e4ba77635eaf8466b0fc..0e388c9425fb098afb76eefb89d5d1b52f48c6b3 100644 (file)
@@ -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.
index a09f1519b9c573f3ec963af0873af58b4d8834fc..01d988efb9c77371044dede327818d719ffdab7b 100644 (file)
@@ -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
 ===========================================
 
index 1098f419086fd14dd99c47f6c39928c02e7a7048..fa63f559de30927ae0a72666c72dcee19e880f23 100644 (file)
@@ -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.
index 85de6398225129b35c55f4e4113a3e5afbc04b77..84ff7371efb32f422c2342ae327bc4fb5b025a11 100644 (file)
@@ -20,35 +20,36 @@ DNSBLOG(8)                                                          DNSBLOG(8)
 
 <b>PROTOCOL</b>
        With each connection, the <a href="dnsblog.8.html"><b>dnsblog</b>(8)</a> server receives a DNS
-       white/blacklist  domain  name  and  an  IP address. If the
-       address is listed under the DNS white/blacklist, the  <b>dns-</b>
-       <b>blog</b>(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
-       <a href="dnsblog.8.html"><b>dnsblog</b>(8)</a> server closes the connection.
+       white/blacklist  domain  name,  IP address, and an ID.  If
+       the address is listed under the DNS  white/blacklist,  the
+       <a href="dnsblog.8.html"><b>dnsblog</b>(8)</a>  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 <a href="dnsblog.8.html"><b>dnsblog</b>(8)</a> server closes the connection.
 
 <b>DIAGNOSTICS</b>
        Problems and transactions are logged to <b>syslogd</b>(8).
 
 <b>CONFIGURATION PARAMETERS</b>
-       Changes to <a href="postconf.5.html"><b>main.cf</b></a> are picked up  automatically,  as  <b>dns-</b>
-       <b>blog</b>(8)  processes  run for only a limited amount of time.
+       Changes  to  <a href="postconf.5.html"><b>main.cf</b></a>  are picked up automatically, as <b>dns-</b>
+       <b>blog</b>(8) processes run for only a limited amount  of  time.
        Use the command "<b>postfix reload</b>" to speed up a change.
 
-       The text below provides  only  a  parameter  summary.  See
+       The  text  below  provides  only  a parameter summary. See
        <a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including examples.
 
        <b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
-              The  default  location  of  the Postfix <a href="postconf.5.html">main.cf</a> and
+              The default location of  the  Postfix  <a href="postconf.5.html">main.cf</a>  and
               <a href="master.5.html">master.cf</a> configuration files.
 
        <b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
-              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.
 
        <b><a href="postconf.5.html#postscreen_dnsbl_sites">postscreen_dnsbl_sites</a> (empty)</b>
-              Optional list of DNS white/blacklist domains,  fil-
+              Optional  list of DNS white/blacklist domains, fil-
               ters and weight factors.
 
        <b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
@@ -56,23 +57,23 @@ DNSBLOG(8)                                                          DNSBLOG(8)
               over an internal communication channel.
 
        <b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
-              The process ID  of  a  Postfix  command  or  daemon
+              The  process  ID  of  a  Postfix  command or daemon
               process.
 
        <b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b>
-              The  process  name  of  a Postfix command or daemon
+              The process name of a  Postfix  command  or  daemon
               process.
 
        <b><a href="postconf.5.html#queue_directory">queue_directory</a> (see 'postconf -d' output)</b>
-              The location of the Postfix top-level queue  direc-
+              The  location of the Postfix top-level queue direc-
               tory.
 
        <b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
               The syslog facility of Postfix logging.
 
        <b><a href="postconf.5.html#syslog_name">syslog_name</a> (see 'postconf -d' output)</b>
-              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".
 
 <b>SEE ALSO</b>
@@ -81,7 +82,7 @@ DNSBLOG(8)                                                          DNSBLOG(8)
        syslogd(5), system logging
 
 <b>LICENSE</b>
-       The  Secure  Mailer  license must be distributed with this
+       The Secure Mailer license must be  distributed  with  this
        software.
 
 <b>HISTORY</b>
index 7432cdbdf66f5f7577a66fa501bfbf583e7de88c..282eabcd4bc528bc28095f9ba50394beae41718e 100644 (file)
@@ -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";;
index ca6660d8e9a616a204680578e43bfffe25948ddc..5f485051b4585ea07ad990185209fd8b4c21a4b9 100644 (file)
@@ -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
index 89d1f0df70f2f18be566452e4e542d14efa42fb8..977a683476c415bf0550e888f8935d282ffac061 100644 (file)
 /* .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);
index 782fff818995e6ca85489d97c10a6c701da68285..b6924097dbee101538dea72479b3f5b7cd17e86d 100644 (file)
@@ -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
index f21b04efdd50de51ab1e294f84bd37a726bc932e..a57f20ef42ac4151238f0f90ee43b3b53b608bdd 100644 (file)
@@ -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",
index 4455fbf20fd29ba6e853b4312d12f4ad3cc731b8..d28d1aaacf934a443acec0a515f3ebce51f1b39a 100644 (file)
@@ -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 (file)
index 0000000..8de8391
--- /dev/null
@@ -0,0 +1,266 @@
+/*++
+/* NAME
+/*     base32_code 3
+/* SUMMARY
+/*     encode/decode data, base 32 style
+/* SYNOPSIS
+/*     #include <base32_code.h>
+/*
+/*     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 <ctype.h>
+#include <string.h>
+#include <limits.h>
+
+#ifndef UCHAR_MAX
+#define UCHAR_MAX 0xff
+#endif
+
+/* Utility library. */
+
+#include <msg.h>
+#include <mymalloc.h>
+#include <vstring.h>
+#include <base32_code.h>
+
+/* 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 (file)
index 0000000..56906f4
--- /dev/null
@@ -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 <base32_code.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * Utility library.
+ */
+#include <vstring.h>
+
+ /*
+  * 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
index 90eb075d6f9aba437fd543153ce91dfe3692d30c..4688f9be0965206602fcf9ecf0bbfbc972c75509 100644 (file)
@@ -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 <sys/types.h>
 #define UINT32_TYPE    unsigned int