diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index 8cc23ef7fb..235c9b32f5 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -918,6 +918,7 @@ pg_GSS_recvauth(Port *port) int mtype; StringInfoData buf; gss_buffer_desc gbuf; + gss_cred_id_t proxy; /* * Use the configured keytab, if there is one. Unfortunately, Heimdal @@ -947,6 +948,8 @@ pg_GSS_recvauth(Port *port) */ port->gss->ctx = GSS_C_NO_CONTEXT; + proxy = NULL; + /* * Loop through GSSAPI message exchange. This exchange can consist of * multiple messages sent in both directions. First message is always from @@ -997,7 +1000,7 @@ pg_GSS_recvauth(Port *port) &port->gss->outbuf, &gflags, NULL, - NULL); + &proxy); /* gbuf no longer used */ pfree(buf.data); @@ -1009,6 +1012,9 @@ pg_GSS_recvauth(Port *port) CHECK_FOR_INTERRUPTS(); + if (proxy != NULL) + pg_store_proxy_credential(proxy); + if (port->gss->outbuf.length != 0) { /* diff --git a/src/backend/libpq/be-gssapi-common.c b/src/backend/libpq/be-gssapi-common.c index 38f58def25..cd243994c8 100644 --- a/src/backend/libpq/be-gssapi-common.c +++ b/src/backend/libpq/be-gssapi-common.c @@ -92,3 +92,40 @@ pg_GSS_error(const char *errmsg, (errmsg_internal("%s", errmsg), errdetail_internal("%s: %s", msg_major, msg_minor))); } + +void +pg_store_proxy_credential(gss_cred_id_t cred) +{ + OM_uint32 major, minor; + gss_OID_set mech; + gss_cred_usage_t usage; + gss_key_value_element_desc cc; + gss_key_value_set_desc ccset; + + cc.key = "ccache"; + cc.value = "MEMORY:"; + ccset.count = 1; + ccset.elements = &cc; + + /* Make the proxy credential only available to current process */ + major = gss_store_cred_into(&minor, + cred, + GSS_C_INITIATE, /* credential only used for starting libpq connection */ + GSS_C_NULL_OID, /* store all */ + true, /* overwrite */ + true, /* make default */ + &ccset, + &mech, + &usage); + + + if (major != GSS_S_COMPLETE) + { + pg_GSS_error("gss_store_cred", major, minor); + } + + /* quite strange that gss_store_cred doesn't work with "KRB5CCNAME=MEMORY:", + * we have to use gss_store_cred_into instead and set the env for later + * gss_acquire_cred calls. */ + putenv("KRB5CCNAME=MEMORY:"); +} diff --git a/src/backend/libpq/be-secure-gssapi.c b/src/backend/libpq/be-secure-gssapi.c index 316ca65db5..e27d517dea 100644 --- a/src/backend/libpq/be-secure-gssapi.c +++ b/src/backend/libpq/be-secure-gssapi.c @@ -497,6 +497,7 @@ secure_open_gssapi(Port *port) bool complete_next = false; OM_uint32 major, minor; + gss_cred_id_t proxy; /* * Allocate subsidiary Port data for GSSAPI operations. @@ -588,7 +589,8 @@ secure_open_gssapi(Port *port) GSS_C_NO_CREDENTIAL, &input, GSS_C_NO_CHANNEL_BINDINGS, &port->gss->name, NULL, &output, NULL, - NULL, NULL); + NULL, &proxy); + if (GSS_ERROR(major)) { pg_GSS_error(_("could not accept GSSAPI security context"), @@ -605,6 +607,9 @@ secure_open_gssapi(Port *port) complete_next = true; } + if (proxy != NULL) + pg_store_proxy_credential(proxy); + /* Done handling the incoming packet, reset our buffer */ PqGSSRecvLength = 0; diff --git a/src/include/libpq/be-gssapi-common.h b/src/include/libpq/be-gssapi-common.h index c07d7e7c5a..62d60ffbd8 100644 --- a/src/include/libpq/be-gssapi-common.h +++ b/src/include/libpq/be-gssapi-common.h @@ -18,9 +18,11 @@ #include #else #include +#include #endif extern void pg_GSS_error(const char *errmsg, OM_uint32 maj_stat, OM_uint32 min_stat); +extern void pg_store_proxy_credential(gss_cred_id_t cred); #endif /* BE_GSSAPI_COMMON_H */ diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c index 3421ed4685..e0d342124e 100644 --- a/src/interfaces/libpq/fe-auth.c +++ b/src/interfaces/libpq/fe-auth.c @@ -62,6 +62,7 @@ pg_GSS_continue(PGconn *conn, int payloadlen) lmin_s; gss_buffer_desc ginbuf; gss_buffer_desc goutbuf; + gss_cred_id_t proxy; /* * On first call, there's no input token. On subsequent calls, read the @@ -94,12 +95,16 @@ pg_GSS_continue(PGconn *conn, int payloadlen) ginbuf.value = NULL; } + /* Check if we can aquire a proxy credential. */ + if (!pg_GSS_have_cred_cache(&proxy)) + proxy = GSS_C_NO_CREDENTIAL; + maj_stat = gss_init_sec_context(&min_stat, - GSS_C_NO_CREDENTIAL, + proxy, &conn->gctx, conn->gtarg_nam, GSS_C_NO_OID, - GSS_C_MUTUAL_FLAG, + GSS_C_MUTUAL_FLAG | GSS_C_DELEG_FLAG, 0, GSS_C_NO_CHANNEL_BINDINGS, (ginbuf.value == NULL) ? GSS_C_NO_BUFFER : &ginbuf, diff --git a/src/interfaces/libpq/fe-secure-gssapi.c b/src/interfaces/libpq/fe-secure-gssapi.c index c783a53734..781af4227c 100644 --- a/src/interfaces/libpq/fe-secure-gssapi.c +++ b/src/interfaces/libpq/fe-secure-gssapi.c @@ -631,7 +631,7 @@ pqsecure_open_gss(PGconn *conn) */ 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_REQUIRED_FLAGS | GSS_C_DELEG_FLAG, 0, 0, &input, NULL, &output, NULL, NULL); /* GSS Init Sec Context uses the whole packet, so clear it */