]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.2-20041210
authorWietse Venema <wietse@porcupine.org>
Fri, 10 Dec 2004 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:30:16 +0000 (06:30 +0000)
45 files changed:
postfix/.indent.pro
postfix/HISTORY
postfix/README_FILES/DATABASE_README
postfix/html/DATABASE_README.html
postfix/html/local.8.html
postfix/html/postalias.1.html
postfix/html/postconf.5.html
postfix/html/postmap.1.html
postfix/man/man1/postalias.1
postfix/man/man1/postmap.1
postfix/man/man5/postconf.5
postfix/man/man8/local.8
postfix/mantools/fixman
postfix/proto/DATABASE_README.html
postfix/proto/postconf.proto
postfix/src/global/mail_params.h
postfix/src/global/mail_version.h
postfix/src/global/smtp_stream.c
postfix/src/global/smtp_stream.h
postfix/src/local/local.c
postfix/src/postalias/postalias.c
postfix/src/postmap/postmap.c
postfix/src/smtp/smtp.h
postfix/src/smtpd/smtpd.c
postfix/src/util/Makefile.in
postfix/src/util/attr.h
postfix/src/util/attr_clnt.c
postfix/src/util/attr_print0.c
postfix/src/util/attr_print64.c
postfix/src/util/attr_print_plain.c
postfix/src/util/attr_scan0.c
postfix/src/util/attr_scan0.ref
postfix/src/util/attr_scan64.c
postfix/src/util/attr_scan64.ref
postfix/src/util/attr_scan_plain.c
postfix/src/util/attr_scan_plain.ref
postfix/src/util/dict_db.c
postfix/src/util/dict_dbm.c
postfix/src/util/dict_open.c
postfix/src/util/dict_sdbm.c [new file with mode: 0644]
postfix/src/util/dict_sdbm.h [new file with mode: 0644]
postfix/src/util/hex_code.c [new file with mode: 0644]
postfix/src/util/hex_code.h [new file with mode: 0644]
postfix/src/util/sys_defs.h
postfix/src/util/watchdog.c

index f84368058041a60b0c27cce00de6ba12791f966f..8536d0b576866e990f6789721e9e4327d3b3d330 100644 (file)
@@ -65,6 +65,7 @@
 -TDICT_REGEXP_PATTERN
 -TDICT_REGEXP_PRESCAN_CONTEXT
 -TDICT_REGEXP_RULE
+-TDICT_SDBM
 -TDICT_TCP
 -TDICT_UNIX
 -TDNS_FIXED
index 45fbc2d84ff38237f69c11696004bfd3b0fe17fd..ac72609b5dc555e39875292d191af3c255d3667e 100644 (file)
@@ -9880,6 +9880,12 @@ Apologies for any names omitted.
        Victor Duchovni for Solaris 2.5.1, but we play safe and
        enable it unconditionally.
 
+20041122
+
+       Infrastructure: support for binary attribute values
+       (ATTR_TYPE_DATA) in Postfix IPC messages. Files:
+       util/attr_scan*c, util/attr_print*c.
+
 20041124
 
        Feature: configurable list of forbidden SMTP commands
@@ -9894,6 +9900,32 @@ Apologies for any names omitted.
        CDB support by Michael Tokarev, documentation by Victor
        Duchovni. Files: util/dict_cdb.[hc], global/mkmap_cdb.c.
 
+20041209
+
+       Completed support for the Berkeley DB sequence operator.
+       This is needed for finding and deleting old entries in TLS
+       session databases. File:  util/dict_db.c.
+
+       Bugfix: the DBM client's sequence operator used exclusive
+       locking instead of shared locking. File: util/dict_dbm.c.
+
+       Feature: dump an entire database with the new postmap/postalias
+       "-s" option. This works only for database types with Postfix
+       sequence operator support: hash, btree, dbm, and sdbm.
+       Files:  postmap/postmap.c, postalias/postalias.c.
+
+20041210
+
+       Back-ports of minor cosmetic changes in comments, in order
+       to keep differences minimal with respect to the TLS-enabled
+       version.
+
+       Client SDBM module, from the TLS-enabled version. Files:
+       util/dict_sdbm.[hc].
+
+       Hexadecimal encode/decode routines, from the TLS-enabled
+       version. Files:  util/hext_code.[hc].
+
 Open problems:
 
        Med: implement ${name[?:]value} in main.cf or update the
index a18c879891114bbca44b67d0ee9225e74e96fd4f..5273d7879ad642d72acc47abed6d643e90b3e08f 100644 (file)
@@ -229,6 +229,12 @@ To find out what database types your Postfix system supports, use the "p\bpo\bos\bs
         A lookup table based on regular expressions. The file format is
         described in regexp_table(5). The lookup table name as used in "regexp:
         table" is the name of the regular expression file.
+    s\bsd\bdb\bbm\bm
+        An indexed file type based on hashing. This is available only on
+        systems with support for SDBM databases. Database files are created
+        with the postmap(1) or postalias(1) command. The lookup table name as
+        used in "sdbm:table" is the database file name without the ".dir" or
+        ".pag" suffix.
     s\bst\bta\bat\bti\bic\bc (read-only)
         Always returns its lookup table name as lookup result. For example, the
         lookup table "static:foobar" always returns the string "foobar" as
index 42dbdabd1821557880e62c5abf93ea3e071deb80..d89bb7829c669b677ec7dd75719b0bfaff65e523 100644 (file)
@@ -343,6 +343,14 @@ lookup table name syntax is "<a href="proxymap.8.html">proxy</a>:type:table". </
 is described in <a href="regexp_table.5.html">regexp_table(5)</a>. The lookup table name as used in
 "<a href="regexp_table.5.html">regexp</a>:table" is the name of the regular expression file. </dd>
 
+<dt> <b>sdbm</b> </dt>
+
+<dd> An indexed file type based on hashing.  This is available only
+on systems with support for SDBM databases. Database files are
+created with the <a href="postmap.1.html">postmap(1)</a> or <a href="postalias.1.html">postalias(1)</a> command. The lookup
+table name as used in "sdbm:table" is the database file name without
+the ".dir" or ".pag" suffix.  </dd>
+
 <dt> <b>static</b> (read-only) </dt>
 
 <dd> Always returns its lookup table name as lookup result.  For
index 0bd88a80a8beedb9ba6a9328a0f95b568b157616..96f864430bcf649b778ffd2a2151cc1e7233c308 100644 (file)
@@ -313,9 +313,9 @@ LOCAL(8)                                                 LOCAL(8)
 
        <b><a href="postconf.5.html#owner_request_special">owner_request_special</a> (yes)</b>
               Give  special treatment to owner-listname and list-
-              name-request address localparts: don't don't  split
-              such  addresses when the <a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> is set
-              to "-".
+              name-request address localparts: don't  split  such
+              addresses  when  the  <a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> is set to
+              "-".
 
        <b><a href="postconf.5.html#sun_mailtool_compatibility">sun_mailtool_compatibility</a> (no)</b>
               Obsolete SUN mailtool compatibility feature.
index 44e04e3be2471755ffc9ecc0616f8ee078e62641..dcf5b671f2e2bfe0b3435f45bd0744ec79f97911 100644 (file)
@@ -10,7 +10,7 @@ POSTALIAS(1)                                         POSTALIAS(1)
        postalias - Postfix alias database maintenance
 
 <b>SYNOPSIS</b>
-       <b>postalias</b> [<b>-Nfinoprvw</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] [<b>-d</b> <i>key</i>] [<b>-q</b> <i>key</i>]
+       <b>postalias</b> [<b>-Nfinoprsvw</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] [<b>-d</b> <i>key</i>] [<b>-q</b> <i>key</i>]
                [<i>file</i><b>_</b><i>type</i>:]<i>file</i><b>_</b><i>name</i> ...
 
 <b>DESCRIPTION</b>
@@ -91,6 +91,13 @@ POSTALIAS(1)                                         POSTALIAS(1)
               attempts to update existing entries, and make those
               updates anyway.
 
+       <b>-s</b>     Retrieve  all database elements, and write one line
+              of <i>key: value</i> output for each element. The elements
+              are  printed in database order, which is not neces-
+              sarily the same as the original input order.   This
+              feature  is  available  in  Postfix version 2.2 and
+              later, and is not available for all database types.
+
        <b>-v</b>     Enable verbose logging for debugging purposes. Mul-
               tiple <b>-v</b> options  make  the  software  increasingly
               verbose.
@@ -122,20 +129,25 @@ POSTALIAS(1)                                         POSTALIAS(1)
                      <i>file</i><b>_</b><i>name</i><b>.db</b>.  This  is  available  only  on
                      systems with support for <b>db</b> databases.
 
-              When  no  <i>file</i><b>_</b><i>type</i> is specified, the software uses
-              the    database    type    specified    via     the
+              <b>sdbm</b>   The  output  consists  of  two  files, named
+                     <i>file</i><b>_</b><i>name</i><b>.pag</b> and  <i>file</i><b>_</b><i>name</i><b>.dir</b>.   This  is
+                     available  only  on systems with support for
+                     <b>sdbm</b> databases.
+
+              When no <i>file</i><b>_</b><i>type</i> is specified, the  software  uses
+              the     database    type    specified    via    the
               <b><a href="postconf.5.html#default_database_type">default_database_type</a></b> configuration parameter.  The
-              default value for this  parameter  depends  on  the
+              default  value  for  this  parameter depends on the
               host environment.
 
        <i>file</i><b>_</b><i>name</i>
-              The  name  of  the  alias database source file when
+              The name of the alias  database  source  file  when
               creating a database.
 
 <b>DIAGNOSTICS</b>
-       Problems are logged to the standard error  stream  and  to
-       <b>syslogd</b>(8).    No  output  means  that  no  problems  were
-       detected. Duplicate entries are skipped  and  are  flagged
+       Problems  are  logged  to the standard error stream and to
+       <b>syslogd</b>(8).   No  output  means  that  no  problems   were
+       detected.  Duplicate  entries  are skipped and are flagged
        with a warning.
 
        <b>postalias</b> terminates with zero exit status in case of suc-
@@ -150,26 +162,26 @@ POSTALIAS(1)                                         POSTALIAS(1)
               Enable verbose logging for debugging purposes.
 
 <b>CONFIGURATION PARAMETERS</b>
-       The  following  <b>main.cf</b> parameters are especially relevant
+       The following <b>main.cf</b> parameters are  especially  relevant
        to this program.
 
-       The text below provides  only  a  parameter  summary.  See
+       The  text  below  provides  only  a parameter summary. See
        <a href="postconf.5.html">postconf(5)</a> for more details including examples.
 
        <b><a href="postconf.5.html#alias_database">alias_database</a> (see 'postconf -d' output)</b>
-              The  alias databases for <a href="local.8.html">local(8)</a> delivery that are
+              The alias databases for <a href="local.8.html">local(8)</a> delivery that  are
               updated with "<b>newaliases</b>" or with "<b>sendmail -bi</b>".
 
        <b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
-              The default location of  the  Postfix  main.cf  and
+              The  default  location  of  the Postfix main.cf and
               master.cf configuration files.
 
        <b><a href="postconf.5.html#berkeley_db_create_buffer_size">berkeley_db_create_buffer_size</a> (16777216)</b>
-              The  per-table  I/O  buffer  size for programs that
+              The per-table I/O buffer  size  for  programs  that
               create Berkeley DB hash or btree tables.
 
        <b><a href="postconf.5.html#berkeley_db_read_buffer_size">berkeley_db_read_buffer_size</a> (131072)</b>
-              The per-table I/O buffer  size  for  programs  that
+              The  per-table  I/O  buffer  size for programs that
               read Berkeley DB hash or btree tables.
 
        <b><a href="postconf.5.html#default_database_type">default_database_type</a> (see 'postconf -d' output)</b>
@@ -180,7 +192,7 @@ POSTALIAS(1)                                         POSTALIAS(1)
               The syslog facility of Postfix logging.
 
        <b><a href="postconf.5.html#syslog_name">syslog_name</a> (postfix)</b>
-              The mail system name that is prepended to the  pro-
+              The  mail system name that is prepended to the pro-
               cess  name  in  syslog  records,  so  that  "smtpd"
               becomes, for example, "postfix/smtpd".
 
@@ -200,7 +212,7 @@ POSTALIAS(1)                                         POSTALIAS(1)
        <a href="DATABASE_README.html">DATABASE_README</a>, Postfix lookup table overview
 
 <b>LICENSE</b>
-       The  Secure  Mailer  license must be distributed with this
+       The Secure Mailer license must be  distributed  with  this
        software.
 
 <b>AUTHOR(S)</b>
index d4b4f2afc592588f998a9bb1badd0d54056aa4d3..3b5f2f4b210397a26afc60c4287889ce292c244f 100644 (file)
@@ -4224,7 +4224,7 @@ Examples:
 
 <p>
 Give special treatment to owner-listname and listname-request
-address localparts: don't don't split such addresses when the
+address localparts: don't split such addresses when the
 <a href="postconf.5.html#recipient_delimiter">recipient_delimiter</a> is set to "-".  This feature is useful for
 mailing lists.
 </p>
@@ -6342,7 +6342,7 @@ specified with the <a href="postconf.5.html#anvil_rate_time_unit">anvil_rate_tim
 
 <p>
 By default, a client can send as many message delivery requests
-requests per time unit as Postfix can accept.
+per time unit as Postfix can accept.
 </p>
 
 <p>
index 52b27cb339776bcab8b892cdf691bc6ab4e1fa37..4c90bf051de5a326dbe30f8ed31a57586a5c1681 100644 (file)
@@ -10,7 +10,7 @@ POSTMAP(1)                                             POSTMAP(1)
        postmap - Postfix lookup table management
 
 <b>SYNOPSIS</b>
-       <b>postmap</b> [<b>-Nfinoprvw</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] [<b>-d</b> <i>key</i>] [<b>-q</b> <i>key</i>]
+       <b>postmap</b> [<b>-Nfinoprsvw</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] [<b>-d</b> <i>key</i>] [<b>-q</b> <i>key</i>]
                [<i>file</i><b>_</b><i>type</i>:]<i>file</i><b>_</b><i>name</i> ...
 
 <b>DESCRIPTION</b>
@@ -109,6 +109,13 @@ POSTMAP(1)                                             POSTMAP(1)
               attempts to update existing entries, and make those
               updates anyway.
 
+       <b>-s</b>     Retrieve  all database elements, and write one line
+              of <i>key value</i> output for each element. The  elements
+              are  printed in database order, which is not neces-
+              sarily the same as the original input order.   This
+              feature  is  available  in  Postfix version 2.2 and
+              later, and is not available for all database types.
+
        <b>-v</b>     Enable verbose logging for debugging purposes. Mul-
               tiple <b>-v</b> options  make  the  software  increasingly
               verbose.
@@ -140,22 +147,27 @@ POSTMAP(1)                                             POSTMAP(1)
                      <i>file</i><b>_</b><i>name</i><b>.db</b>.  This  is  available  only  on
                      systems with support for <b>db</b> databases.
 
-              When  no  <i>file</i><b>_</b><i>type</i> is specified, the software uses
-              the    database    type    specified    via     the
+              <b>sdbm</b>   The  output  consists  of  two  files, named
+                     <i>file</i><b>_</b><i>name</i><b>.pag</b> and  <i>file</i><b>_</b><i>name</i><b>.dir</b>.   This  is
+                     available  only  on systems with support for
+                     <b>sdbm</b> databases.
+
+              When no <i>file</i><b>_</b><i>type</i> is specified, the  software  uses
+              the     database    type    specified    via    the
               <b><a href="postconf.5.html#default_database_type">default_database_type</a></b> configuration parameter.
 
        <i>file</i><b>_</b><i>name</i>
-              The  name  of  the  lookup  table  source file when
+              The name of  the  lookup  table  source  file  when
               rebuilding a database.
 
 <b>DIAGNOSTICS</b>
