]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-3.10-20241025
authorWietse Z Venema <wietse@porcupine.org>
Fri, 25 Oct 2024 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <ietf-dane@dukhovni.org>
Mon, 28 Oct 2024 03:37:28 +0000 (14:37 +1100)
postfix/HISTORY
postfix/html/pgsql_table.5.html
postfix/man/man5/pgsql_table.5
postfix/proto/pgsql_table
postfix/src/global/Makefile.in
postfix/src/global/dict_pgsql.c
postfix/src/global/mail_version.h
postfix/src/util/Makefile.in
postfix/src/util/valid_uri_scheme.c [new file with mode: 0644]
postfix/src/util/valid_uri_scheme.h [new file with mode: 0644]

index 133488489fefdc2d42c874078120afeef803e317..d736e68fa5aef217dda1b7aa3b3d5ba10f289297 100644 (file)
@@ -28439,3 +28439,11 @@ Apologies for any names omitted.
        Documentation: in a pgsql: client configuration, the setting
        "dbname" is required, but ignored when the setting "hosts"
        contains an URI with a database name. File: proto/pgsql_table.
+
+20241025
+
+       Cleanup: accept any well-formed URI prefix as a pgsql: client
+       connection target (the PostgreSQL URI parser decides what
+       is allowed). The dbname setting is now optional if the hosts
+       setting specifies only URIs. Files: util/valid_uri_scheme.[hc],
+       proto/pgsql_table.
index e300bcb8d8cc271c882d33d15bbe13f0b254ee70..f55724ed9d3d45b12aedd76bbcc7aa25f2a794c6 100644 (file)
@@ -43,53 +43,64 @@ PGSQL_TABLE(5)                                                  PGSQL_TABLE(5)
 
 <b><a name="pgsql_parameters">PGSQL PARAMETERS</a></b>
        <b>hosts</b>  The hosts that Postfix will try to connect to  and  query  from.
-              Besides  a  <b>postgresql://</b>  connection URI, this setting supports
-              the historical forms <b>unix:/</b><i>pathname</i> for UNIX-domain sockets  and
+              Besides  a  PostgreSQL connection URI, this setting supports the
+              historical forms  <b>unix:/</b><i>pathname</i>  for  UNIX-domain  sockets  and
               <b>inet:</b><i>host:port</i>  for  TCP  connections, where the <b>unix:</b> and <b>inet:</b>
               prefixes are accepted and ignored for  backwards  compatibility.
               Examples:
                   hosts = postgresql://username@example.com/<i>databasename</i>?sslmode=require
+                  hosts = postgres://user:secret@localhost
                   hosts = inet:host1.some.domain inet:host2.some.domain:port
                   hosts = host1.some.domain host2.some.domain:port
                   hosts = unix:/file/name
 
-              The  hosts  are tried in random order. The connections are auto-
-              matically closed after being idle for about 1  minute,  and  are
-              re-opened as necessary.
+              See   <a href="https://www.postgresql.org/docs/current/libpq-connect.html">https://www.postgresql.org/docs/current/libpq-connect.html</a>
+              for the supported connection URI syntax.
 
-              NOTE:  if "hosts" specifies one load balancer and no alternative
-              servers, specify the load balancer multiple times in the "hosts"
-              line.  Without the duplicate info, the Postfix PostgreSQL client
-              would not reconnect immediately to the same load balancer  after
+              The hosts are tried in random order. The connections  are  auto-
+              matically  closed  after  being idle for about 1 minute, and are
+              re-opened as necessary. See <b>idle_interval</b> for details.
+
+              NOTE: if <b>hosts</b> specifies a PostgreSQL connection URI, the  Post-
+              greSQL  client  library  will ignore the <b>dbname</b> setting for that
+              connection.
+
+              NOTE: if <b>hosts</b> specifies one load balancer  and  no  alternative
+              servers,  specify  the load balancer multiple times in the <b>hosts</b>
+              line. Without the duplicate info, the Postfix PostgreSQL  client
+              would  not reconnect immediately to the same load balancer after
               a PostgreSQL server failure.
 
        <b>user</b>
 
        <b>password</b>
-              The  user name and password to log into the pgsql server.  Exam-
+              The user name and password to log into the pgsql server.   Exam-
               ple:
                   user = someone
                   password = some_password
 
-       <b>dbname</b> (required)
-              The database name on the servers. Example:
+       <b>dbname</b> The database name on the servers. Example:
                   dbname = customer_database
 
-              This setting is required, but ignored when a  postgresql://  URI
-              specifies a database name.
+              The  <b>dbname</b>  setting  is  ignored for <b>hosts</b> connections that are
+              specified as an URI.
+
+              The <b>dbname</b> setting is required with Postfix 3.10 and later, when
+              <b>hosts</b>  specifies  any  non-URI connection; it is always required
+              with earlier Postfix versions.
 
        <b>encoding</b>
-              The  encoding  used  by the database client. The default setting
+              The encoding used by the database client.  The  default  setting
               is:
                   encoding = UTF8
 
