Tom Lane wrote:
Here's a straw-man proposal that we could perhaps do for 8.3:

1. Invent a libpq connection-status function

        bool PQconnectionUsedPassword(const PGconn *conn);

This returns true if the server had demanded a password during the
authentication phase.  Aside from solving the immediate problem, this
can be useful for regular clients such as psql: it could be applied to a
failed connection object to decide whether to prompt for a password
(replacing the current egregious hack of strcmp'ing the error message).

2. Make dblink close the connection and throw error if called by a
non-superuser and PQconnectionUsedPassword returns false.

Attached patch implements this proposal, including documentation changes. I'll work separately on the back-branch version.

Any comments/objections?

Joe
Index: contrib/dblink/dblink.c
===================================================================
RCS file: /opt/src/cvs/pgsql/contrib/dblink/dblink.c,v
retrieving revision 1.63
diff -c -r1.63 dblink.c
*** contrib/dblink/dblink.c	6 Apr 2007 04:21:41 -0000	1.63
--- contrib/dblink/dblink.c	7 Jul 2007 22:49:05 -0000
***************
*** 37,42 ****
--- 37,43 ----
  #include "libpq-fe.h"
  #include "fmgr.h"
  #include "funcapi.h"
+ #include "miscadmin.h"
  #include "access/heapam.h"
  #include "access/tupdesc.h"
  #include "catalog/namespace.h"
***************
*** 245,250 ****
--- 246,261 ----
  				 errdetail("%s", msg)));
  	}
  