-       Problems are logged to the standard error  stream  and  to
-       <b>syslogd</b>(8).    No  output  means  that  no  problems  were
-       detected. Duplicate entries are skipped  and  are  flagged
+       Problems  are  logged  to the standard error stream and to
+       <b>syslogd</b>(8).   No  output  means  that  no  problems   were
+       detected.  Duplicate  entries  are skipped and are flagged
        with a warning.
 
-       <b>postmap</b>  terminates  with zero exit status in case of suc-
-       cess (including successful <b>postmap -q</b> lookup)  and  termi-
+       <b>postmap</b> terminates with zero exit status in case  of  suc-
+       cess  (including  successful <b>postmap -q</b> lookup) and termi-
        nates with non-zero exit status in case of failure.
 
 <b>ENVIRONMENT</b>
@@ -166,21 +178,21 @@ POSTMAP(1)                                             POSTMAP(1)
               Enable verbose logging for debugging purposes.
 
 <b>CONFIGURATION PARAMETERS</b>
-       The  following  <b>main.cf</b> parameters are especially relevant
+       The following <b>main.cf</b> parameters are  especially  relevant
        to this program.  The text below provides only a parameter
-       summary.  See <a href="postconf.5.html">postconf(5)</a> for more details including exam-
+       summary. See <a href="postconf.5.html">postconf(5)</a> for more details including  exam-
        ples.
 
        <b><a href="postconf.5.html#berkeley_db_create_buffer_size">berkeley_db_create_buffer_size</a> (16777216)</b>
-              The per-table I/O buffer  size  for  programs  that
+              The  per-table  I/O  buffer  size for programs that
               create Berkeley DB hash or btree tables.
 
        <b><a href="postconf.5.html#berkeley_db_read_buffer_size">berkeley_db_read_buffer_size</a> (131072)</b>
-              The  per-table  I/O  buffer  size for programs that
+              The per-table I/O buffer  size  for  programs  that
               read Berkeley DB hash or btree tables.
 
        <b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
-              The default location of  the  Postfix  main.cf  and
+              The  default  location  of  the Postfix main.cf and
               master.cf configuration files.
 
        <b><a href="postconf.5.html#default_database_type">default_database_type</a> (see 'postconf -d' output)</b>
@@ -191,7 +203,7 @@ POSTMAP(1)                                             POSTMAP(1)
               The syslog facility of Postfix logging.
 
        <b><a href="postconf.5.html#syslog_name">syslog_name</a> (postfix)</b>
-              The mail system name that is prepended to the  pro-
+              The  mail system name that is prepended to the pro-
               cess  name  in  syslog  records,  so  that  "smtpd"
               becomes, for example, "postfix/smtpd".
 
@@ -205,7 +217,7 @@ POSTMAP(1)                                             POSTMAP(1)
        <a href="DATABASE_README.html">DATABASE_README</a>, Postfix lookup table overview
 
 <b>LICENSE</b>
-       The  Secure  Mailer  license must be distributed with this
+       The Secure Mailer license must be  distributed  with  this
        software.
 
 <b>AUTHOR(S)</b>
index 0990d4a29f43be7ec3ccc7f3b314c04bffc9a593..80062697c4d0ea25769b7f30a0dc3e1bd33f0007 100644 (file)
@@ -9,7 +9,7 @@ Postfix alias database maintenance
 .na
 .nf
 .fi
-\fBpostalias\fR [\fB-Nfinoprvw\fR] [\fB-c \fIconfig_dir\fR]
+\fBpostalias\fR [\fB-Nfinoprsvw\fR] [\fB-c \fIconfig_dir\fR]
 [\fB-d \fIkey\fR] [\fB-q \fIkey\fR]
         [\fIfile_type\fR:]\fIfile_name\fR ...
 .SH DESCRIPTION
@@ -77,6 +77,13 @@ status is zero when at least one of the requested keys was found.
 .IP \fB-r\fR
 When updating a table, do not complain about attempts to update
 existing entries, and make those updates anyway.
+.IP \fB-s\fR
+Retrieve all database elements, and write one line of
+\fIkey: value\fR output for each element. The elements are
+printed in database order, which is not necessarily the same
+as the original input order.
+This feature is available in Postfix version 2.2 and later,
+and is not available for all database types.
 .IP \fB-v\fR
 Enable verbose logging for debugging purposes. Multiple \fB-v\fR
 options make the software increasingly verbose.
@@ -102,6 +109,10 @@ This is available only on systems with support for \fBdbm\fR databases.
 .IP \fBhash\fR
 The output is a hashed file, named \fIfile_name\fB.db\fR.
 This is available only on systems with support for \fBdb\fR databases.
+.IP \fBsdbm\fR
+The output consists of two files, named \fIfile_name\fB.pag\fR and
+\fIfile_name\fB.dir\fR.
+This is available only on systems with support for \fBsdbm\fR databases.
 .PP
 When no \fIfile_type\fR is specified, the software uses the database
 type specified via the \fBdefault_database_type\fR configuration
index b0c88dc3a353c40c81068df5a6f4efb6fcf3ec25..2466df2c3d565d6b70ab3c6575b756d6b6cd9b95 100644 (file)
@@ -9,7 +9,7 @@ Postfix lookup table management
 .na
 .nf
 .fi
-\fBpostmap\fR [\fB-Nfinoprvw\fR] [\fB-c \fIconfig_dir\fR]
+\fBpostmap\fR [\fB-Nfinoprsvw\fR] [\fB-c \fIconfig_dir\fR]
 [\fB-d \fIkey\fR] [\fB-q \fIkey\fR]
         [\fIfile_type\fR:]\fIfile_name\fR ...
 .SH DESCRIPTION
@@ -102,6 +102,13 @@ status is zero when at least one of the requested keys was found.
 .IP \fB-r\fR
 When updating a table, do not complain about attempts to update
 existing entries, and make those updates anyway.
+.IP \fB-s\fR
+Retrieve all database elements, and write one line of
+\fIkey value\fR output for each element. The elements are
+printed in database order, which is not necessarily the same
+as the original input order.
+This feature is available in Postfix version 2.2 and later,
+and is not available for all database types.
 .IP \fB-v\fR
 Enable verbose logging for debugging purposes. Multiple \fB-v\fR
 options make the software increasingly verbose.
@@ -127,6 +134,10 @@ This is available only on systems with support for \fBdbm\fR databases.
 .IP \fBhash\fR
 The output file is a hashed file, named \fIfile_name\fB.db\fR.
 This is available only on systems with support for \fBdb\fR databases.
+.IP \fBsdbm\fR
+The output consists of two files, named \fIfile_name\fB.pag\fR and
+\fIfile_name\fB.dir\fR.
+This is available only on systems with support for \fBsdbm\fR databases.
 .PP
 When no \fIfile_type\fR is specified, the software uses the database
 type specified via the \fBdefault_database_type\fR configuration
index d741406db774489194a7b806764714c939e598a9..accb79de3fa48156a6c9b8bae53bf56330e36d2b 100644 (file)
@@ -2245,7 +2245,7 @@ notify_classes = 2bounce, resource, software
 .ft R
 .SH owner_request_special (default: yes)
 Give special treatment to owner-listname and listname-request
-address localparts: don't don't split such addresses when the
+address localparts: don't split such addresses when the
 recipient_delimiter is set to "-".  This feature is useful for
 mailing lists.
 .SH parent_domain_matches_subdomains (default: see "postconf -d" output)
@@ -3398,7 +3398,7 @@ or not Postfix actually accepts those messages.  The time unit is
 specified with the anvil_rate_time_unit configuration parameter.
 .PP
 By default, a client can send as many message delivery requests
-requests per time unit as Postfix can accept.
+per time unit as Postfix can accept.
 .PP
 To disable this feature, specify a limit of 0.
 .PP
index c205d2dd56a0425bb3a832500dea97a913bdf2dc..62aed60e4c66cd836e508097202927bbd1898efa 100644 (file)
@@ -341,7 +341,7 @@ companion alias, set the envelope sender address to the expansion
 of the "owner-aliasname" alias.
 .IP "\fBowner_request_special (yes)\fR"
 Give special treatment to owner-listname and listname-request
-address localparts: don't don't split such addresses when the
+address localparts: don't split such addresses when the
 recipient_delimiter is set to "-".
 .IP "\fBsun_mailtool_compatibility (no)\fR"
 Obsolete SUN mailtool compatibility feature.
index 24e6eafd226f983d5489595e8305046eb2242c9b..b2e56ac78b801f82177ca4e000b119d1b34069b2 100755 (executable)
@@ -214,7 +214,7 @@ while(<>) {
        next;
     }
 
