[PATCH v1] GSSAPI encryption support

Поиск
Список
Период
Сортировка
От Robbie Harwood
Тема [PATCH v1] GSSAPI encryption support
Дата
Msg-id jlg1tgq1ktm.fsf@thriss.redhat.com
обсуждение исходный текст
Ответы Re: [PATCH v1] GSSAPI encryption support  (Stephen Frost <sfrost@snowman.net>)
Re: [PATCH v1] GSSAPI encryption support  (Michael Paquier <michael.paquier@gmail.com>)
Re: [PATCH v1] GSSAPI encryption support  (Andres Freund <andres@anarazel.de>)
Re: [PATCH v3] GSSAPI encryption support  (Robbie Harwood <rharwood@redhat.com>)
Re: [PATCH v4] GSSAPI encryption support  (Robbie Harwood <rharwood@redhat.com>)
[PATCH v6] GSSAPI encryption support  (Robbie Harwood <rharwood@redhat.com>)
[PATCH v7] GSSAPI encryption support  (Robbie Harwood <rharwood@redhat.com>)
[PATCH v8] GSSAPI encryption support  (Robbie Harwood <rharwood@redhat.com>)
Re: [PATCH v1] GSSAPI encryption support  (Robbie Harwood <rharwood@redhat.com>)
Re: [PATCH v10] GSSAPI encryption support  (Robbie Harwood <rharwood@redhat.com>)
Re: [PATCH v11] GSSAPI encryption support  (Robbie Harwood <rharwood@redhat.com>)
Re: [PATCH v12] GSSAPI encryption support  (Robbie Harwood <rharwood@redhat.com>)
Re: [PATCH v14] GSSAPI encryption support  (Robbie Harwood <rharwood@redhat.com>)
[PATCH v20] GSSAPI encryption support  (Robbie Harwood <rharwood@redhat.com>)
Список pgsql-hackers
Hello -hackers,

As previously discussed on this list, I have coded up GSSAPI encryption
support.  If it is easier for anyone, this code is also available for
viewing on my github:
https://github.com/postgres/postgres/compare/master...frozencemetery:feature/gssencrypt

Fallback support is present in both directions for talking to old client
and old servers; GSSAPI encryption is by default auto-upgraded to where
available (for compatibility), but both client and server contain
settings for requiring it.

There are 8 commits in this series; I have tried to err on the side of
creating too much separation rather than too little.  A patch for each
is attached.  This is v1 of the series.

Thanks!

From f506ba6ab6755f56c8aadba7d72a8839d5fbc0d9 Mon Sep 17 00:00:00 2001
From: "Robbie Harwood (frozencemetery)" <rharwood@redhat.com>
Date: Mon, 8 Jun 2015 19:27:45 -0400
Subject: build: Define with_gssapi for use in Makefiles

This is needed in order to control build of GSSAPI components.
---
 configure              | 2 ++
 configure.in           | 1 +
 src/Makefile.global.in | 1 +
 3 files changed, 4 insertions(+)

diff --git a/configure b/configure
index 0407c4f..b9bab06 100755
--- a/configure
+++ b/configure
@@ -711,6 +711,7 @@ with_uuid
 with_selinux
 with_openssl
 krb_srvtab
+with_gssapi
 with_python
 with_perl
 with_tcl
@@ -5452,6 +5453,7 @@ $as_echo "$with_gssapi" >&6; }



+
 #
 # Kerberos configuration parameters
 #
diff --git a/configure.in b/configure.in
index 1de41a2..113bd65 100644
--- a/configure.in
+++ b/configure.in
@@ -635,6 +635,7 @@ PGAC_ARG_BOOL(with, gssapi, no, [build with GSSAPI support],
   krb_srvtab="FILE:\$(sysconfdir)/krb5.keytab"
 ])
 AC_MSG_RESULT([$with_gssapi])
+AC_SUBST(with_gssapi)


 AC_SUBST(krb_srvtab)
diff --git a/src/Makefile.global.in b/src/Makefile.global.in
index c583b44..e50c87d 100644
--- a/src/Makefile.global.in
+++ b/src/Makefile.global.in
@@ -167,6 +167,7 @@ with_perl    = @with_perl@
 with_python    = @with_python@
 with_tcl    = @with_tcl@
 with_openssl    = @with_openssl@
+with_gssapi     = @with_gssapi@
 with_selinux    = @with_selinux@
 with_libxml    = @with_libxml@
 with_libxslt    = @with_libxslt@
--
2.1.4

From d5b973752968f87c9bb2ff9434d523657eb4ba67 Mon Sep 17 00:00:00 2001
From: "Robbie Harwood (frozencemetery)" <rharwood@redhat.com>
Date: Mon, 8 Jun 2015 20:16:42 -0400
Subject: client: Disable GSS encryption on old servers