+ 	if (!superuser())
+ 	{
+ 		if (!PQconnectionUsedPassword(conn))
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_S_R_E_PROHIBITED_SQL_STATEMENT_ATTEMPTED),
+ 					 errmsg("connection without password not allowed"),
+ 					 errdetail("non-superuser cannot connect if server does not request password"),
+ 					 errhint("target server authentication method must be changed")));
+ 	}
+ 
  	if (connname)
  	{
  		rconn->conn = conn;
Index: contrib/dblink/dblink.sql.in
===================================================================
RCS file: /opt/src/cvs/pgsql/contrib/dblink/dblink.sql.in,v
retrieving revision 1.11
diff -c -r1.11 dblink.sql.in
*** contrib/dblink/dblink.sql.in	2 Sep 2006 21:11:15 -0000	1.11
--- contrib/dblink/dblink.sql.in	8 Jul 2007 01:22:13 -0000
***************
*** 1,3 ****
--- 1,5 ----
+ -- dblink_connect now restricts non-superusers to password
+ -- authenticated connections
  CREATE OR REPLACE FUNCTION dblink_connect (text)
  RETURNS text
  AS 'MODULE_PATHNAME','dblink_connect'
***************
*** 8,13 ****
--- 10,31 ----
  AS 'MODULE_PATHNAME','dblink_connect'
  LANGUAGE C STRICT;
  
+ -- dblink_connect_u allows non-superusers to use
+ -- non-password authenticated connections, but initially
+ -- privileges are revoked from public
+ CREATE OR REPLACE FUNCTION dblink_connect_u (text)
+ RETURNS text
+ AS 'MODULE_PATHNAME','dblink_connect'
+ LANGUAGE C STRICT SECURITY DEFINER;
+ 
+ CREATE OR REPLACE FUNCTION dblink_connect_u (text, text)
+ RETURNS text
+ AS 'MODULE_PATHNAME','dblink_connect'
+ LANGUAGE C STRICT SECURITY DEFINER;
+ 
+ REVOKE ALL ON FUNCTION dblink_connect_u (text) FROM public;
+ REVOKE ALL ON FUNCTION dblink_connect_u (text, text) FROM public;
+ 
  CREATE OR REPLACE FUNCTION dblink_disconnect ()
  RETURNS text
  AS 'MODULE_PATHNAME','dblink_disconnect'
Index: contrib/dblink/doc/connection
===================================================================
RCS file: /opt/src/cvs/pgsql/contrib/dblink/doc/connection,v
retrieving revision 1.4
diff -c -r1.4 connection
*** contrib/dblink/doc/connection	11 Mar 2006 04:38:29 -0000	1.4
--- contrib/dblink/doc/connection	8 Jul 2007 01:51:07 -0000
***************
*** 27,32 ****
--- 27,38 ----
  
    Returns status = "OK"
  
+ Notes
+ 
+   Only superusers may use dblink_connect to create non-password
+   authenticated connections. If non-superusers need this capability,
+   use dblink_connect_u instead.
+ 
  Example usage
  
  select dblink_connect('dbname=postgres');
***************
*** 44,49 ****
--- 50,95 ----
  ==================================================================
  Name
  
+ dblink_connect_u -- Opens a persistent connection to a remote database
+ 
+ Synopsis
+ 
+ dblink_connect_u(text connstr)
+ dblink_connect_u(text connname, text connstr)
+ 
+ Inputs
+ 
+   connname
+     if 2 arguments are given, the first is used as a name for a persistent
+     connection
+ 
+   connstr
+ 
+     standard libpq format connection string, 
+     e.g. "hostaddr=127.0.0.1 port=5432 dbname=mydb user=postgres password=mypasswd"
+ 
+     if only one argument is given, the connection is unnamed; only one unnamed
+     connection can exist at a time
+ 
+ Outputs
+ 
+   Returns status = "OK"
+ 
+ Notes
+ 
+   With dblink_connect_u, a non-superuser may connect to any database server
+   using any authentication method. If the authentication method specified
+   for a particular user does not require a password, impersonation and
+   therefore escalation of privileges may occur. For this reason,
+   dblink_connect_u is initially installed with all privileges revoked from
+   public. Privilege to these functions should be granted with care.
+ 
+ Example usage
+ 
+ 
+ ==================================================================
+ Name
+ 
  dblink_disconnect -- Closes a persistent connection to a remote database
  
  Synopsis
Index: doc/src/sgml/libpq.sgml
===================================================================
RCS file: /opt/src/cvs/pgsql/doc/src/sgml/libpq.sgml,v
retrieving revision 1.235
diff -c -r1.235 libpq.sgml
*** doc/src/sgml/libpq.sgml	30 Mar 2007 03:19:02 -0000	1.235
--- doc/src/sgml/libpq.sgml	8 Jul 2007 02:06:36 -0000
***************
*** 1059,1064 ****
--- 1059,1078 ----
       </listitem>
      </varlistentry>
  
+     <varlistentry>
+      <term><function>PQconnectionUsedPassword</function><indexterm><primary>PQconnectionUsedPassword</></></term>
+      <listitem>
+       <para>
+        Returns true (1) if the connection authentication method
+        required a password to be supplied. Returns false (0)
+        otherwise.
+        <synopsis>
+        bool PQconnectionUsedPassword(const PGconn *conn);
+        </synopsis>
+       </para>
+      </listitem>
+     </varlistentry>
+ 
  </variablelist>
  </para>
  
Index: src/include/libpq/pqcomm.h
===================================================================
RCS file: /opt/src/cvs/pgsql/src/include/libpq/pqcomm.h,v
retrieving revision 1.102
diff -c -r1.102 pqcomm.h
*** src/include/libpq/pqcomm.h	5 Jan 2007 22:19:55 -0000	1.102
--- src/include/libpq/pqcomm.h	8 Jul 2007 01:16:29 -0000
***************
*** 156,161 ****
--- 156,162 ----
  #define AUTH_REQ_CRYPT		4	/* crypt password */
  #define AUTH_REQ_MD5		5	/* md5 password */
  #define AUTH_REQ_SCM_CREDS	6	/* transfer SCM credentials */
+ #define AUTH_REQ_UNK		7	/* User has not yet attempted to authenticate */
  
  typedef uint32 AuthRequest;
  
Index: src/interfaces/libpq/exports.txt
===================================================================
RCS file: /opt/src/cvs/pgsql/src/interfaces/libpq/exports.txt,v
retrieving revision 1.15
diff -c -r1.15 exports.txt
*** src/interfaces/libpq/exports.txt	3 Mar 2007 19:52:46 -0000	1.15
--- src/interfaces/libpq/exports.txt	7 Jul 2007 22:07:48 -0000
***************
*** 137,139 ****
--- 137,140 ----
  PQsendDescribePrepared    135
  PQsendDescribePortal      136
  lo_truncate               137
+ PQconnectionUsedPassword  138
Index: src/interfaces/libpq/fe-connect.c
===================================================================
RCS file: /opt/src/cvs/pgsql/src/interfaces/libpq/fe-connect.c,v
retrieving revision 1.345
diff -c -r1.345 fe-connect.c
*** src/interfaces/libpq/fe-connect.c	8 Mar 2007 19:27:28 -0000	1.345
--- src/interfaces/libpq/fe-connect.c	7 Jul 2007 23:07:02 -0000
***************
*** 1641,1646 ****
--- 1641,1650 ----
  					return PGRES_POLLING_READING;
  				}
  