-    if ($incomment == 2 && /^\/\* +\.IP +"?\\fB([a-z0-9_]+)( +\((.*)\))?/) {
+    if ($incomment == 2 && /^\/\* +\.IP +"?\\fB([a-zA-Z0-9_]+)( +\((.*)\))?/) {
        emit_text() if ($name ne "");
        $name = $1;
        $defval = $3;
index d4a25751a671b34a10594eb77cd1690fed8ff9a4..ecbcfe0a563cca4e12fbb6d67853adfb4f8ba4b3 100644 (file)
@@ -343,6 +343,14 @@ lookup table name syntax is "proxy:type:table". </dd>
 is described in regexp_table(5). The lookup table name as used in
 "regexp:table" is the name of the regular expression file. </dd>
 
+<dt> <b>sdbm</b> </dt>
+
+<dd> An indexed file type based on hashing.  This is available only
+on systems with support for SDBM databases. Database files are
+created with the postmap(1) or postalias(1) command. The lookup
+table name as used in "sdbm:table" is the database file name without
+the ".dir" or ".pag" suffix.  </dd>
+
 <dt> <b>static</b> (read-only) </dt>
 
 <dd> Always returns its lookup table name as lookup result.  For
index f8ea92d197b8a60e697bd6cf6ca399ca426f80fd..1ced6c0599be7914d960d2a98c878b052f056e4e 100644 (file)
@@ -4027,7 +4027,7 @@ specified with the anvil_rate_time_unit configuration parameter.
 
 <p>
 By default, a client can send as many message delivery requests
-requests per time unit as Postfix can accept.
+per time unit as Postfix can accept.
 </p>
 
 <p>
@@ -6359,7 +6359,7 @@ or reject_non_fqdn_recipient restriction.
 
 <p>
 Give special treatment to owner-listname and listname-request
-address localparts: don't don't split such addresses when the
+address localparts: don't split such addresses when the
 recipient_delimiter is set to "-".  This feature is useful for
 mailing lists.
 </p>
index 13ac64290cb21a73ce5165967599ce8684efd087..051560976cf0a4c8bcbd3846372d6ab6b503e4a6 100644 (file)
@@ -2108,7 +2108,7 @@ extern char *var_remote_rwr_domain;
 #define VAR_LOC_RWR_CLIENTS            "local_header_rewrite_clients"
 #ifdef USE_TLS
 #define DEF_LOC_RWR_CLIENTS            PERMIT_MYNETWORKS " " PERMIT_SASL_AUTH \
-                                       " " PERMIT_TLS_CLIENT
+                                       " " PERMIT_TLS_CLIENTCERTS
 #else
 #define DEF_LOC_RWR_CLIENTS            PERMIT_MYNETWORKS " " PERMIT_SASL_AUTH
 #endif
index 8572c42a91b604a7cbd6f6d3b588b8f4be7b8b97..1c5eac077d8a6321cbad5ee67c668ee6a0f19654 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change the patchlevel and the release date. Snapshots change the
   * release date only.
   */
-#define MAIL_RELEASE_DATE      "20041208"
+#define MAIL_RELEASE_DATE      "20041210"
 #define MAIL_VERSION_NUMBER    "2.2"
 
 #define VAR_MAIL_VERSION       "mail_version"
index c2ab8ed26a03fe25a882e91b3226d2e24fffe8a2..aea0c1a4b5fc2e133d87109330aa942c94f989dc 100644 (file)
@@ -17,6 +17,9 @@
 /*     void    smtp_flush(stream)
 /*     VSTREAM *stream;
 /*
+/*     int     smtp_fgetc(stream)
+/*     VSTREAM *stream;
+/*
 /*     int     smtp_get(vp, stream, maxlen)
 /*     VSTRING *vp;
 /*     VSTREAM *stream;
@@ -61,6 +64,8 @@
 /*
 /*     smtp_flush() flushes the named stream.
 /*
+/*     smtp_fgetc() reads one character from the named stream.
+/*
 /*     smtp_get() reads the named stream up to and including
 /*     the next LF character and strips the trailing CR LF. The
 /*     \fImaxlen\fR argument limits the length of a line of text,
@@ -216,6 +221,31 @@ void    smtp_printf(VSTREAM *stream, const char *fmt,...)
     va_end(ap);
 }
 
+/* smtp_fgetc - read one character from SMTP peer */
+
+int     smtp_fgetc(VSTREAM *stream)
+{
+    int     err;
+    int     ch;
+
+    /*
+     * Do the I/O, protected against timeout.
+     */
+    smtp_timeout_reset(stream);
+    ch = VSTREAM_GETC(stream);
+    smtp_timeout_detect(stream);
+
+    /*
+     * See if there was a problem.
+     */
+    if (vstream_feof(stream) || vstream_ferror(stream)) {
+       if (msg_verbose)
+           msg_info("smtp_fgetc: EOF");
+       vstream_longjmp(stream, SMTP_ERR_EOF);
+    }
+    return (ch);
+}
+
 /* smtp_get - read one line from SMTP peer */
 
 int     smtp_get(VSTRING *vp, VSTREAM *stream, int bound)
index 29efecf1e58f11c0e6fd5eeb2078cc356a1dd594..cbd0f7aba0e81b638962f751322fc2e522fbed8a 100644 (file)
@@ -32,6 +32,7 @@
 extern void smtp_timeout_setup(VSTREAM *, int);
 extern void PRINTFLIKE(2, 3) smtp_printf(VSTREAM *, const char *,...);
 extern void smtp_flush(VSTREAM *);
+extern int smtp_fgetc(VSTREAM *);
 extern int smtp_get(VSTRING *, VSTREAM *, int);
 extern void smtp_fputs(const char *, int len, VSTREAM *);
 extern void smtp_fwrite(const char *, int len, VSTREAM *);
index f82f5928a4749aeabbf802c4ba89a912b1fa16bd..ab3ea45584c1ff48b1c24933e290371064290358 100644 (file)
 /*     of the "owner-aliasname" alias.
 /* .IP "\fBowner_request_special (yes)\fR"
 /*     Give special treatment to owner-listname and listname-request
-/*     address localparts: don't don't split such addresses when the
+/*     address localparts: don't split such addresses when the
 /*     recipient_delimiter is set to "-".
 /* .IP "\fBsun_mailtool_compatibility (no)\fR"
 /*     Obsolete SUN mailtool compatibility feature.
index ba02e9b3239c552d059fb450f297b01e63d081f2..c71ab750a4c6dd9f69336e142e30c63533bfa673 100644 (file)
@@ -5,7 +5,7 @@
 /*     Postfix alias database maintenance
 /* SYNOPSIS
 /* .fi
-/*     \fBpostalias\fR [\fB-Nfinoprvw\fR] [\fB-c \fIconfig_dir\fR]
+/*     \fBpostalias\fR [\fB-Nfinoprsvw\fR] [\fB-c \fIconfig_dir\fR]
 /*     [\fB-d \fIkey\fR] [\fB-q \fIkey\fR]
 /*             [\fIfile_type\fR:]\fIfile_name\fR ...
 /* DESCRIPTION
 /* .IP \fB-r\fR
 /*     When updating a table, do not complain about attempts to update
 /*     existing entries, and make those updates anyway.
+/* .IP \fB-s\fR
+/*     Retrieve all database elements, and write one line of
+/*     \fIkey: value\fR output for each element. The elements are
+/*     printed in database order, which is not necessarily the same
+/*     as the original input order.
+/*     This feature is available in Postfix version 2.2 and later,
+/*     and is not available for all database types.
 /* .IP \fB-v\fR
 /*     Enable verbose logging for debugging purposes. Multiple \fB-v\fR
 /*     options make the software increasingly verbose.
 /* .IP \fBhash\fR
 /*     The output is a hashed file, named \fIfile_name\fB.db\fR.
 /*     This is available only on systems with support for \fBdb\fR databases.
+/* .IP \fBsdbm\fR
+/*     The output consists of two files, named \fIfile_name\fB.pag\fR and
+/*     \fIfile_name\fB.dir\fR.
+/*     This is available only on systems with support for \fBsdbm\fR databases.
 /* .PP
 /*     When no \fIfile_type\fR is specified, the software uses the database
 /*     type specified via the \fBdefault_database_type\fR configuration
@@ -470,8 +481,8 @@ static int postalias_query(const char *map_type, const char *map_name,
                     map_type, map_name);
        }
        vstream_printf("%s\n", value);
-       vstream_fflush(VSTREAM_OUT);
     }
+    vstream_fflush(VSTREAM_OUT);
     dict_close(dict);
     return (value != 0);
 }
@@ -534,6 +545,34 @@ static int postalias_delete(const char *map_type, const char *map_name,
     return (status == 0);
 }
 
+/* postalias_seq - print all map entries to stdout */
+
+static void postalias_seq(const char *map_type, const char *map_name)
+{
+    DICT   *dict;
+    const char *key;
+    const char *value;
+    int     func;
+
+    dict = dict_open3(map_type, map_name, O_RDONLY, DICT_FLAG_LOCK);
+    for (func = DICT_SEQ_FUN_FIRST; /* void */ ; func = DICT_SEQ_FUN_NEXT) {
+       if (dict_seq(dict, func, &key, &value) != 0)
+           break;
+       if (*key == 0) {
+           msg_warn("table %s:%s: empty lookup key value is not allowed",
+                    map_type, map_name);
+       } else if (*value == 0) {
+           msg_warn("table %s:%s: key %s: empty string result is not allowed",
+                    map_type, map_name, key);
+           msg_warn("table %s:%s should return NO RESULT in case of NOT FOUND",
+                    map_type, map_name);
+       }
+       vstream_printf("%s:     %s\n", key, value);
+    }
+    vstream_fflush(VSTREAM_OUT);
+    dict_close(dict);
+}
+
 /* usage - explain */
 
 static NORETURN usage(char *myname)
@@ -554,6 +593,7 @@ int     main(int argc, char **argv)
     int     dict_flags = DICT_FLAG_DUP_WARN | DICT_FLAG_FOLD_KEY;
     char   *query = 0;
     char   *delkey = 0;
+    int     sequence = 0;
     int     found;
 
     /*
@@ -590,7 +630,7 @@ int     main(int argc, char **argv)
     /*
      * Parse JCL.
      */
-    while ((ch = GETOPT(argc, argv, "Nc:d:finopq:rvw")) > 0) {
+    while ((ch = GETOPT(argc, argv, "Nc:d:finopq:rsvw")) > 0) {
        switch (ch) {
        default:
            usage(argv[0]);
@@ -604,8 +644,8 @@ int     main(int argc, char **argv)
                msg_fatal("out of memory");
            break;
        case 'd':
-           if (query || delkey)
-               msg_fatal("specify only one of -q or -d");
+           if (sequence || query || delkey)
+               msg_fatal("specify only one of -s -q or -d");
            delkey = optarg;
            break;
        case 'f':
@@ -625,14 +665,19 @@ int     main(int argc, char **argv)
            postalias_flags &= ~POSTALIAS_FLAG_SAVE_PERM;
            break;
        case 'q':
-           if (query || delkey)
-               msg_fatal("specify only one of -q or -d");
+           if (sequence || query || delkey)
+               msg_fatal("specify only one of -s -q or -d");
            query = optarg;
            break;
        case 'r':
            dict_flags &= ~(DICT_FLAG_DUP_WARN | DICT_FLAG_DUP_IGNORE);
            dict_flags |= DICT_FLAG_DUP_REPLACE;
            break;
+       case 's':
+           if (query || delkey)
+               msg_fatal("specify only one of -s or -q or -d");
+           sequence = 1;
+           break;
        case 'v':
            msg_verbose++;
            break;
@@ -683,6 +728,16 @@ int     main(int argc, char **argv)
            optind++;
        }
        exit(1);
+    } else if (sequence) {
+       while (optind < argc) {
+           if ((path_name = split_at(argv[optind], ':')) != 0) {
+               postalias_seq(argv[optind], path_name);
+           } else {
+               postalias_seq(var_db_type, argv[optind]);
+           }
+           exit(0);
+       }
+       exit(1);
     } else {                                   /* create/update map(s) */
        if (optind + 1 > argc)
            usage(argv[0]);
index 0499b6f0035be7184a9ceca458161c18d1ccf2cf..e8d3187a948caf87b9abb28063f4d11ad2b21a03 100644 (file)
@@ -5,7 +5,7 @@
 /*     Postfix lookup table management
 /* SYNOPSIS
 /* .fi
-/*     \fBpostmap\fR [\fB-Nfinoprvw\fR] [\fB-c \fIconfig_dir\fR]
+/*     \fBpostmap\fR [\fB-Nfinoprsvw\fR] [\fB-c \fIconfig_dir\fR]
 /*     [\fB-d \fIkey\fR] [\fB-q \fIkey\fR]
 /*             [\fIfile_type\fR:]\fIfile_name\fR ...
 /* DESCRIPTION
 /* .IP \fB-r\fR
 /*     When updating a table, do not complain about attempts to update
 /*     existing entries, and make those updates anyway.
+/* .IP \fB-s\fR
+/*     Retrieve all database elements, and write one line of
+/*     \fIkey value\fR output for each element. The elements are
+/*     printed in database order, which is not necessarily the same
+/*     as the original input order.
+/*     This feature is available in Postfix version 2.2 and later,
+/*     and is not available for all database types.
 /* .IP \fB-v\fR
 /*     Enable verbose logging for debugging purposes. Multiple \fB-v\fR
 /*     options make the software increasingly verbose.
 /* .IP \fBhash\fR
 /*     The output file is a hashed file, named \fIfile_name\fB.db\fR.
 /*     This is available only on systems with support for \fBdb\fR databases.
+/* .IP \fBsdbm\fR
+/*     The output consists of two files, named \fIfile_name\fB.pag\fR and
+/*     \fIfile_name\fB.dir\fR.
+/*     This is available only on systems with support for \fBsdbm\fR databases.
 /* .PP
 /*     When no \fIfile_type\fR is specified, the software uses the database
 /*     type specified via the \fBdefault_database_type\fR configuration
@@ -417,8 +428,8 @@ static int postmap_query(const char *map_type, const char *map_name,
                     map_type, map_name);
        }
        vstream_printf("%s\n", value);
-       vstream_fflush(VSTREAM_OUT);
     }
+    vstream_fflush(VSTREAM_OUT);
     dict_close(dict);
     return (value != 0);
 }
@@ -481,6 +492,34 @@ static int postmap_delete(const char *map_type, const char *map_name,
     return (status == 0);
 }
 
+/* postmap_seq - print all map entries to stdout */
+
+static void postmap_seq(const char *map_type, const char *map_name)
+{
+    DICT   *dict;
+    const char *key;
+    const char *value;
+    int     func;
+
+    dict = dict_open3(map_type, map_name, O_RDONLY, DICT_FLAG_LOCK);
+    for (func = DICT_SEQ_FUN_FIRST; /* void */ ; func = DICT_SEQ_FUN_NEXT) {
+       if (dict_seq(dict, func, &key, &value) != 0)
+           break;
+       if (*key == 0) {
+           msg_warn("table %s:%s: empty lookup key value is not allowed",
+                    map_type, map_name);
+       } else if (*value == 0) {
+           msg_warn("table %s:%s: key %s: empty string result is not allowed",
+                    map_type, map_name, key);
+           msg_warn("table %s:%s should return NO RESULT in case of NOT FOUND",
+                    map_type, map_name);
+       }
+       vstream_printf("%s      %s\n", key, value);
+    }
+    vstream_fflush(VSTREAM_OUT);
+    dict_close(dict);
+}
+
 /* usage - explain */
 
 static NORETURN usage(char *myname)
@@ -501,6 +540,7 @@ int     main(int argc, char **argv)
     int     dict_flags = DICT_FLAG_DUP_WARN | DICT_FLAG_FOLD_KEY;
     char   *query = 0;
     char   *delkey = 0;
+    int     sequence = 0;
     int     found;
 
     /*
@@ -537,7 +577,7 @@ int     main(int argc, char **argv)
     /*
      * Parse JCL.
      */
-    while ((ch = GETOPT(argc, argv, "Nc:d:finopq:rvw")) > 0) {
+    while ((ch = GETOPT(argc, argv, "Nc:d:finopq:rsvw")) > 0) {
        switch (ch) {
        default:
            usage(argv[0]);
@@ -551,8 +591,8 @@ int     main(int argc, char **argv)
                msg_fatal("out of memory");
            break;
        case 'd':
-           if (query || delkey)
-               msg_fatal("specify only one of -q or -d");
+           if (sequence || query || delkey)
+               msg_fatal("specify only one of -s -q or -d");
            delkey = optarg;
            break;
        case 'f':
@@ -572,14 +612,19 @@ int     main(int argc, char **argv)
            postmap_flags &= ~POSTMAP_FLAG_SAVE_PERM;
            break;
        case 'q':
-           if (query || delkey)
-               msg_fatal("specify only one of -q or -d");
+           if (sequence || query || delkey)
+               msg_fatal("specify only one of -s -q or -d");
            query = optarg;
            break;
        case 'r':
            dict_flags &= ~(DICT_FLAG_DUP_WARN | DICT_FLAG_DUP_IGNORE);
            dict_flags |= DICT_FLAG_DUP_REPLACE;
            break;
+       case 's':
+           if (query || delkey)
+               msg_fatal("specify only one of -s or -q or -d");
+           sequence = 1;
+           break;
        case 'v':
            msg_verbose++;
            break;
@@ -630,6 +675,16 @@ int     main(int argc, char **argv)
            optind++;
        }
        exit(1);
+    } else if (sequence) {
+       while (optind < argc) {
+           if ((path_name = split_at(argv[optind], ':')) != 0) {
+               postmap_seq(argv[optind], path_name);
+           } else {
+               postmap_seq(var_db_type, argv[optind]);
+           }
+           exit(0);
+       }
+       exit(1);
     } else {                                   /* create/update map(s) */
        if (optind + 1 > argc)
            usage(argv[0]);
index 25d631c884271e1109170ddbf5423e24b59e8bbb..6600c96589c44ff416133c86d0d9acc1dcc10999 100644 (file)
@@ -32,8 +32,8 @@
 #include <string_list.h>
 
  /*
-  * State information associated with each SMTP delivery. We're bundling the
-  * state so that we can give meaningful diagnostics in case of problems.
+  * State information associated with each SMTP delivery request.
+  * Session-specific state is stored separately.
   */
 typedef struct SMTP_STATE {
     VSTREAM *src;                      /* queue file stream */
@@ -44,12 +44,12 @@ typedef struct SMTP_STATE {
     int     space_left;                        /* output length control */
 
     /*
-     * Session cache support. The (nexthop_lookup_mx, nexthop_domain,
+     * Connection cache support. The (nexthop_lookup_mx, nexthop_domain,
      * nexthop_port) triple is a parsed next-hop specification, and should be
      * a data type by itself. The (service, nexthop_mumble) members specify
-     * the name under which the first good session should be cached. The
+     * the name under which the first good connection should be cached. The
      * nexthop_mumble members are initialized by the connection management
-     * module. nexthop_domain is reset to null after one session is saved
+     * module. nexthop_domain is reset to null after one connection is saved
      * under the (service, nexthop_mumble) label, or upon exit from the
      * connection management module.
      */
@@ -104,7 +104,7 @@ typedef struct SMTP_STATE {
 #define SMTP_FEATURE_XFORWARD_DOMAIN   (1<<11)
 #define SMTP_FEATURE_BEST_MX           (1<<12) /* for next-hop or fall-back */
 #define SMTP_FEATURE_RSET_REJECTED     (1<<13) /* RSET probe rejected */
-#define SMTP_FEATURE_FROM_CACHE                (1<<14) /* cached session */
+#define SMTP_FEATURE_FROM_CACHE                (1<<14) /* cached connection */
 
  /*
   * Features that passivate under the endpoint.
@@ -140,7 +140,7 @@ extern int smtp_host_lookup_mask;   /* host lookup methods to use */
 #define SMTP_HOST_FLAG_DNS     (1<<0)
 #define SMTP_HOST_FLAG_NATIVE  (1<<1)
 
-extern SCACHE *smtp_scache;            /* cache instance */
+extern SCACHE *smtp_scache;            /* connection cache instance */
 extern STRING_LIST *smtp_cache_dest;   /* cached destinations */
 
  /*
@@ -183,7 +183,7 @@ typedef struct SMTP_SESSION {
 } SMTP_SESSION;
 
 extern SMTP_SESSION *smtp_session_alloc(VSTREAM *, const char *,
-                                     const char *, const char *, unsigned, int);
+                                const char *, const char *, unsigned, int);
 extern void smtp_session_free(SMTP_SESSION *);
 extern int smtp_session_passivate(SMTP_SESSION *, VSTRING *, VSTRING *);
 extern SMTP_SESSION *smtp_session_activate(int, VSTRING *, VSTRING *);
index beff18fedcc0539c34fff1717b401d3d350c78a1..91b449683a830d0a0e6296b906fda99b24fd1469 100644 (file)
@@ -861,6 +861,13 @@ static void chat_reset(SMTPD_STATE *, int);
   */
 #define NEUTER_CHARACTERS " <>()\\\";:@"
 
+ /*
+  * Reasons for losing the client.
+  */
+#define REASON_TIMEOUT                 "timeout"
+#define REASON_LOST_CONNECTION         "lost connection"
+#define REASON_ERROR_LIMIT             "too many errors"
+
 #ifdef USE_SASL_AUTH
 
  /*
@@ -2472,11 +2479,9 @@ typedef struct SMTPD_CMD {
 static SMTPD_CMD smtpd_cmd_table[] = {
     "HELO", helo_cmd, SMTPD_CMD_FLAG_LIMIT,
     "EHLO", ehlo_cmd, SMTPD_CMD_FLAG_LIMIT,
-
 #ifdef USE_SASL_AUTH
     "AUTH", smtpd_sasl_auth_cmd, 0,
 #endif
-
     "MAIL", mail_cmd, 0,
     "RCPT", rcpt_cmd, 0,
     "DATA", data_cmd, 0,
@@ -2531,14 +2536,14 @@ static void smtpd_proto(SMTPD_STATE *state, const char *service)
        break;
 
     case SMTP_ERR_TIME:
-       state->reason = "timeout";
+       state->reason = REASON_TIMEOUT;
        if (vstream_setjmp(state->client) == 0)
            smtpd_chat_reply(state, "421 %s Error: timeout exceeded",
                             var_myhostname);
        break;
 
     case SMTP_ERR_EOF:
-       state->reason = "lost connection";
+       state->reason = REASON_LOST_CONNECTION;
        break;
 
     case 0:
@@ -2589,7 +2594,7 @@ static void smtpd_proto(SMTPD_STATE *state, const char *service)
 
        for (;;) {
            if (state->error_count >= var_smtpd_hard_erlim) {
-               state->reason = "too many errors";
+               state->reason = REASON_ERROR_LIMIT;
                state->error_mask |= MAIL_ERROR_PROTOCOL;
                smtpd_chat_reply(state, "421 %s Error: too many errors",
                                 var_myhostname);
@@ -2673,7 +2678,7 @@ static void smtpd_proto(SMTPD_STATE *state, const char *service)
      */
     if (state->reason && state->where
        && (strcmp(state->where, SMTPD_AFTER_DOT)
-           || strcmp(state->reason, "lost connection")))
+           || strcmp(state->reason, REASON_LOST_CONNECTION)))
        msg_info("%s after %s from %s[%s]",
                 state->reason, state->where, state->name, state->addr);
 
index 37d0736f19a62414df6719460fb841a12646a0f2..f3afec78424a49f134a481ee0a24041e0d272069 100644 (file)
@@ -28,7 +28,8 @@ SRCS  = alldig.c argv.c argv_split.c attr_print0.c attr_print64.c \
        vstream_popen.c vstring.c vstring_vstream.c watchdog.c writable.c \
        write_buf.c write_wait.c auto_clnt.c attr_clnt.c attr_scan_plain.c \
        attr_print_plain.c sane_connect.c neuter.c name_code.c \
-       uppercase.c unix_recv_fd.c stream_recv_fd.c unix_send_fd.c stream_send_fd.c
+       uppercase.c unix_recv_fd.c stream_recv_fd.c unix_send_fd.c \
+       stream_send_fd.c dict_sdbm.c hex_code.c
 OBJS   = alldig.o argv.o argv_split.o attr_print0.o attr_print64.o \
        attr_scan0.o attr_scan64.o base64_code.o basename.o binhash.o \
        chroot_uid.o clean_env.o close_on_exec.o concatenate.o ctable.o \
@@ -58,7 +59,8 @@ OBJS  = alldig.o argv.o argv_split.o attr_print0.o attr_print64.o \
        vstream_popen.o vstring.o vstring_vstream.o watchdog.o writable.o \
        write_buf.o write_wait.o auto_clnt.o attr_clnt.o attr_scan_plain.o \
        attr_print_plain.o sane_connect.o $(STRCASE) neuter.o name_code.o \
-       uppercase.o unix_recv_fd.o stream_recv_fd.o unix_send_fd.o stream_send_fd.o
+       uppercase.o unix_recv_fd.o stream_recv_fd.o unix_send_fd.o \
+       stream_send_fd.o dict_sdbm.o hex_code.o
 HDRS   = argv.h attr.h base64_code.h binhash.h chroot_uid.h clean_env.h \
        connect.h ctable.h dict.h dict_db.h dict_cdb.h dict_dbm.h dict_env.h \
        dict_cidr.h dict_ht.h dict_ni.h dict_nis.h \
@@ -77,7 +79,8 @@ HDRS  = argv.h attr.h base64_code.h binhash.h chroot_uid.h clean_env.h \
        split_at.h stat_as.h stringops.h sys_defs.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 watchdog.h \
-       auto_clnt.h attr_clnt.h sane_connect.h name_code.h
+       auto_clnt.h attr_clnt.h sane_connect.h name_code.h dict_sdbm.h \
+       hex_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)
@@ -93,7 +96,7 @@ TESTPROG= dict_open dup2_pass_on_exec events exec_command fifo_open \
        watchdog unescape hex_quote name_mask rand_sleep sane_time ctable \
        inet_addr_list attr_print64 attr_scan64 base64_code attr_print0 \
        attr_scan0 host_port attr_scan_plain attr_print_plain htable \
-       unix_recv_fd unix_send_fd stream_recv_fd stream_send_fd
+       unix_recv_fd unix_send_fd stream_recv_fd stream_send_fd hex_code
 
 LIB_DIR        = ../../lib
 INC_DIR        = ../../include
@@ -362,6 +365,11 @@ stream_send_fd:  $(LIB)
        $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
        mv junk $@.o
 
+hex_code: $(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 \
@@ -376,7 +384,7 @@ stream_test: stream_test.c $(LIB)
 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
+       dict_cidr_test attr_scan_plain_test htable_test hex_code_test
 
 valid_hostname_test: valid_hostname valid_hostname.in valid_hostname.ref
        ./valid_hostname <valid_hostname.in 2>valid_hostname.tmp
@@ -460,6 +468,9 @@ attr_scan_plain_test: attr_print_plain attr_scan_plain attr_scan_plain.ref
 htable_test: htable /usr/share/dict/words
        ./htable < /usr/share/dict/words
 
+hex_code_test: hex_code
+       ./hex_code
+
 # do not edit below this line - it is generated by 'make depend'
 alldig.o: alldig.c
 alldig.o: sys_defs.h
@@ -499,6 +510,8 @@ attr_print0.o: vstream.h
 attr_print0.o: vbuf.h
 attr_print0.o: htable.h
 attr_print0.o: attr.h
+attr_print0.o: base64_code.h
+attr_print0.o: vstring.h
 attr_print64.o: attr_print64.c
 attr_print64.o: sys_defs.h
 attr_print64.o: msg.h
@@ -516,6 +529,8 @@ attr_print_plain.o: mymalloc.h
 attr_print_plain.o: vstream.h
 attr_print_plain.o: vbuf.h
 attr_print_plain.o: htable.h
+attr_print_plain.o: base64_code.h
+attr_print_plain.o: vstring.h
 attr_print_plain.o: attr.h
 attr_scan0.o: attr_scan0.c
 attr_scan0.o: sys_defs.h
@@ -526,6 +541,7 @@ attr_scan0.o: vbuf.h
 attr_scan0.o: vstring.h
 attr_scan0.o: vstring_vstream.h
 attr_scan0.o: htable.h
+attr_scan0.o: base64_code.h
 attr_scan0.o: attr.h
 attr_scan64.o: attr_scan64.c
 attr_scan64.o: sys_defs.h
@@ -545,6 +561,7 @@ attr_scan_plain.o: vstream.h
 attr_scan_plain.o: vbuf.h
 attr_scan_plain.o: vstring.h
 attr_scan_plain.o: htable.h
+attr_scan_plain.o: base64_code.h
 attr_scan_plain.o: attr.h
 auto_clnt.o: auto_clnt.c
 auto_clnt.o: sys_defs.h
@@ -624,6 +641,17 @@ dict_alloc.o: vbuf.h
 dict_alloc.o: argv.h
 dict_cdb.o: dict_cdb.c
 dict_cdb.o: sys_defs.h
+dict_cdb.o: msg.h
+dict_cdb.o: mymalloc.h
+dict_cdb.o: vstring.h
+dict_cdb.o: vbuf.h
+dict_cdb.o: stringops.h
+dict_cdb.o: iostuff.h
+dict_cdb.o: myflock.h
+dict_cdb.o: dict.h
+dict_cdb.o: vstream.h
+dict_cdb.o: argv.h
+dict_cdb.o: dict_cdb.h
 dict_cidr.o: dict_cidr.c
 dict_cidr.o: sys_defs.h
 dict_cidr.o: mymalloc.h
@@ -714,6 +742,7 @@ dict_open.o: dict_cdb.h
 dict_open.o: dict_env.h
 dict_open.o: dict_unix.h
 dict_open.o: dict_tcp.h
+dict_open.o: dict_sdbm.h
 dict_open.o: dict_dbm.h
 dict_open.o: dict_db.h
 dict_open.o: dict_nis.h
@@ -755,6 +784,20 @@ dict_regexp.o: dict.h
 dict_regexp.o: argv.h
 dict_regexp.o: dict_regexp.h
 dict_regexp.o: mac_parse.h
+dict_sdbm.o: dict_sdbm.c
+dict_sdbm.o: sys_defs.h
+dict_sdbm.o: msg.h
+dict_sdbm.o: mymalloc.h
+dict_sdbm.o: htable.h
+dict_sdbm.o: iostuff.h
+dict_sdbm.o: vstring.h
+dict_sdbm.o: vbuf.h
+dict_sdbm.o: myflock.h
+dict_sdbm.o: stringops.h
+dict_sdbm.o: dict.h
+dict_sdbm.o: vstream.h
+dict_sdbm.o: argv.h
+dict_sdbm.o: dict_sdbm.h
 dict_static.o: dict_static.c
 dict_static.o: sys_defs.h
 dict_static.o: mymalloc.h
@@ -869,6 +912,13 @@ get_hostname.o: mymalloc.h
 get_hostname.o: msg.h
 get_hostname.o: valid_hostname.h
 get_hostname.o: get_hostname.h
+hex_code.o: hex_code.c
+hex_code.o: sys_defs.h
+hex_code.o: msg.h
+hex_code.o: mymalloc.h
+hex_code.o: vstring.h
+hex_code.o: vbuf.h
+hex_code.o: hex_code.h
 hex_quote.o: hex_quote.c
 hex_quote.o: sys_defs.h
 hex_quote.o: msg.h
index f0626f304c86c91d4a291da49209ef44c95fb9f5..db306e1353bd01a4af36f725a03acf0edd1eccdf 100644 (file)
@@ -30,6 +30,7 @@
 #define ATTR_TYPE_HASH         3       /* Hash table */
 #define ATTR_TYPE_NV           3       /* Name-value table */
 #define ATTR_TYPE_LONG         4       /* Unsigned long */
+#define ATTR_TYPE_DATA         5       /* Binary data */
 
 #define ATTR_HASH_LIMIT                1024    /* Size of hash table */
 
@@ -94,6 +95,7 @@ extern int attr_vscan_plain(VSTREAM *, int, va_list);
 #define ATTR_NAME_NUM          "number"
 #define ATTR_NAME_STR          "string"
 #define ATTR_NAME_LONG         "long_number"
+#define ATTR_NAME_DATA         "data"
 #endif
 
 /* LICENSE
index 6dd2307132c58d272603b58dbf624efc58ce7de1..b2c8437119ebae914de59bd101b17f7dc45d23f8 100644 (file)
@@ -201,6 +201,10 @@ int     attr_clnt_request(ATTR_CLNT *client, int send_flags,...)
        (void) va_arg(ap, char *); \
        (void) va_arg(ap, type); \
     }
+#define SKIP_ARG2(ap, t1, t2) { \
+       SKIP_ARG(ap, t1); \
+       (void) va_arg(ap, t2); \
+    }
 
     for (;;) {
        errno = 0;
@@ -218,6 +222,9 @@ int     attr_clnt_request(ATTR_CLNT *client, int send_flags,...)
                    case ATTR_TYPE_STR:
                        SKIP_ARG(ap, char *);
                        break;
+                   case ATTR_TYPE_DATA:
+                       SKIP_ARG2(ap, char *, int);
+                       break;
                    case ATTR_TYPE_NUM:
                        SKIP_ARG(ap, int);
                        break;
index 5bfa31df143d83ff342b5715d18c1e614c9d49bf..81b61309a80237ae0ec91fe2bc23fd9c3d0d79b9 100644 (file)
@@ -51,6 +51,9 @@
 /* .IP "ATTR_TYPE_STR (char *, char *)"
 /*     This argument is followed by an attribute name and a null-terminated
 /*     string.
+/* .IP "ATTR_TYPE_DATA (char *, int, char *)"
+/*     This argument is followed by an attribute name, an attribute value
+/*     length, and an attribute value pointer.
 /* .IP "ATTR_TYPE_HASH (HTABLE *)"
 /* .IP "ATTR_TYPE_NAMEVAL (NVTABLE *)"
 /*     The content of the table is sent as a sequence of string-valued
 #include <vstream.h>
 #include <htable.h>
 #include <attr.h>
+#include <base64_code.h>
+
+#define STR(x) vstring_str(x)
+#define LEN(x) VSTRING_LEN(x)
 
 /* attr_vprint0 - send attribute list to stream */
 
@@ -102,6 +109,8 @@ int     attr_vprint0(VSTREAM *fp, int flags, va_list ap)
     char   *str_val;
     HTABLE_INFO **ht_info_list;
     HTABLE_INFO **ht;
+    int     len_val;
+    static VSTRING *base64_buf;
 
     /*
      * Sanity check.
@@ -141,6 +150,18 @@ int     attr_vprint0(VSTREAM *fp, int flags, va_list ap)
            if (msg_verbose)
                msg_info("send attr %s = %s", attr_name, str_val);
            break;
+       case ATTR_TYPE_DATA:
+           attr_name = va_arg(ap, char *);
+           vstream_fwrite(fp, attr_name, strlen(attr_name) + 1);
+           len_val = va_arg(ap, int);
+           str_val = va_arg(ap, char *);
+           if (base64_buf == 0)
+               base64_buf = vstring_alloc(10);
+           base64_encode(base64_buf, str_val, len_val);
+           vstream_fwrite(fp, STR(base64_buf), LEN(base64_buf) + 1);
+           if (msg_verbose)
+               msg_info("send attr %s = [data %d bytes]", attr_name, len_val);
+           break;
        case ATTR_TYPE_HASH:
            ht_info_list = htable_list(va_arg(ap, HTABLE *));
            for (ht = ht_info_list; *ht; ht++) {
@@ -192,12 +213,14 @@ int     main(int unused_argc, char **argv)
                ATTR_TYPE_NUM, ATTR_NAME_NUM, 4711,
                ATTR_TYPE_LONG, ATTR_NAME_LONG, 1234,
                ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee",
+               ATTR_TYPE_DATA, ATTR_NAME_DATA, strlen("whoopee"), "whoopee",
                ATTR_TYPE_HASH, table,
                ATTR_TYPE_END);
     attr_print0(VSTREAM_OUT, ATTR_FLAG_NONE,
                ATTR_TYPE_NUM, ATTR_NAME_NUM, 4711,
                ATTR_TYPE_LONG, ATTR_NAME_LONG, 1234,
                ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee",
+               ATTR_TYPE_DATA, ATTR_NAME_DATA, strlen("whoopee"), "whoopee",
                ATTR_TYPE_END);
     if (vstream_fflush(VSTREAM_OUT) != 0)
        msg_fatal("write error: %m");
index d43d5db78561531ed4b78caa0b9f8603e08f4cfc..370250025fdf3846a857922b7ca838c8ea804fb3 100644 (file)
@@ -141,6 +141,7 @@ int     attr_vprint64(VSTREAM *fp, int flags, va_list ap)
     char   *str_val;
     HTABLE_INFO **ht_info_list;
     HTABLE_INFO **ht;
+    int     len_val;
 
     /*
      * Sanity check.
@@ -184,6 +185,17 @@ int     attr_vprint64(VSTREAM *fp, int flags, va_list ap)
            if (msg_verbose)
                msg_info("send attr %s = %s", attr_name, str_val);
            break;
+       case ATTR_TYPE_DATA:
+           attr_name = va_arg(ap, char *);
+           attr_print64_str(fp, attr_name, strlen(attr_name));
+           len_val = va_arg(ap, int);
+           str_val = va_arg(ap, char *);
+           VSTREAM_PUTC(':', fp);
+           attr_print64_str(fp, str_val, len_val);
+           VSTREAM_PUTC('\n', fp);
+           if (msg_verbose)
+               msg_info("send attr %s = [data %d bytes]", attr_name, len_val);
+           break;
        case ATTR_TYPE_HASH:
            ht_info_list = htable_list(va_arg(ap, HTABLE *));
            for (ht = ht_info_list; *ht; ht++) {
@@ -237,12 +249,14 @@ int     main(int unused_argc, char **argv)
                 ATTR_TYPE_NUM, ATTR_NAME_NUM, 4711,
                 ATTR_TYPE_LONG, ATTR_NAME_LONG, 1234,
                 ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee",
+                ATTR_TYPE_DATA, ATTR_NAME_DATA, strlen("whoopee"), "whoopee",
                 ATTR_TYPE_HASH, table,
                 ATTR_TYPE_END);
     attr_print64(VSTREAM_OUT, ATTR_FLAG_NONE,
                 ATTR_TYPE_NUM, ATTR_NAME_NUM, 4711,
                 ATTR_TYPE_LONG, ATTR_NAME_LONG, 1234,
                 ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee",
+                ATTR_TYPE_DATA, ATTR_NAME_DATA, strlen("whoopee"), "whoopee",
                 ATTR_TYPE_END);
     if (vstream_fflush(VSTREAM_OUT) != 0)
        msg_fatal("write error: %m");
index 7b898950592b68d40f715ababbbfb9caaefe93ff..d9083d62b069f3fc57617d388f2d34d62f2aa881 100644 (file)
@@ -51,6 +51,9 @@
 /* .IP "ATTR_TYPE_STR (char *, char *)"
 /*     This argument is followed by an attribute name and a null-terminated
 /*     string.
+/* .IP "ATTR_TYPE_DATA (char *, int, char *)"
+/*     This argument is followed by an attribute name, an attribute value
+/*     length, and a pointer to attribute value.
 /* .IP "ATTR_TYPE_HASH (HTABLE *)"
 /* .IP "ATTR_TYPE_NAMEVAL (NVTABLE *)"
 /*     The content of the table is sent as a sequence of string-valued
@@ -88,6 +91,8 @@
 #include <mymalloc.h>
 #include <vstream.h>
 #include <htable.h>
+#include <base64_code.h>
+#include <vstring.h>
 #include <attr.h>
 
 #define STR(x) vstring_str(x)
@@ -105,6 +110,8 @@ int     attr_vprint_plain(VSTREAM *fp, int flags, va_list ap)
     char   *str_val;
     HTABLE_INFO **ht_info_list;
     HTABLE_INFO **ht;
+    static VSTRING *base64_buf;
+    int     len_val;
 
     /*
      * Sanity check.
@@ -139,6 +146,17 @@ int     attr_vprint_plain(VSTREAM *fp, int flags, va_list ap)
            if (msg_verbose)
                msg_info("send attr %s = %s", attr_name, str_val);
            break;
+       case ATTR_TYPE_DATA:
+           attr_name = va_arg(ap, char *);
+           len_val = va_arg(ap, int);
+           str_val = va_arg(ap, char *);
+           if (base64_buf == 0)
+               base64_buf = vstring_alloc(10);
+           base64_encode(base64_buf, str_val, len_val);
+           vstream_fprintf(fp, "%s=%s\n", attr_name, STR(base64_buf));
+           if (msg_verbose)
+               msg_info("send attr %s = [data %d bytes]", attr_name, len_val);
+           break;
        case ATTR_TYPE_HASH:
            ht_info_list = htable_list(va_arg(ap, HTABLE *));
            for (ht = ht_info_list; *ht; ht++) {
@@ -189,12 +207,14 @@ int     main(int unused_argc, char **argv)
                     ATTR_TYPE_NUM, ATTR_NAME_NUM, 4711,
                     ATTR_TYPE_LONG, ATTR_NAME_LONG, 1234,
                     ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee",
+                    ATTR_TYPE_DATA, ATTR_NAME_DATA, strlen("whoopee"), "whoopee",
                     ATTR_TYPE_HASH, table,
                     ATTR_TYPE_END);
     attr_print_plain(VSTREAM_OUT, ATTR_FLAG_NONE,
                     ATTR_TYPE_NUM, ATTR_NAME_NUM, 4711,
                     ATTR_TYPE_LONG, ATTR_NAME_LONG, 1234,
                     ATTR_TYPE_STR, ATTR_NAME_STR, "whoopee",
+                    ATTR_TYPE_DATA, ATTR_NAME_DATA, strlen("whoopee"), "whoopee",
                     ATTR_TYPE_END);
     if (vstream_fflush(VSTREAM_OUT) != 0)
        msg_fatal("write error: %m");
index 11454ce1fd548224f00ebe164b3b8dd2072547f0..fe882c64e69188e11b546428d5b371352b2f6cb4 100644 (file)
@@ -91,6 +91,8 @@
 /*     This argument is followed by an attribute name and a long pointer.
 /* .IP "ATTR_TYPE_STR (char *, VSTRING *)"
 /*     This argument is followed by an attribute name and a VSTRING pointer.
+/* .IP "ATTR_TYPE_DATA (char *, VSTRING *)"
+/*     This argument is followed by an attribute name and a VSTRING pointer.
 /* .IP "ATTR_TYPE_HASH (HTABLE *)"
 /* .IP "ATTR_TYPE_NAMEVAL (NVTABLE *)"
 /*     All further input attributes are processed as string attributes.
 #include <vstring.h>
 #include <vstring_vstream.h>
 #include <htable.h>
+#include <base64_code.h>
 #include <attr.h>
 
 /* Application specific. */
@@ -178,6 +181,26 @@ static int attr_scan0_string(VSTREAM *fp, VSTRING *plain_buf, const char *contex
     return (ch);
 }
 
+/* attr_scan0_data - pull a data blob from the input stream */
+
+static int attr_scan0_data(VSTREAM *fp, VSTRING *str_buf,
+                                  const char *context)
+{
+    static VSTRING *base64_buf = 0;
+    int     ch;
+
+    if (base64_buf == 0)
+       base64_buf = vstring_alloc(10);
+    if ((ch = attr_scan0_string(fp, base64_buf, context)) < 0)
+       return (-1);
+    if (base64_decode(str_buf, STR(base64_buf), LEN(base64_buf)) == 0) {
+       msg_warn("malformed base64 data from %s while reading %s: %.100s",
+                VSTREAM_PATH(fp), context, STR(base64_buf));
+       return (-1);
+    }
+    return (ch);
+}
+
 /* attr_scan0_number - pull a number from the input stream */
 
 static int attr_scan0_number(VSTREAM *fp, unsigned *ptr, VSTRING *str_buf,
@@ -343,6 +366,12 @@ int     attr_vscan0(VSTREAM *fp, int flags, va_list ap)
                                        "input attribute value")) < 0)
                return (-1);
            break;
+       case ATTR_TYPE_DATA:
+           string = va_arg(ap, VSTRING *);
+           if ((ch = attr_scan0_data(fp, string,
+                                     "input attribute value")) < 0)
+               return (-1);
+           break;
        case ATTR_TYPE_HASH:
            if ((ch = attr_scan0_string(fp, str_buf,
                                        "input attribute value")) < 0)
@@ -393,6 +422,7 @@ int     var_line_limit = 2048;
 
 int     main(int unused_argc, char **used_argv)
 {
+    VSTRING *data_val = vstring_alloc(1);
     VSTRING *str_val = vstring_alloc(1);
     HTABLE *table = htable_create(1);
     HTABLE_INFO **ht_info_list;
@@ -408,11 +438,13 @@ int     main(int unused_argc, char **used_argv)
                          ATTR_TYPE_NUM, ATTR_NAME_NUM, &int_val,
                          ATTR_TYPE_LONG, ATTR_NAME_LONG, &long_val,
                          ATTR_TYPE_STR, ATTR_NAME_STR, str_val,
+                         ATTR_TYPE_DATA, ATTR_NAME_DATA, data_val,
                          ATTR_TYPE_HASH, table,
-                         ATTR_TYPE_END)) > 3) {
+                         ATTR_TYPE_END)) > 4) {
        vstream_printf("%s %d\n", ATTR_NAME_NUM, int_val);
        vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val);
        vstream_printf("%s %s\n", ATTR_NAME_STR, STR(str_val));
+       vstream_printf("%s %s\n", ATTR_NAME_DATA, STR(str_val));
        ht_info_list = htable_list(table);
        for (ht = ht_info_list; *ht; ht++)
            vstream_printf("(hash) %s %s\n", ht[0]->key, ht[0]->value);
@@ -425,10 +457,12 @@ int     main(int unused_argc, char **used_argv)
                          ATTR_TYPE_NUM, ATTR_NAME_NUM, &int_val,
                          ATTR_TYPE_LONG, ATTR_NAME_LONG, &long_val,
                          ATTR_TYPE_STR, ATTR_NAME_STR, str_val,
-                         ATTR_TYPE_END)) == 3) {
+                         ATTR_TYPE_DATA, ATTR_NAME_DATA, data_val,
+                         ATTR_TYPE_END)) == 4) {
        vstream_printf("%s %d\n", ATTR_NAME_NUM, int_val);
        vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val);
        vstream_printf("%s %s\n", ATTR_NAME_STR, STR(str_val));