---
 src/interfaces/libpq/fe-connect.c   | 34 ++++++++++++++++++++++++++++++++--
 src/interfaces/libpq/fe-protocol3.c |  5 +++++
 src/interfaces/libpq/libpq-int.h    |  1 +
 3 files changed, 38 insertions(+), 2 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index a45f4cb..c6c551a 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -91,8 +91,9 @@ static int ldapServiceLookup(const char *purl, PQconninfoOption *options,
  * application_name in a startup packet.  We hard-wire the value rather
  * than looking into errcodes.h since it reflects historical behavior
  * rather than that of the current code.
+ * Servers that do not support GSS encryption will also return this error.
  */
-#define ERRCODE_APPNAME_UNKNOWN "42704"
+#define ERRCODE_UNKNOWN_PARAM "42704"

 /* This is part of the protocol so just define it */
 #define ERRCODE_INVALID_PASSWORD "28P01"
@@ -2552,6 +2553,35 @@ keep_going:                        /* We will come back to here until there is
                     if (res->resultStatus != PGRES_FATAL_ERROR)
                         appendPQExpBufferStr(&conn->errorMessage,
                                              libpq_gettext("unexpected message from server during startup\n"));
+#ifdef ENABLE_GSS
+                    else if (!conn->gss_disable_enc)
+                    {
+                        /*
+                         * We tried to request GSS encryption, but the server
+                         * doesn't support it.  Hang up and try again.  A
+                         * connection that doesn't support appname will also
+                         * not support GSSAPI encryption, so this check goes
+                         * before that check.  See comment below.
+                         */
+                        const char *sqlstate;
+
+                        sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE);
+                        if (sqlstate &&
+                            strcmp(sqlstate, ERRCODE_UNKNOWN_PARAM) == 0)
+                        {
+                            OM_uint32 minor;
+
+                            PQclear(res);
+                            conn->gss_disable_enc = true;
+                            /* Must drop the old connection */
+                            pqDropConnection(conn);
+                            conn->status = CONNECTION_NEEDED;
+                            gss_delete_sec_context(&minor, &conn->gctx,
+                                                   GSS_C_NO_BUFFER);
+                            goto keep_going;
+                        }
+                    }
+#endif
                     else if (conn->send_appname &&
                              (conn->appname || conn->fbappname))
                     {
@@ -2569,7 +2599,7 @@ keep_going:                        /* We will come back to here until there is

                         sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE);
                         if (sqlstate &&
-                            strcmp(sqlstate, ERRCODE_APPNAME_UNKNOWN) == 0)
+                            strcmp(sqlstate, ERRCODE_UNKNOWN_PARAM) == 0)
                         {
                             PQclear(res);
                             conn->send_appname = false;
diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c
index a847f08..0deaa0f 100644
--- a/src/interfaces/libpq/fe-protocol3.c
+++ b/src/interfaces/libpq/fe-protocol3.c
@@ -2051,6 +2051,11 @@ build_startup_packet(const PGconn *conn, char *packet,
     if (conn->client_encoding_initial && conn->client_encoding_initial[0])
         ADD_STARTUP_OPTION("client_encoding", conn->client_encoding_initial);

+#ifdef ENABLE_GSS
+    if (!conn->gss_disable_enc)
+        ADD_STARTUP_OPTION("gss_encrypt", "on");
+#endif
+
     /* Add any environment-driven GUC settings needed */
     for (next_eo = options; next_eo->envName; next_eo++)
     {
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 2175957..1578d76 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -445,6 +445,7 @@ struct pg_conn
     gss_name_t    gtarg_nam;        /* GSS target name */
     gss_buffer_desc ginbuf;        /* GSS input token */
     gss_buffer_desc goutbuf;    /* GSS output token */
+    bool gss_disable_enc;        /* Does server recognize gss_encrypt? */
 #endif

 #ifdef ENABLE_SSPI
--
2.1.4

From 36bd232742eb2b920d2cd88dd06176cde7e26cb2 Mon Sep 17 00:00:00 2001
From: "Robbie Harwood (frozencemetery)" <rharwood@redhat.com>
Date: Mon, 8 Jun 2015 21:20:23 -0400
Subject: client: GSSAPI encryption and decryption

---
 src/interfaces/libpq/Makefile        |  4 ++
 src/interfaces/libpq/fe-auth.c       |  2 +-
 src/interfaces/libpq/fe-auth.h       |  5 ++
 src/interfaces/libpq/fe-connect.c    |  5 ++
 src/interfaces/libpq/fe-misc.c       |  5 ++
 src/interfaces/libpq/fe-protocol3.c  | 27 +++++++++++
 src/interfaces/libpq/fe-secure-gss.c | 92 ++++++++++++++++++++++++++++++++++++
 src/interfaces/libpq/libpq-int.h     |  7 +++
 8 files changed, 146 insertions(+), 1 deletion(-)
 create mode 100644 src/interfaces/libpq/fe-secure-gss.c

diff --git a/src/interfaces/libpq/Makefile b/src/interfaces/libpq/Makefile
index c2105f1..a9fb194 100644
--- a/src/interfaces/libpq/Makefile
+++ b/src/interfaces/libpq/Makefile
@@ -48,6 +48,10 @@ ifeq ($(with_openssl),yes)
 OBJS += fe-secure-openssl.o
 endif

+ifeq ($(with_gssapi),yes)
+OBJS += fe-secure-gss.o
+endif
+
 ifeq ($(PORTNAME), cygwin)
 override shlib = cyg$(NAME)$(DLSUFFIX)
 endif
diff --git a/src/interfaces/libpq/fe-auth.c b/src/interfaces/libpq/fe-auth.c
index 5891c75..af6dfff 100644
--- a/src/interfaces/libpq/fe-auth.c
+++ b/src/interfaces/libpq/fe-auth.c
@@ -82,7 +82,7 @@ pg_GSS_error_int(PQExpBuffer str, const char *mprefix,
 /*
  * GSSAPI errors contain two parts; put both into conn->errorMessage.
  */
-static void
+void
 pg_GSS_error(const char *mprefix, PGconn *conn,
              OM_uint32 maj_stat, OM_uint32 min_stat)
 {
diff --git a/src/interfaces/libpq/fe-auth.h b/src/interfaces/libpq/fe-auth.h
index 8d35767..5702a2d 100644
--- a/src/interfaces/libpq/fe-auth.h
+++ b/src/interfaces/libpq/fe-auth.h
@@ -21,4 +21,9 @@
 extern int    pg_fe_sendauth(AuthRequest areq, PGconn *conn);
 extern char *pg_fe_getauthname(PQExpBuffer errorMessage);

+#ifdef ENABLE_GSS
+void pg_GSS_error(const char *mprefix, PGconn *conn, OM_uint32 maj_stat,
+                  OM_uint32 min_stat);
+#endif
+
 #endif   /* FE_AUTH_H */
diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index c6c551a..8fb0a90 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -2513,6 +2513,11 @@ keep_going:                        /* We will come back to here until there is
                     /* We are done with authentication exchange */
                     conn->status = CONNECTION_AUTH_OK;

+#ifdef ENABLE_GSS
+                    if (conn->gctx != 0)
+                        conn->gss_auth_done = true;
+#endif
+
                     /*
                      * Set asyncStatus so that PQgetResult will think that
                      * what comes back next is the result of a query.  See
diff --git a/src/interfaces/libpq/fe-misc.c b/src/interfaces/libpq/fe-misc.c
index 0dbcf73..2379aff 100644
--- a/src/interfaces/libpq/fe-misc.c
+++ b/src/interfaces/libpq/fe-misc.c
@@ -604,6 +604,11 @@ pqPutMsgEnd(PGconn *conn)
         memcpy(conn->outBuffer + conn->outMsgStart, &msgLen, 4);
     }

+#ifdef ENABLE_GSS
+    if (pggss_encrypt(conn) < 0)
+        return EOF;
+#endif
+
     /* Make message eligible to send */
     conn->outCount = conn->outMsgEnd;

diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c
index 0deaa0f..65acfd1 100644
--- a/src/interfaces/libpq/fe-protocol3.c
+++ b/src/interfaces/libpq/fe-protocol3.c
@@ -129,6 +129,33 @@ pqParseInput3(PGconn *conn)
             return;
         }

+#ifdef ENABLE_GSS
+        /* We want to be ready in both IDLE and BUSY states for encryption */
+        if (id == 'g')
+        {
+            ssize_t encEnd, next;
+
+            encEnd = pggss_inplace_decrypt(conn, msgLength);
+            if (encEnd <= 0)
+            {
+                /* error message placed by pggss_inplace_decrypt() */
+                pqSaveErrorResult(conn);
+                conn->asyncStatus = PGASYNC_READY;
+                pqDropConnection(conn);
+                conn->status = CONNECTION_BAD;
+                return;
+            }
+
+            /* shift contents of buffer to account for slack */
+            encEnd += conn->inStart;
+            next = conn->inStart + msgLength + 5;
+            memmove(conn->inBuffer + encEnd, conn->inBuffer + next,
+                    conn->inEnd - next);
+            conn->inEnd = (conn->inEnd - next) + encEnd;
+            continue;
+        }
+#endif
+
         /*
          * NOTIFY and NOTICE messages can happen in any state; always process
          * them right away.
diff --git a/src/interfaces/libpq/fe-secure-gss.c b/src/interfaces/libpq/fe-secure-gss.c
new file mode 100644
index 0000000..afea9c3
--- /dev/null
+++ b/src/interfaces/libpq/fe-secure-gss.c
@@ -0,0 +1,92 @@
+#include <assert.h>
+
+#include "libpq-fe.h"
+#include "postgres_fe.h"
+#include "fe-auth.h"
+#include "libpq-int.h"
+
+ssize_t
+pggss_inplace_decrypt(PGconn *conn, int gsslen)
+{
+    OM_uint32 major, minor;
+    gss_buffer_desc input, output;
+    ssize_t n;
+    int conf;
+
+    input.length = gsslen;
+    input.value = conn->inBuffer + conn->inCursor;
+    output.length = 0;
+    output.value = NULL;
+
+    major = gss_unwrap(&minor, conn->gctx, &input, &output, &conf, NULL);
+    if (GSS_ERROR(major))
+    {
+        pg_GSS_error("GSSAPI unwrap error", conn, major, minor);
+        return -1;
+    }
+    else if (conf == 0)
+    {
+        printfPQExpBuffer(&conn->errorMessage,
+                          libpq_gettext(
+                              "received GSSAPI message without confidentiality\n"));
+        return -1;
+    }
+
+    memcpy(conn->inBuffer + conn->inStart, output.value, output.length);
+    n = output.length;
+    gss_release_buffer(&minor, &output);
+    return n;
+}
+
+int
+pggss_encrypt(PGconn *conn)
+{
+    OM_uint32 major, minor;
+    gss_buffer_desc input, output;
+    int msgLen, conf;
+    uint32 len_n;
+
+    if (conn->gss_disable_enc || !conn->gctx || !conn->gss_auth_done)
+        return 0;
+    assert(conn->outMsgStart > 0);
+
+    /* We need to encrypt message type as well */
+    conn->outMsgStart -= 1;
+    msgLen = conn->outMsgEnd - conn->outMsgStart;
+
+    input.value = conn->outBuffer + conn->outMsgStart;
+    input.length = msgLen;
+    output.length = 0;
+    output.value = NULL;
+
+    major = gss_wrap(&minor, conn->gctx, 1, GSS_C_QOP_DEFAULT, &input, &conf,
+                     &output);
+    if (GSS_ERROR(major))
+    {
+        pg_GSS_error("GSSAPI wrap error", conn, major, minor);
+        return -1;
+    }
+    else if (conf == 0)
+    {
+        printfPQExpBuffer(&conn->errorMessage,
+                          libpq_gettext(
+                              "Failed to obtain confidentiality for outgoing GSSAPI message\n"));
+        return -1;
+    }
+
+    msgLen = output.length + 4;
+    if (pqCheckOutBufferSpace(conn->outMsgStart + msgLen + 1, conn))
+        return -1;
+
+    conn->outBuffer[conn->outMsgStart] = 'g'; /* GSSAPI message */
+
+    len_n = htonl(msgLen);
+    memcpy(conn->outBuffer + conn->outMsgStart + 1, &len_n, 4);
+
+    memcpy(conn->outBuffer + conn->outMsgStart + 1 + 4,
+             output.value, output.length);
+    conn->outMsgEnd = conn->outMsgStart + msgLen + 1;
+
+    gss_release_buffer(&minor, &output);
+    return msgLen + 1;
+}
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 1578d76..ff2e39d 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -446,6 +446,7 @@ struct pg_conn
     gss_buffer_desc ginbuf;        /* GSS input token */
     gss_buffer_desc goutbuf;    /* GSS output token */
     bool gss_disable_enc;        /* Does server recognize gss_encrypt? */
+    bool gss_auth_done;            /* Did we finish the AUTH step? */
 #endif

 #ifdef ENABLE_SSPI
@@ -643,6 +644,12 @@ extern bool pgtls_read_pending(PGconn *conn);
 extern ssize_t pgtls_write(PGconn *conn, const void *ptr, size_t len);

 /*
+ * GSSAPI encryption functions defined in fe-secure-gss.c
+ */
+extern ssize_t pggss_inplace_decrypt(PGconn *conn, int gsslen);
+extern int pggss_encrypt(PGconn *conn);
+
+/*
  * this is so that we can check if a connection is non-blocking internally
  * without the overhead of a function call
  */
--
2.1.4

From 0991d42173394e68e989d84e6574476d6a98e571 Mon Sep 17 00:00:00 2001
From: "Robbie Harwood (frozencemetery)" <rharwood@redhat.com>
Date: Tue, 9 Jun 2015 14:38:26 -0400
Subject: server: GSSAPI encryption and decryption

---
 src/backend/libpq/Makefile        |   4 ++
 src/backend/libpq/auth.c          |   2 +-
 src/backend/libpq/be-secure-gss.c | 101 ++++++++++++++++++++++++++++++++++++++
 src/backend/libpq/pqcomm.c        |  39 +++++++++++++++
 src/backend/tcop/postgres.c       |  18 ++++++-
 src/backend/utils/misc/guc.c      |  19 +++++++
 src/include/libpq/auth.h          |   5 ++
 src/include/libpq/libpq-be.h      |   9 ++++
 src/include/libpq/libpq.h         |   4 ++
 9 files changed, 199 insertions(+), 2 deletions(-)
 create mode 100644 src/backend/libpq/be-secure-gss.c

diff --git a/src/backend/libpq/Makefile b/src/backend/libpq/Makefile
index 09410c4..359e9d5 100644
--- a/src/backend/libpq/Makefile
+++ b/src/backend/libpq/Makefile
@@ -21,4 +21,8 @@ ifeq ($(with_openssl),yes)
 OBJS += be-secure-openssl.o
 endif

+ifeq ($(with_gssapi),yes)
+OBJS += be-secure-gss.o
+endif
+
 include $(top_srcdir)/src/backend/common.mk
diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c
index 4699efa..913d356 100644
--- a/src/backend/libpq/auth.c
+++ b/src/backend/libpq/auth.c
@@ -728,7 +728,7 @@ static GSS_DLLIMP gss_OID GSS_C_NT_USER_NAME = &GSS_C_NT_USER_NAME_desc;
 #endif


-static void
+void
 pg_GSS_error(int severity, char *errmsg, OM_uint32 maj_stat, OM_uint32 min_stat)
 {
     gss_buffer_desc gmsg;
diff --git a/src/backend/libpq/be-secure-gss.c b/src/backend/libpq/be-secure-gss.c
new file mode 100644
index 0000000..64a4ed7
--- /dev/null
+++ b/src/backend/libpq/be-secure-gss.c
@@ -0,0 +1,101 @@
+#include <assert.h>
+
+#include "postgres.h"
+
+#include "libpq/libpq.h"
+#include "libpq/auth.h"
+#include "miscadmin.h"
+
+/* GUC value */
+bool gss_encrypt;
+
+size_t
+be_gss_encrypt(Port *port, char msgtype, const char **msgptr, size_t len)
+{
+    OM_uint32 major, minor;
+    gss_buffer_desc input, output;
+    uint32 len_n;
+    int conf;
+    char *ptr = *((char **)msgptr);
+    char *newbuf = palloc(len + 5);
+
+    len += 4;
+    len_n = htonl(len);
+
+    newbuf[0] = msgtype;
+    memcpy(newbuf + 1, &len_n, 4);
+    memcpy(newbuf + 5, ptr, len - 4);
+
+    input.length = len + 1; /* include type */
+    input.value = newbuf;
+    output.length = 0;
+    output.value = NULL;
+
+    major = gss_wrap(&minor, port->gss->ctx, 1, GSS_C_QOP_DEFAULT, &input,
+                     &conf, &output);
+    if (GSS_ERROR(major))
+    {
+        pg_GSS_error(ERROR, gettext_noop("unwrapping GSS message failed"),
+                     major, minor);
+        return -1;
+    }
+    assert(conf);
+
+    newbuf = repalloc(newbuf, output.length);
+    memcpy(newbuf, output.value, output.length);
+
+    len = output.length;
+    *msgptr = newbuf;
+    gss_release_buffer(&minor, &output);
+
+    return len;
+}
+
+int
+be_gss_inplace_decrypt(StringInfo inBuf)
+{
+    OM_uint32 major, minor;
+    gss_buffer_desc input, output;
+    int qtype, conf;
+    size_t msglen = 0;
+
+    input.length = inBuf->len;
+    input.value = inBuf->data;
+    output.length = 0;
+    output.value = NULL;
+
+    major = gss_unwrap(&minor, MyProcPort->gss->ctx, &input, &output,
+                       &conf, NULL);
+    if (GSS_ERROR(major))
+    {
+        pg_GSS_error(ERROR, gettext_noop("wrapping GSS message failed"),
+                     major, minor);
+        return -1;
+    }
+    else if (conf == 0)
+    {
+        ereport(COMMERROR,
+                (errcode(ERRCODE_PROTOCOL_VIOLATION),
+                 errmsg("Expected GSSAPI confidentiality but it was not received")));
+        return -1;
+    }
+
+    qtype = ((char *)output.value)[0]; /* first byte is message type */
+    inBuf->len = output.length - 5; /* message starts */
+
+    memcpy((char *)&msglen, ((char *)output.value) + 1, 4);
+    msglen = ntohl(msglen);
+    if (msglen - 4 != inBuf->len)
+    {
+        ereport(COMMERROR,
+                (errcode(ERRCODE_PROTOCOL_VIOLATION),
+                 errmsg("Length value inside GSSAPI-encrypted packet was malformed")));
+        return -1;
+    }
+
+    memcpy(inBuf->data, ((char *)output.value) + 5, inBuf->len);
+    inBuf->data[inBuf->len] = '\0'; /* invariant */
+    gss_release_buffer(&minor, &output);
+
+    return qtype;
+}
diff --git a/src/backend/libpq/pqcomm.c b/src/backend/libpq/pqcomm.c
index a4b37ed..5a929a8 100644
--- a/src/backend/libpq/pqcomm.c
+++ b/src/backend/libpq/pqcomm.c
@@ -1485,6 +1485,19 @@ socket_putmessage(char msgtype, const char *s, size_t len)
 {
     if (DoingCopyOut || PqCommBusy)
         return 0;
+
+#ifdef ENABLE_GSS
+    /* Do not wrap auth requests. */
+    if (MyProcPort->hba->auth_method == uaGSS && gss_encrypt &&
+        msgtype != 'R' && msgtype != 'g')
+    {
+        len = be_gss_encrypt(MyProcPort, msgtype, &s, len);
+        if (len < 0)
+            goto fail;
+        msgtype = 'g';
+    }
+#endif
+
     PqCommBusy = true;
     if (msgtype)
         if (internal_putbytes(&msgtype, 1))
@@ -1500,10 +1513,20 @@ socket_putmessage(char msgtype, const char *s, size_t len)
     if (internal_putbytes(s, len))
         goto fail;
     PqCommBusy = false;
+#ifdef ENABLE_GSS
+    /* if we're GSSAPI encrypting, s was allocated in be_gss_encrypt */
+    if (msgtype == 'g')
+        pfree((char *)s);
+#endif
     return 0;

 fail:
     PqCommBusy = false;
+#ifdef ENABLE_GSS
+    /* if we're GSSAPI encrypting, s was allocated in be_gss_encrypt */
+    if (msgtype == 'g')
+        pfree((char *)s);
+#endif
     return EOF;
 }

@@ -1519,6 +1542,22 @@ socket_putmessage_noblock(char msgtype, const char *s, size_t len)
     int res        PG_USED_FOR_ASSERTS_ONLY;
     int            required;

+#ifdef ENABLE_GSS
+    /*
+     * Because socket_putmessage is also a front-facing function, we need the
+     * ability to GSSAPI encrypt from either.  Since socket_putmessage_noblock
+     * calls into socket_putmessage, socket_putmessage will handle freeing the
+     * allocated string.
+     */
+    if (gss_encrypt && msgtype != 'R' && msgtype != 'g')
+    {
+        len = be_gss_encrypt(MyProcPort, msgtype, &s, len);
+        if (len < 0)
+            return;
+        msgtype = 'g';
+    }
+#endif
+
     /*
      * Ensure we have enough space in the output buffer for the message header
      * as well as the message itself.
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index ce4bdaf..8510908 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -336,6 +336,7 @@ static int
 SocketBackend(StringInfo inBuf)
 {
     int            qtype;
+    bool        msg_got = false;

     /*
      * Get message type code from the frontend.
@@ -365,6 +366,21 @@ SocketBackend(StringInfo inBuf)
         return qtype;
     }

+#ifdef ENABLE_GSS
+    else if (qtype == 'g' && gss_encrypt &&
+             MyProcPort->hba->auth_method == uaGSS)
+    {
+        /* GSSAPI wrapping implies protocol >= 3 */
+        if (pq_getmessage(inBuf, 0))
+            return EOF;
+        msg_got = true;
+
+        qtype = be_gss_inplace_decrypt(inBuf);
+        if (qtype < 0)
+            return EOF;
+    }
+#endif
+
     /*
      * Validate message type code before trying to read body; if we have lost
      * sync, better to say "command unknown" than to run out of memory because
@@ -490,7 +506,7 @@ SocketBackend(StringInfo inBuf)
      * after the type code; we can read the message contents independently of
      * the type.
      */
-    if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
+    if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3 && !msg_got)
     {
         if (pq_getmessage(inBuf, 0))
             return EOF;            /* suitable message already logged */
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index 0356ecb..a978af0 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -186,6 +186,10 @@ static const char *show_log_file_mode(void);
 static ConfigVariable *ProcessConfigFileInternal(GucContext context,
                           bool applySettings, int elevel);

+#ifdef ENABLE_GSS
+static void assign_gss_encrypt(bool newval, void *extra);
+#endif
+

 /*
  * Options for enum values defined in this module.
@@ -1618,6 +1622,15 @@ static struct config_bool ConfigureNamesBool[] =
         NULL, NULL, NULL
     },

+    {
+        {"gss_encrypt", PGC_USERSET, CONN_AUTH_SECURITY,
+         gettext_noop("Whether client wants encryption for this connection."),
+         NULL,
+         GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
+        },
+        &gss_encrypt, false, NULL, assign_gss_encrypt, NULL
+    },
+
     /* End-of-list marker */
     {
         {NULL, 0, 0, NULL, NULL}, NULL, false, NULL, NULL, NULL
@@ -10114,4 +10127,10 @@ show_log_file_mode(void)
     return buf;
 }

+static void
+assign_gss_encrypt(bool newval, void *extra)
+{
+    gss_encrypt = newval;
+}
+
 #include "guc-file.c"
diff --git a/src/include/libpq/auth.h b/src/include/libpq/auth.h
index 80f26a8..e98f560 100644
--- a/src/include/libpq/auth.h
+++ b/src/include/libpq/auth.h
@@ -26,4 +26,9 @@ extern void ClientAuthentication(Port *port);
 typedef void (*ClientAuthentication_hook_type) (Port *, int);
 extern PGDLLIMPORT ClientAuthentication_hook_type ClientAuthentication_hook;

+#ifdef ENABLE_GSS
+void pg_GSS_error(int severity, char *errmsg, OM_uint32 maj_stat,
+                  OM_uint32 min_stat);
+#endif
+
 #endif   /* AUTH_H */
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index 6171ef3..58712fc 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -30,6 +30,8 @@
 #endif

 #ifdef ENABLE_GSS
+#include "lib/stringinfo.h"
+
 #if defined(HAVE_GSSAPI_H)
 #include <gssapi.h>
 #else
@@ -219,6 +221,13 @@ extern void be_tls_get_cipher(Port *port, char *ptr, size_t len);
 extern void be_tls_get_peerdn_name(Port *port, char *ptr, size_t len);
 #endif

+#ifdef ENABLE_GSS
+/* These functions are implemented in be-secure-gss.c */
+extern size_t
+be_gss_encrypt(Port *port, char msgtype, const char **msgptr, size_t len);
+extern int be_gss_inplace_decrypt(StringInfo inBuf);
+#endif
+
 extern ProtocolVersion FrontendProtocol;

 /* TCP keepalives configuration. These are no-ops on an AF_UNIX socket. */
diff --git a/src/include/libpq/libpq.h b/src/include/libpq/libpq.h
index c408e5b..e788cc8 100644
--- a/src/include/libpq/libpq.h
+++ b/src/include/libpq/libpq.h
@@ -99,4 +99,8 @@ extern char *SSLCipherSuites;
 extern char *SSLECDHCurve;
 extern bool SSLPreferServerCiphers;

+#ifdef ENABLE_GSS
+extern bool gss_encrypt;
+#endif
+
 #endif   /* LIBPQ_H */
--
2.1.4

From e55795e0638ca37447ef200f21f74db80b07ebf4 Mon Sep 17 00:00:00 2001
From: "Robbie Harwood (frozencemetery)" <rharwood@redhat.com>
Date: Fri, 12 Jun 2015 13:27:50 -0400
Subject: Error when receiving plaintext on GSS-encrypted connections

---
 src/backend/tcop/postgres.c         | 12 ++++++++++++
 src/interfaces/libpq/fe-protocol3.c | 32 ++++++++++++++++++++++++++++++--
 src/interfaces/libpq/libpq-int.h    |  1 +
 3 files changed, 43 insertions(+), 2 deletions(-)

diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 8510908..ba8ed4e 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -379,6 +379,18 @@ SocketBackend(StringInfo inBuf)
         if (qtype < 0)
             return EOF;
     }
+    else if (gss_encrypt && MyProcPort->hba->auth_method == uaGSS &&
+             qtype != 'g' && qtype != 'R' )
+    {
+        /*
+         * Either something malicious is occuring, or we have lost
+         * synchronization.
+         */
+        ereport(FATAL,
+                (errcode(ERRCODE_PROTOCOL_VIOLATION),
+                 errmsg("invalid frontend message type %d", qtype)));
+        return EOF;
+    }
 #endif

     /*
diff --git a/src/interfaces/libpq/fe-protocol3.c b/src/interfaces/libpq/fe-protocol3.c
index 65acfd1..d5fb461 100644
--- a/src/interfaces/libpq/fe-protocol3.c
+++ b/src/interfaces/libpq/fe-protocol3.c
@@ -131,7 +131,7 @@ pqParseInput3(PGconn *conn)

 #ifdef ENABLE_GSS
         /* We want to be ready in both IDLE and BUSY states for encryption */
-        if (id == 'g')
+        if (id == 'g' && !conn->gss_disable_enc && conn->gctx)
         {
             ssize_t encEnd, next;

@@ -152,8 +152,33 @@ pqParseInput3(PGconn *conn)
             memmove(conn->inBuffer + encEnd, conn->inBuffer + next,
                     conn->inEnd - next);
             conn->inEnd = (conn->inEnd - next) + encEnd;
-            continue;
+
+            conn->inCursor = conn->inStart;
+            (void) pqGetc(&id, conn);
+            (void) pqGetInt(&msgLength, 4, conn);
+            msgLength -= 4;
+            if (msgLength != encEnd - conn->inCursor)
+            {
+                /* This isn't a sync error because decrypt was successful */
+                printfPQExpBuffer(&conn->errorMessage,
+                                  libpq_gettext(
+                                      "server lied about message length: got message length %ld, but expected legnth
%d\n"),
+                                  encEnd - conn->inCursor, msgLength);
+                /* build an error result holding the error message */
+                pqSaveErrorResult(conn);
+                /* drop out of GetResult wait loop */
+                conn->asyncStatus = PGASYNC_READY;
+
+                pqDropConnection(conn);
+                /* No more connection to backend */
+                conn->status = CONNECTION_BAD;
+            }
+            conn->gss_decrypted_cur = true;
         }
+        else if (!conn->gss_disable_enc && conn->gss_auth_done &&
+                 !conn->gss_decrypted_cur && id != 'E')
+            /* This could be a sync error, so let's handle it as such. */
+            handleSyncLoss(conn, id, msgLength);
 #endif

         /*
@@ -425,6 +450,9 @@ pqParseInput3(PGconn *conn)
         {
             /* Normal case: parsing agrees with specified length */
             conn->inStart = conn->inCursor;
+#ifdef ENABLE_GSS
+            conn->gss_decrypted_cur = false;
+#endif
         }
         else
         {
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index ff2e39d..7a3ebcd 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -447,6 +447,7 @@ struct pg_conn
     gss_buffer_desc goutbuf;    /* GSS output token */
     bool gss_disable_enc;        /* Does server recognize gss_encrypt? */
     bool gss_auth_done;            /* Did we finish the AUTH step? */
+    bool gss_decrypted_cur;        /* Is first message in buffer decrypted? */
 #endif

 #ifdef ENABLE_SSPI
--
2.1.4

From dcba977f9e37e80fafc7deb89b8856738f20928d Mon Sep 17 00:00:00 2001
From: "Robbie Harwood (frozencemetery)" <rharwood@redhat.com>
Date: Mon, 15 Jun 2015 16:52:10 -0400
Subject: server: hba option for requiring GSSAPI encryption

Also includes logic for failing clients that do not request encryption
in the startup packet when encryption is required.
---
 src/backend/libpq/hba.c           |  9 +++++++++
 src/backend/utils/init/postinit.c |  7 ++++++-
 src/backend/utils/misc/guc.c      | 12 +++++++++++-
 src/include/libpq/hba.h           |  1 +
 4 files changed, 27 insertions(+), 2 deletions(-)

diff --git a/src/backend/libpq/hba.c b/src/backend/libpq/hba.c
index 23c8b5d..90fe57f 100644
--- a/src/backend/libpq/hba.c
+++ b/src/backend/libpq/hba.c
@@ -1570,6 +1570,15 @@ parse_hba_auth_opt(char *name, char *val, HbaLine *hbaline, int line_num)
         else
             hbaline->include_realm = false;
     }
+    else if (strcmp(name, "require_encrypt") == 0)
+    {
+        if (hbaline->auth_method != uaGSS)
+            INVALID_AUTH_OPTION("require_encrypt", "gssapi");
+        if (strcmp(val, "1") == 0)
+            hbaline->require_encrypt = true;
+        else
+            hbaline->require_encrypt = false;
+    }
     else if (strcmp(name, "radiusserver") == 0)
     {
         struct addrinfo *gai_result;
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index 0f04f28..cc5c9af 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -32,7 +32,7 @@
 #include "catalog/pg_db_role_setting.h"
 #include "catalog/pg_tablespace.h"
 #include "libpq/auth.h"
-#include "libpq/libpq-be.h"
+#include "libpq/libpq.h"
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "pgstat.h"
@@ -1085,6 +1085,11 @@ process_startup_options(Port *port, bool am_superuser)

         SetConfigOption(name, value, gucctx, PGC_S_CLIENT);
     }
+
+    if (!gss_encrypt && port->hba->require_encrypt)
+        ereport(FATAL, (errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
+                        errmsg("GSSAPI encryption required from user \"%s\"",
+                               port->user_name)));
 }

 /*
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index a978af0..3a8ba61 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -188,6 +188,7 @@ static ConfigVariable *ProcessConfigFileInternal(GucContext context,

 #ifdef ENABLE_GSS
 static void assign_gss_encrypt(bool newval, void *extra);
+static bool check_gss_encrypt(bool *newval, void **extra, GucSource source);
 #endif


@@ -1628,7 +1629,7 @@ static struct config_bool ConfigureNamesBool[] =
          NULL,
          GUC_NOT_IN_SAMPLE | GUC_DISALLOW_IN_FILE
         },
-        &gss_encrypt, false, NULL, assign_gss_encrypt, NULL
+        &gss_encrypt, false, check_gss_encrypt, assign_gss_encrypt, NULL
     },

     /* End-of-list marker */
