summaryrefslogtreecommitdiff
path: root/src/interfaces
diff options
context:
space:
mode:
Diffstat (limited to 'src/interfaces')
-rw-r--r--src/interfaces/libpq/exports.txt1
-rw-r--r--src/interfaces/libpq/fe-auth.c15
-rw-r--r--src/interfaces/libpq/fe-connect.c17
-rw-r--r--src/interfaces/libpq/fe-secure-gssapi.c23
-rw-r--r--src/interfaces/libpq/libpq-fe.h1
-rw-r--r--src/interfaces/libpq/libpq-int.h2
6 files changed, 54 insertions, 5 deletions
diff --git a/src/interfaces/libpq/exports.txt b/src/interfaces/libpq/exports.txt
index e8bcc883709..7ded77aff37 100644
--- a/src/interfaces/libpq/exports.txt
+++ b/src/interfaces/libpq/exports.txt
@@ -186,3 +186,4 @@ PQpipelineStatus 183
PQsetTraceFlags 184
PQmblenBounded 185
PQsendFlushRequest 186
+PQconnectionUsedGSSAPI 187
diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c
index b0550e63324..fe2634230a3 100644
--- a/src/interfaces/libpq/fe-auth.c
+++ b/src/interfaces/libpq/fe-auth.c
@@ -58,7 +58,8 @@ pg_GSS_continue(PGconn *conn, int payloadlen)
{
OM_uint32 maj_stat,
min_stat,
- lmin_s;
+ lmin_s,
+ gss_flags = GSS_C_MUTUAL_FLAG;
gss_buffer_desc ginbuf;
gss_buffer_desc goutbuf;
@@ -92,12 +93,19 @@ pg_GSS_continue(PGconn *conn, int payloadlen)
ginbuf.value = NULL;
}
+ /* Only try to acquire credentials if GSS delegation isn't disabled. */
+ if (!pg_GSS_have_cred_cache(&conn->gcred))
+ conn->gcred = GSS_C_NO_CREDENTIAL;
+
+ if (conn->gssdeleg && pg_strcasecmp(conn->gssdeleg, "enable") == 0)
+ gss_flags |= GSS_C_DELEG_FLAG;
+
maj_stat = gss_init_sec_context(&min_stat,
- GSS_C_NO_CREDENTIAL,
+ conn->gcred,
&conn->gctx,
conn->gtarg_nam,
GSS_C_NO_OID,
- GSS_C_MUTUAL_FLAG,
+ gss_flags,
0,
GSS_C_NO_CHANNEL_BINDINGS,
(ginbuf.value == NULL) ? GSS_C_NO_BUFFER : &ginbuf,
@@ -139,6 +147,7 @@ pg_GSS_continue(PGconn *conn, int payloadlen)
{
conn->client_finished_auth = true;
gss_release_name(&lmin_s, &conn->gtarg_nam);
+ conn->gssapi_used = true;
}
return STATUS_OK;
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 40fef0e2c81..fcd3d0d9a35 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -343,6 +343,10 @@ static const internalPQconninfoOption PQconninfoOptions[] = {
"GSS-library", "", 7, /* sizeof("gssapi") == 7 */
offsetof(struct pg_conn, gsslib)},
+ {"gssdeleg", "PGGSSDELEG", NULL, NULL,
+ "GSS-delegation", "", 8, /* sizeof("disable") == 8 */
+ offsetof(struct pg_conn, gssdeleg)},
+
{"replication", NULL, NULL, NULL,
"Replication", "D", 5,
offsetof(struct pg_conn, replication)},
@@ -617,6 +621,7 @@ pqDropServerData(PGconn *conn)
conn->auth_req_received = false;
conn->client_finished_auth = false;
conn->password_needed = false;
+ conn->gssapi_used = false;
conn->write_failed = false;
free(conn->write_err_msg);
conn->write_err_msg = NULL;
@@ -4448,6 +4453,7 @@ freePGconn(PGconn *conn)
free(conn->gssencmode);
free(conn->krbsrvname);
free(conn->gsslib);
+ free(conn->gssdeleg);
free(conn->connip);
/* Note that conn->Pfdebug is not ours to close or free */
free(conn->write_err_msg);
@@ -7313,6 +7319,17 @@ PQconnectionUsedPassword(const PGconn *conn)
}
int
+PQconnectionUsedGSSAPI(const PGconn *conn)
+{
+ if (!conn)
+ return false;
+ if (conn->gssapi_used)
+ return true;
+ else
+ return false;
+}
+
+int
PQclientEncoding(const PGconn *conn)
{
if (!conn || conn->status != CONNECTION_OK)
diff --git a/src/interfaces/libpq/fe-secure-gssapi.c b/src/interfaces/libpq/fe-secure-gssapi.c
index 038e847b7e9..bf87ae3fd1a 100644
--- a/src/interfaces/libpq/fe-secure-gssapi.c
+++ b/src/interfaces/libpq/fe-secure-gssapi.c
@@ -477,7 +477,8 @@ pqsecure_open_gss(PGconn *conn)
{
ssize_t ret;
OM_uint32 major,
- minor;
+ minor,
+ gss_flags = GSS_REQUIRED_FLAGS;
uint32 netlen;
PostgresPollingStatusType result;
gss_buffer_desc input = GSS_C_EMPTY_BUFFER,
@@ -621,13 +622,30 @@ pqsecure_open_gss(PGconn *conn)
if (ret != STATUS_OK)
return PGRES_POLLING_FAILED;
+ if (conn->gssdeleg && pg_strcasecmp(conn->gssdeleg, "enable") == 0)
+ {
+ /* Acquire credentials if possbile */
+ if (conn->gcred == GSS_C_NO_CREDENTIAL)
+ (void) pg_GSS_have_cred_cache(&conn->gcred);
+
+ /*
+ * We have credentials and gssdeleg is enabled, so request credential
+ * delegation. This may or may not actually result in credentials
+ * being delegated- it depends on if the forwardable flag has been set
+ * in the credential and if the server is configured to accept
+ * delegated credentials.
+ */
+ if (conn->gcred != GSS_C_NO_CREDENTIAL)
+ gss_flags |= GSS_C_DELEG_FLAG;
+ }
+
/*
* Call GSS init context, either with an empty input, or with a complete
* packet from the server.
*/
major = gss_init_sec_context(&minor, conn->gcred, &conn->gctx,
conn->gtarg_nam, GSS_C_NO_OID,
- GSS_REQUIRED_FLAGS, 0, 0, &input, NULL,
+ gss_flags, 0, 0, &input, NULL,
&output, NULL, NULL);
/* GSS Init Sec Context uses the whole packet, so clear it */
@@ -647,6 +665,7 @@ pqsecure_open_gss(PGconn *conn)
* to do GSS wrapping/unwrapping.
*/
conn->gssenc = true;
+ conn->gssapi_used = true;
/* Clean up */
gss_release_cred(&minor, &conn->gcred);
diff --git a/src/interfaces/libpq/libpq-fe.h b/src/interfaces/libpq/libpq-fe.h
index f3d92204964..7476dbe0e90 100644
--- a/src/interfaces/libpq/libpq-fe.h
+++ b/src/interfaces/libpq/libpq-fe.h
@@ -354,6 +354,7 @@ extern int PQbackendPID(const PGconn *conn);
extern PGpipelineStatus PQpipelineStatus(const PGconn *conn);
extern int PQconnectionNeedsPassword(const PGconn *conn);
extern int PQconnectionUsedPassword(const PGconn *conn);
+extern int PQconnectionUsedGSSAPI(const PGconn *conn);
extern int PQclientEncoding(const PGconn *conn);
extern int PQsetClientEncoding(PGconn *conn, const char *encoding);
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index d93e976ca57..ce0167c1b66 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -404,6 +404,7 @@ struct pg_conn
char *krbsrvname; /* Kerberos service name */
char *gsslib; /* What GSS library to use ("gssapi" or
* "sspi") */
+ char *gssdeleg; /* Try to delegate GSS credentials? */
char *ssl_min_protocol_version; /* minimum TLS protocol version */
char *ssl_max_protocol_version; /* maximum TLS protocol version */
char *target_session_attrs; /* desired session properties */
@@ -465,6 +466,7 @@ struct pg_conn
int sversion; /* server version, e.g. 70401 for 7.4.1 */
bool auth_req_received; /* true if any type of auth req received */
bool password_needed; /* true if server demanded a password */
+ bool gssapi_used; /* true if authenticated via gssapi */
bool sigpipe_so; /* have we masked SIGPIPE via SO_NOSIGPIPE? */
bool sigpipe_flag; /* can we mask SIGPIPE via MSG_NOSIGNAL? */
bool write_failed; /* have we had a write failure on sock? */