+       vstream_printf("%s %s\n", ATTR_NAME_DATA, STR(data_val));
        ht_info_list = htable_list(table);
        for (ht = ht_info_list; *ht; ht++)
            vstream_printf("(hash) %s %s\n", ht[0]->key, ht[0]->value);
@@ -439,6 +473,7 @@ int     main(int unused_argc, char **used_argv)
     if (vstream_fflush(VSTREAM_OUT) != 0)
        msg_fatal("write error: %m");
 
+    vstring_free(data_val);
     vstring_free(str_val);
     htable_free(table, myfree);
 
index 105382fd1efb69a2c65b739b633bc6d317a51d34..a9e211d82d619920e94067cfd7daf5559d1cd0e6 100644 (file)
@@ -1,11 +1,13 @@
 ./attr_print0: send attr number = 4711
 ./attr_print0: send attr long_number = 1234
 ./attr_print0: send attr string = whoopee
+./attr_print0: send attr data = [data 7 bytes]
 ./attr_print0: send attr name foo-name value foo-value
 ./attr_print0: send attr name bar-name value bar-value
 ./attr_print0: send attr number = 4711
 ./attr_print0: send attr long_number = 1234
 ./attr_print0: send attr string = whoopee
+./attr_print0: send attr data = [data 7 bytes]
 ./attr_scan0: unknown_stream: wanted attribute: number
 ./attr_scan0: input attribute name: number
 ./attr_scan0: input attribute value: 4711