+ 				/* save the authentication request type */
+ 				if (conn->areq == AUTH_REQ_UNK)
+ 					conn->areq = areq;
+ 
  				/* Get the password salt if there is one. */
  				if (areq == AUTH_REQ_MD5)
  				{
***************
*** 1873,1878 ****
--- 1877,1883 ----
  	conn->std_strings = false;	/* unless server says differently */
  	conn->verbosity = PQERRORS_DEFAULT;
  	conn->sock = -1;
+ 	conn->areq = AUTH_REQ_UNK;
  #ifdef USE_SSL
  	conn->allow_ssl_try = true;
  	conn->wait_ssl_try = false;
***************
*** 3441,3446 ****
--- 3446,3462 ----
  	return status;
  }
  
+ bool
+ PQconnectionUsedPassword(const PGconn *conn)
+ {
+ 	if (conn->areq == AUTH_REQ_MD5 ||
+ 		conn->areq == AUTH_REQ_CRYPT ||
+ 		conn->areq == AUTH_REQ_PASSWORD)
+ 		return true;
+ 	else
+ 		return false;
+ }
+ 
  PGVerbosity
  PQsetErrorVerbosity(PGconn *conn, PGVerbosity verbosity)
  {
Index: src/interfaces/libpq/libpq-fe.h
===================================================================
RCS file: /opt/src/cvs/pgsql/src/interfaces/libpq/libpq-fe.h,v
retrieving revision 1.136
diff -c -r1.136 libpq-fe.h
*** src/interfaces/libpq/libpq-fe.h	3 Mar 2007 19:52:46 -0000	1.136
--- src/interfaces/libpq/libpq-fe.h	7 Jul 2007 21:55:12 -0000
***************
*** 23,32 ****
  #include <stdio.h>
  
  /*
!  * postgres_ext.h defines the backend's externally visible types,
   * such as Oid.
   */
  #include "postgres_ext.h"
  
  /* Application-visible enum types */
  
--- 23,33 ----
  #include <stdio.h>
  
  /*
!  * defines the backend's externally visible types,
   * such as Oid.
   */
  #include "postgres_ext.h"
+ #include "postgres_fe.h"
  
  /* Application-visible enum types */
  
***************
*** 265,270 ****
--- 266,272 ----
  extern int	PQbackendPID(const PGconn *conn);
  extern int	PQclientEncoding(const PGconn *conn);
  extern int	PQsetClientEncoding(PGconn *conn, const char *encoding);
+ extern bool PQconnectionUsedPassword(const PGconn *conn);
  
  /* Get the OpenSSL structure associated with a connection. Returns NULL for
   * unencrypted connections or if any other TLS library is in use. */
Index: src/interfaces/libpq/libpq-int.h
===================================================================
RCS file: /opt/src/cvs/pgsql/src/interfaces/libpq/libpq-int.h,v
retrieving revision 1.119
diff -c -r1.119 libpq-int.h
*** src/interfaces/libpq/libpq-int.h	3 Mar 2007 19:52:47 -0000	1.119
--- src/interfaces/libpq/libpq-int.h	7 Jul 2007 21:09:40 -0000
***************
*** 299,304 ****
--- 299,305 ----
  	SockAddr	raddr;			/* Remote address */
  	ProtocolVersion pversion;	/* FE/BE protocol version in use */
  	int			sversion;		/* server version, e.g. 70401 for 7.4.1 */
+ 	AuthRequest	areq;			/* server demanded password during auth */
  
  	/* Transient state needed while establishing connection */
  	struct addrinfo *addrlist;	/* list of possible backend addresses */
---------------------------(end of broadcast)---------------------------
TIP 7: You can help support the PostgreSQL project by donating at

                http://www.postgresql.org/about/donate

Reply via email to