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 */