@@ -10133,4 +10134,13 @@ assign_gss_encrypt(bool newval, void *extra)
     gss_encrypt = newval;
 }

+static bool
+check_gss_encrypt(bool *newval, void **extra, GucSource source)
+{
+    if (MyProcPort && MyProcPort->hba && MyProcPort->hba->require_encrypt &&
+        !*newval)
+        return false;
+    return true;
+}
+
 #include "guc-file.c"
diff --git a/src/include/libpq/hba.h b/src/include/libpq/hba.h
index 68a953a..3435674 100644
--- a/src/include/libpq/hba.h
+++ b/src/include/libpq/hba.h
@@ -77,6 +77,7 @@ typedef struct HbaLine
     bool        clientcert;
     char       *krb_realm;
     bool        include_realm;
+    bool        require_encrypt;
     char       *radiusserver;
     char       *radiussecret;
     char       *radiusidentifier;
--
2.1.4

From b32190b69479a46291088b9ef15208d47975bcba Mon Sep 17 00:00:00 2001
From: "Robbie Harwood (frozencemetery)" <rharwood@redhat.com>
Date: Mon, 15 Jun 2015 19:54:29 -0400
Subject: client: gss_enc_require parameter to force GSS encryption

---
 src/interfaces/libpq/fe-connect.c | 27 ++++++++++++++++++++++-----
 src/interfaces/libpq/libpq-int.h  |  1 +
 2 files changed, 23 insertions(+), 5 deletions(-)