@@ -15,6 +17,9 @@
 ./attr_scan0: unknown_stream: wanted attribute: string
 ./attr_scan0: input attribute name: string
 ./attr_scan0: input attribute value: whoopee
+./attr_scan0: unknown_stream: wanted attribute: data
+./attr_scan0: input attribute name: data
+./attr_scan0: input attribute value: d2hvb3BlZQ==
 ./attr_scan0: unknown_stream: wanted attribute: (any attribute name or list terminator)
 ./attr_scan0: input attribute name: foo-name
 ./attr_scan0: input attribute value: foo-value
 ./attr_scan0: unknown_stream: wanted attribute: string
 ./attr_scan0: input attribute name: string
 ./attr_scan0: input attribute value: whoopee
+./attr_scan0: unknown_stream: wanted attribute: data
+./attr_scan0: input attribute name: data
+./attr_scan0: input attribute value: d2hvb3BlZQ==
 ./attr_scan0: unknown_stream: wanted attribute: (list terminator)
 ./attr_scan0: input attribute name: (end)
 number 4711
 long_number 1234
 string whoopee
+data whoopee
 (hash) foo-name foo-value
 (hash) bar-name bar-value
 number 4711
 long_number 1234
 string whoopee
+data whoopee
 (hash) foo-name foo-value
 (hash) bar-name bar-value
index 93fcc44c35bd538f24fb138088e3a43ae0a882c0..b6cce996da52f633b67fa574048d10d86d668f87 100644 (file)
@@ -93,6 +93,8 @@
 /*     This argument is followed by an attribute name and a long pointer.
 /* .IP "ATTR_TYPE_STR (char *, VSTRING *)"
 /*     This argument is followed by an attribute name and a VSTRING pointer.
+/* .IP "ATTR_TYPE_DATA (char *, VSTRING *)"
+/*     This argument is followed by an attribute name and a VSTRING pointer.
 /* .IP "ATTR_TYPE_HASH (HTABLE *)"
 /* .IP "ATTR_TYPE_NAMEVAL (NVTABLE *)"
 /*     All further input attributes are processed as string attributes.
@@ -401,6 +403,22 @@ int     attr_vscan64(VSTREAM *fp, int flags, va_list ap)
                return (-1);
            }
            break;
+       case ATTR_TYPE_DATA:
+           if (ch != ':') {
+               msg_warn("missing value for data attribute %s from %s",
+                        STR(name_buf), VSTREAM_PATH(fp));
+               return (-1);
+           }
+           string = va_arg(ap, VSTRING *);
+           if ((ch = attr_scan64_string(fp, string,
+                                        "input attribute value")) < 0)
+               return (-1);
+           if (ch != '\n') {
+               msg_warn("multiple values for attribute %s from %s",
+                        STR(name_buf), VSTREAM_PATH(fp));
+               return (-1);
+           }
+           break;
        case ATTR_TYPE_HASH:
            if (ch != ':') {
                msg_warn("missing value for string attribute %s from %s",
@@ -461,6 +479,7 @@ int     var_line_limit = 2048;
 
 int     main(int unused_argc, char **used_argv)
 {
+    VSTRING *data_val = vstring_alloc(1);
     VSTRING *str_val = vstring_alloc(1);
     HTABLE *table = htable_create(1);
     HTABLE_INFO **ht_info_list;
@@ -476,11 +495,13 @@ int     main(int unused_argc, char **used_argv)
                           ATTR_TYPE_NUM, ATTR_NAME_NUM, &int_val,
                           ATTR_TYPE_LONG, ATTR_NAME_LONG, &long_val,
                           ATTR_TYPE_STR, ATTR_NAME_STR, str_val,
+                          ATTR_TYPE_DATA, ATTR_NAME_DATA, data_val,
                           ATTR_TYPE_HASH, table,
-                          ATTR_TYPE_END)) > 3) {
+                          ATTR_TYPE_END)) > 4) {
        vstream_printf("%s %d\n", ATTR_NAME_NUM, int_val);
        vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val);
        vstream_printf("%s %s\n", ATTR_NAME_STR, STR(str_val));
+       vstream_printf("%s %s\n", ATTR_NAME_DATA, STR(data_val));
        ht_info_list = htable_list(table);
        for (ht = ht_info_list; *ht; ht++)
            vstream_printf("(hash) %s %s\n", ht[0]->key, ht[0]->value);
@@ -493,10 +514,12 @@ int     main(int unused_argc, char **used_argv)
                           ATTR_TYPE_NUM, ATTR_NAME_NUM, &int_val,
                           ATTR_TYPE_LONG, ATTR_NAME_LONG, &long_val,
                           ATTR_TYPE_STR, ATTR_NAME_STR, str_val,
-                          ATTR_TYPE_END)) == 3) {
+                          ATTR_TYPE_DATA, ATTR_NAME_DATA, data_val,
+                          ATTR_TYPE_END)) == 4) {
        vstream_printf("%s %d\n", ATTR_NAME_NUM, int_val);
        vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val);
        vstream_printf("%s %s\n", ATTR_NAME_STR, STR(str_val));
+       vstream_printf("%s %s\n", ATTR_NAME_DATA, STR(data_val));
        ht_info_list = htable_list(table);
        for (ht = ht_info_list; *ht; ht++)
            vstream_printf("(hash) %s %s\n", ht[0]->key, ht[0]->value);
index 1b3a01581cfbe5822f4cdf7a000531c4248b4326..0f1915bc74172cdf2caa6b64a95dfcb919ed4531 100644 (file)
@@ -1,11 +1,13 @@
 ./attr_print64: send attr number = 4711
 ./attr_print64: send attr long_number = 1234
 ./attr_print64: send attr string = whoopee
+./attr_print64: send attr data = [data 7 bytes]
 ./attr_print64: send attr name foo-name value foo-value
 ./attr_print64: send attr name bar-name value bar-value
 ./attr_print64: send attr number = 4711
 ./attr_print64: send attr long_number = 1234
 ./attr_print64: send attr string = whoopee
+./attr_print64: send attr data = [data 7 bytes]
 ./attr_scan64: unknown_stream: wanted attribute: number
 ./attr_scan64: input attribute name: number
 ./attr_scan64: input attribute value: 4711
@@ -15,6 +17,9 @@
 ./attr_scan64: unknown_stream: wanted attribute: string
 ./attr_scan64: input attribute name: string
 ./attr_scan64: input attribute value: whoopee
+./attr_scan64: unknown_stream: wanted attribute: data
+./attr_scan64: input attribute name: data
+./attr_scan64: input attribute value: whoopee
 ./attr_scan64: unknown_stream: wanted attribute: (any attribute name or list terminator)
 ./attr_scan64: input attribute name: foo-name
 ./attr_scan64: input attribute value: foo-value
 ./attr_scan64: unknown_stream: wanted attribute: string
 ./attr_scan64: input attribute name: string
 ./attr_scan64: input attribute value: whoopee
+./attr_scan64: unknown_stream: wanted attribute: data
+./attr_scan64: input attribute name: data
+./attr_scan64: input attribute value: whoopee
 ./attr_scan64: unknown_stream: wanted attribute: (list terminator)
 ./attr_scan64: input attribute name: (end)
 number 4711
 long_number 1234
 string whoopee
+data whoopee
 (hash) foo-name foo-value
 (hash) bar-name bar-value
 number 4711
 long_number 1234
 string whoopee
+data whoopee
 (hash) foo-name foo-value
 (hash) bar-name bar-value
index 5793dac67feecd2f7a54a679ded9baec7bef2bf7..ba2be79703b38c61d38a7bf556d9fa7b23190bc7 100644 (file)
@@ -91,6 +91,8 @@
 /*     This argument is followed by an attribute name and a long pointer.
 /* .IP "ATTR_TYPE_STR (char *, VSTRING *)"
 /*     This argument is followed by an attribute name and a VSTRING pointer.
+/* .IP "ATTR_TYPE_DATA (char *, VSTRING *)"
+/*     This argument is followed by an attribute name and a VSTRING pointer.
 /* .IP "ATTR_TYPE_HASH (HTABLE *)"
 /* .IP "ATTR_TYPE_NAMEVAL (NVTABLE *)"
 /*     All further input attributes are processed as string attributes.
 #include <vstream.h>
 #include <vstring.h>
 #include <htable.h>
+#include <base64_code.h>
 #include <attr.h>
 
 /* Application specific. */
