v2-0001-kerberos-delegation.patch
text/x-patch
Filename: v2-0001-kerberos-delegation.patch
Type: text/x-patch
Part: 0
Patch
Format: unified
Series: patch v2-0001
| File | + | − |
|---|---|---|
| contrib/postgres_fdw/option.c | 3 | 0 |
| src/backend/libpq/auth.c | 7 | 1 |
| src/backend/libpq/be-gssapi-common.c | 37 | 0 |
| src/backend/libpq/be-secure-gssapi.c | 6 | 1 |
| src/include/libpq/be-gssapi-common.h | 2 | 0 |
| src/interfaces/libpq/fe-auth.c | 7 | 2 |
| src/interfaces/libpq/fe-secure-gssapi.c | 1 | 1 |
commit a413b020afb663b5f89722b480c1b453e4304a36
Author: Peifeng Qiu <peifengq@vmware.com>
Date: Thu Jul 22 17:27:21 2021 +0900
kerberos delegation
diff --git a/contrib/postgres_fdw/option.c b/contrib/postgres_fdw/option.c
index 4593cbc540..855f9af09c 100644
--- a/contrib/postgres_fdw/option.c
+++ b/contrib/postgres_fdw/option.c
@@ -247,6 +247,9 @@ InitPgFdwOptions(void)
{"sslcert", UserMappingRelationId, true},
{"sslkey", UserMappingRelationId, true},
+ /* gssencmode is also libpq option, same to above. */
+ {"gssencmode", UserMappingRelationId, true},
+
{NULL, InvalidOid, false}
};
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 <gssapi.h>
#else
#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_ext.h>
#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 */