-              Historically, the database client was hard coded to  use  LATIN1
+              Historically,  the  database client was hard coded to use LATIN1
               in an attempt to disable multibyte character support.
 
               This feature is available in Postfix 3.8 and later.
 
        <b>idle_interval (default: 60)</b>
-              The  number  of  seconds after which an idle database connection
+              The number of seconds after which an  idle  database  connection
               will be closed.
 
               This feature is available in Postfix 3.9 and later.
@@ -100,8 +111,8 @@ PGSQL_TABLE(5)                                                  PGSQL_TABLE(5)
 
               This feature is available in Postfix 3.9 and later.
 
-       <b>query</b>  The  SQL query template used to search the database, where <b>%s</b> is
-              a substitute for the address Postfix is trying to resolve,  e.g.
+       <b>query</b>  The SQL query template used to search the database, where <b>%s</b>  is
+              a  substitute for the address Postfix is trying to resolve, e.g.
                   query = SELECT replacement FROM aliases WHERE mailbox = '%s'
 
               This parameter supports the following '%' expansions:
@@ -109,48 +120,48 @@ PGSQL_TABLE(5)                                                  PGSQL_TABLE(5)
               <b>%%</b>     This is replaced by a literal '%' character. (Postfix 2.2
                      and later)
 
-              <b>%s</b>     This is replaced by the input key.  SQL quoting  is  used
-                     to  make  sure that the input key does not add unexpected
+              <b>%s</b>     This  is  replaced by the input key.  SQL quoting is used
+                     to make sure that the input key does not  add  unexpected
                      metacharacters.
 
               <b>%u</b>     When the input key is an address of the form user@domain,
-                     <b>%u</b>  is  replaced  by  the  SQL  quoted  local part of the
-                     address.  Otherwise, <b>%u</b> is replaced by the entire  search
-                     string.   If  the  localpart  is empty, the query is sup-
+                     <b>%u</b> is replaced by  the  SQL  quoted  local  part  of  the
+                     address.   Otherwise, <b>%u</b> is replaced by the entire search
+                     string.  If the localpart is empty,  the  query  is  sup-
                      pressed and returns no results.
 
               <b>%d</b>     When the input key is an address of the form user@domain,
-                     <b>%d</b>  is  replaced  by  the  SQL  quoted domain part of the
-                     address.  Otherwise, the query is suppressed and  returns
+                     <b>%d</b> is replaced by the  SQL  quoted  domain  part  of  the
+                     address.   Otherwise, the query is suppressed and returns
                      no results.
 
               <b>%[SUD]</b> The upper-case equivalents of the above expansions behave
-                     in the <b>query</b> parameter identically  to  their  lower-case
-                     counter-parts.   With  the  <b>result_format</b>  parameter (see
-                     below), they expand the input key rather than the  result
+                     in  the  <b>query</b>  parameter identically to their lower-case
+                     counter-parts.  With  the  <b>result_format</b>  parameter  (see
+                     below),  they expand the input key rather than the result
                      value.
 
-                     The  above  %S,  %U  and %D expansions are available with
+                     The above %S, %U and %D  expansions  are  available  with
                      Postfix 2.2 and later
 
-              <b>%[1-9]</b> The patterns %1, %2, ... %9 are replaced  by  the  corre-
-                     sponding  most  significant  component of the input key's
-                     domain. If the input key is  <i>user@mail.example.com</i>,  then
+              <b>%[1-9]</b> The  patterns  %1,  %2, ... %9 are replaced by the corre-
+                     sponding most significant component of  the  input  key's
+                     domain.  If  the input key is <i>user@mail.example.com</i>, then
                      %1 is <b>com</b>, %2 is <b>example</b> and %3 is <b>mail</b>. If the input key
-                     is unqualified or does not have enough domain  components
-                     to  satisfy all the specified patterns, the query is sup-
+                     is  unqualified or does not have enough domain components
+                     to satisfy all the specified patterns, the query is  sup-
                      pressed and returns no results.
 
-                     The above %1, ... %9 expansions are available with  Post-
+                     The  above %1, ... %9 expansions are available with Post-
                      fix 2.2 and later
 
-              The  <b>domain</b>  parameter  described below limits the input keys to
-              addresses in matching domains.  When  the  <b>domain</b>  parameter  is
+              The <b>domain</b> parameter described below limits the  input  keys  to
+              addresses  in  matching  domains.  When  the <b>domain</b> parameter is
               non-empty, SQL queries for unqualified addresses or addresses in
               non-matching domains are suppressed and return no results.
 
-              The precedence of this parameter has changed with  Postfix  2.2,
-              in  prior  releases  the precedence was, from highest to lowest,
+              The  precedence  of this parameter has changed with Postfix 2.2,
+              in prior releases the precedence was, from  highest  to  lowest,
               <b>select_function</b>, <b>query</b>, <b>select_field</b>, ...
 
               With Postfix 2.2 the <b>query</b> parameter has highest precedence, see