@@ -168,7 +171,7 @@ static int attr_scan_plain_string(VSTREAM *fp, VSTRING *plain_buf,
 
     VSTRING_RESET(plain_buf);
     while ((ch = VSTREAM_GETC(fp)) != '\n'
-       && (terminator == 0 || ch != terminator)) {
+          && (terminator == 0 || ch != terminator)) {
        if (ch == VSTREAM_EOF) {
            msg_warn("%s on %s while reading %s",
                vstream_ftimeout(fp) ? "timeout" : "premature end-of-input",
@@ -191,6 +194,27 @@ static int attr_scan_plain_string(VSTREAM *fp, VSTRING *plain_buf,
     return (ch);
 }
 
+/* attr_scan_plain_data - pull a data blob from the input stream */
+
+static int attr_scan_plain_data(VSTREAM *fp, VSTRING *str_buf,
+                                       int terminator,
+                                       const char *context)
+{
+    static VSTRING *base64_buf = 0;
+    int     ch;
+
+    if (base64_buf == 0)
+       base64_buf = vstring_alloc(10);
+    if ((ch = attr_scan_plain_string(fp, base64_buf, terminator, context)) < 0)
+       return (-1);
+    if (base64_decode(str_buf, STR(base64_buf), LEN(base64_buf)) == 0) {
+       msg_warn("malformed base64 data from %s while reading %s: %.100s",
+                VSTREAM_PATH(fp), context, STR(base64_buf));
+       return (-1);
+    }
+    return (ch);
+}
+
 /* attr_scan_plain_number - pull a number from the input stream */
 
 static int attr_scan_plain_number(VSTREAM *fp, unsigned *ptr, VSTRING *str_buf,
@@ -364,7 +388,7 @@ int     attr_vscan_plain(VSTREAM *fp, int flags, va_list ap)
            }
            long_number = va_arg(ap, unsigned long *);
            if ((ch = attr_scan_plain_long_number(fp, long_number, str_buf,
-                                       0, "input attribute value")) < 0)
+                                          0, "input attribute value")) < 0)
                return (-1);
            break;
        case ATTR_TYPE_STR:
@@ -378,6 +402,17 @@ int     attr_vscan_plain(VSTREAM *fp, int flags, va_list ap)
                                             "input attribute value")) < 0)
                return (-1);
            break;
+       case ATTR_TYPE_DATA:
+           if (ch != '=') {
+               msg_warn("missing value for data attribute %s from %s",
+                        STR(name_buf), VSTREAM_PATH(fp));
+               return (-1);
+           }
+           string = va_arg(ap, VSTRING *);
+           if ((ch = attr_scan_plain_data(fp, string, 0,
+                                          "input attribute value")) < 0)
+               return (-1);
+           break;
        case ATTR_TYPE_HASH:
            if (ch != '=') {
                msg_warn("missing value for string attribute %s from %s",
@@ -433,6 +468,7 @@ int     var_line_limit = 2048;
 
 int     main(int unused_argc, char **used_argv)
 {
+    VSTRING *data_val = vstring_alloc(1);
     VSTRING *str_val = vstring_alloc(1);
     HTABLE *table = htable_create(1);
     HTABLE_INFO **ht_info_list;
@@ -448,11 +484,13 @@ int     main(int unused_argc, char **used_argv)
                               ATTR_TYPE_NUM, ATTR_NAME_NUM, &int_val,
                               ATTR_TYPE_LONG, ATTR_NAME_LONG, &long_val,
                               ATTR_TYPE_STR, ATTR_NAME_STR, str_val,
+                              ATTR_TYPE_DATA, ATTR_NAME_DATA, data_val,
                               ATTR_TYPE_HASH, table,
-                              ATTR_TYPE_END)) > 3) {
+                              ATTR_TYPE_END)) > 4) {
        vstream_printf("%s %d\n", ATTR_NAME_NUM, int_val);
        vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val);
        vstream_printf("%s %s\n", ATTR_NAME_STR, STR(str_val));
+       vstream_printf("%s %s\n", ATTR_NAME_DATA, STR(data_val));
        ht_info_list = htable_list(table);
        for (ht = ht_info_list; *ht; ht++)
            vstream_printf("(hash) %s %s\n", ht[0]->key, ht[0]->value);
@@ -465,10 +503,12 @@ int     main(int unused_argc, char **used_argv)
                               ATTR_TYPE_NUM, ATTR_NAME_NUM, &int_val,
                               ATTR_TYPE_LONG, ATTR_NAME_LONG, &long_val,
                               ATTR_TYPE_STR, ATTR_NAME_STR, str_val,