diff --git a/src/interfaces/libpq/fe-connect.c b/src/interfaces/libpq/fe-connect.c
index 8fb0a90..115a52c 100644
--- a/src/interfaces/libpq/fe-connect.c
+++ b/src/interfaces/libpq/fe-connect.c
@@ -297,6 +297,12 @@ static const internalPQconninfoOption PQconninfoOptions[] = {
     offsetof(struct pg_conn, gsslib)},
 #endif

+#if defined(ENABLE_GSS)
+    {"gss_enc_require", "GSS_ENC_REQUIRE", "0", NULL,
+        "Require-GSS-encryption", "", 1, /* should be '0' or '1' */
+    offsetof(struct pg_conn, gss_enc_require)},
+#endif
+
     {"replication", NULL, NULL, NULL,
         "Replication", "D", 5,
     offsetof(struct pg_conn, replication)},
@@ -2559,14 +2565,16 @@ keep_going:                        /* We will come back to here until there is
                         appendPQExpBufferStr(&conn->errorMessage,
                                              libpq_gettext("unexpected message from server during startup\n"));
 #ifdef ENABLE_GSS
-                    else if (!conn->gss_disable_enc)
+                    else if (!conn->gss_disable_enc &&
+                             *conn->gss_enc_require != '1')
                     {
                         /*
                          * We tried to request GSS encryption, but the server
-                         * doesn't support it.  Hang up and try again.  A
-                         * connection that doesn't support appname will also
-                         * not support GSSAPI encryption, so this check goes
-                         * before that check.  See comment below.
+                         * doesn't support it.  Retries are permitted here, so
+                         * hang up and try again.  A connection that doesn't
+                         * support appname will also not support GSSAPI
+                         * encryption, so this check goes before that check.
+                         * See comment below.
                          */
                         const char *sqlstate;