@@ -160,42 +171,42 @@ PGSQL_TABLE(5)                                                  PGSQL_TABLE(5)
 
        <b>result_format (default: %s</b>)
               Format template applied to result attributes. Most commonly used
-              to append (or prepend) text to the result. This  parameter  sup-
+              to  append  (or prepend) text to the result. This parameter sup-
               ports the following '%' expansions:
 
               <b>%%</b>     This is replaced by a literal '%' character.
 
-              <b>%s</b>     This  is  replaced  by the value of the result attribute.
+              <b>%s</b>     This is replaced by the value of  the  result  attribute.
                      When result is empty it is skipped.
 
               <b>%u</b>     When the result attribute value is an address of the form
-                     user@domain,  <b>%u</b>  is  replaced  by  the local part of the
-                     address. When the result has an  empty  localpart  it  is
+                     user@domain, <b>%u</b> is replaced by  the  local  part  of  the
+                     address.  When  the  result  has an empty localpart it is
                      skipped.
 
-              <b>%d</b>     When  a  result attribute value is an address of the form
-                     user@domain, <b>%d</b> is replaced by the  domain  part  of  the
-                     attribute  value.  When  the  result is unqualified it is
+              <b>%d</b>     When a result attribute value is an address of  the  form
+                     user@domain,  <b>%d</b>  is  replaced  by the domain part of the
+                     attribute value. When the result  is  unqualified  it  is
                      skipped.
 
               <b>%[SUD1-9]</b>
-                     The upper-case and decimal digit  expansions  interpolate
-                     the  parts of the input key rather than the result. Their
-                     behavior is identical to that described with  <b>query</b>,  and
-                     in  fact  because  the  input  key  is  known in advance,
-                     queries whose key does not contain  all  the  information
-                     specified  in  the  result  template  are  suppressed and
+                     The  upper-case  and decimal digit expansions interpolate
+                     the parts of the input key rather than the result.  Their
+                     behavior  is  identical to that described with <b>query</b>, and
+                     in fact because  the  input  key  is  known  in  advance,
+                     queries  whose  key  does not contain all the information
+                     specified in  the  result  template  are  suppressed  and
                      return no results.
 
               For example, using "result_format = <a href="smtp.8.html">smtp</a>:[%s]" allows one to use
               a mailHost attribute as the basis of a <a href="transport.5.html">transport(5)</a> table. After
-              applying the result format, multiple values are concatenated  as
+              applying  the result format, multiple values are concatenated as
               comma  separated  strings.  The  expansion_limit  and  parameter
-              explained below allows one to restrict the number of  values  in
+              explained  below  allows one to restrict the number of values in
               the result, which is especially useful for maps that must return
               at most one value.
 
-              The default value <b>%s</b> specifies that each result value should  be
+              The  default value <b>%s</b> specifies that each result value should be
               used as is.
 
               This parameter is available with Postfix 2.2 and later.
@@ -203,15 +214,15 @@ PGSQL_TABLE(5)                                                  PGSQL_TABLE(5)
               NOTE: DO NOT put quotes around the result format!
 
        <b>domain (default: no domain list)</b>
-              This  is a list of domain names, paths to files, or "<a href="DATABASE_README.html">type:table</a>"
+              This is a list of domain names, paths to files, or  "<a href="DATABASE_README.html">type:table</a>"
               databases. When specified, only fully qualified search keys with
-              a  *non-empty*  localpart and a matching domain are eligible for
+              a *non-empty* localpart and a matching domain are  eligible  for
               lookup:  'user'  lookups,  bare  domain  lookups  and  "@domain"
-              lookups  are  not  performed.  This can significantly reduce the
+              lookups are not performed. This  can  significantly  reduce  the
               query load on the PostgreSQL server.
                   domain = postfix.org, <a href="DATABASE_README.html#types">hash</a>:/etc/postfix/searchdomains
 
-              It is best not to use SQL to store the domains eligible for  SQL
+              It  is best not to use SQL to store the domains eligible for SQL
               lookups.
 
               This parameter is available with Postfix 2.2 and later.
@@ -220,28 +231,28 @@ PGSQL_TABLE(5)                                                  PGSQL_TABLE(5)
               the input keys are always unqualified.
 
        <b>expansion_limit (default: 0)</b>