-                              ATTR_TYPE_END)) == 3) {
+                              ATTR_TYPE_DATA, ATTR_NAME_DATA, data_val,
+                              ATTR_TYPE_END)) == 4) {
        vstream_printf("%s %d\n", ATTR_NAME_NUM, int_val);
        vstream_printf("%s %ld\n", ATTR_NAME_LONG, long_val);
        vstream_printf("%s %s\n", ATTR_NAME_STR, STR(str_val));
+       vstream_printf("%s %s\n", ATTR_NAME_DATA, STR(data_val));
        ht_info_list = htable_list(table);
        for (ht = ht_info_list; *ht; ht++)
            vstream_printf("(hash) %s %s\n", ht[0]->key, ht[0]->value);
index 68aa7d17f931aab193673042a6b0ccd8c3b1478a..eee95eb546466b5298a1a744fbad62bdd12a7a20 100644 (file)
@@ -1,11 +1,13 @@
 ./attr_print_plain: send attr number = 4711
 ./attr_print_plain: send attr long_number = 1234
 ./attr_print_plain: send attr string = whoopee
+./attr_print_plain: send attr data = [data 7 bytes]
 ./attr_print_plain: send attr name foo-name value foo-value
 ./attr_print_plain: send attr name bar-name value bar-value
 ./attr_print_plain: send attr number = 4711
 ./attr_print_plain: send attr long_number = 1234
 ./attr_print_plain: send attr string = whoopee
+./attr_print_plain: send attr data = [data 7 bytes]
 ./attr_scan_plain: unknown_stream: wanted attribute: number
 ./attr_scan_plain: input attribute name: number
 ./attr_scan_plain: input attribute value: 4711
@@ -15,6 +17,9 @@
 ./attr_scan_plain: unknown_stream: wanted attribute: string
 ./attr_scan_plain: input attribute name: string
 ./attr_scan_plain: input attribute value: whoopee
+./attr_scan_plain: unknown_stream: wanted attribute: data
+./attr_scan_plain: input attribute name: data
+./attr_scan_plain: input attribute value: d2hvb3BlZQ==
 ./attr_scan_plain: unknown_stream: wanted attribute: (any attribute name or list terminator)
 ./attr_scan_plain: input attribute name: foo-name
 ./attr_scan_plain: input attribute value: foo-value
 ./attr_scan_plain: unknown_stream: wanted attribute: string
 ./attr_scan_plain: input attribute name: string
 ./attr_scan_plain: input attribute value: whoopee
+./attr_scan_plain: unknown_stream: wanted attribute: data
+./attr_scan_plain: input attribute name: data
+./attr_scan_plain: input attribute value: d2hvb3BlZQ==
 ./attr_scan_plain: unknown_stream: wanted attribute: (list terminator)
 ./attr_scan_plain: input attribute name: (end)
 number 4711
 long_number 1234
 string whoopee
+data whoopee
 (hash) foo-name foo-value
 (hash) bar-name bar-value
 number 4711
 long_number 1234
 string whoopee
+data whoopee
 (hash) foo-name foo-value
 (hash) bar-name bar-value
index 4322add0344ed406b4bc2ffb528b564c196e3148..acdaf4e414acae4602296e9e95f79c1944b65368 100644 (file)
 typedef struct {
     DICT    dict;                      /* generic members */
     DB     *db;                                /* open db file */
+#if DB_VERSION_MAJOR > 1
+    DBC    *cursor;                    /* dict_db_sequence() */
+#endif
+    VSTRING *key_buf;                  /* key result */
+    VSTRING *val_buf;                  /* value result */
 } DICT_DB;
 
+#define SCOPY(buf, data, size) \
+    vstring_str(vstring_strncpy(buf ? buf : (buf = vstring_alloc(10)), data, size))
+
  /*
   * You can override the default dict_db_cache_size setting before calling
   * dict_hash_open() or dict_btree_open(). This is done in mkmap_db_open() to
@@ -164,7 +172,6 @@ static const char *dict_db_lookup(DICT *dict, const char *name)
     DBT     db_key;
     DBT     db_value;
     int     status;
-    static VSTRING *buf;
     const char *result = 0;
 
     /*
@@ -195,7 +202,7 @@ static const char *dict_db_lookup(DICT *dict, const char *name)
            msg_fatal("error reading %s: %m", dict_db->dict.name);
        if (status == 0) {
            dict->flags &= ~DICT_FLAG_TRY0NULL;
-           result = db_value.data;
+           result = SCOPY(dict_db->val_buf, db_value.data, db_value.size);
        }
     }
 
@@ -209,11 +216,8 @@ static const char *dict_db_lookup(DICT *dict, const char *name)
        if ((status = DICT_DB_GET(db, &db_key, &db_value, 0)) < 0)
            msg_fatal("error reading %s: %m", dict_db->dict.name);
        if (status == 0) {
-           if (buf == 0)
-               buf = vstring_alloc(10);
-           vstring_strncpy(buf, db_value.data, db_value.size);
            dict->flags &= ~DICT_FLAG_TRY1NULL;
-           result = vstring_str(buf);
+           result = SCOPY(dict_db->val_buf, db_value.data, db_value.size);
        }
     }
 
@@ -373,9 +377,6 @@ static int dict_db_delete(DICT *dict, const char *name)
 static int dict_db_sequence(DICT *dict, int function,
                                    const char **key, const char **value)
 {
-#if DB_VERSION_MAJOR > 1
-    msg_fatal("dict_db_sequence - operation is to be implemented");
-#else
     char   *myname = "dict_db_sequence";
     DICT_DB *dict_db = (DICT_DB *) dict;
     DB     *db = dict_db->db;
@@ -383,8 +384,64 @@ static int dict_db_sequence(DICT *dict, int function,
     DBT     db_value;
     int     status = 0;
     int     db_function;
-    static VSTRING *key_buf;
-    static VSTRING *value_buf;
+
+#if DB_VERSION_MAJOR > 1
+
+    /*
+     * Initialize.
+     */
+    dict_errno = 0;
+    memset(&db_key, 0, sizeof(db_key));
+    memset(&db_value, 0, sizeof(db_value));
+    if (dict_db->cursor == 0)
+       db->cursor(db, NULL, &(dict_db->cursor), 0);
+
+    /*
+     * Determine the function.
+     */
+    switch (function) {
+    case DICT_SEQ_FUN_FIRST:
+       db_function = DB_FIRST;
+       break;
+    case DICT_SEQ_FUN_NEXT:
+       db_function = DB_NEXT;
+       break;
+    default:
+       msg_panic("%s: invalid function %d", myname, function);
+    }
+
+    /*
+     * Acquire a shared lock.
+     */
+    if ((dict->flags & DICT_FLAG_LOCK)
+       && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_SHARED) < 0)
+       msg_fatal("%s: lock dictionary: %m", dict_db->dict.name);
+
+    /*
+     * Database lookup.
+     */
+    status =
+       dict_db->cursor->c_get(dict_db->cursor, &db_key, &db_value, DB_NEXT);
+    if (status != 0 && status != DB_NOTFOUND)
+       msg_fatal("error [%d] seeking %s: %m", status, dict_db->dict.name);
+
+    /*
+     * Release the shared lock.
+     */
+    if ((dict->flags & DICT_FLAG_LOCK)
+       && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
+       msg_fatal("%s: unlock dictionary: %m", dict_db->dict.name);
+
+    if (status == 0) {
+
+       /*
+        * Copy the result so it is guaranteed null terminated.
+        */
+       *key = SCOPY(dict_db->key_buf, db_key.data, db_key.size);
+       *value = SCOPY(dict_db->val_buf, db_value.data, db_value.size);
+    }
+    return (status);
+#else
 
     /*
      * determine the function
@@ -401,17 +458,17 @@ static int dict_db_sequence(DICT *dict, int function,
     }
 
     /*
-     * Acquire an exclusive lock.
+     * Acquire a shared lock.
      */
     if ((dict->flags & DICT_FLAG_LOCK)
-       && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0)
+       && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_SHARED) < 0)
        msg_fatal("%s: lock dictionary: %m", dict_db->dict.name);
 
     if ((status = db->seq(db, &db_key, &db_value, db_function)) < 0)
        msg_fatal("error seeking %s: %m", dict_db->dict.name);
 
     /*
-     * Release the exclusive lock.
+     * Release the shared lock.
      */
     if ((dict->flags & DICT_FLAG_LOCK)
        && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
@@ -420,25 +477,10 @@ static int dict_db_sequence(DICT *dict, int function,
     if (status == 0) {
 
        /*
-        * See if this DB file was written with one null byte appended to key
-        * and value or not.
+        * Copy the result so that it is guaranteed null terminated.
         */
-       if (((char *) db_key.data)[db_key.size] == 0) {
-           *key = db_key.data;
-       } else {
-           if (key_buf == 0)
-               key_buf = vstring_alloc(10);
-           vstring_strncpy(key_buf, db_key.data, db_key.size);
-           *key = vstring_str(key_buf);
-       }
-       if (((char *) db_value.data)[db_value.size] == 0) {
-           *value = db_value.data;
-       } else {
-           if (value_buf == 0)
-               value_buf = vstring_alloc(10);
-           vstring_strncpy(value_buf, db_value.data, db_value.size);
-           *value = vstring_str(value_buf);
-       }
+       *key = SCOPY(dict_db->key_buf, db_key.data, db_key.size);
+       *value = SCOPY(dict_db->val_buf, db_value.data, db_value.size);
     }
     return status;
 #endif
@@ -450,10 +492,18 @@ static void dict_db_close(DICT *dict)
 {
     DICT_DB *dict_db = (DICT_DB *) dict;
 
+#if DB_VERSION_MAJOR > 1
+    if (dict_db->cursor)
+       dict_db->cursor->c_close(dict_db->cursor);
+#endif
     if (DICT_DB_SYNC(dict_db->db, 0) < 0)
        msg_fatal("flush database %s: %m", dict_db->dict.name);
     if (DICT_DB_CLOSE(dict_db->db) < 0)
        msg_fatal("close database %s: %m", dict_db->dict.name);
+    if (dict_db->key_buf)
+       vstring_free(dict_db->key_buf);
+    if (dict_db->val_buf)
+       vstring_free(dict_db->val_buf);
     dict_free(dict);
 }
 
@@ -612,6 +662,12 @@ static DICT *dict_db_open(const char *class, const char *path, int open_flags,
     if ((dict_flags & (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL)) == 0)
        dict_db->dict.flags |= (DICT_FLAG_TRY1NULL | DICT_FLAG_TRY0NULL);
     dict_db->db = db;
+#if DB_VERSION_MAJOR > 1
+    dict_db->cursor = 0;
+#endif
+    dict_db->key_buf = 0;
+    dict_db->val_buf = 0;
+
     myfree(db_path);
     return (DICT_DEBUG (&dict_db->dict));
 }
index a1e326fb99455a23a8802ca303a2e0aa3d2a01cf..fa58ad004316417d01d86d61a1c211a856b9bed7 100644 (file)
 typedef struct {
     DICT    dict;                      /* generic members */
     DBM    *dbm;                       /* open database */
+    VSTRING *key_buf;                  /* key buffer */
+    VSTRING *val_buf;                  /* result buffer */
 } DICT_DBM;
 
+#define SCOPY(buf, data, size) \
+    vstring_str(vstring_strncpy(buf ? buf : (buf = vstring_alloc(10)), data, size))
+
 /* dict_dbm_lookup - find database entry */
 
 static const char *dict_dbm_lookup(DICT *dict, const char *name)
@@ -75,7 +80,6 @@ static const char *dict_dbm_lookup(DICT *dict, const char *name)
     DICT_DBM *dict_dbm = (DICT_DBM *) dict;
     datum   dbm_key;
     datum   dbm_value;
-    static VSTRING *buf;
     const char *result = 0;
 
     /*
@@ -103,7 +107,7 @@ static const char *dict_dbm_lookup(DICT *dict, const char *name)
        dbm_value = dbm_fetch(dict_dbm->dbm, dbm_key);
        if (dbm_value.dptr != 0) {
            dict->flags &= ~DICT_FLAG_TRY0NULL;
-           result = dbm_value.dptr;
+           result = SCOPY(dict_dbm->val_buf, dbm_value.dptr, dbm_value.dsize);
        }
     }
 
@@ -116,11 +120,8 @@ static const char *dict_dbm_lookup(DICT *dict, const char *name)
        dbm_key.dsize = strlen(name);
        dbm_value = dbm_fetch(dict_dbm->dbm, dbm_key);
        if (dbm_value.dptr != 0) {
-           if (buf == 0)
-               buf = vstring_alloc(10);
-           vstring_strncpy(buf, dbm_value.dptr, dbm_value.dsize);
            dict->flags &= ~DICT_FLAG_TRY1NULL;
-           result = vstring_str(buf);
+           result = SCOPY(dict_dbm->val_buf, dbm_value.dptr, dbm_value.dsize);
        }
     }
 
@@ -281,14 +282,12 @@ static int dict_dbm_sequence(DICT *dict, int function,
     datum   dbm_key;
     datum   dbm_value;
     int     status = 0;
-    static VSTRING *key_buf;
-    static VSTRING *value_buf;
 
     /*
-     * Acquire an exclusive lock.
+     * Acquire a shared lock.
      */
     if ((dict->flags & DICT_FLAG_LOCK)
-       && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0)
+       && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_SHARED) < 0)
        msg_fatal("%s: lock dictionary: %m", dict_dbm->dict.name);
 
     /*
@@ -306,7 +305,7 @@ static int dict_dbm_sequence(DICT *dict, int function,
     }
 
     /*
-     * Release the exclusive lock.
+     * Release the shared lock.
      */
     if ((dict->flags & DICT_FLAG_LOCK)
        && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
@@ -315,17 +314,9 @@ static int dict_dbm_sequence(DICT *dict, int function,
     if (dbm_key.dptr != 0 && dbm_key.dsize > 0) {
 
        /*
-        * See if this DB file was written with one null byte appended to key
-        * an d value or not. If necessary, copy the key.
+        * Copy the key so that it is guaranteed null terminated.
         */
-       if (((char *) dbm_key.dptr)[dbm_key.dsize - 1] == 0) {
-           *key = dbm_key.dptr;
-       } else {
-           if (key_buf == 0)
-               key_buf = vstring_alloc(10);
-           vstring_strncpy(key_buf, dbm_key.dptr, dbm_key.dsize);
-           *key = vstring_str(key_buf);
-       }
+       *key = SCOPY(dict_dbm->key_buf, dbm_key.dptr, dbm_key.dsize);
 
        /*
         * Fetch the corresponding value.
@@ -335,17 +326,9 @@ static int dict_dbm_sequence(DICT *dict, int function,
        if (dbm_value.dptr != 0 && dbm_value.dsize > 0) {
 
            /*
-            * See if this DB file was written with one null byte appended to
-            * key and value or not. If necessary, copy the key.
+            * Copy the value so that it is guaranteed null terminated.
             */
-           if (((char *) dbm_value.dptr)[dbm_value.dsize - 1] == 0) {
-               *value = dbm_value.dptr;
-           } else {
-               if (value_buf == 0)
-                   value_buf = vstring_alloc(10);
-               vstring_strncpy(value_buf, dbm_value.dptr, dbm_value.dsize);
-               *value = vstring_str(value_buf);
-           }
+           *value = SCOPY(dict_dbm->val_buf, dbm_value.dptr, dbm_value.dsize);
        } else {
 
            /*
@@ -376,6 +359,10 @@ static void dict_dbm_close(DICT *dict)
     DICT_DBM *dict_dbm = (DICT_DBM *) dict;
 
     dbm_close(dict_dbm->dbm);
+    if (dict_dbm->key_buf)
+       vstring_free(dict_dbm->key_buf);
+    if (dict_dbm->val_buf)
+       vstring_free(dict_dbm->val_buf);
     dict_free(dict);
 }
 
@@ -446,6 +433,8 @@ DICT   *dict_dbm_open(const char *path, int open_flags, int dict_flags)
     if ((dict_flags & (DICT_FLAG_TRY0NULL | DICT_FLAG_TRY1NULL)) == 0)
        dict_dbm->dict.flags |= (DICT_FLAG_TRY0NULL | DICT_FLAG_TRY1NULL);
     dict_dbm->dbm = dbm;
+    dict_dbm->key_buf = 0;
+    dict_dbm->val_buf = 0;
 
     if ((dict_flags & DICT_FLAG_LOCK))
        myfree(dbm_path);
index 66919c8358b30ea7c9c50a6c0de1f5b67dfafff5..008d3becbbf8ec0a16a2cb6b90d122edf681b2c3 100644 (file)
 #include <dict_env.h>
 #include <dict_unix.h>
 #include <dict_tcp.h>
+#include <dict_sdbm.h>
 #include <dict_dbm.h>
 #include <dict_db.h>
 #include <dict_nis.h>
@@ -198,6 +199,9 @@ static DICT_OPEN_INFO dict_open_info[] = {
 #ifdef SNAPSHOT
     DICT_TYPE_TCP, dict_tcp_open,
 #endif
+#ifdef HAS_SDBM
+    DICT_TYPE_SDBM, dict_sdbm_open,
+#endif
 #ifdef HAS_DBM
     DICT_TYPE_DBM, dict_dbm_open,
 #endif
diff --git a/postfix/src/util/dict_sdbm.c b/postfix/src/util/dict_sdbm.c
new file mode 100644 (file)
index 0000000..d123fcf
--- /dev/null
@@ -0,0 +1,414 @@
+/*++
+/* NAME
+/*     dict_sdbm 3
+/* SUMMARY
+/*     dictionary manager interface to SDBM files
+/* SYNOPSIS
+/*     #include <dict_sdbm.h>
+/*
+/*     DICT    *dict_sdbm_open(path, open_flags, dict_flags)
+/*     const char *name;
+/*     const char *path;
+/*     int     open_flags;
+/*     int     dict_flags;
+/* DESCRIPTION
+/*     dict_sdbm_open() opens the named SDBM database and makes it available
+/*     via the generic interface described in dict_open(3).
+/* DIAGNOSTICS
+/*     Fatal errors: cannot open file, file write error, out of memory.
+/* SEE ALSO
+/*     dict(3) generic dictionary manager
+/*     sdbm(3) data base subroutines
+/* 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
+/*--*/
+
+#include "sys_defs.h"
+
+/* System library. */
+
+#include <sys/stat.h>
+#include <string.h>
+#include <unistd.h>
+#ifdef HAS_SDBM
+#include <sdbm.h>
+#endif
+
+/* Utility library. */
+
+#include <msg.h>
+#include <mymalloc.h>
+#include <htable.h>
+#include <iostuff.h>
+#include <vstring.h>
+#include <myflock.h>
+#include <stringops.h>
+#include <dict.h>
+#include <dict_sdbm.h>
+
+#ifdef HAS_SDBM
+
+/* Application-specific. */
+
+typedef struct {
+    DICT    dict;                      /* generic members */
+    SDBM   *dbm;                       /* open database */
+    char   *path;                      /* pathname */
+} DICT_SDBM;
+
+/* dict_sdbm_lookup - find database entry */
+
+static const char *dict_sdbm_lookup(DICT *dict, const char *name)
+{
+    DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict;
+    datum   dbm_key;
+    datum   dbm_value;
+    static VSTRING *buf;
+    const char *result = 0;
+
+    dict_errno = 0;
+
+    /*
+     * Acquire an exclusive lock.
+     */
+    if ((dict->flags & DICT_FLAG_LOCK)
+       && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_SHARED) < 0)
+       msg_fatal("%s: lock dictionary: %m", dict_sdbm->path);
+
+    /*
+     * See if this DBM file was written with one null byte appended to key
+     * and value.
+     */
+    if (dict->flags & DICT_FLAG_TRY1NULL) {
+       dbm_key.dptr = (void *) name;
+       dbm_key.dsize = strlen(name) + 1;
+       dbm_value = sdbm_fetch(dict_sdbm->dbm, dbm_key);
+       if (dbm_value.dptr != 0) {
+           dict->flags &= ~DICT_FLAG_TRY0NULL;
+           result = dbm_value.dptr;
+       }
+    }
+
+    /*
+     * See if this DBM file was written with no null byte appended to key and
+     * value.
+     */
+    if (result == 0 && (dict->flags & DICT_FLAG_TRY0NULL)) {
+       dbm_key.dptr = (void *) name;
+       dbm_key.dsize = strlen(name);
+       dbm_value = sdbm_fetch(dict_sdbm->dbm, dbm_key);
+       if (dbm_value.dptr != 0) {
+           if (buf == 0)
+               buf = vstring_alloc(10);
+           vstring_strncpy(buf, dbm_value.dptr, dbm_value.dsize);
+           dict->flags &= ~DICT_FLAG_TRY1NULL;
+           result = vstring_str(buf);
+       }
+    }
+
+    /*
+     * Release the exclusive lock.
+     */
+    if ((dict->flags & DICT_FLAG_LOCK)
+       && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
+       msg_fatal("%s: unlock dictionary: %m", dict_sdbm->path);
+
+    return (result);
+}
+
+/* dict_sdbm_update - add or update database entry */
+
+static void dict_sdbm_update(DICT *dict, const char *name, const char *value)
+{
+    DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict;
+    datum   dbm_key;
+    datum   dbm_value;
+    int     status;
+
+    dbm_key.dptr = (void *) name;
+    dbm_value.dptr = (void *) value;
+    dbm_key.dsize = strlen(name);
+    dbm_value.dsize = strlen(value);
+
+    /*
+     * If undecided about appending a null byte to key and value, choose a
+     * default depending on the platform.
+     */
+    if ((dict->flags & DICT_FLAG_TRY1NULL)
+       && (dict->flags & DICT_FLAG_TRY0NULL)) {
+#ifdef DBM_NO_TRAILING_NULL
+       dict->flags &= ~DICT_FLAG_TRY1NULL;
+#else
+       dict->flags &= ~DICT_FLAG_TRY0NULL;
+#endif
+    }
+
+    /*
+     * Optionally append a null byte to key and value.
+     */
+    if (dict->flags & DICT_FLAG_TRY1NULL) {
+       dbm_key.dsize++;
+       dbm_value.dsize++;
+    }
+
+    /*
+     * Acquire an exclusive lock.
+     */
+    if ((dict->flags & DICT_FLAG_LOCK)
+       && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0)
+       msg_fatal("%s: lock dictionary: %m", dict_sdbm->path);
+
+    /*
+     * Do the update.
+     */
+    if ((status = sdbm_store(dict_sdbm->dbm, dbm_key, dbm_value,
+     (dict->flags & DICT_FLAG_DUP_REPLACE) ? DBM_REPLACE : DBM_INSERT)) < 0)
+       msg_fatal("error writing SDBM database %s: %m", dict_sdbm->path);
+    if (status) {
+       if (dict->flags & DICT_FLAG_DUP_IGNORE)
+            /* void */ ;
+       else if (dict->flags & DICT_FLAG_DUP_WARN)
+           msg_warn("%s: duplicate entry: \"%s\"", dict_sdbm->path, name);
+       else
+           msg_fatal("%s: duplicate entry: \"%s\"", dict_sdbm->path, name);
+    }
+
+    /*
+     * Release the exclusive lock.
+     */
+    if ((dict->flags & DICT_FLAG_LOCK)
+       && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
+       msg_fatal("%s: unlock dictionary: %m", dict_sdbm->path);
+}
+
+
+/* dict_sdbm_delete - delete one entry from the dictionary */
+
+static int dict_sdbm_delete(DICT *dict, const char *name)
+{
+    DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict;
+    datum   dbm_key;
+    int     status = 1;
+    int     flags = 0;
+
+    /*
+     * Acquire an exclusive lock.
+     */
+    if ((dict->flags & DICT_FLAG_LOCK)
+       && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0)
+       msg_fatal("%s: lock dictionary: %m", dict_sdbm->path);
+
+    /*
+     * See if this DBM file was written with one null byte appended to key
+     * and value.
+     */
+    if (dict->flags & DICT_FLAG_TRY1NULL) {
+       dbm_key.dptr = (void *) name;
+       dbm_key.dsize = strlen(name) + 1;
+       sdbm_clearerr(dict_sdbm->dbm);
+       if ((status = sdbm_delete(dict_sdbm->dbm, dbm_key)) < 0) {
+           if (sdbm_error(dict_sdbm->dbm) != 0)        /* fatal error */
+               msg_fatal("error deleting from %s: %m", dict_sdbm->path);
+           status = 1;                         /* not found */
+       } else {
+           dict->flags &= ~DICT_FLAG_TRY0NULL; /* found */
+       }
+    }
+
+    /*
+     * See if this DBM file was written with no null byte appended to key and
+     * value.
+     */
+    if (status > 0 && (dict->flags & DICT_FLAG_TRY0NULL)) {
+       dbm_key.dptr = (void *) name;
+       dbm_key.dsize = strlen(name);
+       sdbm_clearerr(dict_sdbm->dbm);
+       if ((status = sdbm_delete(dict_sdbm->dbm, dbm_key)) < 0) {
+           if (sdbm_error(dict_sdbm->dbm) != 0)        /* fatal error */
+               msg_fatal("error deleting from %s: %m", dict_sdbm->path);
+           status = 1;                         /* not found */
+       } else {
+           dict->flags &= ~DICT_FLAG_TRY1NULL; /* found */
+       }
+    }
+
+    /*
+     * Release the exclusive lock.
+     */
+    if ((dict->flags & DICT_FLAG_LOCK)
+       && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
+       msg_fatal("%s: unlock dictionary: %m", dict_sdbm->path);
+
+    return (status);
+}
+
+/* traverse the dictionary */
+
+static int dict_sdbm_sequence(DICT *dict, const int function,
+                                    const char **key, const char **value)
+{
+    char   *myname = "dict_sdbm_sequence";
+    DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict;
+    datum   dbm_key;
+    datum   dbm_value;
+    int     status = 0;
+    static VSTRING *key_buf;
+    static VSTRING *value_buf;
+
+    /*
+     * Acquire a shared lock.
+     */
+    if ((dict->flags & DICT_FLAG_LOCK)
+       && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_SHARED) < 0)
+       msg_fatal("%s: lock dictionary: %m", dict_sdbm->path);
+
+    /*
+     * Determine and execute the seek function. It returns the key.
+     */
+    switch (function) {
+    case DICT_SEQ_FUN_FIRST:
+       dbm_key = sdbm_firstkey(dict_sdbm->dbm);
+       break;
+    case DICT_SEQ_FUN_NEXT:
+       dbm_key = sdbm_nextkey(dict_sdbm->dbm);
+       break;
+    default:
+       msg_panic("%s: invalid function: %d", myname, function);
+    }
+
+    /*
+     * Release the shared lock.
+     */
+    if ((dict->flags & DICT_FLAG_LOCK)
+       && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
+       msg_fatal("%s: unlock dictionary: %m", dict_sdbm->path);
+
+    if (dbm_key.dptr != 0 && dbm_key.dsize > 0) {
+
+       /*
+        * See if this DB file was written with one null byte appended to key
+        * and value or not. If necessary, copy the key.
+        */
+       if (((char *) dbm_key.dptr)[dbm_key.dsize - 1] == 0) {
+           *key = dbm_key.dptr;
+       } else {
+           if (key_buf == 0)
+               key_buf = vstring_alloc(10);
+           vstring_strncpy(key_buf, dbm_key.dptr, dbm_key.dsize);
+           *key = vstring_str(key_buf);
+       }
+
+       /*
+        * Fetch the corresponding value.
+        */
+       dbm_value = sdbm_fetch(dict_sdbm->dbm, dbm_key);
+
+       if (dbm_value.dptr != 0 && dbm_value.dsize > 0) {
+
+           /*
+            * See if this DB file was written with one null byte appended to
+            * key and value or not. If necessary, copy the key.
+            */
+           if (((char *) dbm_value.dptr)[dbm_value.dsize - 1] == 0) {
+               *value = dbm_value.dptr;
+           } else {
+               if (value_buf == 0)
+                   value_buf = vstring_alloc(10);
+               vstring_strncpy(value_buf, dbm_value.dptr, dbm_value.dsize);
+               *value = vstring_str(value_buf);
+           }
+       } else {
+
+           /*
+            * Determine if we have hit the last record or an error
+            * condition.
+            */
+           if (sdbm_error(dict_sdbm->dbm))
+               msg_fatal("error seeking %s: %m", dict_sdbm->path);
+           return (1);                         /* no error: eof/not found
+                                                * (should not happen!) */
+       }
+    } else {
+
+       /*
+        * Determine if we have hit the last record or an error condition.
+        */
+       if (sdbm_error(dict_sdbm->dbm))
+           msg_fatal("error seeking %s: %m", dict_sdbm->path);
+       return (1);                             /* no error: eof/not found */
+    }
+    return (0);
+}
+
+/* dict_sdbm_close - disassociate from data base */
+
+static void dict_sdbm_close(DICT *dict)
+{
+    DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict;
+
+    sdbm_close(dict_sdbm->dbm);
+    myfree(dict_sdbm->path);
+    myfree((char *) dict_sdbm);
+}
+
+/* dict_sdbm_open - open SDBM data base */
+
+DICT   *dict_sdbm_open(const char *path, int open_flags, int dict_flags)
+{
+    DICT_SDBM *dict_sdbm;
+    struct stat st;
+    SDBM   *dbm;
+    char   *dbm_path;
+    int     lock_fd;
+
+    if (dict_flags & DICT_FLAG_LOCK) {
+       dbm_path = concatenate(path, ".pag", (char *) 0);
+       if ((lock_fd = open(dbm_path, open_flags, 0644)) < 0)
+           msg_fatal("open database %s: %m", dbm_path);
+       if (myflock(lock_fd, INTERNAL_LOCK, MYFLOCK_OP_SHARED) < 0)
+           msg_fatal("shared-lock database %s for open: %m", dbm_path);
+    }
+
+    /*
+     * XXX sdbm_open() has no const in prototype.
+     */
+    if ((dbm = sdbm_open((char *) path, open_flags, 0644)) == 0)
+       msg_fatal("open database %s.{dir,pag}: %m", path);
+
+    if (dict_flags & DICT_FLAG_LOCK) {
+       if (myflock(lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0)
+           msg_fatal("unlock database %s for open: %m", dbm_path);
+       if (close(lock_fd) < 0)
+           msg_fatal("close database %s: %m", dbm_path);
+       myfree(dbm_path);
+    }
+    dict_sdbm = (DICT_SDBM *) mymalloc(sizeof(*dict_sdbm));
+    dict_sdbm->dict.lookup = dict_sdbm_lookup;
+    dict_sdbm->dict.update = dict_sdbm_update;
+    dict_sdbm->dict.delete = dict_sdbm_delete;
+    dict_sdbm->dict.sequence = dict_sdbm_sequence;
+    dict_sdbm->dict.close = dict_sdbm_close;
+    dict_sdbm->dict.lock_fd = sdbm_dirfno(dbm);
+    dict_sdbm->dict.stat_fd = sdbm_pagfno(dbm);
+    if (fstat(dict_sdbm->dict.stat_fd, &st) < 0)
+       msg_fatal("dict_sdbm_open: fstat: %m");
+    dict_sdbm->dict.mtime = st.st_mtime;
+    close_on_exec(sdbm_pagfno(dbm), CLOSE_ON_EXEC);
+    close_on_exec(sdbm_dirfno(dbm), CLOSE_ON_EXEC);
+    dict_sdbm->dict.flags = dict_flags | DICT_FLAG_FIXED;
+    if ((dict_flags & (DICT_FLAG_TRY0NULL | DICT_FLAG_TRY1NULL)) == 0)
+       dict_sdbm->dict.flags |= (DICT_FLAG_TRY0NULL | DICT_FLAG_TRY1NULL);
+    dict_sdbm->dbm = dbm;
+    dict_sdbm->path = mystrdup(path);
+
+    return (&dict_sdbm->dict);
+}
+
+#endif
diff --git a/postfix/src/util/dict_sdbm.h b/postfix/src/util/dict_sdbm.h
new file mode 100644 (file)
index 0000000..6a1b281
--- /dev/null
@@ -0,0 +1,37 @@
+#ifndef _DICT_SDBM_H_INCLUDED_
+#define _DICT_SDBM_H_INCLUDED_
+
+/*++
+/* NAME
+/*     dict_dbm 3h
+/* SUMMARY
+/*     dictionary manager interface to DBM files
+/* SYNOPSIS
+/*     #include <dict_dbm.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * Utility library.
+  */
+#include <dict.h>
+
+ /*
+  * External interface.
+  */
+#define DICT_TYPE_SDBM "sdbm"
+
+extern DICT *dict_sdbm_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/src/util/hex_code.c b/postfix/src/util/hex_code.c
new file mode 100644 (file)
index 0000000..1397b58
--- /dev/null
@@ -0,0 +1,168 @@
+/*++
+/* NAME
+/*     hex_code 3
+/* SUMMARY
+/*     encode/decode data, hexadecimal style
+/* SYNOPSIS
+/*     #include <hex_code.h>
+/*
+/*     VSTRING *hex_encode(result, in, len)
+/*     VSTRING *result;
+/*     const char *in;
+/*     int     len;
+/*
+/*     VSTRING *hex_decode(result, in, len)
+/*     VSTRING *result;
+/*     const char *in;
+/*     int     len;
+/* DESCRIPTION
+/*     hex_encode() takes a block of len bytes and encodes it as one
+/*      upper-case null-terminated string.  The result value is
+/*     the result argument.
+/*
+/*     hex_decode() performs the opposite transformation on
+/*     lower-case, upper-case or mixed-case input. The result
+/*     value is the result argument. The result is null terminated,
+/*     whether or not that makes sense.
+/* DIAGNOSTICS
+/*     hex_decode() returns a null pointer when the input contains
+/*     characters not in the hexadecimal alphabet.
+/* 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>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <mymalloc.h>
+#include <vstring.h>
+#include <hex_code.h>
+
+/* Application-specific. */
+
+static const unsigned char hex_chars[] = "0123456789ABCDEF";
+
+#define UCHAR_PTR(x) ((const unsigned char *)(x))
+
+/* hex_encode - raw data to encoded */
+
+VSTRING *hex_encode(VSTRING *result, const char *in, int len)
+{
+    const unsigned char *cp;
+    int     ch;
+    int     count;
+
+    VSTRING_RESET(result);
+    for (cp = UCHAR_PTR(in), count = len; count > 0; count--, cp++) {
+       ch = *cp;
+       VSTRING_ADDCH(result, hex_chars[(ch >> 4) & 0xf]);
+       VSTRING_ADDCH(result, hex_chars[ch & 0xf]);
+    }
+    VSTRING_TERMINATE(result);
+    return (result);
+}
+
+/* hex_decode - encoded data to raw */
+
+VSTRING *hex_decode(VSTRING *result, const char *in, int len)
+{
+    const unsigned char *cp;
+    int     count;
+    unsigned int hex;
+    unsigned int bin;
+
+    VSTRING_RESET(result);
+    for (cp = UCHAR_PTR(in), count = len; count > 0; cp += 2, count -= 2) {
+       if (count < 2)
+           return (0);
+       hex = cp[0];
+       if (hex >= '0' && hex <= '9')
+           bin = (hex - '0') << 4;
+       else if (hex >= 'A' && hex <= 'F')
+           bin = (hex - 'A' + 10) << 4;
+       else if (hex >= 'a' && hex <= 'f')
+           bin = (hex - 'a' + 10) << 4;
+       else
+           return (0);
+       hex = cp[1];
+       if (hex >= '0' && hex <= '9')
+           bin |= (hex - '0') ;
+       else if (hex >= 'A' && hex <= 'F')
+           bin |= (hex - 'A' + 10) ;
+       else if (hex >= 'a' && hex <= 'f')
+           bin |= (hex - 'a' + 10) ;
+       else
+           return (0);
+       VSTRING_ADDCH(result, bin);
+    }
+    VSTRING_TERMINATE(result);
+    return (result);
+}
+
+#ifdef TEST
+
+ /*
+  * Proof-of-concept test program: convert to hexadecimal 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);
+    char   *test = "this is a test";
+
+#define DECODE(b,x,l) { \
+       if (hex_decode((b),(x),(l)) == 0) \
+           msg_panic("bad hex: %s", (x)); \
+    }
+#define VERIFY(b,t) { \
+       if (strcmp((b), (t)) != 0) \
+           msg_panic("bad test: %s", (b)); \
+    }
+
+    hex_encode(b1, test, strlen(test));
+    DECODE(b2, STR(b1), LEN(b1));
+    VERIFY(STR(b2), test);
+
+    hex_encode(b1, test, strlen(test));
+    hex_encode(b2, STR(b1), LEN(b1));
+    hex_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), test);
+
+    hex_encode(b1, test, strlen(test));
+    hex_encode(b2, STR(b1), LEN(b1));
+    hex_encode(b1, STR(b2), LEN(b2));
+    hex_encode(b2, STR(b1), LEN(b1));
+    hex_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), test);
+
+    vstring_free(b1);
+    vstring_free(b2);
+    return (0);
+}
+
+#endif
diff --git a/postfix/src/util/hex_code.h b/postfix/src/util/hex_code.h
new file mode 100644 (file)
index 0000000..d437da1
--- /dev/null
@@ -0,0 +1,36 @@
+#ifndef _HEX_CODE_H_INCLUDED_
+#define _HEX_CODE_H_INCLUDED_
+
+/*++
+/* NAME
+/*     hex_code 3h
+/* SUMMARY
+/*     encode/decode data, hexadecimal style
+/* SYNOPSIS
+/*     #include <hex_code.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * Utility library.
+ */
+#include <vstring.h>
+
+ /*
+  * External interface.
+  */
+extern VSTRING *hex_encode(VSTRING *, const char *, int);
+extern VSTRING *hex_decode(VSTRING *, const char *, 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
index 1d443961aa1ad9b28dd15460e7c219a175e0a922..ddee46102c93c1dfaab3c71b161f2fc3d509062c 100644 (file)
 #define HAS_DUPLEX_PIPE
 #endif
 
+#if __FreeBSD_version >= 220000
+#define HAS_DEV_URANDOM                        /* introduced in 2.1.5 */
+#endif
+
 #if __FreeBSD_version >= 300000
 #define HAS_ISSETUGID
 #endif
@@ -85,6 +89,7 @@
 
 #if OpenBSD >= 200000                  /* XXX */
 #define HAS_ISSETUGID
+#define HAS_DEV_URANDOM                        /* XXX probably earlier */
 #endif
 
 #if OpenBSD >= 200200                  /* XXX */
 #if __NetBSD_Version__ >= 103000000    /* XXX maybe earlier */
 #undef DEF_MAILBOX_LOCK
 #define DEF_MAILBOX_LOCK "flock, dotlock"
+#define HAS_DEV_URANDOM                        /* XXX probably earlier */
 #endif
 
 #if __NetBSD_Version__ >= 105000000    /* XXX maybe earlier */
@@ -592,6 +598,7 @@ extern int initgroups(const char *, int);
 #else
 # define CANT_WRITE_BEFORE_SENDING_FD
 #endif
+#define HAS_DEV_URANDOM                        /* introduced in 1.1 */
 #endif
 
 #ifdef LINUX1
index 14504e90de3cec325a5612102618d3bf335c3fe6..f0d2bb3665a4b02df9c20aff060643422a256795 100644 (file)
@@ -132,7 +132,7 @@ static void watchdog_event(int unused_sig)
      */
     if ((wp = watchdog_curr) == 0)
        msg_panic("%s: no instance", myname);
-    if (msg_verbose)
+    if (msg_verbose > 1)
        msg_info("%s: %p %d", myname, (void *) wp, wp->trip_run);
     if (++(wp->trip_run) < WATCHDOG_STEPS) {
        alarm(wp->timeout);
@@ -168,7 +168,7 @@ WATCHDOG *watchdog_create(unsigned timeout, WATCHDOG_FN action, char *context)
     sig_action.sa_handler = watchdog_event;
     if (sigaction(SIGALRM, &sig_action, &wp->saved_action) < 0)
        msg_fatal("%s: sigaction(SIGALRM): %m", myname);
-    if (msg_verbose)
+    if (msg_verbose > 1)
        msg_info("%s: %p %d", myname, (void *) wp, timeout);
     return (watchdog_curr = wp);
 }
@@ -186,7 +186,7 @@ void    watchdog_destroy(WATCHDOG *wp)
     if (wp->saved_time)
        alarm(wp->saved_time);
     myfree((char *) wp);
-    if (msg_verbose)
+    if (msg_verbose > 1)
        msg_info("%s: %p", myname, (void *) wp);
 }
 
@@ -200,7 +200,7 @@ void    watchdog_start(WATCHDOG *wp)
        msg_panic("%s: wrong watchdog instance", myname);
     wp->trip_run = 0;
     alarm(wp->timeout);
-    if (msg_verbose)
+    if (msg_verbose > 1)
        msg_info("%s: %p", myname, (void *) wp);
 }
 
@@ -213,7 +213,7 @@ void    watchdog_stop(WATCHDOG *wp)
     if (wp != watchdog_curr)
        msg_panic("%s: wrong watchdog instance", myname);
     alarm(0);
-    if (msg_verbose)
+    if (msg_verbose > 1)
        msg_info("%s: %p", myname, (void *) wp);
 }
 
@@ -225,7 +225,7 @@ void    watchdog_pat(void)
 
     if (watchdog_curr)
        watchdog_curr->trip_run = 0;
-    if (msg_verbose)
+    if (msg_verbose > 1)
        msg_info("%s: %p", myname, (void *) watchdog_curr);
 }
 
@@ -237,7 +237,7 @@ main(int unused_argc, char **unused_argv)
 {
     WATCHDOG *wp;
 
-    msg_verbose = 1;
+    msg_verbose = 2;
 
     wp = watchdog_create(10, (WATCHDOG_FN) 0, (char *) 0);
     watchdog_start(wp);