Hi,

This is a small patch (against master) to allow an application using libpq with GSSAPI authentication to specify where to fetch the credential cache from -- it effectively consists of a new field in PQconninfoOptions to store this data and (where the user has specified a ccache location) a call into the gss_krb5_ccache_name function in the GSSAPI library.

It's my first go at submitting a patch -- it works as far as I can tell, but I suspect there will probably still be stuff to fix before it's ready to use!

As far as I'm concerned this is working (the code compiles successfully following "./configure --with-gssapi --enable-cassert", and seems to work for specifying the ccache location without any noticeable errors).

I hope there shouldn't be anything platform-specific here (I've been working on Ubuntu Linux but the only interactions with external applications are via the GSSAPI library, which was already in use).

The dispsize value for ccache_name is 64 in this code (which seems to be what's used with other file-path-like parameters in the existing code) but I'm happy to have this corrected if it needs a different value -- as far as I can tell this is just for display purposes rather than anything critical in terms of actually storing the value?

If no ccache_name is specified in the connection string then it defaults to NULL, which means the gss_krb5_ccache_name call is not made and the current behaviour (of letting the GSSAPI library work out the location of the ccache) is not changed.

Many thanks,
Daniel

diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index 7bcb7504a6..ffdec1ba40 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -1974,6 +1974,20 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
        </para>
       </listitem>
      </varlistentry>
+
+     <varlistentry id="libpq-connect-ccache-name" xreflabel="ccache_name">
+      <term><literal>ccache_name</literal></term>
+      <listitem>
+       <para>
+        Location of credential cache for GSSAPI authentication, which will be passed on to the
+        GSSAPI library via a <literal>gss_krb5_ccache_name</literal> call.
+        If no name is specified, the <literal>gss_krb5_ccache_name</literal> call will not be
+        made and the location of the credential cache will be left for the system GSSAPI library
+        to determine.
+       </para>
+      </listitem>
+     </varlistentry>
+
     </variablelist>
    </para>
   </sect2>
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index aa654dd6a8..8464c9c6de 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -345,6 +345,12 @@ static const internalPQconninfoOption PQconninfoOptions[] = {
 		"Target-Session-Attrs", "", 15, /* sizeof("prefer-standby") = 15 */
 	offsetof(struct pg_conn, target_session_attrs)},
 
+#ifdef ENABLE_GSS
+	{"ccache_name", NULL, NULL, NULL,
+		"Credential-cache-name", "", 64,
+	offsetof(struct pg_conn, ccache_name)},
+#endif
+
 	/* Terminating entry --- MUST BE LAST */
 	{NULL, NULL, NULL, NULL,
 	NULL, NULL, 0}
@@ -2888,7 +2894,7 @@ keep_going:						/* We will come back to here until there is
 				 * regular startup below).
 				 */
 				if (conn->try_gss && !conn->gctx)
-					conn->try_gss = pg_GSS_have_cred_cache(&conn->gcred);
+					conn->try_gss = pg_GSS_have_cred_cache(&conn->gcred, conn->ccache_name);
 				if (conn->try_gss && !conn->gctx)
 				{
 					ProtocolVersion pv = pg_hton32(NEGOTIATE_GSS_CODE);
@@ -4129,6 +4135,11 @@ freePGconn(PGconn *conn)
 	termPQExpBuffer(&conn->errorMessage);
 	termPQExpBuffer(&conn->workBuffer);
 
+#ifdef ENABLE_GSS
+	if (conn->ccache_name)
+		free(conn->ccache_name);
+#endif
+
 	free(conn);
 }
 
diff --git a/src/interfaces/libpq/fe-gssapi-common.c b/src/interfaces/libpq/fe-gssapi-common.c
index b26fbf8a9f..17e42d2c80 100644
--- a/src/interfaces/libpq/fe-gssapi-common.c
+++ b/src/interfaces/libpq/fe-gssapi-common.c
@@ -57,12 +57,16 @@ pg_GSS_error(const char *mprefix, PGconn *conn,
  * Check if we can acquire credentials at all (and yield them if so).
  */
 bool
-pg_GSS_have_cred_cache(gss_cred_id_t *cred_out)
+pg_GSS_have_cred_cache(gss_cred_id_t *cred_out, const char *ccache_name)
 {
 	OM_uint32	major,
 				minor;
 	gss_cred_id_t cred = GSS_C_NO_CREDENTIAL;
 
+	if (ccache_name != NULL) {
+		gss_krb5_ccache_name(&minor, ccache_name, NULL);
+	}
+
 	major = gss_acquire_cred(&minor, GSS_C_NO_NAME, 0, GSS_C_NO_OID_SET,
 							 GSS_C_INITIATE, &cred, NULL, NULL);
 	if (major != GSS_S_COMPLETE)
diff --git a/src/interfaces/libpq/fe-gssapi-common.h b/src/interfaces/libpq/fe-gssapi-common.h
index 477660660a..fcb693ac94 100644
--- a/src/interfaces/libpq/fe-gssapi-common.h
+++ b/src/interfaces/libpq/fe-gssapi-common.h
@@ -20,7 +20,7 @@
 
 void		pg_GSS_error(const char *mprefix, PGconn *conn,
 						 OM_uint32 maj_stat, OM_uint32 min_stat);
-bool		pg_GSS_have_cred_cache(gss_cred_id_t *cred_out);
+bool		pg_GSS_have_cred_cache(gss_cred_id_t *cred_out, const char *ccache_name);
 int			pg_GSS_load_servicename(PGconn *conn);
 
 #endif
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index e81dc37906..0bf2087e5d 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -529,6 +529,8 @@ struct pg_conn
 #ifdef ENABLE_GSS
 	gss_ctx_id_t gctx;			/* GSS context */
 	gss_name_t	gtarg_nam;		/* GSS target name */
+	char		*ccache_name;		/* Location of credential cache */
+
 
 	/* The following are encryption-only */
 	bool		try_gss;		/* GSS attempting permitted */

Reply via email to