@@ -2614,6 +2622,15 @@ keep_going:                        /* We will come back to here until there is
                             goto keep_going;
                         }
                     }
+#ifdef ENABLE_GSS
+                    else if (*conn->gss_enc_require == '1')
+                        /*
+                         * It has been determined that appname was not the
+                         * cause of connection failure, so give up.
+                         */
+                        appendPQExpBufferStr(&conn->errorMessage,
+                                             libpq_gettext("Server does not support required GSS encryption\n"));
+#endif

                     /*
                      * if the resultStatus is FATAL, then conn->errorMessage
diff --git a/src/interfaces/libpq/libpq-int.h b/src/interfaces/libpq/libpq-int.h
index 7a3ebcd..3140c7f 100644
--- a/src/interfaces/libpq/libpq-int.h
+++ b/src/interfaces/libpq/libpq-int.h
@@ -448,6 +448,7 @@ struct pg_conn
     bool gss_disable_enc;        /* Does server recognize gss_encrypt? */
     bool gss_auth_done;            /* Did we finish the AUTH step? */
     bool gss_decrypted_cur;        /* Is first message in buffer decrypted? */
+    char *gss_enc_require;        /* Can we downgrade to plaintext? */
 #endif

 #ifdef ENABLE_SSPI
--
2.1.4