-              A limit on the total number of result elements  returned  (as  a
+              A  limit  on  the total number of result elements returned (as a
               comma separated list) by a lookup against the map.  A setting of
-              zero disables the limit. Lookups fail with a temporary error  if
-              the  limit  is  exceeded.   Setting  the limit to 1 ensures that
+              zero  disables the limit. Lookups fail with a temporary error if
+              the limit is exceeded.  Setting the  limit  to  1  ensures  that
               lookups do not return multiple values.
 
 <b>OBSOLETE MAIN.CF PARAMETERS</b>
-       For compatibility with other Postfix lookup tables, PostgreSQL  parame-
-       ters  can  also be defined in <a href="postconf.5.html">main.cf</a>.  In order to do that, specify as
+       For  compatibility with other Postfix lookup tables, PostgreSQL parame-
+       ters can also be defined in <a href="postconf.5.html">main.cf</a>.  In order to do that,  specify  as
        PostgreSQL source a name that doesn't begin with a slash or a dot.  The
-       PostgreSQL  parameters will then be accessible as the name you've given
+       PostgreSQL parameters will then be accessible as the name you've  given
        the source in its definition, an underscore, and the name of the param-
-       eter.   For  example, if the map is specified as "<a href="pgsql_table.5.html">pgsql</a>:<i>pgsqlname</i>", the
+       eter.  For example, if the map is specified as  "<a href="pgsql_table.5.html">pgsql</a>:<i>pgsqlname</i>",  the
        parameter "hosts" would be defined in <a href="postconf.5.html">main.cf</a> as "<i>pgsqlname</i>_hosts".
 
-       Note: with this form, the passwords  for  the  PostgreSQL  sources  are
+       Note:  with  this  form,  the  passwords for the PostgreSQL sources are
        written in <a href="postconf.5.html">main.cf</a>, which is normally world-readable.  Support for this
        form will be removed in a future Postfix version.
 
 <b><a name="obsolete_query_interfaces">OBSOLETE QUERY INTERFACES</a></b>
        This section describes query interfaces that are deprecated as of Post-
-       fix  2.2.   Please migrate to the new <b>query</b> interface as the old inter-
+       fix 2.2.  Please migrate to the new <b>query</b> interface as the  old  inter-
        faces are slated to be phased out.
 
        <b>select_function</b>
@@ -251,14 +262,14 @@ PGSQL_TABLE(5)                                                  PGSQL_TABLE(5)
               This is equivalent to:
                   query = SELECT my_lookup_user_alias('%s')
 
-              This  parameter  overrides  the  legacy   table-related   fields
-              (described  below).  With Postfix versions prior to 2.2, it also
-              overrides the <b>query</b> parameter. Starting with  Postfix  2.2,  the
-              <b>query</b>  parameter has highest precedence, and the <b>select_function</b>
+              This   parameter   overrides  the  legacy  table-related  fields
+              (described below). With Postfix versions prior to 2.2,  it  also
+              overrides  the  <b>query</b>  parameter. Starting with Postfix 2.2, the
+              <b>query</b> parameter has highest precedence, and the  <b>select_function</b>
               parameter is deprecated.
 
-       The following parameters (with lower precedence than  the  <b>select_func-</b>
-       <b>tion</b>  interface  described  above)  can be used to build the SQL select
+       The  following  parameters (with lower precedence than the <b>select_func-</b>
+       <b>tion</b> interface described above) can be used to  build  the  SQL  select
        statement as follows:
 
            SELECT [<b>select_field</b>]
@@ -266,13 +277,13 @@ PGSQL_TABLE(5)                                                  PGSQL_TABLE(5)
            WHERE [<b>where_field</b>] = '%s'
                  [<b>additional_conditions</b>]
 
-       The specifier %s is replaced with each lookup by the lookup key and  is
-       escaped  so  if  it  contains single quotes or other odd characters, it
+       The  specifier %s is replaced with each lookup by the lookup key and is
+       escaped so if it contains single quotes or  other  odd  characters,  it
        will not cause a parse error, or worse, a security problem.
 
        Starting with Postfix 2.2, this interface is obsoleted by the more gen-
        eral <b>query</b> interface described above. If higher precedence the <b>query</b> or
-       <b>select_function</b> parameters described above are defined, the  parameters
+       <b>select_function</b>  parameters described above are defined, the parameters
        described here are ignored.
 
        <b>select_field</b>
index 6d9df55fd03f3be3554e85094db9b40e89ad319b..1d0064cf6010e49830caeddaeb4875eaae780657 100644 (file)
@@ -55,7 +55,7 @@ return the key itself or a constant value.
 .fi
 .IP "\fBhosts\fR"
 The hosts that Postfix will try to connect to and query
-from. Besides a \fBpostgresql://\fR connection URI, this
+from. Besides a PostgreSQL connection URI, this
 setting supports the historical forms \fBunix:/\fIpathname\fR
 for UNIX\-domain sockets and \fBinet:\fIhost:port\fR for TCP
 connections, where the \fBunix:\fR and \fBinet:\fR prefixes
@@ -63,18 +63,28 @@ are accepted and ignored for backwards compatibility.
 Examples:
 .nf
     hosts = postgresql://username@example.com/\fIdatabasename\fR?sslmode=require
+    hosts = postgres://user:secret@localhost
     hosts = inet:host1.some.domain inet:host2.some.domain:port
     hosts = host1.some.domain host2.some.domain:port
     hosts = unix:/file/name
 .fi
 
+See https://www.postgresql.org/docs/current/libpq\-connect.html
+for the supported connection URI syntax.
+
 The hosts are tried in random order. The connections are
 automatically closed after being idle for about 1 minute,
-and are re\-opened as necessary.
+and are re\-opened as necessary. See \fBidle_interval\fR
+for details.
+
+NOTE: if \fBhosts\fR specifies a PostgreSQL connection URI,
+the PostgreSQL client library will ignore the \fBdbname\fR
+setting for that connection.
 
-NOTE: if "hosts" specifies one load balancer and no alternative
+NOTE: if \fBhosts\fR specifies one load balancer and no
+alternative
 servers, specify the load balancer multiple times in the
-"hosts" line. Without the duplicate info, the Postfix
+\fBhosts\fR line. Without the duplicate info, the Postfix
 PostgreSQL client would not reconnect immediately to the
 same load balancer after a PostgreSQL server failure.
 .IP "\fBuser\fR"
@@ -85,14 +95,18 @@ Example:
     user = someone
     password = some_password
 .fi
-.IP "\fBdbname\fR (required)"
+.IP "\fBdbname\fR"
 The database name on the servers. Example:
 .nf
     dbname = customer_database
 .fi
 .sp
-This setting is required, but ignored when a postgresql://
-URI specifies a database name.
+The \fBdbname\fR setting is ignored for \fBhosts\fR connections
+that are specified as an URI.
+
+The \fBdbname\fR setting is required with Postfix 3.10 and later,
+when \fBhosts\fR specifies any non\-URI connection; it is always
+required with earlier Postfix versions.
 .IP "\fBencoding\fR"
 The encoding used by the database client. The default setting
 is:
index 6bc797b5b0aa05fa0c2870582eb375f2dbe027d4..e434779a37d8b3bccf0df3a5abe2dde2afb0b4ec 100644 (file)
@@ -45,7 +45,7 @@
 # .fi
 # .IP "\fBhosts\fR"
 #      The hosts that Postfix will try to connect to and query
-#      from. Besides a \fBpostgresql://\fR connection URI, this
+#      from. Besides a PostgreSQL connection URI, this
 #      setting supports the historical forms \fBunix:/\fIpathname\fR
 #      for UNIX-domain sockets and \fBinet:\fIhost:port\fR for TCP
 #      connections, where the \fBunix:\fR and \fBinet:\fR prefixes
 #      Examples:
 # .nf
 #          hosts = postgresql://username@example.com/\fIdatabasename\fR?sslmode=require
+#          hosts = postgres://user:secret@localhost
 #          hosts = inet:host1.some.domain inet:host2.some.domain:port
 #          hosts = host1.some.domain host2.some.domain:port
 #          hosts = unix:/file/name
 # .fi
 #
+#      See https://www.postgresql.org/docs/current/libpq-connect.html
+#      for the supported connection URI syntax.
+#
 #      The hosts are tried in random order. The connections are
 #      automatically closed after being idle for about 1 minute,
-#      and are re-opened as necessary.
+#      and are re-opened as necessary. See \fBidle_interval\fR
+#      for details.
+#
+#      NOTE: if \fBhosts\fR specifies a PostgreSQL connection URI,
+#      the PostgreSQL client library will ignore the \fBdbname\fR
+#      setting for that connection.
 #
-#      NOTE: if "hosts" specifies one load balancer and no alternative
+#      NOTE: if \fBhosts\fR specifies one load balancer and no
+#      alternative
 #      servers, specify the load balancer multiple times in the
-#      "hosts" line. Without the duplicate info, the Postfix
+#      \fBhosts\fR line. Without the duplicate info, the Postfix
 #      PostgreSQL client would not reconnect immediately to the
 #      same load balancer after a PostgreSQL server failure.
 # .IP "\fBuser\fR"
 #          user = someone
 #          password = some_password
 # .fi
-# .IP "\fBdbname\fR (required)"
+# .IP "\fBdbname\fR"
 #      The database name on the servers. Example:
 # .nf
 #          dbname = customer_database
 # .fi
 # .sp
-#      This setting is required, but ignored when a postgresql://
-#      URI specifies a database name.
+#      The \fBdbname\fR setting is ignored for \fBhosts\fR connections
+#      that are specified as an URI.
+#
+#      The \fBdbname\fR setting is required with Postfix 3.10 and later,
+#      when \fBhosts\fR specifies any non-URI connection; it is always
+#      required with earlier Postfix versions.
 # .IP "\fBencoding\fR"
 #      The encoding used by the database client. The default setting
 #      is:
index 491fe0f1537ac3f4d03732235bd10008cacd3a6e..e1410bb7ee84f350b6a4f981f05871b5f91b33ad 100644 (file)
@@ -1252,6 +1252,7 @@ dict_pgsql.o: ../../include/myrand.h
 dict_pgsql.o: ../../include/split_at.h
 dict_pgsql.o: ../../include/stringops.h
 dict_pgsql.o: ../../include/sys_defs.h
+dict_pgsql.o: ../../include/valid_uri_scheme.h
 dict_pgsql.o: ../../include/vbuf.h
 dict_pgsql.o: ../../include/vstream.h
 dict_pgsql.o: ../../include/vstring.h
index c62685451d51a43c76819723b94f9a61b571294c..53fafd2287281a8d0de04714a8c702bd04de1490 100644 (file)
@@ -92,6 +92,7 @@
 #include "myrand.h"
 #include "events.h"
 #include "stringops.h"
+#include "valid_uri_scheme.h"
 
 /* Global library. */
 
@@ -127,6 +128,7 @@ typedef struct {
 typedef struct {
     int     len_hosts;                 /* number of hosts */
     HOST  **db_hosts;                  /* hosts on which databases reside */
+    char   *non_uri_target;            /* require dbname to be specified */
 } PLPGSQL;
 
 typedef struct {
@@ -626,7 +628,7 @@ static void pgsql_parse_config(DICT_PGSQL *dict_pgsql, const char *pgsqlcf)
 
     dict_pgsql->username = cfg_get_str(p, "user", "", 0, 0);
     dict_pgsql->password = cfg_get_str(p, "password", "", 0, 0);
-    dict_pgsql->dbname = cfg_get_str(p, "dbname", "", 1, 0);
+    dict_pgsql->dbname = cfg_get_str(p, "dbname", "", 0, 0);
     dict_pgsql->encoding = cfg_get_str(p, "encoding", "UTF8", 1, 0);
     dict_pgsql->retry_interval = cfg_get_int(p, "retry_interval",
                                             DEF_RETRY_INTV, 1, 0);
@@ -723,6 +725,21 @@ DICT   *dict_pgsql_open(const char *name, int open_flags, int dict_flags)
     dict_pgsql->pldb = plpgsql_init(dict_pgsql->hosts);
     if (dict_pgsql->pldb == NULL)
        msg_fatal("couldn't initialize pldb!\n");
+    if (msg_verbose && dict_pgsql->pldb->non_uri_target == 0
+       && dict_pgsql->dbname[0] != 0)
+       msg_info("%s:%s table ignores 'dbname' field -- "
+                "all 'hosts' targets are URIs",
+                DICT_TYPE_PGSQL, name);
+    if (dict_pgsql->pldb->non_uri_target && dict_pgsql->dbname[0] == 0) {
+       DICT   *ret;
+
+       ret == (dict_surrogate(DICT_TYPE_PGSQL, name, open_flags, dict_flags,
+                          "%s:%s host target '%s' requires dbname setting",
+                              DICT_TYPE_PGSQL, name,
+                              dict_pgsql->pldb->non_uri_target));
+       dict_pgsql_close(&dict_pgsql->dict);
+       return (ret);
+    }
     dict_pgsql->dict.owner = cfg_get_owner(dict_pgsql->parser);
     return (DICT_DEBUG (&dict_pgsql->dict));
 }
@@ -737,8 +754,12 @@ static PLPGSQL *plpgsql_init(ARGV *hosts)
     PLDB = (PLPGSQL *) mymalloc(sizeof(PLPGSQL));
     PLDB->len_hosts = hosts->argc;
     PLDB->db_hosts = (HOST **) mymalloc(sizeof(HOST *) * hosts->argc);
-    for (i = 0; i < hosts->argc; i++)
+    PLDB->non_uri_target = 0;
+    for (i = 0; i < hosts->argc; i++) {
        PLDB->db_hosts[i] = host_init(hosts->argv[i]);
+       if (PLDB->db_hosts[i]->type != TYPECONNSTR)
+           PLDB->non_uri_target = PLDB->db_hosts[i]->name;
+    }
 
     return PLDB;
 }
@@ -758,9 +779,9 @@ static HOST *host_init(const char *hostname)
     host->ts = 0;
 
     /*
-     * Modern syntax: "postgresql://connection-info".
+     * Modern syntax: connection URI.
      */
-    if (strncmp(d, "postgresql:", 11) == 0) {
+    if (valid_uri_scheme(d)) {
        host->type = TYPECONNSTR;
        host->name = mystrdup(d);
        host->port = 0;
index 02a818a0f5fb1f428256246a5ece50b180d660c3..eb01b3a5726768aa729eb06e2bf80534687e1b73 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20241024"
+#define MAIL_RELEASE_DATE      "20241025"
 #define MAIL_VERSION_NUMBER    "3.10"
 
 #ifdef SNAPSHOT
index 531b786bfc9276171fb0186094b49d141b3ce4ec..77781bc0a374878da98edd821df576440cc7d4a5 100644 (file)
@@ -46,7 +46,7 @@ SRCS  = alldig.c allprint.c argv.c argv_split.c attr_clnt.c attr_print0.c \
        sane_strtol.c hash_fnv.c ldseed.c mkmap_cdb.c mkmap_db.c mkmap_dbm.c \
        mkmap_fail.c mkmap_lmdb.c mkmap_open.c mkmap_sdbm.c inet_prefix_top.c \
        inet_addr_sizes.c quote_for_json.c mystrerror.c \
-       sane_sockaddr_to_hostaddr.c normalize_ws.c
+       sane_sockaddr_to_hostaddr.c normalize_ws.c valid_uri_scheme.c
 OBJS   = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
        attr_print64.o attr_print_plain.o attr_scan0.o attr_scan64.o \
        attr_scan_plain.o auto_clnt.o base64_code.o basename.o binhash.o \
@@ -94,7 +94,7 @@ OBJS  = alldig.o allprint.o argv.o argv_split.o attr_clnt.o attr_print0.o \
        sane_strtol.o hash_fnv.o ldseed.o mkmap_db.o mkmap_dbm.o \
        mkmap_fail.o mkmap_open.o inet_prefix_top.o inet_addr_sizes.o \
        quote_for_json.o mystrerror.o sane_sockaddr_to_hostaddr.o \
-       normalize_ws.o
+       normalize_ws.o valid_uri_scheme.o
 # MAP_OBJ is for maps that may be dynamically loaded with dynamicmaps.cf.
 # When hard-linking these, makedefs sets NON_PLUGIN_MAP_OBJ=$(MAP_OBJ),
 # otherwise it sets the PLUGIN_* macros.
@@ -126,7 +126,7 @@ HDRS        = argv.h attr.h attr_clnt.h auto_clnt.h base64_code.h binhash.h \
        valid_utf8_hostname.h midna_domain.h dict_union.h dict_inline.h \
        check_arg.h argv_attr.h msg_logger.h logwriter.h byte_mask.h \
        known_tcp_ports.h sane_strtol.h hash_fnv.h ldseed.h mkmap.h \
-       inet_prefix_top.h inet_addr_sizes.h
+       inet_prefix_top.h inet_addr_sizes.h valid_uri_scheme.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)
@@ -149,7 +149,7 @@ TESTPROG= dict_open dup2_pass_on_exec events exec_command fifo_open \
        vbuf_print split_qnameval vstream msg_logger byte_mask \
        known_tcp_ports dict_stream find_inet binhash hash_fnv argv \
        clean_env inet_prefix_top printable readlline quote_for_json \
-       normalize_ws
+       normalize_ws valid_uri_scheme
 PLUGIN_MAP_SO = $(LIB_PREFIX)pcre$(LIB_SUFFIX) $(LIB_PREFIX)lmdb$(LIB_SUFFIX) \
        $(LIB_PREFIX)cdb$(LIB_SUFFIX) $(LIB_PREFIX)sdbm$(LIB_SUFFIX)
 HTABLE_FIX = NORANDOMIZE=1
@@ -618,6 +618,11 @@ normalize_ws: $(LIB)
        $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
        mv junk $@.o
 
+valid_uri_scheme: $(LIB)
+       mv $@.o junk
+       $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(SYSLIBS)
+       mv junk $@.o
+
 tests: all 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 host_port_test dict_tests \
@@ -629,7 +634,7 @@ tests: all valid_hostname_test mac_expand_test dict_test unescape_test \
        vstream_test byte_mask_tests mystrtok_test known_tcp_ports_test \
        binhash_test argv_test inet_prefix_top_test printable_test \
        valid_utf8_string_test readlline_test quote_for_json_test \
-       normalize_ws_test
+       normalize_ws_test valid_uri_scheme_test
  
 dict_tests: all dict_test \
        dict_pcre_tests dict_cidr_test dict_thash_test dict_static_test \
@@ -1109,6 +1114,9 @@ quote_for_json_test: quote_for_json
 normalize_ws_test: normalize_ws
        $(SHLIB_ENV) ${VALGRIND} ./normalize_ws
 
+valid_uri_scheme_test: valid_uri_scheme
+       $(SHLIB_ENV) ${VALGRIND} ./valid_uri_scheme
+
 depend: $(MAKES)
        (sed '1,/^# do not edit/!d' Makefile.in; \
        set -e; for i in [a-z][a-z0-9]*.c; do \
@@ -2893,6 +2901,16 @@ valid_hostname.o: valid_hostname.c
 valid_hostname.o: valid_hostname.h
 valid_hostname.o: vbuf.h
 valid_hostname.o: vstring.h
+valid_uri_scheme.o: check_arg.h
+valid_uri_scheme.o: msg.h
+valid_uri_scheme.o: msg_vstream.h
+valid_uri_scheme.o: stringops.h
+valid_uri_scheme.o: sys_defs.h
+valid_uri_scheme.o: valid_uri_scheme.c
+valid_uri_scheme.o: valid_uri_scheme.h
+valid_uri_scheme.o: vbuf.h
+valid_uri_scheme.o: vstream.h
+valid_uri_scheme.o: vstring.h
 valid_utf8_hostname.o: check_arg.h
 valid_utf8_hostname.o: midna_domain.h
 valid_utf8_hostname.o: msg.h
diff --git a/postfix/src/util/valid_uri_scheme.c b/postfix/src/util/valid_uri_scheme.c
new file mode 100644 (file)
index 0000000..6a10f22
--- /dev/null
@@ -0,0 +1,129 @@
+/*++
+/* NAME
+/*     valid_uri_scheme 3
+/* SUMMARY
+/*     validate scheme:// prefix
+/* SYNOPSIS
+/*     #include <valid_uri_scheme.h>
+/*
+/*     int     valid_uri_scheme(const char *str)
+/* DESCRIPTION
+/*     valid_uri_scheme() takes a null-terminated string and returns
+/*     the length of a valid scheme:// prefix, or zero if no valid
+/*     prefix was found.
+/*
+/*     This function requires that input is encoded in ASCII or UTF-8.
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     porcupine.org
+/*--*/
+
+ /*
+  * System library.
+  */
+#include <sys_defs.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+ /*
+  * Utility library.
+  */
+#include <valid_uri_scheme.h>
+#include <msg.h>
+#include <msg_vstream.h>
+#include <stringops.h>
+
+/* valid_uri_scheme - predicate that string starts with scheme:// */
+
+ssize_t valid_uri_scheme(const char *str)
+{
+    const char *cp = str;
+    int     ch = *cp++;
+
+    /* Per RFC 3986, a valid scheme starts with ALPHA. */
+    if (!ISALPHA(ch))
+       return (0);
+
+    while ((ch = *cp++) != 0) {
+       /* A valid scheme continues with ALPHA | DIGIT | '+' | '-'. */
+       if (ISALNUM(ch) || ch == '+' || ch == '-')
+           continue;
+       /* A valid scheme is followed by "://". */
+       if (ch == ':' && *cp++ == '/' && *cp++ == '/')
+           return (cp - str);
+       /* Not a valid scheme. */
+       break;
+    }
+    /* Not a valid scheme. */
+    return (0);
+}
+
+#ifdef TEST
+
+typedef struct TEST_CASE {
+    const char *label;
+    const char *input;
+    const ssize_t want;
+} TEST_CASE;
+
+#define PASS    (0)
+#define FAIL    (1)
+
+static const TEST_CASE test_cases[] = {
+    {"accepts_alpha_scheme", "abcd://blah", sizeof("abcd://") - 1},
+    {"accepts_mixed_scheme", "a-bcd+123://blah", sizeof("a-bcd+123://") - 1},
+    {"rejects_minus_first", "-bcd+123://blah'", 0},
+    {"rejects_plus_first", "+123://blah", 0},
+    {"rejects_digit_first", "123://blah", 0},
+    {"rejects_other_first", "?123://blah", 0},
+    {"rejects_other_middle", "abcd?123://blah", 0},
+    {"rejects_other_end", "abcd-123?://blah", 0},
+    {"rejects_non_scheme", "inet:host:port", 0},
+    {"rejects_no_colon", "inet", 0},
+    {"rejects_colon_slash", "abcd:/blah", 0},
+    {"rejects_empty", "", 0},
+    {0,}
+};
+
+static int test_validate_scheme(const TEST_CASE *tp)
+{
+    int     got;
+
+    got = valid_uri_scheme(tp->input);
+    if (got != tp->want) {
+       msg_warn("got '%ld', want '%ld'", (long) got, (long) tp->want);
+       return (FAIL);
+    }
+    return (PASS);
+}
+
+int     main(int argc, char **argv)
+{
+    const TEST_CASE *tp;
+    int     pass = 0;
+    int     fail = 0;
+
+    msg_vstream_init(sane_basename((VSTRING *) 0, argv[0]), VSTREAM_ERR);
+
+    for (tp = test_cases; tp->label != 0; tp++) {
+       int     test_failed;
+
+       msg_info("RUN  %s", tp->label);
+       test_failed = test_validate_scheme(tp);
+       if (test_failed) {
+           msg_info("FAIL %s", tp->label);
+           fail++;
+       } else {
+           msg_info("PASS %s", tp->label);
+           pass++;
+       }
+    }
+    msg_info("PASS=%d FAIL=%d", pass, fail);
+    exit(fail != 0);
+}
+
+#endif
diff --git a/postfix/src/util/valid_uri_scheme.h b/postfix/src/util/valid_uri_scheme.h
new file mode 100644 (file)
index 0000000..94327ed
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef _VALID_SCHEME_H_INCLUDED_
+#define _VALID_SCHEME_H_INCLUDED_
+
+/*++
+/* NAME
+/*     valid_uri_scheme 3h
+/* SUMMARY
+/*     validate scheme:// prefix
+/* SYNOPSIS
+/*     #include <valid_uri_scheme.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+  * External interface.
+  */
+extern ssize_t valid_uri_scheme(const char *);
+
+/* LICENSE
+/* .ad
+/* .fi
+/*     The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/*     Wietse Venema
+/*     porcupine.org
+/*--*/
+
+#endif