From 10fb050503b3f8fcab2fcac6e8f0a00c3aeddc96 Mon Sep 17 00:00:00 2001 From: Hiroshi Inoue Date: Sun, 10 Oct 2010 16:19:46 +0000 Subject: [PATCH] Oops forgot to add files for GSSAPI authentication. --- gsssvcs.c | 296 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ gsssvcs.h | 5 + version.h | 2 +- 3 files changed, 302 insertions(+), 1 deletion(-) create mode 100644 gsssvcs.c create mode 100644 gsssvcs.h diff --git a/gsssvcs.c b/gsssvcs.c new file mode 100644 index 0000000..fb879e5 --- /dev/null +++ b/gsssvcs.c @@ -0,0 +1,296 @@ +#ifndef WIN32 +#include "config.h" +#endif /* WIN32 */ + +#ifdef USE_GSS +#if defined(WIN32) && defined( _MSC_VER) +#ifdef _WIN64 +#pragma comment(lib, "gssapi64") +#else +#pragma comment(lib, "gssapi32") +#endif /* _WIN64 */ +#endif /* WIN32 */ + +#include "connection.h" +#ifdef _WIN64 +CSTR GSSAPIDLL = "gssapi64"; +#else +CSTR GSSAPIDLL = "gssapi32"; +#endif /* _WIN64 */ +#include "socket.h" +#include "environ.h" +#ifndef MAXHOSTNAMELEN +#include +#endif + +#ifndef STATUS_ERROR +#define STATUS_ERROR (-1) +#endif +#ifndef STATUS_OK +#define STATUS_OK (0) +#endif + +/* + * GSSAPI authentication system. + */ + +#if defined(WIN32) && !defined(_MSC_VER) +/* + * MIT Kerberos GSSAPI DLL doesn't properly export the symbols for MingW + * that contain the OIDs required. Redefine here, values copied + * from src/athena/auth/krb5/src/lib/gssapi/generic/gssapi_generic.c + */ +static const gss_OID_desc GSS_C_NT_HOSTBASED_SERVICE_desc = +{10, (void *) "\x2a\x86\x48\x86\xf7\x12\x01\x02\x01\x04"}; +static GSS_DLLIMP gss_OID GSS_C_NT_HOSTBASED_SERVICE = &GSS_C_NT_HOSTBASED_SERVICE_desc; +#endif + +/* + * Fetch all errors of a specific type and append to "str". + */ +static void +pg_GSS_error_int(ConnectionClass *conn, const char *mprefix, + OM_uint32 stat, int type) +{ + char *errmsg, *nerrmsg; + size_t alclen; + OM_uint32 lmaj_s, + lmin_s; + gss_buffer_desc lmsg; + OM_uint32 msg_ctx = 0; + + do + { + lmaj_s = gss_display_status(&lmin_s, stat, type, + GSS_C_NO_OID, &msg_ctx, &lmsg); + + errmsg = CC_get_errormsg(conn); + alclen = strlen(errmsg) + strlen(mprefix) + 2 + strlen(lmsg.value) + strlen("\n") + 1; + nerrmsg = malloc(alclen); + snprintf(nerrmsg, alclen, "%s%s: %s\n", errmsg, mprefix, (char *) lmsg.value); + CC_set_errormsg(conn, nerrmsg); + free(nerrmsg); + + gss_release_buffer(&lmin_s, &lmsg); + } while (msg_ctx); +} + +/* + * GSSAPI errors contain two parts; put both into conn->errorMessage. + */ +static void +pg_GSS_error(const char *mprefix, ConnectionClass *conn, + OM_uint32 maj_stat, OM_uint32 min_stat) +{ + CC_set_errormsg(conn, ""); + + /* Fetch major error codes */ + pg_GSS_error_int(conn, mprefix, maj_stat, GSS_C_GSS_CODE); + + /* Add the minor codes as well */ + pg_GSS_error_int(conn, mprefix, min_stat, GSS_C_MECH_CODE); +} + +/* + * Continue GSS authentication with next token as needed. + */ +int pg_GSS_continue(ConnectionClass *conn, Int4 inlen) +{ + SocketClass *sock = CC_get_socket(conn); + OM_uint32 maj_stat, + min_stat, + lmin_s; + gss_buffer_desc ginbuf, goutbuf; + + ginbuf.length = 0; +mylog("!!! %s inlen=%d in\n", __FUNCTION__, inlen); + if (sock->gctx != GSS_C_NO_CONTEXT) + { +mylog("!!! %s -1\n", __FUNCTION__); + if (inlen > 0) + { + if (NULL == (ginbuf.value = malloc(inlen))) + { + CC_set_error(conn, CONN_NO_MEMORY_ERROR, + "realloc error during autehntication", __FUNCTION__); + return STATUS_ERROR; + } +mylog("!!! %s -2\n", __FUNCTION__); + ginbuf.length = inlen; + SOCK_get_n_char(conn->sock, ginbuf.value, inlen); + if (0 != SOCK_get_errcode(conn->sock)) + { + CC_set_error(conn, CONN_INVALID_AUTHENTICATION, + "communication error during autehntication", __FUNCTION__); + free(ginbuf.value); + return STATUS_ERROR; + } + } + } + +mylog("!!! %s 0\n", __FUNCTION__); + maj_stat = gss_init_sec_context(&min_stat, + GSS_C_NO_CREDENTIAL, + &sock->gctx, + sock->gtarg_nam, + GSS_C_NO_OID, + GSS_C_MUTUAL_FLAG, + 0, + GSS_C_NO_CHANNEL_BINDINGS, + (sock->gctx == GSS_C_NO_CONTEXT) ? GSS_C_NO_BUFFER : &ginbuf, + NULL, + &goutbuf, + NULL, + NULL); + +mylog("!!! %s 1\n", __FUNCTION__); + if (ginbuf.length != 0) + { + free(ginbuf.value); + ginbuf.length = 0; + } + +mylog("!!! %s 1-1 outlen=%d\n", __FUNCTION__, goutbuf.length); + if (goutbuf.length != 0) + { + SocketClass *sock = conn->sock; + int slen; + /* + * GSS generated data to send to the server. We don't care if it's the + * first or subsequent packet, just send the same kind of password + * packet. + */ +mylog("!!! %s 2\n", __FUNCTION__); + if (PROTOCOL_74(&(conn->connInfo))) + SOCK_put_char(sock, 'p'); + slen = goutbuf.length; + SOCK_put_int(sock, slen + 4, 4); + SOCK_put_n_char(sock, goutbuf.value, slen); + SOCK_flush_output(sock); + gss_release_buffer(&lmin_s, &goutbuf); + goutbuf.length = 0; + if (0 != SOCK_get_errcode(sock)) + { +mylog("!!! %s 3\n", __FUNCTION__); + CC_set_error(conn, CONN_INVALID_AUTHENTICATION, + "communication error during autehntication", __FUNCTION__); + } + } + +mylog("!!! %s maj_stat=%d\n", __FUNCTION__, maj_stat); + if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) + { +mylog("!!! %s 5\n", __FUNCTION__); + pg_GSS_error("GSSAPI continuation error", + conn, + maj_stat, min_stat); + gss_release_name(&lmin_s, &sock->gtarg_nam); + if (sock->gctx) + gss_delete_sec_context(&lmin_s, &sock->gctx, GSS_C_NO_BUFFER); + return STATUS_ERROR; + } +mylog("!!! %s 6\n", __FUNCTION__); + + if (maj_stat == GSS_S_COMPLETE) + gss_release_name(&lmin_s, &sock->gtarg_nam); + + return STATUS_OK; +} + +/* + * This is needed to make /Delayload:gssapi32(64).dll possible + * under Windows. + */ +static gss_OID get_c_nt_hostbased_service() +{ +#if defined(WIN32) && defined(_MSC_VER) + static FARPROC proc = NULL; + + shortterm_common_lock(); + if (NULL == proc) + { + HMODULE hmodule = GetModuleHandle(GSSAPIDLL); + + if (NULL != hmodule) + proc = GetProcAddress(hmodule, "GSS_C_NT_HOSTBASED_SERVICE"); + } + shortterm_common_unlock(); + if (NULL != proc) + return *((gss_OID *) proc); + return 0; +#else + return GSS_C_NT_HOSTBASED_SERVICE; +#endif +} + +/* + * Send initial GSS authentication token + */ +int pg_GSS_startup(ConnectionClass *conn, void *opt) +{ + SocketClass *sock = CC_get_socket(conn); + OM_uint32 maj_stat, + min_stat; + gss_buffer_desc temp_gbuf; + +mylog("!!! %s in\n", __FUNCTION__); + if (sock->gctx) + { + char mesg[100]; + +mylog("!!! %s 0\n", __FUNCTION__); + snprintf(mesg, sizeof(mesg), "duplicate GSS authentication request"); + CC_set_error(conn, CONN_INVALID_AUTHENTICATION, + mesg, __FUNCTION__); + free(opt); + return STATUS_ERROR; + } +mylog("!!! %s 2\n", __FUNCTION__); + + /* + * Import service principal name so the proper ticket can be acquired by + * the GSSAPI system. + */ + temp_gbuf.value = (char *) opt; + temp_gbuf.length = strlen(temp_gbuf.value); + +mylog("!!! temp_gbuf.value=%s\n", temp_gbuf.value); + maj_stat = gss_import_name(&min_stat, &temp_gbuf, + // GSS_C_NT_HOSTBASED_SERVICE, + get_c_nt_hostbased_service(), + &sock->gtarg_nam); + free(temp_gbuf.value); + + if (maj_stat != GSS_S_COMPLETE) + { +mylog("!!! %s 3\n", __FUNCTION__); + pg_GSS_error("GSSAPI name import error", + conn, + maj_stat, min_stat); + return STATUS_ERROR; + } + +mylog("!!! %s 4\n", __FUNCTION__); + /* + * Initial packet is the same as a continuation packet with no initial + * context. + */ + sock->gctx = GSS_C_NO_CONTEXT; + + return pg_GSS_continue(conn, 0); +} + +void pg_GSS_cleanup(SocketClass *sock) +{ + OM_uint32 min_s; + + if (sock->gctx) + { + gss_delete_sec_context(&min_s, &sock->gctx, GSS_C_NO_BUFFER); + } + if (sock->gtarg_nam) + { + gss_release_name(&min_s, &sock->gtarg_nam); + } +} +#endif /* USE_GSS */ diff --git a/gsssvcs.h b/gsssvcs.h new file mode 100644 index 0000000..f68714d --- /dev/null +++ b/gsssvcs.h @@ -0,0 +1,5 @@ +#ifdef USE_GSS +int pg_GSS_continue(ConnectionClass *conn, Int4 inlen); +int pg_GSS_startup(ConnectionClass *conn, void *opt); +void pg_GSS_cleanup(SocketClass *sock); +#endif /* USE_GSS */ diff --git a/version.h b/version.h index a40bf0b..bb70192 100644 --- a/version.h +++ b/version.h @@ -12,6 +12,6 @@ #define POSTGRESDRIVERVERSION "09.00.0100" #define POSTGRES_RESOURCE_VERSION "09.00.0100\0" #define PG_DRVFILE_VERSION 9,0,01,00 -#define PG_BUILD_VERSION "201010060001" +#define PG_BUILD_VERSION "201010110001" #endif -- 2.39.5