From d5b374d0a466c4bf642d806168d973d4aad638e8 Mon Sep 17 00:00:00 2001
From: "Robbie Harwood (frozencemetery)" <rharwood@redhat.com>
Date: Mon, 29 Jun 2015 15:29:36 -0400
Subject: Document GSSAPI encryption

---
 doc/src/sgml/client-auth.sgml | 19 ++++++++++++++++---
 doc/src/sgml/libpq.sgml       | 12 ++++++++++++
 doc/src/sgml/protocol.sgml    | 40 ++++++++++++++++++++++++++++++++++++++++
 doc/src/sgml/runtime.sgml     | 20 +++++++++++++++++++-
 4 files changed, 87 insertions(+), 4 deletions(-)

diff --git a/doc/src/sgml/client-auth.sgml b/doc/src/sgml/client-auth.sgml
index 5f72beb..3c49612 100644
--- a/doc/src/sgml/client-auth.sgml
+++ b/doc/src/sgml/client-auth.sgml
@@ -913,9 +913,10 @@ omicron         bryanh                  guest1
     <productname>GSSAPI</productname> with <productname>Kerberos</productname>
     authentication according to RFC 1964. <productname>GSSAPI</productname>
     provides automatic authentication (single sign-on) for systems
-    that support it. The authentication itself is secure, but the
-    data sent over the database connection will be sent unencrypted unless
-    <acronym>SSL</acronym> is used.
+    that support it. The authentication itself is secure, and GSSAPI can be
+    used for connection encryption as well (see the
+    <literal>require_encrypt</literal> parameter below); <acronym>SSL</acronym>
+    can also be used for connection security.
    </para>

    <para>
