Re: Kerberos v5 support - Mailing list pgsql-patches

From Bruce Momjian
Subject Re: Kerberos v5 support
Date
Msg-id 200011061705.MAA22568@candle.pha.pa.us
Whole thread Raw
In response to Kerberos v5 support  (Garrett Wollman <wollman@khavrinen.lcs.mit.edu>)
Responses Re: Kerberos v5 support  (Garrett Wollman <wollman@khavrinen.lcs.mit.edu>)
List pgsql-patches
I have applied some kerberos changes to the current snapshot a few
months ago.  Can you grab that and let me know what you would like
changed?  Thanks.


> I thought I sent this back in September, but I can't find anything in
> the mailing-list archives, so I am assuming it fell into a black hole.
>
> Enclosed please find a set of patches, relative to 7.0.2, which will
> result in Kerberos v5 support which both compiles and works (as in,
> I've successfully authenticated as a remote client).
>
> Our pg_hba.conf file then looks like:
>
> local        all                                           trust
> host         all         0.0.0.0        0.0.0.0         krb5
>
> However, that `trust' is tempered by changes to the startup scripts
> (not included here) which force the local-domain socket to mode 600,
> thereby ensuring that all normal clients connect via an authenticated
> network connection.
>
> You can see from some of the comments that I'd like this to be made
> stronger in a number of ways.  This patch set simply gets pgsql up to
> the minimum acceptable level of security for our environment and
> application.
>
> My original message follows.
>
> ------------------------------------------------------------------------
>
> The enclosed patches fix the Kerberos v5 support in libpq and the
> backend.  It was totally broken before, now it's still broken but
> works.  (That is to say: before, it didn't work, and now it does work
> but doesn't provide the level of security it should.  Still better
> than plaintext passwords.)  So far as I can tell, the original code
> was written for an early beta version, and rotted severely in the
> intervening years.  We actually need authentication to work, which is
> why I'm doing this now.
>
> A few notes:
>
> - See the comment near pg_an_to_ln() about one part of the brokenness.
>
> - As implemented, this code will not work over PF_LOCAL sockets.
>
> - Some things don't work correctly in the absence of a `local all
> trust' line in pg_hba.conf, and PGUSER needs to be set in order for
> *that* to work.
>
> - E2E encryption would really be preferable.  It looks fairly easy to
> do in the fe->be side of the protocol, but it's not obviously possible
> for the other direction.  In any event, I wanted to confine my changes
> to the smallest number of source files, so I didn't make any effort to
> implement this.  Either way, a protocol change is required.
>
> -GAWollman
>
> # This is a shell archive.  Save it in a file, remove anything before
> # this line, and then unpack it by entering "sh file".  Note, it may
> # create directories; files and directories will be owned by you and
> # have default permissions.
> #
> # This archive contains:
> #
> #    patch-be
> #    patch-bf
> #    patch-bg
> #    patch-bh
> #
> echo x - patch-be
> sed 's/^X//' >patch-be << 'END-of-patch-be'
> X--- backend/libpq/auth.c.orig    Wed Apr 12 13:15:13 2000
> X+++ backend/libpq/auth.c    Wed Sep 27 23:33:17 2000
> X@@ -142,7 +142,4 @@
> X
> X #ifdef KRB5
> X-/* This needs to be ifdef'd out because krb5.h doesn't exist.  This needs
> X-   to be fixed.
> X-*/
> X /*----------------------------------------------------------------
> X  * MIT Kerberos authentication system - protocol version 5
> X@@ -150,5 +147,15 @@
> X  */
> X
> X-#include "krb5/krb5.h"
> X+#include "krb5.h"
> X+#ifndef PG_KRB_SRVNAM
> X+#define    PG_KRB_SRVNAM    "pgsql"
> X+#endif
> X+#ifndef PG_KRB_KEYTAB
> X+#define PG_KRB_KEYTAB    "FILE:/etc/keytab.pgsql"
> X+#endif
> X+
> X+static krb5_context    mycontext;
> X+static int        mycontext_inited;
> X+static krb5_keytab    keytab;
> X
> X /*
> X@@ -156,12 +163,11 @@
> X  *                  name
> X  *
> X- * XXX Assumes that the first aname component is the user name.  This is NOT
> X- *       necessarily so, since an aname can actually be something out of your
> X- *       worst X.400 nightmare, like
> X- *          ORGANIZATION=U. C. Berkeley/NAME=Paul M. Aoki@CS.BERKELEY.EDU
> X- *       Note that the MIT an_to_ln code does the same thing if you don't
> X- *       provide an aname mapping database...it may be a better idea to use
> X- *       krb5_an_to_ln, except that it punts if multiple components are found,
> X- *       and we can't afford to punt.
> X+ * XXX - this is totally broken (and potentially insecure on the server side).
> X+ * The correct mechanism is to use the entire principal name, and make
> X+ * the server do a table lookup to discover the mapping.
> X+ * (In the protocol as it stands, if user jrl@A.EXAMPLE.COM authenticates to
> X+ * a server in the B.EXAMPLE.COM realm, the server will accept him as
> X+ * local-user `jrl' regardless of whether or not jrl@A.EXAMPLE.COM is
> X+ * the same user as jrl@B.EXAMPLE.COM.)
> X  */
> X static char *
> X@@ -200,68 +206,117 @@
> X pg_krb5_recvauth(Port *port)
> X {
> X-    char        servbuf[MAXHOSTNAMELEN + 1 +
> X-                                    sizeof(PG_KRB_SRVNAM)];
> X-    char       *hostp,
> X-               *kusername = (char *) NULL;
> X+    char        hostbuf[MAXHOSTNAMELEN + 1];
> X+    char        *kusername = (char *) NULL;
> X     krb5_error_code code;
> X-    krb5_principal client,
> X-                server;
> X-    krb5_address sender_addr;
> X-    krb5_rdreq_key_proc keyproc = (krb5_rdreq_key_proc) NULL;
> X-    krb5_pointer keyprocarg = (krb5_pointer) NULL;
> X+    krb5_principal    server;
> X+    krb5_auth_context authctx;
> X+    krb5_authenticator *them;
> X+
> X+    if (!mycontext_inited)
> X+    {
> X+        code = krb5_init_context(&mycontext);
> X+        if (code)
> X+        {
> X+            snprintf(PQerrormsg, PQERRORMSG_LENGTH,
> X+                 "pg_krb5_recvauth: krb5_init_context: %s\n",
> X+                 error_message(code));
> X+            fputs(PQerrormsg, stderr);
> X+            pqdebug("%s", PQerrormsg);
> X+            return STATUS_ERROR;
> X+        }
> X+        if (strcmp(PG_KRB_KEYTAB, "default") == 0)
> X+        {
> X+            code = krb5_kt_default(mycontext, &keytab);
> X+        }
> X+        else
> X+        {
> X+            code = krb5_kt_resolve(mycontext, PG_KRB_KEYTAB,
> X+                           &keytab);
> X+        }
> X+        if (code)
> X+        {
> X+            snprintf(PQerrormsg, PQERRORMSG_LENGTH,
> X+                 "pg_krb5_recvauth: keytab %s: %s\n",
> X+                 PG_KRB_KEYTAB,
> X+                 error_message(code));
> X+            fputs(PQerrormsg, stderr);
> X+            pqdebug("%s", PQerrormsg);
> X+            return STATUS_ERROR;
> X+        }
> X+        mycontext_inited = 1;
> X+    }
> X
> X-    /*
> X-     * Set up server side -- since we have no ticket file to make this
> X-     * easy, we construct our own name and parse it.  See note on
> X-     * canonicalization above.
> X-     */
> X-    strcpy(servbuf, PG_KRB_SRVNAM);
> X-    *(hostp = servbuf + (sizeof(PG_KRB_SRVNAM) - 1)) = '/';
> X-    if (gethostname(++hostp, MAXHOSTNAMELEN) < 0)
> X-        strcpy(hostp, "localhost");
> X-    if (hostp = strchr(hostp, '.'))
> X-        *hostp = '\0';
> X-    if (code = krb5_parse_name(servbuf, &server))
> X+    code = krb5_auth_con_init(mycontext, &authctx);
> X+    if (code)
> X+    {
> X+        snprintf(PQerrormsg, PQERRORMSG_LENGTH,
> X+             "pg_krb5_recvauth: krb5_auth_con_init: %s\n",
> X+             error_message(code));
> X+        fputs(PQerrormsg, stderr);
> X+        pqdebug("%s", PQerrormsg);
> X+        return STATUS_ERROR;
> X+    }
> X+
> X+    if (gethostname(hostbuf, MAXHOSTNAMELEN) < 0)
> X     {
> X         snprintf(PQerrormsg, PQERRORMSG_LENGTH,
> X-        "pg_krb5_recvauth: Kerberos error %d in krb5_parse_name\n", code);
> X-        com_err("pg_krb5_recvauth", code, "in krb5_parse_name");
> X+             "pg_krb5_recvauth: gethostname: %s\n",
> X+             strerror(errno));
> X+        fputs(PQerrormsg, stderr);
> X+        pqdebug("%s", PQerrormsg);
> X+        krb5_auth_con_free(mycontext, authctx);
> X         return STATUS_ERROR;
> X     }
> X
> X+    code = krb5_sname_to_principal(mycontext, hostbuf, PG_KRB_SRVNAM,
> X+                       KRB5_NT_SRV_HST, &server);
> X+    if (code)
> X+    {
> X+        snprintf(PQerrormsg, PQERRORMSG_LENGTH,
> X+             "pg_krb5_recvauth: krb5_sname_to_principal: %s\n",
> X+             error_message(code));
> X+        fputs(PQerrormsg, stderr);
> X+        pqdebug("%s", PQerrormsg);
> X+        krb5_auth_con_free(mycontext, authctx);
> X+        return STATUS_ERROR;
> X+    }
> X+
> X     /*
> X      * krb5_sendauth needs this to verify the address in the client
> X      * authenticator.
> X      */
> X-    sender_addr.addrtype = port->raddr.in.sin_family;
> X-    sender_addr.length = sizeof(port->raddr.in.sin_addr);
> X-    sender_addr.contents = (krb5_octet *) & (port->raddr.in.sin_addr);
> X-
> X-    if (strcmp(PG_KRB_SRVTAB, ""))
> X+#define    ALL    (KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR | \
> X+         KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)
> X+    code = krb5_auth_con_genaddrs(mycontext, authctx, port->sock, ALL);
> X+#undef ALL
> X+
> X+    code = krb5_recvauth(mycontext, &authctx, (krb5_pointer)&port->sock,
> X+                 PG_KRB5_VERSION, server, 0, keytab,
> X+                 (krb5_ticket **)0);
> X+    if (code)
> X     {
> X-        keyproc = krb5_kt_read_service_key;
> X-        keyprocarg = PG_KRB_SRVTAB;
> X+        snprintf(PQerrormsg, PQERRORMSG_LENGTH,
> X+             "pg_krb5_recvauth: krb5_recvauth: %s\n",
> X+             error_message(code));
> X+        fputs(PQerrormsg, stderr);
> X+        pqdebug("%s", PQerrormsg);
> X+        krb5_free_principal(mycontext, server);
> X+        krb5_auth_con_free(mycontext, authctx);
> X+        return STATUS_ERROR;
> X     }
> X+    krb5_free_principal(mycontext, server);
> X
> X-    if (code = krb5_recvauth((krb5_pointer) & port->sock,
> X-                             PG_KRB5_VERSION,
> X-                             server,
> X-                             &sender_addr,
> X-                             (krb5_pointer) NULL,
> X-                             keyproc,
> X-                             keyprocarg,
> X-                             (char *) NULL,
> X-                             (krb5_int32 *) NULL,
> X-                             &client,
> X-                             (krb5_ticket **) NULL,
> X-                             (krb5_authenticator **) NULL))
> X+    code = krb5_auth_con_getauthenticator(mycontext, authctx, &them);
> X+    if (code)
> X     {
> X         snprintf(PQerrormsg, PQERRORMSG_LENGTH,
> X-         "pg_krb5_recvauth: Kerberos error %d in krb5_recvauth\n", code);
> X-        com_err("pg_krb5_recvauth", code, "in krb5_recvauth");
> X-        krb5_free_principal(server);
> X+         "pg_krb5_recvauth: getauthenticator: %s\n",
> X+             error_message(code));
> X+        fputs(PQerrormsg, stderr);
> X+        pqdebug("%s", PQerrormsg);
> X+        krb5_free_principal(mycontext, server);
> X+        krb5_auth_con_free(mycontext, authctx);
> X         return STATUS_ERROR;
> X     }
> X-    krb5_free_principal(server);
> X
> X     /*
> X@@ -270,13 +325,18 @@
> X      * postmaster startup packet.
> X      */
> X-    if ((code = krb5_unparse_name(client, &kusername)))
> X+    if ((code = krb5_unparse_name(mycontext, them->client, &kusername)))
> X     {
> X         snprintf(PQerrormsg, PQERRORMSG_LENGTH,
> X-                 "pg_krb5_recvauth: Kerberos error %d in krb5_unparse_name\n", code);
> X-        com_err("pg_krb5_recvauth", code, "in krb5_unparse_name");
> X-        krb5_free_principal(client);
> X+             "pg_krb5_recvauth: krb5_unparse_name: %s\n",
> X+             error_message(code));
> X+        fputs(PQerrormsg, stderr);
> X+        pqdebug("%s", PQerrormsg);
> X+        krb5_free_authenticator(mycontext, them);
> X+        krb5_auth_con_free(mycontext, authctx);
> X         return STATUS_ERROR;
> X     }
> X-    krb5_free_principal(client);
> X+    krb5_free_authenticator(mycontext, them);
> X+    krb5_auth_con_free(mycontext, authctx);
> X+
> X     if (!kusername)
> X     {
> X@@ -288,5 +348,5 @@
> X     }
> X     kusername = pg_an_to_ln(kusername);
> X-    if (strncmp(username, kusername, SM_USER))
> X+    if (strncmp(port->user, kusername, SM_USER))
> X     {
> X         snprintf(PQerrormsg, PQERRORMSG_LENGTH,
> X@@ -294,8 +354,8 @@
> X         fputs(PQerrormsg, stderr);
> X         pqdebug("%s", PQerrormsg);
> X-        pfree(kusername);
> X+        free(kusername);
> X         return STATUS_ERROR;
> X     }
> X-    pfree(kusername);
> X+    free(kusername);
> X     return STATUS_OK;
> X }
> END-of-patch-be
> echo x - patch-bf
> sed 's/^X//' >patch-bf << 'END-of-patch-bf'
> Xdiff -ru2 old/configure.in configure.in
> X--- old/configure.in    Wed May 24 18:43:59 2000
> X+++ configure.in    Tue Sep 26 22:39:46 2000
> X@@ -369,4 +369,55 @@
> X export USE_ODBC
> X
> X+AC_ARG_WITH(
> X+    krb5,
> X+    [  --with-krb5[=PREFIX]    build Kerberos 5 authentication support ],
> X+    [
> X+    case "$withval" in
> X+    y | ye | yes)    USE_KRB5=true;;
> X+    n | no)    USE_KRB5=false;;
> X+    *)    USE_KRB5=true
> X+        KRB5_INCS="-I$withval/include $KRB5_INCS"
> X+        KRB5_LIBS="-L$withval/lib $KRB5_LIBS";;
> X+    esac
> X+    ],
> X+    [ USE_KRB5=false ]
> X+)
> X+
> X+AC_ARG_WITH(
> X+    krb-service-name,
> X+    [  --with-krb-service-name=NAME authenticate as Kerberos principal NAME ],
> X+    [  KRB_SRVNAM="$withval" ],
> X+    [  unset KRB_SRVNAM ]
> X+)
> X+
> X+AC_ARG_WITH(
> X+    krb-keytab,
> X+    [  --with-krb-keytab=FILE:FILENAME use Kerberos v5 keytab FILENAME ],
> X+    [  KRB_KEYTAB="$withval" ],
> X+    [  unset KRB_KEYTAB ]
> X+)
> X+
> X+export USE_KRB5
> X+export KRB5_INCS
> X+export KRB5_LIBS
> X+
> X+AC_ARG_WITH(
> X+    openssl,
> X+    [  --with-openssl[=PREFIX] build OpenSSL transport support ],
> X+    [
> X+    case "$withval" in
> X+    y | ye | yes)    USE_OPENSSL=true;;
> X+    n | no)    USE_OPENSSL=false;;
> X+    *)    USE_OPENSSL=true
> X+        OPENSSL_INCS="-I$withval $OPENSSL_INCS"
> X+        OPENSSL_LIBS="-L$withval $OPENSSL_LIBS -lopenssl -lcrypto";;
> X+    esac
> X+    ],
> X+    [ USE_OPENSSL=false ]
> X+)
> X+export USE_OPENSSL
> X+export OPENSSL_INCS
> X+export OPENSSL_LIBS
> X+
> X AC_MSG_CHECKING(setproctitle)
> X AC_ARG_WITH(
> X@@ -509,4 +560,6 @@
> X AC_SUBST(USE_ODBC)
> X AC_SUBST(MULTIBYTE)
> X+AC_SUBST(USE_KRB5)
> X+AC_SUBST(USE_OPENSSL)
> X
> X dnl Check for C++ support (allow override if needed)
> X@@ -1312,4 +1365,50 @@
> X     CPPFLAGS="$ice_save_CPPFLAGS"
> X     LDFLAGS="$ice_save_LDFLAGS"
> X+fi
> X+
> X+dnl
> X+dnl User requested Kerberos support in libpq; see if the required
> X+dnl header files and libraries are actually there.
> X+dnl
> X+if $USE_KRB5; then
> X+    AC_CHECKING(if Kerberos 5 environment is complete)
> X+    OCFLAGS="$CFLAGS"
> X+    OCPPFLAGS="$CPPFLAGS"
> X+    OLIBS="$LIBS"
> X+    if test "$KRB5_INCS"; then
> X+        CFLAGS="$CFLAGS $KRB5_INCS"
> X+        CPPFLAGS="$CPPFLAGS $KRB5_INCS"
> X+    fi
> X+    if test "$KRB5_LIBS"; then
> X+        LIBS="$LIBS $KRB5_LIBS"
> X+    fi
> X+    AC_CHECK_HEADERS(krb5.h)
> X+    AC_CHECK_LIB(krb5, krb5_recvauth, , , [-lk5crypto -lcom_err])
> X+    if test "$ac_cv_header_krb5_h" = "no"; then
> X+        AC_MSG_WARN([krb5.h not found; disabling Kerberos v5 support])
> X+        USE_KRB5=false
> X+        CFLAGS="$OCFLAGS"
> X+        LIBS="$OLIBS"
> X+    else
> X+        if test "$ac_cv_lib_krb5" = "no"; then
> X+            AC_MSG_WARN([libkrb5 not found; disabling Kerberos v5 support])
> X+            USE_KRB5=false
> X+        else
> X+        fi
> X+    fi
> X+    if $USE_KRB5; then
> X+        CFLAGS="$CFLAGS -DKRB5 -DUSE_KRB5"
> X+        LIBS="$LIBS -lkrb5 -lk5crypto -lcom_err"
> X+        if test "$KRB_SRVNAM"; then
> X+            CFLAGS="$CFLAGS -DPG_KRB_SRVNAM=\\\"$KRB_SRVNAM\\\""
> X+        fi
> X+        if test "$KRB_KEYTAB"; then
> X+            CFLAGS="$CFLAGS -DPG_KRB_KEYTAB=\\\"$KRB_KEYTAB\\\""
> X+        fi
> X+    else
> X+        CFLAGS="$OCFLAGS"
> X+        CPPFLAGS="$OCPPFLAGS"
> X+        LIBS="$OLIBS"
> X+    fi
> X fi
> X
> END-of-patch-bf
> echo x - patch-bg
> sed 's/^X//' >patch-bg << 'END-of-patch-bg'
> Xdiff -ru2 old/interfaces/libpq/Makefile.in interfaces/libpq/Makefile.in
> X--- old/interfaces/libpq/Makefile.in    Thu Apr 13 20:42:06 2000
> X+++ interfaces/libpq/Makefile.in    Tue Sep 26 23:50:45 2000
> X@@ -34,4 +34,8 @@
> X # make sure it gets included in shared libpq.
> X SHLIB_LINK+= $(findstring -lcrypt,$(LIBS))
> X+SHLIB_LINK+= $(filter -L%,$(LIBS))
> X+SHLIB_LINK+= $(findstring -lkrb5,$(LIBS))
> X+SHLIB_LINK+= $(findstring -lk5crypto,$(LIBS))
> X+SHLIB_LINK+= $(findstring -lcom_err,$(LIBS))
> X
> X # Shared library stuff, also default 'all' target
> END-of-patch-bg
> echo x - patch-bh
> sed 's/^X//' >patch-bh << 'END-of-patch-bh'
> X--- interfaces/libpq/fe-auth.c.orig    Wed Apr 12 13:17:13 2000
> X+++ interfaces/libpq/fe-auth.c    Wed Sep 27 23:15:30 2000
> X@@ -235,5 +235,9 @@
> X  */
> X
> X-#include "krb5/krb5.h"
> X+#include <fcntl.h>
> X+#include "krb5.h"
> X+#ifndef PG_KRB_SRVNAM
> X+#define    PG_KRB_SRVNAM    "pgsql"
> X+#endif
> X
> X /*
> X@@ -241,12 +245,11 @@
> X  *                  name
> X  *
> X- * XXX Assumes that the first aname component is the user name.  This is NOT
> X- *       necessarily so, since an aname can actually be something out of your
> X- *       worst X.400 nightmare, like
> X- *          ORGANIZATION=U. C. Berkeley/NAME=Paul M. Aoki@CS.BERKELEY.EDU
> X- *       Note that the MIT an_to_ln code does the same thing if you don't
> X- *       provide an aname mapping database...it may be a better idea to use
> X- *       krb5_an_to_ln, except that it punts if multiple components are found,
> X- *       and we can't afford to punt.
> X+ * XXX - this is totally broken (and potentially insecure on the server side).
> X+ * The correct mechanism is to use the entire principal name, and make
> X+ * the server do a table lookup to discover the mapping.
> X+ * (In the protocol as it stands, if user jrl@A.EXAMPLE.COM authenticates to
> X+ * a server in the B.EXAMPLE.COM realm, the server will accept him as
> X+ * local-user `jrl' regardless of whether or not jrl@A.EXAMPLE.COM is
> X+ * the same user as jrl@B.EXAMPLE.COM.)
> X  */
> X static char *
> X@@ -260,63 +263,37 @@
> X }
> X
> X+static krb5_context mycontext;
> X+static int mycontext_inited;
> X+static krb5_ccache ccache;
> X
> X-/*
> X- * pg_krb5_init -- initialization performed before any Kerberos calls are made
> X- *
> X- * With v5, we can no longer set the ticket (credential cache) file name;
> X- * we now have to provide a file handle for the open (well, "resolved")
> X- * ticket file everywhere.
> X- *
> X- */
> X-static int
> X-            krb5_ccache
> X+static krb5_error_code
> X pg_krb5_init(void)
> X {
> X     krb5_error_code code;
> X-    char       *realm,
> X-               *defname;
> X-    char        tktbuf[MAXPGPATH];
> X-    static krb5_ccache ccache = (krb5_ccache) NULL;
> X
> X-    if (ccache)
> X-        return ccache;
> X-
> X-    /*
> X-     * If the user set PGREALM, then we use a ticket file with a special
> X-     * name: <usual-ticket-file-name>@<PGREALM-value>
> X-     */
> X-    if (!(defname = krb5_cc_default_name()))
> X-    {
> X-        (void) sprintf(PQerrormsg,
> X-                       "pg_krb5_init: krb5_cc_default_name failed\n");
> X-        return (krb5_ccache) NULL;
> X-    }
> X-    strcpy(tktbuf, defname);
> X-    if (realm = getenv("PGREALM"))
> X-    {
> X-        strcat(tktbuf, "@");
> X-        strcat(tktbuf, realm);
> X-    }
> X+    if (mycontext_inited)
> X+        return 0;
> X
> X-    if (code = krb5_cc_resolve(tktbuf, &ccache))
> X-    {
> X-        (void) sprintf(PQerrormsg,
> X-           "pg_krb5_init: Kerberos error %d in krb5_cc_resolve\n", code);
> X-        com_err("pg_krb5_init", code, "in krb5_cc_resolve");
> X-        return (krb5_ccache) NULL;
> X-    }
> X-    return ccache;
> X+    code = krb5_init_context(&mycontext);
> X+    if (code)
> X+        return code;
> X+
> X+    code = krb5_cc_default(mycontext, &ccache);
> X+    if (code)
> X+        return code;
> X+    mycontext_inited = 1;
> X+    return 0;
> X }
> X
> X /*
> X  * pg_krb5_authname -- returns a pointer to static space containing whatever
> X- *                       name the user has authenticated to the system
> X+ *                name the user has authenticated to the system
> X  *
> X  * We obtain this information by digging around in the ticket file.
> X+ * XXX see comments above
> X  */
> X-static const char *
> X-pg_krb5_authname(const char *PQerrormsg)
> X+static char *
> X+pg_krb5_authname(char *PQerrormsg)
> X {
> X-    krb5_ccache ccache;
> X     krb5_principal principal;
> X     krb5_error_code code;
> X@@ -326,22 +303,33 @@
> X         return authname;
> X
> X-    ccache = pg_krb5_init();    /* don't free this */
> X+    code = pg_krb5_init();
> X+    if (code)
> X+    {
> X+        sprintf(PQerrormsg, "pg_krb5_init: %s\n",
> X+            error_message(code));
> X+        fputs(PQerrormsg, stderr);
> X+        return (char *)NULL;
> X+    }
> X
> X-    if (code = krb5_cc_get_principal(ccache, &principal))
> X+    code = krb5_cc_get_principal(mycontext, ccache, &principal);
> X+    if (code)
> X     {
> X         (void) sprintf(PQerrormsg,
> X-                       "pg_krb5_authname: Kerberos error %d in krb5_cc_get_principal\n", code);
> X-        com_err("pg_krb5_authname", code, "in krb5_cc_get_principal");
> X+                   "pg_krb5_authname: krb5_cc_get_principal: %s\n",
> X+                   error_message(code));
> X+        fputs(PQerrormsg, stderr);
> X         return (char *) NULL;
> X     }
> X-    if (code = krb5_unparse_name(principal, &authname))
> X+    code = krb5_unparse_name(mycontext, principal, &authname);
> X+    if (code)
> X     {
> X         (void) sprintf(PQerrormsg,
> X-                       "pg_krb5_authname: Kerberos error %d in krb5_unparse_name\n", code);
> X-        com_err("pg_krb5_authname", code, "in krb5_unparse_name");
> X-        krb5_free_principal(principal);
> X+                   "pg_krb5_authname: krb5_unparse_name: %s\n",
> X+                   error_message(code));
> X+        fputs(PQerrormsg, stderr);
> X+        krb5_free_principal(mycontext, principal);
> X         return (char *) NULL;
> X     }
> X-    krb5_free_principal(principal);
> X+    krb5_free_principal(mycontext, principal);
> X     return pg_an_to_ln(authname);
> X }
> X@@ -349,107 +337,125 @@
> X /*
> X  * pg_krb5_sendauth -- client routine to send authentication information to
> X- *                       the server
> X- *
> X- * This routine does not do mutual authentication, nor does it return enough
> X- * information to do encrypted connections.  But then, if we want to do
> X- * encrypted connections, we'll have to redesign the whole RPC mechanism
> X- * anyway.
> X+ *               the server
> X  *
> X- * Server hostnames are canonicalized v4-style, i.e., all domain suffixes
> X- * are simply chopped off.    Hence, we are assuming that you've entered your
> X- * server instances as
> X- *        <value-of-PG_KRB_SRVNAM>/<canonicalized-hostname>
> X- * in the PGREALM (or local) database.    This is probably a bad assumption.
> X  */
> X static int
> X-pg_krb5_sendauth(const char *PQerrormsg, int sock,
> X-                 struct sockaddr_in * laddr,
> X-                 struct sockaddr_in * raddr,
> X-                 const char *hostname)
> X+pg_krb5_sendauth(char *PQerrormsg, int sock,
> X+         struct sockaddr_in * laddr,
> X+         struct sockaddr_in * raddr,
> X+         const char *hostname)
> X {
> X-    char        servbuf[MAXHOSTNAMELEN + 1 +
> X-                                    sizeof(PG_KRB_SRVNAM)];
> X-    const char *hostp;
> X-    const char *realm;
> X+    int sflags;
> X+    char servbuf[MAXHOSTNAMELEN + 1];
> X     krb5_error_code code;
> X-    krb5_principal client,
> X-                server;
> X-    krb5_ccache ccache;
> X+    krb5_principal server;
> X     krb5_error *error = (krb5_error *) NULL;
> X+    krb5_auth_context authctx;
> X
> X-    ccache = pg_krb5_init();    /* don't free this */
> X+    code = pg_krb5_init();
> X+    if (code)
> X+    {
> X+        sprintf(PQerrormsg, "pg_krb5_init: %s\n",
> X+            error_message(code));
> X+        fputs(PQerrormsg, stderr);
> X+        return STATUS_ERROR;
> X+    }
> X
> X-    /*
> X-     * set up client -- this is easy, we can get it out of the ticket
> X-     * file.
> X-     */
> X-    if (code = krb5_cc_get_principal(ccache, &client))
> X+    code = krb5_auth_con_init(mycontext, &authctx);
> X+    if (code)
> X     {
> X-        (void) sprintf(PQerrormsg,
> X-                       "pg_krb5_sendauth: Kerberos error %d in krb5_cc_get_principal\n", code);
> X-        com_err("pg_krb5_sendauth", code, "in krb5_cc_get_principal");
> X+        sprintf(PQerrormsg,
> X+            "pg_krb5_recvauth: krb5_auth_con_init: %s\n",
> X+            error_message(code));
> X+        fputs(PQerrormsg, stderr);
> X         return STATUS_ERROR;
> X     }
> X
> X-    /*
> X-     * set up server -- canonicalize as described above
> X-     */
> X-    strcpy(servbuf, PG_KRB_SRVNAM);
> X-    *(hostp = servbuf + (sizeof(PG_KRB_SRVNAM) - 1)) = '/';
> X-    if (hostname || *hostname)
> X-        strncpy(++hostp, hostname, MAXHOSTNAMELEN);
> X-    else
> X-    {
> X-        if (gethostname(++hostp, MAXHOSTNAMELEN) < 0)
> X-            strcpy(hostp, "localhost");
> X-    }
> X-    if (hostp = strchr(hostp, '.'))
> X-        *hostp = '\0';
> X-    if (realm = getenv("PGREALM"))
> X+    if (hostname == 0 || *hostname == '\0')
> X     {
> X-        strcat(servbuf, "@");
> X-        strcat(servbuf, realm);
> X+        if (gethostname(servbuf, MAXHOSTNAMELEN) < 0)
> X+        {
> X+            sprintf(PQerrormsg,
> X+                 "pg_krb5_sendauth: gethostname: %s\n",
> X+                 strerror(errno));
> X+            fputs(PQerrormsg, stderr);
> X+            krb5_auth_con_free(mycontext, authctx);
> X+            return STATUS_ERROR;
> X+        }
> X+        hostname = servbuf;
> X     }
> X-    if (code = krb5_parse_name(servbuf, &server))
> X+
> X+    code = krb5_sname_to_principal(mycontext, hostname, PG_KRB_SRVNAM,
> X+                       KRB5_NT_SRV_HST, &server);
> X+
> X+    if (code)
> X     {
> X-        (void) sprintf(PQerrormsg,
> X-        "pg_krb5_sendauth: Kerberos error %d in krb5_parse_name\n", code);
> X-        com_err("pg_krb5_sendauth", code, "in krb5_parse_name");
> X-        krb5_free_principal(client);
> X+        sprintf(PQerrormsg,
> X+            "pg_krb5_sendauth: krb5_sname_to_principal: %s\n",
> X+            error_message(code));
> X+        fputs(PQerrormsg, stderr);
> X+        krb5_auth_con_free(mycontext, authctx);
> X+        return STATUS_ERROR;
> X+    }
> X+
> X+#define    ALL    (KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR | \
> X+         KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)
> X+    code = krb5_auth_con_genaddrs(mycontext, authctx, sock, ALL);
> X+#undef ALL
> X+    if (code)
> X+    {
> X+        sprintf(PQerrormsg,
> X+            "pg_krb5_sendauth: krb5_auth_con_genaddrs: %s\n",
> X+            error_message(code));
> X+        fputs(PQerrormsg, stderr);
> X+        krb5_free_principal(mycontext, server);
> X+        krb5_auth_con_free(mycontext, authctx);
> X         return STATUS_ERROR;
> X     }
> X
> X+
> X+    /*
> X+     * krb5_sendauth does not appreciate getting a non-blocking file
> X+     * descriptor.  So, we set it to blocking mode and then reset
> X+     * it afterwards.
> X+     */
> X+    sflags = fcntl(sock, F_GETFL, 0);
> X+    fcntl(sock, F_SETFL, sflags & ~O_NONBLOCK);
> X+
> X     /*
> X      * The only thing we want back from krb5_sendauth is an error status
> X-     * and any error messages.
> X+     * and any error messages.  If we cared, we could get the session
> X+     * key(s) from the auth context and stick them somewhere to encrypt
> X+     * the whole data stream.  However, this would mean a major change
> X+     * in the protocol, and I'm not prepared to do that right now.
> X+     * (It should work to encrypt the session using SSL, if a bit of a
> X+     * muchness.)
> X      */
> X-    if (code = krb5_sendauth((krb5_pointer) & sock,
> X-                             PG_KRB5_VERSION,
> X-                             client,
> X-                             server,
> X-                             (krb5_flags) 0,
> X-                             (krb5_checksum *) NULL,
> X-                             (krb5_creds *) NULL,
> X-                             ccache,
> X-                             (krb5_int32 *) NULL,
> X-                             (krb5_keyblock **) NULL,
> X-                             &error,
> X-                             (krb5_ap_rep_enc_part **) NULL))
> X+    code = krb5_sendauth(mycontext, &authctx, (krb5_pointer) &sock,
> X+                 PG_KRB5_VERSION, (krb5_principal) NULL,
> X+                 server, AP_OPTS_MUTUAL_REQUIRED,
> X+                 (krb5_data *) NULL, (krb5_creds *) NULL,
> X+                 ccache, &error, (krb5_ap_rep_enc_part **) NULL,
> X+                 (krb5_creds **) NULL);
> X+    fcntl(sock, F_SETFL, sflags);
> X+    if (code)
> X     {
> X         if ((code == KRB5_SENDAUTH_REJECTED) && error)
> X         {
> X-            (void) sprintf(PQerrormsg,
> X-                  "pg_krb5_sendauth: authentication rejected: \"%*s\"\n",
> X-                           error->text.length, error->text.data);
> X+            sprintf(PQerrormsg,
> X+                "pg_krb5_sendauth: authentication rejected: \"%.*s\"\n",
> X+                error->text.length, error->text.data);
> X         }
> X         else
> X         {
> X-            (void) sprintf(PQerrormsg,
> X-                           "pg_krb5_sendauth: Kerberos error %d in krb5_sendauth\n", code);
> X-            com_err("pg_krb5_sendauth", code, "in krb5_sendauth");
> X+            sprintf(PQerrormsg,
> X+                "pg_krb5_sendauth: krb5_sendauth: %s\n",
> X+                error_message(code));
> X         }
> X     }
> X-    krb5_free_principal(client);
> X-    krb5_free_principal(server);
> X+    krb5_free_principal(mycontext, server);
> X+    if (error != 0)
> X+        krb5_free_error(mycontext, error);
> X+    krb5_auth_con_free(mycontext, authctx);
> X     return code ? STATUS_ERROR : STATUS_OK;
> X }
> END-of-patch-bh
> exit
>
>
>


--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 853-3000
  +  If your life is a hard drive,     |  830 Blythe Avenue
  +  Christ can be your backup.        |  Drexel Hill, Pennsylvania 19026

pgsql-patches by date:

Previous
From: Pete Forman
Date:
Subject: Minor make bug on AIX
Next
From: Peter Eisentraut
Date:
Subject: Re: Minor make bug on AIX