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.
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
===========================================
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.
<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>
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>
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>
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";;
.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
/* .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
static void dnsblog_service(VSTREAM *client_stream, char *unused_service,
char **argv)
{
+ int request_id;
/*
* Sanity check. This service takes no command-line arguments.
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);
* 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
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 */
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);
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
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,
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;
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",
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 \
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 \
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)
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
$(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:
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 \
--- /dev/null
+/*++
+/* 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
--- /dev/null
+#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
* 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