@@ -1046,6 +1047,18 @@ omicron         bryanh                  guest1
        </para>
       </listitem>
      </varlistentry>
+
+     <varlistentry>
+      <term><literal>require_encrypt</literal></term>
+      <listitem>
+       <para>
+        Whether to require GSSAPI encryption.  Default is off, which causes
+        GSSAPI encryption to be enabled if available and requested for
+        compatability with old clients.  It is recommended to set this unless
+        old clients are present.
+       </para>
+      </listitem>
+     </varlistentry>
     </variablelist>
    </para>
   </sect2>
diff --git a/doc/src/sgml/libpq.sgml b/doc/src/sgml/libpq.sgml
index de6b3ad..db2340c 100644
--- a/doc/src/sgml/libpq.sgml
+++ b/doc/src/sgml/libpq.sgml
@@ -1356,6 +1356,18 @@ postgresql://%2Fvar%2Flib%2Fpostgresql/dbname
       </listitem>
      </varlistentry>

+     <varlistentry id="libpq-connect-gss-enc-require" xreflabel="gss-enc-require">
+      <term><literal>gss_enc_require</literal></term>
+      <listitem>
+       <para>
+        If set, whether to require GSSAPI encryption support from the remote
+        server. Defaults to unset, which will cause the client to fall back to
+        not using GSSAPI encryption if the server does not support encryption
+        through GSSAPI.
+       </para>
+      </listitem>
+     </varlistentry>
+
      <varlistentry id="libpq-connect-service" xreflabel="service">
       <term><literal>service</literal></term>
       <listitem>
