diff options
Diffstat (limited to 'src/interfaces')
| -rw-r--r-- | src/interfaces/libpq/exports.txt | 1 | ||||
| -rw-r--r-- | src/interfaces/libpq/fe-auth.c | 15 | ||||
| -rw-r--r-- | src/interfaces/libpq/fe-connect.c | 17 | ||||
| -rw-r--r-- | src/interfaces/libpq/fe-secure-gssapi.c | 23 | ||||
| -rw-r--r-- | src/interfaces/libpq/libpq-fe.h | 1 | ||||
| -rw-r--r-- | src/interfaces/libpq/libpq-int.h | 2 |
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? */ |