diff --git a/doc/src/sgml/protocol.sgml b/doc/src/sgml/protocol.sgml
index 42e9497..8355e54 100644
--- a/doc/src/sgml/protocol.sgml
+++ b/doc/src/sgml/protocol.sgml
@@ -1295,6 +1295,46 @@
     of authentication checking.
    </para>
   </sect2>
+
+  <sect2>
+   <title><acronym>GSSAPI</acronym> Session Encryption</title>
+
+   <para>
+    If <productname>PostgreSQL</> was built with
+    <acronym>GSSAPI</acronym> and <acronym>GSSAPI</acronym> support, traffic
+    can also be encrypted using <acronym>GSSAPI</acronym>. To force encryption
+    using <acronym>GSSAPI</acronym>, set require_encrypt in
+    <filename>pg_hba.conf</filename>.
+   </para>
+
+   <para>
+    In order to probe for <acronym>GSSAPI</acronym> support, the client will
+    include in their StartupMessage the parameter gss_encrypt. If the server
+    does not support <acronym>GSSAPI</acronym> or <acronym>GSSAPI</acronym>
+    encryption, the server will error the connection; otherwise, it continues
+    as normal. The client may retry the connection
+    without <acronym>GSSAPI</acronym> encryption support depending on its
+    settings. If the client does not probe support, depending on settings
+    in <filename>pg_hba.conf</filename>, the server may drop
+    <acronym>GSSAPI</acronym>-authenticated connections without encryption.
+   </para>
+
+   <para>
+    If the client has probed <acronym>GSSAPI</acronym> encryption support and
+    the connection is <acronym>GSSAPI</acronym>-authenticated, then after the
+    server sends AuthenticationOk, all traffic between the client and server
+    will be <acronym>GSSAPI</acronym>-encrypted. Because
+    <acronym>GSSAPI</acronym> does not provide framing,
+    <acronym>GSSAPI</acronym>-encrypted messages are modeled after protocol-3
+    messages: the first byte is the caracter g, then four bytes of length, and
+    then an encrypted message.
+   </para>
+
+   <para>
+     It is valid to use <acronym>GSSAPI</acronym> encryption over
+     <acronym>SSL</acronym>-encrypted connections.
+   </para>
+  </sect2>
  </sect1>

 <sect1 id="protocol-replication">
diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml
index 547567e..0b1b009 100644
--- a/doc/src/sgml/runtime.sgml
+++ b/doc/src/sgml/runtime.sgml
@@ -1833,7 +1833,7 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433
   </para>

   <para>
-   To prevent spoofing on TCP connections, the best solution is to use
+   To prevent spoofing on TCP connections, one possible solution is to use
    SSL certificates and make sure that clients check the server's certificate.
    To do that, the server
    must be configured to accept only <literal>hostssl</> connections (<xref
@@ -1843,6 +1843,15 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433
    <literal>verify-full</> and have the appropriate root certificate
    file installed (<xref linkend="libq-ssl-certificates">).
   </para>
+
+  <para>
+   Another way of preventing spoofing on TCP connections is to use GSSAPI
+   encryption. In order to force all GSSAPI connections to be encrypted, one
+   should set <literal>require_encrypt</> in <filename>pg_hba.conf</> on GSS
+   connections. Then, using Kerberos, the client and server will mutually
+   authenticate, and the connection will be encrypted once the authentication
+   step is complete.
+  </para>
  </sect1>

  <sect1 id="encryption-options">
@@ -1958,6 +1967,15 @@ pg_dumpall -p 5432 | psql -d postgres -p 5433
       connect to servers only via SSL. <application>Stunnel</> or
       <application>SSH</> can also be used to encrypt transmissions.
      </para>
+
+     <para>
+      GSSAPI connections can also encrypt all data sent across the
+      network. In the <filename>pg_hba.conf</> file, the GSS authenticaion
+      method has a parameter to require encryption; otherwise, connections
+      will be encrypted if available and requiested by the client. On the
+      client side, there is also a parameter to require GSSAPI encryption
+      support from the server.
+     </para>
     </listitem>
   </varlistentry>

--
2.1.4


Вложения

В списке pgsql-hackers по дате отправления:

Предыдущее
От: Robert Haas
Дата:
Сообщение: Re: Reducing ClogControlLock contention
Следующее
От: Heikki Linnakangas
Дата:
Сообщение: Re: Time to fully remove heap_formtuple() and friends?